Bad Code After Enabling Paging

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
F4doraOfDoom
Posts: 4
Joined: Tue Nov 05, 2019 2:09 am

Bad Code After Enabling Paging

Post by F4doraOfDoom »

Hey,
I'm following James Molloy's OS Development tutorial.
I'm in Paging chapter, and I'm having trouble getting it to work.
I use QEMU to run the ISO and GDB to debug the code.
Everything works until I reach the enablePaging function (xor cr0 with 0x80000000), and afterwards the code that starts executing is garbage.

(In GDB)
Code before enabling paging:

Code: Select all

   0x101438 <_enable_paging+1>:	mov    ebp,esp
   0x10143a <_enable_paging+3>:	mov    eax,cr0
   0x10143d <_enable_paging+6>:	or     eax,0x80000000
=> 0x101442 <_enable_paging+11>:	mov    cr0,eax
   0x101445 <_enable_paging+14>:	mov    esp,ebp
   0x101447 <_enable_paging+16>:	pop    ebp
   0x101448 <_enable_paging+17>:	ret    
   0x101449 <gdt_dump>:	mov    eax,DWORD PTR [esp+0x4]

Registers:
eax            0x80000011          0x80000011
ecx            0xb8000             0xb8000
edx            0x10077c            0x10077c
ebx            0x10000             0x10000
esp            0x107c38            0x107c38
ebp            0x107c38            0x107c38
esi            0x0                 0x0
edi            0x0                 0x0
eip            0x101442            0x101442 <_enable_paging+11>
eflags         0x286               [ PF SF IF ]
cs             0x8                 0x8
ss             0x10                0x10
ds             0x10                0x10
es             0x10                0x10
fs             0x10                0x10
gs             0x10                0x10


After (one single step):

Code: Select all

   0x10143f <_enable_paging+8>:	add    BYTE PTR [eax],al
   0x101441 <_enable_paging+10>:	add    BYTE PTR [eax],al
   0x101443 <_enable_paging+12>:	add    BYTE PTR [eax],al
=> 0x101445 <_enable_paging+14>:	add    BYTE PTR [eax],al
   0x101447 <_enable_paging+16>:	add    BYTE PTR [eax],al
   0x101449 <gdt_dump>:	add    BYTE PTR [eax],al
   0x10144b <gdt_dump+2>:	add    BYTE PTR [eax],al
   0x10144d <gdt_dump+4>:	add    BYTE PTR [eax],al

Registers:
eax            0x80000011          0x80000011
ecx            0xb8000             0xb8000
edx            0x10077c            0x10077c
ebx            0x10000             0x10000
esp            0x107c38            0x107c38
ebp            0x107c38            0x107c38
esi            0x0                 0x0
edi            0x0                 0x0
eip            0x101445            0x101445 <_enable_paging+14>
eflags         0x286               [ PF SF IF ]
cs             0x8                 0x8
ss             0x10                0x10
ds             0x10                0x10
es             0x10                0x10
fs             0x10                0x10
gs             0x10                0x10
Here is my code (some of my coding conventions may seem weird):

Code: Select all

void kernel::paging::start()
{
    // allocate array of frame indexes
    nframes = (K_PHYSICAL_MEM_SIZE / K_PAGE_SIZE);
    frames = (uint32_t*)heap::allocate(INDEX_FROM_BIT(nframes), false);
    memset(frames, 0, INDEX_FROM_BIT(nframes));

    // TODO: When I implement new, change this to calling the constrcutor of page_directory_t
    kernel_directory = (page_directory_t*)heap::allocate(sizeof(page_directory_t));
    memset(kernel_directory, 0, sizeof(page_directory_t));

    // we are currently using this directory
    current_directory = kernel_directory;

    // identity map the kernel
    uint32_t i = 0;
    while(i < __kernel_heap)
    {
        frame::alloc(get_page(
                i,
                kernel_directory,
                true
                ), // we want to create all pages in directory
            false, // this directory is the kernel's
            false // kernel directory is1 not writeable from user space
        );
        i += PAGE_SIZE;
        printf("loop %d\n", i);
    }

    interrupts::set_handler((uint32_t)InterruptList::PageFault, __page_fault_handler);

    // this will enable paging
    set_directory(kernel_directory);
    paging::enable(); // just calls _enable_paging
}

