OSDev.org

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

All times are UTC - 6 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: the virtual address points to the wrong physical address!
PostPosted: Mon Jul 05, 2021 7:18 am 
Offline

Joined: Mon Jul 05, 2021 7:05 am
Posts: 8
Hi:
I developed a os, in one user process,I had loaded cr3 register in the corresponding kernel thread,the code is follow:
Code:
/* 激活页表 */
void page_dir_activate(struct task_struct* p_thread) {
    /********************************************************************
     * 执行此函数时,当前任务可能是线程
     * 之所以对线程也要重新安装页表,原因是上一次被调度的可能是进程,
     * 否则不恢复页表的话,线程就会使用进程的页表了。
     * *****************************************************/
   
    /* 若为内核线程,需要重新填充页表为 0x100000 */
    uint32_t pagedir_phy_addr = 0x100000;  // 默认为内核的页目录物理地址,也就是内核线程所用的页目录表
    if(p_thread->pgdir != NULL) {     // 用户态进程有自己的页目录表
      pagedir_phy_addr = addr_v2p((uint32_t)p_thread->pgdir);
    }
    /* 更新页目录寄存器 cr3, 使新页表生效 */
    asm volatile ("movl %0, %%cr3" : : "r" (pagedir_phy_addr) : "memory");
}



here is the code which I use 'info tab' in the Bochs

Code:


<bochs:25> info tab
cr3: 0x00000025a000
0x0000000008048000-0x0000000008049fff -> 0x000010105000-0x000010106fff
0x000000000804a000-0x000000000804afff -> 0x000010108000-0x000010108fff
0x000000000804b000-0x000000000804bfff -> 0x00001010a000-0x00001010afff
0x00000000080a0000-0x00000000080a0fff -> 0x000010109000-0x000010109fff
0x00000000bffff000-0x00000000bfffffff -> 0x000010107000-0x000010107fff
0x00000000c0000000-0x00000000c00fffff -> 0x000000000000-0x0000000fffff
0x00000000c0100000-0x00000000c011dfff -> 0x000000200000-0x00000021dfff
0x00000000c011e000-0x00000000c0138fff -> 0x000000220000-0x00000023afff
0x00000000c0139000-0x00000000c013dfff -> 0x00000023d000-0x000000241fff
0x00000000c013f000-0x00000000c0156fff -> 0x000000243000-0x00000025afff
0x00000000ffc20000-0x00000000ffc20fff -> 0x00000025b000-0x00000025bfff
0x00000000ffeff000-0x00000000ffefffff -> 0x00000025c000-0x00000025cfff
0x00000000fff00000-0x00000000ffffefff -> 0x000000101000-0x0000001fffff
0x00000000fffff000-0x00000000ffffffff -> 0x00000025a000-0x00000025afff
<bochs:26>


everything is as I expected,but when the code write data to the '804b000' virtual address,it always write into '0x000010109000' physical address, not the '0x00001010a000'.
I don't know why, could anyone help me, thanks a lot!


Top
 Profile  
 
 Post subject: the virtual address points to the wrong physical address!
PostPosted: Mon Jul 05, 2021 7:51 am 
Offline

Joined: Mon Jul 05, 2021 7:05 am
Posts: 8
Hi:
I developed an os, in a user process, I had loaded cr3 register in corresponding kernel thread, here is the code:

Code:


/* 激活页表 */
void page_dir_activate(struct task_struct* p_thread) {
    /********************************************************************
     * 执行此函数时,当前任务可能是线程
     * 之所以对线程也要重新安装页表,原因是上一次被调度的可能是进程,
     * 否则不恢复页表的话,线程就会使用进程的页表了。
     * *****************************************************/
   
    /* 若为内核线程,需要重新填充页表为 0x100000 */
    uint32_t pagedir_phy_addr = 0x100000;  // 默认为内核的页目录物理地址,也就是内核线程所用的页目录表
    if(p_thread->pgdir != NULL) {     // 用户态进程有自己的页目录表
      pagedir_phy_addr = addr_v2p((uint32_t)p_thread->pgdir);
    }
    /* 更新页目录寄存器 cr3, 使新页表生效 */
    asm volatile ("movl %0, %%cr3" : : "r" (pagedir_phy_addr) : "memory");
}




