Page 1 of 1
Can't access VESA LFB without getting page fault
Posted: Fri May 20, 2016 2:34 pm
by codyd51
Whenever I try to write a pixel to the LFB in VESA mode, I get a page fault (page present, read). My paging implementation is from James Molloy's OS series. I've tried identity mapping the LFB as follows:
Code: Select all
for (unsigned int i = 0xFD000000; i < 0xFE000000; i += 0x1000) {
page_t* pg = get_page(i, 1, kernel_directory);
alloc_page(pg, 1, 1);
}
These are the prototypes for those functions:
Code: Select all
page_t* get_page(uint32_t address, int make, page_directory_t* dir);
void alloc_frame(page_t* page, int is_kernel, int is_writeable);
When paging is disabled, I'm able to write pixels to the LFB without issue.
Am I identity mapping the LFB incorrectly? Is there something else I need to do to identity map it correctly? Feel free to let me know if you need any more of the implementation. Thanks!
Re: Can't access VESA LFB without getting page fault
Posted: Fri May 20, 2016 3:25 pm
by BrightLight
Do you flush caches after modifying the page tables? Use INVLPG instruction, or simply do:
What error code does your page fault have?
Re: Can't access VESA LFB without getting page fault
Posted: Fri May 20, 2016 5:00 pm
by max
Invalidating might help as omar said, but to tell you for sure you'd have to show us what the functions you call there do.
Re: Can't access VESA LFB without getting page fault
Posted: Fri May 20, 2016 7:10 pm
by codyd51
The page fault still happens even after flushing the cache :/ error code 2.
Here's the implementation of those two functions:
Code: Select all
page_t* get_page(uint32_t address, int make, page_directory_t* dir) {
//turn address into an index
address /= 0x1000;
//find page table containing this address
uint32_t table_idx = address / 1024;
//if this page is already assigned
if (dir->tables[table_idx]) {
return &dir->tables[table_idx]->pages[address%1024];
}
else if (make) {
uint32_t tmp;
dir->tables[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp);
memset(dir->tables[table_idx], 0, 0x1000);
//PRESENT, RW, US
dir->tablesPhysical[table_idx] = tmp | 0x7;
return &dir->tables[table_idx]->pages[address%1024];
}
return 0;
}
void alloc_frame(page_t* page, int is_kernel, int is_writeable) {
if (page->frame != 0) {
//frame was already allocated, return early
return;
}
uint32_t idx = first_frame(); //index of first free frame
if (idx == (uint32_t)-1) {
PANIC("No free frames!");
}
set_frame(idx*0x1000); //frame is now ours
page->present = 1; //mark as present
page->rw = (is_writeable) ? 1 : 0; //should page be writable?
page->user = (is_kernel) ? 0 : 1; //should page be user mode?
page->frame = idx;
}
Re: Can't access VESA LFB without getting page fault
Posted: Fri May 20, 2016 7:18 pm
by codyd51
If I mov the regs in the order from omarrx024's comment, the page fault still occurs. If I use the order listed on
http://wiki.osdev.org/TLB, it triple faults.
Re: Can't access VESA LFB without getting page fault
Posted: Fri May 20, 2016 8:54 pm
by BrightLight
codyd51 wrote:If I mov the regs in the order from omarrx024's comment, the page fault still occurs. If I use the order listed on
http://wiki.osdev.org/TLB, it triple faults.
In the TLB Wiki page, it is in GAS syntax, not Intel syntax. The code there is the same as my code but in different syntax.
Error code 2 says that the kernel tried to write to a non-present page. So either your page directory or your page table entry doesn't has the present bit set.
Re: Can't access VESA LFB without getting page fault
Posted: Sun May 22, 2016 9:18 am
by codyd51
omarrx024 wrote:codyd51 wrote:If I mov the regs in the order from omarrx024's comment, the page fault still occurs. If I use the order listed on
http://wiki.osdev.org/TLB, it triple faults.
In the TLB Wiki page, it is in GAS syntax, not Intel syntax. The code there is the same as my code but in different syntax.
Error code 2 says that the kernel tried to write to a non-present page. So either your page directory or your page table entry doesn't has the present bit set.
Whoops! Silly me
I finally figured it out, I call the following function in my init_paging function. Not totally sure why it doesn't work after paging is already enabled and flushing the TLB cache, but oh well:
Code: Select all
#define VESA_WIDTH 1024
#define VESA_HEIGHT 768
void identity_map_lfb(uint32_t location) {
uint32_t j = location;
while (j < location + (VESA_WIDTH * VESA_HEIGHT * 4)) {
//if frame is valid
if (j + location + (VESA_WIDTH * VESA_HEIGHT * 4) < memsize) {
set_frame(j); //tell frame bitset this frame is in use
}
//get page
page_t* page = get_page(j, 1, kernel_directory);
//fill it
page->present = 1;
page->rw = 1;
page->user = 1;
page->frame = j / 0x1000;
j += 0x1000;
}
}
And it'd be called with:
identity_map_lfb(your_vesa_mode_info->physbase);
I hope this helps someone having the same problem!