jos学习---day1代码整体结构

目录结构

workdir
|------ GNUmakefile
|
|------ boot
|         |---- Makefrag
|         |---- boot.S
|         |---- main.c
|------ fs
|
|------ inc
|
|------ kern
|         |---- Makefrag
|         |---- kernel.ld
|         |---- entry.S
|         |---- entrypgdir,c
|         |---- init.c
|         |---- monitor.c
|         |---- monitor.h
|         |---- kdebug.c
|         |---- kdebug.h
|         |---- printf.c
|         |---- console.c
|         |---- console.h
|
|------ user
|
|------ conf
|         |---- env.mk
|         |---- lab.mk

这里boot和kern目录下的Makefrag分别定义了内核boot和主体在编译时所需要的文件

文件boot/Makefarg内容如下:

# 编译之后对象文件输出的目录
OBJDIRS += boot

# 编译之后输出的对象文件
BOOT_OBJS := $(OBJDIR)/boot/boot.o $(OBJDIR)/boot/main.o

# 得到对象文件的方法
# 下面出现的变量都是在顶层Makefile中
# 将所有的.c文件编译成.o文件
$(OBJDIR)/boot/%.o: boot/%.c
    @echo + cc -Os $<
    @mkdir -p $(@D)
    $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $@ $<

# 将所有的.S文件编译.o文件
$(OBJDIR)/boot/%.o: boot/%.S
    @echo + as $<
    @mkdir -p $(@D)
    $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<

$(OBJDIR)/boot/main.o: boot/main.c
    @echo + cc -Os $<
    $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $(OBJDIR)/boot/main.o boot/main.c

