Page 1 of 1

Triple Fault While Enabling Paging

Posted: Fri Aug 05, 2016 4:40 am
by RezaNoei
Hi,

I have a kernel loaded on 0x10000 (1mb) and I'm using grub 0.97 as bootloader.

I have a physical memory management just like brokenthorn os development series;

In this method we will divide memory into 4k blocks. if we have a (4GB) 0xFFFFFFFF memory then we have 0x1000 blocks of 4kb.
So to represent if a block is in use or it is free to use, we just need to one bit of data. we used an array of 32768 elements of uint32 for it.
the next step was to init or deinit used or unused memory.

all functions worked fine and everything was good :wink:
--------------------------------------------------------------------------------

So I have started to add Virtual memory management to my kernel.

in Virtual memory management we have a PDT that contains 1024 elements of Page tables.
and each page table contains 1024 elements of Pages.

so an 32 bit virtual address will be translated to a physical address in this way :

PDT [ 10 highest bit of 32 bit address ] [ next 10 higher bit of 32 bit address ] + 12 lower bit as offset in the page.
------------------------------------------------- ------------------------------------------------------
Page Table Index Page Index

my problem comes from vmmngr_initialize() where i have defined an identity paging for the first 4mb of memory and then i have mapped 4mb of (address 0xC0000000 or 3GB) higher half to the second 4mb of main memory.

Code: Select all

void vmmngr_initialize () {

   // physical memory allocations are 4kb aligned

   //! allocate default page table
   ptable* table = (ptable*) pmmngr_alloc_block ();
   if (!table)
      return;
   
   //! allocates 3gb page table
   ptable* table2 = (ptable*) pmmngr_alloc_block ();
   if (!table2)
      return;

   //! clear page table
   memset (table, 0, sizeof (ptable));

   //! 1st 4mb are idenitity mapped
   for (int i=0, frame=0x0, virt=0x00000000; i<1024; i++, frame+=4096, virt+=4096) {

      //! create a new page
      pt_entry page=0;
      pt_entry_add_attrib (&page, I86_PTE_PRESENT);
      pt_entry_set_frame (&page, frame);

      //! ...and add it to the page table
      table2->m_entries [PAGE_TABLE_INDEX (virt) ] = page;
   }
   //! map 1mb to 3gb (where we are at)
   for (int i=0, frame=0x100000, virt=0xc0000000; i<1024; i++, frame+=4096, virt+=4096) {

      //! create a new page
      pt_entry page=0;
      pt_entry_add_attrib (&page, I86_PTE_PRESENT);
      pt_entry_set_frame (&page, frame);

      //! ...and add it to the page table
      table->m_entries [PAGE_TABLE_INDEX (virt) ] = page;
   }

   //! create default directory table
   pdirectory*   dir = (pdirectory*) pmmngr_alloc_blocks (3);
   if (!dir)
      return;

  //! clear directory table and set it as current
  memset (dir, 0, sizeof (pdirectory)); 

   //! get first entry in dir table and set it up to point to our table
   pd_entry* entry = &dir->m_entries [PAGE_DIRECTORY_INDEX (0xc0000000) ];
   pd_entry_add_attrib (entry, I86_PDE_PRESENT);
   pd_entry_add_attrib (entry, I86_PDE_WRITABLE);
   pd_entry_set_frame (entry, (physical_addr)table);

   pd_entry* entry2 = &dir->m_entries [PAGE_DIRECTORY_INDEX (0x00000000) ];
   pd_entry_add_attrib (entry2, I86_PDE_PRESENT);
   pd_entry_add_attrib (entry2, I86_PDE_WRITABLE);
   pd_entry_set_frame (entry2, (physical_addr)table2);

   //! store current PDBR
   _cur_pdbr = (physical_addr) &dir->m_entries;

   //! switch to our page directory
   vmmngr_switch_pdirectory (dir);

   //! enable paging
   pmmngr_paging_enable ();
}
in debugging affords i saw that everything works right before pmmngr_paging_enable ()
this function is written in inline assmebly :

Code: Select all

void pmmngr_paging_enable ()
{
	__asm__ __volatile__ ("movl %%cr0,%%eax":::"%eax");
	__asm__ __volatile__ ("orl $0x80000000,%%eax":::"%eax");
	__asm__ __volatile__ ("movl	%%eax,%%cr0":::"%eax");
}
can you help me to find its problem :oops: ?

Re: Triple Fault While Enabling Paging