in the user process,when use malloc or free,I used 'page_table_pte_remove' and 'page_table_add' function to flush TLB, here is the code
Code:
/* 去掉页表中虚拟地址vaddr的映射,只去掉vaddr对应的pte */
static void page_table_pte_remove(uint32_t vaddr) {
   uint32_t* pte = pte_ptr(vaddr);
   *pte &= ~PG_P_1;   // 将页表项pte的P位置0
   asm volatile ("
              %0"::"m" (vaddr):"memory");    //更新tlb
}



Code:


/* 页表中添加虚拟地址_vaddr与物理地址_page_phyaddr的映射 */
void page_table_add(void* _vaddr, void* _page_phyaddr) {
   uint32_t vaddr = (uint32_t)_vaddr, page_phyaddr = (uint32_t)_page_phyaddr;
   uint32_t* pde = pde_ptr(vaddr);
   uint32_t* pte = pte_ptr(vaddr);
#ifdef KERNEL_MEMORY_DEBUG
   //printk("_vaddr-::0x%x-::0x%x-::0x%x:",_vaddr,pde,pte);
   put_str("_vaddr-::");
   put_int(_vaddr);
   put_str("-::");
   put_int(pde);
   put_str("-::");
   put_int(*pte);
   put_str("-::");
   put_str("\n");
#endif
   /************************   注意   *************************
    * 执行*pte,会访问到pde。所以确保pde创建完成后才能执行*pte,
    * 否则会引发page_fault。因此在pde未创建时,
    * *pte只能出现在下面最外层else语句块中的*pde后面。
    * *********************************************************/
   /* 先在页目录内判断目录项的P位,若为1,则表示该表已存在 */
   if (*pde & 0x00000001) {
      ASSERT(!(*pte & 0x00000001));
      
      if (!(*pte & 0x00000001)) {   // 只要是创建页表,pte就应该不存在,多判断一下放心
         *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);    // US=1,RW=1,P=1
      } else {     // 调试模式下不会执行到此,上面的ASSERT会先执行.关闭调试时下面的PANIC会起作用
         PANIC("pte repeat");
      }
   } else {      // 页目录项不存在,所以要先创建页目录项再创建页表项.
      /* 页表中用到的页框一律从内核空间分配 */
      uint32_t pde_phyaddr = (uint32_t)palloc(&kernel_pool);
      *pde = (pde_phyaddr | PG_US_U | PG_RW_W | PG_P_1);
      
      /*******************   必须将页表所在的页清0   *********************
       * 必须把分配到的物理页地址pde_phyaddr对应的物理内存清0,
       * 避免里面的陈旧数据变成了页表中的页表项,从而让页表混乱.
       * pte的高20位会映射到pde所指向的页表的物理起始地址.*/
      memset((void*)((int)pte & 0xfffff000), 0, PG_SIZE);
      /************************************************************/
      ASSERT(!(*pte & 0x00000001));
      *pte = (page_phyaddr | PG_US_U | PG_RW_W | PG_P_1);      // US=1,RW=1,P=1
   }
}



in the bochs, when used 'info tab' command, it's shown:
Code:

<bochs:25> info tab
cr3: 0x00000025a000
0x0000000008048000-0x0000000008049fff -> 0x000010105000-0x000010106fff
0x000000000804a000-0x000000000804afff -> 0x000010108000-0x000010108fff
0x000000000804b000-0x000000000804bfff -> 0x00001010a000-0x00001010afff
0x00000000080a0000-0x00000000080a0fff -> 0x000010109000-0x000010109fff
0x00000000bffff000-0x00000000bfffffff -> 0x000010107000-0x000010107fff
0x00000000c0000000-0x00000000c00fffff -> 0x000000000000-0x0000000fffff
0x00000000c0100000-0x00000000c011dfff -> 0x000000200000-0x00000021dfff
0x00000000c011e000-0x00000000c0138fff -> 0x000000220000-0x00000023afff
0x00000000c0139000-0x00000000c013dfff -> 0x00000023d000-0x000000241fff
0x00000000c013f000-0x00000000c0156fff -> 0x000000243000-0x00000025afff
0x00000000ffc20000-0x00000000ffc20fff -> 0x00000025b000-0x00000025bfff
0x00000000ffeff000-0x00000000ffefffff -> 0x00000025c000-0x00000025cfff
0x00000000fff00000-0x00000000ffffefff -> 0x000000101000-0x0000001fffff
0x00000000fffff000-0x00000000ffffffff -> 0x00000025a000-0x00000025afff
<bochs:26>


everything is as I expected, but when the os exec code writes data to the '0x804b000' virtual address, it wrote to the '0x000010109000' physical address, not the '0x00001010a000' physical address.

I don't know why could anyone help me? thanks a lot!


Top
 Profile  
 
 Post subject: Re: the virtual address points to the wrong physical address
PostPosted: Mon Jul 05, 2021 10:01 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5103
Princekin wrote:
Code:
   asm volatile ("
              %0"::"m" (vaddr):"memory");    //更新tlb

Your code does not flush the TLB. Are you trying to use INVLPG?

If you want to use INVLPG, it should look like this:

Code:
asm volatile ( "invlpg %0" :: "m"(*(uint8_t*)vaddr) : "memory" );


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], DotBot [Bot], Google [Bot] and 173 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