faulting when accessing virtual address 0xC000,0000 (64bit)

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
markq
Posts: 24
Joined: Fri Jan 30, 2015 3:42 pm

faulting when accessing virtual address 0xC000,0000 (64bit)

Post by markq »

Hello,

I am in the process of writing my bootloader. I have followed the instructions here on how to enter x64 bit long mode. And then I have mapped virtual address 0xC000,0000 - 0xC020,0000 to 0x0000 - 0x20,0000. I was able to successfully load virtual address 0x4000,0000 but not 0x8000,0000 or any higher addresses. The below code demonstrates what I have done.

Code: Select all

    
; zero out tables
    push edi
    
    mov eax, 0x0
.ZeroOutAllTable:
    mov [edi], eax	;zero out
    add edi, 4			
    cmp edi, 0x900000	
    jb .ZeroOutAllTable

    pop edi


    ;edi contains free memory space which starts at 0x100000
    ; I have set one page table to be at address edi + 0x6000
    ;PML4 at edi
    ;PDPT at edi+0x1000
    ;PD at edi + 0x2000
    ;Page Table at edi + 0x6000

    ; Build the Page Map Level 4.
    ; es:di points to the Page Map Level 4 table.    
    lea eax, [edi + 0x1000]   
    or eax, PAGE_PRESENT | PAGE_WRITE 
    mov [edi], eax                
   
    ; Build the Page Directory Pointer Table.
    
    ; 0x0000,0000 - 0x3FFFF000
    lea eax, [edi + 0x2000]         
    or eax, PAGE_PRESENT | PAGE_WRITE 
    mov [edi + 0x1000], eax       

    ;; 0x4000,0000 - 0x7FFFF000
    lea eax, [edi + 0x2000]
    or eax, PAGE_PRESENT | PAGE_WRITE
    mov [edi + 0x1008], eax

    ;; 0x8000,0000 - 0xBFFFF000
    lea eax, [edi + 0x2000]
    or eax, PAGE_PRESENT | PAGE_WRITE
    mov [edi + 0x1010], eax

    ;; 0xC000,0000 - 0xFFFFF000
    lea eax, [edi + 0x2000]
    or eax, PAGE_PRESENT | PAGE_WRITE
    mov [edi + 0x1018], eax

    ; Build the Page Directory.

    ;; 0x0000,0000 - 0x0020,0000
    lea eax, [edi + 0x6000]        
    or eax, PAGE_PRESENT | PAGE_WRITE 
    mov [edi + 0x2000], eax        

 ; Build the Identity map.
    push edi                           
    lea edi, [edi + 0x6000]             ; Point DI to the page table.
    mov eax, PAGE_PRESENT | PAGE_WRITE    

.LoopIdentityPageTable:
    mov [edi], eax
    add eax, 0x1000
    add edi, 8
    cmp eax, 0x200000                 ; If we did all 2MiB, end.
    jb .LoopIdentityPageTable
 
    pop edi                            ; Restore DI.
 
Last edited by markq on Sun Feb 08, 2015 9:30 pm, edited 1 time in total.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: faulting when accessing virtual address 0xC000,0000 (64b

Post by Brendan »

Hi,

Can you guarantee that the pages you're using are all full of zeros before this code executes? If you can't, then the highest 4 bytes of all (8 byte) table entries may still contain old trash left over from the BIOS or anything else.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
markq
Posts: 24
Joined: Fri Jan 30, 2015 3:42 pm

Re: faulting when accessing virtual address 0xC000,0000 (64b

Post by markq »

Brendan wrote:Hi,

Can you guarantee that the pages you're using are all full of zeros before this code executes? If you can't, then the highest 4 bytes of all (8 byte) table entries may still contain old trash left over from the BIOS or anything else.


Cheers,

Brendan
Hi, I have zero out all the tables. I have added the code from the original. Also, I have written a function called print_hex_in_long_mode which prints out values in hex form. And I can verify that all the tables contain the correct addresses but for some reason it's faulting when I try to print what is in 0xC000,0000. However, no such problem occured when I printed from address 0x4000,0000.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: faulting when accessing virtual address 0xC000,0000 (64b

Post by Brendan »

Hi,
markq wrote:Hi, I have zero out all the tables. I have added the code from the original. Also, I have written a function called print_hex_in_long_mode which prints out values in hex form. And I can verify that all the tables contain the correct addresses but for some reason it's faulting when I try to print what is in 0xC000,0000. However, no such problem occured when I printed from address 0x4000,0000.
Ok.

Taking that into account; I'd expect that your memory map should look like this:
  • 0x00000000 to 0x001FFFFF virtual = 0x00000000 to 0x001FFFFF physical
    0x40000000 to 0x401FFFFF virtual = 0x00000000 to 0x001FFFFF physical
    0x80000000 to 0x801FFFFF virtual = 0x00000000 to 0x001FFFFF physical
    0xC0000000 to 0xC01FFFFF virtual = 0x00000000 to 0x001FFFFF physical
I see no cause for the symptoms you've described.

With that in mind; I suspect the problem is elsewhere - either something trashing memory afterwards, segment limits being dodgy (impossible if you are in long mode), or faulty tests giving a "false negative" result...

Further; I'd assume that the most likely problem is faulty testing. Specifically; my guess is that 0xC0000000 is being signed extended from 32-bit to 64-bit and you're actually trying to access 0xFFFFFFFF40000000.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
markq
Posts: 24
Joined: Fri Jan 30, 2015 3:42 pm

Re: faulting when accessing virtual address 0xC000,0000 (64b

Post by markq »

Brendan wrote:Hi,
markq wrote:Hi, I have zero out all the tables. I have added the code from the original. Also, I have written a function called print_hex_in_long_mode which prints out values in hex form. And I can verify that all the tables contain the correct addresses but for some reason it's faulting when I try to print what is in 0xC000,0000. However, no such problem occured when I printed from address 0x4000,0000.
Ok.

Taking that into account; I'd expect that your memory map should look like this:
  • 0x00000000 to 0x001FFFFF virtual = 0x00000000 to 0x001FFFFF physical
    0x40000000 to 0x401FFFFF virtual = 0x00000000 to 0x001FFFFF physical
    0x80000000 to 0x801FFFFF virtual = 0x00000000 to 0x001FFFFF physical
    0xC0000000 to 0xC01FFFFF virtual = 0x00000000 to 0x001FFFFF physical
I see no cause for the symptoms you've described.

With that in mind; I suspect the problem is elsewhere - either something trashing memory afterwards, segment limits being dodgy (impossible if you are in long mode), or faulty tests giving a "false negative" result...

Further; I'd assume that the most likely problem is faulty testing. Specifically; my guess is that 0xC0000000 is being signed extended from 32-bit to 64-bit and you're actually trying to access 0xFFFFFFFF40000000.


Cheers,

Brendan
Hi,

I have found the issue. It seems that 0xc000,0000 has "exceed data word limit" according to nasm and could not be directly loaded. Even though there is this issue nasm still compiles. I was sloppy not spotting the warning when compiling. In the end, I had to use a place holder resgister to fix this. Thanks for the help anyways.
Post Reply