Posted: Fri Aug 05, 2016 5:18 am
by SpyderTL
If you run your OS in bochs in debug mode, it will tell you exactly why a fault happens, and at what memory address.

But there are only a few possible culprits. Either the code that is running isn't available (and executable) in the page table, or an interrupt handler isn't in the page table, or the code calling this code isn't on the page table, or some data address being used isn't in the page table.

If you can give us a bochs debug log of the crash, we can probably tell you what the problem is. But it should be obvious at that point.

You mentioned that your kernel is loaded at 1Mb, and you are identity mapping the first 4Mb of memory. I'm assuming your kernel is smaller than 3Mb then.

Re: Triple Fault While Enabling Paging

Posted: Fri Aug 05, 2016 6:00 am
by RezaNoei
This is the important parts of the bochs output :

Code: Select all

00212045515i[CPU0 ] CPU is in protected mode (active)
00212045515i[CPU0 ] CS.d_b = 32 bit
00212045515i[CPU0 ] SS.d_b = 32 bit
00212045515i[CPU0 ] EFER   = 0x00000000
00212045515i[CPU0 ] | RAX=00000000e0000011  RBX=0000000000003000
00212045515i[CPU0 ] | RCX=0000000000003c00  RDX=0000000000003000
00212045515i[CPU0 ] | RSP=000000000010c814  RBP=0000000000003000
00212045515i[CPU0 ] | RSI=0000000000001000  RDI=0000000000002000
00212045515i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00212045515i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00212045515i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00212045515i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00212045515i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df IF tf SF zf af PF cf
00212045515i[CPU0 ] | SEG selector     base    limit G D
00212045515i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00212045515i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00212045515i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00212045515i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00212045515i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00212045515i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00212045515i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00212045515i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00212045515i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00212045515i[CPU0 ] | RIP=000000000010253b (000000000010253b)
00212045515i[CPU0 ] | CR0=0xe0000011 CR2=0x00000000001080c0
00212045515i[CPU0 ] | CR3=0x00002003 CR4=0x00000000
00212045515i[CPU0 ] 0x000000000010253b: (instruction unavailable) page not present
00212045515e[CPU0 ] exception(): 3rd (14) exception with no resolution, shutdown status is 00h, resetting
00212045515i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00212045515i[CPU0 ] cpu hardware reset
yes my kernel is in a 1.44mb floppy disk image.

Re: Triple Fault While Enabling Paging

Posted: Fri Aug 05, 2016 6:09 am
by iansjack
The log tells you exactly what the problem is. The page table entry for address 0x000000000010253b says that page is not present. Inspect the page table in the debugger to see what the entry is, then you have to look at your code to see why it is wrong.

Re: Triple Fault While Enabling Paging

Posted: Fri Aug 05, 2016 10:56 am
by RezaNoei
Finally i have found the problem.

there are some mysterious mistakes that i have found in my inline assembly, here is all :

Code: Select all

void pmmngr_load_PDBR (physical_addr addr) {
	
	__asm__("movl (%0),%%eax"::"r"(addr):"%eax");
	__asm__("movl %%eax,%%cr3":::"%eax");
}
in above function i expected that addr will moves into CR3. but it doesn't.

in below function i expected that paging will enable paging ( i must see that CR3 has a value like 0x8000?000), But it wants to be kidding me.

Code: Select all

void pmmngr_paging_enable ()
{
   __asm__ __volatile__ ("movl %%cr0,%%eax":::"%eax");
   __asm__ __volatile__ ("orl $0x80000000,%%eax":::"%eax");
   __asm__ __volatile__ ("movl   %%eax,%%cr0":::"%eax");
}
i have wrote this functions by reading inline assembly samples and some other articles. but they are incorrect in some way.
can you tell me, what is my mistake.

thanks.

Re: Triple Fault While Enabling Paging

Posted: Sun Aug 07, 2016 8:53 pm
by RezaNoei
WOW ! :lol:

It's done.

Code: Select all

void pmmngr_load_PDBR (physical_addr addr) {
   
   __asm__("movl (%0),%%eax"::"r"(addr):"%eax");
   __asm__("movl %%eax,%%cr3":::"%eax");
}
must be :

Code: Select all

void pmmngr_load_PDBR (physical_addr addr) {
   
   __asm__("movl %0,%%eax"::"r"(addr):"%eax");
   __asm__("movl %%eax,%%cr3":::"%eax");
}
:D