Page 1 of 1

bx_dbg_read_linear: physical memory read error

Posted: Wed Dec 23, 2015 6:36 pm
by heat
Hi guys :D ,

I'm implementing a higher-half kernel. I followed this tutorial for paging and the one before that for physical MM.

After i followed the higher-half bare bones on the wiki, it could successfully execute code in the higher half (0xC0000000).
All went well until i tried to load a new page directory,which greets me with the following error, followed by a triple fault:

Code: Select all

00084886892i[CPU0  ] CPU is in protected mode (active)
00084886892i[CPU0  ] CS.mode = 32 bit
00084886892i[CPU0  ] SS.mode = 32 bit
00084886892i[CPU0  ] EFER   = 0x00000000
00084886892i[CPU0  ] | EAX=c03ff000  EBX=c0010130  ECX=00000000  EDX=c03ff000
00084886892i[CPU0  ] | ESP=c0113ce8  EBP=c0113ce8  ESI=c0010000  EDI=c0400000
00084886892i[CPU0  ] | IOPL=0 ID vip vif ac vm RF nt of df IF tf SF zf af PF cf
00084886892i[CPU0  ] | SEG sltr(index|ti|rpl)     base    limit G D
00084886892i[CPU0  ] |  CS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00084886892i[CPU0  ] |  DS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00084886892i[CPU0  ] |  SS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00084886892i[CPU0  ] |  ES:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00084886892i[CPU0  ] |  FS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00084886892i[CPU0  ] |  GS:0010( 0002| 0|  0) 00000000 ffffffff 1 1
00084886892i[CPU0  ] | EIP=c010195c (c010195c)
00084886892i[CPU0  ] | CR0=0xe0000011 CR2=0xc0105560
00084886892i[CPU0  ] | CR3=0xc03ff000 CR4=0x00000010
bx_dbg_read_linear: physical memory read error (phy=0x01ffffd0195c, lin=0xc010195c)
00084886892e[CPU0  ] exception(): 3rd (14) exception with no resolution, shutdown status is 00h, resetting
The address it fails to read is a part of my loadPageDirectory function, right after i load cr3 with the page directory address:

Code: Select all

c0101952 <loadPageDirectory>:
c0101952:	55                   	  push   %ebp
c0101953:	89 e5                     mov    %esp,%ebp
c0101955:	8b 44 24 08               mov    0x8(%esp),%eax
c0101959:	0f 22 d8                  mov    %eax,%cr3
c010195c:	89 ec                     mov    %ebp,%esp
c010195e:	5d                   	  pop    %ebp
c010195f:	c3                    	 ret    
(Taken from objdump)

I think the error might be from a failed instruction fetch???Or maybe i overwrote some part of my kernel???

My paging code:

Code: Select all

inline int switch_directory (pdirectory* dir) {
 
	if (!dir)
		return 1;
 
	_cur_directory = dir;
	loadPageDirectory(dir);
	return 0;
}
void init_paging()
{
        ptable* table = 0xC0300000;
        memset(table, 0,sizeof(ptable));
        ptable* table2 = 0xC03F0000;
        memset(table2, 0,sizeof(ptable));
        // 1st 4mb are identity 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_set_bit (&page, _PTE_PRESENT);
 		pt_entry_set_frame (&page, frame);

		//! ...and add it to the page table
		table2->entries [PAGE_TABLE_INDEX (virt) ] = page;
	}
       
        for(int i=0,frame=0x000000,virt=0xC0000000;i<1024;i++,frame+=4096, virt+=4096)
        {
            pt_entry page=0;
            pt_entry_set_bit(&page,_PTE_PRESENT);
            pt_entry_set_frame(&page, frame);
            
            table->entries [PAGE_TABLE_INDEX(virt)] = page;
        }
	pdirectory* dir = 0xC03FF000;
        memset(dir, 0,sizeof(pdirectory));
        pd_entry* entry =&dir->entries [PAGE_DIRECTORY_INDEX (0xC0000000)];
        pd_entry_set_bit (entry,_PDE_PRESENT);
        pd_entry_set_bit (entry,_PDE_WRITABLE);
        pd_entry_set_frame(entry,(physical_addr)table);
        
        pd_entry* entry2 = &dir->entries [PAGE_DIRECTORY_INDEX (0x00000000) ];
	pd_entry_set_bit (entry2, _PDE_PRESENT);
	pd_entry_set_bit (entry2, _PDE_WRITABLE);
	pd_entry_set_frame (entry2, (physical_addr)table2);
        switch_directory(dir);
}
The rest of my code is in this pastebin: http://pastebin.com/GnG69kJN

