I think I asked you on another site some time back if you were using paging and whether you had mapped the framebuffer into virtual memory. I believe you said you were using paging. I recommend taking your entire project and putting it on Github including make files, build script, source (everything to reproduce your problem) and provide a link.
Note: Just learned on Stackoverflow that this is also 64-bit code running in long mode so paging must be enabled. The code on Stackoverflow for paging that you gave was:
Code: Select all
setup_page_tables:
mov eax, page_table_l3
or eax, 0b11 ; present, writable
mov [page_table_l4], eax
mov eax, page_table_l2
or eax, 0b11 ; present, writable
mov [page_table_l3], eax
mov ecx, 0 ; counter
.loop:
mov eax, 0x200000 ; 2MiB
mul ecx
or eax, 0b10000011 ; present, writable, huge page
mov [page_table_l2 + ecx * 8], eax
inc ecx ; increment counter
cmp ecx, 512 ; checks if the whole table is mapped
jne .loop ; if not, continue
ret
enable_paging:
; pass page table location to cpu
mov eax, page_table_l4
mov cr3, eax
; enable PAE
mov eax, cr4
or eax, 1 << 5
mov cr4, eax
; enable long mode
mov ecx, 0xC0000080
rdmsr
or eax, 1 << 8
wrmsr
; enable paging
mov eax, cr0
or eax, 1 << 31
mov cr0, eax
ret
setup_page_tables is only mapping the first 1GiB of memory (512 * 2MiB) into virtual address space (one to one mapping from virtual to physical). One serious problem is that the frame buffer is at 0xFD000000 which is well above 1GiB (but below 4GiB). Any access to 0xFD000000 memory region would almost certainly cause a page fault since that memory hasn't been mapped. To fix this you'd have to map the frame buffer into memory. It may be just easier to map the entire first 4GiB into virtual memory. I also assume from the way the page tables are set up that you are running your kernel in the lower half of memory (below 1GiB) and are not using a higher-half kernel.
From your other questions it appears you are using QEMU to test. I'd recommend for debugging purposes running QEMU with the
-d int -no-reboot -no-shutdown options. '-d int' would allow you to see the exceptions and interrupts thrown and you'd likely find access to frame buffer memory throwing a page fault (v=0e).
I am taking a guess as to how things are in your code (I have to guess with the absence of any additional code), but to map the entire first 4 GiB (one to one virtual to physical) you can change the code to:
Code: Select all
setup_page_tables:
mov dword [page_table_l4], page_table_l3 + 0b11 ; present, writable
mov dword [page_table_l3 + 0*8], (page_table_l2 + 0x1000*0) + 0b11 ; First GiB present, writable
mov dword [page_table_l3 + 1*8], (page_table_l2 + 0x1000*1) + 0b11 ; Second GiB present, writable
mov dword [page_table_l3 + 2*8], (page_table_l2 + 0x1000*2) + 0b11 ; Third GiB present, writable
mov dword [page_table_l3 + 3*8], (page_table_l2 + 0x1000*3) + 0b11 ; Fourth GiB present, writable
mov ecx, 0 ; counter
.loop:
mov eax, 0x200000 ; 2MiB
mul ecx
or eax, 0b10000011 ; present, writable, huge page
mov [page_table_l2 + ecx * 8], eax
inc ecx ; increment counter
cmp ecx, 512*4 ; checks if the first 4 page directories are mapped
jne .loop ; if not, continue
ret
In order for this code to work you will have change code I figure looks something like
to
. The idea is to create 4 level_2 page tables (page directories) and populate the first 4 entries of the level_3 page table (page directory pointer table). In the code the loop was extended to go to 512*4 instead of 512. The effect is we filled in 4 page directory tables with the one loop.
These changes should identity map (one to one mapping virtual to physical) the first 4GiB, and any framebuffer below 4GiB should be accessible including at 0xFD000000. There may be other issues with the code but I can't tell you because I don't have access to anything beyond what you show.
Side note: If your system supported 1GiB pages this could be simplified with just a Level 4 page table (PML4) and a Level 3 page table (PDPT) if you used the 1GiB paging feature.