回顾 828 的 Lab2,内存管理部分。
从跳转到内核入口点开始
1 控制台初始化
- 初始化 cga。
- 初始化 kbd。
- 初始化 serial。
2 内存初始化
- 首先,
i386_detect_memory
函数负责探测内存,主要记录两个变量。npages = ,npages_basemem = 。 - 然后,创建初始化页目录。
- 向页目录中插入页表。
- 创建
npages
个struct PageInfo
, 并存储在 pages 数组中。pages 数组中有每一个物理页的入口地址。 - 初始化页面。即将空闲的物理页用一个链表连接起来。
- 进入内核 monitor 。
详细过程
((void (*)(void)) (ELFHDR->e_entry))();
此指令跳转到 entry.S
中的 _start
指令处执行程序。
1 entry.S
所做工作
进入内核时,还没有设置虚拟内存,所以程序运行在 1MB 处。但是 C 代码被链接到
KERNBASE + 1MB
处,因此,首先设置一个手写的 4MB 页表。此页表将虚拟地址[KERNBASE, KERNBASE + 4MB)
翻译到物理地址[0, 4MB)
。此页表一直使用到设置真正的页表为止。首先,将
entry_pgdir
的地址(即:手写页表的指针)存入寄存器cr3
。开启分页(即:设置cr0
中的标志位)。跳转到高地址。设置栈指针为
bootstactop
,调用i386_init
。
2 i386_init
初始化
初始化控制台设备,包括 cga、kbd 和 serial。
-
初始化内存。首先找出机器有多少内存。
- physical memory : 128 MB
- npages : 32K
创建初始页目录
kern_pgdir
。 (0xf0345000
)把页目录作为一张页表插入它自己。
分配页面。一共 npages 个页面结构,其指针存储在以 pages 为起始指针的数组里。
页面初始化。即将空闲页面组织为一个链表,以便后续使用。
3 设置虚拟内存
- 在
UPAGES
处映射用户只读的页面。(0xEF000000
) - 设置内核栈。将
[KSTACKTOP-PTSIZE, KSTACKTOP)
分为两部分:(0xF0000000)
-
[KSTACKTOP-KSTKSIZE, KSTACKTOP)
-- 内核栈 -
[KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE)
-- 保护页
-
- 在
KERNBASE
处映射所有物理内存 (256MB 中的 128MB)。(0xF0000000
) - 加载
KERNBASE
物理地址进入cr3
,目的是切换到新的页表。(注:cr3
又称 the page directory base register (PDBR))。 - 设置
cr0
。开启分页等。 - 内存设置完毕,跳转进入montior。
4 内存布局
* Virtual memory map: Permissions
* kernel/user
*
* 4 Gig --------> +------------------------------+
* | | RW/--
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* : . :
* : . :
* : . :
* |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| RW/--
* | | RW/--
* | Remapped Physical Memory | RW/--
* | | RW/--
* KERNBASE, ----> +------------------------------+ 0xf0000000/256MB--+
* KSTACKTOP | CPU0's Kernel Stack | RW/-- KSTKSIZE |
* | - - - - - - - - - - - - - - -| |
* | Invalid Memory (*) | --/-- KSTKGAP |
* +------------------------------+ |
* | CPU1's Kernel Stack | RW/-- KSTKSIZE |
* | - - - - - - - - - - - - - - -| PTSIZE
* | Invalid Memory (*) | --/-- KSTKGAP |
* +------------------------------+ |
* : . : |
* : . : |
* MMIOLIM ------> +------------------------------+ 0xefc00000 --+
* | Memory-mapped I/O | RW/-- PTSIZE
* ULIM, MMIOBASE --> +------------------------------+ 0xef800000
* | Cur. Page Table (User R-) | R-/R- PTSIZE
* UVPT ----> +------------------------------+ 0xef400000
* | RO PAGES | R-/R- PTSIZE
* UPAGES ----> +------------------------------+ 0xef000000
* | RO ENVS | R-/R- PTSIZE
* UTOP,UENVS ------> +------------------------------+ 0xeec00000
* UXSTACKTOP -/ | User Exception Stack | RW/RW PGSIZE
* +------------------------------+ 0xeebff000
* | Empty Memory (*) | --/-- PGSIZE
* USTACKTOP ---> +------------------------------+ 0xeebfe000
* | Normal User Stack | RW/RW PGSIZE
* +------------------------------+ 0xeebfd000
* | |
* | |
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* . .
* . .
* . .
* |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
* | Program Data & Heap |
* UTEXT --------> +------------------------------+ 0x00800000
* PFTEMP -------> | Empty Memory (*) | PTSIZE
* | |
* UTEMP --------> +------------------------------+ 0x00400000 --+
* | Empty Memory (*) | |
* | - - - - - - - - - - - - - - -| |
* | User STAB Data (optional) | PTSIZE
* USTABDATA ----> +------------------------------+ 0x00200000 |
* | Empty Memory (*) | |
* 0 ------------> +------------------------------+ --+
*
* (*) Note: The kernel ensures that "Invalid Memory" is *never* mapped.
* "Empty Memory" is normally unmapped, but user programs may map pages
* there if desired. JOS user programs map pages temporarily at UTEMP.