这此来分析Main中的第三个函数Init_Mem(bootInfo)。
参数bootInfo是在主函数Main中传入的,为struct Boot_Info类型
定义在./include/geekos/bootinfo.h
struct Boot_Info {
int bootInfoSize; /* size of this struct; for versioning */
int memSizeKB; /* number of KB, as reported by int 15h */
};
内存信息是setup代码获得的,在进入main函数前按照Boot_Info *类型作为参数压入。
如下
xor eax, eax
mov ax, [(SETUPSEG<<4)+mem_size_kbytes]
push eax ; memSizeKB
push dword 8 ; bootInfoSize
; Pass pointer to Boot_Info struct as argument to kernel
; entry point.
push esp ;注意这里,传入的是一个指针!!作为Main函数的参数
; Push return address to make this look like a call , yes, it like a call.
; XXX - untested
push dword (SETUPSEG<<4)+.returnAddr
; Far jump into kernel
jmp KERNEL_CS:ENTRY_POINT ; 直接跳到Main函数入口处!!!!!!!
注意压入的参数是一个指针类型
Init_Mem函数位于./src/geekos/mem.c中,有点长了。
/*
* Initialize memory management data structures.
* Enables the use of Alloc_Page() and Free_Page() functions.
*/
void Init_Mem(struct Boot_Info* bootInfo)
{
ulong_t numPages = bootInfo->memSizeKB >> 2;
ulong_t endOfMem = numPages * PAGE_SIZE;
unsigned numPageListBytes = sizeof(struct Page) * numPages;
ulong_t pageListAddr;
ulong_t kernEnd;
KASSERT(bootInfo->memSizeKB > 0);
/*
* Before we do anything, switch from setup.asm's temporary GDT
* to the kernel's permanent GDT.
*/
Init_GDT();
/*
* We'll put the list of Page objects right after the end
* of the kernel, and mark it as "kernel". This will bootstrap
* us sufficiently that we can start allocating pages and
* keeping track of them.
*/
pageListAddr = Round_Up_To_Page((ulong_t) &end);
g_pageList = (struct Page*) pageListAddr;
kernEnd = Round_Up_To_Page(pageListAddr + numPageListBytes);
s_numPages = numPages;
/*
* The initial kernel thread and its stack are placed
* just beyond the ISA hole.
*/
KASSERT(ISA_HOLE_END == KERN_THREAD_OBJ);
KASSERT(KERN_STACK == KERN_THREAD_OBJ + PAGE_SIZE);
/*
* Memory looks like this:
* 0 - start: available (might want to preserve BIOS data area)
* start - end: kernel
* end - ISA_HOLE_START: available
* ISA_HOLE_START - ISA_HOLE_END: used by hardware (and ROM BIOS?)
* ISA_HOLE_END - HIGHMEM_START: used by initial kernel thread
* HIGHMEM_START - end of memory: available
* (the kernel heap is located at HIGHMEM_START; any unused memory
* beyond that is added to the freelist)
*/
Add_Page_Range(0, PAGE_SIZE, PAGE_UNUSED);
Add_Page_Range(PAGE_SIZE, KERNEL_START_ADDR, PAGE_AVAIL);
Add_Page_Range(KERNEL_START_ADDR, kernEnd, PAGE_KERN);
Add_Page_Range(kernEnd, ISA_HOLE_START, PAGE_AVAIL);
Add_Page_Range(ISA_HOLE_START, ISA_HOLE_END, PAGE_HW);
Add_Page_Range(ISA_HOLE_END, HIGHMEM_START, PAGE_ALLOCATED);
Add_Page_Range(HIGHMEM_START, HIGHMEM_START + KERNEL_HEAP_SIZE, PAGE_HEAP);
Add_Page_Range(HIGHMEM_START + KERNEL_HEAP_SIZE, endOfMem, PAGE_AVAIL);
/* Initialize the kernel heap */
Init_Heap(HIGHMEM_START, KERNEL_HEAP_SIZE);
Print("%uKB memory detected, %u pages in freelist, %d bytes in kernel heap\n",
bootInfo->memSizeKB, g_freePageCount, KERNEL_HEAP_SIZE);
}
先看前两句
ulong_t numPages = bootInfo->memSizeKB >> 2;
ulong_t endOfMem = numPages * PAGE_SIZE;
实际调试中,bootInfo->memSizeKB = 32768
numPages=8192 PAGE_SIZE则是一个物理页的大小4K,
endOfMem为8192*4K,为32768K
memSizeKB是系统可用的物理内存,以K为单位,系统为每一个4K的物理页建立一个描述项,numPages得到描述项的个数。
endOfMem则得到可用内存的最终地址。
比如说如果boot_SIZE为32769,那么最终得到endOfMem为32768,剩余的1K不用,因为这个物理页不完整,无法用一个描述项描述。
下一句
unsigned numPageListBytes = sizeof(struct Page) * numPages;
得到这些描述项共占内存大小。
struct Page是物理页描述项的类型
定义在./include/geekos/mem.h中
/*
* Each page of physical memory has one of these structures
* associated with it, to do allocation and bookkeeping.
*/
struct Page {
unsigned flags; /* Flags indicating state of page */
DEFINE_LINK(Page_List, Page); /* Link fields for Page_List */
};
其中DEFINE_LINK()是一个宏,定义在./include/geekos/list.h中
/*
* Define members of a struct to be used as link fields for
* membership in given list type.
*/
#define DEFINE_LINK(listTypeName, nodeTypeName) \
struct nodeTypeName * prev##listTypeName, * next##listTypeNa