OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Mar 29, 2024 5:48 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: problems with setting up paging
PostPosted: Mon Aug 22, 2022 4:41 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1925
Location: Athens, GA, USA
I am working on setting up paging in my Ordo design, and have run into a problem. As things stand, I can get the transition into p-mode to work correctly if I have paging disabled, but when I set up the page directory and a few relevant page tables (while still in real mode), setting CR3 to the page directory, and then transitioning to p-mode with the paging bit set, it seems to jump into hyperspace.

The code which calls the paging initialization and transfers to p-mode is:

Code:
promote_pm:
        call init_page_directory

        mov eax, cr0
        or eax, Protection | Paging ; set PE (Protection Enable) and Paging bits in CR0 (Control Register 0)
        mov cr0, eax

        ; Perform far jump to selector 08h (offset into GDT, pointing at a 32bit PM code segment descriptor)
        ; to load CS with proper PM32 descriptor)
        jmp system_code_selector:PModeMain


(Where Protection is 0x00000001 and Paging is 0x80000000.)

The code for initializing the page tables and page directory is:

Code:
%ifndef _PAGING_CODE__INC__
%define _PAGING_CODE__INC__

bits 16

align 4096
page_directory     resw 0x0400

page_table_0       resw 0x0400
page_table_768     resw 0x0400

page_table_1023    resw 0x0400

init_page_directory:
        mov bx, page_directory
        memset_rm 0, 0x0400, bx               ; clear the page dir table

        ; start by setting up the base page table
        mov bx, page_table_0                  ; get index into the base page table
        memset_rm 0, 0x0400, bx               ; clear the table entries
        ; entries 0-1024 - identity mapping the first 1 MiB of memory
        mov cx, 0x0100                        ; 256 entries * 4KiB = 1 MiB
        mov eax, PTE_Page_Index_Mask | PTE_Present
    .pt_0_fill:
        mov [bx], dword eax
        add eax, 0x1000
        add bx, 4
        loop .pt_0_fill

        ; set up the kernel code table
        mov bx, page_table_768                ; get index into the kernel code page table
        memset_rm 0, 0x0400, bx               ; clear the table entries
        ; entries 0-4096 - mapping the start of higher half
        mov cx, 0x0010                        ; 8 entries * 4KiB = 32 KiB
        mov edx, PTE_Page_Index_Mask | PTE_Present
        add edx, 0x100000
    .pt_768_fill:
        mov [bx], dword edx
        add edx, 0x1000
        add bx, 4
        loop .pt_768_fill

        ; set up the kernel stack table
        mov bx, page_table_1023               ; get index into the kernel stack page table
        memset_rm 0, 0x0400, bx               ; clear the table entries
        ; entries 0-4096 - mapping the start of higher half
        mov cx, 0x0004                        ; 4 entries * 4KiB = 16KiB
        mov edx, PTE_Page_Index_Mask | PTE_Present
        add edx, 0xffffff00
    .pt_1023_fill:
        mov [bx], dword edx
        add edx, 0x1000
        add bx, 4
        loop .pt_1023_fill


    .setup_directory:
        mov bx, page_directory
    .pd_fill:
        mov eax, page_table_0
        shl eax, 12
        or eax, PDE_Present
        mov [bx], eax
        add bx, 768 * 4
        mov eax, page_table_768
        shl eax, 12
        or eax, PDE_Present
        mov [bx], eax
        add bx, 1023 * 4
        mov eax, page_table_1023
        shl eax, 12
        or eax, PDE_Present
        mov [bx], eax


        ; set the page directory
        mov eax, page_directory
        mov cr3, eax
        ret


%endif


I am following the wiki entry on paging regarding the location of the start of higher half (i.e., page table 768).

The constants used by the paging init routine are:

Code:
%ifndef _PAGING__INC__
%define _PAGING__INC__


