lab4

2023-11-01

这一个lab主要学习进程管理和进程通讯,come on,好好学习

PART A: 多处理器支持

Exercise 1:
void *
mmio_map_region(physaddr_t pa, size_t size)
{
	// Where to start the next region.  Initially, this is the
	// beginning of the MMIO region.  Because this is static, its
	// value will be preserved between calls to mmio_map_region
	// (just like nextfree in boot_alloc).
	static uintptr_t base = MMIOBASE;

	// Reserve size bytes of virtual memory starting at base and
	// map physical pages [pa,pa+size) to virtual addresses
	// [base,base+size).  Since this is device memory and not
	// regular DRAM, you'll have to tell the CPU that it isn't
	// safe to cache access to this memory.  Luckily, the page
	// tables provide bits for this purpose; simply create the
	// mapping with PTE_PCD|PTE_PWT (cache-disable and
	// write-through) in addition to PTE_W.  (If you're interested
	// in more details on this, see section 10.5 of IA32 volume
	// 3A.)
	//
	// Be sure to round size up to a multiple of PGSIZE and to
	// handle if this reservation would overflow MMIOLIM (it's
	// okay to simply panic if this happens).
	//
	// Hint: The staff solution uses boot_map_region.
	//
	// Your code here:
	uintptr_t nextBase=base+ROUNDUP(size,PGSIZE);
	uintptr_t i;
	if(nextBase>=MMIOLIM) panic(" mmio_map_region: mmio is out of limit\n");
	boot_map_region(kern_pgdir,base,ROUNDUP(size,PGSIZE),pa,PTE_PCD|PTE_PWT|PTE_W);
	i=base;
	base=nextBase;
	return (void *)i;
	//panic("mmio_map_region not implemented");
}


Exercise 2:
void
page_init(void)
{
	
	size_t i;
	uint32_t j=((uint32_t)boot_alloc(0)-KERNBASE)/PGSIZE;
	uint32_t j2=IOPHYSMEM/PGSIZE;
	uint32_t j3=MPENTRY_PADDR/PGSIZE;
	for (i = npages-1; i>=1; i--) {
		//the physical memory pages that has been used by pages and kernel 
		
		//cprintf("rrrrrrrrrrrrrrrrr");
		if(!((i>=j2&&i<j)||i==0||i==j3)){
			pages[i].pp_ref = 0;
			pages[i].pp_link = page_free_list;
			page_free_list = &pages[i];
		}
	}
}


