MINIX3分析一
结构
先来看看生成的内核的结构,根据链接脚本,可以看到
- 内核加载的物理地址是
0x00400000
也就是4MB的位置 - 内核的虚拟基址是
0xF0400000
,换算下来内核的虚拟地址空间约为256MB
- 内核入口地址为
__k_unpaged_MINIX
unpaged_*.o
的文件被链接在内核的最开始处,且其虚拟地址等于其物理地址- 再之后安排的是
usermapped
相关的东西,和内核的.text
、.data
、.rodata
、.bss
等段。
minix/kernel/arch/i386/kernel.lds
OUTPUT_ARCH("i386")
ENTRY(__k_unpaged_MINIX)
_kern_phys_base = 0x00400000; /* phys 4MB aligned for convenient remapping */
_kern_vir_base = 0xF0400000; /* map kernel high for max. user vir space */
_kern_offset = (_kern_vir_base - _kern_phys_base);
__k_unpaged__kern_offset = _kern_offset;
__k_unpaged__kern_vir_base = _kern_vir_base;
__k_unpaged__kern_phys_base = _kern_phys_base;
SECTIONS
{
. = _kern_phys_base;
__k_unpaged__kern_unpaged_start = .;
.unpaged_text : { unpaged_*.o(.text) }
.unpaged_data ALIGN(4096) : { unpaged_*.o(.data .rodata*) }
.unpaged_bss ALIGN(4096) : { unpaged_*.o(.bss COMMON) }
__k_unpaged__kern_unpaged_end = .;
. += _kern_offset;
. = ALIGN(4096); usermapped_start = .;
.usermapped_glo : AT(ADDR(.usermapped_glo) - _kern_offset) { *(.usermapped_glo) }
. = ALIGN(4096); usermapped_nonglo_start = .;
.usermapped : AT(ADDR(.usermapped) - _kern_offset) { *(.usermapped) }
. = ALIGN(4096); usermapped_end = .;
.text : AT(ADDR(.text) - _kern_offset) { *(.text*) }
.data ALIGN(4096) : AT(ADDR(.data) - _kern_offset) { *(.data .rodata* ) }
. = ALIGN(4096);
.bss ALIGN(4096) : AT(ADDR(.bss) - _kern_offset) { *(.bss* COMMON)
__k_unpaged__kern_size = . - _kern_vir_base;
_kern_size = __k_unpaged__kern_size;
}
_end = .;
}
关于这个链接脚本,我们可以看到会有.unpaged_text : { unpaged_*.o(.text) }
这样的定义,就是把所有unpaged_
开头的obj
文件的.text
段链接到一起。但是当用find . -name "unpaged_*"
查找时,却找不到任何这样的代码文件。这是因为unpaged_
开头的obj
文件是在Makefile
中根据一定规则生成的。参考minix/kernel/arch/i386/Makefile.inc
可以看到它会利用head.o
、pre_init.o
等这些文件生成带unpaged_
前缀的相应的文件,然后利用objcopy
命令为obj
文件的所有符号添加__k_unpaged_
前缀。
# some object files we give a symbol prefix (or namespace) of __k_unpaged_
# that must live in their own unique namespace.
#
.for unpaged_obj in head.o pre_init.o direct_tty_utils.o \
pg_utils.o klib.o utility.o arch_reset.o \
io_inb.o io_outb.o \
${MINLIB_OBJS_UNPAGED} ${MINC_OBJS_UNPAGED} ${SYS_OBJS_UNPAGED}
# ...
unpaged_${unpaged_obj}: ${unpaged_obj}
${OBJCOPY} --prefix-symbols=__k_unpaged_ ${.OBJDIR}/${unpaged_obj} $@
# ...
UNPAGED_OBJS += unpaged_${unpaged_obj}
ORIG_UNPAGED_OBJS += ${unpaged_obj}
.endfor
入口
minix支持grub的multiboot协议引导,其入口处在kernel/arch/i386/head.S
.text
/*===========================================================================*/
/* MINIX */
/*===========================================================================*/
.global MINIX
MINIX:
/* this is the entry point for the MINIX kernel */
jmp multiboot_init
/* Multiboot header here*/
.balign 8
#define MULTIBOOT_FLAGS (MULTIBOOT_HEADER_WANT_MEMORY | MULTIBOOT_HEADER_MODS_ALIGNED)
multiboot_magic:
.long MULTIBOOT_HEADER_MAGIC
multiboot_flags:
.long MULTIBOOT_FLAGS
multiboot_checksum:
.long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_FLAGS)
.long 0
.long 0
.long 0
.long 0
.long 0
/* Video mode */
multiboot_mode_type:
.long MULTIBOOT_VIDEO_MODE_EGA
multiboot_width:
.long MULTIBOOT_CONSOLE_COLS
multiboot_height:
.long MULTIBOOT_CONSOLE_LINES
multiboot_depth:
.long 0
multiboot_init:
mov $load_stack_start, %esp /* make usable stack */
mov $0, %ebp
push $0 /* set flags to known good state */
popf /* esp, clear nested task and int enable */
push $0
push %ebx /* multiboot information struct */
push %eax /* multiboot magic number */
call _C_LABEL(pre_init)
/* Kernel is mapped high now and ready to go, with
* the boot info pointer returnd in %eax. Set the
* highly mapped stack, initialize it, push the boot
* info pointer and jump to the highly mapped kernel.
*/
mov $k_initial_stktop, %esp
push $0 /* Terminate stack */
push %eax
call _C_LABEL(kmain)
/* not reached */
hang:
jmp hang
.data
load_stack:
.space 4096
load_stack_start:
分配了4096的栈用于调用pre_init
,完成之后切换栈到k_initial_stktop
调用kmain
正式进入内核。
这个head.S
会生成head.o
,结合前述的Makefile
,它会被进一步在所有符号前添加__k_unpaged_
前缀后生成新的unpaged_head.o
文件。然后它们就会被链接在内核二进制文件的最开始处。
这个head.S
的入口MINIX
会被改成__k_unpaged_MINIX
,正好是链接脚本kernel.lds
所指示的入口地址。