$(OBJDIR)/boot/boot: $(BOOT_OBJS)
    @echo + ld boot/boot
    $(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o $@.out $^
    $(V)$(OBJDUMP) -S $@.out >$@.asm
    $(V)$(OBJCOPY) -S -O binary -j .text $@.out $@
    $(V)perl boot/sign.pl $(OBJDIR)/boot/boot

文件kern/Makefarg内容如下:

OBJDIRS += kern

KERN_LDFLAGS := $(LDFLAGS) -T kern/kernel.ld -nostdlib

# entry.S must be first, so that it's the first code in the text segment!!!
#
# We also snatch the use of a couple handy source files
# from the lib directory, to avoid gratuitous code duplication.
KERN_SRCFILES :=    kern/entry.S \
            kern/entrypgdir.c \
            kern/init.c \
            kern/console.c \
            kern/monitor.c \
            kern/pmap.c \
            kern/env.c \
            kern/kclock.c \
            kern/picirq.c \
            kern/printf.c \
            kern/trap.c \
            kern/trapentry.S \
            kern/sched.c \
            kern/syscall.c \
            kern/kdebug.c \
            lib/printfmt.c \
            lib/readline.c \
            lib/string.c

# Only build files if they exist.
KERN_SRCFILES := $(wildcard $(KERN_SRCFILES))

# Binary program images to embed within the kernel.
KERN_BINFILES :=

KERN_OBJFILES := $(patsubst %.c, $(OBJDIR)/%.o, $(KERN_SRCFILES))
KERN_OBJFILES := $(patsubst %.S, $(OBJDIR)/%.o, $(KERN_OBJFILES))
KERN_OBJFILES := $(patsubst $(OBJDIR)/lib/%, $(OBJDIR)/kern/%, $(KERN_OBJFILES))

KERN_BINFILES := $(patsubst %, $(OBJDIR)/%, $(KERN_BINFILES))

# How to build kernel object files
$(OBJDIR)/kern/%.o: kern/%.c $(OBJDIR)/.vars.KERN_CFLAGS
    @echo + cc $<
    @mkdir -p $(@D)
    $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<

$(OBJDIR)/kern/%.o: kern/%.S $(OBJDIR)/.vars.KERN_CFLAGS
    @echo + as $<
    @mkdir -p $(@D)
    $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<

$(OBJDIR)/kern/%.o: lib/%.c $(OBJDIR)/.vars.KERN_CFLAGS
    @echo + cc $<
    @mkdir -p $(@D)
    $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<

# Special flags for kern/init
$(OBJDIR)/kern/init.o: override KERN_CFLAGS+=$(INIT_CFLAGS)
$(OBJDIR)/kern/init.o: $(OBJDIR)/.vars.INIT_CFLAGS

# How to build the kernel itself
$(OBJDIR)/kern/kernel: $(KERN_OBJFILES) $(KERN_BINFILES) kern/kernel.ld \
      $(OBJDIR)/.vars.KERN_LDFLAGS
    @echo + ld $@
    $(V)$(LD) -o $@ $(KERN_LDFLAGS) $(KERN_OBJFILES) $(GCC_LIB) -b binary $(KERN_BINFILES)
    $(V)$(OBJDUMP) -S $@ > $@.asm
    $(V)$(NM) -n $@ > $@.sym

# How to build the kernel disk image
$(OBJDIR)/kern/kernel.img: $(OBJDIR)/kern/kernel $(OBJDIR)/boot/boot
    @echo + mk $@
    $(V)dd if=/dev/zero of=$(OBJDIR)/kern/kernel.img~ count=10000 2>/dev/null
    $(V)dd if=$(OBJDIR)/boot/boot of=$(OBJDIR)/kern/kernel.img~ conv=notrunc 2>/dev/null
    $(V)dd if=$(OBJDIR)/kern/kernel of=$(OBJDIR)/kern/kernel.img~ seek=1 conv=notrunc 2>/dev/null
    $(V)mv $(OBJDIR)/kern/kernel.img~ $(OBJDIR)/kern/kernel.img

all: $(OBJDIR)/kern/kernel.img

grub: $(OBJDIR)/jos-grub

$(OBJDIR)/jos-grub: $(OBJDIR)/kern/kernel
    @echo + oc $@
    $(V)$(OBJCOPY) --adjust-vma=0x10000000 $^ $@

关于makefile语法的一些补充
makefile中等号的使用
=:make会将整个makefile展开之后再决定左边变量的值,所以左边变量的值会是makefile中最后被指定的值
:=:变量使用:=赋值会覆盖之前的值,当使用:=赋值时,变量的值取决于赋值的位置
?=:如果左边变量之前没有被赋值,则将右边的值赋给左边,反之,变量保留原值
+=:将右边的值加到左边的变量中
$<代表依赖目标,即:右边的文件,这里是将右边的文件一个一个的提取出来
$@代表目标文件,即:左边的文件,这里是将左边的文件一个一个的提取出来
以上面的Makefile为例
$(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $@ $<
这句在执行时会将$(OBJDIR)/boot/%.o: boot/%.c指定的.c文件一个一个的编译成.o文件

关于gcc编译选项的说明
-Os:优化等级和-O2一致,但是不缩减代码尺寸
-nostdinc:不在系统目录中寻找头文件
-pipe:在编译的各个阶段使用管道而不是临时文件进行通信
-fno-builtin:不引用标准库的c语言函数
-MD:根据makefile会生成对应目标文件的依赖文件,即.d文件

关于ld的链接选项
-N:与--omagic等价,作用是将text段和data段设置为可读可写的。同时data段不以page为单位对齐
-e:与--entry等价,作用是将后面跟的符号作为程序执行的入口,而不是默认入口(一般是main)
-Ttext:设置text段的地址,与其类似的还有-TbssTdata

关于dd指令的使用
创建一个可以启动的jos镜像需要以下三步

  1. dd if=/dev/zero of=obj/kern/kernel.img~ count=10000 2>/dev/null
  2. dd if=obj/boot/boot of=obj/kern/kernel.img~ conv=notrunc 2>/dev/null
  3. dd if=obj/kern/kernel of=obj/kern/kernel.img~ seek=1 conv=notrunc 2>/dev/null

第一步是初始化了一个10000个block的镜像文件kernel.img~,每个block的大小可以有ibs选项设置,默认是512bytes
第二步是将编译出来的boot elf文件加载到kernel.img~的第一个block中
第三步是将编译出来的kernel elf文件从第二个block开始加载到kernel.img中
seek:跳过seek选项后面数值的block之后开始复制
conv:设置传输模式,这里设置的notrunc意思是不截断输出文件

jos在qemu中启动内核的操作

qemu-system-i386 -drive file=obj/kern/kernel.img,index=0,media=disk,format=raw -serial mon:stdio -gdb tcp::26000 -D qemu.log 

里面比较关键的几个选项是:

  • -drive file=obj/kern/kernel.img,index=0,media=disk,format=raw

  • -serial mon:stdio

  • gdb tcp::26000

  • -D qemu.log

我尝试了一下不加-drive选项直接引导镜像,也可以启动系统,但是有一个警告,并且在系统运行的过程中shell中没有任何的log输出。

WARNING: Image format was not specified for 'obj/kern/kernel.img' and probing guessed raw.Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.Specify the 'raw' format explicitly to remove the restrictions.

这里的提示是没有指定镜像的格式,自动探测为raw格式。限制了对block 0的写操作。

qemu一些标志的使用

参考

标准选项

  • -h : 显示帮助

  • -version : 显示版本

  • -machine [type]name[,prop=value[,…]]

    • 该选项中name指定qemu模拟的机器平台,prop用于指定该机器运行时的一些属性。当前支持的机器平台可以使用-machine help得到
  • -drive option[[,option[,option[,…]]]]

    • file=file 该选项用于指定要使用的镜像文件
    • if=interface 该选项用于指定驱动器连接的接口类型,包括ide, scsi, sd, mtd, floppy, pflash, virtio, none.
    • bus=bus,unit=unit 该选项指定bus号和unit号,决定驱动器的连接位置。
    • index=index 在给定的接口类型的列表中定位连接驱动器的位置
    • media=media 指定存储介质,包括disk和cdrom
  • -serial dev 该选项试讲虚拟串口重定向到宿主机的字符设备上去。默认是vc(图形化界面)和stdio(非图形化界面)

    • vc[:WxH] 配置图形的大小
    • pty
    • chardev:id
    • mon:dev_string 允许监视器被多路复用到另一个端口
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值