3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * Based on JamesM's paging tutorial
28 extern unsigned *code
, *bss
, *data
, *end
;
30 // A bitset of frames - used or free.
31 static unsigned page_nframes
;
33 // Amount of RAM Memory in Bytes
34 static unsigned long mem_end_page
;
36 // Static function to set a bit in the frames bitset
37 static void page_set_frame (page_ent_t
*page_cover
, unsigned frame_addr
)
39 unsigned frame
= frame_addr
/ 0x1000;
40 unsigned idx
= index_from_bit (frame
);
41 unsigned off
= offset_from_bit (frame
);
42 page_cover
->frames
[idx
] |= (0x1 << off
);
45 // Static function to clear a bit in the frames bitset
46 static void page_clear_frame (page_ent_t
*page_cover
, unsigned frame_addr
)
48 unsigned frame
= frame_addr
/ 0x1000;
49 unsigned idx
= index_from_bit (frame
);
50 unsigned off
= offset_from_bit (frame
);
51 page_cover
->frames
[idx
] &= ~(0x1 << off
);
54 // Static function to test if a bit is set.
55 static unsigned page_test_frame (page_ent_t
*page_cover
, unsigned frame_addr
)
57 unsigned frame
= frame_addr
/ 0x1000;
58 unsigned idx
= index_from_bit (frame
);
59 unsigned off
= offset_from_bit (frame
);
61 return (page_cover
->frames
[idx
] & (0x1 << off
));
64 // Static function to find the first free frame.
65 static unsigned page_first_frame (page_ent_t
*page_cover
)
68 for (i
= 0; i
< index_from_bit (page_nframes
); i
++) {
69 // nothing free, exit early.
70 if (page_cover
->frames
[i
] != ~0) {
71 // at least one bit is free here.
72 for (j
= 0; j
< 32; j
++) {
73 unsigned toTest
= 0x1 << j
;
75 if (!(page_cover
->frames
[i
] & toTest
))
76 return (i
* 4 * 8 + j
);
84 // Function to allocate a frame.
85 void page_alloc_frame (page_ent_t
*page_cover
, page_t
*page
, int supervisor
, int rw
)
88 return; // Frame was already allocated, return straight away.
90 unsigned idx
= page_first_frame (page_cover
); // idx is now the index of the first free frame.
92 if (idx
== (unsigned) -1) {
93 // PANIC is just a macro that prints a message to the screen then hits an infinite loop.
94 kprintf ("No free frames!");
97 page_set_frame (page_cover
, idx
* 0x1000); // this frame is now ours!
98 page
->present
= 1; // Mark it as present.
99 page
->rw
= (rw
) ? 1 : 0; // Should the page be writeable?
100 page
->user
= (supervisor
) ? 0 : 1; // Should the page be user-mode?
105 // Function to deallocate a frame.
106 void page_free_frame (page_ent_t
*page_cover
, page_t
*page
)
109 if (!(frame
= page
->frame
)) {
110 return; // The given page didn't actually have an allocated frame!
112 page_clear_frame (page_cover
, frame
); // Frame is now free again.
113 page
->frame
= 0x0; // Page now doesn't have a frame.
117 void page_dir_switch (page_dir_t
*page_dir
)
119 #ifdef CONFIG_MEM_PAGING
120 page_cover_curr
= page_dir
;
122 write_cr3 (&page_dir
->tables_phys
); // put that page directory address into CR3
126 page_t
*page_get (page_dir_t
*dir
, unsigned address
, int make
)
128 // Turn the address into an index.
130 // Find the page table containing this address.
131 unsigned table_idx
= address
/ 1024;
133 // If this table is already assigned
134 if (dir
->tables
[table_idx
])
135 return &dir
->tables
[table_idx
]->pages
[address
% 1024];
138 dir
->tables
[table_idx
] = (page_table_t
*) pmalloc_ext (sizeof (page_table_t
), (unsigned *) &tmp
);
140 memset (dir
->tables
[table_idx
], 0, 0x1000);
141 dir
->tables_phys
[table_idx
] = tmp
| 0x7; // PRESENT, RW, US.
143 return &dir
->tables
[table_idx
]->pages
[address
% 1024];
149 page_ent_t
*page_cover_create ()
151 #ifdef CONFIG_MEM_PAGING
152 /* Alloc memory for new page_ent_t * structure */
153 page_ent_t
*page_cover
= (page_ent_t
*) kmalloc (sizeof (page_ent_t
));
158 // Alloc page aligned memory for new page directory
159 page_cover
->page_dir
= (page_dir_t
*) pmalloc (sizeof (page_dir_t
));
161 if (!page_cover
->page_dir
) {
166 memset (page_cover
->page_dir
, 0, sizeof (page_dir_t
));
168 page_cover
->frames
= (unsigned *) kmalloc (index_from_bit (page_nframes
));
170 if (!page_cover
->frames
) {
171 pfree (page_cover
->page_dir
);
176 memset (page_cover
->frames
, 0, index_from_bit (page_nframes
));
184 unsigned page_mmap (page_ent_t
*page_cover
, void *from
, void *to
, unsigned kernel
, unsigned writeable
)
186 #ifdef CONFIG_MEM_PAGING
190 page_cover_curr
= page_cover
->page_dir
;
192 /* There is start address, where we begin mapping */
193 unsigned i
= (unsigned) from
;
195 /* Loop for increase next 4kB of memory from start */
196 while (i
< ((unsigned) to
) ) {
197 page_alloc_frame (page_cover
, page_get (page_cover
->page_dir
, i
, 1), kernel
, writeable
);
204 unsigned page_fault (struct regs
*r
)
206 // A page fault has occurred.
207 // The faulting address is stored in the CR2 register.
208 unsigned faulting_address
;
209 //asm volatile ("movl %%cr2, %0" : "=r" (faulting_address));
210 faulting_address
= 0;
211 // The error code gives us details of what happened.
212 int present
= !(r
->err_code
& 0x1); // Page not present
213 int rw
= r
->err_code
& 0x2; // Write operation?
214 int us
= r
->err_code
& 0x4; // Processor was in user-mode?
215 int reserved
= r
->err_code
& 0x8; // Overwritten CPU-reserved bits of page entry?
216 int id
= r
->err_code
& 0x10; // Caused by an instruction fetch?
218 settextcolor (14, 0);
220 // Output an error message.
221 kprintf ("\nERROR -> page flags: ");
224 kprintf ("present ");
226 kprintf ("read-only ");
228 kprintf ("user-mode ");
230 kprintf ("reserved ");
232 kprintf ("\n\tFault at 0x%x address\n", faulting_address
);
234 return proc_page_fault ();
237 unsigned paging_enable ()
239 #ifdef CONFIG_MEM_PAGING
240 unsigned long flags
= read_cr0 ();
242 if (flags
& PAGING_BIT
)
245 write_cr0 (flags
| PAGING_BIT
); // set the paging bit in CR0 to 1
250 unsigned paging_disable ()
252 #ifdef CONFIG_MEM_PAGING
253 unsigned long flags
= read_cr0 ();
255 if (!(flags
& PAGING_BIT
))
258 flags
&= ~PAGING_BIT
;
260 write_cr0 (flags
); // set the paging bit in CR0 to 0
264 unsigned int init_paging ()
266 #ifdef CONFIG_MEM_PAGING
267 // The size of physical memory.
268 mem_end_page
= mem_ext
* 1024 * 1024;
270 page_nframes
= mem_end_page
/ 0x1000;