码迷,mamicode.com
首页 > 其他好文 > 详细

MIT 操作系统实验 MIT JOS lab3

时间:2015-02-15 06:12:57      阅读:972      评论:0      收藏:0      [点我收藏+]

标签:

MIT JOS lab3



Allocating the Environments Array


                 In lab 2, you allocated memory in  mem_init()  for the  pages[]  array, which is a table the kernel uses to
keep track of which pages are free and which are not. You will now need to modify  mem_init()  further to
allocate a similar array of  Env  structures, called  envs .

技术分享

技术分享



Creating and Running Environments


               要知道JOS是没有文件系统的,那么如果在JOS上运行用户程序怎么办?——直接和内核镜像结合在一起,在编译时期就做好....希望以后自己完成JOS所有实验之后能够对其改进,照猫画虎的把Minix的文件系统添加进去


                补全env.c缺失的部分.


技术分享


inc/env.h里面又关于env.c要用到的结构体或者宏定义的相关信息

这里进程运行的状态还可以联想linux做对比,linux中进程状态又TASK_RUNNING,TASK_INTERRUPTIBLE,TASK_UNINTERRUPTIBLE,TASK_STOPPED等状态

技术分享



env_init部分 对envs指向的 struct Env数组做初始化操作,注意这里temp--,这种初始化的方向是故意的,

为了确保最后env_free_list指向最开始的结构体即envs[0]。

                   The JOS kernel keeps all of the inactive  Env  structures on the  env_free_list . This design allows easy
allocation and deallocation of environments, as they merely have to be added to or removed from the free list.

void
env_init(void)
{
	// Set up envs array
	// LAB 3: Your code here.

	int temp = 0;
	env_free_list = NULL;
	cprintf("NENV -1 : %u\n",NENV -1);
	for(temp = NENV -1;temp >= 0;temp--)
	{
		envs[temp].env_id = 0;
		envs[temp].env_parent_id = 0;
		envs[temp].env_type = ENV_TYPE_USER;
		envs[temp].env_status = 0;
		envs[temp].env_runs = 0;
		envs[temp].env_pgdir = NULL;
		envs[temp].env_link = env_free_list;
		env_free_list = &envs[temp];
	}

	cprintf("env_free_list : 0x%08x, &envs[temp]: 0x%08x\n",env_free_list,&envs[temp]);

	// Per-CPU part of the initialization
	env_init_percpu();
}


env_setup_vm部分为进程分配内存空间!单独的分配page directory—— p

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;

	// LAB 3: Your code here.

	(p->pp_ref)++;
	pde_t* page_dir = page2kva(p);
	memcpy(page_dir,kern_pgdir,PGSIZE);
	e->env_pgdir = page_dir;

	// 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;
}


region_alloc 为environment *e 开辟len byte大小的物理空间,并将va虚拟地址开始的len长度大小的空间和物理空间建立映射关系(其实干活儿的还是page_insert 哈哈~).

static void
region_alloc(struct Env *e, void *va, size_t len)
{
	// LAB 3: Your code here.
	// (But only if you need it for load_icode.)
	//
	// Hint: It is easier to use region_alloc if the caller can pass
	//   'va' and 'len' values that are not page-aligned.
	//   You should round va down, and round (va + len) up.
	//   (Watch out for corner-cases!)

	va  = ROUNDDOWN(va,PGSIZE);
	len = ROUNDUP(len,PGSIZE);

	struct PageInfo *pp;
	int ret = 0;

	for(;len > 0; len -= PGSIZE, va += PGSIZE)
	{
		pp = page_alloc(0);

		if(!pp)
		{
			panic("region_alloc failed!\n");
		}

		ret = page_insert(e->env_pgdir,pp,va,PTE_U | PTE_W);

		if(ret)
		{
			panic("region_alloc failed!\n");
		}
	}
}



static void
load_icode(struct Env *e, uint8_t *binary)
{
	// LAB 3: Your code here.

	struct Elf* elfhdr = (struct Elf*)binary;
	struct Proghdr* ph,*eph;
	if(elfhdr->e_magic != ELF_MAGIC)
	{
		panic("elf header's magic is not correct\n");			
	}

	ph = (struct Proghdr*)((uint8_t*)elfhdr + elfhdr->e_phoff);

	eph = ph + elfhdr->e_phnum;

	lcr3(PADDR(e->env_pgdir));

	for(;ph < eph; ph++)
	{
		if(ph->p_type != ELF_PROG_LOAD)
		{
			continue;
		}

		if(ph->p_filesz > ph->p_memsz)
		{
			panic("file size is great than memory size\n");
		}

		region_alloc(e,(void*)ph->p_va,ph->p_memsz);
		memmove((void*)ph->p_va,binary+ph->p_offset,ph->p_filesz);
		memset((void*)ph->p_va + ph->p_filesz,0,(ph->p_memsz - ph->p_filesz));
	}

	e->env_tf.tf_eip = elfhdr->e_entry;

	// Now map one page for the program's initial stack
	// at virtual address USTACKTOP - PGSIZE.

	// LAB 3: Your code here.

	lcr3(PADDR(kern_pgdir));

	region_alloc(e,(void*)USTACKTOP - PGSIZE,PGSIZE);
}