void kernel::paging::set_directory(page_directory_t* dir)
{
    current_directory = dir;
    _load_page_directory((uint32_t*)&dir->tables_physical);
}

page_t* kernel::paging::get_page(uint32_t address, page_directory_t* dir, bool create)
{
    address /= PAGE_SIZE;

    uint32_t table_idx = address / 1024;

    // if we find an existing table, return it
    if (dir->tables[table_idx] != nullptr)
    {
        return &dir->tables[table_idx]->pages[address%1024];
    }

    // if no, create one and return it
    if (create)
    {
        uint32_t table_ptr = 0;
        dir->tables[table_idx] = (page_table_t*)heap::allocate_p(
            sizeof(page_directory_t), 
            &table_ptr // save the physical address 
        );
        memset(dir->tables[table_idx], 0, PAGE_SIZE);
        dir->tables_physical[table_idx] = table_ptr | 0x7; // PRESENT, RW, US
        return &dir->tables[table_idx]->pages[address%1024];
    }

    return (page_t*)PAGE_NOT_FOUND;
}
I've been searching for an explenation for this kind of mistake, but haven't found any.
Could someone please help me with my error or point me as to how I might fix this?
Thanks in advance!
User avatar
iansjack
Member
Member
Posts: 4704
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Bad Code After Enabling Paging

Post by iansjack »

It looks like you haven't identity mapped the page(s) that your code is running in (or haven't done it correctly). So as soon as you enable paging you are pointing to a different physical address.

You need to either (a) identity map the pages that the kernel occupies or (b) before paging copy the code to the pages that you have mapped its address range to.
F4doraOfDoom
Posts: 4
Joined: Tue Nov 05, 2019 2:09 am

Re: Bad Code After Enabling Paging

Post by F4doraOfDoom »

iansjack wrote:It looks like you haven't identity mapped the page(s) that your code is running in (or haven't done it correctly). So as soon as you enable paging you are pointing to a different physical address.

You need to either (a) identity map the pages that the kernel occupies or (b) before paging copy the code to the pages that you have mapped its address range to.
Hey,
I define my __kernel_heap like this:

Code: Select all

uint32_t __kernel_heap = (uint32_t)&end; // this will be the beginning of the kernel's heap
where "end" is defined by the linker like this:

Code: Select all

ENTRY(_start)
SECTIONS
{

    .text 0x100000 :
    {
        code = .; _code = .; __code = .;
        *(.multiboot)
		*(.text)
        . = ALIGN(4096);
    }

    .data :
    {
        data = .; _data = .; __data = .;
        *(.data)
        *(.rodata)
        . = ALIGN(4096);
    }

    .bss :
    {
        bss = .; _bss = .; __bss = .;
        *(.bss)
        . = ALIGN(4096);
    }

    end = .; _end = .; __end = .;
}
Since I identity map all the way from 0 to __kernel_heap, shouldn't all of the program's code be identity mapped as well already?
User avatar
iansjack
Member
Member
Posts: 4704
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Bad Code After Enabling Paging

Post by iansjack »

You certainly map that address range, but I'm not convinced that you identity map it. I don't see enough of your code to be sure. The other possibility is that you clear a physical page when you allocate.

Your best bet is to set a breakpoint just before you enable paging, then check the page table.
F4doraOfDoom
Posts: 4
Joined: Tue Nov 05, 2019 2:09 am

Re: Bad Code After Enabling Paging

Post by F4doraOfDoom »

I fixed the problem!

For future generations:
I'm not exactly sure where I had it wrong, but I suspect it was with the frame allocations.
I the paging with my own design and understanding of Paging (still heavily relying on the tutorial) and it worked!
I used a normal boolean array instead of a BITSET. Now that I know it works, I'll be changing the implementation to use a bitset instead.
Post Reply