Page 1 of 1

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

Posted: Sun Feb 08, 2015 8:45 pm
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.
 

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

Posted: Sun Feb 08, 2015 9:25 pm
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

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

Posted: Sun Feb 08, 2015 9:31 pm
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.

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

Posted: Sun Feb 08, 2015 10:20 pm
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

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

Posted: Sun Feb 08, 2015 10:29 pm
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.