1:进程控制块
2:进程的内存模型
也就是说假设4g内存,每个进程都独占除kernel space 的所有4g内存空间
栈帧esp ebp
3:CPU的工作模型
4:虚拟内存和物理内存
共享内存:
共享内存的核心其实是put_page();找到相同的物理地址,然后再映射回去
void * sys_shmat(int shmid)
{
int i;
unsigned long data_base, brk;
if(shmid < 0 || SHM_SIZE <= shmid || shm_list[shmid].page==0 || shm_list[shmid].key <= 0)
return (void *)-EINVAL;
data_base = get_base(current->ldt[2]);
printk("current's data_base = 0x%08x,new page = 0x%08x\n",data_base,shm_list[shmid].page);
brk = current->brk + data_base;
current->brk += PAGE_SIZE;
if(put_page(shm_list[shmid].page, brk) == 0)
return (void *)-ENOMEM;
//将物理地址shm_list[shimid].page映射到进程的虚拟地址brk上
return (void *)(current->brk - PAGE_SIZE);
}
//put_page就是将物理地址映射到虚拟地址的
//page是物理地址 address是虚拟地址
unsigned long put_page(unsigned long page,unsigned long address)
{
unsigned long tmp, *page_table;
//memmap其实就是page管理,看4G内存哪个被分配了 一页4kb所以右移12
if (page < LOW_MEM || page >= HIGH_MEMORY)
printk("Trying to put page %p at %p\n",page,address);
if (mem_map[(page-LOW_MEM)>>12] != 1)
printk("mem_map disagrees with %p at %p\n",page,address);
page_table = (unsigned long *) ((address>>20) & 0xffc);
//这里是这么理解 *pagetable通过mmu去找前12位对应的地址,如果有效则说明mmu建立了映射,无效则取get——free——page
//*pagetable其实就是页表实际保存的物理地址
if ((*page_table)&1)
page_table = (unsigned long *) (0xfffff000 & *page_table);//找前20位对应的页表然后找到
//前10位对应的地址保存的是页表项的地址
//中间10位的地址保存的是页的地址
else {
if (!(tmp=get_free_page()))
return 0;
*page_table = tmp|7;
page_table = (unsigned long *) tmp;
}
page_table[(address>>12) & 0x3ff] = page | 7;
/* no need for invalidate */
return page;
}
这段代码将物理页映射到虚拟地址。逐行解释如下:
unsigned long tmp, *page_table;
定义了临时变量 tmp 和页表指针 page_table。
if (page < LOW_MEM || page >= HIGH_MEMORY)
检查物理页是否在有效的低内存和高内存范围内。
printk("Trying to put page %p at %p\n",page,address);
如果页不在有效范围内,打印警告信息。
if (mem_map[(page-LOW_MEM)>>12] != 1)
验证 mem_map 中该页的状态是否与预期一致。
printk("mem_map disagrees with %p at %p\n",page,address);
如果 mem_map 不一致,打印警告信息。
page_table = (unsigned long *) ((address>>20) & 0xffc);
计算虚拟地址所在页表的地址。将虚拟地址右移20位后取低12位,得到页目录项的地址。
if ((*page_table)&1)
检查页表是否已经存在。如果存在,页表项的最低位应为1。
page_table = (unsigned long *) (0xfffff000 & *page_table);
如果页表项存在,提取页表的物理地址(掩码为 0xfffff000)。
else {
如果页表项不存在:
if (!(tmp=get_free_page()))
尝试分配一个新的页。如果失败,返回0。
*page_table = tmp|7;
更新页表项,设置为新分配的页地址,并设置标志位。
page_table = (unsigned long *) tmp;
更新 page_table 指针,指向新的页表。
}
结束 else 代码块。
page_table[(address>>12) & 0x3ff] = page | 7;
在页表中设置虚拟地址到物理页的映射,标志位也设置。
return page;
返回物理页的地址。
异常和中断
IDT
idt介绍
fork调用原理:
写时复制:
进程组:
进程切换的场景:
进程和线程的切换: