1
1
#include "page_table.h"
2
2
3
3
#include "../loader.h"
4
+ #include "../multiboot_utils.h"
4
5
6
+ uint32_t free_pages ;
7
+
8
+ #define PAGE_DIRECTORY_OFFSET_BITS 10
9
+ #define PAGE_TABLE_OFFSET_BITS 10
10
+ #define PAGE_OFFSET_BITS 12
11
+
12
+ #define PAGE_SIZE_BYTES 4096
13
+ #define PAGE_SIZE_DWORDS 1024
14
+
15
+ // #define BITMAP_SIZE 32768
16
+ // Enough room for 512 MB of RAM
17
+ // TODO: Find a more efficient way to initialize page allocator
18
+ #define BITMAP_SIZE 4096
19
+ uint32_t free_page_bitmap [BITMAP_SIZE ];
20
+
21
+ uint32_t page_number (uint32_t address );
5
22
enum page_size_t {FOUR_KB , FOUR_MB };
6
23
enum page_privilege_t {SUPERVISOR , USER };
7
24
enum page_permissions_t {READ_ONLY , READ_WRITE };
8
25
9
- struct page_directory_entry_t {
10
- uint32_t page_table_address ;
11
- } __attribute__((packed ));
12
-
13
26
uint32_t make_page_directory_entry (
14
- uint32_t page_table_address ,
27
+ void * page_table_physical_address ,
15
28
enum page_size_t page_size ,
16
29
bool cache_disabled ,
17
30
bool write_through ,
18
31
enum page_privilege_t privelage ,
19
32
enum page_permissions_t permissions ,
20
33
bool present
21
34
) {
22
- uint32_t entry = page_table_address ;
35
+ log ("make_page_directory_entry()\n" );
36
+ uint32_t entry = (uint32_t ) page_table_physical_address ;
23
37
entry |= page_size << 7 ;
24
38
entry |= cache_disabled << 4 ;
25
39
entry |= write_through << 3 ;
@@ -31,15 +45,15 @@ uint32_t make_page_directory_entry(
31
45
}
32
46
33
47
uint32_t make_page_table_entry (
34
- uint32_t page_frame_address ,
48
+ void * page_frame_address ,
35
49
bool global ,
36
50
bool cache_disabled ,
37
51
bool write_through ,
38
52
enum page_privilege_t privelage ,
39
53
enum page_permissions_t permissions ,
40
54
bool present
41
55
) {
42
- uint32_t entry = page_frame_address ;
56
+ uint32_t entry = ( uint32_t ) page_frame_address ;
43
57
entry |= global << 8 ;
44
58
entry |= cache_disabled << 6 ;
45
59
entry |= write_through << 3 ;
@@ -50,12 +64,104 @@ uint32_t make_page_table_entry(
50
64
return entry ;
51
65
}
52
66
67
+ void mark_free (uint32_t page_number );
68
+ void mark_unavailable (uint32_t page_number );
69
+
53
70
// 1 page = 1024 * 4 bytes = 4 kB
54
71
// 1 page table = 1024 pages = 4 mB
55
72
// 1 page directory = 1024 page tables = 4 gB
56
73
74
+ void * allocate_physical_page () {
75
+ // log("allocate_physical_page()\n");
76
+ for (uint32_t index = 0 ; index < BITMAP_SIZE ; index ++ ) {
77
+ // log("allocate_physical_page() index ");
78
+ // print_uint32(LOG, index);
79
+ // log("\n");
80
+ if (free_page_bitmap [index ] != 0 ) {
81
+ for (uint8_t bit = 0 ; bit < 32 ; bit ++ ) {
82
+ // log("allocate_physical_page() bit ");
83
+ // print_uint32(LOG, bit);
84
+ // log("\n");
85
+ if ((free_page_bitmap [index ] & (1 << bit )) != 0 ) {
86
+ uint32_t page_number = index * 32 + bit ;
87
+ mark_unavailable (page_number );
88
+ uint32_t * page_start = (uint32_t * ) (page_number << 12 );
89
+ // for (uint32_t i = 0; i < PAGE_SIZE_DWORDS; i++) {
90
+ // page_start[i] = 0;
91
+ // }
92
+ return (void * ) page_start ;
93
+ }
94
+ }
95
+ }
96
+ }
97
+ return 0 ;
98
+ }
99
+
100
+ void * page_table_virtual_address (uint32_t page_number ) {
101
+ uint32_t virtual_address = page_number << PAGE_OFFSET_BITS ;
102
+ virtual_address |= 0xFFC00000 ;
103
+ return (void * ) virtual_address ;
104
+ }
105
+
57
106
page_directory_t initialize_page_directory () {
58
107
page_directory_t pd = (page_directory_t ) & BootPageDirectory ;
108
+ log ("pd: " );
109
+ print_uint32 (LOG , (uint32_t ) pd );
110
+ log ("\n" );
111
+
112
+ // Make the last entry in the pd a pointer to itself
113
+ log ("Setting last entry in page directory.\n" );
114
+ uint32_t pde = make_page_directory_entry (
115
+ (void * ) & BootPageDirectoryPhysicalAddress ,
116
+ FOUR_KB ,
117
+ false,
118
+ false,
119
+ SUPERVISOR ,
120
+ READ_WRITE ,
121
+ true
122
+ );
123
+ log ("pde: " );
124
+ print_uint32 (LOG , pde );
125
+ log ("\n" );
126
+ pd [1023 ] = pde ;
127
+
128
+ // dedicate one page table for memory for the kernel
129
+ void * page_table_physical_address = allocate_physical_page ();
130
+ log ("allocated physical memory for page table: " );
131
+ print_uint32 (LOG , (uint32_t ) page_table_physical_address );
132
+ log ("\n" );
133
+ pd [768 ] = make_page_directory_entry (
134
+ page_table_physical_address ,
135
+ FOUR_KB ,
136
+ false,
137
+ false,
138
+ SUPERVISOR ,
139
+ READ_WRITE ,
140
+ true
141
+ );
142
+
143
+ // From here on out, we can access present page tables by setting the
144
+ // upper bits of the address to 0xFFFFF
145
+ page_table_t pt = (page_table_t ) page_table_virtual_address (768 );
146
+ log ("page_table virtual address: " );
147
+ print_uint32 (LOG , (uint32_t ) pt );
148
+ log ("\n" );
149
+ for (uint32_t i = 0 ; i < 1024 ; i ++ ) {
150
+ void * page_base = allocate_physical_page ();
151
+ // log("allocated physical memory for a kernel page: ");
152
+ // print_uint32(LOG, (uint32_t) page_base);
153
+ // log("\n");
154
+ pt [i ] = make_page_table_entry (
155
+ page_base ,
156
+ false,
157
+ false,
158
+ false,
159
+ SUPERVISOR ,
160
+ READ_WRITE ,
161
+ true
162
+ );
163
+ }
164
+
59
165
return pd ;
60
166
}
61
167
@@ -71,3 +177,77 @@ void print_page_directory(FILE stream, page_directory_t pd) {
71
177
}
72
178
}
73
179
}
180
+
181
+ uint32_t round_up_to_nearest_page_start (uint32_t address ) {
182
+ if ((address & 0xFFF ) != 0 ) {
183
+ address &= 0xFFFFF000 ;
184
+ address += 0x00001000 ;
185
+ }
186
+ return address ;
187
+ }
188
+
189
+ uint32_t round_down_to_nearest_page_start (uint32_t address ) {
190
+ if ((address & 0xFFF ) != 0 ) {
191
+ address &= 0xFFFFF000 ;
192
+ address -= 0x00001000 ;
193
+ }
194
+ return address ;
195
+ }
196
+
197
+ uint32_t page_number (uint32_t address ) {
198
+ return address >> 12 ;
199
+ }
200
+
201
+ void mark_free (uint32_t page_number ) {
202
+ uint32_t index = page_number >> 5 ;
203
+ uint32_t bit = page_number & 0b11111 ;
204
+ uint32_t value = free_page_bitmap [index ];
205
+ value |= (1 << bit );
206
+ free_page_bitmap [index ] = value ;
207
+ free_pages ++ ;
208
+ }
209
+
210
+ void mark_unavailable (uint32_t page_number ) {
211
+ uint32_t index = page_number >> 5 ;
212
+ uint32_t bit = page_number & 0b11111 ;
213
+ uint32_t value = free_page_bitmap [index ];
214
+ value &= ~(1 << bit );
215
+ free_page_bitmap [index ] = value ;
216
+ free_pages -- ;
217
+ }
218
+
219
+ uint32_t initialize_page_allocator (struct kernel_memory_descriptor_t kernel_memory , multiboot_info_t * mbinfo ) {
220
+ memory_map_t * memory_map = (memory_map_t * ) p_to_v (mbinfo -> mmap_addr );
221
+ uint32_t num_entries = mbinfo -> mmap_length / sizeof (memory_map_t );
222
+
223
+ for (uint32_t i = 0 ; i < num_entries ; i ++ ) {
224
+ if (memory_map [i ].type == 1 ) {
225
+ // Available
226
+ uint32_t first_addr = memory_map [i ].base_addr_low ;
227
+ uint32_t one_past_last_addr = first_addr + memory_map [i ].length_low ;
228
+ uint32_t first_full_page = page_number (round_up_to_nearest_page_start (first_addr ));
229
+ uint32_t one_past_last_full_page = page_number (round_down_to_nearest_page_start (one_past_last_addr ));
230
+
231
+ for (uint32_t i = first_full_page ; i < one_past_last_full_page ; i ++ ) {
232
+ mark_free (i );
233
+ }
234
+ } else {
235
+ // Unavailable
236
+ }
237
+ }
238
+
239
+ uint32_t first_partial_page = page_number (round_down_to_nearest_page_start (kernel_memory .kernel_physical_start ));
240
+ uint32_t one_past_last_partial_page = page_number (round_up_to_nearest_page_start (kernel_memory .kernel_physical_end ));
241
+
242
+ for (uint32_t i = first_partial_page ; i < one_past_last_partial_page ; i ++ ) {
243
+ mark_unavailable (i );
244
+ }
245
+
246
+ // for(uint16_t i = 0; i < BITMAP_SIZE; i++) {
247
+ // print_uint16(LOG, i);
248
+ // print_uint32(LOG, free_page_bitmap[i]);
249
+ // log("\n");
250
+ // }
251
+
252
+ return free_pages ;
253
+ }
0 commit comments