OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 11:12 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 13 posts ] 
Author Message
 Post subject: CR3 changes to 0 on jump
PostPosted: Fri Aug 31, 2018 11:22 am 
Offline
User avatar

Joined: Thu Jul 19, 2018 9:40 pm
Posts: 24
I've been trying to switch to a higher half kernel but can't seem to figure out paging. I've been reading the wiki page on it as well as the Intel manual.
Can someone help me figure out how to do it correctly?

I've came up with the following algorithm for setting up the structures:
Code:
;[pd + VIRT_BASE >> 22] = pt | flags
;[pd] = pt_low | flags

;while i < ro_end
;   [pt_low + i >> 12 & 0x03FF] = i | flags
;   i += 0x1000
;end
;while i < rw_end
;   [pt_low + i >> 12 & 0x03FF] = i | flags
;   i += 0x1000
;end
;i = 0
;while i < ro_end
;   [pt_high + (VIRT_BASE + i) >> 12 & 0x03FF] = i | flags
;   i += 0x1000
;end
;while i < rw_end
;   [pt_high + (VIRT_BASE + i) >> 12 & 0x03FF] = i | flags
;   i += 0x1000
;end


Although it doesn't seem to have been working (or I implemented it incorrectly)

My code is here: https://github.com/the-sushi/os
And the relevant parts are here: https://github.com/the-sushi/os/blob/ma ... 6/boot.asm

I'm not exactly aiming for the most efficient code here yet, I'll try cleaning it up and making it into routines after I can get it working at all.

Can someone please help get me onto the right path? Also, what is the PAT bit of a page directory table entry supposed to be? Intel's manual was a bit confusing in this regard.

Thanks,
~Ender


Last edited by Ender on Wed Sep 12, 2018 4:20 pm, edited 3 times in total.

Top
 Profile  
 
 Post subject: Re: Need help with higher half / paging
PostPosted: Fri Aug 31, 2018 5:21 pm 
Offline
User avatar

Joined: Thu Jul 19, 2018 9:40 pm
Posts: 24
Tried again, with an edited algorithm.
This time the relevant code is small enough that I don't feel too bad putting it into a single post:
Code:
      lea eax, [page_table - VIRT_BASE]
   mov ebx, PT_PRESENT

.fill_ro:
   mov [eax], ebx ;insert entry
   add eax, 4 ;next entry
   add ebx, PAGE_SIZE ;next mem address
   cmp ebx, (ro_end - VIRT_BASE)
   jl .fill_ro

   or ebx, PT_READWRITE
.fill_rw:
   mov [eax], ebx
   add eax, 4
   add ebx, PAGE_SIZE
   cmp ebx, (rw_end - VIRT_BASE)
   jl .fill_rw

;done with page table
   lea ebx, [page_table - VIRT_BASE]
   or ebx, PD_PRESENT | PD_READWRITE

   lea eax, [page_dir - VIRT_BASE] ;load page dir
   mov dword [eax], ebx
   add eax, PD_INDEX
   mov dword [eax], ebx

   xchg bx, bx ;bochs breakpoint
   lea eax, [page_dir - VIRT_BASE]
   mov cr3, eax

   mov eax, cr4
   or eax, 0x00000010 ;enable PSE (4MiB pages)
   mov cr4, eax

   mov eax, cr0
   or eax, 0x80010001 ;enable paging, WP, PE
   mov cr0, eax

   lea eax, [higher_half_start]
   jmp eax


I still can't figure out what exactly I'm doing wrong though

