@@ -2,71 +2,78 @@ use core::mem::size_of;
2
2
3
3
use kernel:: console;
4
4
use arch:: idt;
5
+ use memory:: allocator;
5
6
6
7
static PAGE_SIZE : u32 = 0x1000 ;
7
8
9
+ static NUM_ENTRIES : u32 = 1024 ;
10
+
8
11
#[ packed]
9
12
struct Page ( u32 ) ;
10
13
11
14
#[ packed]
12
15
struct PageTable {
13
- pages : [ Page , ..1024 ]
16
+ entries : [ Page , ..NUM_ENTRIES ]
14
17
}
15
18
16
- #[ packed]
17
- struct PageDirectory {
18
- tables : [ u32 , ..1024 ]
19
- }
19
+ static mut kernel_directory: * mut PageTable = 0xFFFFF000 as * mut PageTable ;
20
+ static PAGES : u32 = 0xFFC00000 ;
20
21
21
- static mut kernel_directory: * mut PageDirectory = 0 as * mut PageDirectory ;
22
+ pub static FLAG_PRESENT : u32 = 1 << 0 ;
23
+ pub static FLAG_WRITE : u32 = 1 << 1 ;
24
+ pub static FLAG_USER : u32 = 1 << 2 ;
22
25
23
- static NO_FLAGS : u32 = 0 ;
24
- static FLAG_PRESENT : u32 = 1 << 0 ;
25
- static FLAG_WRITE : u32 = 1 << 1 ;
26
- static FLAG_USER : u32 = 1 << 2 ;
27
-
28
- static mut next_frame: u32 = 0 ;
29
- fn get_next_frame ( ) -> u32 {
26
+ pub fn init ( ) {
30
27
unsafe {
31
- let frame = next_frame;
32
- next_frame += 1 ;
33
- frame
28
+ let directory = allocator:: allocate_frame ( ) as * mut PageTable ;
29
+ * directory = PageTable :: empty ( ) ;
30
+
31
+ let table = allocator:: allocate_frame ( ) as * mut PageTable ;
32
+ * table = PageTable :: empty ( ) ;
33
+
34
+ // Identity map table the whole table, 4MB
35
+ let mut i = 0 ;
36
+ while i < PAGE_SIZE * NUM_ENTRIES {
37
+ let page = ( * table) . get_page ( i) ;
38
+ page. set ( i, FLAG_PRESENT | FLAG_WRITE ) ;
39
+ i += PAGE_SIZE ;
40
+ }
41
+
42
+ ( * directory) . set_entry ( 0 , table, FLAG_PRESENT | FLAG_WRITE ) ;
43
+
44
+ // Map the directory itself as the last entry
45
+ ( * directory) . set_entry ( dir_index ( kernel_directory as u32 ) , directory, FLAG_PRESENT | FLAG_WRITE ) ;
46
+
47
+ idt:: register_isr_handler ( 14 , page_fault) ;
48
+
49
+ switch_page_directory ( unsafe { directory } ) ;
34
50
}
35
51
}
36
52
37
- pub fn init ( ) {
53
+ pub fn map ( addr : u32 , size : u32 , flags : u32 ) {
38
54
unsafe {
39
- kernel_directory = box_alloc ( PageDirectory :: new ( ) ) ;
40
- }
55
+ // FIXME: We assume the table doesn't exist and it can hold the whole size
56
+ let directory_index = dir_index ( addr ) ;
41
57
42
- // Identity map all currently used memory
43
- let mut i = 0 ;
44
- // We don't currently have a real malloc so just use some extra space
45
- while i < unsafe { placement_address + PAGE_SIZE * 10 } {
46
- let page = unsafe { ( * kernel_directory) . get_page ( i) } ;
47
- page. set ( get_next_frame ( ) * PAGE_SIZE , FLAG_PRESENT | FLAG_WRITE ) ;
48
- i += PAGE_SIZE ;
49
- }
58
+ let table_physical = allocator:: allocate_frame ( ) as * mut PageTable ;
59
+ ( * kernel_directory) . set_entry ( directory_index, table_physical, FLAG_PRESENT | flags) ;
50
60
51
- idt:: register_isr_handler ( 14 , page_fault) ;
61
+ let table = page_table ( directory_index) ;
62
+ // Flush table so we can write to its virtual address
63
+ flush_tlb ( table) ;
52
64
53
- switch_page_directory ( unsafe { kernel_directory } ) ;
54
- }
65
+ * table = PageTable :: empty ( ) ;
55
66
56
- pub fn map ( addr : u32 , size : u32 ) {
57
- let mut current_addr = addr;
58
- while current_addr < addr + size {
59
- let page = unsafe { ( * kernel_directory) . get_page ( current_addr) } ;
60
- page. set ( get_next_frame ( ) * PAGE_SIZE , FLAG_PRESENT | FLAG_WRITE ) ;
61
- flush_tlb ( current_addr) ;
67
+ let mut current_addr = addr;
68
+ while current_addr < addr + size {
69
+ let page = ( * table) . get_page ( current_addr) ;
62
70
63
- current_addr += PAGE_SIZE ;
64
- }
71
+ page . set ( allocator :: allocate_frame ( ) , FLAG_PRESENT | FLAG_WRITE ) ;
72
+ flush_tlb ( current_addr ) ;
65
73
66
- console:: write_str ( "Mapping: " ) ;
67
- console:: write_hex ( addr) ;
68
- console:: write_newline ( ) ;
69
- //reload_page_directory();
74
+ current_addr += PAGE_SIZE ;
75
+ }
76
+ }
70
77
}
71
78
72
79
fn page_fault ( regs : & idt:: Registers ) {
@@ -110,66 +117,40 @@ impl Page {
110
117
111
118
impl PageTable {
112
119
fn empty ( ) -> PageTable {
113
- PageTable { pages : [ Page :: empty ( ) , ..1024 ] }
120
+ PageTable { entries : [ Page :: empty ( ) , ..NUM_ENTRIES ] }
114
121
}
115
- }
116
122
117
- impl PageDirectory {
118
- fn new ( ) -> PageDirectory {
119
- PageDirectory {
120
- tables : [ 0 , ..1024 ]
121
- }
123
+ unsafe fn set_entry < T > ( & mut self , index : u32 , entry : * mut T , flags : u32 ) {
124
+ self . entries [ index] = Page ( entry as u32 | flags) ;
122
125
}
123
126
124
- unsafe fn get_table ( & mut self , address : u32 ) -> * mut PageTable {
125
- let table_index = address / ( 4096 * 1024 ) ;
126
-
127
- /*console::write_str("Table index: ");
128
- console::write_num(table_index);
129
- console::write_newline();*/
130
-
131
- if to_addr ( self . tables [ table_index] ) == 0 {
132
- //console::write_str("does not exists\n");
133
- let table = box_alloc ( PageTable :: empty ( ) ) ;
134
-
135
-
136
-
137
- self . tables [ table_index] = table as u32 | FLAG_PRESENT | FLAG_WRITE | FLAG_USER ;
138
- table
139
- } else {
140
- //console::write_str("exists\n");
141
- to_addr ( self . tables [ table_index] ) as * mut PageTable
142
- }
127
+ unsafe fn get_page < ' a > ( & ' a mut self , addr : u32 ) -> & ' a mut Page {
128
+ & ' a mut self . entries [ table_index ( addr) ]
143
129
}
130
+ }
144
131
145
- unsafe fn get_page ( & mut self , address : u32 ) -> & mut Page {
146
- let table = self . get_table ( address) ;
147
-
148
- let page_index = address / 4096 ;
149
-
150
- /*console::write_str("Page index: ");
151
- console::write_num(page_index % 1024);
152
- console::write_newline();*/
132
+ fn page_table ( index : u32 ) -> * mut PageTable {
133
+ let size = size_of :: < PageTable > ( ) as u32 ;
134
+ ( PAGES + index * size) as * mut PageTable
135
+ }
153
136
154
- & mut ( * table) . pages [ page_index % 1024 ]
155
- }
137
+ fn dir_index ( addr : u32 ) -> u32 {
138
+ addr / ( PAGE_SIZE * NUM_ENTRIES )
139
+ }
156
140
157
- unsafe fn get_physical ( & mut self , address : u32 ) -> u32 {
158
- let page = self . get_page ( address) ;
159
- page. addr ( ) + ( address % 1024 )
160
- }
141
+ fn table_index ( addr : u32 ) -> u32 {
142
+ ( addr / PAGE_SIZE ) % NUM_ENTRIES
161
143
}
162
144
163
- fn flush_tlb ( addr : u32 ) {
145
+ fn flush_tlb < T > ( addr : T ) {
164
146
unsafe {
165
- asm ! ( "invlpg ($0)" :: "r" ( addr) : "volatile memory" ) ;
147
+ asm ! ( "invlpg ($0)" :: "r" ( addr) : "volatile" , " memory") ;
166
148
}
167
149
}
168
150
169
- fn switch_page_directory ( directory : * mut PageDirectory ) {
151
+ fn switch_page_directory ( directory : * mut PageTable ) {
170
152
unsafe {
171
- let address = ( * directory) . get_physical ( directory as u32 ) ;
172
- write_cr3 ( address) ;
153
+ write_cr3 ( directory as u32 ) ;
173
154
// Set the paging bit in CR0 to 1
174
155
write_cr0 ( read_cr0 ( ) | 0x80000000 ) ;
175
156
}
@@ -202,28 +183,3 @@ unsafe fn read_cr0() -> u32 {
202
183
unsafe fn write_cr0 ( value : u32 ) {
203
184
asm ! ( "mov $0, %cr0" :: "r" ( value) :: "volatile" ) ;
204
185
}
205
-
206
- #[ inline]
207
- unsafe fn box_alloc < T > ( value : T ) -> * mut T {
208
- let size = size_of :: < T > ( ) ;
209
- let ptr = alloc :: < T > ( size as u32 ) ;
210
- * ptr = value;
211
- ptr
212
- }
213
-
214
- static mut placement_address: u32 = 0 ;
215
- unsafe fn alloc < T > ( size : u32 ) -> * mut T {
216
- if placement_address == 0 {
217
- extern { static kernel_end: u32 ; }
218
- placement_address = ( & kernel_end as * u32 ) as u32 ;
219
- }
220
-
221
- if placement_address & !0xfff != 0 {
222
- placement_address &= !0xfff ;
223
- placement_address += 0x1000 ;
224
- }
225
-
226
- let address = placement_address;
227
- placement_address += size;
228
- address as * mut T
229
- }
0 commit comments