%define PDE_Present           0b00000000000000000000000000000001
%define PDE_Read_Write        0b00000000000000000000000000000010
%define PDE_User              0b00000000000000000000000000000100
%define PDE_Write_Thru        0b00000000000000000000000000001000
%define PDE_Cache_Disable     0b00000000000000000000000000010000
%define PDE_Acccessed         0b00000000000000000000000000100000
%define PDE_Dirty             0b00000000000000000000000001000000
%define PDE_Page_Size         0b00000000000000000000000010000000
%define PDE_Global            0b00000000000000000000000100000000
%define PDE_Availability_Mask 0b00000000000000000000111000000000
%define PDE_Page_Attr_Table   0b00000000000000000001000000000000
%define PDE_Page_Index_Mask   0b11111111111111111110000000000000


%define PTE_Present           0b00000000000000000000000000000001
%define PTE_Read_Write        0b00000000000000000000000000000010
%define PTE_User              0b00000000000000000000000000000100
%define PTE_Write_Through     0b00000000000000000000000000001000
%define PTE_Cache_Disable     0b00000000000000000000000000010000
%define PTE_Acccessed         0b00000000000000000000000000100000
%define PTE_Dirty             0b00000000000000000000000001000000
%define PTE_Page_Attr_Table   0b00000000000000000000000010000000
%define PTE_Global            0b00000000000000000000000100000000
%define PTE_Availability_Mask 0b00000000000000000000111000000000
%define PTE_Page_Index_Mask   0b11111111111111111111000000000000

%endif


I can only imagine that the logic of my fill loops is flawed, but I am unclear as to how.

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


Top
 Profile  
 
 Post subject: Re: problems with setting up paging
PostPosted: Mon Aug 22, 2022 4:52 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5103
Schol-R-LEA wrote:
Code:
page_directory     resw 0x0400

That's not 4096 bytes.


Top
 Profile  
 
 Post subject: Re: problems with setting up paging
PostPosted: Mon Aug 22, 2022 5:07 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1925
Location: Athens, GA, USA
Gah, no, it isn't I meant to have it as resd, not resw, I have no idea how I made that mistake.

However, I now have another problem, which I will need to solve before I proceed: the second stage loader is now too large to fit in the first segment after the boot sector. This isn't the first time I've run into this issue, and there are a few ways I can resolve it before getting back to the immediate problem. In the short term, I will probably move the page directory and page tables to a separate segment, which is what I've already done to the kernel code loading (because having a 16KiB block of memory assigned for that out of the 20KiB available turned out to be a problem).

If this limitation keeps cropping up, though, the long-term solution may well be to change the first stage boot loader so that it loads everything to another, otherwise unused segment higher in memory.

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


Top
 Profile  
 
 Post subject: Re: problems with setting up paging
PostPosted: Mon Aug 22, 2022 5:56 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5103
You've only hit that limitation because your second stage binary is more padding than code. Open it in a hex editor and see for yourself.

Plus, you've already finished loading the kernel binary, right? Why not switch to protected mode (or at least unreal mode) before you set up your page tables? Then you won't need to worry about segments.


Top
 Profile  
 
 Post subject: Re: problems with setting up paging
PostPosted: Mon Aug 22, 2022 6:18 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1925
Location: Athens, GA, USA
Octocontrabass wrote:
You've only hit that limitation because your second stage binary is more padding than code. Open it in a hex editor and see for yourself.

That's true, and it is something I have considered. I did move the page tables to a separate segment, now, though the current result is that it is triple-faulting.

Octocontrabass wrote:
Plus, you've already finished loading the kernel binary, right? Why not switch to protected mode (or at least unreal mode) before you set up your page tables? Then you won't need to worry about segments.

That's a fair point, actually. I'd have to pivot a bit, but that may be the better solution.

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


Top
 Profile  
 
 Post subject: Re: problems with setting up paging
PostPosted: Mon Aug 22, 2022 7:36 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1925
Location: Athens, GA, USA
I've moved the paging setup to after the p-mode transition, but it still doesn't seem to be working - the code which is supposed to immediately follow it doesn't run. The current version of the code is:

