⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 memory.c

📁 带中文注释的 linux 0.11 源代码0.11,很好的
💻 C
📖 第 1 页 / 共 3 页
字号:
      oom ();    }}/** try_to_share() checks the page at address "address" in the task "p",* to see if it exists, and if it is clean. If so, share it with the current* task.** NOTE! This assumes we have checked that p != current, and that they* share the same executable.*//** try_to_share()在任务"p"中检查位于地址"address"处的页面,看页面是否存在,是否干净。* 如果是干净的话,就与当前任务共享。** 注意!这里我们已假定p !=当前任务,并且它们共享同一个执行程序。*///// 尝试对进程指定地址处的页面进行共享操作。// 同时还验证指定的地址处是否已经申请了页面,若是则出错,死机。// 返回1-成功,0-失败。static inttry_to_share (unsigned long address, struct task_struct *p){  unsigned long from;  unsigned long to;  unsigned long from_page;  unsigned long to_page;  unsigned long phys_addr;// 求指定内存地址的页目录项。  from_page = to_page = ((address >> 20) & 0xffc);// 计算进程p 的代码起始地址所对应的页目录项。  from_page += ((p->start_code >> 20) & 0xffc);// 计算当前进程中代码起始地址所对应的页目录项。  to_page += ((current->start_code >> 20) & 0xffc);/* is there a page-directory at from? *//* 在from 处是否存在页目录?*/// *** 对p 进程页面进行操作。// 取页目录项内容。如果该目录项无效(P=0),则返回。否则取该目录项对应页表地址??from。  from = *(unsigned long *) from_page;  if (!(from & 1))    return 0;  from &= 0xfffff000;// 计算地址对应的页表项指针值,并取出该页表项内容??phys_addr。  from_page = from + ((address >> 10) & 0xffc);  phys_addr = *(unsigned long *) from_page;/* is the page clean and present? *//* 页面干净并且存在吗?*/// 0x41 对应页表项中的Dirty 和Present 标志。如果页面不干净或无效则返回。  if ((phys_addr & 0x41) != 0x01)    return 0;// 取页面的地址??phys_addr。如果该页面地址不存在或小于内存低端(1M)也返回退出。  phys_addr &= 0xfffff000;  if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM)    return 0;// *** 对当前进程页面进行操作。// 取页目录项内容??to。如果该目录项无效(P=0),则取空闲页面,并更新to_page 所指的目录项。  to = *(unsigned long *) to_page;  if (!(to & 1))    if (to = get_free_page ())      *(unsigned long *) to_page = to | 7;    else      oom ();// 取对应页表地址??to,页表项地址??to_page。如果对应的页面已经存在,则出错,死机。  to &= 0xfffff000;  to_page = to + ((address >> 10) & 0xffc);  if (1 & *(unsigned long *) to_page)    panic ("try_to_share: to_page already exists");/* share them: write-protect *//* 对它们进行共享处理:写保护 */// 对p 进程中页面置写保护标志(置R/W=0 只读)。并且当前进程中的对应页表项指向它。  *(unsigned long *) from_page &= ~2;  *(unsigned long *) to_page = *(unsigned long *) from_page;// 刷新页变换高速缓冲。  invalidate ();// 计算所操作页面的页面号,并将对应页面映射数组项中的引用递增1。  phys_addr -= LOW_MEM;  phys_addr >>= 12;  mem_map[phys_addr]++;  return 1;}/** share_page() tries to find a process that could share a page with* the current one. Address is the address of the wanted page relative* to the current data space.** We first check if it is at all feasible by checking executable->i_count.* It should be >1 if there are other tasks sharing this inode.*//** share_page()试图找到一个进程,它可以与当前进程共享页面。参数address 是* 当前数据空间中期望共享的某页面地址。** 首先我们通过检测executable->i_count 来查证是否可行。如果有其它任务已共享* 该inode,则它应该大于1。*///// 共享页面。在缺页处理时看看能否共享页面。// 返回1 - 成功,0 - 失败。static intshare_page (unsigned long address){  struct task_struct **p;// 如果是不可执行的,则返回。excutable 是执行进程的内存i 节点结构。  if (!current->executable)    return 0;// 如果只能单独执行(executable->i_count=1),也退出。  if (current->executable->i_count < 2)    return 0;// 搜索任务数组中所有任务。寻找与当前进程可共享页面的进程,并尝试对指定地址的页面进行共享。  for (p = &LAST_TASK; p > &FIRST_TASK; --p)    {      if (!*p)			// 如果该任务项空闲,则继续寻找。	continue;      if (current == *p)	// 如果就是当前任务,也继续寻找。	continue;      if ((*p)->executable != current->executable)	// 如果executable 不等,也继续。	continue;      if (try_to_share (address, *p))	// 尝试共享页面。	return 1;    }  return 0;}//// 页异常中断处理调用的函数。处理缺页异常情况。在page.s 程序中被调用。// 参数error_code 是由CPU 自动产生,address 是页面线性地址。voiddo_no_page (unsigned long error_code, unsigned long address){  int nr[4];  unsigned long tmp;  unsigned long page;  int block, i;  address &= 0xfffff000;	// 页面地址。// 首先算出指定线性地址在进程空间中相对于进程基址的偏移长度值。  tmp = address - current->start_code;// 若当前进程的executable 空,或者指定地址超出代码+数据长度,则申请一页物理内存,并映射// 影射到指定的线性地址处。executable 是进程的i 节点结构。该值为0,表明进程刚开始设置,// 需要内存;而指定的线性地址超出代码加数据长度,表明进程在申请新的内存空间,也需要给予。// 因此就直接调用get_empty_page()函数,申请一页物理内存并映射到指定线性地址处即可。// start_code 是进程代码段地址,end_data 是代码加数据长度。对于linux 内核,它的代码段和// 数据段是起始基址是相同的。  if (!current->executable || tmp >= current->end_data)    {      get_empty_page (address);      return;    }// 如果尝试共享页面成功,则退出。  if (share_page (tmp))    return;// 取空闲页面,如果内存不够了,则显示内存不够,终止进程。  if (!(page = get_free_page ()))    oom ();/* remember that 1 block is used for header *//* 记住,(程序)头要使用1 个数据块 */// 首先计算缺页所在的数据块项。BLOCK_SIZE = 1024 字节,因此一页内存需要4 个数据块。  block = 1 + tmp / BLOCK_SIZE;// 根据i 节点信息,取数据块在设备上的对应的逻辑块号。  for (i = 0; i < 4; block++, i++)    nr[i] = bmap (current->executable, block);// 读设备上一个页面的数据(4 个逻辑块)到指定物理地址page 处。  bread_page (page, current->executable->i_dev, nr);// 在增加了一页内存后,该页内存的部分可能会超过进程的end_data 位置。下面的循环即是对物理// 页面超出的部分进行清零处理。  i = tmp + 4096 - current->end_data;  tmp = page + 4096;  while (i-- > 0)    {      tmp--;      *(char *) tmp = 0;    }// 如果把物理页面映射到指定线性地址的操作成功,就返回。否则就释放内存页,显示内存不够。  if (put_page (page, address))    return;  free_page (page);  oom ();}//// 物理内存初始化。// 参数:start_mem - 可用作分页处理的物理内存起始位置(已去除RAMDISK 所占内存空间等)。// end_mem - 实际物理内存最大地址。// 在该版的linux 内核中,最多能使用16Mb 的内存,大于16Mb 的内存将不于考虑,弃置不用。// 0 - 1Mb 内存空间用于内核系统(其实是0-640Kb)。voidmem_init (long start_mem, long end_mem){  int i;  HIGH_MEMORY = end_mem;	// 设置内存最高端。  for (i = 0; i < PAGING_PAGES; i++)	// 首先置所有页面为已占用(USED=100)状态,    mem_map[i] = USED;		// 即将页面映射数组全置成USED。  i = MAP_NR (start_mem);	// 然后计算可使用起始内存的页面号。  end_mem -= start_mem;		// 再计算可分页处理的内存块大小。  end_mem >>= 12;		// 从而计算出可用于分页处理的页面数。  while (end_mem-- > 0)		// 最后将这些可用页面对应的页面映射数组清零。    mem_map[i++] = 0;}// 计算内存空闲页面数并显示。voidcalc_mem (void){  int i, j, k, free = 0;  long *pg_tbl;// 扫描内存页面映射数组mem_map[],获取空闲页面数并显示。  for (i = 0; i < PAGING_PAGES; i++)    if (!mem_map[i])      free++;  printk ("%d pages free (of %d)\n\r", free, PAGING_PAGES);// 扫描所有页目录项(除0,1 项),如果页目录项有效,则统计对应页表中有效页面数,并显示。  for (i = 2; i < 1024; i++)    {      if (1 & pg_dir[i])	{	  pg_tbl = (long *) (0xfffff000 & pg_dir[i]);	  10.5 page.s 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -