Exercise 1

要求完成的函数内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
static void *
boot_alloc(uint32_t n)
{
static char *nextfree; // virtual address of next byte of free memory
char *result;

// Initialize nextfree if this is the first time.
// 'end' is a magic symbol automatically generated by the linker,
// which points to the end of the kernel's bss segment:
// the first virtual address that the linker did *not* assign
// to any kernel code or global variables.
if (!nextfree) {
extern char end[];
nextfree = ROUNDUP((char *) end, PGSIZE);
}

// Allocate a chunk large enough to hold 'n' bytes, then update
// nextfree. Make sure nextfree is kept aligned
// to a multiple of PGSIZE.
//
// LAB 2: Your code here.
result = nextfree;
nextfree += ROUNDUP(n, PGSIZE);
return result;
}

void
mem_init(void)
{
uint32_t cr0;
size_t n;

// Find out how much memory the machine has (npages & npages_basemem).
i386_detect_memory();

// Remove this line when you're ready to test this function.
// panic("mem_init: This function is not finished\n");

//////////////////////////////////////////////////////////////////////
// create initial page directory.
kern_pgdir = (pde_t *) boot_alloc(PGSIZE);
memset(kern_pgdir, 0, PGSIZE);

//////////////////////////////////////////////////////////////////////
// Recursively insert PD in itself as a page table, to form
// a virtual page table at virtual address UVPT.
// (For now, you don't have understand the greater purpose of the
// following line.)

// Permissions: kernel R, user R
kern_pgdir[PDX(UVPT)] = PADDR(kern_pgdir) | PTE_U | PTE_P;

//////////////////////////////////////////////////////////////////////
// Allocate an array of npages 'struct PageInfo's and store it in 'pages'.
// The kernel uses this array to keep track of physical pages: for
// each physical page, there is a corresponding struct PageInfo in this
// array. 'npages' is the number of physical pages in memory. Use memset
// to initialize all fields of each struct PageInfo to 0.
// Your code goes here:
pages = (struct PageInfo*)boot_alloc(npages * sizeof(struct PageInfo));
memset(pages,0,npages * sizeof(struct PageInfo));
//////////////////////////////////////////////////////////////////////
// Now that we've allocated the initial kernel data structures, we set
// up the list of free physical pages. Once we've done so, all further
// memory management will go through the page_* functions. In
// particular, we can now map memory using boot_map_region
// or page_insert
page_init();
check_page_free_list(1);
check_page_alloc();
check_page();
...

}

void
page_init(void)
{
// The example code here marks all physical pages as free.
// However this is not truly the case. What memory is free?
// 1) Mark physical page 0 as in use.
// This way we preserve the real-mode IDT and BIOS structures
// in case we ever need them. (Currently we don't, but...)
// 2) The rest of base memory, [PGSIZE, npages_basemem * PGSIZE)
// is free.
// 3) Then comes the IO hole [IOPHYSMEM, EXTPHYSMEM), which must
// never be allocated.
// 4) Then extended memory [EXTPHYSMEM, ...).
// Some of it is in use, some is free. Where is the kernel
// in physical memory? Which pages are already in use for
// page tables and other data structures?
//
// Change the code to reflect this.
// NB: DO NOT actually touch the physical memory corresponding to
// free pages!
void * kern_used = boot_alloc(0);
size_t i;
for (i = 0; i < npages; i++) {
if(i == 0){
pages[i].pp_ref = 1;
pages[i].pp_link = NULL;
}else if(i < npages_basemem || i < IOPHYSMEM >> PGSHIFT){
pages[i].pp_ref = 0;
pages[i].pp_link = page_free_list;
page_free_list = &pages[i];
}else if(i >= IOPHYSMEM >> PGSHIFT && i < EXTPHYSMEM >> PGSHIFT){
pages[i].pp_ref = 1;
pages[i].pp_link = NULL;
}else if(i <= PADDR(kern_used) >> PGSHIFT){
pages[i].pp_ref = 1;
pages[i].pp_link = NULL;
}else{
pages[i].pp_ref = 0;
pages[i].pp_link = page_free_list;
page_free_list = &pages[i];
}
}
}