Code:
PModeMain:
        ; set the segment selectors
        mov ax, system_data_selector
        mov ds, ax
        mov ss, ax
        mov es, ax
        mov fs, ax
        mov gs, ax
        mov esp, 0x00090000

        call init_page_directory
        mov eax, cr0
        or eax, Paging           ; set Paging bit in CR0 (Control Register 0)
        mov cr0, eax

    ;    call clear_screen

        ; write 'Kernel started' to text buffer
        write32 kernel_start, 7

;;; halt the CPU
halted:
    .halted_loop:
        hlt
        jmp short .halted_loop


and

Code:
%ifndef _PAGING_CODE__INC__
%define _PAGING_CODE__INC__

%line 0, "paging.asm"
bits 32

page_directory           equ 0xffff0000
page_table_0             equ page_directory + 0x1000
page_table_768           equ page_directory + 0x2000
page_table_1018          equ page_directory + 0x3000
page_table_1023          equ page_directory + 0x4000
init_page_directory:
        mov ebx, dword page_directory
        memset32 0, 0x0400, ebx                ; clear the page dir table

        ; start by setting up the base page table
        mov ebx, dword page_table_0            ; get index into the base page table
        memset32 0, 0x0400, ebx                ; clear the table entries
        ; entries 0-1024 - identity mapping the first 1 MiB of memory
        mov ecx, 0x0100                        ; 256 entries * 4KiB = 1 MiB
        mov eax, PTE_Page_Index_Mask | PTE_Present
    .pt_0_fill:
        mov [ebx], dword eax
        add eax, 0x1000
        add ebx, 4
        loop .pt_0_fill

        ; set up the kernel code table
        mov ebx, page_table_768                ; get index into the kernel code page table
        memset32 0, 0x0400, ebx                ; clear the table entries
        ; entries 0-4096 - mapping the start of higher half
        mov ecx, 0x0010                        ; 8 entries * 4KiB = 32 KiB
        mov edx, PTE_Page_Index_Mask | PTE_Present
        add edx, 0x100000
    .pt_768_fill:
        mov [ebx], dword edx
        add edx, 0x1000
        add ebx, 4
        loop .pt_768_fill

        ; set up the page table mapping
        mov ebx, page_table_1018               ; get index into the kernel stack page table
        memset32 0, 0x0400, ebx                ; clear the table entries
        ; entries 0-4096 - mapping the start of higher half
        mov ecx, 0x0008                        ; 8 entries * 4KiB = 32KiB
        mov edx, PTE_Page_Index_Mask | PTE_Present
        add edx, 0xffff0000
    .pt_1018_fill:
        mov [ebx], dword edx
        add edx, 0x1000
        add ebx, 4
        loop .pt_1018_fill

        ; set up the kernel stack table
        mov ebx, page_table_1023               ; get index into the kernel stack page table
        memset32 0, 0x0400, ebx                ; clear the table entries
        ; entries 0-4096 - mapping the start of higher half
        mov ecx, 0x0004                        ; 4 entries * 4KiB = 16KiB
        mov edx, PTE_Page_Index_Mask | PTE_Present
        add edx, 0xffffff00
    .pt_1023_fill:
        mov [ebx], dword edx
        add edx, 0x1000
        add ebx, 4
        loop .pt_1023_fill


    .setup_directory:
        mov ebx, page_directory
    .pd_fill:
        mov eax, page_table_0
        shl eax, 12
        or eax, PDE_Present
        mov [ebx], eax
        add ebx, 768 * 4
        mov eax, page_table_768
        shl eax, 12
        or eax, PDE_Present
        mov [ebx], eax
        add ebx, 1018 * 4
        mov eax, page_table_1018
        shl eax, 12
        or eax, PDE_Present
        mov [ebx], eax
        add ebx, 1023 * 4
        mov eax, page_table_1023
        shl eax, 12
        or eax, PDE_Present
        mov [ebx], eax


        ; set the page directory
        mov eax, page_directory
        mov cr3, eax
        ret


