OSDev.org
https://forum.osdev.org/

GDT/Paging Kernel into Higher Half
https://forum.osdev.org/viewtopic.php?f=1&t=10924
Page 1 of 1

Author:  spacedsteve [ Thu Sep 22, 2005 7:46 pm ]
Post subject:  GDT/Paging Kernel into Higher Half

Hello everybody, I need some help big time please, I've been banging my head against this for nearly 30 hours this week!

Grub loads my kernel code at physical location of 0x00101000 but it is linked to be at virtual address of 0xC0000000

I had my kernel working when it was linked as virtual=physical but I want to move it up the the 3GB mark. I've used Tims trick to use a GDT with segment offsets that give me 0xC0000000 + 0x40101000 = 0x00101000. This works fine and I jump into my kernel code.

Now I want to setup and enable paging and then load new linear code/data segments and continue on with things.

Setting up the linear segments is fine but my paging code triple faults Bochs. (paging seemed to work when linked to virtual=physical). My code is on SourceForge and I would be eternally gratefull if somebody could have a look through it and spot the problem(s). My heads spinning and fresh eyes are definatly needed :)

loader.asm sets up the GDT with the special base's and jumps into the kernel address space (0xC0000000) which inturn calls main() in kernel.c. Here we setup paging in paging.c and then back in kernel.c the newly created page directory is installed and then the linear code/data descriptors will be put inplace. It triple faults around loadind cr3 with the page directory in kernel.c. I've tried following all similar threads about this topic but no joy.

LOADER.ASM http://cvs.sourceforge.net/viewcvs.py/osamos/AMOS/src/kernel/loader.asm?view=markup

KERNEL.C http://cvs.sourceforge.net/viewcvs.py/osamos/AMOS/src/kernel/kernel.c?view=markup

PAGING.C http://cvs.sourceforge.net/viewcvs.py/osamos/AMOS/src/kernel/mm/paging.c?view=markup

This code in kernel.c was for testing as 0x00000000 = *pagedirectory
Code:
   // Enable Paging...
   __asm__ __volatile__ ( "movl %%eax, %%cr3" : : "a" ( 0x00000000 ) );

As 0x00000000 is the first address physical_pageAlloc() will give out and setting up the pagedirectory is the first call to physical_pageAlloc().

Any and all help greatly appreciated, cheers :)

Author:  Crazed123 [ Thu Sep 22, 2005 9:32 pm ]
Post subject:  Re:GDT/Paging Kernel into Higher Half

Not absolutely sure about this, but...
Code:
struct PAGE_DIRECTORY_ENTRY
  35 :                {
  36 :                unsigned int present:1;
  37 :                unsigned int readwrite:1;
  38 :                unsigned int user:1;
  39 :                unsigned int writethrough:1;
  40 :                unsigned int cachedisabled:1;
  41 :                unsigned int accessed:1;
  42 :                unsigned int reserved:1;
  43 :                unsigned int pagesize:1;
  44 :                unsigned int globalpage:1;
  45 :                unsigned int available:3;
  46 :                unsigned int address:20;
  47 :                } PACKED;
  48 :              
  49 :                struct PAGE_TABLE_ENTRY
  50 :                {
  51 :                unsigned int present:1;
  52 :                unsigned int readwrite:1;
  53 :                unsigned int user:1;
  54 :                unsigned int writethrough:1;
  55 :                unsigned int cachedisabled:1;
  56 :                unsigned int accessed:1;
  57 :                unsigned int dirty:1;
  58 :                unsigned int attributeindex:1;
  59 :                unsigned int globalpage:1;
  60 :                unsigned int available:3;
  61 :                unsigned int address:20;
  62 :                } PACKED;