struct PageInfo *
page_alloc(int alloc_flags)
{
// Fill this function in
if(page_free_list == NULL)
return NULL;
struct PageInfo *pp = page_free_list;
if(alloc_flags & ALLOC_ZERO){
memset(page2kva(pp), 0, PGSIZE);
}
page_free_list = pp->pp_link;
pp->pp_link = NULL;

return pp;
}

void
page_free(struct PageInfo *pp)
{
// Fill this function in
// Hint: You may want to panic if pp->pp_ref is nonzero or
// pp->pp_link is not NULL.
if(pp->pp_ref != 0 || pp->pp_link != NULL){
panic("page ref is not null");
}
pp->pp_link = page_free_list;
page_free_list = pp;
}

Exercise 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
// Fill this function in
uint32_t pde = pgdir[PDX(va)];
if(!(pde & PTE_P)){
if (!create)return NULL;
struct PageInfo * page = page_alloc(ALLOC_ZERO);
if(page == NULL){
return NULL;
}
page->pp_ref++;
pgdir[PDX(va)] = page2pa(page) | PTE_W | PTE_U | PTE_P;
}

pte_t * pte = (pte_t*)(KADDR(PTE_ADDR((pgdir[PDX(va)])))) + PTX(va);

return pte;
}

static void
boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm)
{
// Fill this function in
for(size_t i = 0;i < size;i+=PGSIZE){
pte_t * pte = pgdir_walk(pgdir,(void*)(va+i),1);
*pte = (pa+i)|perm|PTE_P;
}
}

int
page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm)
{
// Fill this function in
pte_t * pte = pgdir_walk(pgdir,va,1);
if(pte == NULL){
return -E_NO_MEM;
}
pp->pp_ref++;
if((*pte) & PTE_P){
tlb_invalidate(pgdir,va);
page_remove(pgdir,va);
}
*pte = (page2pa(pp) | perm | PTE_P);
return 0;
}

struct PageInfo *
page_lookup(pde_t *pgdir, void *va, pte_t **pte_store)
{
// Fill this function in
pte_t * pte = pgdir_walk(pgdir,va,0);
if(pte == NULL || !(*pte & PTE_P)){
return NULL;
}
if(pte_store != NULL){
pte_store = &pte;
}
struct PageInfo * page = pa2page(PTE_ADDR(*pte));
return page;
}


void
page_remove(pde_t *pgdir, void *va)
{
// Fill this function in
pte_t * pte = pgdir_walk(pgdir,va,0);
struct PageInfo * page = page_lookup(pgdir,va,&pte);
if(page == NULL){
return;
}
page_decref(page);
tlb_invalidate(pgdir,va);
if(pte){
*pte = 0;
}
}

Exercise 5

1
2
3
boot_map_region(kern_pgdir, UPAGES, PTSIZE, PADDR(pages), PTE_U);
boot_map_region(kern_pgdir, KSTACKTOP - KSTKSIZE, KSTKSIZE, PADDR(bootstack), PTE_W);
boot_map_region(kern_pgdir, KERNBASE, (0xffffffff - KERNBASE), 0, PTE_W);

Question

What entries (rows) in the page directory have been filled in at this point? What addresses do they map and where do they point? In other words, fill out this table as much as possible:

Entry Base Virtual Address Points to (logically):
1023 Page table for top 4MB of phys memory
1022 KERN
. 以上都是kernel
960 0xf0000000 KERNBASE
959 0xefc00000 kernel stack
957 0xef400000 UVPT
956 0xef000000 UPAGES
. ? ?
2 0x00800000 ?
1 0x00400000 ?
0 0x00000000 [see next question]