mirror of
https://github.com/SmallPond/MIT6.828_OS.git
synced 2026-04-05 03:28:55 +08:00
LAB 4 IS DONE.
This commit is contained in:
1
lab
1
lab
Submodule lab deleted from da14b2e50c
80
lab/LAB4.si4project/Backup/dumbfork(162).c
Normal file
80
lab/LAB4.si4project/Backup/dumbfork(162).c
Normal file
@@ -0,0 +1,80 @@
|
||||
// Ping-pong a counter between two processes.
|
||||
// Only need to start one of these -- splits into two, crudely.
|
||||
|
||||
#include <inc/string.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
envid_t dumbfork(void);
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
envid_t who;
|
||||
int i;
|
||||
|
||||
// fork a child process
|
||||
who = dumbfork();
|
||||
|
||||
// print a message and yield to the other a few times
|
||||
for (i = 0; i < (who ? 10 : 20); i++) {
|
||||
cprintf("%d: I am the %s!\n", i, who ? "parent" : "child");
|
||||
sys_yield();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
duppage(envid_t dstenv, void *addr)
|
||||
{
|
||||
int r;
|
||||
|
||||
// This is NOT what you should do in your fork.
|
||||
if ((r = sys_page_alloc(dstenv, addr, PTE_P|PTE_U|PTE_W)) < 0)
|
||||
panic("sys_page_alloc: %e", r);
|
||||
if ((r = sys_page_map(dstenv, addr, 0, UTEMP, PTE_P|PTE_U|PTE_W)) < 0)
|
||||
panic("sys_page_map: %e", r);
|
||||
memmove(UTEMP, addr, PGSIZE);
|
||||
if ((r = sys_page_unmap(0, UTEMP)) < 0)
|
||||
panic("sys_page_unmap: %e", r);
|
||||
}
|
||||
|
||||
envid_t
|
||||
dumbfork(void)
|
||||
{
|
||||
envid_t envid;
|
||||
uint8_t *addr;
|
||||
int r;
|
||||
extern unsigned char end[];
|
||||
|
||||
// Allocate a new child environment.
|
||||
// The kernel will initialize it with a copy of our register state,
|
||||
// so that the child will appear to have called sys_exofork() too -
|
||||
// except that in the child, this "fake" call to sys_exofork()
|
||||
// will return 0 instead of the envid of the child.
|
||||
envid = sys_exofork();
|
||||
if (envid < 0)
|
||||
panic("sys_exofork: %e", envid);
|
||||
if (envid == 0) {
|
||||
// We're the child.
|
||||
// The copied value of the global variable 'thisenv'
|
||||
// is no longer valid (it refers to the parent!).
|
||||
// Fix it and return 0.
|
||||
thisenv = &envs[ENVX(sys_getenvid())];
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We're the parent.
|
||||
// Eagerly copy our entire address space into the child.
|
||||
// This is NOT what you should do in your fork implementation.
|
||||
for (addr = (uint8_t*) UTEXT; addr < end; addr += PGSIZE)
|
||||
duppage(envid, addr);
|
||||
|
||||
// Also copy the stack we are currently running on.
|
||||
duppage(envid, ROUNDDOWN(&addr, PGSIZE));
|
||||
|
||||
// Start the child environment running
|
||||
if ((r = sys_env_set_status(envid, ENV_RUNNABLE)) < 0)
|
||||
panic("sys_env_set_status: %e", r);
|
||||
|
||||
return envid;
|
||||
}
|
||||
|
||||
80
lab/LAB4.si4project/Backup/dumbfork(7443).c
Normal file
80
lab/LAB4.si4project/Backup/dumbfork(7443).c
Normal file
@@ -0,0 +1,80 @@
|
||||
// Ping-pong a counter between two processes.
|
||||
// Only need to start one of these -- splits into two, crudely.
|
||||
|
||||
#include <inc/string.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
envid_t dumbfork(void);
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
envid_t who;
|
||||
int i;
|
||||
|
||||
// fork a child process
|
||||
who = dumbfork();
|
||||
|
||||
// print a message and yield to the other a few times
|
||||
for (i = 0; i < (who ? 10 : 20); i++) {
|
||||
cprintf("%d: I am the %s!\n", i, who ? "parent" : "child");
|
||||
sys_yield();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
duppage(envid_t dstenv, void *addr)
|
||||
{
|
||||
int r;
|
||||
|
||||
// This is NOT what you should do in your fork.
|
||||
if ((r = sys_page_alloc(dstenv, addr, PTE_P|PTE_U|PTE_W)) < 0)
|
||||
panic("sys_page_alloc: %e", r);
|
||||
if ((r = sys_page_map(dstenv, addr, 0, UTEMP, PTE_P|PTE_U|PTE_W)) < 0)
|
||||
panic("sys_page_map: %e", r);
|
||||
memmove(UTEMP, addr, PGSIZE);
|
||||
if ((r = sys_page_unmap(0, UTEMP)) < 0)
|
||||
panic("sys_page_unmap: %e", r);
|
||||
}
|
||||
|
||||
envid_t
|
||||
dumbfork(void)
|
||||
{
|
||||
envid_t envid;
|
||||
uint8_t *addr;
|
||||
int r;
|
||||
extern unsigned char end[];
|
||||
|
||||
// Allocate a new child environment.
|
||||
// The kernel will initialize it with a copy of our register state,
|
||||
// so that the child will appear to have called sys_exofork() too -
|
||||
// except that in the child, this "fake" call to sys_exofork()
|
||||
// will return 0 instead of the envid of the child.
|
||||
envid = sys_exofork();
|
||||
if (envid < 0)
|
||||
panic("sys_exofork: %e", envid);
|
||||
if (envid == 0) {
|
||||
// We're the child.
|
||||
// The copied value of the global variable 'thisenv'
|
||||
// is no longer valid (it refers to the parent!).
|
||||
// Fix it and return 0.
|
||||
thisenv = &envs[ENVX(sys_getenvid())];
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We're the parent.
|
||||
// Eagerly copy our entire address space into the child.
|
||||
// This is NOT what you should do in your fork implementation.
|
||||
for (addr = (uint8_t*) UTEXT; addr < end; addr += PGSIZE)
|
||||
duppage(envid, addr);
|
||||
|
||||
// Also copy the stack we are currently running on.
|
||||
duppage(envid, ROUNDDOWN(&addr, PGSIZE));
|
||||
|
||||
// Start the child environment running
|
||||
if ((r = sys_env_set_status(envid, ENV_RUNNABLE)) < 0)
|
||||
panic("sys_env_set_status: %e", r);
|
||||
|
||||
return envid;
|
||||
}
|
||||
|
||||
89
lab/LAB4.si4project/Backup/dumbfork(8040).c
Normal file
89
lab/LAB4.si4project/Backup/dumbfork(8040).c
Normal file
@@ -0,0 +1,89 @@
|
||||
// Ping-pong a counter between two processes.
|
||||
// Only need to start one of these -- splits into two, crudely.
|
||||
|
||||
#include <inc/string.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
envid_t dumbfork(void);
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
envid_t who;
|
||||
int i;
|
||||
|
||||
// fork a child process
|
||||
who = dumbfork();
|
||||
|
||||
// print a message and yield to the other a few times
|
||||
for (i = 0; i < (who ? 10 : 20); i++) {
|
||||
cprintf("%d: I am the %s!\n", i, who ? "parent" : "child");
|
||||
sys_yield();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
duppage(envid_t dstenv, void *addr)
|
||||
{
|
||||
int r;
|
||||
|
||||
// This is NOT what you should do in your fork.
|
||||
if ((r = sys_page_alloc(dstenv, addr, PTE_P|PTE_U|PTE_W)) < 0)
|
||||
panic("sys_page_alloc: %e", r);
|
||||
// dstenv 的 addr 映射到 envs[0]的UTEMP,
|
||||
if ((r = sys_page_map(dstenv, addr, 0, UTEMP, PTE_P|PTE_U|PTE_W)) < 0)
|
||||
panic("sys_page_map: %e", r);
|
||||
|
||||
memmove(UTEMP, addr, PGSIZE);
|
||||
if ((r = sys_page_unmap(0, UTEMP)) < 0)
|
||||
panic("sys_page_unmap: %e", r);
|
||||
}
|
||||
|
||||
envid_t
|
||||
dumbfork(void)
|
||||
{
|
||||
envid_t envid;
|
||||
uint8_t *addr;
|
||||
int r;
|
||||
extern unsigned char end[];
|
||||
|
||||
// Allocate a new child environment.
|
||||
// The kernel will initialize it with a copy of our register state,
|
||||
// so that the child will appear to have called sys_exofork() too -
|
||||
// except that in the child, this "fake" call to sys_exofork()
|
||||
// will return 0 instead of the envid of the child.
|
||||
envid = sys_exofork();
|
||||
cprintf("envid: %d\n",envid);
|
||||
if (envid < 0)
|
||||
panic("sys_exofork: %e", envid);
|
||||
if (envid == 0) {
|
||||
// We're the child.
|
||||
// The copied value of the global variable 'thisenv'
|
||||
// is no longer valid (it refers to the parent!).
|
||||
// Fix it and return 0.
|
||||
// "child, sysgetenvid() : 1
|
||||
// cprintf("child, sysgetenvid() :%d\n", ENVX(sys_getenvid()));
|
||||
thisenv = &envs[ENVX(sys_getenvid())];
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We're the parent.
|
||||
// Eagerly copy our entire address space into the child.
|
||||
// This is NOT what you should do in your fork implementation.
|
||||
for (addr = (uint8_t*) UTEXT; addr < end; addr += PGSIZE) {
|
||||
// copying addr :00800000
|
||||
// copying addr :00801000
|
||||
// copying addr :00802000
|
||||
cprintf("copying addr :%08x\n", (uint32_t)addr);
|
||||
duppage(envid, addr);
|
||||
}
|
||||
// Also copy the stack we are currently running on.
|
||||
duppage(envid, ROUNDDOWN(&addr, PGSIZE));
|
||||
|
||||
// Start the child environment running
|
||||
if ((r = sys_env_set_status(envid, ENV_RUNNABLE)) < 0)
|
||||
panic("sys_env_set_status: %e", r);
|
||||
|
||||
return envid;
|
||||
}
|
||||
|
||||
35
lab/LAB4.si4project/Backup/entry(6508).S
Normal file
35
lab/LAB4.si4project/Backup/entry(6508).S
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/memlayout.h>
|
||||
|
||||
.data
|
||||
// Define the global symbols 'envs', 'pages', 'uvpt', and 'uvpd'
|
||||
// so that they can be used in C as if they were ordinary global arrays.
|
||||
.globl envs
|
||||
.set envs, UENVS
|
||||
.globl pages
|
||||
.set pages, UPAGES
|
||||
.globl uvpt
|
||||
.set uvpt, UVPT
|
||||
.globl uvpd
|
||||
.set uvpd, (UVPT+(UVPT>>12)*4)
|
||||
|
||||
|
||||
// Entrypoint - this is where the kernel (or our parent environment)
|
||||
// starts us running when we are initially loaded into a new environment.
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
// See if we were started with arguments on the stack
|
||||
cmpl $USTACKTOP, %esp
|
||||
jne args_exist
|
||||
|
||||
// If not, push dummy argc/argv arguments.
|
||||
// This happens when we are loaded by the kernel,
|
||||
// because the kernel does not know about passing arguments.
|
||||
pushl $0
|
||||
pushl $0
|
||||
|
||||
args_exist:
|
||||
call libmain
|
||||
1: jmp 1b
|
||||
|
||||
569
lab/LAB4.si4project/Backup/env(1818).c
Normal file
569
lab/LAB4.si4project/Backup/env(1818).c
Normal file
@@ -0,0 +1,569 @@
|
||||
/* See COPYRIGHT for copyright information. */
|
||||
|
||||
#include <inc/x86.h>
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/error.h>
|
||||
#include <inc/string.h>
|
||||
#include <inc/assert.h>
|
||||
#include <inc/elf.h>
|
||||
|
||||
#include <kern/env.h>
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/trap.h>
|
||||
#include <kern/monitor.h>
|
||||
#include <kern/sched.h>
|
||||
#include <kern/cpu.h>
|
||||
#include <kern/spinlock.h>
|
||||
|
||||
struct Env *envs = NULL; // All environments
|
||||
static struct Env *env_free_list; // Free environment list
|
||||
// (linked by Env->env_link)
|
||||
|
||||
#define ENVGENSHIFT 12 // >= LOGNENV
|
||||
|
||||
// Global descriptor table.
|
||||
//
|
||||
// Set up global descriptor table (GDT) with separate segments for
|
||||
// kernel mode and user mode. Segments serve many purposes on the x86.
|
||||
// We don't use any of their memory-mapping capabilities, but we need
|
||||
// them to switch privilege levels.
|
||||
//
|
||||
// The kernel and user segments are identical except for the DPL.
|
||||
// To load the SS register, the CPL must equal the DPL. Thus,
|
||||
// we must duplicate the segments for the user and the kernel.
|
||||
//
|
||||
// In particular, the last argument to the SEG macro used in the
|
||||
// definition of gdt specifies the Descriptor Privilege Level (DPL)
|
||||
// of that descriptor: 0 for kernel and 3 for user.
|
||||
//
|
||||
struct Segdesc gdt[NCPU + 5] =
|
||||
{
|
||||
// 0x0 - unused (always faults -- for trapping NULL far pointers)
|
||||
SEG_NULL,
|
||||
|
||||
// 0x8 - kernel code segment
|
||||
[GD_KT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 0),
|
||||
|
||||
// 0x10 - kernel data segment
|
||||
[GD_KD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 0),
|
||||
|
||||
// 0x18 - user code segment
|
||||
[GD_UT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 3),
|
||||
|
||||
// 0x20 - user data segment
|
||||
[GD_UD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 3),
|
||||
|
||||
// Per-CPU TSS descriptors (starting from GD_TSS0) are initialized
|
||||
// in trap_init_percpu()
|
||||
[GD_TSS0 >> 3] = SEG_NULL
|
||||
};
|
||||
|
||||
struct Pseudodesc gdt_pd = {
|
||||
sizeof(gdt) - 1, (unsigned long) gdt
|
||||
};
|
||||
|
||||
//
|
||||
// Converts an envid to an env pointer.
|
||||
// If checkperm is set, the specified environment must be either the
|
||||
// current environment or an immediate child of the current environment.
|
||||
//
|
||||
// RETURNS
|
||||
// 0 on success, -E_BAD_ENV on error.
|
||||
// On success, sets *env_store to the environment.
|
||||
// On error, sets *env_store to NULL.
|
||||
//
|
||||
int
|
||||
envid2env(envid_t envid, struct Env **env_store, bool checkperm)
|
||||
{
|
||||
struct Env *e;
|
||||
|
||||
// If envid is zero, return the current environment.
|
||||
if (envid == 0) {
|
||||
*env_store = curenv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Look up the Env structure via the index part of the envid,
|
||||
// then check the env_id field in that struct Env
|
||||
// to ensure that the envid is not stale
|
||||
// (i.e., does not refer to a _previous_ environment
|
||||
// that used the same slot in the envs[] array).
|
||||
e = &envs[ENVX(envid)];
|
||||
if (e->env_status == ENV_FREE || e->env_id != envid) {
|
||||
*env_store = 0;
|
||||
return -E_BAD_ENV;
|
||||
}
|
||||
|
||||
// Check that the calling environment has legitimate permission
|
||||
// to manipulate the specified environment.
|
||||
// If checkperm is set, the specified environment
|
||||
// must be either the current environment
|
||||
// or an immediate child of the current environment.
|
||||
if (checkperm && e != curenv && e->env_parent_id != curenv->env_id) {
|
||||
*env_store = 0;
|
||||
return -E_BAD_ENV;
|
||||
}
|
||||
|
||||
*env_store = e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Mark all environments in 'envs' as free, set their env_ids to 0,
|
||||
// and insert them into the env_free_list.
|
||||
// Make sure the environments are in the free list in the same order
|
||||
// they are in the envs array (i.e., so that the first call to
|
||||
// env_alloc() returns envs[0]).
|
||||
//
|
||||
void
|
||||
env_init(void)
|
||||
{
|
||||
// Set up envs array
|
||||
// LAB 3: Your code here.
|
||||
int i;
|
||||
// 确保最小的env在最前端
|
||||
for (i = NENV-1; i >= 0; --i) {
|
||||
envs[i].env_id = 0;
|
||||
|
||||
envs[i].env_link = env_free_list;
|
||||
env_free_list = &envs[i];
|
||||
}
|
||||
|
||||
// Per-CPU part of the initialization
|
||||
env_init_percpu();
|
||||
}
|
||||
|
||||
// Load GDT and segment descriptors.
|
||||
void
|
||||
env_init_percpu(void)
|
||||
{
|
||||
lgdt(&gdt_pd);
|
||||
// The kernel never uses GS or FS, so we leave those set to
|
||||
// the user data segment.
|
||||
asm volatile("movw %%ax,%%gs" : : "a" (GD_UD|3));
|
||||
asm volatile("movw %%ax,%%fs" : : "a" (GD_UD|3));
|
||||
// The kernel does use ES, DS, and SS. We'll change between
|
||||
// the kernel and user data segments as needed.
|
||||
asm volatile("movw %%ax,%%es" : : "a" (GD_KD));
|
||||
asm volatile("movw %%ax,%%ds" : : "a" (GD_KD));
|
||||
asm volatile("movw %%ax,%%ss" : : "a" (GD_KD));
|
||||
// Load the kernel text segment into CS.
|
||||
asm volatile("ljmp %0,$1f\n 1:\n" : : "i" (GD_KT));
|
||||
// For good measure, clear the local descriptor table (LDT),
|
||||
// since we don't use it.
|
||||
lldt(0);
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the kernel virtual memory layout for environment e.
|
||||
// Allocate a page directory, set e->env_pgdir accordingly,
|
||||
// and initialize the kernel portion of the new environment's address space.
|
||||
// Do NOT (yet) map anything into the user portion
|
||||
// of the environment's virtual address space.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors include:
|
||||
// -E_NO_MEM if page directory or table could not be allocated.
|
||||
// 这里又为每个环境分配一个页目录,有点晕了。
|
||||
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 = page2kva(p);
|
||||
// why ?因为在UTOP之上都是一样的,所以可以直接把kern_pgdir的内容全部拷贝过来
|
||||
|
||||
memcpy(e->env_pgdir, kern_pgdir, PGSIZE);
|
||||
p->pp_ref++;
|
||||
// UVPT maps the env's own page table read-only.
|
||||
// Permissions: kernel R, user R
|
||||
// 但是唯独UVPT这个地方是不一样的,因为要放的是自己的页表目录
|
||||
e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_P | PTE_U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocates and initializes a new environment.
|
||||
// On success, the new environment is stored in *newenv_store.
|
||||
//
|
||||
// Returns 0 on success, < 0 on failure. Errors include:
|
||||
// -E_NO_FREE_ENV if all NENV environments are allocated
|
||||
// -E_NO_MEM on memory exhaustion
|
||||
//
|
||||
int
|
||||
env_alloc(struct Env **newenv_store, envid_t parent_id)
|
||||
{
|
||||
int32_t generation;
|
||||
int r;
|
||||
struct Env *e;
|
||||
|
||||
if (!(e = env_free_list))
|
||||
return -E_NO_FREE_ENV;
|
||||
|
||||
// Allocate and set up the page directory for this environment.
|
||||
if ((r = env_setup_vm(e)) < 0)
|
||||
return r;
|
||||
|
||||
// Generate an env_id for this environment.
|
||||
generation = (e->env_id + (1 << ENVGENSHIFT)) & ~(NENV - 1);
|
||||
if (generation <= 0) // Don't create a negative env_id.
|
||||
generation = 1 << ENVGENSHIFT;
|
||||
e->env_id = generation | (e - envs);
|
||||
|
||||
// Set the basic status variables.
|
||||
e->env_parent_id = parent_id;
|
||||
e->env_type = ENV_TYPE_USER;
|
||||
e->env_status = ENV_RUNNABLE;
|
||||
e->env_runs = 0;
|
||||
|
||||
// Clear out all the saved register state,
|
||||
// to prevent the register values
|
||||
// of a prior environment inhabiting this Env structure
|
||||
// from "leaking" into our new environment.
|
||||
memset(&e->env_tf, 0, sizeof(e->env_tf));
|
||||
|
||||
// Set up appropriate initial values for the segment registers.
|
||||
// GD_UD is the user data segment selector in the GDT, and
|
||||
// GD_UT is the user text segment selector (see inc/memlayout.h).
|
||||
// The low 2 bits of each segment register contains the
|
||||
// Requestor Privilege Level (RPL); 3 means user mode. When
|
||||
// we switch privilege levels, the hardware does various
|
||||
// checks involving the RPL and the Descriptor Privilege Level
|
||||
// (DPL) stored in the descriptors themselves.
|
||||
e->env_tf.tf_ds = GD_UD | 3;
|
||||
e->env_tf.tf_es = GD_UD | 3;
|
||||
e->env_tf.tf_ss = GD_UD | 3;
|
||||
e->env_tf.tf_esp = USTACKTOP;
|
||||
e->env_tf.tf_cs = GD_UT | 3;
|
||||
// You will set e->env_tf.tf_eip later.
|
||||
|
||||
// Enable interrupts while in user mode.
|
||||
// LAB 4: Your code here.
|
||||
|
||||
// Clear the page fault handler until user installs one.
|
||||
e->env_pgfault_upcall = 0;
|
||||
|
||||
// Also clear the IPC receiving flag.
|
||||
e->env_ipc_recving = 0;
|
||||
|
||||
// commit the allocation
|
||||
env_free_list = e->env_link;
|
||||
*newenv_store = e;
|
||||
|
||||
cprintf("[%08x] new env %08x\n", curenv ? curenv->env_id : 0, e->env_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate len bytes of physical memory for environment env,
|
||||
// and map it at virtual address va in the environment's address space.
|
||||
// Does not zero or otherwise initialize the mapped pages in any way.
|
||||
// Pages should be writable by user and kernel.
|
||||
// Panic if any allocation attempt fails.
|
||||
//
|
||||
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.)
|
||||
//
|
||||
struct PageInfo *pp;
|
||||
size_t i;
|
||||
size_t pgs = ROUNDUP(len, PGSIZE)/PGSIZE;
|
||||
size_t pva = ROUNDDOWN((size_t)va, PGSIZE);
|
||||
|
||||
|
||||
for(i=0; i < pgs; i++) {
|
||||
if (!(pp = page_alloc(ALLOC_ZERO))) {
|
||||
int ex = -E_NO_MEM;
|
||||
panic("region_alloc: %e", ex);
|
||||
}
|
||||
page_insert(e->env_pgdir, pp, (void *)pva, PTE_U|PTE_W|PTE_P);
|
||||
pva += PGSIZE;
|
||||
|
||||
}
|
||||
// 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!)
|
||||
}
|
||||
|
||||
//
|
||||
// Set up the initial program binary, stack, and processor flags
|
||||
// for a user process.
|
||||
// This function is ONLY called during kernel initialization,
|
||||
// before running the first user-mode environment.
|
||||
//
|
||||
// This function loads all loadable segments from the ELF binary image
|
||||
// into the environment's user memory, starting at the appropriate
|
||||
// virtual addresses indicated in the ELF program header.
|
||||
// At the same time it clears to zero any portions of these segments
|
||||
// that are marked in the program header as being mapped
|
||||
// but not actually present in the ELF file - i.e., the program's bss section.
|
||||
//
|
||||
// All this is very similar to what our boot loader does, except the boot
|
||||
// loader also needs to read the code from disk. Take a look at
|
||||
// boot/main.c to get ideas.
|
||||
//
|
||||
// Finally, this function maps one page for the program's initial stack.
|
||||
//
|
||||
// load_icode panics if it encounters problems.
|
||||
// - How might load_icode fail? What might be wrong with the given input?
|
||||
//
|
||||
static void
|
||||
load_icode(struct Env *e, uint8_t *binary)
|
||||
{
|
||||
// Hints:
|
||||
// Load each program segment into virtual memory
|
||||
// at the address specified in the ELF segment header.
|
||||
// You should only load segments with ph->p_type == ELF_PROG_LOAD.
|
||||
// Each segment's virtual address can be found in ph->p_va
|
||||
// and its size in memory can be found in ph->p_memsz.
|
||||
// The ph->p_filesz bytes from the ELF binary, starting at
|
||||
// 'binary + ph->p_offset', should be copied to virtual address
|
||||
// ph->p_va. Any remaining memory bytes should be cleared to zero.
|
||||
// (The ELF header should have ph->p_filesz <= ph->p_memsz.)
|
||||
// Use functions from the previous lab to allocate and map pages.
|
||||
//
|
||||
// All page protection bits should be user read/write for now.
|
||||
// ELF segments are not necessarily page-aligned, but you can
|
||||
// assume for this function that no two segments will touch
|
||||
// the same virtual page.
|
||||
//
|
||||
// You may find a function like region_alloc useful.
|
||||
//
|
||||
// Loading the segments is much simpler if you can move data
|
||||
// directly into the virtual addresses stored in the ELF binary.
|
||||
// So which page directory should be in force during
|
||||
// this function?
|
||||
//
|
||||
// You must also do something with the program's entry point,
|
||||
// to make sure that the environment starts executing there.
|
||||
// What? (See env_run() and env_pop_tf() below.)
|
||||
|
||||
// LAB 3: Your code here.
|
||||
// 怎么得到program的ELF地址? 就是bianry
|
||||
struct Proghdr *ph, *eph;
|
||||
struct Elf *elfhdr = (struct Elf *)binary;
|
||||
|
||||
// is this a valid ELF?
|
||||
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 memmory size\n");
|
||||
|
||||
region_alloc(e, (void *)ph->p_va, ph->p_memsz);
|
||||
memcpy((void *)ph->p_va, binary + ph->p_offset, ph->p_filesz);
|
||||
// clear bss section
|
||||
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.
|
||||
|
||||
// map the user stack
|
||||
region_alloc(e, (void *)USTACKTOP-PGSIZE, PGSIZE);
|
||||
lcr3(PADDR(kern_pgdir));
|
||||
}
|
||||
|
||||
//
|
||||
// Allocates a new env with env_alloc, loads the named elf
|
||||
// binary into it with load_icode, and sets its env_type.
|
||||
// This function is ONLY called during kernel initialization,
|
||||
// before running the first user-mode environment.
|
||||
// The new env's parent ID is set to 0.
|
||||
//
|
||||
void
|
||||
env_create(uint8_t *binary, enum EnvType type)
|
||||
{
|
||||
// LAB 3: Your code here.
|
||||
struct Env *newenv;
|
||||
int ret = 0;
|
||||
if ((ret = env_alloc(&newenv, 0)) < 0) {
|
||||
panic("env_create: %e\n", ret);
|
||||
}
|
||||
newenv->env_type = type;
|
||||
load_icode(newenv, binary);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Frees env e and all memory it uses.
|
||||
//
|
||||
void
|
||||
env_free(struct Env *e)
|
||||
{
|
||||
pte_t *pt;
|
||||
uint32_t pdeno, pteno;
|
||||
physaddr_t pa;
|
||||
|
||||
// If freeing the current environment, switch to kern_pgdir
|
||||
// before freeing the page directory, just in case the page
|
||||
// gets reused.
|
||||
if (e == curenv)
|
||||
lcr3(PADDR(kern_pgdir));
|
||||
|
||||
// Note the environment's demise.
|
||||
cprintf("[%08x] free env %08x\n", curenv ? curenv->env_id : 0, e->env_id);
|
||||
|
||||
// Flush all mapped pages in the user portion of the address space
|
||||
static_assert(UTOP % PTSIZE == 0);
|
||||
for (pdeno = 0; pdeno < PDX(UTOP); pdeno++) {
|
||||
|
||||
// only look at mapped page tables
|
||||
if (!(e->env_pgdir[pdeno] & PTE_P))
|
||||
continue;
|
||||
|
||||
// find the pa and va of the page table
|
||||
pa = PTE_ADDR(e->env_pgdir[pdeno]);
|
||||
pt = (pte_t*) KADDR(pa);
|
||||
|
||||
// unmap all PTEs in this page table
|
||||
for (pteno = 0; pteno <= PTX(~0); pteno++) {
|
||||
if (pt[pteno] & PTE_P)
|
||||
page_remove(e->env_pgdir, PGADDR(pdeno, pteno, 0));
|
||||
}
|
||||
|
||||
// free the page table itself
|
||||
e->env_pgdir[pdeno] = 0;
|
||||
page_decref(pa2page(pa));
|
||||
}
|
||||
|
||||
// free the page directory
|
||||
pa = PADDR(e->env_pgdir);
|
||||
e->env_pgdir = 0;
|
||||
page_decref(pa2page(pa));
|
||||
|
||||
// return the environment to the free list
|
||||
e->env_status = ENV_FREE;
|
||||
e->env_link = env_free_list;
|
||||
env_free_list = e;
|
||||
}
|
||||
|
||||
//
|
||||
// Frees environment e.
|
||||
// If e was the current env, then runs a new environment (and does not return
|
||||
// to the caller).
|
||||
//
|
||||
void
|
||||
env_destroy(struct Env *e)
|
||||
{
|
||||
// If e is currently running on other CPUs, we change its state to
|
||||
// ENV_DYING. A zombie environment will be freed the next time
|
||||
// it traps to the kernel.
|
||||
if (e->env_status == ENV_RUNNING && curenv != e) {
|
||||
e->env_status = ENV_DYING;
|
||||
return;
|
||||
}
|
||||
|
||||
env_free(e);
|
||||
|
||||
if (curenv == e) {
|
||||
curenv = NULL;
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Restores the register values in the Trapframe with the 'iret' instruction.
|
||||
// This exits the kernel and starts executing some environment's code.
|
||||
//
|
||||
// This function does not return.
|
||||
//
|
||||
void
|
||||
env_pop_tf(struct Trapframe *tf)
|
||||
{
|
||||
// Record the CPU we are running on for user-space debugging
|
||||
curenv->env_cpunum = cpunum();
|
||||
|
||||
asm volatile(
|
||||
"\tmovl %0,%%esp\n"
|
||||
"\tpopal\n"
|
||||
"\tpopl %%es\n"
|
||||
"\tpopl %%ds\n"
|
||||
"\taddl $0x8,%%esp\n" /* skip tf_trapno and tf_errcode */
|
||||
"\tiret\n"
|
||||
: : "g" (tf) : "memory");
|
||||
panic("iret failed"); /* mostly to placate the compiler */
|
||||
}
|
||||
|
||||
//
|
||||
// Context switch from curenv to env e.
|
||||
// Note: if this is the first call to env_run, curenv is NULL.
|
||||
//
|
||||
// This function does not return.
|
||||
//
|
||||
void
|
||||
env_run(struct Env *e)
|
||||
{
|
||||
// Step 1: If this is a context switch (a new environment is running):
|
||||
// 1. Set the current environment (if any) back to
|
||||
// ENV_RUNNABLE if it is ENV_RUNNING (think about
|
||||
// what other states it can be in),
|
||||
// 2. Set 'curenv' to the new environment,
|
||||
// 3. Set its status to ENV_RUNNING,
|
||||
// 4. Update its 'env_runs' counter,
|
||||
// 5. Use lcr3() to switch to its address space.
|
||||
// Step 2: Use env_pop_tf() to restore the environment's
|
||||
// registers and drop into user mode in the
|
||||
// environment.
|
||||
|
||||
// Hint: This function loads the new environment's state from
|
||||
// e->env_tf. Go back through the code you wrote above
|
||||
// and make sure you have set the relevant parts of
|
||||
// e->env_tf to sensible values.
|
||||
|
||||
// LAB 3: Your code here.
|
||||
if (curenv && curenv->env_status == ENV_RUNNING) {
|
||||
curenv->env_status = ENV_RUNNABLE;
|
||||
}
|
||||
curenv = e;
|
||||
curenv->env_status = ENV_RUNNING;
|
||||
curenv->env_runs++;
|
||||
lcr3(PADDR(curenv->env_pgdir));
|
||||
// 将当前进程的trapframe通过弹栈的形式,切换当前的运行环境
|
||||
env_pop_tf(&(curenv->env_tf));
|
||||
|
||||
unlock_kernel();
|
||||
// panic("env_run not yet implemented");
|
||||
}
|
||||
|
||||
70
lab/LAB4.si4project/Backup/env(4388).h
Normal file
70
lab/LAB4.si4project/Backup/env(4388).h
Normal file
@@ -0,0 +1,70 @@
|
||||
/* See COPYRIGHT for copyright information. */
|
||||
|
||||
#ifndef JOS_INC_ENV_H
|
||||
#define JOS_INC_ENV_H
|
||||
|
||||
#include <inc/types.h>
|
||||
#include <inc/trap.h>
|
||||
#include <inc/memlayout.h>
|
||||
|
||||
typedef int32_t envid_t;
|
||||
|
||||
// An environment ID 'envid_t' has three parts:
|
||||
//
|
||||
// +1+---------------21-----------------+--------10--------+
|
||||
// |0| Uniqueifier | Environment |
|
||||
// | | | Index |
|
||||
// +------------------------------------+------------------+
|
||||
// \--- ENVX(eid) --/
|
||||
//
|
||||
// The environment index ENVX(eid) equals the environment's index in the
|
||||
// 'envs[]' array. The uniqueifier distinguishes environments that were
|
||||
// created at different times, but share the same environment index.
|
||||
//
|
||||
// All real environments are greater than 0 (so the sign bit is zero).
|
||||
// envid_ts less than 0 signify errors. The envid_t == 0 is special, and
|
||||
// stands for the current environment.
|
||||
|
||||
#define LOG2NENV 10
|
||||
#define NENV (1 << LOG2NENV)
|
||||
#define ENVX(envid) ((envid) & (NENV - 1))
|
||||
|
||||
// Values of env_status in struct Env
|
||||
enum {
|
||||
ENV_FREE = 0,
|
||||
ENV_DYING,
|
||||
ENV_RUNNABLE,
|
||||
ENV_RUNNING,
|
||||
ENV_NOT_RUNNABLE
|
||||
};
|
||||
|
||||
// Special environment types
|
||||
enum EnvType {
|
||||
ENV_TYPE_USER = 0,
|
||||
};
|
||||
|
||||
struct Env {
|
||||
struct Trapframe env_tf; // Saved registers
|
||||
struct Env *env_link; // Next free Env
|
||||
envid_t env_id; // Unique environment identifier
|
||||
envid_t env_parent_id; // env_id of this env's parent
|
||||
enum EnvType env_type; // Indicates special system environments
|
||||
unsigned env_status; // Status of the environment
|
||||
uint32_t env_runs; // Number of times environment has run
|
||||
int env_cpunum; // The CPU that the env is running on
|
||||
|
||||
// Address space
|
||||
pde_t *env_pgdir; // Kernel virtual address of page dir
|
||||
|
||||
// Exception handling
|
||||
void *env_pgfault_upcall; // Page fault upcall entry point
|
||||
|
||||
// Lab 4 IPC
|
||||
bool env_ipc_recving; // Env is blocked receiving
|
||||
void *env_ipc_dstva; // VA at which to map received page
|
||||
uint32_t env_ipc_value; // Data value sent to us
|
||||
envid_t env_ipc_from; // envid of the sender
|
||||
int env_ipc_perm; // Perm of page mapping received
|
||||
};
|
||||
|
||||
#endif // !JOS_INC_ENV_H
|
||||
572
lab/LAB4.si4project/Backup/env(572).c
Normal file
572
lab/LAB4.si4project/Backup/env(572).c
Normal file
@@ -0,0 +1,572 @@
|
||||
/* See COPYRIGHT for copyright information. */
|
||||
|
||||
#include <inc/x86.h>
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/error.h>
|
||||
#include <inc/string.h>
|
||||
#include <inc/assert.h>
|
||||
#include <inc/elf.h>
|
||||
|
||||
#include <kern/env.h>
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/trap.h>
|
||||
#include <kern/monitor.h>
|
||||
#include <kern/sched.h>
|
||||
#include <kern/cpu.h>
|
||||
#include <kern/spinlock.h>
|
||||
|
||||
struct Env *envs = NULL; // All environments
|
||||
static struct Env *env_free_list; // Free environment list
|
||||
// (linked by Env->env_link)
|
||||
|
||||
#define ENVGENSHIFT 12 // >= LOGNENV
|
||||
|
||||
// Global descriptor table.
|
||||
//
|
||||
// Set up global descriptor table (GDT) with separate segments for
|
||||
// kernel mode and user mode. Segments serve many purposes on the x86.
|
||||
// We don't use any of their memory-mapping capabilities, but we need
|
||||
// them to switch privilege levels.
|
||||
//
|
||||
// The kernel and user segments are identical except for the DPL.
|
||||
// To load the SS register, the CPL must equal the DPL. Thus,
|
||||
// we must duplicate the segments for the user and the kernel.
|
||||
//
|
||||
// In particular, the last argument to the SEG macro used in the
|
||||
// definition of gdt specifies the Descriptor Privilege Level (DPL)
|
||||
// of that descriptor: 0 for kernel and 3 for user.
|
||||
//
|
||||
struct Segdesc gdt[NCPU + 5] =
|
||||
{
|
||||
// 0x0 - unused (always faults -- for trapping NULL far pointers)
|
||||
SEG_NULL,
|
||||
|
||||
// 0x8 - kernel code segment
|
||||
[GD_KT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 0),
|
||||
|
||||
// 0x10 - kernel data segment
|
||||
[GD_KD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 0),
|
||||
|
||||
// 0x18 - user code segment
|
||||
[GD_UT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 3),
|
||||
|
||||
// 0x20 - user data segment
|
||||
[GD_UD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 3),
|
||||
|
||||
// Per-CPU TSS descriptors (starting from GD_TSS0) are initialized
|
||||
// in trap_init_percpu()
|
||||
[GD_TSS0 >> 3] = SEG_NULL
|
||||
};
|
||||
|
||||
struct Pseudodesc gdt_pd = {
|
||||
sizeof(gdt) - 1, (unsigned long) gdt
|
||||
};
|
||||
|
||||
//
|
||||
// Converts an envid to an env pointer.
|
||||
// If checkperm is set, the specified environment must be either the
|
||||
// current environment or an immediate child of the current environment.
|
||||
//
|
||||
// RETURNS
|
||||
// 0 on success, -E_BAD_ENV on error.
|
||||
// On success, sets *env_store to the environment.
|
||||
// On error, sets *env_store to NULL.
|
||||
//
|
||||
int
|
||||
envid2env(envid_t envid, struct Env **env_store, bool checkperm)
|
||||
{
|
||||
struct Env *e;
|
||||
|
||||
// If envid is zero, return the current environment.
|
||||
if (envid == 0) {
|
||||
*env_store = curenv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Look up the Env structure via the index part of the envid,
|
||||
// then check the env_id field in that struct Env
|
||||
// to ensure that the envid is not stale
|
||||
// (i.e., does not refer to a _previous_ environment
|
||||
// that used the same slot in the envs[] array).
|
||||
e = &envs[ENVX(envid)];
|
||||
if (e->env_status == ENV_FREE || e->env_id != envid) {
|
||||
*env_store = 0;
|
||||
return -E_BAD_ENV;
|
||||
}
|
||||
|
||||
// Check that the calling environment has legitimate permission
|
||||
// to manipulate the specified environment.
|
||||
// If checkperm is set, the specified environment
|
||||
// must be either the current environment
|
||||
// or an immediate child of the current environment.
|
||||
if (checkperm && e != curenv && e->env_parent_id != curenv->env_id) {
|
||||
*env_store = 0;
|
||||
return -E_BAD_ENV;
|
||||
}
|
||||
|
||||
*env_store = e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Mark all environments in 'envs' as free, set their env_ids to 0,
|
||||
// and insert them into the env_free_list.
|
||||
// Make sure the environments are in the free list in the same order
|
||||
// they are in the envs array (i.e., so that the first call to
|
||||
// env_alloc() returns envs[0]).
|
||||
//
|
||||
void
|
||||
env_init(void)
|
||||
{
|
||||
// Set up envs array
|
||||
// LAB 3: Your code here.
|
||||
int i;
|
||||
// 确保最小的env在最前端
|
||||
for (i = NENV-1; i >= 0; --i) {
|
||||
envs[i].env_id = 0;
|
||||
|
||||
envs[i].env_link = env_free_list;
|
||||
env_free_list = &envs[i];
|
||||
}
|
||||
|
||||
// Per-CPU part of the initialization
|
||||
env_init_percpu();
|
||||
}
|
||||
|
||||
// Load GDT and segment descriptors.
|
||||
void
|
||||
env_init_percpu(void)
|
||||
{
|
||||
lgdt(&gdt_pd);
|
||||
// The kernel never uses GS or FS, so we leave those set to
|
||||
// the user data segment.
|
||||
asm volatile("movw %%ax,%%gs" : : "a" (GD_UD|3));
|
||||
asm volatile("movw %%ax,%%fs" : : "a" (GD_UD|3));
|
||||
// The kernel does use ES, DS, and SS. We'll change between
|
||||
// the kernel and user data segments as needed.
|
||||
asm volatile("movw %%ax,%%es" : : "a" (GD_KD));
|
||||
asm volatile("movw %%ax,%%ds" : : "a" (GD_KD));
|
||||
asm volatile("movw %%ax,%%ss" : : "a" (GD_KD));
|
||||
// Load the kernel text segment into CS.
|
||||
asm volatile("ljmp %0,$1f\n 1:\n" : : "i" (GD_KT));
|
||||
// For good measure, clear the local descriptor table (LDT),
|
||||
// since we don't use it.
|
||||
lldt(0);
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize the kernel virtual memory layout for environment e.
|
||||
// Allocate a page directory, set e->env_pgdir accordingly,
|
||||
// and initialize the kernel portion of the new environment's address space.
|
||||
// Do NOT (yet) map anything into the user portion
|
||||
// of the environment's virtual address space.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors include:
|
||||
// -E_NO_MEM if page directory or table could not be allocated.
|
||||
// 这里又为每个环境分配一个页目录,有点晕了。
|
||||
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 = page2kva(p);
|
||||
// why ?因为在UTOP之上都是一样的,所以可以直接把kern_pgdir的内容全部拷贝过来
|
||||
|
||||
memcpy(e->env_pgdir, kern_pgdir, PGSIZE);
|
||||
p->pp_ref++;
|
||||
// UVPT maps the env's own page table read-only.
|
||||
// Permissions: kernel R, user R
|
||||
// 但是唯独UVPT这个地方是不一样的,因为要放的是自己的页表目录
|
||||
e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_P | PTE_U;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocates and initializes a new environment.
|
||||
// On success, the new environment is stored in *newenv_store.
|
||||
//
|
||||
// Returns 0 on success, < 0 on failure. Errors include:
|
||||
// -E_NO_FREE_ENV if all NENV environments are allocated
|
||||
// -E_NO_MEM on memory exhaustion
|
||||
//
|
||||
int
|
||||
env_alloc(struct Env **newenv_store, envid_t parent_id)
|
||||
{
|
||||
int32_t generation;
|
||||
int r;
|
||||
struct Env *e;
|
||||
|
||||
if (!(e = env_free_list))
|
||||
return -E_NO_FREE_ENV;
|
||||
|
||||
// Allocate and set up the page directory for this environment.
|
||||
if ((r = env_setup_vm(e)) < 0)
|
||||
return r;
|
||||
|
||||
// Generate an env_id for this environment.
|
||||
generation = (e->env_id + (1 << ENVGENSHIFT)) & ~(NENV - 1);
|
||||
if (generation <= 0) // Don't create a negative env_id.
|
||||
generation = 1 << ENVGENSHIFT;
|
||||
e->env_id = generation | (e - envs);
|
||||
|
||||
// Set the basic status variables.
|
||||
e->env_parent_id = parent_id;
|
||||
e->env_type = ENV_TYPE_USER;
|
||||
e->env_status = ENV_RUNNABLE;
|
||||
e->env_runs = 0;
|
||||
|
||||
// Clear out all the saved register state,
|
||||
// to prevent the register values
|
||||
// of a prior environment inhabiting this Env structure
|
||||
// from "leaking" into our new environment.
|
||||
memset(&e->env_tf, 0, sizeof(e->env_tf));
|
||||
|
||||
// Set up appropriate initial values for the segment registers.
|
||||
// GD_UD is the user data segment selector in the GDT, and
|
||||
// GD_UT is the user text segment selector (see inc/memlayout.h).
|
||||
// The low 2 bits of each segment register contains the
|
||||
// Requestor Privilege Level (RPL); 3 means user mode. When
|
||||
// we switch privilege levels, the hardware does various
|
||||
// checks involving the RPL and the Descriptor Privilege Level
|
||||
// (DPL) stored in the descriptors themselves.
|
||||
e->env_tf.tf_ds = GD_UD | 3;
|
||||
e->env_tf.tf_es = GD_UD | 3;
|
||||
e->env_tf.tf_ss = GD_UD | 3;
|
||||
e->env_tf.tf_esp = USTACKTOP;
|
||||
e->env_tf.tf_cs = GD_UT | 3;
|
||||
// You will set e->env_tf.tf_eip later.
|
||||
|
||||
// Enable interrupts while in user mode.
|
||||
// LAB 4: Your code here.
|
||||
|
||||
// Clear the page fault handler until user installs one.
|
||||
e->env_pgfault_upcall = 0;
|
||||
|
||||
// Also clear the IPC receiving flag.
|
||||
e->env_ipc_recving = 0;
|
||||
|
||||
// commit the allocation
|
||||
env_free_list = e->env_link;
|
||||
*newenv_store = e;
|
||||
|
||||
cprintf("[%08x] new env %08x\n", curenv ? curenv->env_id : 0, e->env_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate len bytes of physical memory for environment env,
|
||||
// and map it at virtual address va in the environment's address space.
|
||||
// Does not zero or otherwise initialize the mapped pages in any way.
|
||||
// Pages should be writable by user and kernel.
|
||||
// Panic if any allocation attempt fails.
|
||||
//
|
||||
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.)
|
||||
//
|
||||
struct PageInfo *pp;
|
||||
size_t i;
|
||||
size_t pgs = ROUNDUP(len, PGSIZE)/PGSIZE;
|
||||
size_t pva = ROUNDDOWN((size_t)va, PGSIZE);
|
||||
|
||||
|
||||
for(i=0; i < pgs; i++) {
|
||||
if (!(pp = page_alloc(ALLOC_ZERO))) {
|
||||
int ex = -E_NO_MEM;
|
||||
panic("region_alloc: %e", ex);
|
||||
}
|
||||
page_insert(e->env_pgdir, pp, (void *)pva, PTE_U|PTE_W|PTE_P);
|
||||
pva += PGSIZE;
|
||||
|
||||
}
|
||||
// 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!)
|
||||
}
|
||||
|
||||
//
|
||||
// Set up the initial program binary, stack, and processor flags
|
||||
// for a user process.
|
||||
// This function is ONLY called during kernel initialization,
|
||||
// before running the first user-mode environment.
|
||||
//
|
||||
// This function loads all loadable segments from the ELF binary image
|
||||
// into the environment's user memory, starting at the appropriate
|
||||
// virtual addresses indicated in the ELF program header.
|
||||
// At the same time it clears to zero any portions of these segments
|
||||
// that are marked in the program header as being mapped
|
||||
// but not actually present in the ELF file - i.e., the program's bss section.
|
||||
//
|
||||
// All this is very similar to what our boot loader does, except the boot
|
||||
// loader also needs to read the code from disk. Take a look at
|
||||
// boot/main.c to get ideas.
|
||||
//
|
||||
// Finally, this function maps one page for the program's initial stack.
|
||||
//
|
||||
// load_icode panics if it encounters problems.
|
||||
// - How might load_icode fail? What might be wrong with the given input?
|
||||
//
|
||||
static void
|
||||
load_icode(struct Env *e, uint8_t *binary)
|
||||
{
|
||||
// Hints:
|
||||
// Load each program segment into virtual memory
|
||||
// at the address specified in the ELF segment header.
|
||||
// You should only load segments with ph->p_type == ELF_PROG_LOAD.
|
||||
// Each segment's virtual address can be found in ph->p_va
|
||||
// and its size in memory can be found in ph->p_memsz.
|
||||
// The ph->p_filesz bytes from the ELF binary, starting at
|
||||
// 'binary + ph->p_offset', should be copied to virtual address
|
||||
// ph->p_va. Any remaining memory bytes should be cleared to zero.
|
||||
// (The ELF header should have ph->p_filesz <= ph->p_memsz.)
|
||||
// Use functions from the previous lab to allocate and map pages.
|
||||
//
|
||||
// All page protection bits should be user read/write for now.
|
||||
// ELF segments are not necessarily page-aligned, but you can
|
||||
// assume for this function that no two segments will touch
|
||||
// the same virtual page.
|
||||
//
|
||||
// You may find a function like region_alloc useful.
|
||||
//
|
||||
// Loading the segments is much simpler if you can move data
|
||||
// directly into the virtual addresses stored in the ELF binary.
|
||||
// So which page directory should be in force during
|
||||
// this function?
|
||||
//
|
||||
// You must also do something with the program's entry point,
|
||||
// to make sure that the environment starts executing there.
|
||||
// What? (See env_run() and env_pop_tf() below.)
|
||||
|
||||
// LAB 3: Your code here.
|
||||
// 怎么得到program的ELF地址? 就是bianry
|
||||
struct Proghdr *ph, *eph;
|
||||
struct Elf *elfhdr = (struct Elf *)binary;
|
||||
|
||||
// is this a valid ELF?
|
||||
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 memmory size\n");
|
||||
|
||||
region_alloc(e, (void *)ph->p_va, ph->p_memsz);
|
||||
memcpy((void *)ph->p_va, binary + ph->p_offset, ph->p_filesz);
|
||||
// clear bss section
|
||||
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.
|
||||
|
||||
// map the user stack
|
||||
region_alloc(e, (void *)USTACKTOP-PGSIZE, PGSIZE);
|
||||
lcr3(PADDR(kern_pgdir));
|
||||
}
|
||||
|
||||
//
|
||||
// Allocates a new env with env_alloc, loads the named elf
|
||||
// binary into it with load_icode, and sets its env_type.
|
||||
// This function is ONLY called during kernel initialization,
|
||||
// before running the first user-mode environment.
|
||||
// The new env's parent ID is set to 0.
|
||||
//
|
||||
void
|
||||
env_create(uint8_t *binary, enum EnvType type)
|
||||
{
|
||||
// LAB 3: Your code here.
|
||||
struct Env *newenv;
|
||||
int ret = 0;
|
||||
if ((ret = env_alloc(&newenv, 0)) < 0) {
|
||||
panic("env_create: %e\n", ret);
|
||||
}
|
||||
newenv->env_type = type;
|
||||
load_icode(newenv, binary);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// Frees env e and all memory it uses.
|
||||
//
|
||||
void
|
||||
env_free(struct Env *e)
|
||||
{
|
||||
pte_t *pt;
|
||||
uint32_t pdeno, pteno;
|
||||
physaddr_t pa;
|
||||
|
||||
// If freeing the current environment, switch to kern_pgdir
|
||||
// before freeing the page directory, just in case the page
|
||||
// gets reused.
|
||||
if (e == curenv)
|
||||
lcr3(PADDR(kern_pgdir));
|
||||
|
||||
// Note the environment's demise.
|
||||
cprintf("[%08x] free env %08x\n", curenv ? curenv->env_id : 0, e->env_id);
|
||||
|
||||
// Flush all mapped pages in the user portion of the address space
|
||||
static_assert(UTOP % PTSIZE == 0);
|
||||
for (pdeno = 0; pdeno < PDX(UTOP); pdeno++) {
|
||||
|
||||
// only look at mapped page tables
|
||||
if (!(e->env_pgdir[pdeno] & PTE_P))
|
||||
continue;
|
||||
|
||||
// find the pa and va of the page table
|
||||
pa = PTE_ADDR(e->env_pgdir[pdeno]);
|
||||
pt = (pte_t*) KADDR(pa);
|
||||
|
||||
// unmap all PTEs in this page table
|
||||
for (pteno = 0; pteno <= PTX(~0); pteno++) {
|
||||
if (pt[pteno] & PTE_P)
|
||||
page_remove(e->env_pgdir, PGADDR(pdeno, pteno, 0));
|
||||
}
|
||||
|
||||
// free the page table itself
|
||||
e->env_pgdir[pdeno] = 0;
|
||||
page_decref(pa2page(pa));
|
||||
}
|
||||
|
||||
// free the page directory
|
||||
pa = PADDR(e->env_pgdir);
|
||||
e->env_pgdir = 0;
|
||||
page_decref(pa2page(pa));
|
||||
|
||||
// return the environment to the free list
|
||||
e->env_status = ENV_FREE;
|
||||
e->env_link = env_free_list;
|
||||
env_free_list = e;
|
||||
}
|
||||
|
||||
//
|
||||
// Frees environment e.
|
||||
// If e was the current env, then runs a new environment (and does not return
|
||||
// to the caller).
|
||||
//
|
||||
void
|
||||
env_destroy(struct Env *e)
|
||||
{
|
||||
// If e is currently running on other CPUs, we change its state to
|
||||
// ENV_DYING. A zombie environment will be freed the next time
|
||||
// it traps to the kernel.
|
||||
if (e->env_status == ENV_RUNNING && curenv != e) {
|
||||
e->env_status = ENV_DYING;
|
||||
return;
|
||||
}
|
||||
|
||||
env_free(e);
|
||||
|
||||
if (curenv == e) {
|
||||
curenv = NULL;
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Restores the register values in the Trapframe with the 'iret' instruction.
|
||||
// This exits the kernel and starts executing some environment's code.
|
||||
//
|
||||
// This function does not return.
|
||||
//
|
||||
void
|
||||
env_pop_tf(struct Trapframe *tf)
|
||||
{
|
||||
// Record the CPU we are running on for user-space debugging
|
||||
curenv->env_cpunum = cpunum();
|
||||
|
||||
asm volatile(
|
||||
"\tmovl %0,%%esp\n"
|
||||
"\tpopal\n"
|
||||
"\tpopl %%es\n"
|
||||
"\tpopl %%ds\n"
|
||||
"\taddl $0x8,%%esp\n" /* skip tf_trapno and tf_errcode */
|
||||
"\tiret\n"
|
||||
: : "g" (tf) : "memory");
|
||||
panic("iret failed"); /* mostly to placate the compiler */
|
||||
}
|
||||
|
||||
//
|
||||
// Context switch from curenv to env e.
|
||||
// Note: if this is the first call to env_run, curenv is NULL.
|
||||
//
|
||||
// This function does not return.
|
||||
//
|
||||
void
|
||||
env_run(struct Env *e)
|
||||
{
|
||||
// Step 1: If this is a context switch (a new environment is running):
|
||||
// 1. Set the current environment (if any) back to
|
||||
// ENV_RUNNABLE if it is ENV_RUNNING (think about
|
||||
// what other states it can be in),
|
||||
// 2. Set 'curenv' to the new environment,
|
||||
// 3. Set its status to ENV_RUNNING,
|
||||
// 4. Update its 'env_runs' counter,
|
||||
// 5. Use lcr3() to switch to its address space.
|
||||
// Step 2: Use env_pop_tf() to restore the environment's
|
||||
// registers and drop into user mode in the
|
||||
// environment.
|
||||
|
||||
// Hint: This function loads the new environment's state from
|
||||
// e->env_tf. Go back through the code you wrote above
|
||||
// and make sure you have set the relevant parts of
|
||||
// e->env_tf to sensible values.
|
||||
|
||||
// LAB 3: Your code here.
|
||||
if (curenv && curenv->env_status == ENV_RUNNING) {
|
||||
curenv->env_status = ENV_RUNNABLE;
|
||||
}
|
||||
curenv = e;
|
||||
curenv->env_status = ENV_RUNNING;
|
||||
curenv->env_runs++;
|
||||
lcr3(PADDR(curenv->env_pgdir));
|
||||
|
||||
unlock_kernel();
|
||||
// iret退出内核, 回到用户环境执行,
|
||||
// 在load_icode() 中 env_tf保存了可执行文件的eip等信息
|
||||
env_pop_tf(&(curenv->env_tf));
|
||||
|
||||
|
||||
// panic("env_run not yet implemented");
|
||||
}
|
||||
|
||||
90
lab/LAB4.si4project/Backup/fork(3728).c
Normal file
90
lab/LAB4.si4project/Backup/fork(3728).c
Normal file
@@ -0,0 +1,90 @@
|
||||
// implement fork from user space
|
||||
|
||||
#include <inc/string.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
// PTE_COW marks copy-on-write page table entries.
|
||||
// It is one of the bits explicitly allocated to user processes (PTE_AVAIL).
|
||||
#define PTE_COW 0x800
|
||||
|
||||
//
|
||||
// Custom page fault handler - if faulting page is copy-on-write,
|
||||
// map in our own private writable copy.
|
||||
//
|
||||
static void
|
||||
pgfault(struct UTrapframe *utf)
|
||||
{
|
||||
void *addr = (void *) utf->utf_fault_va;
|
||||
uint32_t err = utf->utf_err;
|
||||
int r;
|
||||
|
||||
// Check that the faulting access was (1) a write, and (2) to a
|
||||
// copy-on-write page. If not, panic.
|
||||
// Hint:
|
||||
// Use the read-only page table mappings at uvpt
|
||||
// (see <inc/memlayout.h>).
|
||||
|
||||
// LAB 4: Your code here.
|
||||
|
||||
// Allocate a new page, map it at a temporary location (PFTEMP),
|
||||
// copy the data from the old page to the new page, then move the new
|
||||
// page to the old page's address.
|
||||
// Hint:
|
||||
// You should make three system calls.
|
||||
|
||||
// LAB 4: Your code here.
|
||||
|
||||
panic("pgfault not implemented");
|
||||
}
|
||||
|
||||
//
|
||||
// Map our virtual page pn (address pn*PGSIZE) into the target envid
|
||||
// at the same virtual address. If the page is writable or copy-on-write,
|
||||
// the new mapping must be created copy-on-write, and then our mapping must be
|
||||
// marked copy-on-write as well. (Exercise: Why do we need to mark ours
|
||||
// copy-on-write again if it was already copy-on-write at the beginning of
|
||||
// this function?)
|
||||
//
|
||||
// Returns: 0 on success, < 0 on error.
|
||||
// It is also OK to panic on error.
|
||||
//
|
||||
static int
|
||||
duppage(envid_t envid, unsigned pn)
|
||||
{
|
||||
int r;
|
||||
|
||||
// LAB 4: Your code here.
|
||||
panic("duppage not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// User-level fork with copy-on-write.
|
||||
// Set up our page fault handler appropriately.
|
||||
// Create a child.
|
||||
// Copy our address space and page fault handler setup to the child.
|
||||
// Then mark the child as runnable and return.
|
||||
//
|
||||
// Returns: child's envid to the parent, 0 to the child, < 0 on error.
|
||||
// It is also OK to panic on error.
|
||||
//
|
||||
// Hint:
|
||||
// Use uvpd, uvpt, and duppage.
|
||||
// Remember to fix "thisenv" in the child process.
|
||||
// Neither user exception stack should ever be marked copy-on-write,
|
||||
// so you must allocate a new page for the child's user exception stack.
|
||||
//
|
||||
envid_t
|
||||
fork(void)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("fork not implemented");
|
||||
}
|
||||
|
||||
// Challenge!
|
||||
int
|
||||
sfork(void)
|
||||
{
|
||||
panic("sfork not implemented");
|
||||
return -E_INVAL;
|
||||
}
|
||||
56
lab/LAB4.si4project/Backup/ipc(963).c
Normal file
56
lab/LAB4.si4project/Backup/ipc(963).c
Normal file
@@ -0,0 +1,56 @@
|
||||
// User-level IPC library routines
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
// Receive a value via IPC and return it.
|
||||
// If 'pg' is nonnull, then any page sent by the sender will be mapped at
|
||||
// that address.
|
||||
// If 'from_env_store' is nonnull, then store the IPC sender's envid in
|
||||
// *from_env_store.
|
||||
// If 'perm_store' is nonnull, then store the IPC sender's page permission
|
||||
// in *perm_store (this is nonzero iff a page was successfully
|
||||
// transferred to 'pg').
|
||||
// If the system call fails, then store 0 in *fromenv and *perm (if
|
||||
// they're nonnull) and return the error.
|
||||
// Otherwise, return the value sent by the sender
|
||||
//
|
||||
// Hint:
|
||||
// Use 'thisenv' to discover the value and who sent it.
|
||||
// If 'pg' is null, pass sys_ipc_recv a value that it will understand
|
||||
// as meaning "no page". (Zero is not the right value, since that's
|
||||
// a perfectly valid place to map a page.)
|
||||
int32_t
|
||||
ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("ipc_recv not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Send 'val' (and 'pg' with 'perm', if 'pg' is nonnull) to 'toenv'.
|
||||
// This function keeps trying until it succeeds.
|
||||
// It should panic() on any error other than -E_IPC_NOT_RECV.
|
||||
//
|
||||
// Hint:
|
||||
// Use sys_yield() to be CPU-friendly.
|
||||
// If 'pg' is null, pass sys_ipc_try_send a value that it will understand
|
||||
// as meaning "no page". (Zero is not the right value.)
|
||||
void
|
||||
ipc_send(envid_t to_env, uint32_t val, void *pg, int perm)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("ipc_send not implemented");
|
||||
}
|
||||
|
||||
// Find the first environment of the given type. We'll use this to
|
||||
// find special environments.
|
||||
// Returns 0 if no such environment exists.
|
||||
envid_t
|
||||
ipc_find_env(enum EnvType type)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NENV; i++)
|
||||
if (envs[i].env_type == type)
|
||||
return envs[i].env_id;
|
||||
return 0;
|
||||
}
|
||||
82
lab/LAB4.si4project/Backup/pfentry(173).S
Normal file
82
lab/LAB4.si4project/Backup/pfentry(173).S
Normal file
@@ -0,0 +1,82 @@
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/memlayout.h>
|
||||
|
||||
// Page fault upcall entrypoint.
|
||||
|
||||
// This is where we ask the kernel to redirect us to whenever we cause
|
||||
// a page fault in user space (see the call to sys_set_pgfault_handler
|
||||
// in pgfault.c).
|
||||
//
|
||||
// When a page fault actually occurs, the kernel switches our ESP to
|
||||
// point to the user exception stack if we're not already on the user
|
||||
// exception stack, and then it pushes a UTrapframe onto our user
|
||||
// exception stack:
|
||||
//
|
||||
// trap-time esp
|
||||
// trap-time eflags
|
||||
// trap-time eip
|
||||
// utf_regs.reg_eax
|
||||
// ...
|
||||
// utf_regs.reg_esi
|
||||
// utf_regs.reg_edi
|
||||
// utf_err (error code)
|
||||
// utf_fault_va <-- %esp
|
||||
//
|
||||
// If this is a recursive fault, the kernel will reserve for us a
|
||||
// blank word above the trap-time esp for scratch work when we unwind
|
||||
// the recursive call.
|
||||
//
|
||||
// We then have call up to the appropriate page fault handler in C
|
||||
// code, pointed to by the global variable '_pgfault_handler'.
|
||||
|
||||
.text
|
||||
.globl _pgfault_upcall
|
||||
_pgfault_upcall:
|
||||
// Call the C page fault handler.
|
||||
pushl %esp // function argument: pointer to UTF
|
||||
movl _pgfault_handler, %eax
|
||||
call *%eax
|
||||
addl $4, %esp // pop function argument
|
||||
|
||||
// Now the C page fault handler has returned and you must return
|
||||
// to the trap time state.
|
||||
// Push trap-time %eip onto the trap-time stack.
|
||||
//
|
||||
// Explanation:
|
||||
// We must prepare the trap-time stack for our eventual return to
|
||||
// re-execute the instruction that faulted.
|
||||
// Unfortunately, we can't return directly from the exception stack:
|
||||
// We can't call 'jmp', since that requires that we load the address
|
||||
// into a register, and all registers must have their trap-time
|
||||
// values after the return.
|
||||
// We can't call 'ret' from the exception stack either, since if we
|
||||
// did, %esp would have the wrong value.
|
||||
// So instead, we push the trap-time %eip onto the *trap-time* stack!
|
||||
// Below we'll switch to that stack and call 'ret', which will
|
||||
// restore %eip to its pre-fault value.
|
||||
//
|
||||
// In the case of a recursive fault on the exception stack,
|
||||
// note that the word we're pushing now will fit in the
|
||||
// blank word that the kernel reserved for us.
|
||||
//
|
||||
// Throughout the remaining code, think carefully about what
|
||||
// registers are available for intermediate calculations. You
|
||||
// may find that you have to rearrange your code in non-obvious
|
||||
// ways as registers become unavailable as scratch space.
|
||||
//
|
||||
// LAB 4: Your code here.
|
||||
|
||||
// Restore the trap-time registers. After you do this, you
|
||||
// can no longer modify any general-purpose registers.
|
||||
// LAB 4: Your code here.
|
||||
|
||||
// Restore eflags from the stack. After you do this, you can
|
||||
// no longer use arithmetic operations or anything else that
|
||||
// modifies eflags.
|
||||
// LAB 4: Your code here.
|
||||
|
||||
// Switch back to the adjusted trap-time stack.
|
||||
// LAB 4: Your code here.
|
||||
|
||||
// Return to re-execute the instruction that faulted.
|
||||
// LAB 4: Your code here.
|
||||
37
lab/LAB4.si4project/Backup/pgfault(4647).c
Normal file
37
lab/LAB4.si4project/Backup/pgfault(4647).c
Normal file
@@ -0,0 +1,37 @@
|
||||
// User-level page fault handler support.
|
||||
// Rather than register the C page fault handler directly with the
|
||||
// kernel as the page fault handler, we register the assembly language
|
||||
// wrapper in pfentry.S, which in turns calls the registered C
|
||||
// function.
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
|
||||
// Assembly language pgfault entrypoint defined in lib/pfentry.S.
|
||||
extern void _pgfault_upcall(void);
|
||||
|
||||
// Pointer to currently installed C-language pgfault handler.
|
||||
void (*_pgfault_handler)(struct UTrapframe *utf);
|
||||
|
||||
//
|
||||
// Set the page fault handler function.
|
||||
// If there isn't one yet, _pgfault_handler will be 0.
|
||||
// The first time we register a handler, we need to
|
||||
// allocate an exception stack (one page of memory with its top
|
||||
// at UXSTACKTOP), and tell the kernel to call the assembly-language
|
||||
// _pgfault_upcall routine when a page fault occurs.
|
||||
//
|
||||
void
|
||||
set_pgfault_handler(void (*handler)(struct UTrapframe *utf))
|
||||
{
|
||||
int r;
|
||||
|
||||
if (_pgfault_handler == 0) {
|
||||
// First time through!
|
||||
// LAB 4: Your code here.
|
||||
panic("set_pgfault_handler not implemented");
|
||||
}
|
||||
|
||||
// Save handler pointer for assembly to call.
|
||||
_pgfault_handler = handler;
|
||||
}
|
||||
86
lab/LAB4.si4project/Backup/picirq(7101).c
Normal file
86
lab/LAB4.si4project/Backup/picirq(7101).c
Normal file
@@ -0,0 +1,86 @@
|
||||
/* See COPYRIGHT for copyright information. */
|
||||
|
||||
#include <inc/assert.h>
|
||||
#include <inc/trap.h>
|
||||
|
||||
#include <kern/picirq.h>
|
||||
|
||||
|
||||
// Current IRQ mask.
|
||||
// Initial IRQ mask has interrupt 2 enabled (for slave 8259A).
|
||||
uint16_t irq_mask_8259A = 0xFFFF & ~(1<<IRQ_SLAVE);
|
||||
static bool didinit;
|
||||
|
||||
/* Initialize the 8259A interrupt controllers. */
|
||||
void
|
||||
pic_init(void)
|
||||
{
|
||||
didinit = 1;
|
||||
|
||||
// mask all interrupts
|
||||
outb(IO_PIC1+1, 0xFF);
|
||||
outb(IO_PIC2+1, 0xFF);
|
||||
|
||||
// Set up master (8259A-1)
|
||||
|
||||
// ICW1: 0001g0hi
|
||||
// g: 0 = edge triggering, 1 = level triggering
|
||||
// h: 0 = cascaded PICs, 1 = master only
|
||||
// i: 0 = no ICW4, 1 = ICW4 required
|
||||
outb(IO_PIC1, 0x11);
|
||||
|
||||
// ICW2: Vector offset
|
||||
outb(IO_PIC1+1, IRQ_OFFSET);
|
||||
|
||||
// ICW3: bit mask of IR lines connected to slave PICs (master PIC),
|
||||
// 3-bit No of IR line at which slave connects to master(slave PIC).
|
||||
outb(IO_PIC1+1, 1<<IRQ_SLAVE);
|
||||
|
||||
// ICW4: 000nbmap
|
||||
// n: 1 = special fully nested mode
|
||||
// b: 1 = buffered mode
|
||||
// m: 0 = slave PIC, 1 = master PIC
|
||||
// (ignored when b is 0, as the master/slave role
|
||||
// can be hardwired).
|
||||
// a: 1 = Automatic EOI mode
|
||||
// p: 0 = MCS-80/85 mode, 1 = intel x86 mode
|
||||
outb(IO_PIC1+1, 0x3);
|
||||
|
||||
// Set up slave (8259A-2)
|
||||
outb(IO_PIC2, 0x11); // ICW1
|
||||
outb(IO_PIC2+1, IRQ_OFFSET + 8); // ICW2
|
||||
outb(IO_PIC2+1, IRQ_SLAVE); // ICW3
|
||||
// NB Automatic EOI mode doesn't tend to work on the slave.
|
||||
// Linux source code says it's "to be investigated".
|
||||
outb(IO_PIC2+1, 0x01); // ICW4
|
||||
|
||||
// OCW3: 0ef01prs
|
||||
// ef: 0x = NOP, 10 = clear specific mask, 11 = set specific mask
|
||||
// p: 0 = no polling, 1 = polling mode
|
||||
// rs: 0x = NOP, 10 = read IRR, 11 = read ISR
|
||||
outb(IO_PIC1, 0x68); /* clear specific mask */
|
||||
outb(IO_PIC1, 0x0a); /* read IRR by default */
|
||||
|
||||
outb(IO_PIC2, 0x68); /* OCW3 */
|
||||
outb(IO_PIC2, 0x0a); /* OCW3 */
|
||||
|
||||
if (irq_mask_8259A != 0xFFFF)
|
||||
irq_setmask_8259A(irq_mask_8259A);
|
||||
}
|
||||
|
||||
void
|
||||
irq_setmask_8259A(uint16_t mask)
|
||||
{
|
||||
int i;
|
||||
irq_mask_8259A = mask;
|
||||
if (!didinit)
|
||||
return;
|
||||
outb(IO_PIC1+1, (char)mask);
|
||||
outb(IO_PIC2+1, (char)(mask >> 8));
|
||||
cprintf("enabled interrupts:");
|
||||
for (i = 0; i < 16; i++)
|
||||
if (~mask & (1<<i))
|
||||
cprintf(" %d", i);
|
||||
cprintf("\n");
|
||||
}
|
||||
|
||||
1260
lab/LAB4.si4project/Backup/pmap(6520).c
Normal file
1260
lab/LAB4.si4project/Backup/pmap(6520).c
Normal file
File diff suppressed because it is too large
Load Diff
84
lab/LAB4.si4project/Backup/sched(4329).c
Normal file
84
lab/LAB4.si4project/Backup/sched(4329).c
Normal file
@@ -0,0 +1,84 @@
|
||||
#include <inc/assert.h>
|
||||
#include <inc/x86.h>
|
||||
#include <kern/spinlock.h>
|
||||
#include <kern/env.h>
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/monitor.h>
|
||||
|
||||
void sched_halt(void);
|
||||
|
||||
// Choose a user environment to run and run it.
|
||||
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.
|
||||
|
||||
// sched_halt never returns
|
||||
sched_halt();
|
||||
}
|
||||
|
||||
// Halt this CPU when there is nothing to do. Wait until the
|
||||
// timer interrupt wakes it up. This function never returns.
|
||||
//
|
||||
void
|
||||
sched_halt(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// For debugging and testing purposes, if there are no runnable
|
||||
// environments in the system, then drop into the kernel monitor.
|
||||
for (i = 0; i < NENV; i++) {
|
||||
if ((envs[i].env_status == ENV_RUNNABLE ||
|
||||
envs[i].env_status == ENV_RUNNING ||
|
||||
envs[i].env_status == ENV_DYING))
|
||||
break;
|
||||
}
|
||||
if (i == NENV) {
|
||||
cprintf("No runnable environments in the system!\n");
|
||||
while (1)
|
||||
monitor(NULL);
|
||||
}
|
||||
|
||||
// Mark that no environment is running on this CPU
|
||||
curenv = NULL;
|
||||
lcr3(PADDR(kern_pgdir));
|
||||
|
||||
// Mark that this CPU is in the HALT state, so that when
|
||||
// timer interupts come in, we know we should re-acquire the
|
||||
// big kernel lock
|
||||
xchg(&thiscpu->cpu_status, CPU_HALTED);
|
||||
|
||||
// Release the big kernel lock as if we were "leaving" the kernel
|
||||
unlock_kernel();
|
||||
|
||||
// Reset stack pointer, enable interrupts and then halt.
|
||||
asm volatile (
|
||||
"movl $0, %%ebp\n"
|
||||
"movl %0, %%esp\n"
|
||||
"pushl $0\n"
|
||||
"pushl $0\n"
|
||||
// Uncomment the following line after completing exercise 13
|
||||
//"sti\n"
|
||||
"1:\n"
|
||||
"hlt\n"
|
||||
"jmp 1b\n"
|
||||
: : "a" (thiscpu->cpu_ts.ts_esp0));
|
||||
}
|
||||
|
||||
99
lab/LAB4.si4project/Backup/sched(5719).c
Normal file
99
lab/LAB4.si4project/Backup/sched(5719).c
Normal file
@@ -0,0 +1,99 @@
|
||||
#include <inc/assert.h>
|
||||
#include <inc/x86.h>
|
||||
#include <kern/spinlock.h>
|
||||
#include <kern/env.h>
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/monitor.h>
|
||||
|
||||
void sched_halt(void);
|
||||
|
||||
// Choose a user environment to run and run it.
|
||||
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.
|
||||
|
||||
idle = curenv;
|
||||
int start_envid = idle ? ENVX(idle->env_id)+1 : 0;
|
||||
|
||||
for (int i = 0; i < NENV; i++) {
|
||||
int j = (start_envid + i) % NENV;
|
||||
if (envs[j].env_status == ENV_RUNNABLE) {
|
||||
env_run(&envs[j]);
|
||||
}
|
||||
}
|
||||
|
||||
if (idle && idle->env_status == ENV_RUNNING) {
|
||||
env_run(idle);
|
||||
}
|
||||
|
||||
// sched_halt never returns
|
||||
sched_halt();
|
||||
|
||||
}
|
||||
|
||||
// Halt this CPU when there is nothing to do. Wait until the
|
||||
// timer interrupt wakes it up. This function never returns.
|
||||
//
|
||||
void
|
||||
sched_halt(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// For debugging and testing purposes, if there are no runnable
|
||||
// environments in the system, then drop into the kernel monitor.
|
||||
for (i = 0; i < NENV; i++) {
|
||||
if ((envs[i].env_status == ENV_RUNNABLE ||
|
||||
envs[i].env_status == ENV_RUNNING ||
|
||||
envs[i].env_status == ENV_DYING))
|
||||
break;
|
||||
}
|
||||
if (i == NENV) {
|
||||
cprintf("No runnable environments in the system!\n");
|
||||
while (1)
|
||||
monitor(NULL);
|
||||
}
|
||||
|
||||
// Mark that no environment is running on this CPU
|
||||
curenv = NULL;
|
||||
lcr3(PADDR(kern_pgdir));
|
||||
|
||||
// Mark that this CPU is in the HALT state, so that when
|
||||
// timer interupts come in, we know we should re-acquire the
|
||||
// big kernel lock
|
||||
xchg(&thiscpu->cpu_status, CPU_HALTED);
|
||||
|
||||
// Release the big kernel lock as if we were "leaving" the kernel
|
||||
unlock_kernel();
|
||||
|
||||
// Reset stack pointer, enable interrupts and then halt.
|
||||
asm volatile (
|
||||
"movl $0, %%ebp\n"
|
||||
"movl %0, %%esp\n"
|
||||
"pushl $0\n"
|
||||
"pushl $0\n"
|
||||
// Uncomment the following line after completing exercise 13
|
||||
//"sti\n"
|
||||
"1:\n"
|
||||
"hlt\n"
|
||||
"jmp 1b\n"
|
||||
: : "a" (thiscpu->cpu_ts.ts_esp0));
|
||||
}
|
||||
|
||||
99
lab/LAB4.si4project/Backup/sched(6307).c
Normal file
99
lab/LAB4.si4project/Backup/sched(6307).c
Normal file
@@ -0,0 +1,99 @@
|
||||
#include <inc/assert.h>
|
||||
#include <inc/x86.h>
|
||||
#include <kern/spinlock.h>
|
||||
#include <kern/env.h>
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/monitor.h>
|
||||
|
||||
void sched_halt(void);
|
||||
|
||||
// Choose a user environment to run and run it.
|
||||
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.
|
||||
|
||||
idle = curenv;
|
||||
int start_envid = idle ? ENVX(idle->env_id)+1 : 0;
|
||||
|
||||
for (int i = 0; i < NENV; i++) {
|
||||
int j = (start_envid + i) % NENV;
|
||||
if (envs[j].env_status == ENV_RUNNABLE) {
|
||||
env_run(&envs[j]);
|
||||
}
|
||||
}
|
||||
|
||||
if (idle && idle->env_status == ENV_RUNNING) {
|
||||
env_run(idle);
|
||||
}
|
||||
|
||||
// sched_halt never returns
|
||||
sched_halt();
|
||||
|
||||
}
|
||||
|
||||
// Halt this CPU when there is nothing to do. Wait until the
|
||||
// timer interrupt wakes it up. This function never returns.
|
||||
//
|
||||
void
|
||||
sched_halt(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// For debugging and testing purposes, if there are no runnable
|
||||
// environments in the system, then drop into the kernel monitor.
|
||||
for (i = 0; i < NENV; i++) {
|
||||
if ((envs[i].env_status == ENV_RUNNABLE ||
|
||||
envs[i].env_status == ENV_RUNNING ||
|
||||
envs[i].env_status == ENV_DYING))
|
||||
break;
|
||||
}
|
||||
if (i == NENV) {
|
||||
cprintf("No runnable environments in the system!\n");
|
||||
while (1)
|
||||
monitor(NULL);
|
||||
}
|
||||
|
||||
// Mark that no environment is running on this CPU
|
||||
curenv = NULL;
|
||||
lcr3(PADDR(kern_pgdir));
|
||||
|
||||
// Mark that this CPU is in the HALT state, so that when
|
||||
// timer interupts come in, we know we should re-acquire the
|
||||
// big kernel lock
|
||||
xchg(&thiscpu->cpu_status, CPU_HALTED);
|
||||
|
||||
// Release the big kernel lock as if we were "leaving" the kernel
|
||||
unlock_kernel();
|
||||
|
||||
// Reset stack pointer, enable interrupts and then halt.
|
||||
asm volatile (
|
||||
"movl $0, %%ebp\n"
|
||||
"movl %0, %%esp\n"
|
||||
"pushl $0\n"
|
||||
"pushl $0\n"
|
||||
// Uncomment the following line after completing exercise 13
|
||||
//"sti\n"
|
||||
"1:\n"
|
||||
"hlt\n"
|
||||
"jmp 1b\n"
|
||||
: : "a" (thiscpu->cpu_ts.ts_esp0));
|
||||
}
|
||||
|
||||
378
lab/LAB4.si4project/Backup/syscall(1135).c
Normal file
378
lab/LAB4.si4project/Backup/syscall(1135).c
Normal file
@@ -0,0 +1,378 @@
|
||||
/* See COPYRIGHT for copyright information. */
|
||||
|
||||
#include <inc/x86.h>
|
||||
#include <inc/error.h>
|
||||
#include <inc/string.h>
|
||||
#include <inc/assert.h>
|
||||
|
||||
#include <kern/env.h>
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/trap.h>
|
||||
#include <kern/syscall.h>
|
||||
#include <kern/console.h>
|
||||
#include <kern/sched.h>
|
||||
|
||||
// Print a string to the system console.
|
||||
// The string is exactly 'len' characters long.
|
||||
// Destroys the environment on memory errors.
|
||||
static void
|
||||
sys_cputs(const char *s, size_t len)
|
||||
{
|
||||
// Check that the user has permission to read memory [s, s+len).
|
||||
// Destroy the environment if not.
|
||||
|
||||
// LAB 3: Your code here.
|
||||
user_mem_assert(curenv, (const void *) s, len, 0);
|
||||
// Print the string supplied by the user.
|
||||
cprintf("%.*s", len, s);
|
||||
}
|
||||
|
||||
// Read a character from the system console without blocking.
|
||||
// Returns the character, or 0 if there is no input waiting.
|
||||
static int
|
||||
sys_cgetc(void)
|
||||
{
|
||||
return cons_getc();
|
||||
}
|
||||
|
||||
// Returns the current environment's envid.
|
||||
static envid_t
|
||||
sys_getenvid(void)
|
||||
{
|
||||
return curenv->env_id;
|
||||
}
|
||||
|
||||
// Destroy a given environment (possibly the currently running environment).
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
static int
|
||||
sys_env_destroy(envid_t envid)
|
||||
{
|
||||
int r;
|
||||
struct Env *e;
|
||||
|
||||
if ((r = envid2env(envid, &e, 1)) < 0)
|
||||
return r;
|
||||
if (e == curenv)
|
||||
cprintf("[%08x] exiting gracefully\n", curenv->env_id);
|
||||
else
|
||||
cprintf("[%08x] destroying %08x\n", curenv->env_id, e->env_id);
|
||||
env_destroy(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Deschedule current environment and pick a different one to run.
|
||||
static void
|
||||
sys_yield(void)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
|
||||
// Allocate a new environment.
|
||||
// Returns envid of new environment, or < 0 on error. Errors are:
|
||||
// -E_NO_FREE_ENV if no free environment is available.
|
||||
// -E_NO_MEM on memory exhaustion.
|
||||
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;
|
||||
int32_t ret;
|
||||
if ((ret = env_alloc(&newenv, sys_getenvid())) < 0) {
|
||||
// 两个函数的返回值是一样的
|
||||
return ret;
|
||||
}
|
||||
newenv->env_status = ENV_NOT_RUNNABLE;
|
||||
newenv->env_tf = curenv->env_tf;
|
||||
// newenv的返回值为0, 实现子进程返回0值
|
||||
newenv->env_tf.tf_regs.reg_eax = 0;
|
||||
// 返回值存放在eax中
|
||||
return newenv->env_id;
|
||||
|
||||
// panic("sys_exofork not implemented");
|
||||
}
|
||||
|
||||
// Set envid's env_status to status, which must be ENV_RUNNABLE
|
||||
// or ENV_NOT_RUNNABLE.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if status is not a valid status for an environment.
|
||||
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 *e;
|
||||
if (envid2env(envid, &e, 1)) return -E_BAD_ENV;
|
||||
|
||||
if (status != ENV_NOT_RUNNABLE && status != ENV_RUNNABLE)
|
||||
return -E_INVAL;
|
||||
|
||||
e->env_status = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set the page fault upcall for 'envid' by modifying the corresponding struct
|
||||
// Env's 'env_pgfault_upcall' field. When 'envid' causes a page fault, the
|
||||
// kernel will push a fault record onto the exception stack, then branch to
|
||||
// 'func'.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
static int
|
||||
sys_env_set_pgfault_upcall(envid_t envid, void *func)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
|
||||
|
||||
panic("sys_env_set_pgfault_upcall not implemented");
|
||||
}
|
||||
|
||||
// Allocate a page of memory and map it at 'va' with permission
|
||||
// 'perm' in the address space of 'envid'.
|
||||
// The page's contents are set to 0.
|
||||
// If a page is already mapped at 'va', that page is unmapped as a
|
||||
// side effect.
|
||||
//
|
||||
// perm -- PTE_U | PTE_P must be set, PTE_AVAIL | PTE_W may or may not be set,
|
||||
// but no other bits may be set. See PTE_SYSCALL in inc/mmu.h.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if va >= UTOP, or va is not page-aligned.
|
||||
// -E_INVAL if perm is inappropriate (see above).
|
||||
// -E_NO_MEM if there's no memory to allocate the new page,
|
||||
// or to allocate any necessary page tables.
|
||||
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.
|
||||
int ret = 0;
|
||||
struct Env *env;
|
||||
|
||||
if ((ret = envid2env(envid, &env, 1)) < 0)
|
||||
return -E_BAD_ENV;
|
||||
|
||||
if((uintptr_t)va >= UTOP || PGOFF(va))
|
||||
return -E_INVAL;
|
||||
if ((perm & PTE_U) == 0 || (perm & PTE_P) == 0)
|
||||
return -E_INVAL;
|
||||
if (perm & ~PTE_SYSCALL)
|
||||
return -E_INVAL;
|
||||
|
||||
struct PageInfo *pp = page_alloc(ALLOC_ZERO);
|
||||
if(!pp)
|
||||
return -E_NO_MEM;
|
||||
|
||||
if (page_insert(env->env_pgdir, pp, va, perm) < 0)
|
||||
return -E_NO_MEM;
|
||||
|
||||
return 0;
|
||||
// panic("sys_page_alloc not implemented");
|
||||
}
|
||||
|
||||
// Map the page of memory at 'srcva' in srcenvid's address space
|
||||
// at 'dstva' in dstenvid's address space with permission 'perm'.
|
||||
// Perm has the same restrictions as in sys_page_alloc, except
|
||||
// that it also must not grant write access to a read-only
|
||||
// page.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change one of them.
|
||||
// -E_INVAL if srcva >= UTOP or srcva is not page-aligned,
|
||||
// or dstva >= UTOP or dstva is not page-aligned.
|
||||
// -E_INVAL is srcva is not mapped in srcenvid's address space.
|
||||
// -E_INVAL if perm is inappropriate (see sys_page_alloc).
|
||||
// -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's
|
||||
// address space.
|
||||
// -E_NO_MEM if there's no memory to allocate any necessary page tables.
|
||||
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.
|
||||
int ret = 0;
|
||||
struct Env *srcenv, *dstenv;
|
||||
struct PageInfo *srcpp, *dstpp;
|
||||
pte_t *pte;
|
||||
if ((envid2env(srcenvid, &srcenv, 1) < 0 )|| ( envid2env(dstenvid, &dstenv, 1) < 0))
|
||||
return -E_BAD_ENV;
|
||||
if ((uintptr_t)srcva >= UTOP || PGOFF(srcva) || (uintptr_t)dstva >= UTOP || PGOFF(dstva))
|
||||
return -E_INVAL;
|
||||
if ( (perm & PTE_U) == 0 || (perm & PTE_P) == 0 || (perm & ~PTE_SYSCALL))
|
||||
return -E_INVAL;
|
||||
if (!(srcpp = page_lookup(srcenv->env_pgdir, srcva, &pte)))
|
||||
return -E_INVAL;
|
||||
if ((perm & PTE_W) && ((*pte & PTE_W) == 0))
|
||||
return -E_INVAL;
|
||||
if (page_insert(dstenv->env_pgdir, srcpp, dstva, perm) < 0)
|
||||
return -E_NO_MEM;
|
||||
|
||||
return 0;
|
||||
// panic("sys_page_map not implemented");
|
||||
}
|
||||
|
||||
// Unmap the page of memory at 'va' in the address space of 'envid'.
|
||||
// If no page is mapped, the function silently succeeds.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if va >= UTOP, or va is not page-aligned.
|
||||
static int
|
||||
sys_page_unmap(envid_t envid, void *va)
|
||||
{
|
||||
// Hint: This function is a wrapper around page_remove().
|
||||
|
||||
// LAB 4: Your code here.
|
||||
int ret = 0;
|
||||
struct Env *env;
|
||||
|
||||
if ((ret = envid2env(envid, &env, 1)) < 0)
|
||||
return -E_BAD_ENV;
|
||||
if ((uintptr_t)va >= UTOP || PGOFF(va))
|
||||
return -E_INVAL;
|
||||
page_remove(env->env_pgdir, va);
|
||||
return 0;
|
||||
// panic("sys_page_unmap not implemented");
|
||||
}
|
||||
|
||||
// Try to send 'value' to the target env 'envid'.
|
||||
// If srcva < UTOP, then also send page currently mapped at 'srcva',
|
||||
// so that receiver gets a duplicate mapping of the same page.
|
||||
//
|
||||
// The send fails with a return value of -E_IPC_NOT_RECV if the
|
||||
// target is not blocked, waiting for an IPC.
|
||||
//
|
||||
// The send also can fail for the other reasons listed below.
|
||||
//
|
||||
// Otherwise, the send succeeds, and the target's ipc fields are
|
||||
// updated as follows:
|
||||
// env_ipc_recving is set to 0 to block future sends;
|
||||
// env_ipc_from is set to the sending envid;
|
||||
// env_ipc_value is set to the 'value' parameter;
|
||||
// env_ipc_perm is set to 'perm' if a page was transferred, 0 otherwise.
|
||||
// The target environment is marked runnable again, returning 0
|
||||
// from the paused sys_ipc_recv system call. (Hint: does the
|
||||
// sys_ipc_recv function ever actually return?)
|
||||
//
|
||||
// If the sender wants to send a page but the receiver isn't asking for one,
|
||||
// then no page mapping is transferred, but no error occurs.
|
||||
// The ipc only happens when no errors occur.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error.
|
||||
// Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist.
|
||||
// (No need to check permissions.)
|
||||
// -E_IPC_NOT_RECV if envid is not currently blocked in sys_ipc_recv,
|
||||
// or another environment managed to send first.
|
||||
// -E_INVAL if srcva < UTOP but srcva is not page-aligned.
|
||||
// -E_INVAL if srcva < UTOP and perm is inappropriate
|
||||
// (see sys_page_alloc).
|
||||
// -E_INVAL if srcva < UTOP but srcva is not mapped in the caller's
|
||||
// address space.
|
||||
// -E_INVAL if (perm & PTE_W), but srcva is read-only in the
|
||||
// current environment's address space.
|
||||
// -E_NO_MEM if there's not enough memory to map srcva in envid's
|
||||
// address space.
|
||||
static int
|
||||
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_ipc_try_send not implemented");
|
||||
}
|
||||
|
||||
// Block until a value is ready. Record that you want to receive
|
||||
// using the env_ipc_recving and env_ipc_dstva fields of struct Env,
|
||||
// mark yourself not runnable, and then give up the CPU.
|
||||
//
|
||||
// If 'dstva' is < UTOP, then you are willing to receive a page of data.
|
||||
// 'dstva' is the virtual address at which the sent page should be mapped.
|
||||
//
|
||||
// This function only returns on error, but the system call will eventually
|
||||
// return 0 on success.
|
||||
// Return < 0 on error. Errors are:
|
||||
// -E_INVAL if dstva < UTOP but dstva is not page-aligned.
|
||||
static int
|
||||
sys_ipc_recv(void *dstva)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_ipc_recv not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Dispatches to the correct kernel function, passing the arguments.
|
||||
int32_t
|
||||
syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
|
||||
{
|
||||
// Call the function corresponding to the 'syscallno' parameter.
|
||||
// Return any appropriate return value.
|
||||
// LAB 3: Your code here.
|
||||
switch (syscallno) {
|
||||
case SYS_cputs:
|
||||
sys_cputs((const char*)a1, a2);
|
||||
break;
|
||||
case SYS_cgetc:
|
||||
return sys_cgetc();
|
||||
case SYS_getenvid:
|
||||
ret = sys_getenvid();
|
||||
break;
|
||||
case SYS_env_destroy:
|
||||
return sys_env_destroy(a1);
|
||||
case SYS_yield:
|
||||
sys_yield();
|
||||
break;
|
||||
case SYS_page_alloc:
|
||||
return sys_page_alloc((envid_t)a1, (void * )a2, (int )a3);
|
||||
|
||||
case SYS_page_map:
|
||||
return sys_page_map((envid_t) a1, (void *) a2, (envid_t) a3, (void *) a4, (int) a5);
|
||||
|
||||
case SYS_page_unmap:
|
||||
return sys_page_unmap((envid_t) a1, (void *) a2);
|
||||
|
||||
case SYS_exofork:
|
||||
return sys_exofork();
|
||||
|
||||
case SYS_env_set_status:
|
||||
return sys_env_set_status((envid_t) a1, (int) a2);
|
||||
case NSYSCALLS:
|
||||
return -E_INVAL;
|
||||
|
||||
default:
|
||||
return -E_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
383
lab/LAB4.si4project/Backup/syscall(1286).c
Normal file
383
lab/LAB4.si4project/Backup/syscall(1286).c
Normal file
@@ -0,0 +1,383 @@
|
||||
/* See COPYRIGHT for copyright information. */
|
||||
|
||||
#include <inc/x86.h>
|
||||
#include <inc/error.h>
|
||||
#include <inc/string.h>
|
||||
#include <inc/assert.h>
|
||||
|
||||
#include <kern/env.h>
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/trap.h>
|
||||
#include <kern/syscall.h>
|
||||
#include <kern/console.h>
|
||||
#include <kern/sched.h>
|
||||
|
||||
// Print a string to the system console.
|
||||
// The string is exactly 'len' characters long.
|
||||
// Destroys the environment on memory errors.
|
||||
static void
|
||||
sys_cputs(const char *s, size_t len)
|
||||
{
|
||||
// Check that the user has permission to read memory [s, s+len).
|
||||
// Destroy the environment if not.
|
||||
|
||||
// LAB 3: Your code here.
|
||||
user_mem_assert(curenv, (const void *) s, len, 0);
|
||||
// Print the string supplied by the user.
|
||||
cprintf("%.*s", len, s);
|
||||
}
|
||||
|
||||
// Read a character from the system console without blocking.
|
||||
// Returns the character, or 0 if there is no input waiting.
|
||||
static int
|
||||
sys_cgetc(void)
|
||||
{
|
||||
return cons_getc();
|
||||
}
|
||||
|
||||
// Returns the current environment's envid.
|
||||
static envid_t
|
||||
sys_getenvid(void)
|
||||
{
|
||||
return curenv->env_id;
|
||||
}
|
||||
|
||||
// Destroy a given environment (possibly the currently running environment).
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
static int
|
||||
sys_env_destroy(envid_t envid)
|
||||
{
|
||||
int r;
|
||||
struct Env *e;
|
||||
|
||||
if ((r = envid2env(envid, &e, 1)) < 0)
|
||||
return r;
|
||||
if (e == curenv)
|
||||
cprintf("[%08x] exiting gracefully\n", curenv->env_id);
|
||||
else
|
||||
cprintf("[%08x] destroying %08x\n", curenv->env_id, e->env_id);
|
||||
env_destroy(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Deschedule current environment and pick a different one to run.
|
||||
static void
|
||||
sys_yield(void)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
|
||||
// Allocate a new environment.
|
||||
// Returns envid of new environment, or < 0 on error. Errors are:
|
||||
// -E_NO_FREE_ENV if no free environment is available.
|
||||
// -E_NO_MEM on memory exhaustion.
|
||||
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;
|
||||
int32_t ret;
|
||||
if ((ret = env_alloc(&newenv, sys_getenvid())) < 0) {
|
||||
// 两个函数的返回值是一样的
|
||||
return ret;
|
||||
}
|
||||
newenv->env_status = ENV_NOT_RUNNABLE;
|
||||
newenv->env_tf = curenv->env_tf;
|
||||
// newenv的返回值为0, 实现子进程返回0值
|
||||
newenv->env_tf.tf_regs.reg_eax = 0;
|
||||
// 返回值存放在eax中
|
||||
return newenv->env_id;
|
||||
|
||||
// panic("sys_exofork not implemented");
|
||||
}
|
||||
|
||||
// Set envid's env_status to status, which must be ENV_RUNNABLE
|
||||
// or ENV_NOT_RUNNABLE.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if status is not a valid status for an environment.
|
||||
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 *e;
|
||||
if (envid2env(envid, &e, 1)) return -E_BAD_ENV;
|
||||
|
||||
if (status != ENV_NOT_RUNNABLE && status != ENV_RUNNABLE)
|
||||
return -E_INVAL;
|
||||
|
||||
e->env_status = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set the page fault upcall for 'envid' by modifying the corresponding struct
|
||||
// Env's 'env_pgfault_upcall' field. When 'envid' causes a page fault, the
|
||||
// kernel will push a fault record onto the exception stack, then branch to
|
||||
// 'func'.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
static int
|
||||
sys_env_set_pgfault_upcall(envid_t envid, void *func)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
struct Env *e;
|
||||
if (envid2env(envid, &e, 1))
|
||||
return -E_BAD_ENV;
|
||||
|
||||
e->env_pgfault_upcall = func;
|
||||
return 0;
|
||||
// panic("sys_env_set_pgfault_upcall not implemented");
|
||||
}
|
||||
|
||||
// Allocate a page of memory and map it at 'va' with permission
|
||||
// 'perm' in the address space of 'envid'.
|
||||
// The page's contents are set to 0.
|
||||
// If a page is already mapped at 'va', that page is unmapped as a
|
||||
// side effect.
|
||||
//
|
||||
// perm -- PTE_U | PTE_P must be set, PTE_AVAIL | PTE_W may or may not be set,
|
||||
// but no other bits may be set. See PTE_SYSCALL in inc/mmu.h.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if va >= UTOP, or va is not page-aligned.
|
||||
// -E_INVAL if perm is inappropriate (see above).
|
||||
// -E_NO_MEM if there's no memory to allocate the new page,
|
||||
// or to allocate any necessary page tables.
|
||||
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.
|
||||
int ret = 0;
|
||||
struct Env *env;
|
||||
|
||||
if ((ret = envid2env(envid, &env, 1)) < 0)
|
||||
return -E_BAD_ENV;
|
||||
|
||||
if((uintptr_t)va >= UTOP || PGOFF(va))
|
||||
return -E_INVAL;
|
||||
if ((perm & PTE_U) == 0 || (perm & PTE_P) == 0)
|
||||
return -E_INVAL;
|
||||
if (perm & ~PTE_SYSCALL)
|
||||
return -E_INVAL;
|
||||
|
||||
struct PageInfo *pp = page_alloc(ALLOC_ZERO);
|
||||
if(!pp)
|
||||
return -E_NO_MEM;
|
||||
|
||||
if (page_insert(env->env_pgdir, pp, va, perm) < 0)
|
||||
return -E_NO_MEM;
|
||||
|
||||
return 0;
|
||||
// panic("sys_page_alloc not implemented");
|
||||
}
|
||||
|
||||
// Map the page of memory at 'srcva' in srcenvid's address space
|
||||
// at 'dstva' in dstenvid's address space with permission 'perm'.
|
||||
// Perm has the same restrictions as in sys_page_alloc, except
|
||||
// that it also must not grant write access to a read-only
|
||||
// page.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change one of them.
|
||||
// -E_INVAL if srcva >= UTOP or srcva is not page-aligned,
|
||||
// or dstva >= UTOP or dstva is not page-aligned.
|
||||
// -E_INVAL is srcva is not mapped in srcenvid's address space.
|
||||
// -E_INVAL if perm is inappropriate (see sys_page_alloc).
|
||||
// -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's
|
||||
// address space.
|
||||
// -E_NO_MEM if there's no memory to allocate any necessary page tables.
|
||||
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.
|
||||
int ret = 0;
|
||||
struct Env *srcenv, *dstenv;
|
||||
struct PageInfo *srcpp, *dstpp;
|
||||
pte_t *pte;
|
||||
if ((envid2env(srcenvid, &srcenv, 1) < 0 )|| ( envid2env(dstenvid, &dstenv, 1) < 0))
|
||||
return -E_BAD_ENV;
|
||||
if ((uintptr_t)srcva >= UTOP || PGOFF(srcva) || (uintptr_t)dstva >= UTOP || PGOFF(dstva))
|
||||
return -E_INVAL;
|
||||
if ( (perm & PTE_U) == 0 || (perm & PTE_P) == 0 || (perm & ~PTE_SYSCALL))
|
||||
return -E_INVAL;
|
||||
if (!(srcpp = page_lookup(srcenv->env_pgdir, srcva, &pte)))
|
||||
return -E_INVAL;
|
||||
if ((perm & PTE_W) && ((*pte & PTE_W) == 0))
|
||||
return -E_INVAL;
|
||||
if (page_insert(dstenv->env_pgdir, srcpp, dstva, perm) < 0)
|
||||
return -E_NO_MEM;
|
||||
|
||||
return 0;
|
||||
// panic("sys_page_map not implemented");
|
||||
}
|
||||
|
||||
// Unmap the page of memory at 'va' in the address space of 'envid'.
|
||||
// If no page is mapped, the function silently succeeds.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if va >= UTOP, or va is not page-aligned.
|
||||
static int
|
||||
sys_page_unmap(envid_t envid, void *va)
|
||||
{
|
||||
// Hint: This function is a wrapper around page_remove().
|
||||
|
||||
// LAB 4: Your code here.
|
||||
int ret = 0;
|
||||
struct Env *env;
|
||||
|
||||
if ((ret = envid2env(envid, &env, 1)) < 0)
|
||||
return -E_BAD_ENV;
|
||||
if ((uintptr_t)va >= UTOP || PGOFF(va))
|
||||
return -E_INVAL;
|
||||
page_remove(env->env_pgdir, va);
|
||||
return 0;
|
||||
// panic("sys_page_unmap not implemented");
|
||||
}
|
||||
|
||||
// Try to send 'value' to the target env 'envid'.
|
||||
// If srcva < UTOP, then also send page currently mapped at 'srcva',
|
||||
// so that receiver gets a duplicate mapping of the same page.
|
||||
//
|
||||
// The send fails with a return value of -E_IPC_NOT_RECV if the
|
||||
// target is not blocked, waiting for an IPC.
|
||||
//
|
||||
// The send also can fail for the other reasons listed below.
|
||||
//
|
||||
// Otherwise, the send succeeds, and the target's ipc fields are
|
||||
// updated as follows:
|
||||
// env_ipc_recving is set to 0 to block future sends;
|
||||
// env_ipc_from is set to the sending envid;
|
||||
// env_ipc_value is set to the 'value' parameter;
|
||||
// env_ipc_perm is set to 'perm' if a page was transferred, 0 otherwise.
|
||||
// The target environment is marked runnable again, returning 0
|
||||
// from the paused sys_ipc_recv system call. (Hint: does the
|
||||
// sys_ipc_recv function ever actually return?)
|
||||
//
|
||||
// If the sender wants to send a page but the receiver isn't asking for one,
|
||||
// then no page mapping is transferred, but no error occurs.
|
||||
// The ipc only happens when no errors occur.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error.
|
||||
// Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist.
|
||||
// (No need to check permissions.)
|
||||
// -E_IPC_NOT_RECV if envid is not currently blocked in sys_ipc_recv,
|
||||
// or another environment managed to send first.
|
||||
// -E_INVAL if srcva < UTOP but srcva is not page-aligned.
|
||||
// -E_INVAL if srcva < UTOP and perm is inappropriate
|
||||
// (see sys_page_alloc).
|
||||
// -E_INVAL if srcva < UTOP but srcva is not mapped in the caller's
|
||||
// address space.
|
||||
// -E_INVAL if (perm & PTE_W), but srcva is read-only in the
|
||||
// current environment's address space.
|
||||
// -E_NO_MEM if there's not enough memory to map srcva in envid's
|
||||
// address space.
|
||||
static int
|
||||
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_ipc_try_send not implemented");
|
||||
}
|
||||
|
||||
// Block until a value is ready. Record that you want to receive
|
||||
// using the env_ipc_recving and env_ipc_dstva fields of struct Env,
|
||||
// mark yourself not runnable, and then give up the CPU.
|
||||
//
|
||||
// If 'dstva' is < UTOP, then you are willing to receive a page of data.
|
||||
// 'dstva' is the virtual address at which the sent page should be mapped.
|
||||
//
|
||||
// This function only returns on error, but the system call will eventually
|
||||
// return 0 on success.
|
||||
// Return < 0 on error. Errors are:
|
||||
// -E_INVAL if dstva < UTOP but dstva is not page-aligned.
|
||||
static int
|
||||
sys_ipc_recv(void *dstva)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_ipc_recv not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Dispatches to the correct kernel function, passing the arguments.
|
||||
int32_t
|
||||
syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
|
||||
{
|
||||
// Call the function corresponding to the 'syscallno' parameter.
|
||||
// Return any appropriate return value.
|
||||
// LAB 3: Your code here.
|
||||
switch (syscallno) {
|
||||
case SYS_cputs:
|
||||
sys_cputs((const char*)a1, a2);
|
||||
break;
|
||||
case SYS_cgetc:
|
||||
return sys_cgetc();
|
||||
case SYS_getenvid:
|
||||
return sys_getenvid();
|
||||
case SYS_env_destroy:
|
||||
return sys_env_destroy(a1);
|
||||
case SYS_yield:
|
||||
sys_yield();
|
||||
break;
|
||||
case SYS_page_alloc:
|
||||
return sys_page_alloc((envid_t)a1, (void * )a2, (int )a3);
|
||||
case SYS_env_set_pgfault_upcall:
|
||||
return sys_env_set_pgfault_upcall((envid_t) a1, (void *) a2);
|
||||
case SYS_page_map:
|
||||
return sys_page_map((envid_t) a1, (void *) a2, (envid_t) a3, (void *) a4, (int) a5);
|
||||
|
||||
case SYS_page_unmap:
|
||||
return sys_page_unmap((envid_t) a1, (void *) a2);
|
||||
|
||||
case SYS_exofork:
|
||||
return sys_exofork();
|
||||
|
||||
case SYS_env_set_status:
|
||||
return sys_env_set_status((envid_t) a1, (int) a2);
|
||||
case NSYSCALLS:
|
||||
return -E_INVAL;
|
||||
|
||||
default:
|
||||
return -E_INVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
301
lab/LAB4.si4project/Backup/syscall(2799).c
Normal file
301
lab/LAB4.si4project/Backup/syscall(2799).c
Normal file
@@ -0,0 +1,301 @@
|
||||
/* See COPYRIGHT for copyright information. */
|
||||
|
||||
#include <inc/x86.h>
|
||||
#include <inc/error.h>
|
||||
#include <inc/string.h>
|
||||
#include <inc/assert.h>
|
||||
|
||||
#include <kern/env.h>
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/trap.h>
|
||||
#include <kern/syscall.h>
|
||||
#include <kern/console.h>
|
||||
#include <kern/sched.h>
|
||||
|
||||
// Print a string to the system console.
|
||||
// The string is exactly 'len' characters long.
|
||||
// Destroys the environment on memory errors.
|
||||
static void
|
||||
sys_cputs(const char *s, size_t len)
|
||||
{
|
||||
// Check that the user has permission to read memory [s, s+len).
|
||||
// Destroy the environment if not.
|
||||
|
||||
// LAB 3: Your code here.
|
||||
user_mem_assert(curenv, (const void *) s, len, 0);
|
||||
// Print the string supplied by the user.
|
||||
cprintf("%.*s", len, s);
|
||||
}
|
||||
|
||||
// Read a character from the system console without blocking.
|
||||
// Returns the character, or 0 if there is no input waiting.
|
||||
static int
|
||||
sys_cgetc(void)
|
||||
{
|
||||
return cons_getc();
|
||||
}
|
||||
|
||||
// Returns the current environment's envid.
|
||||
static envid_t
|
||||
sys_getenvid(void)
|
||||
{
|
||||
return curenv->env_id;
|
||||
}
|
||||
|
||||
// Destroy a given environment (possibly the currently running environment).
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
static int
|
||||
sys_env_destroy(envid_t envid)
|
||||
{
|
||||
int r;
|
||||
struct Env *e;
|
||||
|
||||
if ((r = envid2env(envid, &e, 1)) < 0)
|
||||
return r;
|
||||
if (e == curenv)
|
||||
cprintf("[%08x] exiting gracefully\n", curenv->env_id);
|
||||
else
|
||||
cprintf("[%08x] destroying %08x\n", curenv->env_id, e->env_id);
|
||||
env_destroy(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Deschedule current environment and pick a different one to run.
|
||||
static void
|
||||
sys_yield(void)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
// Allocate a new environment.
|
||||
// Returns envid of new environment, or < 0 on error. Errors are:
|
||||
// -E_NO_FREE_ENV if no free environment is available.
|
||||
// -E_NO_MEM on memory exhaustion.
|
||||
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.
|
||||
panic("sys_exofork not implemented");
|
||||
}
|
||||
|
||||
// Set envid's env_status to status, which must be ENV_RUNNABLE
|
||||
// or ENV_NOT_RUNNABLE.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if status is not a valid status for an environment.
|
||||
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.
|
||||
panic("sys_env_set_status not implemented");
|
||||
}
|
||||
|
||||
// Set the page fault upcall for 'envid' by modifying the corresponding struct
|
||||
// Env's 'env_pgfault_upcall' field. When 'envid' causes a page fault, the
|
||||
// kernel will push a fault record onto the exception stack, then branch to
|
||||
// 'func'.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
static int
|
||||
sys_env_set_pgfault_upcall(envid_t envid, void *func)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_env_set_pgfault_upcall not implemented");
|
||||
}
|
||||
|
||||
// Allocate a page of memory and map it at 'va' with permission
|
||||
// 'perm' in the address space of 'envid'.
|
||||
// The page's contents are set to 0.
|
||||
// If a page is already mapped at 'va', that page is unmapped as a
|
||||
// side effect.
|
||||
//
|
||||
// perm -- PTE_U | PTE_P must be set, PTE_AVAIL | PTE_W may or may not be set,
|
||||
// but no other bits may be set. See PTE_SYSCALL in inc/mmu.h.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if va >= UTOP, or va is not page-aligned.
|
||||
// -E_INVAL if perm is inappropriate (see above).
|
||||
// -E_NO_MEM if there's no memory to allocate the new page,
|
||||
// or to allocate any necessary page tables.
|
||||
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.
|
||||
panic("sys_page_alloc not implemented");
|
||||
}
|
||||
|
||||
// Map the page of memory at 'srcva' in srcenvid's address space
|
||||
// at 'dstva' in dstenvid's address space with permission 'perm'.
|
||||
// Perm has the same restrictions as in sys_page_alloc, except
|
||||
// that it also must not grant write access to a read-only
|
||||
// page.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change one of them.
|
||||
// -E_INVAL if srcva >= UTOP or srcva is not page-aligned,
|
||||
// or dstva >= UTOP or dstva is not page-aligned.
|
||||
// -E_INVAL is srcva is not mapped in srcenvid's address space.
|
||||
// -E_INVAL if perm is inappropriate (see sys_page_alloc).
|
||||
// -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's
|
||||
// address space.
|
||||
// -E_NO_MEM if there's no memory to allocate any necessary page tables.
|
||||
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.
|
||||
panic("sys_page_map not implemented");
|
||||
}
|
||||
|
||||
// Unmap the page of memory at 'va' in the address space of 'envid'.
|
||||
// If no page is mapped, the function silently succeeds.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if va >= UTOP, or va is not page-aligned.
|
||||
static int
|
||||
sys_page_unmap(envid_t envid, void *va)
|
||||
{
|
||||
// Hint: This function is a wrapper around page_remove().
|
||||
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_page_unmap not implemented");
|
||||
}
|
||||
|
||||
// Try to send 'value' to the target env 'envid'.
|
||||
// If srcva < UTOP, then also send page currently mapped at 'srcva',
|
||||
// so that receiver gets a duplicate mapping of the same page.
|
||||
//
|
||||
// The send fails with a return value of -E_IPC_NOT_RECV if the
|
||||
// target is not blocked, waiting for an IPC.
|
||||
//
|
||||
// The send also can fail for the other reasons listed below.
|
||||
//
|
||||
// Otherwise, the send succeeds, and the target's ipc fields are
|
||||
// updated as follows:
|
||||
// env_ipc_recving is set to 0 to block future sends;
|
||||
// env_ipc_from is set to the sending envid;
|
||||
// env_ipc_value is set to the 'value' parameter;
|
||||
// env_ipc_perm is set to 'perm' if a page was transferred, 0 otherwise.
|
||||
// The target environment is marked runnable again, returning 0
|
||||
// from the paused sys_ipc_recv system call. (Hint: does the
|
||||
// sys_ipc_recv function ever actually return?)
|
||||
//
|
||||
// If the sender wants to send a page but the receiver isn't asking for one,
|
||||
// then no page mapping is transferred, but no error occurs.
|
||||
// The ipc only happens when no errors occur.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error.
|
||||
// Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist.
|
||||
// (No need to check permissions.)
|
||||
// -E_IPC_NOT_RECV if envid is not currently blocked in sys_ipc_recv,
|
||||
// or another environment managed to send first.
|
||||
// -E_INVAL if srcva < UTOP but srcva is not page-aligned.
|
||||
// -E_INVAL if srcva < UTOP and perm is inappropriate
|
||||
// (see sys_page_alloc).
|
||||
// -E_INVAL if srcva < UTOP but srcva is not mapped in the caller's
|
||||
// address space.
|
||||
// -E_INVAL if (perm & PTE_W), but srcva is read-only in the
|
||||
// current environment's address space.
|
||||
// -E_NO_MEM if there's not enough memory to map srcva in envid's
|
||||
// address space.
|
||||
static int
|
||||
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_ipc_try_send not implemented");
|
||||
}
|
||||
|
||||
// Block until a value is ready. Record that you want to receive
|
||||
// using the env_ipc_recving and env_ipc_dstva fields of struct Env,
|
||||
// mark yourself not runnable, and then give up the CPU.
|
||||
//
|
||||
// If 'dstva' is < UTOP, then you are willing to receive a page of data.
|
||||
// 'dstva' is the virtual address at which the sent page should be mapped.
|
||||
//
|
||||
// This function only returns on error, but the system call will eventually
|
||||
// return 0 on success.
|
||||
// Return < 0 on error. Errors are:
|
||||
// -E_INVAL if dstva < UTOP but dstva is not page-aligned.
|
||||
static int
|
||||
sys_ipc_recv(void *dstva)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_ipc_recv not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Dispatches to the correct kernel function, passing the arguments.
|
||||
int32_t
|
||||
syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
|
||||
{
|
||||
// Call the function corresponding to the 'syscallno' parameter.
|
||||
// Return any appropriate return value.
|
||||
// LAB 3: Your code here.
|
||||
|
||||
|
||||
// panic("syscall not implemented");
|
||||
|
||||
int ret = 0;
|
||||
switch (syscallno) {
|
||||
case SYS_cputs:
|
||||
sys_cputs((const char*)a1, a2);
|
||||
break;
|
||||
case SYS_cgetc:
|
||||
ret = sys_cgetc();
|
||||
|
||||
break;
|
||||
case SYS_getenvid:
|
||||
ret = sys_getenvid();
|
||||
break;
|
||||
case SYS_env_destroy:
|
||||
sys_env_destroy(a1);
|
||||
break;
|
||||
case NSYSCALLS:
|
||||
return -E_INVAL;
|
||||
|
||||
default:
|
||||
return -E_INVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
22
lab/LAB4.si4project/Backup/syscall(5045).h
Normal file
22
lab/LAB4.si4project/Backup/syscall(5045).h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef JOS_INC_SYSCALL_H
|
||||
#define JOS_INC_SYSCALL_H
|
||||
|
||||
/* system call numbers */
|
||||
enum {
|
||||
SYS_cputs = 0,
|
||||
SYS_cgetc,
|
||||
SYS_getenvid,
|
||||
SYS_env_destroy,
|
||||
SYS_page_alloc,
|
||||
SYS_page_map,
|
||||
SYS_page_unmap,
|
||||
SYS_exofork,
|
||||
SYS_env_set_status,
|
||||
SYS_env_set_pgfault_upcall,
|
||||
SYS_yield,
|
||||
SYS_ipc_try_send,
|
||||
SYS_ipc_recv,
|
||||
NSYSCALLS
|
||||
};
|
||||
|
||||
#endif /* !JOS_INC_SYSCALL_H */
|
||||
384
lab/LAB4.si4project/Backup/syscall(7459).c
Normal file
384
lab/LAB4.si4project/Backup/syscall(7459).c
Normal file
@@ -0,0 +1,384 @@
|
||||
/* See COPYRIGHT for copyright information. */
|
||||
|
||||
#include <inc/x86.h>
|
||||
#include <inc/error.h>
|
||||
#include <inc/string.h>
|
||||
#include <inc/assert.h>
|
||||
|
||||
#include <kern/env.h>
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/trap.h>
|
||||
#include <kern/syscall.h>
|
||||
#include <kern/console.h>
|
||||
#include <kern/sched.h>
|
||||
|
||||
// Print a string to the system console.
|
||||
// The string is exactly 'len' characters long.
|
||||
// Destroys the environment on memory errors.
|
||||
static void
|
||||
sys_cputs(const char *s, size_t len)
|
||||
{
|
||||
// Check that the user has permission to read memory [s, s+len).
|
||||
// Destroy the environment if not.
|
||||
|
||||
// LAB 3: Your code here.
|
||||
user_mem_assert(curenv, (const void *) s, len, 0);
|
||||
// Print the string supplied by the user.
|
||||
cprintf("%.*s", len, s);
|
||||
}
|
||||
|
||||
// Read a character from the system console without blocking.
|
||||
// Returns the character, or 0 if there is no input waiting.
|
||||
static int
|
||||
sys_cgetc(void)
|
||||
{
|
||||
return cons_getc();
|
||||
}
|
||||
|
||||
// Returns the current environment's envid.
|
||||
static envid_t
|
||||
sys_getenvid(void)
|
||||
{
|
||||
return curenv->env_id;
|
||||
}
|
||||
|
||||
// Destroy a given environment (possibly the currently running environment).
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
static int
|
||||
sys_env_destroy(envid_t envid)
|
||||
{
|
||||
int r;
|
||||
struct Env *e;
|
||||
|
||||
if ((r = envid2env(envid, &e, 1)) < 0)
|
||||
return r;
|
||||
if (e == curenv)
|
||||
cprintf("[%08x] exiting gracefully\n", curenv->env_id);
|
||||
else
|
||||
cprintf("[%08x] destroying %08x\n", curenv->env_id, e->env_id);
|
||||
env_destroy(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Deschedule current environment and pick a different one to run.
|
||||
static void
|
||||
sys_yield(void)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
|
||||
// Allocate a new environment.
|
||||
// Returns envid of new environment, or < 0 on error. Errors are:
|
||||
// -E_NO_FREE_ENV if no free environment is available.
|
||||
// -E_NO_MEM on memory exhaustion.
|
||||
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;
|
||||
int32_t ret;
|
||||
if ((ret = env_alloc(&newenv, sys_getenvid())) < 0) {
|
||||
// 两个函数的返回值是一样的
|
||||
return ret;
|
||||
}
|
||||
newenv->env_status = ENV_NOT_RUNNABLE;
|
||||
newenv->env_tf = curenv->env_tf;
|
||||
// newenv的返回值为0, 实现子进程返回0值
|
||||
newenv->env_tf.tf_regs.reg_eax = 0;
|
||||
|
||||
// 返回值存放在eax中
|
||||
return newenv->env_id;
|
||||
|
||||
// panic("sys_exofork not implemented");
|
||||
}
|
||||
|
||||
// Set envid's env_status to status, which must be ENV_RUNNABLE
|
||||
// or ENV_NOT_RUNNABLE.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if status is not a valid status for an environment.
|
||||
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 *e;
|
||||
if (envid2env(envid, &e, 1)) return -E_BAD_ENV;
|
||||
|
||||
if (status != ENV_NOT_RUNNABLE && status != ENV_RUNNABLE)
|
||||
return -E_INVAL;
|
||||
|
||||
e->env_status = status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Set the page fault upcall for 'envid' by modifying the corresponding struct
|
||||
// Env's 'env_pgfault_upcall' field. When 'envid' causes a page fault, the
|
||||
// kernel will push a fault record onto the exception stack, then branch to
|
||||
// 'func'.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
static int
|
||||
sys_env_set_pgfault_upcall(envid_t envid, void *func)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
struct Env *e;
|
||||
if (envid2env(envid, &e, 1))
|
||||
return -E_BAD_ENV;
|
||||
// cprintf("set pgfault upcall\n");
|
||||
e->env_pgfault_upcall = func;
|
||||
return 0;
|
||||
// panic("sys_env_set_pgfault_upcall not implemented");
|
||||
}
|
||||
|
||||
// Allocate a page of memory and map it at 'va' with permission
|
||||
// 'perm' in the address space of 'envid'.
|
||||
// The page's contents are set to 0.
|
||||
// If a page is already mapped at 'va', that page is unmapped as a
|
||||
// side effect.
|
||||
//
|
||||
// perm -- PTE_U | PTE_P must be set, PTE_AVAIL | PTE_W may or may not be set,
|
||||
// but no other bits may be set. See PTE_SYSCALL in inc/mmu.h.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if va >= UTOP, or va is not page-aligned.
|
||||
// -E_INVAL if perm is inappropriate (see above).
|
||||
// -E_NO_MEM if there's no memory to allocate the new page,
|
||||
// or to allocate any necessary page tables.
|
||||
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.
|
||||
int ret = 0;
|
||||
struct Env *env;
|
||||
|
||||
if ((ret = envid2env(envid, &env, 1)) < 0)
|
||||
return -E_BAD_ENV;
|
||||
|
||||
if((uintptr_t)va >= UTOP || PGOFF(va))
|
||||
return -E_INVAL;
|
||||
if ((perm & PTE_U) == 0 || (perm & PTE_P) == 0)
|
||||
return -E_INVAL;
|
||||
if (perm & ~PTE_SYSCALL)
|
||||
return -E_INVAL;
|
||||
|
||||
struct PageInfo *pp = page_alloc(ALLOC_ZERO);
|
||||
if(!pp)
|
||||
return -E_NO_MEM;
|
||||
|
||||
if (page_insert(env->env_pgdir, pp, va, perm) < 0)
|
||||
return -E_NO_MEM;
|
||||
|
||||
return 0;
|
||||
// panic("sys_page_alloc not implemented");
|
||||
}
|
||||
|
||||
// Map the page of memory at 'srcva' in srcenvid's address space
|
||||
// at 'dstva' in dstenvid's address space with permission 'perm'.
|
||||
// Perm has the same restrictions as in sys_page_alloc, except
|
||||
// that it also must not grant write access to a read-only
|
||||
// page.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change one of them.
|
||||
// -E_INVAL if srcva >= UTOP or srcva is not page-aligned,
|
||||
// or dstva >= UTOP or dstva is not page-aligned.
|
||||
// -E_INVAL is srcva is not mapped in srcenvid's address space.
|
||||
// -E_INVAL if perm is inappropriate (see sys_page_alloc).
|
||||
// -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's
|
||||
// address space.
|
||||
// -E_NO_MEM if there's no memory to allocate any necessary page tables.
|
||||
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.
|
||||
int ret = 0;
|
||||
struct Env *srcenv, *dstenv;
|
||||
struct PageInfo *srcpp, *dstpp;
|
||||
pte_t *pte;
|
||||
if ((envid2env(srcenvid, &srcenv, 1) < 0 )|| ( envid2env(dstenvid, &dstenv, 1) < 0))
|
||||
return -E_BAD_ENV;
|
||||
if ((uintptr_t)srcva >= UTOP || PGOFF(srcva) || (uintptr_t)dstva >= UTOP || PGOFF(dstva))
|
||||
return -E_INVAL;
|
||||
if ( (perm & PTE_U) == 0 || (perm & PTE_P) == 0 || (perm & ~PTE_SYSCALL))
|
||||
return -E_INVAL;
|
||||
if (!(srcpp = page_lookup(srcenv->env_pgdir, srcva, &pte)))
|
||||
return -E_INVAL;
|
||||
if ((perm & PTE_W) && ((*pte & PTE_W) == 0))
|
||||
return -E_INVAL;
|
||||
if (page_insert(dstenv->env_pgdir, srcpp, dstva, perm) < 0)
|
||||
return -E_NO_MEM;
|
||||
|
||||
return 0;
|
||||
// panic("sys_page_map not implemented");
|
||||
}
|
||||
|
||||
// Unmap the page of memory at 'va' in the address space of 'envid'.
|
||||
// If no page is mapped, the function silently succeeds.
|
||||
//
|
||||
// Return 0 on success, < 0 on error. Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist,
|
||||
// or the caller doesn't have permission to change envid.
|
||||
// -E_INVAL if va >= UTOP, or va is not page-aligned.
|
||||
static int
|
||||
sys_page_unmap(envid_t envid, void *va)
|
||||
{
|
||||
// Hint: This function is a wrapper around page_remove().
|
||||
|
||||
// LAB 4: Your code here.
|
||||
int ret = 0;
|
||||
struct Env *env;
|
||||
|
||||
if ((ret = envid2env(envid, &env, 1)) < 0)
|
||||
return -E_BAD_ENV;
|
||||
if ((uintptr_t)va >= UTOP || PGOFF(va))
|
||||
return -E_INVAL;
|
||||
page_remove(env->env_pgdir, va);
|
||||
return 0;
|
||||
// panic("sys_page_unmap not implemented");
|
||||
}
|
||||
|
||||
// Try to send 'value' to the target env 'envid'.
|
||||
// If srcva < UTOP, then also send page currently mapped at 'srcva',
|
||||
// so that receiver gets a duplicate mapping of the same page.
|
||||
//
|
||||
// The send fails with a return value of -E_IPC_NOT_RECV if the
|
||||
// target is not blocked, waiting for an IPC.
|
||||
//
|
||||
// The send also can fail for the other reasons listed below.
|
||||
//
|
||||
// Otherwise, the send succeeds, and the target's ipc fields are
|
||||
// updated as follows:
|
||||
// env_ipc_recving is set to 0 to block future sends;
|
||||
// env_ipc_from is set to the sending envid;
|
||||
// env_ipc_value is set to the 'value' parameter;
|
||||
// env_ipc_perm is set to 'perm' if a page was transferred, 0 otherwise.
|
||||
// The target environment is marked runnable again, returning 0
|
||||
// from the paused sys_ipc_recv system call. (Hint: does the
|
||||
// sys_ipc_recv function ever actually return?)
|
||||
//
|
||||
// If the sender wants to send a page but the receiver isn't asking for one,
|
||||
// then no page mapping is transferred, but no error occurs.
|
||||
// The ipc only happens when no errors occur.
|
||||
//
|
||||
// Returns 0 on success, < 0 on error.
|
||||
// Errors are:
|
||||
// -E_BAD_ENV if environment envid doesn't currently exist.
|
||||
// (No need to check permissions.)
|
||||
// -E_IPC_NOT_RECV if envid is not currently blocked in sys_ipc_recv,
|
||||
// or another environment managed to send first.
|
||||
// -E_INVAL if srcva < UTOP but srcva is not page-aligned.
|
||||
// -E_INVAL if srcva < UTOP and perm is inappropriate
|
||||
// (see sys_page_alloc).
|
||||
// -E_INVAL if srcva < UTOP but srcva is not mapped in the caller's
|
||||
// address space.
|
||||
// -E_INVAL if (perm & PTE_W), but srcva is read-only in the
|
||||
// current environment's address space.
|
||||
// -E_NO_MEM if there's not enough memory to map srcva in envid's
|
||||
// address space.
|
||||
static int
|
||||
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_ipc_try_send not implemented");
|
||||
}
|
||||
|
||||
// Block until a value is ready. Record that you want to receive
|
||||
// using the env_ipc_recving and env_ipc_dstva fields of struct Env,
|
||||
// mark yourself not runnable, and then give up the CPU.
|
||||
//
|
||||
// If 'dstva' is < UTOP, then you are willing to receive a page of data.
|
||||
// 'dstva' is the virtual address at which the sent page should be mapped.
|
||||
//
|
||||
// This function only returns on error, but the system call will eventually
|
||||
// return 0 on success.
|
||||
// Return < 0 on error. Errors are:
|
||||
// -E_INVAL if dstva < UTOP but dstva is not page-aligned.
|
||||
static int
|
||||
sys_ipc_recv(void *dstva)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_ipc_recv not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Dispatches to the correct kernel function, passing the arguments.
|
||||
int32_t
|
||||
syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
|
||||
{
|
||||
// Call the function corresponding to the 'syscallno' parameter.
|
||||
// Return any appropriate return value.
|
||||
// LAB 3: Your code here.
|
||||
switch (syscallno) {
|
||||
case SYS_cputs:
|
||||
sys_cputs((const char*)a1, a2);
|
||||
break;
|
||||
case SYS_cgetc:
|
||||
return sys_cgetc();
|
||||
case SYS_getenvid:
|
||||
return sys_getenvid();
|
||||
case SYS_env_destroy:
|
||||
return sys_env_destroy(a1);
|
||||
case SYS_yield:
|
||||
sys_yield();
|
||||
break;
|
||||
case SYS_page_alloc:
|
||||
return sys_page_alloc((envid_t)a1, (void * )a2, (int )a3);
|
||||
case SYS_env_set_pgfault_upcall:
|
||||
return sys_env_set_pgfault_upcall((envid_t) a1, (void *) a2);
|
||||
case SYS_page_map:
|
||||
return sys_page_map((envid_t) a1, (void *) a2, (envid_t) a3, (void *) a4, (int) a5);
|
||||
|
||||
case SYS_page_unmap:
|
||||
return sys_page_unmap((envid_t) a1, (void *) a2);
|
||||
|
||||
case SYS_exofork:
|
||||
return sys_exofork();
|
||||
|
||||
case SYS_env_set_status:
|
||||
return sys_env_set_status((envid_t) a1, (int) a2);
|
||||
case NSYSCALLS:
|
||||
return -E_INVAL;
|
||||
|
||||
default:
|
||||
return -E_INVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
402
lab/LAB4.si4project/Backup/trap(1475).c
Normal file
402
lab/LAB4.si4project/Backup/trap(1475).c
Normal file
@@ -0,0 +1,402 @@
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/x86.h>
|
||||
#include <inc/assert.h>
|
||||
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/trap.h>
|
||||
#include <kern/console.h>
|
||||
#include <kern/monitor.h>
|
||||
#include <kern/env.h>
|
||||
#include <kern/syscall.h>
|
||||
#include <kern/sched.h>
|
||||
#include <kern/kclock.h>
|
||||
#include <kern/picirq.h>
|
||||
#include <kern/cpu.h>
|
||||
#include <kern/spinlock.h>
|
||||
|
||||
static struct Taskstate ts;
|
||||
|
||||
/* For debugging, so print_trapframe can distinguish between printing
|
||||
* a saved trapframe and printing the current trapframe and print some
|
||||
* additional information in the latter case.
|
||||
*/
|
||||
static struct Trapframe *last_tf;
|
||||
|
||||
/* Interrupt descriptor table. (Must be built at run time because
|
||||
* shifted function addresses can't be represented in relocation records.)
|
||||
*/
|
||||
struct Gatedesc idt[256] = { { 0 } };
|
||||
struct Pseudodesc idt_pd = {
|
||||
sizeof(idt) - 1, (uint32_t) idt
|
||||
};
|
||||
|
||||
|
||||
static const char *trapname(int trapno)
|
||||
{
|
||||
static const char * const excnames[] = {
|
||||
"Divide error",
|
||||
"Debug",
|
||||
"Non-Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Overflow",
|
||||
"BOUND Range Exceeded",
|
||||
"Invalid Opcode",
|
||||
"Device Not Available",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Invalid TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection",
|
||||
"Page Fault",
|
||||
"(unknown trap)",
|
||||
"x87 FPU Floating-Point Error",
|
||||
"Alignment Check",
|
||||
"Machine-Check",
|
||||
"SIMD Floating-Point Exception"
|
||||
};
|
||||
|
||||
if (trapno < ARRAY_SIZE(excnames))
|
||||
return excnames[trapno];
|
||||
if (trapno == T_SYSCALL)
|
||||
return "System call";
|
||||
if (trapno >= IRQ_OFFSET && trapno < IRQ_OFFSET + 16)
|
||||
return "Hardware Interrupt";
|
||||
return "(unknown trap)";
|
||||
}
|
||||
|
||||
// You will also need to modify trap_init() to initialize the idt to
|
||||
// point to each of these entry points defined in trapentry.S;
|
||||
// the SETGATE macro will be helpful here
|
||||
void
|
||||
trap_init(void)
|
||||
{
|
||||
|
||||
extern struct Segdesc gdt[];
|
||||
void divide_handler();
|
||||
void debug_handler();
|
||||
void nmi_handler();
|
||||
void brkpt_handler();
|
||||
void oflow_handler();
|
||||
void bound_handler();
|
||||
void device_handler();
|
||||
void illop_handler();
|
||||
void tss_handler();
|
||||
void segnp_handler();
|
||||
void stack_handler();
|
||||
void gpflt_handler();
|
||||
void pgflt_handler();
|
||||
void fperr_handler();
|
||||
void align_handler();
|
||||
void mchk_handler();
|
||||
void simderr_handler();
|
||||
void syscall_handler();
|
||||
void dblflt_handler();
|
||||
|
||||
// LAB 3: Your code here.
|
||||
// GD_KT 全局描述符, kernel text
|
||||
SETGATE(idt[T_DIVIDE], 0, GD_KT, divide_handler, 0);
|
||||
SETGATE(idt[T_DEBUG], 0, GD_KT, debug_handler, 0);
|
||||
SETGATE(idt[T_NMI], 0, GD_KT, nmi_handler, 0);
|
||||
SETGATE(idt[T_BRKPT], 0, GD_KT, brkpt_handler, 3);
|
||||
SETGATE(idt[T_OFLOW], 0, GD_KT, oflow_handler, 0);
|
||||
SETGATE(idt[T_BOUND], 0, GD_KT, bound_handler, 0);
|
||||
SETGATE(idt[T_DEVICE], 0, GD_KT, device_handler, 0);
|
||||
SETGATE(idt[T_ILLOP], 0, GD_KT, illop_handler, 0);
|
||||
SETGATE(idt[T_DBLFLT], 0, GD_KT, dblflt_handler, 0);
|
||||
SETGATE(idt[T_TSS], 0, GD_KT, tss_handler, 0);
|
||||
SETGATE(idt[T_SEGNP], 0, GD_KT, segnp_handler, 0);
|
||||
SETGATE(idt[T_STACK], 0, GD_KT, stack_handler, 0);
|
||||
SETGATE(idt[T_GPFLT], 0, GD_KT, gpflt_handler, 0);
|
||||
SETGATE(idt[T_PGFLT], 0, GD_KT, pgflt_handler, 0);
|
||||
SETGATE(idt[T_FPERR], 0, GD_KT, fperr_handler, 0);
|
||||
SETGATE(idt[T_ALIGN], 0, GD_KT, align_handler, 0);
|
||||
SETGATE(idt[T_MCHK], 0, GD_KT, mchk_handler, 0);
|
||||
SETGATE(idt[T_SIMDERR], 0, GD_KT, simderr_handler, 0);
|
||||
SETGATE(idt[T_SYSCALL], 0, GD_KT, syscall_handler, 3);
|
||||
|
||||
// Per-CPU setup
|
||||
trap_init_percpu();
|
||||
}
|
||||
|
||||
// Initialize and load the per-CPU TSS and IDT
|
||||
void
|
||||
trap_init_percpu(void)
|
||||
{
|
||||
// The example code here sets up the Task State Segment (TSS) and
|
||||
// the TSS descriptor for CPU 0. But it is incorrect if we are
|
||||
// running on other CPUs because each CPU has its own kernel stack.
|
||||
// Fix the code so that it works for all CPUs.
|
||||
//
|
||||
// Hints:
|
||||
// - The macro "thiscpu" always refers to the current CPU's
|
||||
// struct CpuInfo;
|
||||
// - The ID of the current CPU is given by cpunum() or
|
||||
// thiscpu->cpu_id;
|
||||
// - Use "thiscpu->cpu_ts" as the TSS for the current CPU,
|
||||
// rather than the global "ts" variable;
|
||||
// - Use gdt[(GD_TSS0 >> 3) + i] for CPU i's TSS descriptor;
|
||||
// - You mapped the per-CPU kernel stacks in mem_init_mp()
|
||||
// - Initialize cpu_ts.ts_iomb to prevent unauthorized environments
|
||||
// from doing IO (0 is not the correct value!)
|
||||
//
|
||||
// ltr sets a 'busy' flag in the TSS selector, so if you
|
||||
// accidentally load the same TSS on more than one CPU, you'll
|
||||
// get a triple fault. If you set up an individual CPU's TSS
|
||||
// wrong, you may not get a fault until you try to return from
|
||||
// user space on that CPU.
|
||||
//
|
||||
// LAB 4: Your code here:
|
||||
thiscpu->cpu_ts.ts_esp0 = KSTACKTOP - cpunum() * (KSTKGAP + KSTKSIZE);
|
||||
thiscpu->cpu_ts.ts_ss0 = GD_KD;
|
||||
|
||||
// Initialize the TSS slot of the gdt.
|
||||
gdt[(GD_TSS0 >> 3) + cpunum()] = SEG16(STS_T32A, (uint32_t) (&thiscpu->cpu_ts), sizeof(struct Taskstate) - 1, 0);
|
||||
gdt[(GD_TSS0 >> 3) + cpunum()].sd_s = 0;
|
||||
|
||||
// Load the TSS selector (like other segment selectors, the
|
||||
// bottom three bits are special; we leave them 0)
|
||||
ltr(GD_TSS0 + sizeof(struct Segdesc) * cpunum());
|
||||
|
||||
// Load the IDT
|
||||
lidt(&idt_pd);
|
||||
}
|
||||
|
||||
void
|
||||
print_trapframe(struct Trapframe *tf)
|
||||
{
|
||||
cprintf("TRAP frame at %p from CPU %d\n", tf, cpunum());
|
||||
print_regs(&tf->tf_regs);
|
||||
cprintf(" es 0x----%04x\n", tf->tf_es);
|
||||
cprintf(" ds 0x----%04x\n", tf->tf_ds);
|
||||
cprintf(" trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
|
||||
// If this trap was a page fault that just happened
|
||||
// (so %cr2 is meaningful), print the faulting linear address.
|
||||
if (tf == last_tf && tf->tf_trapno == T_PGFLT)
|
||||
cprintf(" cr2 0x%08x\n", rcr2());
|
||||
cprintf(" err 0x%08x", tf->tf_err);
|
||||
// For page faults, print decoded fault error code:
|
||||
// U/K=fault occurred in user/kernel mode
|
||||
// W/R=a write/read caused the fault
|
||||
// PR=a protection violation caused the fault (NP=page not present).
|
||||
if (tf->tf_trapno == T_PGFLT)
|
||||
cprintf(" [%s, %s, %s]\n",
|
||||
tf->tf_err & 4 ? "user" : "kernel",
|
||||
tf->tf_err & 2 ? "write" : "read",
|
||||
tf->tf_err & 1 ? "protection" : "not-present");
|
||||
else
|
||||
cprintf("\n");
|
||||
cprintf(" eip 0x%08x\n", tf->tf_eip);
|
||||
cprintf(" cs 0x----%04x\n", tf->tf_cs);
|
||||
cprintf(" flag 0x%08x\n", tf->tf_eflags);
|
||||
if ((tf->tf_cs & 3) != 0) {
|
||||
cprintf(" esp 0x%08x\n", tf->tf_esp);
|
||||
cprintf(" ss 0x----%04x\n", tf->tf_ss);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_regs(struct PushRegs *regs)
|
||||
{
|
||||
cprintf(" edi 0x%08x\n", regs->reg_edi);
|
||||
cprintf(" esi 0x%08x\n", regs->reg_esi);
|
||||
cprintf(" ebp 0x%08x\n", regs->reg_ebp);
|
||||
cprintf(" oesp 0x%08x\n", regs->reg_oesp);
|
||||
cprintf(" ebx 0x%08x\n", regs->reg_ebx);
|
||||
cprintf(" edx 0x%08x\n", regs->reg_edx);
|
||||
cprintf(" ecx 0x%08x\n", regs->reg_ecx);
|
||||
cprintf(" eax 0x%08x\n", regs->reg_eax);
|
||||
}
|
||||
|
||||
static void
|
||||
trap_dispatch(struct Trapframe *tf)
|
||||
{
|
||||
// Handle processor exceptions.
|
||||
// LAB 3: Your code here.
|
||||
switch(tf->tf_trapno) {
|
||||
case T_PGFLT:
|
||||
page_fault_handler(tf);
|
||||
break;
|
||||
case T_BRKPT:
|
||||
monitor(tf);
|
||||
break;
|
||||
case T_SYSCALL:
|
||||
|
||||
tf->tf_regs.reg_eax = syscall(tf->tf_regs.reg_eax,
|
||||
tf->tf_regs.reg_edx,
|
||||
tf->tf_regs.reg_ecx,
|
||||
tf->tf_regs.reg_ebx,
|
||||
tf->tf_regs.reg_edi,
|
||||
tf->tf_regs.reg_esi);
|
||||
break;
|
||||
default:
|
||||
// Unexpected trap: The user process or the kernel has a bug.
|
||||
print_trapframe(tf);
|
||||
if (tf->tf_cs == GD_KT)
|
||||
panic("unhandled trap in kernel");
|
||||
else {
|
||||
env_destroy(curenv);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Handle clock interrupts. Don't forget to acknowledge the
|
||||
// interrupt using lapic_eoi() before calling the scheduler!
|
||||
// LAB 4: Your code here.
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
trap(struct Trapframe *tf)
|
||||
{
|
||||
// The environment may have set DF and some versions
|
||||
// of GCC rely on DF being clear
|
||||
asm volatile("cld" ::: "cc");
|
||||
|
||||
// Halt the CPU if some other CPU has called panic()
|
||||
extern char *panicstr;
|
||||
if (panicstr)
|
||||
asm volatile("hlt");
|
||||
|
||||
// Re-acqurie the big kernel lock if we were halted in
|
||||
// sched_yield()
|
||||
if (xchg(&thiscpu->cpu_status, CPU_STARTED) == CPU_HALTED)
|
||||
lock_kernel();
|
||||
// Check that interrupts are disabled. If this assertion
|
||||
// fails, DO NOT be tempted to fix it by inserting a "cli" in
|
||||
// the interrupt path.
|
||||
assert(!(read_eflags() & FL_IF));
|
||||
|
||||
if ((tf->tf_cs & 3) == 3) {
|
||||
// Trapped from user mode.
|
||||
// Acquire the big kernel lock before doing any
|
||||
// serious kernel work.
|
||||
// LAB 4: Your code here.
|
||||
lock_kernel();
|
||||
assert(curenv);
|
||||
|
||||
// Garbage collect if current enviroment is a zombie
|
||||
if (curenv->env_status == ENV_DYING) {
|
||||
env_free(curenv);
|
||||
curenv = NULL;
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
// Copy trap frame (which is currently on the stack)
|
||||
// into 'curenv->env_tf', so that running the environment
|
||||
// will restart at the trap point.
|
||||
curenv->env_tf = *tf;
|
||||
// The trapframe on the stack should be ignored from here on.
|
||||
tf = &curenv->env_tf;
|
||||
}
|
||||
|
||||
// Record that tf is the last real trapframe so
|
||||
// print_trapframe can print some additional information.
|
||||
last_tf = tf;
|
||||
|
||||
// Dispatch based on what type of trap occurred
|
||||
trap_dispatch(tf);
|
||||
|
||||
// If we made it to this point, then no other environment was
|
||||
// scheduled, so we should return to the current environment
|
||||
// if doing so makes sense.
|
||||
if (curenv && curenv->env_status == ENV_RUNNING)
|
||||
env_run(curenv);
|
||||
else
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
page_fault_handler(struct Trapframe *tf)
|
||||
{
|
||||
uint32_t fault_va;
|
||||
|
||||
// Read processor's CR2 register to find the faulting address
|
||||
fault_va = rcr2();
|
||||
|
||||
// Handle kernel-mode page faults.
|
||||
|
||||
// LAB 3: Your code here.
|
||||
|
||||
// 怎么判断是内核模式, CPL位
|
||||
|
||||
if(tf->tf_cs && 3 == 0) {
|
||||
panic("page_fault in kernel mode, fault address %d\n", fault_va);
|
||||
}
|
||||
|
||||
// We've already handled kernel-mode exceptions, so if we get here,
|
||||
// the page fault happened in user mode.
|
||||
|
||||
|
||||
// Call the environment's page fault upcall, if one exists. Set up a
|
||||
// page fault stack frame on the user exception stack (below
|
||||
// UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
|
||||
//
|
||||
// The page fault upcall might cause another page fault, in which case
|
||||
// we branch to the page fault upcall recursively, pushing another
|
||||
// page fault stack frame on top of the user exception stack.
|
||||
//
|
||||
// It is convenient for our code which returns from a page fault
|
||||
// (lib/pfentry.S) to have one word of scratch space at the top of the
|
||||
// trap-time stack; it allows us to more easily restore the eip/esp. In
|
||||
// the non-recursive case, we don't have to worry about this because
|
||||
// the top of the regular user stack is free. In the recursive case,
|
||||
// this means we have to leave an extra word between the current top of
|
||||
// the exception stack and the new stack frame because the exception
|
||||
// stack _is_ the trap-time stack.
|
||||
//
|
||||
// If there's no page fault upcall, the environment didn't allocate a
|
||||
// page for its exception stack or can't write to it, or the exception
|
||||
// stack overflows, then destroy the environment that caused the fault.
|
||||
// Note that the grade script assumes you will first check for the page
|
||||
// fault upcall and print the "user fault va" message below if there is
|
||||
// none. The remaining three checks can be combined into a single test.
|
||||
//
|
||||
// Hints:
|
||||
// user_mem_assert() and env_run() are useful here.
|
||||
// To change what the user environment runs, modify 'curenv->env_tf'
|
||||
// (the 'tf' variable points at 'curenv->env_tf').
|
||||
|
||||
// LAB 4: Your code here.
|
||||
struct UTrapframe *utf;
|
||||
// cprintf("I'M in page_fault_handler [%08x] user fault va %08x \n",curenv->env_id, fault_va);
|
||||
if (curenv->env_pgfault_upcall) {
|
||||
|
||||
if (tf->tf_esp >= UXSTACKTOP-PGSIZE && tf->tf_esp < UXSTACKTOP) {
|
||||
// 异常模式下陷入
|
||||
utf = (struct UTrapframe *)(tf->tf_esp - sizeof(struct UTrapframe) - 4);
|
||||
|
||||
}
|
||||
else {
|
||||
// 非异常模式下陷入
|
||||
utf = (struct UTrapframe *)(UXSTACKTOP - sizeof(struct UTrapframe));
|
||||
}
|
||||
// 检查异常栈是否溢出
|
||||
user_mem_assert(curenv, (const void *) utf, sizeof(struct UTrapframe), PTE_P|PTE_W);
|
||||
|
||||
utf->utf_fault_va = fault_va;
|
||||
utf->utf_err = tf->tf_trapno;
|
||||
utf->utf_regs = tf->tf_regs;
|
||||
utf->utf_eflags = tf->tf_eflags;
|
||||
// 保存陷入时现场,用于返回
|
||||
utf->utf_eip = tf->tf_eip;
|
||||
utf->utf_esp = tf->tf_esp;
|
||||
// 再次转向执行
|
||||
curenv->env_tf.tf_eip = (uint32_t) curenv->env_pgfault_upcall;
|
||||
// 异常栈
|
||||
curenv->env_tf.tf_esp = (uint32_t) utf;
|
||||
env_run(curenv);
|
||||
}
|
||||
else {
|
||||
// Destroy the environment that caused the fault.
|
||||
cprintf("[%08x] user fault va %08x ip %08x\n",
|
||||
curenv->env_id, fault_va, tf->tf_eip);
|
||||
print_trapframe(tf);
|
||||
env_destroy(curenv);
|
||||
}
|
||||
}
|
||||
|
||||
375
lab/LAB4.si4project/Backup/trap(2812).c
Normal file
375
lab/LAB4.si4project/Backup/trap(2812).c
Normal file
@@ -0,0 +1,375 @@
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/x86.h>
|
||||
#include <inc/assert.h>
|
||||
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/trap.h>
|
||||
#include <kern/console.h>
|
||||
#include <kern/monitor.h>
|
||||
#include <kern/env.h>
|
||||
#include <kern/syscall.h>
|
||||
#include <kern/sched.h>
|
||||
#include <kern/kclock.h>
|
||||
#include <kern/picirq.h>
|
||||
#include <kern/cpu.h>
|
||||
#include <kern/spinlock.h>
|
||||
|
||||
static struct Taskstate ts;
|
||||
|
||||
/* For debugging, so print_trapframe can distinguish between printing
|
||||
* a saved trapframe and printing the current trapframe and print some
|
||||
* additional information in the latter case.
|
||||
*/
|
||||
static struct Trapframe *last_tf;
|
||||
|
||||
/* Interrupt descriptor table. (Must be built at run time because
|
||||
* shifted function addresses can't be represented in relocation records.)
|
||||
*/
|
||||
struct Gatedesc idt[256] = { { 0 } };
|
||||
struct Pseudodesc idt_pd = {
|
||||
sizeof(idt) - 1, (uint32_t) idt
|
||||
};
|
||||
|
||||
|
||||
static const char *trapname(int trapno)
|
||||
{
|
||||
static const char * const excnames[] = {
|
||||
"Divide error",
|
||||
"Debug",
|
||||
"Non-Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Overflow",
|
||||
"BOUND Range Exceeded",
|
||||
"Invalid Opcode",
|
||||
"Device Not Available",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Invalid TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection",
|
||||
"Page Fault",
|
||||
"(unknown trap)",
|
||||
"x87 FPU Floating-Point Error",
|
||||
"Alignment Check",
|
||||
"Machine-Check",
|
||||
"SIMD Floating-Point Exception"
|
||||
};
|
||||
|
||||
if (trapno < ARRAY_SIZE(excnames))
|
||||
return excnames[trapno];
|
||||
if (trapno == T_SYSCALL)
|
||||
return "System call";
|
||||
if (trapno >= IRQ_OFFSET && trapno < IRQ_OFFSET + 16)
|
||||
return "Hardware Interrupt";
|
||||
return "(unknown trap)";
|
||||
}
|
||||
|
||||
// You will also need to modify trap_init() to initialize the idt to
|
||||
// point to each of these entry points defined in trapentry.S;
|
||||
// the SETGATE macro will be helpful here
|
||||
void
|
||||
trap_init(void)
|
||||
{
|
||||
|
||||
extern struct Segdesc gdt[];
|
||||
void divide_handler();
|
||||
void debug_handler();
|
||||
void nmi_handler();
|
||||
void brkpt_handler();
|
||||
void oflow_handler();
|
||||
void bound_handler();
|
||||
void device_handler();
|
||||
void illop_handler();
|
||||
void tss_handler();
|
||||
void segnp_handler();
|
||||
void stack_handler();
|
||||
void gpflt_handler();
|
||||
void pgflt_handler();
|
||||
void fperr_handler();
|
||||
void align_handler();
|
||||
void mchk_handler();
|
||||
void simderr_handler();
|
||||
void syscall_handler();
|
||||
void dblflt_handler();
|
||||
|
||||
// LAB 3: Your code here.
|
||||
// GD_KT 全局描述符, kernel text
|
||||
SETGATE(idt[T_DIVIDE], 0, GD_KT, divide_handler, 0);
|
||||
SETGATE(idt[T_DEBUG], 0, GD_KT, debug_handler, 0);
|
||||
SETGATE(idt[T_NMI], 0, GD_KT, nmi_handler, 0);
|
||||
SETGATE(idt[T_BRKPT], 0, GD_KT, brkpt_handler, 3);
|
||||
SETGATE(idt[T_OFLOW], 0, GD_KT, oflow_handler, 0);
|
||||
SETGATE(idt[T_BOUND], 0, GD_KT, bound_handler, 0);
|
||||
SETGATE(idt[T_DEVICE], 0, GD_KT, device_handler, 0);
|
||||
SETGATE(idt[T_ILLOP], 0, GD_KT, illop_handler, 0);
|
||||
SETGATE(idt[T_DBLFLT], 0, GD_KT, dblflt_handler, 0);
|
||||
SETGATE(idt[T_TSS], 0, GD_KT, tss_handler, 0);
|
||||
SETGATE(idt[T_SEGNP], 0, GD_KT, segnp_handler, 0);
|
||||
SETGATE(idt[T_STACK], 0, GD_KT, stack_handler, 0);
|
||||
SETGATE(idt[T_GPFLT], 0, GD_KT, gpflt_handler, 0);
|
||||
SETGATE(idt[T_PGFLT], 0, GD_KT, pgflt_handler, 0);
|
||||
SETGATE(idt[T_FPERR], 0, GD_KT, fperr_handler, 0);
|
||||
SETGATE(idt[T_ALIGN], 0, GD_KT, align_handler, 0);
|
||||
SETGATE(idt[T_MCHK], 0, GD_KT, mchk_handler, 0);
|
||||
SETGATE(idt[T_SIMDERR], 0, GD_KT, simderr_handler, 0);
|
||||
SETGATE(idt[T_SYSCALL], 0, GD_KT, syscall_handler, 3);
|
||||
|
||||
// Per-CPU setup
|
||||
trap_init_percpu();
|
||||
}
|
||||
|
||||
// Initialize and load the per-CPU TSS and IDT
|
||||
void
|
||||
trap_init_percpu(void)
|
||||
{
|
||||
// The example code here sets up the Task State Segment (TSS) and
|
||||
// the TSS descriptor for CPU 0. But it is incorrect if we are
|
||||
// running on other CPUs because each CPU has its own kernel stack.
|
||||
// Fix the code so that it works for all CPUs.
|
||||
//
|
||||
// Hints:
|
||||
// - The macro "thiscpu" always refers to the current CPU's
|
||||
// struct CpuInfo;
|
||||
// - The ID of the current CPU is given by cpunum() or
|
||||
// thiscpu->cpu_id;
|
||||
// - Use "thiscpu->cpu_ts" as the TSS for the current CPU,
|
||||
// rather than the global "ts" variable;
|
||||
// - Use gdt[(GD_TSS0 >> 3) + i] for CPU i's TSS descriptor;
|
||||
// - You mapped the per-CPU kernel stacks in mem_init_mp()
|
||||
// - Initialize cpu_ts.ts_iomb to prevent unauthorized environments
|
||||
// from doing IO (0 is not the correct value!)
|
||||
//
|
||||
// ltr sets a 'busy' flag in the TSS selector, so if you
|
||||
// accidentally load the same TSS on more than one CPU, you'll
|
||||
// get a triple fault. If you set up an individual CPU's TSS
|
||||
// wrong, you may not get a fault until you try to return from
|
||||
// user space on that CPU.
|
||||
//
|
||||
// LAB 4: Your code here:
|
||||
thiscpu->cpu_ts.ts_esp0 = KSTACKTOP - cpunum() * (KSTKGAP + KSTKSIZE);
|
||||
thiscpu->cpu_ts.ts_ss0 = GD_KD;
|
||||
|
||||
// Initialize the TSS slot of the gdt.
|
||||
gdt[(GD_TSS0 >> 3) + cpunum()] = SEG16(STS_T32A, (uint32_t) (&thiscpu->cpu_ts), sizeof(struct Taskstate) - 1, 0);
|
||||
gdt[(GD_TSS0 >> 3) + cpunum()].sd_s = 0;
|
||||
|
||||
// Load the TSS selector (like other segment selectors, the
|
||||
// bottom three bits are special; we leave them 0)
|
||||
ltr(GD_TSS0 + sizeof(struct Segdesc) * cpunum());
|
||||
|
||||
// Load the IDT
|
||||
lidt(&idt_pd);
|
||||
}
|
||||
|
||||
void
|
||||
print_trapframe(struct Trapframe *tf)
|
||||
{
|
||||
cprintf("TRAP frame at %p from CPU %d\n", tf, cpunum());
|
||||
print_regs(&tf->tf_regs);
|
||||
cprintf(" es 0x----%04x\n", tf->tf_es);
|
||||
cprintf(" ds 0x----%04x\n", tf->tf_ds);
|
||||
cprintf(" trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
|
||||
// If this trap was a page fault that just happened
|
||||
// (so %cr2 is meaningful), print the faulting linear address.
|
||||
if (tf == last_tf && tf->tf_trapno == T_PGFLT)
|
||||
cprintf(" cr2 0x%08x\n", rcr2());
|
||||
cprintf(" err 0x%08x", tf->tf_err);
|
||||
// For page faults, print decoded fault error code:
|
||||
// U/K=fault occurred in user/kernel mode
|
||||
// W/R=a write/read caused the fault
|
||||
// PR=a protection violation caused the fault (NP=page not present).
|
||||
if (tf->tf_trapno == T_PGFLT)
|
||||
cprintf(" [%s, %s, %s]\n",
|
||||
tf->tf_err & 4 ? "user" : "kernel",
|
||||
tf->tf_err & 2 ? "write" : "read",
|
||||
tf->tf_err & 1 ? "protection" : "not-present");
|
||||
else
|
||||
cprintf("\n");
|
||||
cprintf(" eip 0x%08x\n", tf->tf_eip);
|
||||
cprintf(" cs 0x----%04x\n", tf->tf_cs);
|
||||
cprintf(" flag 0x%08x\n", tf->tf_eflags);
|
||||
if ((tf->tf_cs & 3) != 0) {
|
||||
cprintf(" esp 0x%08x\n", tf->tf_esp);
|
||||
cprintf(" ss 0x----%04x\n", tf->tf_ss);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_regs(struct PushRegs *regs)
|
||||
{
|
||||
cprintf(" edi 0x%08x\n", regs->reg_edi);
|
||||
cprintf(" esi 0x%08x\n", regs->reg_esi);
|
||||
cprintf(" ebp 0x%08x\n", regs->reg_ebp);
|
||||
cprintf(" oesp 0x%08x\n", regs->reg_oesp);
|
||||
cprintf(" ebx 0x%08x\n", regs->reg_ebx);
|
||||
cprintf(" edx 0x%08x\n", regs->reg_edx);
|
||||
cprintf(" ecx 0x%08x\n", regs->reg_ecx);
|
||||
cprintf(" eax 0x%08x\n", regs->reg_eax);
|
||||
}
|
||||
|
||||
static void
|
||||
trap_dispatch(struct Trapframe *tf)
|
||||
{
|
||||
// Handle processor exceptions.
|
||||
// LAB 3: Your code here.
|
||||
switch(tf->tf_trapno) {
|
||||
case T_PGFLT:
|
||||
page_fault_handler(tf);
|
||||
break;
|
||||
case T_BRKPT:
|
||||
monitor(tf);
|
||||
break;
|
||||
case T_SYSCALL:
|
||||
|
||||
tf->tf_regs.reg_eax = syscall(tf->tf_regs.reg_eax,
|
||||
tf->tf_regs.reg_edx,
|
||||
tf->tf_regs.reg_ecx,
|
||||
tf->tf_regs.reg_ebx,
|
||||
tf->tf_regs.reg_edi,
|
||||
tf->tf_regs.reg_esi);
|
||||
break;
|
||||
default:
|
||||
// Unexpected trap: The user process or the kernel has a bug.
|
||||
print_trapframe(tf);
|
||||
if (tf->tf_cs == GD_KT)
|
||||
panic("unhandled trap in kernel");
|
||||
else {
|
||||
env_destroy(curenv);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Handle clock interrupts. Don't forget to acknowledge the
|
||||
// interrupt using lapic_eoi() before calling the scheduler!
|
||||
// LAB 4: Your code here.
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
trap(struct Trapframe *tf)
|
||||
{
|
||||
// The environment may have set DF and some versions
|
||||
// of GCC rely on DF being clear
|
||||
asm volatile("cld" ::: "cc");
|
||||
|
||||
// Halt the CPU if some other CPU has called panic()
|
||||
extern char *panicstr;
|
||||
if (panicstr)
|
||||
asm volatile("hlt");
|
||||
|
||||
// Re-acqurie the big kernel lock if we were halted in
|
||||
// sched_yield()
|
||||
if (xchg(&thiscpu->cpu_status, CPU_STARTED) == CPU_HALTED)
|
||||
lock_kernel();
|
||||
// Check that interrupts are disabled. If this assertion
|
||||
// fails, DO NOT be tempted to fix it by inserting a "cli" in
|
||||
// the interrupt path.
|
||||
assert(!(read_eflags() & FL_IF));
|
||||
|
||||
if ((tf->tf_cs & 3) == 3) {
|
||||
// Trapped from user mode.
|
||||
// Acquire the big kernel lock before doing any
|
||||
// serious kernel work.
|
||||
// LAB 4: Your code here.
|
||||
lock_kernel();
|
||||
assert(curenv);
|
||||
|
||||
// Garbage collect if current enviroment is a zombie
|
||||
if (curenv->env_status == ENV_DYING) {
|
||||
env_free(curenv);
|
||||
curenv = NULL;
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
// Copy trap frame (which is currently on the stack)
|
||||
// into 'curenv->env_tf', so that running the environment
|
||||
// will restart at the trap point.
|
||||
curenv->env_tf = *tf;
|
||||
// The trapframe on the stack should be ignored from here on.
|
||||
tf = &curenv->env_tf;
|
||||
}
|
||||
|
||||
// Record that tf is the last real trapframe so
|
||||
// print_trapframe can print some additional information.
|
||||
last_tf = tf;
|
||||
|
||||
// Dispatch based on what type of trap occurred
|
||||
trap_dispatch(tf);
|
||||
|
||||
// If we made it to this point, then no other environment was
|
||||
// scheduled, so we should return to the current environment
|
||||
// if doing so makes sense.
|
||||
if (curenv && curenv->env_status == ENV_RUNNING)
|
||||
env_run(curenv);
|
||||
else
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
page_fault_handler(struct Trapframe *tf)
|
||||
{
|
||||
uint32_t fault_va;
|
||||
|
||||
// Read processor's CR2 register to find the faulting address
|
||||
fault_va = rcr2();
|
||||
|
||||
// Handle kernel-mode page faults.
|
||||
|
||||
// LAB 3: Your code here.
|
||||
|
||||
// 怎么判断是内核模式, CPL位
|
||||
|
||||
if(tf->tf_cs && 3 == 0) {
|
||||
panic("page_fault in kernel mode, fault address %d\n", fault_va);
|
||||
}
|
||||
|
||||
// We've already handled kernel-mode exceptions, so if we get here,
|
||||
// the page fault happened in user mode.
|
||||
|
||||
|
||||
// Call the environment's page fault upcall, if one exists. Set up a
|
||||
// page fault stack frame on the user exception stack (below
|
||||
// UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
|
||||
//
|
||||
// The page fault upcall might cause another page fault, in which case
|
||||
// we branch to the page fault upcall recursively, pushing another
|
||||
// page fault stack frame on top of the user exception stack.
|
||||
//
|
||||
// It is convenient for our code which returns from a page fault
|
||||
// (lib/pfentry.S) to have one word of scratch space at the top of the
|
||||
// trap-time stack; it allows us to more easily restore the eip/esp. In
|
||||
// the non-recursive case, we don't have to worry about this because
|
||||
// the top of the regular user stack is free. In the recursive case,
|
||||
// this means we have to leave an extra word between the current top of
|
||||
// the exception stack and the new stack frame because the exception
|
||||
// stack _is_ the trap-time stack.
|
||||
//
|
||||
// If there's no page fault upcall, the environment didn't allocate a
|
||||
// page for its exception stack or can't write to it, or the exception
|
||||
// stack overflows, then destroy the environment that caused the fault.
|
||||
// Note that the grade script assumes you will first check for the page
|
||||
// fault upcall and print the "user fault va" message below if there is
|
||||
// none. The remaining three checks can be combined into a single test.
|
||||
//
|
||||
// Hints:
|
||||
// user_mem_assert() and env_run() are useful here.
|
||||
// To change what the user environment runs, modify 'curenv->env_tf'
|
||||
// (the 'tf' variable points at 'curenv->env_tf').
|
||||
|
||||
// LAB 4: Your code here.
|
||||
|
||||
|
||||
// user_mem_assert(curenv, (const void *) fault_va, PGSIZE, 0);
|
||||
|
||||
// Destroy the environment that caused the fault.
|
||||
cprintf("[%08x] user fault va %08x ip %08x\n",
|
||||
curenv->env_id, fault_va, tf->tf_eip);
|
||||
print_trapframe(tf);
|
||||
env_destroy(curenv);
|
||||
}
|
||||
|
||||
401
lab/LAB4.si4project/Backup/trap(359).c
Normal file
401
lab/LAB4.si4project/Backup/trap(359).c
Normal file
@@ -0,0 +1,401 @@
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/x86.h>
|
||||
#include <inc/assert.h>
|
||||
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/trap.h>
|
||||
#include <kern/console.h>
|
||||
#include <kern/monitor.h>
|
||||
#include <kern/env.h>
|
||||
#include <kern/syscall.h>
|
||||
#include <kern/sched.h>
|
||||
#include <kern/kclock.h>
|
||||
#include <kern/picirq.h>
|
||||
#include <kern/cpu.h>
|
||||
#include <kern/spinlock.h>
|
||||
|
||||
static struct Taskstate ts;
|
||||
|
||||
/* For debugging, so print_trapframe can distinguish between printing
|
||||
* a saved trapframe and printing the current trapframe and print some
|
||||
* additional information in the latter case.
|
||||
*/
|
||||
static struct Trapframe *last_tf;
|
||||
|
||||
/* Interrupt descriptor table. (Must be built at run time because
|
||||
* shifted function addresses can't be represented in relocation records.)
|
||||
*/
|
||||
struct Gatedesc idt[256] = { { 0 } };
|
||||
struct Pseudodesc idt_pd = {
|
||||
sizeof(idt) - 1, (uint32_t) idt
|
||||
};
|
||||
|
||||
|
||||
static const char *trapname(int trapno)
|
||||
{
|
||||
static const char * const excnames[] = {
|
||||
"Divide error",
|
||||
"Debug",
|
||||
"Non-Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Overflow",
|
||||
"BOUND Range Exceeded",
|
||||
"Invalid Opcode",
|
||||
"Device Not Available",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Invalid TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection",
|
||||
"Page Fault",
|
||||
"(unknown trap)",
|
||||
"x87 FPU Floating-Point Error",
|
||||
"Alignment Check",
|
||||
"Machine-Check",
|
||||
"SIMD Floating-Point Exception"
|
||||
};
|
||||
|
||||
if (trapno < ARRAY_SIZE(excnames))
|
||||
return excnames[trapno];
|
||||
if (trapno == T_SYSCALL)
|
||||
return "System call";
|
||||
if (trapno >= IRQ_OFFSET && trapno < IRQ_OFFSET + 16)
|
||||
return "Hardware Interrupt";
|
||||
return "(unknown trap)";
|
||||
}
|
||||
|
||||
// You will also need to modify trap_init() to initialize the idt to
|
||||
// point to each of these entry points defined in trapentry.S;
|
||||
// the SETGATE macro will be helpful here
|
||||
void
|
||||
trap_init(void)
|
||||
{
|
||||
|
||||
extern struct Segdesc gdt[];
|
||||
void divide_handler();
|
||||
void debug_handler();
|
||||
void nmi_handler();
|
||||
void brkpt_handler();
|
||||
void oflow_handler();
|
||||
void bound_handler();
|
||||
void device_handler();
|
||||
void illop_handler();
|
||||
void tss_handler();
|
||||
void segnp_handler();
|
||||
void stack_handler();
|
||||
void gpflt_handler();
|
||||
void pgflt_handler();
|
||||
void fperr_handler();
|
||||
void align_handler();
|
||||
void mchk_handler();
|
||||
void simderr_handler();
|
||||
void syscall_handler();
|
||||
void dblflt_handler();
|
||||
|
||||
// LAB 3: Your code here.
|
||||
// GD_KT 全局描述符, kernel text
|
||||
SETGATE(idt[T_DIVIDE], 0, GD_KT, divide_handler, 0);
|
||||
SETGATE(idt[T_DEBUG], 0, GD_KT, debug_handler, 0);
|
||||
SETGATE(idt[T_NMI], 0, GD_KT, nmi_handler, 0);
|
||||
SETGATE(idt[T_BRKPT], 0, GD_KT, brkpt_handler, 3);
|
||||
SETGATE(idt[T_OFLOW], 0, GD_KT, oflow_handler, 0);
|
||||
SETGATE(idt[T_BOUND], 0, GD_KT, bound_handler, 0);
|
||||
SETGATE(idt[T_DEVICE], 0, GD_KT, device_handler, 0);
|
||||
SETGATE(idt[T_ILLOP], 0, GD_KT, illop_handler, 0);
|
||||
SETGATE(idt[T_DBLFLT], 0, GD_KT, dblflt_handler, 0);
|
||||
SETGATE(idt[T_TSS], 0, GD_KT, tss_handler, 0);
|
||||
SETGATE(idt[T_SEGNP], 0, GD_KT, segnp_handler, 0);
|
||||
SETGATE(idt[T_STACK], 0, GD_KT, stack_handler, 0);
|
||||
SETGATE(idt[T_GPFLT], 0, GD_KT, gpflt_handler, 0);
|
||||
SETGATE(idt[T_PGFLT], 0, GD_KT, pgflt_handler, 0);
|
||||
SETGATE(idt[T_FPERR], 0, GD_KT, fperr_handler, 0);
|
||||
SETGATE(idt[T_ALIGN], 0, GD_KT, align_handler, 0);
|
||||
SETGATE(idt[T_MCHK], 0, GD_KT, mchk_handler, 0);
|
||||
SETGATE(idt[T_SIMDERR], 0, GD_KT, simderr_handler, 0);
|
||||
SETGATE(idt[T_SYSCALL], 0, GD_KT, syscall_handler, 3);
|
||||
|
||||
// Per-CPU setup
|
||||
trap_init_percpu();
|
||||
}
|
||||
|
||||
// Initialize and load the per-CPU TSS and IDT
|
||||
void
|
||||
trap_init_percpu(void)
|
||||
{
|
||||
// The example code here sets up the Task State Segment (TSS) and
|
||||
// the TSS descriptor for CPU 0. But it is incorrect if we are
|
||||
// running on other CPUs because each CPU has its own kernel stack.
|
||||
// Fix the code so that it works for all CPUs.
|
||||
//
|
||||
// Hints:
|
||||
// - The macro "thiscpu" always refers to the current CPU's
|
||||
// struct CpuInfo;
|
||||
// - The ID of the current CPU is given by cpunum() or
|
||||
// thiscpu->cpu_id;
|
||||
// - Use "thiscpu->cpu_ts" as the TSS for the current CPU,
|
||||
// rather than the global "ts" variable;
|
||||
// - Use gdt[(GD_TSS0 >> 3) + i] for CPU i's TSS descriptor;
|
||||
// - You mapped the per-CPU kernel stacks in mem_init_mp()
|
||||
// - Initialize cpu_ts.ts_iomb to prevent unauthorized environments
|
||||
// from doing IO (0 is not the correct value!)
|
||||
//
|
||||
// ltr sets a 'busy' flag in the TSS selector, so if you
|
||||
// accidentally load the same TSS on more than one CPU, you'll
|
||||
// get a triple fault. If you set up an individual CPU's TSS
|
||||
// wrong, you may not get a fault until you try to return from
|
||||
// user space on that CPU.
|
||||
//
|
||||
// LAB 4: Your code here:
|
||||
thiscpu->cpu_ts.ts_esp0 = KSTACKTOP - cpunum() * (KSTKGAP + KSTKSIZE);
|
||||
thiscpu->cpu_ts.ts_ss0 = GD_KD;
|
||||
|
||||
// Initialize the TSS slot of the gdt.
|
||||
gdt[(GD_TSS0 >> 3) + cpunum()] = SEG16(STS_T32A, (uint32_t) (&thiscpu->cpu_ts), sizeof(struct Taskstate) - 1, 0);
|
||||
gdt[(GD_TSS0 >> 3) + cpunum()].sd_s = 0;
|
||||
|
||||
// Load the TSS selector (like other segment selectors, the
|
||||
// bottom three bits are special; we leave them 0)
|
||||
ltr(GD_TSS0 + sizeof(struct Segdesc) * cpunum());
|
||||
|
||||
// Load the IDT
|
||||
lidt(&idt_pd);
|
||||
}
|
||||
|
||||
void
|
||||
print_trapframe(struct Trapframe *tf)
|
||||
{
|
||||
cprintf("TRAP frame at %p from CPU %d\n", tf, cpunum());
|
||||
print_regs(&tf->tf_regs);
|
||||
cprintf(" es 0x----%04x\n", tf->tf_es);
|
||||
cprintf(" ds 0x----%04x\n", tf->tf_ds);
|
||||
cprintf(" trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
|
||||
// If this trap was a page fault that just happened
|
||||
// (so %cr2 is meaningful), print the faulting linear address.
|
||||
if (tf == last_tf && tf->tf_trapno == T_PGFLT)
|
||||
cprintf(" cr2 0x%08x\n", rcr2());
|
||||
cprintf(" err 0x%08x", tf->tf_err);
|
||||
// For page faults, print decoded fault error code:
|
||||
// U/K=fault occurred in user/kernel mode
|
||||
// W/R=a write/read caused the fault
|
||||
// PR=a protection violation caused the fault (NP=page not present).
|
||||
if (tf->tf_trapno == T_PGFLT)
|
||||
cprintf(" [%s, %s, %s]\n",
|
||||
tf->tf_err & 4 ? "user" : "kernel",
|
||||
tf->tf_err & 2 ? "write" : "read",
|
||||
tf->tf_err & 1 ? "protection" : "not-present");
|
||||
else
|
||||
cprintf("\n");
|
||||
cprintf(" eip 0x%08x\n", tf->tf_eip);
|
||||
cprintf(" cs 0x----%04x\n", tf->tf_cs);
|
||||
cprintf(" flag 0x%08x\n", tf->tf_eflags);
|
||||
if ((tf->tf_cs & 3) != 0) {
|
||||
cprintf(" esp 0x%08x\n", tf->tf_esp);
|
||||
cprintf(" ss 0x----%04x\n", tf->tf_ss);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_regs(struct PushRegs *regs)
|
||||
{
|
||||
cprintf(" edi 0x%08x\n", regs->reg_edi);
|
||||
cprintf(" esi 0x%08x\n", regs->reg_esi);
|
||||
cprintf(" ebp 0x%08x\n", regs->reg_ebp);
|
||||
cprintf(" oesp 0x%08x\n", regs->reg_oesp);
|
||||
cprintf(" ebx 0x%08x\n", regs->reg_ebx);
|
||||
cprintf(" edx 0x%08x\n", regs->reg_edx);
|
||||
cprintf(" ecx 0x%08x\n", regs->reg_ecx);
|
||||
cprintf(" eax 0x%08x\n", regs->reg_eax);
|
||||
}
|
||||
|
||||
static void
|
||||
trap_dispatch(struct Trapframe *tf)
|
||||
{
|
||||
// Handle processor exceptions.
|
||||
// LAB 3: Your code here.
|
||||
switch(tf->tf_trapno) {
|
||||
case T_PGFLT:
|
||||
page_fault_handler(tf);
|
||||
break;
|
||||
case T_BRKPT:
|
||||
monitor(tf);
|
||||
break;
|
||||
case T_SYSCALL:
|
||||
|
||||
tf->tf_regs.reg_eax = syscall(tf->tf_regs.reg_eax,
|
||||
tf->tf_regs.reg_edx,
|
||||
tf->tf_regs.reg_ecx,
|
||||
tf->tf_regs.reg_ebx,
|
||||
tf->tf_regs.reg_edi,
|
||||
tf->tf_regs.reg_esi);
|
||||
break;
|
||||
default:
|
||||
// Unexpected trap: The user process or the kernel has a bug.
|
||||
print_trapframe(tf);
|
||||
if (tf->tf_cs == GD_KT)
|
||||
panic("unhandled trap in kernel");
|
||||
else {
|
||||
env_destroy(curenv);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Handle clock interrupts. Don't forget to acknowledge the
|
||||
// interrupt using lapic_eoi() before calling the scheduler!
|
||||
// LAB 4: Your code here.
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
trap(struct Trapframe *tf)
|
||||
{
|
||||
// The environment may have set DF and some versions
|
||||
// of GCC rely on DF being clear
|
||||
asm volatile("cld" ::: "cc");
|
||||
|
||||
// Halt the CPU if some other CPU has called panic()
|
||||
extern char *panicstr;
|
||||
if (panicstr)
|
||||
asm volatile("hlt");
|
||||
|
||||
// Re-acqurie the big kernel lock if we were halted in
|
||||
// sched_yield()
|
||||
if (xchg(&thiscpu->cpu_status, CPU_STARTED) == CPU_HALTED)
|
||||
lock_kernel();
|
||||
// Check that interrupts are disabled. If this assertion
|
||||
// fails, DO NOT be tempted to fix it by inserting a "cli" in
|
||||
// the interrupt path.
|
||||
assert(!(read_eflags() & FL_IF));
|
||||
|
||||
if ((tf->tf_cs & 3) == 3) {
|
||||
// Trapped from user mode.
|
||||
// Acquire the big kernel lock before doing any
|
||||
// serious kernel work.
|
||||
// LAB 4: Your code here.
|
||||
lock_kernel();
|
||||
assert(curenv);
|
||||
|
||||
// Garbage collect if current enviroment is a zombie
|
||||
if (curenv->env_status == ENV_DYING) {
|
||||
env_free(curenv);
|
||||
curenv = NULL;
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
// Copy trap frame (which is currently on the stack)
|
||||
// into 'curenv->env_tf', so that running the environment
|
||||
// will restart at the trap point.
|
||||
curenv->env_tf = *tf;
|
||||
// The trapframe on the stack should be ignored from here on.
|
||||
tf = &curenv->env_tf;
|
||||
}
|
||||
|
||||
// Record that tf is the last real trapframe so
|
||||
// print_trapframe can print some additional information.
|
||||
last_tf = tf;
|
||||
|
||||
// Dispatch based on what type of trap occurred
|
||||
trap_dispatch(tf);
|
||||
|
||||
// If we made it to this point, then no other environment was
|
||||
// scheduled, so we should return to the current environment
|
||||
// if doing so makes sense.
|
||||
if (curenv && curenv->env_status == ENV_RUNNING)
|
||||
env_run(curenv);
|
||||
else
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
page_fault_handler(struct Trapframe *tf)
|
||||
{
|
||||
uint32_t fault_va;
|
||||
|
||||
// Read processor's CR2 register to find the faulting address
|
||||
fault_va = rcr2();
|
||||
|
||||
// Handle kernel-mode page faults.
|
||||
|
||||
// LAB 3: Your code here.
|
||||
|
||||
// 怎么判断是内核模式, CPL位
|
||||
|
||||
if(tf->tf_cs && 3 == 0) {
|
||||
panic("page_fault in kernel mode, fault address %d\n", fault_va);
|
||||
}
|
||||
|
||||
// We've already handled kernel-mode exceptions, so if we get here,
|
||||
// the page fault happened in user mode.
|
||||
|
||||
|
||||
// Call the environment's page fault upcall, if one exists. Set up a
|
||||
// page fault stack frame on the user exception stack (below
|
||||
// UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
|
||||
//
|
||||
// The page fault upcall might cause another page fault, in which case
|
||||
// we branch to the page fault upcall recursively, pushing another
|
||||
// page fault stack frame on top of the user exception stack.
|
||||
//
|
||||
// It is convenient for our code which returns from a page fault
|
||||
// (lib/pfentry.S) to have one word of scratch space at the top of the
|
||||
// trap-time stack; it allows us to more easily restore the eip/esp. In
|
||||
// the non-recursive case, we don't have to worry about this because
|
||||
// the top of the regular user stack is free. In the recursive case,
|
||||
// this means we have to leave an extra word between the current top of
|
||||
// the exception stack and the new stack frame because the exception
|
||||
// stack _is_ the trap-time stack.
|
||||
//
|
||||
// If there's no page fault upcall, the environment didn't allocate a
|
||||
// page for its exception stack or can't write to it, or the exception
|
||||
// stack overflows, then destroy the environment that caused the fault.
|
||||
// Note that the grade script assumes you will first check for the page
|
||||
// fault upcall and print the "user fault va" message below if there is
|
||||
// none. The remaining three checks can be combined into a single test.
|
||||
//
|
||||
// Hints:
|
||||
// user_mem_assert() and env_run() are useful here.
|
||||
// To change what the user environment runs, modify 'curenv->env_tf'
|
||||
// (the 'tf' variable points at 'curenv->env_tf').
|
||||
|
||||
// LAB 4: Your code here.
|
||||
struct UTrapframe *utf;
|
||||
|
||||
if (curenv->env_pgfault_upcall) {
|
||||
|
||||
if (tf->tf_esp >= UXSTACKTOP-PGSIZE && tf->tf_esp < UXSTACKTOP) {
|
||||
// 异常模式下陷入
|
||||
utf = (struct UTrapframe *)(tf->tf_esp - sizeof(struct UTrapframe) - 4);
|
||||
|
||||
}
|
||||
else {
|
||||
// 非异常模式下陷入
|
||||
utf = (struct UTrapframe *)(UXSTACKTOP - sizeof(struct UTrapframe) - 4);
|
||||
}
|
||||
// 检查异常栈是否溢出
|
||||
user_mem_assert(curenv, (const void *) utf, sizeof(struct UTrapframe), PTE_U|PTE_W);
|
||||
|
||||
utf->utf_fault_va = fault_va;
|
||||
utf->utf_err = tf->tf_trapno;
|
||||
utf->utf_regs = tf->tf_regs;
|
||||
utf->utf_eflags = tf->tf_eflags;
|
||||
// 保存上次陷入时现场,用于返回
|
||||
utf->utf_eip = tf->tf_eip;
|
||||
utf->utf_esp = tf->tf_esp;
|
||||
// 再次转向执行
|
||||
tf->tf_eip = (uint32_t) curenv->env_pgfault_upcall;
|
||||
tf->tf_esp = (uint32_t) utf;
|
||||
env_run(curenv);
|
||||
}
|
||||
|
||||
|
||||
// Destroy the environment that caused the fault.
|
||||
cprintf("[%08x] user fault va %08x ip %08x\n",
|
||||
curenv->env_id, fault_va, tf->tf_eip);
|
||||
print_trapframe(tf);
|
||||
env_destroy(curenv);
|
||||
}
|
||||
|
||||
384
lab/LAB4.si4project/Backup/trap(6309).c
Normal file
384
lab/LAB4.si4project/Backup/trap(6309).c
Normal file
@@ -0,0 +1,384 @@
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/x86.h>
|
||||
#include <inc/assert.h>
|
||||
|
||||
#include <kern/pmap.h>
|
||||
#include <kern/trap.h>
|
||||
#include <kern/console.h>
|
||||
#include <kern/monitor.h>
|
||||
#include <kern/env.h>
|
||||
#include <kern/syscall.h>
|
||||
#include <kern/sched.h>
|
||||
#include <kern/kclock.h>
|
||||
#include <kern/picirq.h>
|
||||
#include <kern/cpu.h>
|
||||
#include <kern/spinlock.h>
|
||||
|
||||
static struct Taskstate ts;
|
||||
|
||||
/* For debugging, so print_trapframe can distinguish between printing
|
||||
* a saved trapframe and printing the current trapframe and print some
|
||||
* additional information in the latter case.
|
||||
*/
|
||||
static struct Trapframe *last_tf;
|
||||
|
||||
/* Interrupt descriptor table. (Must be built at run time because
|
||||
* shifted function addresses can't be represented in relocation records.)
|
||||
*/
|
||||
struct Gatedesc idt[256] = { { 0 } };
|
||||
struct Pseudodesc idt_pd = {
|
||||
sizeof(idt) - 1, (uint32_t) idt
|
||||
};
|
||||
|
||||
|
||||
static const char *trapname(int trapno)
|
||||
{
|
||||
static const char * const excnames[] = {
|
||||
"Divide error",
|
||||
"Debug",
|
||||
"Non-Maskable Interrupt",
|
||||
"Breakpoint",
|
||||
"Overflow",
|
||||
"BOUND Range Exceeded",
|
||||
"Invalid Opcode",
|
||||
"Device Not Available",
|
||||
"Double Fault",
|
||||
"Coprocessor Segment Overrun",
|
||||
"Invalid TSS",
|
||||
"Segment Not Present",
|
||||
"Stack Fault",
|
||||
"General Protection",
|
||||
"Page Fault",
|
||||
"(unknown trap)",
|
||||
"x87 FPU Floating-Point Error",
|
||||
"Alignment Check",
|
||||
"Machine-Check",
|
||||
"SIMD Floating-Point Exception"
|
||||
};
|
||||
|
||||
if (trapno < ARRAY_SIZE(excnames))
|
||||
return excnames[trapno];
|
||||
if (trapno == T_SYSCALL)
|
||||
return "System call";
|
||||
if (trapno >= IRQ_OFFSET && trapno < IRQ_OFFSET + 16)
|
||||
return "Hardware Interrupt";
|
||||
return "(unknown trap)";
|
||||
}
|
||||
|
||||
// You will also need to modify trap_init() to initialize the idt to
|
||||
// point to each of these entry points defined in trapentry.S;
|
||||
// the SETGATE macro will be helpful here
|
||||
void
|
||||
trap_init(void)
|
||||
{
|
||||
|
||||
extern struct Segdesc gdt[];
|
||||
void divide_handler();
|
||||
void debug_handler();
|
||||
void nmi_handler();
|
||||
void brkpt_handler();
|
||||
void oflow_handler();
|
||||
void bound_handler();
|
||||
void device_handler();
|
||||
void illop_handler();
|
||||
void tss_handler();
|
||||
void segnp_handler();
|
||||
void stack_handler();
|
||||
void gpflt_handler();
|
||||
void pgflt_handler();
|
||||
void fperr_handler();
|
||||
void align_handler();
|
||||
void mchk_handler();
|
||||
void simderr_handler();
|
||||
void syscall_handler();
|
||||
void dblflt_handler();
|
||||
|
||||
// LAB 3: Your code here.
|
||||
// GD_KT 全局描述符, kernel text
|
||||
SETGATE(idt[T_DIVIDE], 0, GD_KT, divide_handler, 0);
|
||||
SETGATE(idt[T_DEBUG], 0, GD_KT, debug_handler, 0);
|
||||
SETGATE(idt[T_NMI], 0, GD_KT, nmi_handler, 0);
|
||||
SETGATE(idt[T_BRKPT], 0, GD_KT, brkpt_handler, 3);
|
||||
SETGATE(idt[T_OFLOW], 0, GD_KT, oflow_handler, 0);
|
||||
SETGATE(idt[T_BOUND], 0, GD_KT, bound_handler, 0);
|
||||
SETGATE(idt[T_DEVICE], 0, GD_KT, device_handler, 0);
|
||||
SETGATE(idt[T_ILLOP], 0, GD_KT, illop_handler, 0);
|
||||
SETGATE(idt[T_DBLFLT], 0, GD_KT, dblflt_handler, 0);
|
||||
SETGATE(idt[T_TSS], 0, GD_KT, tss_handler, 0);
|
||||
SETGATE(idt[T_SEGNP], 0, GD_KT, segnp_handler, 0);
|
||||
SETGATE(idt[T_STACK], 0, GD_KT, stack_handler, 0);
|
||||
SETGATE(idt[T_GPFLT], 0, GD_KT, gpflt_handler, 0);
|
||||
SETGATE(idt[T_PGFLT], 0, GD_KT, pgflt_handler, 0);
|
||||
SETGATE(idt[T_FPERR], 0, GD_KT, fperr_handler, 0);
|
||||
SETGATE(idt[T_ALIGN], 0, GD_KT, align_handler, 0);
|
||||
SETGATE(idt[T_MCHK], 0, GD_KT, mchk_handler, 0);
|
||||
SETGATE(idt[T_SIMDERR], 0, GD_KT, simderr_handler, 0);
|
||||
SETGATE(idt[T_SYSCALL], 0, GD_KT, syscall_handler, 3);
|
||||
|
||||
// Per-CPU setup
|
||||
trap_init_percpu();
|
||||
}
|
||||
|
||||
// Initialize and load the per-CPU TSS and IDT
|
||||
void
|
||||
trap_init_percpu(void)
|
||||
{
|
||||
// The example code here sets up the Task State Segment (TSS) and
|
||||
// the TSS descriptor for CPU 0. But it is incorrect if we are
|
||||
// running on other CPUs because each CPU has its own kernel stack.
|
||||
// Fix the code so that it works for all CPUs.
|
||||
//
|
||||
// Hints:
|
||||
// - The macro "thiscpu" always refers to the current CPU's
|
||||
// struct CpuInfo;
|
||||
// - The ID of the current CPU is given by cpunum() or
|
||||
// thiscpu->cpu_id;
|
||||
// - Use "thiscpu->cpu_ts" as the TSS for the current CPU,
|
||||
// rather than the global "ts" variable;
|
||||
// - Use gdt[(GD_TSS0 >> 3) + i] for CPU i's TSS descriptor;
|
||||
// - You mapped the per-CPU kernel stacks in mem_init_mp()
|
||||
// - Initialize cpu_ts.ts_iomb to prevent unauthorized environments
|
||||
// from doing IO (0 is not the correct value!)
|
||||
//
|
||||
// ltr sets a 'busy' flag in the TSS selector, so if you
|
||||
// accidentally load the same TSS on more than one CPU, you'll
|
||||
// get a triple fault. If you set up an individual CPU's TSS
|
||||
// wrong, you may not get a fault until you try to return from
|
||||
// user space on that CPU.
|
||||
//
|
||||
// LAB 4: Your code here:
|
||||
thiscpu->cpu_ts.ts_esp0 = KSTACKTOP - cpunum() * (KSTKGAP + KSTKSIZE);
|
||||
thiscpu->cpu_ts.ts_ss0 = GD_KD;
|
||||
|
||||
// Initialize the TSS slot of the gdt.
|
||||
gdt[(GD_TSS0 >> 3) + cpunum()] = SEG16(STS_T32A, (uint32_t) (&thiscpu->cpu_ts), sizeof(struct Taskstate) - 1, 0);
|
||||
gdt[(GD_TSS0 >> 3) + cpunum()].sd_s = 0;
|
||||
|
||||
// Load the TSS selector (like other segment selectors, the
|
||||
// bottom three bits are special; we leave them 0)
|
||||
ltr(GD_TSS0 + sizeof(struct Segdesc) * cpunum());
|
||||
|
||||
// Load the IDT
|
||||
lidt(&idt_pd);
|
||||
}
|
||||
|
||||
void
|
||||
print_trapframe(struct Trapframe *tf)
|
||||
{
|
||||
cprintf("TRAP frame at %p from CPU %d\n", tf, cpunum());
|
||||
print_regs(&tf->tf_regs);
|
||||
cprintf(" es 0x----%04x\n", tf->tf_es);
|
||||
cprintf(" ds 0x----%04x\n", tf->tf_ds);
|
||||
cprintf(" trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
|
||||
// If this trap was a page fault that just happened
|
||||
// (so %cr2 is meaningful), print the faulting linear address.
|
||||
if (tf == last_tf && tf->tf_trapno == T_PGFLT)
|
||||
cprintf(" cr2 0x%08x\n", rcr2());
|
||||
cprintf(" err 0x%08x", tf->tf_err);
|
||||
// For page faults, print decoded fault error code:
|
||||
// U/K=fault occurred in user/kernel mode
|
||||
// W/R=a write/read caused the fault
|
||||
// PR=a protection violation caused the fault (NP=page not present).
|
||||
if (tf->tf_trapno == T_PGFLT)
|
||||
cprintf(" [%s, %s, %s]\n",
|
||||
tf->tf_err & 4 ? "user" : "kernel",
|
||||
tf->tf_err & 2 ? "write" : "read",
|
||||
tf->tf_err & 1 ? "protection" : "not-present");
|
||||
else
|
||||
cprintf("\n");
|
||||
cprintf(" eip 0x%08x\n", tf->tf_eip);
|
||||
cprintf(" cs 0x----%04x\n", tf->tf_cs);
|
||||
cprintf(" flag 0x%08x\n", tf->tf_eflags);
|
||||
if ((tf->tf_cs & 3) != 0) {
|
||||
cprintf(" esp 0x%08x\n", tf->tf_esp);
|
||||
cprintf(" ss 0x----%04x\n", tf->tf_ss);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_regs(struct PushRegs *regs)
|
||||
{
|
||||
cprintf(" edi 0x%08x\n", regs->reg_edi);
|
||||
cprintf(" esi 0x%08x\n", regs->reg_esi);
|
||||
cprintf(" ebp 0x%08x\n", regs->reg_ebp);
|
||||
cprintf(" oesp 0x%08x\n", regs->reg_oesp);
|
||||
cprintf(" ebx 0x%08x\n", regs->reg_ebx);
|
||||
cprintf(" edx 0x%08x\n", regs->reg_edx);
|
||||
cprintf(" ecx 0x%08x\n", regs->reg_ecx);
|
||||
cprintf(" eax 0x%08x\n", regs->reg_eax);
|
||||
}
|
||||
|
||||
static void
|
||||
trap_dispatch(struct Trapframe *tf)
|
||||
{
|
||||
// Handle processor exceptions.
|
||||
// LAB 3: Your code here.
|
||||
switch(tf->tf_trapno) {
|
||||
case T_PGFLT:
|
||||
page_fault_handler(tf);
|
||||
break;
|
||||
case T_BRKPT:
|
||||
monitor(tf);
|
||||
break;
|
||||
case T_SYSCALL:
|
||||
|
||||
tf->tf_regs.reg_eax = syscall(tf->tf_regs.reg_eax,
|
||||
tf->tf_regs.reg_edx,
|
||||
tf->tf_regs.reg_ecx,
|
||||
tf->tf_regs.reg_ebx,
|
||||
tf->tf_regs.reg_edi,
|
||||
tf->tf_regs.reg_esi);
|
||||
break;
|
||||
default:
|
||||
// Unexpected trap: The user process or the kernel has a bug.
|
||||
print_trapframe(tf);
|
||||
if (tf->tf_cs == GD_KT)
|
||||
panic("unhandled trap in kernel");
|
||||
else {
|
||||
env_destroy(curenv);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Handle clock interrupts. Don't forget to acknowledge the
|
||||
// interrupt using lapic_eoi() before calling the scheduler!
|
||||
// LAB 4: Your code here.
|
||||
|
||||
// Unexpected trap: The user process or the kernel has a bug.
|
||||
print_trapframe(tf);
|
||||
if (tf->tf_cs == GD_KT)
|
||||
panic("unhandled trap in kernel");
|
||||
else {
|
||||
env_destroy(curenv);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
trap(struct Trapframe *tf)
|
||||
{
|
||||
// The environment may have set DF and some versions
|
||||
// of GCC rely on DF being clear
|
||||
asm volatile("cld" ::: "cc");
|
||||
|
||||
// Halt the CPU if some other CPU has called panic()
|
||||
extern char *panicstr;
|
||||
if (panicstr)
|
||||
asm volatile("hlt");
|
||||
|
||||
// Re-acqurie the big kernel lock if we were halted in
|
||||
// sched_yield()
|
||||
if (xchg(&thiscpu->cpu_status, CPU_STARTED) == CPU_HALTED)
|
||||
lock_kernel();
|
||||
// Check that interrupts are disabled. If this assertion
|
||||
// fails, DO NOT be tempted to fix it by inserting a "cli" in
|
||||
// the interrupt path.
|
||||
assert(!(read_eflags() & FL_IF));
|
||||
|
||||
if ((tf->tf_cs & 3) == 3) {
|
||||
// Trapped from user mode.
|
||||
// Acquire the big kernel lock before doing any
|
||||
// serious kernel work.
|
||||
// LAB 4: Your code here.
|
||||
lock_kernel();
|
||||
assert(curenv);
|
||||
|
||||
// Garbage collect if current enviroment is a zombie
|
||||
if (curenv->env_status == ENV_DYING) {
|
||||
env_free(curenv);
|
||||
curenv = NULL;
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
// Copy trap frame (which is currently on the stack)
|
||||
// into 'curenv->env_tf', so that running the environment
|
||||
// will restart at the trap point.
|
||||
curenv->env_tf = *tf;
|
||||
// The trapframe on the stack should be ignored from here on.
|
||||
tf = &curenv->env_tf;
|
||||
}
|
||||
|
||||
// Record that tf is the last real trapframe so
|
||||
// print_trapframe can print some additional information.
|
||||
last_tf = tf;
|
||||
|
||||
// Dispatch based on what type of trap occurred
|
||||
trap_dispatch(tf);
|
||||
|
||||
// If we made it to this point, then no other environment was
|
||||
// scheduled, so we should return to the current environment
|
||||
// if doing so makes sense.
|
||||
if (curenv && curenv->env_status == ENV_RUNNING)
|
||||
env_run(curenv);
|
||||
else
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
page_fault_handler(struct Trapframe *tf)
|
||||
{
|
||||
uint32_t fault_va;
|
||||
|
||||
// Read processor's CR2 register to find the faulting address
|
||||
fault_va = rcr2();
|
||||
|
||||
// Handle kernel-mode page faults.
|
||||
|
||||
// LAB 3: Your code here.
|
||||
|
||||
// 怎么判断是内核模式, CPL位
|
||||
|
||||
if(tf->tf_cs && 3 == 0) {
|
||||
panic("page_fault in kernel mode, fault address %d\n", fault_va);
|
||||
}
|
||||
|
||||
// We've already handled kernel-mode exceptions, so if we get here,
|
||||
// the page fault happened in user mode.
|
||||
|
||||
|
||||
// Call the environment's page fault upcall, if one exists. Set up a
|
||||
// page fault stack frame on the user exception stack (below
|
||||
// UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
|
||||
//
|
||||
// The page fault upcall might cause another page fault, in which case
|
||||
// we branch to the page fault upcall recursively, pushing another
|
||||
// page fault stack frame on top of the user exception stack.
|
||||
//
|
||||
// It is convenient for our code which returns from a page fault
|
||||
// (lib/pfentry.S) to have one word of scratch space at the top of the
|
||||
// trap-time stack; it allows us to more easily restore the eip/esp. In
|
||||
// the non-recursive case, we don't have to worry about this because
|
||||
// the top of the regular user stack is free. In the recursive case,
|
||||
// this means we have to leave an extra word between the current top of
|
||||
// the exception stack and the new stack frame because the exception
|
||||
// stack _is_ the trap-time stack.
|
||||
//
|
||||
// If there's no page fault upcall, the environment didn't allocate a
|
||||
// page for its exception stack or can't write to it, or the exception
|
||||
// stack overflows, then destroy the environment that caused the fault.
|
||||
// Note that the grade script assumes you will first check for the page
|
||||
// fault upcall and print the "user fault va" message below if there is
|
||||
// none. The remaining three checks can be combined into a single test.
|
||||
//
|
||||
// Hints:
|
||||
// user_mem_assert() and env_run() are useful here.
|
||||
// To change what the user environment runs, modify 'curenv->env_tf'
|
||||
// (the 'tf' variable points at 'curenv->env_tf').
|
||||
|
||||
// LAB 4: Your code here.
|
||||
|
||||
|
||||
// user_mem_assert(curenv, (const void *) fault_va, PGSIZE, 0);
|
||||
|
||||
// Destroy the environment that caused the fault.
|
||||
cprintf("[%08x] user fault va %08x ip %08x\n",
|
||||
curenv->env_id, fault_va, tf->tf_eip);
|
||||
print_trapframe(tf);
|
||||
env_destroy(curenv);
|
||||
}
|
||||
|
||||
100
lab/LAB4.si4project/Backup/trapentry(2731).S
Normal file
100
lab/LAB4.si4project/Backup/trapentry(2731).S
Normal file
@@ -0,0 +1,100 @@
|
||||
/* See COPYRIGHT for copyright information. */
|
||||
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/memlayout.h>
|
||||
#include <inc/trap.h>
|
||||
|
||||
#include <kern/picirq.h>
|
||||
|
||||
|
||||
###################################################################
|
||||
# exceptions/interrupts
|
||||
###################################################################
|
||||
|
||||
/* TRAPHANDLER defines a globally-visible function for handling a trap.
|
||||
* It pushes a trap number onto the stack, then jumps to _alltraps.
|
||||
* Use TRAPHANDLER for traps where the CPU automatically pushes an error code.
|
||||
*
|
||||
* You shouldn't call a TRAPHANDLER function from C, but you may
|
||||
* need to _declare_ one in C (for instance, to get a function pointer
|
||||
* during IDT setup). You can declare the function with
|
||||
* void NAME();
|
||||
* where NAME is the argument passed to TRAPHANDLER.
|
||||
*/
|
||||
#define TRAPHANDLER(name, num) \
|
||||
.globl name; /* define global symbol for 'name' */ \
|
||||
.type name, @function; /* symbol type is function */ \
|
||||
.align 2; /* align function definition */ \
|
||||
name: /* function starts here */ \
|
||||
pushl $(num); \
|
||||
jmp _alltraps
|
||||
|
||||
/* Use TRAPHANDLER_NOEC for traps where the CPU doesn't push an error code.
|
||||
* It pushes a 0 in place of the error code, so the trap frame has the same
|
||||
* format in either case.
|
||||
|
||||
* tarp handler no error code
|
||||
*/
|
||||
|
||||
#define TRAPHANDLER_NOEC(name, num) \
|
||||
.globl name; \
|
||||
.type name, @function; \
|
||||
.align 2; \
|
||||
name: \
|
||||
pushl $0; \
|
||||
pushl $(num); \
|
||||
jmp _alltraps
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
* 我们知道哪些trap是有错误代码的? https://wiki.osdev.org/Exceptions
|
||||
* Lab 3: Your code here for generating entry points for the different traps.
|
||||
*/
|
||||
TRAPHANDLER_NOEC(divide_handler, T_DIVIDE);
|
||||
TRAPHANDLER_NOEC(debug_handler, T_DEBUG);
|
||||
TRAPHANDLER_NOEC(nmi_handler, T_NMI);
|
||||
TRAPHANDLER_NOEC(brkpt_handler, T_BRKPT);
|
||||
TRAPHANDLER_NOEC(oflow_handler, T_OFLOW);
|
||||
TRAPHANDLER_NOEC(bound_handler, T_BOUND);
|
||||
TRAPHANDLER_NOEC(illop_handler, T_ILLOP);
|
||||
TRAPHANDLER_NOEC(device_handler, T_DEVICE);
|
||||
TRAPHANDLER(dblflt_handler, T_DBLFLT);
|
||||
TRAPHANDLER(tss_handler, T_TSS);
|
||||
TRAPHANDLER(segnp_handler, T_SEGNP);
|
||||
TRAPHANDLER(stack_handler, T_STACK);
|
||||
TRAPHANDLER(gpflt_handler, T_GPFLT);
|
||||
TRAPHANDLER(pgflt_handler, T_PGFLT);
|
||||
TRAPHANDLER_NOEC(fperr_handler, T_FPERR);
|
||||
TRAPHANDLER(align_handler, T_ALIGN);
|
||||
TRAPHANDLER_NOEC(mchk_handler, T_MCHK);
|
||||
TRAPHANDLER_NOEC(simderr_handler, T_SIMDERR);
|
||||
TRAPHANDLER_NOEC(syscall_handler, T_SYSCALL);
|
||||
|
||||
/*
|
||||
Your _alltraps should:
|
||||
1. push values to make the stack look like a struct Trapframe
|
||||
2. load GD_KD into %ds and %es
|
||||
3. pushl %esp to pass a pointer to the Trapframe as an argument to trap()
|
||||
4. call trap (can trap ever return?)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Lab 3: Your code here for _alltraps
|
||||
*what is padding ? 填充 pushl %ds;小端模式,是指数据的高字节保存在内存的高地址中
|
||||
*/
|
||||
.globl _alltraps
|
||||
_alltraps:
|
||||
|
||||
pushl %ds;
|
||||
pushl %es;
|
||||
pushal;
|
||||
|
||||
movw $GD_KD, %ax;
|
||||
movw %ax, %ds;
|
||||
movw %ax, %es;
|
||||
|
||||
/*push esp, trap 能自己读esp, 我有点觉得是赋值*/
|
||||
pushl %esp;
|
||||
call trap
|
||||
|
||||
100
lab/LAB4.si4project/Backup/trapentry(7165).S
Normal file
100
lab/LAB4.si4project/Backup/trapentry(7165).S
Normal file
@@ -0,0 +1,100 @@
|
||||
/* See COPYRIGHT for copyright information. */
|
||||
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/memlayout.h>
|
||||
#include <inc/trap.h>
|
||||
|
||||
#include <kern/picirq.h>
|
||||
|
||||
|
||||
###################################################################
|
||||
# exceptions/interrupts
|
||||
###################################################################
|
||||
|
||||
/* TRAPHANDLER defines a globally-visible function for handling a trap.
|
||||
* It pushes a trap number onto the stack, then jumps to _alltraps.
|
||||
* Use TRAPHANDLER for traps where the CPU automatically pushes an error code.
|
||||
*
|
||||
* You shouldn't call a TRAPHANDLER function from C, but you may
|
||||
* need to _declare_ one in C (for instance, to get a function pointer
|
||||
* during IDT setup). You can declare the function with
|
||||
* void NAME();
|
||||
* where NAME is the argument passed to TRAPHANDLER.
|
||||
*/
|
||||
#define TRAPHANDLER(name, num) \
|
||||
.globl name; /* define global symbol for 'name' */ \
|
||||
.type name, @function; /* symbol type is function */ \
|
||||
.align 2; /* align function definition */ \
|
||||
name: /* function starts here */ \
|
||||
pushl $(num); \
|
||||
jmp _alltraps
|
||||
|
||||
/* Use TRAPHANDLER_NOEC for traps where the CPU doesn't push an error code.
|
||||
* It pushes a 0 in place of the error code, so the trap frame has the same
|
||||
* format in either case.
|
||||
|
||||
* tarp handler no error code
|
||||
*/
|
||||
|
||||
#define TRAPHANDLER_NOEC(name, num) \
|
||||
.globl name; \
|
||||
.type name, @function; \
|
||||
.align 2; \
|
||||
name: \
|
||||
pushl $0; \
|
||||
pushl $(num); \
|
||||
jmp _alltraps
|
||||
|
||||
.text
|
||||
|
||||
/*
|
||||
* 我们知道哪些trap是有错误代码的? https://wiki.osdev.org/Exceptions
|
||||
* Lab 3: Your code here for generating entry points for the different traps.
|
||||
*/
|
||||
TRAPHANDLER_NOEC(divide_handler, T_DIVIDE);
|
||||
TRAPHANDLER_NOEC(debug_handler, T_DEBUG);
|
||||
TRAPHANDLER_NOEC(nmi_handler, T_NMI);
|
||||
TRAPHANDLER_NOEC(brkpt_handler, T_BRKPT);
|
||||
TRAPHANDLER_NOEC(oflow_handler, T_OFLOW);
|
||||
TRAPHANDLER_NOEC(bound_handler, T_BOUND);
|
||||
TRAPHANDLER_NOEC(illop_handler, T_ILLOP);
|
||||
TRAPHANDLER_NOEC(device_handler, T_DEVICE);
|
||||
TRAPHANDLER(dblflt_handler, T_DBLFLT);
|
||||
TRAPHANDLER(tss_handler, T_TSS);
|
||||
TRAPHANDLER(segnp_handler, T_SEGNP);
|
||||
TRAPHANDLER(stack_handler, T_STACK);
|
||||
TRAPHANDLER(gpflt_handler, T_GPFLT);
|
||||
TRAPHANDLER(pgflt_handler, T_PGFLT);
|
||||
TRAPHANDLER_NOEC(fperr_handler, T_FPERR);
|
||||
TRAPHANDLER(align_handler, T_ALIGN);
|
||||
TRAPHANDLER_NOEC(mchk_handler, T_MCHK);
|
||||
TRAPHANDLER_NOEC(simderr_handler, T_SIMDERR);
|
||||
TRAPHANDLER_NOEC(syscall_handler, T_SYSCALL);
|
||||
|
||||
/*
|
||||
Your _alltraps should:
|
||||
1. push values to make the stack look like a struct Trapframe
|
||||
2. load GD_KD into %ds and %es
|
||||
3. pushl %esp to pass a pointer to the Trapframe as an argument to trap()
|
||||
4. call trap (can trap ever return?)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Lab 3: Your code here for _alltraps
|
||||
*what is padding ? 填充 pushl %ds;小端模式,是指数据的高字节保存在内存的高地址中
|
||||
*/
|
||||
.globl _alltraps
|
||||
_alltraps:
|
||||
|
||||
pushl %ds;
|
||||
pushl %es;
|
||||
pushal;
|
||||
|
||||
movw $GD_KD, %ax;
|
||||
movw %ax, %ds;
|
||||
movw %ax, %es;
|
||||
|
||||
/*push esp, trap 能自己读esp, 我有点觉得是赋值*/
|
||||
pushl %esp;
|
||||
call trap
|
||||
|
||||
4
lab/LAB4.si4project/LAB4.SearchResults
Normal file
4
lab/LAB4.si4project/LAB4.SearchResults
Normal file
@@ -0,0 +1,4 @@
|
||||
---- sched_halt Matches (3 in 1 files) ----
|
||||
sched.c (kern) line 8 : void sched_halt(void);
|
||||
sched_yield in sched.c (kern) : sched_halt();
|
||||
sched.c (kern) line 56 : sched_halt(void)
|
||||
7
lab/LAB4.si4project/LAB4.bookmarks.xml
Normal file
7
lab/LAB4.si4project/LAB4.bookmarks.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<SourceInsightBookmarks
|
||||
AppVer="4.00.0084"
|
||||
AppVerMinReader="4.00.0009"
|
||||
>
|
||||
<Bookmarks/>
|
||||
</SourceInsightBookmarks>
|
||||
BIN
lab/LAB4.si4project/LAB4.sip_sym
Normal file
BIN
lab/LAB4.si4project/LAB4.sip_sym
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/LAB4.sip_xab
Normal file
BIN
lab/LAB4.si4project/LAB4.sip_xab
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/LAB4.sip_xad
Normal file
BIN
lab/LAB4.si4project/LAB4.sip_xad
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/LAB4.sip_xc
Normal file
BIN
lab/LAB4.si4project/LAB4.sip_xc
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/LAB4.sip_xf
Normal file
BIN
lab/LAB4.si4project/LAB4.sip_xf
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/LAB4.sip_xm
Normal file
BIN
lab/LAB4.si4project/LAB4.sip_xm
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/LAB4.sip_xr
Normal file
BIN
lab/LAB4.si4project/LAB4.sip_xr
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/LAB4.sip_xsb
Normal file
BIN
lab/LAB4.si4project/LAB4.sip_xsb
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/LAB4.sip_xsd
Normal file
BIN
lab/LAB4.si4project/LAB4.sip_xsd
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/LAB4.siproj
Normal file
BIN
lab/LAB4.si4project/LAB4.siproj
Normal file
Binary file not shown.
22
lab/LAB4.si4project/LAB4.siproj_settings.xml
Normal file
22
lab/LAB4.si4project/LAB4.siproj_settings.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ProjectSettings
|
||||
AppVer="4.00.0084"
|
||||
AppVerMinReader="4.00.0034"
|
||||
GlobalConfiguration="1"
|
||||
GlobalWorkspace="0"
|
||||
LocalsInDb="0"
|
||||
IndexMembers="1"
|
||||
IndexFragments="1"
|
||||
UseMasterFileList="0"
|
||||
SourceDir="..\"
|
||||
BackupDir="%PROJECT_DATA_DIR%\Backup"
|
||||
MasterFileList="%PROJECT_SOURCE_DIR%\%PROJECT_NAME%_filelist.txt"
|
||||
IsImportProject="0"
|
||||
>
|
||||
<Imports>
|
||||
<ImportedLibs/>
|
||||
</Imports>
|
||||
<ParseConditions>
|
||||
<Defines/>
|
||||
</ParseConditions>
|
||||
</ProjectSettings>
|
||||
BIN
lab/LAB4.si4project/LAB4.siwork
Normal file
BIN
lab/LAB4.si4project/LAB4.siwork
Normal file
Binary file not shown.
7
lab/LAB4.si4project/LAB4.snippets.xml
Normal file
7
lab/LAB4.si4project/LAB4.snippets.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<SourceInsightCodeSnippets
|
||||
AppVer="4.00.0084"
|
||||
AppVerMinReader="4.00.0019"
|
||||
>
|
||||
<SnippetList/>
|
||||
</SourceInsightCodeSnippets>
|
||||
BIN
lab/LAB4.si4project/cache/parse/boot_main.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/boot_main.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/fs_test.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/fs_test.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/gradelib.py.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/gradelib.py.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_assert.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_assert.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_elf.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_elf.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_env.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_env.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_error.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_error.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_kbdreg.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_kbdreg.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_lib.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_lib.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_memlayout.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_memlayout.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_mmu.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_mmu.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_stab.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_stab.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_stdarg.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_stdarg.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_stdio.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_stdio.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_string.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_string.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_syscall.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_syscall.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_trap.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_trap.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_types.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_types.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/inc_x86.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/inc_x86.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_console.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_console.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_console.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_console.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_cpu.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_cpu.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_entrypgdir.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_entrypgdir.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_env.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_env.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_env.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_env.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_init.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_init.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_kclock.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_kclock.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_kclock.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_kclock.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_kdebug.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_kdebug.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_kdebug.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_kdebug.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_lapic.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_lapic.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_monitor.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_monitor.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_monitor.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_monitor.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_mpconfig.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_mpconfig.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_picirq.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_picirq.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_picirq.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_picirq.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_pmap.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_pmap.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_pmap.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_pmap.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_printf.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_printf.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_sched.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_sched.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_sched.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_sched.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_spinlock.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_spinlock.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_spinlock.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_spinlock.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_syscall.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_syscall.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_syscall.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_syscall.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_trap.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_trap.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/kern_trap.h.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/kern_trap.h.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/lib_console.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/lib_console.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/lib_exit.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/lib_exit.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/lib_fork.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/lib_fork.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/lib_ipc.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/lib_ipc.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/lib_libmain.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/lib_libmain.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/lib_panic.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/lib_panic.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/lib_pgfault.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/lib_pgfault.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/lib_printf.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/lib_printf.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/lib_printfmt.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/lib_printfmt.c.sisc
vendored
Normal file
Binary file not shown.
BIN
lab/LAB4.si4project/cache/parse/lib_readline.c.sisc
vendored
Normal file
BIN
lab/LAB4.si4project/cache/parse/lib_readline.c.sisc
vendored
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user