Relevant bochs stuff:
Code:
CPU 0: Exception 0x0e - (#PF) page fault occured (error_code=0x0000)
CPU 0: Interrupt 0x0e occured (error_code=0x0000)
CPU 0: Exception 0x0d - (#GP) general protection fault occured (error_code=0x0073)
CPU 0: Exception 0x08 - (#DF) double fault occured (error_code=0x0000)
CPU 0: Interrupt 0x08 occured (error_code=0x0000)
CPU 0: Exception 0x0d - (#GP) general protection fault occured (error_code=0x0043)


This occurs after the "mov cr0, eax" (obviously).


Top
 Profile  
 
 Post subject: Re: Need help with higher half / paging
PostPosted: Sat Sep 01, 2018 1:13 am 
Offline

Joined: Sun Jul 01, 2018 11:13 am
Posts: 8
Paging has several levels, you have to fill up the whole table. Only the last level points to physical memory for data, upper levels point to other page tables, and CR3 points to the root of the tree.

In bochs debug console use "page X" to travese the tree for virtual address X. It will show you where the error is. If everything is right, you should see 4 levels and a message "Address X translates to physical page Y".

This is how I do it:
Code:
            ; -------- paging ---------
            ;map core at higher half of memory
            ;to address 0xffffffffffe00000
            xor         eax, eax
            mov         edi, 0A000h
            mov         ecx, (15000h-0A000h)/4
            repnz       stosd

            ;PML4
            mov         edi, 0A000h
            ;pointer to 2M PDPE (first 4G RAM identity mapped)
            mov         dword [edi], 0E001h
            ;pointer to 4k PDPE (core mapped at -2M)
            mov         dword [edi+4096-8], 0B001h

            ;4K PDPE
            mov         edi, 0B000h
            mov         dword [edi+4096-8], 0C001h
            ;4K PDE
            mov         edi, 0C000h+3840
            mov         eax, dword[fb_ptr] ;map framebuffer
            mov         al,81h
            mov         ecx, 31
@@:         stosd
            add         edi, 4
            add         eax, 2*1024*1024
            dec         ecx
            jnz         @b
            mov         dword [0C000h+4096-8], 0D001h

            ;4K PT
            mov         edi, 0D000h
            mov         eax, dword[core_ptr]    ;map core text segment
            inc         eax
            mov         ecx, dword[core_len]
            shr         ecx, 12
            inc         ecx
@@:         stosd
            add         edi, 4
            add         eax, 4096
            dec         ecx
            jnz         @b
            mov         dword[0DFF8h], 014001h  ;map core stack

I place the paging tables at 0xA000, starting with the top level PML4 table, followed by two PDPE tables (one for lower mapping, one for higher mapping), followed by several PDE and PTE tables. I also map the framebuffer in higher half, so that the kernel can use it regardless to lfb's physical address. And finally I map the kernel stack in higher half too, because the C kernel going to need it.


Top
 Profile  
 
 Post subject: Re: Need help with higher half / paging
PostPosted: Sat Sep 01, 2018 6:24 am 
Offline
Member
Member

Joined: Sat Mar 10, 2018 10:16 am
Posts: 296
You can try tutorial http://www.osdever.net/tutorials/view/implementing-basic-paging. It seems working.

_________________
https://github.com/VendelinSlezak/BleskOS


Top
 Profile  
 
 Post subject: Re: Need help with higher half / paging
PostPosted: Sat Sep 01, 2018 12:11 pm 
Offline
User avatar

Joined: Thu Jul 19, 2018 9:40 pm
Posts: 24
bzt9999 wrote:
I place the paging tables at 0xA000, starting with the top level PML4 table, followed by two PDPE tables (one for lower mapping, one for higher mapping), followed by several PDE and PTE tables. I also map the framebuffer in higher half, so that the kernel can use it regardless to lfb's physical address. And finally I map the kernel stack in higher half too, because the C kernel going to need it.


Must I use 4 level paging? 32 bit paging seems to have worked fine for others.
Intel's manual says "If CR0.PG = 1 and CR4.PAE = 0, 32-bit paging is used", however "If CR0.PG = 1, CR4.PAE = 1, and IA32_EFER.LME = 1, 4-level paging is used".
And seemingly, 32 bit paging only uses the page directory and page tables, without PML4 and PDPE tables preceding them.
I'll try 4 level later (perhaps later today?), but I don't believe that this is the issue.

Klakap wrote:

That tutorial is different from my setup. He simply maps the first 4MB, wheras I'm attempting to map .text and .rodata separately from .data and .bss, as I want to keep .rodata and .text non-writable.


Top
 Profile  
 
 Post subject: Re: Need help with higher half / paging
PostPosted: Sun Sep 02, 2018 5:54 am 
Offline

Joined: Sun Jul 01, 2018 11:13 am
Posts: 8
Ender wrote:
Must I use 4 level paging? 32 bit paging seems to have worked fine for others.

Nope, if you limit yourself to 4G RAM, then you won't need all 4 levels, only 2. I forgot to mention I set up paging tables for long mode (56 bits).

Regardless, I suggest to use "page X" in bochs right after you have loaded cr3, to figure out what's wrong. Or even better, start your page fault handler with "xchg bx,bx", so that you can use "page cr2" in bochs.


Top
 Profile  
 
 Post subject: Re: Need help with higher half / paging
PostPosted: Sun Sep 02, 2018 10:46 pm 
Offline
User avatar

Joined: Thu Jul 19, 2018 9:40 pm
Posts: 24
bzt9999 wrote:
Ender wrote:
Must I use 4 level paging? 32 bit paging seems to have worked fine for others.

Nope, if you limit yourself to 4G RAM, then you won't need all 4 levels, only 2. I forgot to mention I set up paging tables for long mode (56 bits).

Regardless, I suggest to use "page X" in bochs right after you have loaded cr3, to figure out what's wrong. Or even better, start your page fault handler with "xchg bx,bx", so that you can use "page cr2" in bochs.


Ah.
I quickly tried a couple 'page X's to see if it gave me any obvious errors or anything, but no-go
Code:
<bochs:13> page 0
linear page 0x0000000000000000 maps to physical page 0x000000000000
<bochs:14> page 55555555555555555555555555
linear page 0xfffffffffffff000 maps to physical page 0x0000fffff000


I'll play around with it some more later and see if I can figure something else.


Top
 Profile  
 
 Post subject: Re: Need help with higher half / paging
PostPosted: Mon Sep 03, 2018 11:19 pm 
Offline
User avatar

Joined: Thu Jul 19, 2018 9:40 pm
Posts: 24
I've been trying, still can't get it. I might just try and use PAE or 4-level paging, but I highly doubt that one of those will work if this doesn't.

My current code is as such:
Code:
   lea eax, [page_table - VIRT_BASE]
   mov ebx, PT_PRESENT

   mov ecx, (ro_end - VIRT_BASE)
   shr ecx, 12

.fill_ro:
   mov dword [eax], ebx ;insert entry
   add eax, 4 ;next entry
   add ebx, PAGE_SIZE ;next mem address
   loop .fill_ro

   or ebx, PT_READWRITE
   mov ecx, (rw_end - VIRT_BASE)
   sub ecx, (ro_end - VIRT_BASE)
   shr ecx, 12
.fill_rw:
   mov dword [eax], ebx
   add eax, 4
   add ebx, PAGE_SIZE
   loop .fill_rw

;done with page table
   lea ebx, [page_table - VIRT_BASE] ;load page table
   or ebx, PD_PRESENT | PD_READWRITE ;set flags

   lea eax, [page_dir - VIRT_BASE] ;load page dir
   mov dword [eax], ebx ;move page table to 0 in page dir
   add eax, PD_INDEX ;move to higher half entry
   mov dword [eax], ebx ;move page table to higher half entry

   lea eax, [page_dir - VIRT_BASE]
   mov cr3, eax

   mov eax, cr4
   or eax, 0x00000010 ;enable PSE (4MiB pages)
   mov cr4, eax

   mov eax, cr0
   or eax, 0x80010001 ;enable paging, WP, PE
   mov cr0, eax

   lea eax, [higher_half_start]
   jmp eax


Not much different from before, just small changes.

The only thing specific that I can think of is if I need to set PTE.PWT, PTE.PCD, or PTE.PAT, but I'm not sure, and I also doubt it. I've been looking through others' code, but can't seem to find any that are higher half, 32-bit, and separate RO and RW data. Could someone at least point me to that if they happen to know of a kernel that fits those requirements?


Top
 Profile  
 
 Post subject: Re: Need help with higher half / paging
PostPosted: Wed Sep 05, 2018 8:27 pm 
Offline
User avatar

Joined: Thu Jul 19, 2018 9:40 pm
Posts: 24
Bochs:
Code:
CR0=0x60000010: pg CD NW ac wp ne ET ts em mp pe
CR2=page fault laddr=0x0000000000000000
CR3=0x000000000000
    PCD=page-level cache disable=0
    PWT=page-level write-through=0
CR4=0x00000000: pke smap smep osxsave pcid fsgsbase smx vmx osxmmexcpt umip osfxsr pce pge mce pae pse de tsd pvi vme
CR8: 0x0
EFER=0x00000000: ffxsr nxe lma lme sce


I doubt that CR3 should be 0, so there's my problem. Now I need to figure out where I went wrong though... #-o
Not sure why I didn't think to check this earlier...

Changed title appropriately, I'm stumped

Turns out that CR3 changes to 0 after the JMP to higher_half_start (according to bochs at least), but I'm not sure of the reason for this


EDIT: Gave up, I'm wasting too much time on this. I'll just map the bottom 4MiB as Ring-0 RW.


Top
 Profile  
 
 Post subject: Re: Need help: CR3 changes to 0 on jump
PostPosted: Sat Sep 08, 2018 1:30 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5102
Ender wrote:
I doubt that CR3 should be 0, so there's my problem. Now I need to figure out where I went wrong though... #-o

A triple fault will (usually) cause the CPU to reset. Many registers are cleared by a CPU reset, including CR3.

Ender wrote:
Code:
   mov eax, cr0
   or eax, 0x80010001 ;enable paging, WP, PE
   mov cr0, eax

   lea eax, [higher_half_start]
   jmp eax

The instruction immediately following a MOV to CR0 that enables paging must be JMP. If you're linking your code properly, you should have no trouble doing this:
Code:
   mov cr0, eax
   jmp higher_half_start

Additionally, the page containing this code must be identity mapped, but it sounds like you've got that working already.

Ender wrote:
Turns out that CR3 changes to 0 after the JMP to higher_half_start (according to bochs at least), but I'm not sure of the reason for this

What address are you jumping to? Is that address mapped properly? Does it contain your code like it's supposed to? What is the first fault that occurs (before the third fault and CPU reset)?


PAT is an extension upon the older PCD and PWT bits. On CPUs that support it, those three bits are actually used as an index into an 8-entry Page Attribute Table (thus the name). By default, the table is filled with entries to make it appear like the PCD and PWT bits behave the same way they did on really old CPUs, but you can update the table to contain any of the cache types available on x86, in any order. It's almost like having page-granular MTRRs, although you must still pay attention to MTRRs when you're messing with page cache controls.


Top
 Profile  
 
 Post subject: Re: Need help: CR3 changes to 0 on jump
PostPosted: Sat Sep 08, 2018 6:14 pm 
Offline
User avatar

Joined: Thu Jul 19, 2018 9:40 pm
Posts: 24
Octocontrabass wrote:
The instruction immediately following a MOV to CR0 that enables paging must be JMP. If you're linking your code properly, you should have no trouble doing this

I had it load it into a register to insure it is an absolute jmp, and I've seen other projects do the same, and it works fine when mapping the entire bottom 4MiB instead of in 4KiB increments.

Octocontrabass wrote:
What address are you jumping to? Is that address mapped properly? Does it contain your code like it's supposed to? What is the first fault that occurs (before the third fault and CPU reset)?

Page fault, if I remember correctly. higher_half_start was right after the jmp physically, although I was jumping to the virtual address.

Octocontrabass wrote:
PAT is an extension upon the older PCD and PWT bits. On CPUs that support it, those three bits are actually used as an index into an 8-entry Page Attribute Table (thus the name). By default, the table is filled with entries to make it appear like the PCD and PWT bits behave the same way they did on really old CPUs, but you can update the table to contain any of the cache types available on x86, in any order. It's almost like having page-granular MTRRs, although you must still pay attention to MTRRs when you're messing with page cache controls.

I see. What should I set the PAT bit to in PTEs?


Top
 Profile  
 
 Post subject: Re: Need help: CR3 changes to 0 on jump
PostPosted: Tue Sep 11, 2018 2:15 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5102
Ender wrote:
it works fine when mapping the entire bottom 4MiB instead of in 4KiB increments.

Sounds to me like your code to build page tables in 4KiB increments was not working correctly.

Ender wrote:
Page fault, if I remember correctly. higher_half_start was right after the jmp physically, although I was jumping to the virtual address.

After the three faults and reboot, Bochs will log a bunch of information about the CPU state. The address that caused the page fault will be in CR2, and the rest of the CPU state may be helpful as well.

Ender wrote:
What should I set the PAT bit to in PTEs?

The PAT, PCD, and PWT bits should all be zero unless you know for sure that you need to change the cache setting for a particular page.


Top
 Profile  
 
 Post subject: Re: Need help: CR3 changes to 0 on jump
PostPosted: Wed Sep 12, 2018 8:09 pm 
Offline
User avatar

Joined: Thu Jul 19, 2018 9:40 pm
Posts: 24
Octocontrabass wrote:
Ender wrote:
it works fine when mapping the entire bottom 4MiB instead of in 4KiB increments.

Sounds to me like your code to build page tables in 4KiB increments was not working correctly.

That's what I thought as well, but I couldn't figure out where I went wrong.

Octocontrabass wrote:
Ender wrote:
Page fault, if I remember correctly. higher_half_start was right after the jmp physically, although I was jumping to the virtual address.

After the three faults and reboot, Bochs will log a bunch of information about the CPU state. The address that caused the page fault will be in CR2, and the rest of the CPU state may be helpful as well.

As posted earlier, bochs said:
Code:
CR2=page fault laddr=0x0000000000000000


Octocontrabass wrote:
Ender wrote:
What should I set the PAT bit to in PTEs?

The PAT, PCD, and PWT bits should all be zero unless you know for sure that you need to change the cache setting for a particular page.

Ah, thank you.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], DotBot [Bot], Google [Bot] and 73 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group