Thanks for the help guys,
TheRussianFail

Re: bx_dbg_read_linear: physical memory read error

Posted: Thu Dec 24, 2015 2:31 am
by Octocontrabass
TheRussianFail wrote:

Code: Select all

00084886892i[CPU0  ] | CR3=0xc03ff000 CR4=0x00000010
I think I see the problem.

Re: bx_dbg_read_linear: physical memory read error

Posted: Thu Dec 24, 2015 3:46 am
by heat
Octocontrabass wrote:
TheRussianFail wrote:

Code: Select all

00084886892i[CPU0  ] | CR3=0xc03ff000 CR4=0x00000010
I think I see the problem.
Can you please explain me what's wrong with CR3 and/or CR4.I don't understand.The CR3 address is page aligned and everything. :?

Thanks for the help,
TheRussianFail

Re: bx_dbg_read_linear: physical memory read error

Posted: Thu Dec 24, 2015 4:04 am
by Octocontrabass
Intel wrote:The base physical address of the paging-structure hierarchy is contained in control register CR3.

Re: bx_dbg_read_linear: physical memory read error

Posted: Thu Dec 24, 2015 4:22 am
by heat
Octocontrabass wrote:
Intel wrote:The base physical address of the paging-structure hierarchy is contained in control register CR3.
Then how can i use the physical address if its not mapped in virtual memory??By subtracting KERNEL_VIRTUAL_BASE (0xC0000000) from the address,right?And then when i load it into cr3 the page directory addr will be physical and it wont triple fault,right? :?

Thanks for the help,
TheRussianFail

Re: bx_dbg_read_linear: physical memory read error

Posted: Thu Dec 24, 2015 4:48 am
by neon
Hello,

Been wanting to rewrite that...the code is way over complicated. We provided an example of creating a new page directory in Chapter 24 (Process Management 1). Keep in mind that all PTE's, PDE's, and the PDBR store physical addresses not virtual. To create a new page directory, you need to allocate it from the page frame allocator. The physical addresses are used by the CPU - you don't need to use them. You update and reference them through virtual addresses (recursive page directories are a common trick for this.)

Code: Select all

ptable* table = 0xC0300000;
memset(table, 0,sizeof(ptable));
ptable* table2 = 0xC03F0000;
memset(table2, 0,sizeof(ptable));
These are supposed to be physical addresses not virtual. The series allocates these dynamically through the page frame allocator (pmmngr_alloc_block.) This is what you should be doing (the series PMM acts as a page frame number (PFN) database.) When creating new page directories, you should still be calling the PMM to allocate free page frames. You can then map the page table into the page directory which would allow you to map the pages in that table.

That is, map the page tables first in the page directory, then memset them using their virtual address that you mapped it to. Chapter 24 provides a method that makes this process simple - vmmngr_mapPhysicalAddress.

Re: bx_dbg_read_linear: physical memory read error

Posted: Thu Dec 24, 2015 5:24 am
by heat
neon wrote:Hello,

Been wanting to rewrite that...the code is way over complicated. We provided an example of creating a new page directory in Chapter 24 (Process Management 1). Keep in mind that all PTE's, PDE's, and the PDBR store physical addresses not virtual. To create a new page directory, you need to allocate it from the page frame allocator. The physical addresses are used by the CPU - you don't need to use them. You update and reference them through virtual addresses (recursive page directories are a common trick for this.)

Code: Select all

ptable* table = 0xC0300000;
memset(table, 0,sizeof(ptable));
ptable* table2 = 0xC03F0000;
memset(table2, 0,sizeof(ptable));
These are supposed to be physical addresses not virtual. The series allocates these dynamically through the page frame allocator (pmmngr_alloc_block.) This is what you should be doing (the series PMM acts as a page frame number (PFN) database.) When creating new page directories, you should still be calling the PMM to allocate free page frames. You can then map the page table into the page directory which would allow you to map the pages in that table.