env_create 函数

void
env_create(uint8_t *binary, enum EnvType type)
{
	// LAB 3: Your code here.

	int ret = 0;
	struct Env *e  = NULL;
	ret = env_alloc(&e,0);
	if(ret < 0)
	{
		panic("env_create: %e\n",r);
	}

	load_icode(e,binary);
	e->env_type = type;
}




env_run 函数是正真进程切换的地方.

                   To run an environment, the kernel must set up the CPU with both the saved registers and the appropriate address space.

void
env_run(struct Env *e)
{
	// LAB 3: Your code here.
//	panic("env_run not yet implemented");

	if(curenv && curenv->env_status == ENV_RUNNING)
	{
		curenv->env_status = ENV_RUNNABLE;
	}

	curenv = e;
	e->env_status = ENV_RUNNING;
	e->env_runs++;

	lcr3(PADDR(e->env_pgdir));

	env_pop_tf(&(e->env_tf));
}


             If all goes well, your system should enter user space and execute the  hello  binary until it makes a system call with the  int instruction. At that point there will be trouble, since JOS has not set up the hardware to allow any kind of transition from user space into the kernel. When the CPU discovers that it is not set up to handle this
system call interrupt, it will generate a general protection exception, find that it can‘t handle that, generate a double fault exception, find that it can‘t handle that either, and finally give up with what‘s known as a "triple fault". Usually,you would then see the CPU reset and the system reboot.


技术分享


So .如果完成了以上部分,JOS启动时回不断的重启重启,这是正常现象....表慌,没错,接着做就是了.

如果没有出现这种现象引起的重启... 骚年, debug吧!... 你代码有问题.


技术分享


在lab3中, 在kern/Makefrag里面会看到-b 的链接选项

       The  -b binary  option on the linker command line causes these files to be linked in as "raw" uninterpreted binary files rather than as regular  .o  files produced by the compile


技术分享

技术分享

编译成功的时候,会发现在 ./lab/obj/kern/kernel.sym里面会有这样一段:

技术分享



我不会说我这这破问题这儿折腾了两天了, 问候一下神兽.

在0x800b56这个地方(sys_cputs)的入口地方

技术分享

技术分享


当触发这个中断的时候系统就会重启. 如果你不能执行到这一步,就说明之前的地址空间配置还没有做好....


好的, 下一关!




Basics of Protected Control Transfer


                Exceptions and interrupts are both "protected control transfers," which cause the processor to switch from user to kernel mode (CPL=0) without giving the user-mode code any opportunity to interfere with the functioning of the kernel or other environments. In Intel‘s terminology, an interrupt is a protected control transfer that is caused by an asynchronous event usually external to the processor, such as notification of external device I/O activity. An exception, in contrast, is a protected control transfer caused synchronously by the currently running code, for example due to a divide by zero or an invalid memory access.


如果不知道啥是CPL, 可以移步这里,看看 http://blog.csdn.net/cinmyheart/article/details/40075257



Handling Interrupts and Exceptions


             At this point, the first  int $0x30  system call instruction in user space is a dead end: once the processor gets into user mode, there is no way to get back out. 

前面那个 int 0x30中断挂掉, 进入了用户空间就回不来鸟...所以现在要想办法让他回来...

这时候我听到某个歌声  "你快回来.....我的..."


Types of Exceptions and Interrupts (这里讨论了异常和中断的区别)


         All of the synchronous exceptions that the x86 processor can generate internally use interrupt vectors between 0 and 31, and therefore map to IDT entries 0-31. For example, a page fault always causes an exception through vector 14. Interrupt vectors greater than 31 are only used by software interrupts, which can be generated by the  int  instruction, or asynchronous hardware interrupts, caused by external devices when they need attention.

同步的是异常, 异步的是中断. 异常的中断向量在0~31之间, 而中断的中断向量大于31.


技术分享

在kern/trap.c 里面的trapname()函数中我们可以对应的看到各种trap名字

技术分享


补全好函数,  代码有点小多, 不贴出来了, github传送门. 去看lab3的分支中对应文件就可以了.

https://github.com/jasonleaster


技术分享



后面还有坑... 先抛粗来了再填....





2015年2月 <<扁担和竹篮的生活>>

技术分享





MIT 操作系统实验 MIT JOS lab3

标签:

原文地址:http://blog.csdn.net/cinmyheart/article/details/40023965

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!