Question 1:
MPBOOTPHYS(start32)是取得start32的物理地址
为什么ljmpl $(PROT_MODE_CSEG),$(MPBOOTPHYS(start32),中需要取得start32的物理地址?
在boot/boot.s中,0-4M线性地址空间被映射到0-4M物理内存,start的线性地址与实际的物理地址一样,使用相对地址跳转后,还是跳转到protcseg, 所以不需要求物理地址;
而在这里,mpentry.s从别的地方拷贝过来的,其中start32是相对于mpentry_start的地址,这个地址与启用用保护模式后start32所在的物理地址不同,所以跳转不到start32指令处。
记住ljmpl后,就是跳转到cs+EIP的地址去,这里的内容就是cs+EIP转化为物理地址后,这个物理内存的内容。
深入理解跳转的含义!!!
Exercise 3:
static void
mem_init_mp(void)
{

	// LAB 4: Your code here:
	uint32_t i,stacki_beginV,stacki_beginPh;
	for(i=0;i<NCPU;i++){
	 stacki_beginV=(uint32_t)(KSTACKTOP-i*(KSTKSIZE + KSTKGAP)-KSTKSIZE);
	 //stacki_beginPh=(uint32_t)(bootstacktop-i*(KSTKSIZE + KSTKGAP)-KSTKSIZE);
	 boot_map_region(kern_pgdir,stacki_beginV,KSTKSIZE,PADDR(percpu_kstacks[i]),PTE_W|PTE_P);
	}

}


Exercise 4:

void
trap_init_percpu(void)
{
// LAB 4: Your code here:

	// Setup a TSS so that we get the right stack
	// when we trap to the kernel.
	//ts.ts_esp0 = KSTACKTOP;
	//ts.ts_ss0 = GD_KD;
	uint8_t i=thiscpu->cpu_id;
	thiscpu->cpu_ts.ts_esp0=KSTACKTOP-i*(KSTKSIZE+KSTKGAP);
	thiscpu->cpu_ts.ts_ss0=GD_KD;
	// Initialize the TSS slot of the gdt.
	//gdt[GD_TSS0 >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
	//				sizeof(struct Taskstate), 0);
	//gdt[GD_TSS0 >> 3].sd_s = 0;
	gdt[(GD_TSS0>>3)+i]=SEG16(STS_T32A,(uint32_t)(&thiscpu->cpu_ts),sizeof(struct Taskstate),0);
	gdt[(GD_TSS0>>3)+i].sd_s = 0;
	

	// Load the TSS selector (like other segment selectors, the
	// bottom three bits are special; we leave them 0)
	ltr(GD_TSS0+(i<<3));

	// Load the IDT
	lidt(&idt_pd);
}

Exercise 5: 很简单
Question 2: 为什么呢?user->kernel,使用kernel栈? 使用完后,下一次再进入kernel,栈中数据清空了!
                   考虑极端情况,如果某个cpu A在使用kernel, cpu B用户程序运行时产生中断,这时cpu B直接将数据保存到内核堆栈,而这时还没有申请big kernel lock呢!!!

Challenge 1:这个很难呀,很难! 

Exercise 6:这个花了我好长的时间,kernel总是崩掉,后来经过仔细调试,发现有两点影响这个问题:1. 以前lab所编写的函数env_setup_vm没有将这次试验中用到的MMIOBASE-MMIOLIM之间的内用拷贝到enviroment的页目录中去。2.就是trap_init_percpu中thiscpu->cpu_ts.ts_esp0的赋值,我一开始给出的是percpu_kstacks[i],不知为什么使用这个总是出现问题,必须使用KSTACKTOP-i*(KSTKSIZE+KSTKGAP), 可能有别的地方用到了这个地址了

static int
env_setup_vm(struct Env *e)
{
	int i;
	struct PageInfo *p = NULL;

	// Allocate a page for the page directory
	if (!(p = page_alloc(ALLOC_ZERO)))
		return -E_NO_MEM;

	// Now, set e->env_pgdir and initialize the page directory.
	//
	// Hint:
	//    - The VA space of all envs is identical above UTOP
	//	(except at UVPT, which we've set below).
	//	See inc/memlayout.h for permissions and layout.
	//	Can you use kern_pgdir as a template?  Hint: Yes.
	//	(Make sure you got the permissions right in Lab 2.)
	//    - The initial VA below UTOP is empty.
	//    - You do not need to make any more calls to page_alloc.
	//    - Note: In general, pp_ref is not maintained for
	//	physical pages mapped only above UTOP, but env_pgdir
	//	is an exception -- you need to increment env_pgdir's
	//	pp_ref for env_free to work correctly.
	//    - The functions in kern/pmap.h are handy.

	// LAB 3: Your code here.
	e->env_pgdir = (pde_t *)page2kva(p);
    memmove(e->env_pgdir, kern_pgdir, PGSIZE);
    memset(e->env_pgdir, 0, PDX(UTOP)*sizeof(pde_t));
    p->pp_ref ++;
	
	// UVPT maps the env's own page table read-only.
	// Permissions: kernel R, user R
	e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_P | PTE_U;

	return 0;
}
void
sched_yield(void)
{
	struct Env *idle;

	// Implement simple round-robin scheduling.
	//
	// Search through 'envs' for an ENV_RUNNABLE environment in
	// circular fashion starting just after the env this CPU was
	// last running.  Switch to the first such environment found.
	//
	// If no envs are runnable, but the environment previously
	// running on this CPU is still ENV_RUNNING, it's okay to
	// choose that environment.
	//
	// Never choose an environment that's currently running on
	// another CPU (env_status == ENV_RUNNING). If there are
	// no runnable environments, simply drop through to the code
	// below to halt the cpu.

	// LAB 4: Your code here.
	
    int i;
	if(thiscpu->cpu_env != NULL) {
		int cur_env_id = thiscpu->cpu_env->env_id;
		cur_env_id = ENVX(cur_env_id);
		for(i = (cur_env_id+1)%NENV; i != cur_env_id; i = (i+1)%NENV) {
			if(envs[i].env_status == ENV_RUNNABLE)
				break;
		}
		if(i != cur_env_id)
		env_run(&envs[i]);
		if(thiscpu->cpu_env->env_status == ENV_RUNNING)
		env_run(thiscpu->cpu_env);
     }else{
        for(i = 0; i<NENV; i++){
			if(envs[i].env_status == ENV_RUNNABLE)
				break;
		}
		if(i!=NENV) env_run(&envs[i]);
     }
	// sched_halt never returns
	sched_halt();
}

Question 3: 所有envrioment中的kernel线性地址部分都一样,和没有进入environment前的kernel一样. 所以按理说exericse6中使用percpu_kstacks[i]也正确,但是不知为什么总是报中断问题!!
Question 4: 使用sys_yield(),从用户模式进入kernel模式,trap.c中就保存在envs中了
Challenge 2: 添加一个系统调用,设置priority, 这样可以设置每个env的优先级
Challenge 3: env添加一些保存的项目
Exercise 7:
static envid_t
sys_exofork(void)
{
	// Create the new environment with env_alloc(), from kern/env.c.
	// It should be left as env_alloc created it, except that
	// status is set to ENV_NOT_RUNNABLE, and the register set is copied
	// from the current environment -- but tweaked so sys_exofork
	// will appear to return 0.

	// LAB 4: Your code here.
	struct Env *newenv_store=NULL;
	int r=env_alloc(&newenv_store,curenv->env_id);
	if(r<0) {cprintf("env_alloc error: %e", r);return r;}
	newenv_store->env_tf=curenv->env_tf;
	//memmove((void *)&(newenv_store->env_tf),(const void *)&(curenv->env_tf), sizeof(struct Trapframe));
	newenv_store->env_status=ENV_NOT_RUNNABLE;
	newenv_store->env_tf.tf_regs.reg_eax=0;
	return newenv_store->env_id;
	//panic("sys_exofork not implemented");
}

static int
sys_env_set_status(envid_t envid, int status)
{
	// Hint: Use the 'envid2env' function from kern/env.c to translate an
	// envid to a struct Env.
	// You should set envid2env's third argument to 1, which will
	// check whether the current environment has permission to set
	// envid's status.

	// LAB 4: Your code here.
	struct Env *newenv_store=NULL;
	int i=envid2env(envid,&newenv_store,1);
	if(i<0) return -E_BAD_ENV;
	if((status==ENV_RUNNABLE)||(status==ENV_NOT_RUNNABLE)){
		newenv_store->env_status=status;
		return 0;
	}else{
	     cprintf("xxxxxxxxxxx   status %d\n",status);
	     return -E_INVAL;
	}

	
	//panic("sys_env_set_status not implemented");
}
static int
sys_page_alloc(envid_t envid, void *va, int perm)
{
	// Hint: This function is a wrapper around page_alloc() and
	//   page_insert() from kern/pmap.c.
	//   Most of the new code you write should be to check the
	//   parameters for correctness.
	//   If page_insert() fails, remember to free the page you
	//   allocated!

	// LAB 4: Your code here.
	if(((uint32_t)va>=UTOP)||((uint32_t)va%PGSIZE!=0))return -E_INVAL;
	if(!((perm&PTE_U)&&(perm&PTE_P)))return -E_INVAL;
	if(perm&(~PTE_SYSCALL))return -E_INVAL;
	struct Env *newenv_store=NULL;
	int i=envid2env(envid,&newenv_store,1);
	if(i<0) return -E_BAD_ENV;
	struct PageInfo *pageinfo=page_alloc(ALLOC_ZERO);
	if(pageinfo==NULL) return -E_NO_MEM;
	
	i=page_insert(newenv_store->env_pgdir,pageinfo,va,perm);
	if(i<0) {
		page_free(pageinfo);
		return -E_NO_MEM;
	}
	return 0;
	//panic("sys_page_alloc not implemented");
}

static int
sys_page_map(envid_t srcenvid, void *srcva,
	     envid_t dstenvid, void *dstva, int perm)
{
	// Hint: This function is a wrapper around page_lookup() and
	//   page_insert() from kern/pmap.c.
	//   Again, most of the new code you write should be to check the
	//   parameters for correctness.
	//   Use the third argument to page_lookup() to
	//   check the current permissions on the page.

	// LAB 4: Your code here.
	if(((uint32_t)srcva>=UTOP)||((uint32_t)srcva%PGSIZE!=0))return -E_INVAL;
	if(((uint32_t)dstva>=UTOP)||((uint32_t)dstva%PGSIZE!=0))return -E_INVAL;
	if(!((perm&PTE_U)&&(perm&PTE_P)))return -E_INVAL;
	if(perm&(~PTE_SYSCALL))return -E_INVAL;
	struct Env *newenv_store=NULL;
	int i=envid2env(srcenvid,&newenv_store,1);
	if(i<0) return -E_BAD_ENV;
	pte_t *ptet=NULL;
	struct PageInfo *pageinfo=page_lookup(newenv_store->env_pgdir,srcva,&ptet);
	if(pageinfo==NULL)return -E_INVAL;
	if(perm&PTE_W){
		if(!(*ptet&PTE_W))return -E_INVAL;
	}
	i=envid2env(dstenvid,&newenv_store,1);
	if(i<0) return -E_BAD_ENV;
	i=page_insert(newenv_store->env_pgdir,pageinfo,dstva,perm);
	if(i<0)return -E_NO_MEM;
	return 0;
	//panic("sys_page_map not implemented");
}

static int
sys_page_unmap(envid_t envid, void *va)
{
	// Hint: This function is a wrapper around page_remove().

	// LAB 4: Your code here.
	if(((uint32_t)va>=UTOP)||((uint32_t)va%PGSIZE!=0))return -E_INVAL;
	struct Env *newenv_store=NULL;
	int i=envid2env(envid,&newenv_store,1);
	if(i<0) return -E_BAD_ENV;
	pte_t *ptet=NULL;
	struct PageInfo *pageinfo=page_lookup(newenv_store->env_pgdir,va,&ptet);
	if(pageinfo==NULL)return 0;
	page_remove(newenv_store->env_pgdir,va);
	return 0;
	//panic("sys_page_unmap not implemented");
}

int32_t syscall中添加:
case SYS_exofork:
			r=sys_exofork();
			break;
		case SYS_page_alloc:
			r=sys_page_alloc((envid_t)a1,(void *) a2,(int)a3);
			break;
		case SYS_page_map:
			r=sys_page_map((envid_t)a1,(void*)a2,(envid_t)a3,(void*)a4,(int)a5);
			break;
		case SYS_page_unmap:
			r=sys_page_unmap((envid_t)a1,(void*)a2);
			break;
		case SYS_env_set_status:
			r=sys_env_set_status((envid_t)a1,(int)a2);
			break;

注意:sys_page_umap中我一开始未使用page_remove,而使用*ptet=0,哈哈,这样不行呀,导致系统崩溃!!!
Challenge 4: 这个和进程干冻差不多,哈哈,未做!

PART B: Copy-on-write fork

Exercise 9:
Exercise 10:
Exercise 11:
Challenge 4:怎么要处理user environment所有的异常呢?现代OS中都是这么搞的?为什么是用户程序来处理这些呢??
Exercise 12: 这几个exercises没认真做,看明白了ruizhe huang的代码, pfentry.s的代码注意,如何实现user unexception-> user normal模式和user->unexception? 将eip保存到空白中,esp指到这个空白处,然后pop %esp,然后ret(pop %eip),这样就跳转过去了,真的很tricky,很tricky
Challenge 5,6:未做 

PART C: Preemptive Multitasking and IPC

Exersice 13:很简单, 使用SEGGATE时,设置为中断门,而不是异常门。

Exersice 14:时钟中断为IRQ0,对应处理函数为routine_irq0

trap_dispatch中添加:

case (IRQ_OFFSET+IRQ_TIMER):
			lapic_eoi();
			sched_yield();
			return;


Exercise 15: 具体实现IPC,就是实现两个系统调用,send和recv,来实现进程通信。具体没做,看huangrui zhe的实验报告跑了跑
最后几个Challenge也未做
2013.7.29-2012.8.4
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

lab4 的相关文章

随机推荐

  • C++ vector容器-45-vector互换和节省空间和预留空间

    这篇来学习vector一个互换操作 也就是有两个vector对象 可以通过一个api 把两个对象互换过来 实际上 就是在内存中交换了对象的指针 原来的指针指向新的vector对象 这种交换有时候是很有必要 特别是匿名vector对象进行交换
  • UE4蓝图系统详细讲解

    关于UE4蓝图系统原理可以参考 UE4编辑器进阶 里面清楚的讲解了关于编辑器开发所涉及到的知识点 比如蓝图开发 虚拟机开发 蓝图编译 反射数据 序列化字节码等
  • 解决Mac安装Homebrew失败

    首先使用Homebrew官网的安装shell命令安装 bin bash c curl fsSL https raw githubusercontent com Homebrew install HEAD install sh 会出现如下错误
  • JSON.stringify()和JSON.parse()应用场景

    前言 JSON stringify 将对象 数组转换成字符串 JSON parse 将字符串转成json对象 应用场景 1 a 浏览器创建 获取 sessionStorage localStorage 数组内容 b 路由 浏览器地址 传参
  • 如何新建一个duilib项目(手把手创建)

    如何新建一个duilib项目 duilib示例项目下载 0积分下载 1 创建项目目录 在桌面上新建一个文件夹 MyDuilib 用来做我们项目的根目录 2 创建一个Win32项目 1 打开VS2013 新建一个 Win32项目 项目目录选择
  • uniapp运行到小程序之无法启动

    创建了一个uniapp项目 要求是在H5以及小程序都可运行 H5端很容易实现 那么我们来一起探讨小程序遇到的问题 首先 HbuilderX运行到微信小程序 前提是要安装微信开发者工具 来模拟手机上的小程序情景 运行报错 原因是微信小程序工具
  • 国产WMS仓库管理系统排名

    导读 WMS仓库管理系统是通过入库业务 出库业务 仓库调拨 库存调拨和虚仓管理等功能 对批次管理 物料对应 库存盘点 质检管理 虚仓管理和即时库存管理等功能综合运用的管理系统 可以有效控制并跟踪仓库业务的物流及成本管理的全过程 实现或完善企
  • 学习笔记 JavaScript ES6 Webpack核心概念

    学习内容 入口 entry 出口 output Loader 插件 plugin 模式 mode ES6 新特性的语法是无法被浏览器所识别的 浏览器只能识别ES5的语法 所以ES6 需要使用一个工具 把语法转化为ES5的语法 这个工具就是B
  • MyBatis3框架详解(四)

    一 select元素 select标签元素是用来定义查询操作的 id属性 唯一标识符 用来引用这条语句 需要和接口的方法名一致 parameterType属性 参数类型 可以不传 mybatis会根据TypeHandler自动推断 resu
  • 计算机网络3—网络层

    IP报文的格式和各个字段的含义 掌握IP分片 如何避免IP分片 在应用层做限制 在传输层做限制 如何确定分片顺序 接收端如何确定所有分片都到了 IP线路 路由表 路由表每个字段的含义 ICMP协议 查询 报错 ICMP协议的层次和作用 IC
  • java异常NoClassDefFoundError

    这个问题错误原因众多 如下是我在解析数据时遇到的问题并附上解决方法 遇到这样的问题 java lang ClassNotFoundException serialization Serializer 提示没有找到定义的Class 查看各个文
  • win下安装nextcloud_在 Windows 平台下搭建docker - nextCloud 个人云盘

    一直感觉放在百度网盘里面的数据很不安全 因为之前因为存一些技术教程被封过号 再也没活过来 正巧赶上盘当劳事件 手里还有闲置硬件资源 终于下定决心自己搭建一个 NAS 来用了 先挂载到本地磁盘中 因为我们不想因为存储的数据随着容器的删除而消失
  • 机器学习之数据准备

    1 数据预处理的理由 在开始训练机器学习的模型之前 需要对数据进行预处理 这是一个必须的过程 不同算法对数据有不同的假设 需要按照不同的方式转换数据 这样做的目的是为了提高模型的准确度 2 数据转换的方法 调整数据尺度 正态化数据 二值数据
  • oracle libcpt ora,Oracle12c R2注意事项: Active DataGuard logon fail with ORA-00604& ORA-04024

    这是一套12c R2 4 nodes Oracle RAC on RHEL 7的环境 已安装0417 RU 该库有一套Phyical DataGard 同时也是GoldenGate的target端 存在一个replicat 进程同步数据 一
  • C++类模板

    类模板和函数模板语法相似 在声明模板template后面加类 此类称为类模板 类模板作用 建立一个通用类 类中的成员 数据类型可以不具体制定 用一个虚拟的类型来代表 语法 template
  • scanner hasnext方法的结束输入

    先看一段经典的程序 import java util Scanner public class aplusb public static void main String args Scanner in new Scanner System
  • ubuntu 18.04 中 编译 FasterTransformer,与缺少安装包

    前提 A100 cuda 11 6 cudnn8 nccl zlib1g dev git clone recursive https github com NVIDIA FasterTransformer git git submodule
  • 【转】svn详解

    转自 svn status详解 世界 太精彩 博客园 svn 是在提交前查看本地文本和版本库里面的文件的区别 返回值有许多种具体含义如下 L abc c svn已经在 svn目录锁定了abc c M bar c bar c的内容已经在本地修
  • python+pyqt5设置窗体图标和任务栏图标及窗体标题的方法

    本次设置窗体标题只用了一种方法 在进行窗体实例化后window Window 使用setWindowTitle str 命令 在主程序中的设置命令如下所示 if name main QApplication setAttribute Qt
  • lab4

    这一个lab主要学习进程管理和进程通讯 come on 好好学习 PART A 多处理器支持 Exercise 1 void mmio map region physaddr t pa size t size Where to start