You see those unsigned ints? Whenever you assign to one of those an entire 32 bits of data (all zeroed out except one because you're assigning the number one) is moved to the correct location, overriding other bits. In other words, you're treating a single unsigned int as many, thus making the entire thing's final value 1 = 0x00000001 = 00000000000000000000000000000001 in binary. I remember C as having a datatype called a "bitfield" that might allow you to do what you want, or you might just have to use ORs and shifts.

Again, not exactly sure this is The Problem You Asked About, but it's certainly a bug unless my C is rusty. Somebody please let me know if my C is rusty.

Author:  AR [ Thu Sep 22, 2005 10:27 pm ]
Post subject:  Re:GDT/Paging Kernel into Higher Half

The colon with a number after the end declares a bitfield of "number" bits. unsigned int present:1 = 1bit, they are automatically packed apparently but I assume PACKED is defined as __attribute__((packed)) which should make sure it's packed.

Paging is under segmentation, you need to map the kernel at both 0x00101000 and 0xC0000000, once you load a flat segment you can remove the 0x00101000 mapping.

Author:  spacedsteve [ Fri Sep 23, 2005 4:49 am ]
Post subject:  Re:GDT/Paging Kernel into Higher Half

Hello, thanks for the quick replys :)
AR wrote:
I assume PACKED is defined as __attribute__((packed)) which should make sure it's packed.
yup PACKED is defined in sys/types.h as #define PACKED __attribute__( (packed) )

I'm nearly sure that the paging code is ok as it seemed to work when the kernel was linked to run at its physical address, e.g. I could map the video memory to some high location and successfully write to the console at that point.

AR wrote:
Paging is under segmentation, you need to map the kernel at both 0x00101000 and 0xC0000000, once you load a flat segment you can remove the 0x00101000 mapping.


Ya im guessing that as im trying to do this under segmentation with a base of 0x40101000 that its causing problems. From PAGING.C:
Code:
   // identity map bottom 4MB's
   for( physicalAddress=0L ; physicalAddress<(1024*SIZE_4KB) ; physicalAddress+=SIZE_4KB )
      paging_setPageTableEntry( physicalAddress, physicalAddress, TRUE );      

   // map the kernel's virtual address to its physical memory location
   linearAddress = 0xC0000000;
   // 0x00101000 = &start (start in loader.asm which is the kernel entry point)
   for( physicalAddress=(DWORD)0x00101000; physicalAddress<(DWORD)(0x00101000+(1024*SIZE_4KB)) ; physicalAddress+=SIZE_4KB )
   {
      paging_setPageTableEntry( linearAddress, physicalAddress, TRUE );
      linearAddress += SIZE_4KB;      
   }


I think this does what you said though, the bottom 4MB's includes the kernel and then I also map it to its new virtual location of 0xC000000

Author:  Crazed123 [ Fri Sep 23, 2005 9:01 am ]
Post subject:  Re:GDT/Paging Kernel into Higher Half

What you appear to be doing is identity mapping the kernel to both its physical address AND its new virtual address in order to make paging work before you can change the segments. This should work. Do you have IRQs enabled, or any other sort of interrupt enabled that could be firing after paging is enabled?

Author:  spacedsteve [ Fri Sep 23, 2005 9:08 am ]
Post subject:  Re:GDT/Paging Kernel into Higher Half

no I havnt setup IRQ's yet and I perform a CLI instruction to disable maskable interrupts before I setup/enable paging ...boy am I stumped on this one! ???

Author:  Crazed123 [ Fri Sep 23, 2005 2:18 pm ]
Post subject:  Re:GDT/Paging Kernel into Higher Half

Do you have exceptions set up?

Author:  spacedsteve [ Mon Sep 26, 2005 3:28 am ]
Post subject:  Re:GDT/Paging Kernel into Higher Half

No I have disabled my code for exceptions until I have this sorted out, that wouldnt make a difference though would it? If I enable my exception code it doesnt help either ...I'm spending the rest of the day at this so hopefully I will figure it out :)

[edit ...a day later]

arrgg! so I dumped the idea of trying to get the gdt trick working, instead I setup a simple page directory & 2 tables in my setup routine called by Grub. maping the kernel into the higher half and jump into my kernel from their. soo much easier and it works and took only a few hours compared to the week of my life i spent to get the other way working! :P

Anyways thanks for helping me out :)

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/