That is, map the page tables first in the page directory, then memset them using their virtual address that you mapped it to. Chapter 24 provides a method that makes this process simple - vmmngr_mapPhysicalAddress.
Hi,
First off,I love your series and think you explain stuff very well. :D
I finally got it to work.Thanks to everybody.
I tried using the page frame allocator, but it didn't work. It would page fault everytime when i memset'ed them, simply because the addresses that they returned were not mapped in Virtual Memory.That's why i went with the hardcoded addresses instead of the page fault allocator.

I have two questions:
1-How does the recursive page directory trick work? Is it like mapping the last entry to the page directory address right?
2-How do the page table and page directory indexes work? I looked everywhere but i couldn't understand what do they mean.Is it something thats needed to get right?How can i know where i need to put the PD and PT entry?

Thanks for the help,
TheRussianFail

Re: bx_dbg_read_linear: physical memory read error

Posted: Thu Dec 24, 2015 9:06 am
by neon
Hello,
2-How do the page table and page directory indexes work? I looked everywhere but i couldn't understand what do they mean.Is it something thats needed to get right?How can i know where i need to put the PD and PT entry?
We'll address (2) first. What is most important is being able to visualize the relationship between the page tables and the address space. Let's say that we divide the address space into blocks of 4096 bytes. For the sake of discussion, let's assume the entire address space is 4 GB. This gives us 0x100000000 / 4096 = 0x100000 pages. So page[0] is the first 4096 bytes, page[0xfffff] is the last 4096 bytes. So we have,

Code: Select all

Page Frame    Virtual address range
page[0]       => 0x0000     - 0x1000
page[1]       => 0x1000     - 0x2000
...
page[0xfffff] => 0xfffff000 - 0x100000000
Page tables and the page directory just allow us to break this up even more. Each page table is 1024 page frames. Since each page frame is 4096 bytes in this example, that is 1024 * 4096 = 0x400000, or 4 MB. And so, Page table[0] is the first 4096 pages (first 4MB), Page table[1] is the next 4MB, and so on. So our address map now looks like this,

Code: Select all

Page Table     Virtual address range
table[0]       => 0x0000     - 0x3fffff
table[1]       => 0x400000   - 0x7fffff
...
table[1023]    => ffc00000   - 0x100000000
This is your page directory. Each table contains 1024 pages. For example, table[0] contains pages 0-1023. table[1] contains pages 1024-2047 and so on.

So what do the indices represent?

If a page table maps 4 MB of the address space, the index maps 4096 bytes of it. If a page directory maps 4 GB of the address space, the index maps a page table (which maps a possible 4 MB region.)

For example...If we wanted to map the 4 MB region starting at 0x400000, remember that each page table maps a 4 MB region. So table[0] is first 4 MB, table[1] is next 4 MB etc. So we need to map table[1]. We map tables by putting them in the page directory,

page_directory [1] = (physical_address) page_table | 3;

This sets up a page table and "maps" the 4 MB from 0x400000. So what parts of that 4 MB do we want to actually map? Let's say that we want to actually map 0x402000 into the address space. Recall that the page table is 1024 pages. So page[0] is first 1024 (starting at 0x400000!) page[1] is next 1024 and so on. 0x2000 is at page[3]. So to map this specific page,

/* map 0x400000 - 0x7fffff region. */
page_directory [1] = (physical_address) page_table | 3;

/* map 0x402000 - 0x403000. */
page_table [3] = (physical_address) page | 3;

This maps 0x402000 - 0x403000 into the address space. I hope this clarifies things for you. If you have any doubts, please don't hesitate to ask.
1-How does the recursive page directory trick work? Is it like mapping the last entry to the page directory address right?
To answer (1), recursive page directories are used to easily update and modify page tables and page directories. You would reserve some area of the address space (typically the last 4 MB). You do not have to map the last entry to itself - however it is the most common way of implementing it. Note the above example, if we were to use the last entry, it would be mapping table[1023] in the page directory to, well, the page directory. Note also above that the 4 MB address range for this page table is ffc00000 - ffffffff. This means that your page directory virtual address must be ffc00000. This is where your page tables start.

For the trick to work, you will also have to map table[1023].page[1023]. Since your page tables must begin at ffc00000, we can do some quick math:

ffc00000 + (4*1024)*1023 = fffff000

And and last page table is at fffff000.

The goal of the trick is to be able to access the page directory as a page table. We can modify the page tables directly by accessing them like a page table itself through fffff000. This is the basic idea, although it can be a bit hard at first. It would be a good idea to try to walk through whats going on by hand to get a feel for the trick.