%endif

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


Top
 Profile  
 
 Post subject: Re: problems with setting up paging
PostPosted: Mon Aug 22, 2022 7:41 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5103
Schol-R-LEA wrote:
Code:
page_directory           equ 0xffff0000

Try putting your page tables in RAM instead of the firmware ROM.


Top
 Profile  
 
 Post subject: Re: problems with setting up paging
PostPosted: Mon Aug 22, 2022 8:06 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1925
Location: Athens, GA, USA
OK, good point. Though I am not certain where system firmware is located on a modern system, so... yeah. I probably need to consult the documentation, as well as the memory map I went to such trouble to collect earlier.

sigh I think I am thrashing a bit at this point. I may need to step away from the project for a while.

I did try to place the pages at 0xb000000 instead, just to see if it made a difference, but no change. I wasn't certain how to compute where that would be in the page directory when I went to map the page tables themselves. I need to work out just where I can and should place the stack and page tables where it would be safe.

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


Top
 Profile  
 
 Post subject: Re: problems with setting up paging
PostPosted: Mon Aug 22, 2022 9:44 pm 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1593
You know, building a simple allocator from the memory map is not very hard. Here's mine from the boot loader.
Code:
struct memblock {
    uint32_t start, len;
};
static struct memblock memavail[32];
static struct memblock memreserved[64];
static size_t navail, nreserved;

static void add_range_to_memblock(struct memblock* arr, size_t *n, size_t limit, uint32_t start, uint32_t len)
{
    size_t i;
    for (i = 0; i < *n; i++)
        if (arr[i].start > start)
            break;
    /* can we just add this to the preceding block? */
    if (i && arr[i-1].start + arr[i-1].len == start)
        arr[i-1].len += len;
    /* can we extend the current block? */
    else if (i < *n && start + len == arr[i].start)
    {
        arr[i].start = start;
        arr[i].len += len;
    }
    else if (*n < limit)
    {
        if (i < *n)
            memmove(arr + i + 1, arr + i, (*n - i - 1) * sizeof (struct memblock));
        arr[i].start = start;
        arr[i].len = len;
        ++*n;
    }
    else
    {
        dbg_printf("Out of memory adding block at %x\n", start);
        halt();
    }
}

static void add_avail_range(uint32_t addr, uint32_t len)
{
    add_range_to_memblock(memavail, &navail, sizeof memavail / sizeof *memavail, addr, len);
}

static void add_reserved_range(uint32_t addr, uint32_t len)
{
    add_range_to_memblock(memreserved, &nreserved, sizeof memreserved / sizeof *memreserved, addr, len);
}
static void *alloc(size_t sz, size_t algn)
{
    size_t avidx, residx = 0;
    for (avidx = 0; avidx < navail; avidx++)
    {
        uint32_t start, len;
        while (memreserved[residx].start + memreserved[residx].len < memavail[avidx].start && residx < nreserved)
            residx++;
        while (residx < nreserved && memreserved[residx].start < memavail[avidx].start + memavail[avidx].len)
        {
            start = memavail[avidx].start;
            if (memreserved[residx].start + memreserved[residx].len > start)
                start = memreserved[residx].start + memreserved[residx].len;
            len = memavail[avidx].start + memavail[avidx].len - start;
            if (residx < nreserved && memreserved[residx+1].start - start < len)
                len = memreserved[residx+1].start - start;
            if (((start + algn - 1) & -algn) + sz <= start + len)
            {
                start = (start + algn - 1) & -algn;
                add_reserved_range(start, sz);
                dbg_printf("Allocating address %8x\n", start);
                return (void*)start;
            }
        }
    }
    return 0;
}

static void *page_alloc_or_die(void)
{
    void* ret = alloc(0x1000, 0x1000);
    if (!ret)
        die("Out of memory!\n");
    return memset(ret, 0, 0x1000);
}
Not a very good allocator, but enough to set up 64-bit page tables from 32-bit mode.

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: problems with setting up paging
PostPosted: Mon Aug 22, 2022 9:58 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5103
Schol-R-LEA wrote:
I am not certain where system firmware is located on a modern system, so...

After power-on or reset, the CPU begins executing code at physical address 0xFFFFFFF0, so there's always firmware ROM in that general area. It'll be listed in your memory map as "reserved".

Schol-R-LEA wrote:
I did try to place the pages at 0xb000000 instead, just to see if it made a difference, but no change.

That address is awfully high; you would have to use your memory map to see if it's available even if your VM is configured for enough memory. And even if it's available, I suspect there are other problems. Dumping the paging structures (to the screen or in your debugger) before using them might help.

Schol-R-LEA wrote:
I wasn't certain how to compute where that would be in the page directory when I went to map the page tables themselves.

I've found this page to be very helpful for visualizing x86 page table structures. To work out which entry in your page directory and page table correspond to a virtual address, you can use the "virtual address translation (2-level and 3-level)" chart. The top row corresponds to what you're using now, which is 4kB pages in 2-level translation.

But that assumes you're identity mapping the page tables, which isn't required - you can map them wherever you like. You can even enable paging without mapping the page tables at all.

Schol-R-LEA wrote:
I need to work out just where I can and should place the stack and page tables where it would be safe.

Unless your target is extremely old PCs, there's about half a megabyte of conventional memory that you haven't used for anything yet.


Top
 Profile  
 
 Post subject: Re: problems with setting up paging
PostPosted: Mon Aug 22, 2022 10:52 pm 
Offline
Member
Member
User avatar

Joined: Fri Oct 27, 2006 9:42 am
Posts: 1925
Location: Athens, GA, USA
Octocontrabass wrote:
Schol-R-LEA wrote:
I am not certain where system firmware is located on a modern system, so...

After power-on or reset, the CPU begins executing code at physical address 0xFFFFFFF0, so there's always firmware ROM in that general area. It'll be listed in your memory map as "reserved".


I should have known that, I am slightly peeved with myself that it didn't occur to me until you mentioned it.

Octocontrabass wrote:
Schol-R-LEA wrote:
I did try to place the pages at 0xb000000 instead, just to see if it made a difference, but no change.

That address is awfully high; you would have to use your memory map to see if it's available even if your VM is configured for enough memory. And even if it's available, I suspect there are other problems. Dumping the paging structures (to the screen or in your debugger) before using them might help.


I tried putting the page directory and the four stub page tables at 0x00200000, and that worked. Well, after I fixed some faults in how I was filling the page directory, that is.

Octocontrabass wrote:
Schol-R-LEA wrote:
I wasn't certain how to compute where that would be in the page directory when I went to map the page tables themselves.

I've found this page to be very helpful for visualizing x86 page table structures. To work out which entry in your page directory and page table correspond to a virtual address, you can use the "virtual address translation (2-level and 3-level)" chart. The top row corresponds to what you're using now, which is 4kB pages in 2-level translation.

But that assumes you're identity mapping the page tables, which isn't required - you can map them wherever you like. You can even enable paging without mapping the page tables at all.


The charts will still probably help regardless. thank you.

Octocontrabass wrote:
Schol-R-LEA wrote:
I need to work out just where I can and should place the stack and page tables where it would be safe.

Unless your target is extremely old PCs, there's about half a megabyte of conventional memory that you haven't used for anything yet.

I've been trying to avoid putting much in conventional memory, but that's a valid point. I'm not sure where this hesitancy came from, either, as there's no reason for it. I just tried putting them at 256KiB and it worked like a charm, which also means I can remove one of the page table entries. Two, actually, since I decided to move the stack to 0xC03fffff so it would be within the same page table as the kernel code (for the time being).

_________________
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Majestic-12 [Bot] and 166 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