Compare commits
16 Commits
c3e2a92b08
...
lab4
| Author | SHA1 | Date | |
|---|---|---|---|
| 9acc7c80f7 | |||
| 721a113c93 | |||
| 86c4aa03ed | |||
| f1980d32ca | |||
| 46e7d21fbf | |||
| d943a2be37 | |||
| 1e5c0639ee | |||
| 34e9433d15 | |||
| 9bec3d83bd | |||
| 0289ec3b3e | |||
| 46cc5c9478 | |||
| 4e4de7b836 | |||
| 03b296f7e1 | |||
| 74b1c2c69d | |||
| 3449b8c566 | |||
| 7d76204053 |
22
answers-lab2.txt
Normal file
22
answers-lab2.txt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
1. The entry given by PDX(UVPT) is mapped to the page directory itself,
|
||||||
|
to allow programs to read existing memory mappings. The entry at PDX(UPAGES)
|
||||||
|
is mapped to the pages variable in memory so that the kernel (and potentially other ring 0 programs) can access it. The entry pointed to by PDX(KSTACKTOP-KSTACKSIZE) is mapped
|
||||||
|
to the bootstack location. Finally, both the memory pointed to by 0 and PDX(KERNBASE) are mapped to kernel memory. However, the mappings at VA 0 are read-only, so user programs can't touch them, while the mappings at PDX(KERNBASE) are kernel-private and RW.
|
||||||
|
|
||||||
|
A table could be as follows:
|
||||||
|
|
||||||
|
400 - Kernel memory
|
||||||
|
... - Kernel memory
|
||||||
|
3c0 - Kernel memory
|
||||||
|
3bf - Kernel Stack
|
||||||
|
3bd - UVPT
|
||||||
|
3bc - UPAGES
|
||||||
|
|
||||||
|
|
||||||
|
2. The kernel memory is mapped as kernel read write. This means there are several flags set in the kernel page directory and page table entries, which indicate that this is restricted memory. The lower 3 bits of the CS register will be checked when an access to this memory is made, and, if they are not 0 or 1 (indicating kernel code), the CPU generates a fault, and the user program gives up control back to the OS. Thus, unless a program is started in ring 0, it will not be able to read or write kernel memory, as it should.
|
||||||
|
|
||||||
|
3. The absolute maximum is 4GB, since we use 32-bit integers for referencing memory. Some of this memory is used for the kernel itself, as well as for the page directory and tables.
|
||||||
|
|
||||||
|
4. The page directory and the corresponding pages are all 4kb. The page directory can have 1024 entries, and each of these point to a page table. Thus, we use approximatey 4MB (slightly more than that, actually, due to the size of the page directory itself) of memory. Additionally, the "pages" structs (which are used to keep track of available physical pages), will require ~1000000 entries, each of which is between 6 and 8 bytes (depending on whether GCC aligns struct sizes). This means another 8MB is used to keep track of free pages, to a total of around 12MB.
|
||||||
|
|
||||||
|
5. We switch to high EIP when we jump to "relocated". Relocated is a label, and a symbol that's inserted by the linker. Since the linker is configured to link the kernel high, relocated points to the upper portion of memory, where KERNBASE is. However, the entry page directory, just like our full page directory later on, sets up two mappings, one starting at 0 (creating a one to one mapping between some of the virtual addresses and their physical counterparts), and one starting at KERNBASE. Thus, we can continue to run at a low EIP. The only reason I can think of as to why we NEED to make the switch, besides the elementary "the kernel links high", is that we need to be able to write to various symbols, also linked above KERNBASE.
|
||||||
19
inc/x86.h
19
inc/x86.h
@@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
#include <inc/types.h>
|
#include <inc/types.h>
|
||||||
|
|
||||||
|
#define MSR_IA32_SYSENTER_CS 0x174
|
||||||
|
#define MSR_IA32_SYSENTER_EIP 0x176
|
||||||
|
#define MSR_IA32_SYSENTER_ESP 0x175
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
breakpoint(void)
|
breakpoint(void)
|
||||||
{
|
{
|
||||||
@@ -261,4 +265,19 @@ xchg(volatile uint32_t *addr, uint32_t newval)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
write_msr(uint32_t reg, uint32_t low, uint32_t high) {
|
||||||
|
asm volatile("wrmsr\n\t"
|
||||||
|
:: "c" (reg), "a" (low), "d" (high));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
read_msr(uint32_t reg, uint32_t* low, uint32_t* high) {
|
||||||
|
uint32_t eax, edx;
|
||||||
|
asm volatile("rdmsr\n\t"
|
||||||
|
: "=a" (eax), "=d" (edx) : "c" (reg));
|
||||||
|
*low = eax;
|
||||||
|
*high = edx;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* !JOS_INC_X86_H */
|
#endif /* !JOS_INC_X86_H */
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ KERN_BINFILES := user/hello \
|
|||||||
user/faultread \
|
user/faultread \
|
||||||
user/faultreadkernel \
|
user/faultreadkernel \
|
||||||
user/faultwrite \
|
user/faultwrite \
|
||||||
user/faultwritekernel
|
user/faultwritekernel \
|
||||||
|
user/getc
|
||||||
|
|
||||||
# Binary files for LAB4
|
# Binary files for LAB4
|
||||||
KERN_BINFILES += user/idle \
|
KERN_BINFILES += user/idle \
|
||||||
|
|||||||
@@ -255,6 +255,7 @@ env_alloc(struct Env **newenv_store, envid_t parent_id)
|
|||||||
|
|
||||||
// Enable interrupts while in user mode.
|
// Enable interrupts while in user mode.
|
||||||
// LAB 4: Your code here.
|
// LAB 4: Your code here.
|
||||||
|
e->env_tf.tf_eflags |= FL_IF;
|
||||||
|
|
||||||
// Clear the page fault handler until user installs one.
|
// Clear the page fault handler until user installs one.
|
||||||
e->env_pgfault_upcall = 0;
|
e->env_pgfault_upcall = 0;
|
||||||
@@ -356,6 +357,7 @@ load_icode(struct Env *e, uint8_t *binary)
|
|||||||
// LAB 3: Your code here.
|
// LAB 3: Your code here.
|
||||||
|
|
||||||
// TODO validate the headers
|
// TODO validate the headers
|
||||||
|
lcr3(PADDR(e->env_pgdir));
|
||||||
struct Elf* elf = (struct Elf*) binary;
|
struct Elf* elf = (struct Elf*) binary;
|
||||||
struct Proghdr* ph = (struct Proghdr*) (binary + elf->e_phoff);
|
struct Proghdr* ph = (struct Proghdr*) (binary + elf->e_phoff);
|
||||||
struct Proghdr* phend = ph + elf->e_phnum;
|
struct Proghdr* phend = ph + elf->e_phnum;
|
||||||
@@ -363,11 +365,10 @@ load_icode(struct Env *e, uint8_t *binary)
|
|||||||
if(ph->p_type != ELF_PROG_LOAD) continue;
|
if(ph->p_type != ELF_PROG_LOAD) continue;
|
||||||
|
|
||||||
region_alloc(e, (void*) ph->p_va, ph->p_memsz);
|
region_alloc(e, (void*) ph->p_va, ph->p_memsz);
|
||||||
lcr3(PADDR(e->env_pgdir));
|
|
||||||
memcpy((void*) ph->p_va, binary + ph->p_offset, ph->p_filesz);
|
memcpy((void*) ph->p_va, binary + ph->p_offset, ph->p_filesz);
|
||||||
memset((void*) ph->p_va + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
|
memset((void*) ph->p_va + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
|
||||||
lcr3(PADDR(kern_pgdir));
|
|
||||||
}
|
}
|
||||||
|
lcr3(PADDR(kern_pgdir));
|
||||||
e->env_tf.tf_eip = elf->e_entry;
|
e->env_tf.tf_eip = elf->e_entry;
|
||||||
|
|
||||||
// Now map one page for the program's initial stack
|
// Now map one page for the program's initial stack
|
||||||
@@ -528,6 +529,7 @@ env_run(struct Env *e)
|
|||||||
e->env_status = ENV_RUNNING;
|
e->env_status = ENV_RUNNING;
|
||||||
e->env_runs++;
|
e->env_runs++;
|
||||||
lcr3(PADDR(e->env_pgdir));
|
lcr3(PADDR(e->env_pgdir));
|
||||||
|
unlock_kernel();
|
||||||
env_pop_tf(&e->env_tf);
|
env_pop_tf(&e->env_tf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
kern/init.c
14
kern/init.c
@@ -3,6 +3,7 @@
|
|||||||
#include <inc/stdio.h>
|
#include <inc/stdio.h>
|
||||||
#include <inc/string.h>
|
#include <inc/string.h>
|
||||||
#include <inc/assert.h>
|
#include <inc/assert.h>
|
||||||
|
#include <inc/x86.h>
|
||||||
|
|
||||||
#include <kern/monitor.h>
|
#include <kern/monitor.h>
|
||||||
#include <kern/console.h>
|
#include <kern/console.h>
|
||||||
@@ -17,6 +18,7 @@
|
|||||||
|
|
||||||
static void boot_aps(void);
|
static void boot_aps(void);
|
||||||
|
|
||||||
|
void sysenter_handler();
|
||||||
|
|
||||||
void
|
void
|
||||||
i386_init(void)
|
i386_init(void)
|
||||||
@@ -33,6 +35,10 @@ i386_init(void)
|
|||||||
"\33[34m" "r"
|
"\33[34m" "r"
|
||||||
"\33[0m" " Works!" "\n");
|
"\33[0m" " Works!" "\n");
|
||||||
|
|
||||||
|
write_msr(MSR_IA32_SYSENTER_EIP, (uint32_t) sysenter_handler, 0);
|
||||||
|
write_msr(MSR_IA32_SYSENTER_ESP, KSTACKTOP, 0);
|
||||||
|
write_msr(MSR_IA32_SYSENTER_CS, GD_KT, 0);
|
||||||
|
|
||||||
// Lab 2 memory management initialization functions
|
// Lab 2 memory management initialization functions
|
||||||
mem_init();
|
mem_init();
|
||||||
|
|
||||||
@@ -49,6 +55,7 @@ i386_init(void)
|
|||||||
|
|
||||||
// Acquire the big kernel lock before waking up APs
|
// Acquire the big kernel lock before waking up APs
|
||||||
// Your code here:
|
// Your code here:
|
||||||
|
lock_kernel();
|
||||||
|
|
||||||
// Starting non-boot CPUs
|
// Starting non-boot CPUs
|
||||||
boot_aps();
|
boot_aps();
|
||||||
@@ -58,7 +65,10 @@ i386_init(void)
|
|||||||
ENV_CREATE(TEST, ENV_TYPE_USER);
|
ENV_CREATE(TEST, ENV_TYPE_USER);
|
||||||
#else
|
#else
|
||||||
// Touch all you want.
|
// Touch all you want.
|
||||||
ENV_CREATE(user_primes, ENV_TYPE_USER);
|
ENV_CREATE(user_yield, ENV_TYPE_USER);
|
||||||
|
ENV_CREATE(user_yield, ENV_TYPE_USER);
|
||||||
|
ENV_CREATE(user_yield, ENV_TYPE_USER);
|
||||||
|
ENV_CREATE(user_yield, ENV_TYPE_USER);
|
||||||
#endif // TEST*
|
#endif // TEST*
|
||||||
|
|
||||||
// Schedule and run the first user environment!
|
// Schedule and run the first user environment!
|
||||||
@@ -115,6 +125,8 @@ mp_main(void)
|
|||||||
// only one CPU can enter the scheduler at a time!
|
// only one CPU can enter the scheduler at a time!
|
||||||
//
|
//
|
||||||
// Your code here:
|
// Your code here:
|
||||||
|
lock_kernel();
|
||||||
|
sched_yield();
|
||||||
|
|
||||||
// Remove this after you finish Exercise 6
|
// Remove this after you finish Exercise 6
|
||||||
for (;;);
|
for (;;);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <inc/assert.h>
|
#include <inc/assert.h>
|
||||||
#include <inc/x86.h>
|
#include <inc/x86.h>
|
||||||
|
|
||||||
|
#include <kern/env.h>
|
||||||
#include <kern/ansi.h>
|
#include <kern/ansi.h>
|
||||||
#include <kern/console.h>
|
#include <kern/console.h>
|
||||||
#include <kern/monitor.h>
|
#include <kern/monitor.h>
|
||||||
@@ -31,7 +32,9 @@ static struct Command commands[] = {
|
|||||||
{ "kerninfo", "Display information about the kernel", mon_kerninfo },
|
{ "kerninfo", "Display information about the kernel", mon_kerninfo },
|
||||||
{ "backtrace", "Display current backtrace", mon_backtrace },
|
{ "backtrace", "Display current backtrace", mon_backtrace },
|
||||||
{ "showmappings", "Display the physical mappings for range", mon_showmappings },
|
{ "showmappings", "Display the physical mappings for range", mon_showmappings },
|
||||||
{ "mperms", "Change the permissions of a memory range", mon_mperms }
|
{ "mperms", "Change the permissions of a memory range", mon_mperms },
|
||||||
|
{ "resume", "Resume from a breakpoint", mon_resume },
|
||||||
|
{ "step", "Step to next instruction", mon_step }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -188,6 +191,43 @@ int mon_mperms(int argc, char** argv, struct Trapframe* tf) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a nice thought and all...
|
||||||
|
// But we should modify the trap frame.
|
||||||
|
// I feel stupid.
|
||||||
|
static inline void
|
||||||
|
set_eflag(uint16_t flagno, int value) {
|
||||||
|
uint32_t temp;
|
||||||
|
uint32_t mask = ~(1 << flagno);
|
||||||
|
uint32_t regv = value << flagno;
|
||||||
|
asm volatile("pushfl\n\t"
|
||||||
|
"pop %w0\n\t"
|
||||||
|
"and %w1, %w0\n\t"
|
||||||
|
"or %w2, %w0\n\t"
|
||||||
|
"push %w0\n\t"
|
||||||
|
"popfl\n\t"
|
||||||
|
: "=r" (temp)
|
||||||
|
: "r" (mask), "r" (regv));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT_BRKPT if(!(tf->tf_trapno == T_BRKPT || tf->tf_trapno == T_DEBUG)) { \
|
||||||
|
cprintf(ACOL_ERR("I don't think I should resume from this.\n")); \
|
||||||
|
return 0; }
|
||||||
|
#define EFLAGS_TF 0x8
|
||||||
|
|
||||||
|
int mon_resume(int argc, char** argv, struct Trapframe* tf) {
|
||||||
|
EXPECT_BRKPT;
|
||||||
|
tf->tf_eflags &= ~(1 << EFLAGS_TF);
|
||||||
|
env_pop_tf(tf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mon_step(int argc, char** argv, struct Trapframe* tf) {
|
||||||
|
EXPECT_BRKPT;
|
||||||
|
tf->tf_eflags |= 1 << EFLAGS_TF;
|
||||||
|
env_pop_tf(tf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/***** Kernel monitor command interpreter *****/
|
/***** Kernel monitor command interpreter *****/
|
||||||
|
|
||||||
#define WHITESPACE "\t\r\n "
|
#define WHITESPACE "\t\r\n "
|
||||||
|
|||||||
@@ -17,5 +17,7 @@ int mon_kerninfo(int argc, char **argv, struct Trapframe *tf);
|
|||||||
int mon_backtrace(int argc, char **argv, struct Trapframe *tf);
|
int mon_backtrace(int argc, char **argv, struct Trapframe *tf);
|
||||||
int mon_showmappings(int argc, char **argv, struct Trapframe *tf);
|
int mon_showmappings(int argc, char **argv, struct Trapframe *tf);
|
||||||
int mon_mperms(int argc, char** argv, struct Trapframe* tf);
|
int mon_mperms(int argc, char** argv, struct Trapframe* tf);
|
||||||
|
int mon_resume(int argc, char** argv, struct Trapframe* tf);
|
||||||
|
int mon_step(int argc, char** argv, struct Trapframe* tf);
|
||||||
|
|
||||||
#endif // !JOS_KERN_MONITOR_H
|
#endif // !JOS_KERN_MONITOR_H
|
||||||
|
|||||||
26
kern/pmap.c
26
kern/pmap.c
@@ -187,8 +187,6 @@ mem_init(void)
|
|||||||
boot_map_region(kern_pgdir,
|
boot_map_region(kern_pgdir,
|
||||||
UPAGES, ROUNDUP(pages_size, PGSIZE),
|
UPAGES, ROUNDUP(pages_size, PGSIZE),
|
||||||
PADDR(pages), PTE_U);
|
PADDR(pages), PTE_U);
|
||||||
kern_pgdir[PDX(UPAGES)] |= PTE_U;
|
|
||||||
kern_pgdir[PDX(UPAGES)] &= ~PTE_W;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Map the 'envs' array read-only by the user at linear address UENVS
|
// Map the 'envs' array read-only by the user at linear address UENVS
|
||||||
@@ -197,11 +195,10 @@ mem_init(void)
|
|||||||
// - the new image at UENVS -- kernel R, user R
|
// - the new image at UENVS -- kernel R, user R
|
||||||
// - envs itself -- kernel RW, user NONE
|
// - envs itself -- kernel RW, user NONE
|
||||||
// LAB 3: Your code here.
|
// LAB 3: Your code here.
|
||||||
|
cprintf("Mapping envs from %p to %p\n", UENVS, ROUNDUP(envs_size, PGSIZE));
|
||||||
boot_map_region(kern_pgdir,
|
boot_map_region(kern_pgdir,
|
||||||
UENVS, ROUNDUP(envs_size, PGSIZE),
|
UENVS, ROUNDUP(envs_size, PGSIZE),
|
||||||
PADDR(envs), PTE_U);
|
PADDR(envs), PTE_U);
|
||||||
kern_pgdir[PDX(UENVS)] |= PTE_U;
|
|
||||||
kern_pgdir[PDX(UPAGES)] &= ~PTE_W;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Use the physical memory that 'bootstack' refers to as the kernel
|
// Use the physical memory that 'bootstack' refers to as the kernel
|
||||||
@@ -217,8 +214,6 @@ mem_init(void)
|
|||||||
boot_map_region(kern_pgdir,
|
boot_map_region(kern_pgdir,
|
||||||
KSTACKTOP-KSTKSIZE, KSTKSIZE,
|
KSTACKTOP-KSTKSIZE, KSTKSIZE,
|
||||||
PADDR(bootstack), PTE_W);
|
PADDR(bootstack), PTE_W);
|
||||||
kern_pgdir[PDX(KSTACKTOP-KSTKSIZE)] |= PTE_W;
|
|
||||||
kern_pgdir[PDX(KSTACKTOP-KSTKSIZE)] &= ~PTE_U;
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// Map all of physical memory at KERNBASE.
|
// Map all of physical memory at KERNBASE.
|
||||||
@@ -231,9 +226,6 @@ mem_init(void)
|
|||||||
boot_map_region(kern_pgdir,
|
boot_map_region(kern_pgdir,
|
||||||
KERNBASE, 0x100000000 - KERNBASE,
|
KERNBASE, 0x100000000 - KERNBASE,
|
||||||
0, PTE_W);
|
0, PTE_W);
|
||||||
kern_pgdir[PDX(KERNBASE)] |= PTE_W | PTE_P;
|
|
||||||
kern_pgdir[PDX(KERNBASE)] &= ~PTE_U;
|
|
||||||
|
|
||||||
|
|
||||||
// Initialize the SMP-related parts of the memory map
|
// Initialize the SMP-related parts of the memory map
|
||||||
mem_init_mp();
|
mem_init_mp();
|
||||||
@@ -285,6 +277,11 @@ mem_init_mp(void)
|
|||||||
// Permissions: kernel RW, user NONE
|
// Permissions: kernel RW, user NONE
|
||||||
//
|
//
|
||||||
// LAB 4: Your code here:
|
// LAB 4: Your code here:
|
||||||
|
for(int i = 0; i < NCPU; i++) {
|
||||||
|
uintptr_t kstacktop = KSTACKTOP - i * (KSTKSIZE + KSTKGAP);
|
||||||
|
boot_map_region(kern_pgdir, kstacktop - KSTKSIZE,
|
||||||
|
KSTKSIZE, PADDR(percpu_kstacks[i]), PTE_W);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,6 +295,7 @@ is_reserved(size_t pagenum) {
|
|||||||
if(pagenum == 0) return true;
|
if(pagenum == 0) return true;
|
||||||
if(pagenum >= PGNUM(IOPHYSMEM) &&
|
if(pagenum >= PGNUM(IOPHYSMEM) &&
|
||||||
pagenum < PGNUM(PADDR(boot_alloc(0)))) return true;
|
pagenum < PGNUM(PADDR(boot_alloc(0)))) return true;
|
||||||
|
if(pagenum == PGNUM(MPENTRY_PADDR)) return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -605,7 +603,15 @@ mmio_map_region(physaddr_t pa, size_t size)
|
|||||||
// Hint: The staff solution uses boot_map_region.
|
// Hint: The staff solution uses boot_map_region.
|
||||||
//
|
//
|
||||||
// Your code here:
|
// Your code here:
|
||||||
panic("mmio_map_region not implemented");
|
size = ROUNDUP(size, PGSIZE);
|
||||||
|
if((base + size) > MMIOLIM)
|
||||||
|
panic("Not enough memory-mapped IO space!");
|
||||||
|
|
||||||
|
boot_map_region(kern_pgdir, base, size, pa, PTE_PCD | PTE_PWT | PTE_W);
|
||||||
|
uintptr_t to_return = base;
|
||||||
|
base += size;
|
||||||
|
|
||||||
|
return (void*) to_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uintptr_t user_mem_check_addr;
|
static uintptr_t user_mem_check_addr;
|
||||||
|
|||||||
19
kern/sched.c
19
kern/sched.c
@@ -29,6 +29,23 @@ sched_yield(void)
|
|||||||
// below to halt the cpu.
|
// below to halt the cpu.
|
||||||
|
|
||||||
// LAB 4: Your code here.
|
// LAB 4: Your code here.
|
||||||
|
struct Env* next_env = curenv ? curenv + 1 : envs;
|
||||||
|
struct Env* end_env = envs + NENV;
|
||||||
|
struct Env* to_run = NULL;
|
||||||
|
|
||||||
|
for(int i = 0; i < NENV; i++, next_env++) {
|
||||||
|
if(next_env == end_env) next_env = envs;
|
||||||
|
if(next_env->env_status == ENV_RUNNABLE) {
|
||||||
|
to_run = next_env;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!to_run && curenv && curenv->env_status == ENV_RUNNING) {
|
||||||
|
to_run = curenv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(to_run) env_run(to_run);
|
||||||
|
|
||||||
// sched_halt never returns
|
// sched_halt never returns
|
||||||
sched_halt();
|
sched_halt();
|
||||||
@@ -76,7 +93,7 @@ sched_halt(void)
|
|||||||
"pushl $0\n"
|
"pushl $0\n"
|
||||||
// LAB 4:
|
// LAB 4:
|
||||||
// Uncomment the following line after completing exercise 13
|
// Uncomment the following line after completing exercise 13
|
||||||
//"sti\n"
|
"sti\n"
|
||||||
"1:\n"
|
"1:\n"
|
||||||
"hlt\n"
|
"hlt\n"
|
||||||
"jmp 1b\n"
|
"jmp 1b\n"
|
||||||
|
|||||||
147
kern/syscall.c
147
kern/syscall.c
@@ -80,9 +80,16 @@ sys_exofork(void)
|
|||||||
// status is set to ENV_NOT_RUNNABLE, and the register set is copied
|
// status is set to ENV_NOT_RUNNABLE, and the register set is copied
|
||||||
// from the current environment -- but tweaked so sys_exofork
|
// from the current environment -- but tweaked so sys_exofork
|
||||||
// will appear to return 0.
|
// will appear to return 0.
|
||||||
|
struct Env* new_env;
|
||||||
|
int error_code;
|
||||||
|
|
||||||
// LAB 4: Your code here.
|
error_code = env_alloc(&new_env, curenv->env_id);
|
||||||
panic("sys_exofork not implemented");
|
if(error_code < 0) return error_code;
|
||||||
|
|
||||||
|
new_env->env_tf = curenv->env_tf;
|
||||||
|
new_env->env_tf.tf_regs.reg_eax = 0;
|
||||||
|
new_env->env_status = ENV_NOT_RUNNABLE;
|
||||||
|
return new_env->env_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set envid's env_status to status, which must be ENV_RUNNABLE
|
// Set envid's env_status to status, which must be ENV_RUNNABLE
|
||||||
@@ -100,9 +107,17 @@ sys_env_set_status(envid_t envid, int status)
|
|||||||
// You should set envid2env's third argument to 1, which will
|
// You should set envid2env's third argument to 1, which will
|
||||||
// check whether the current environment has permission to set
|
// check whether the current environment has permission to set
|
||||||
// envid's status.
|
// envid's status.
|
||||||
|
struct Env* env;
|
||||||
|
int error_code;
|
||||||
|
|
||||||
// LAB 4: Your code here.
|
error_code = envid2env(envid, &env, 1);
|
||||||
panic("sys_env_set_status not implemented");
|
if(error_code < 0) return error_code;
|
||||||
|
|
||||||
|
if(status != ENV_RUNNABLE && status != ENV_NOT_RUNNABLE)
|
||||||
|
return -E_INVAL;
|
||||||
|
|
||||||
|
env->env_status = status;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the page fault upcall for 'envid' by modifying the corresponding struct
|
// Set the page fault upcall for 'envid' by modifying the corresponding struct
|
||||||
@@ -116,10 +131,18 @@ sys_env_set_status(envid_t envid, int status)
|
|||||||
static int
|
static int
|
||||||
sys_env_set_pgfault_upcall(envid_t envid, void *func)
|
sys_env_set_pgfault_upcall(envid_t envid, void *func)
|
||||||
{
|
{
|
||||||
// LAB 4: Your code here.
|
struct Env* env;
|
||||||
panic("sys_env_set_pgfault_upcall not implemented");
|
int return_code;
|
||||||
|
if((return_code = envid2env(envid, &env, 1)) < 0) return return_code;
|
||||||
|
env->env_pgfault_upcall = func;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SYS_CHECKPERMS(perm) \
|
||||||
|
((((perm) & (PTE_P | PTE_U)) == (PTE_P | PTE_U)) && \
|
||||||
|
(((perm) & ~(PTE_P | PTE_U | PTE_W | PTE_AVAIL)) == 0))
|
||||||
|
#define SYS_CHECKADDR(addr) (((uintptr_t) (addr) < UTOP) && ((uintptr_t) (addr) % PGSIZE == 0))
|
||||||
|
|
||||||
// Allocate a page of memory and map it at 'va' with permission
|
// Allocate a page of memory and map it at 'va' with permission
|
||||||
// 'perm' in the address space of 'envid'.
|
// 'perm' in the address space of 'envid'.
|
||||||
// The page's contents are set to 0.
|
// The page's contents are set to 0.
|
||||||
@@ -145,9 +168,22 @@ sys_page_alloc(envid_t envid, void *va, int perm)
|
|||||||
// parameters for correctness.
|
// parameters for correctness.
|
||||||
// If page_insert() fails, remember to free the page you
|
// If page_insert() fails, remember to free the page you
|
||||||
// allocated!
|
// allocated!
|
||||||
|
struct Env* env;
|
||||||
|
int return_code;
|
||||||
|
if((return_code = envid2env(envid, &env, 1)) < 0) return return_code;
|
||||||
|
|
||||||
// LAB 4: Your code here.
|
if(!SYS_CHECKPERMS(perm)) return -E_INVAL;
|
||||||
panic("sys_page_alloc not implemented");
|
if(!SYS_CHECKADDR(va)) return -E_INVAL;
|
||||||
|
|
||||||
|
struct PageInfo* page = page_alloc(1);
|
||||||
|
if(!page) return -E_NO_MEM;
|
||||||
|
|
||||||
|
if((return_code = page_insert(env->env_pgdir, page, va, perm)) < 0) {
|
||||||
|
page_free(page);
|
||||||
|
return return_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map the page of memory at 'srcva' in srcenvid's address space
|
// Map the page of memory at 'srcva' in srcenvid's address space
|
||||||
@@ -176,9 +212,24 @@ sys_page_map(envid_t srcenvid, void *srcva,
|
|||||||
// parameters for correctness.
|
// parameters for correctness.
|
||||||
// Use the third argument to page_lookup() to
|
// Use the third argument to page_lookup() to
|
||||||
// check the current permissions on the page.
|
// check the current permissions on the page.
|
||||||
|
struct Env *srcenv, *dstenv;
|
||||||
|
pte_t* srcpte;
|
||||||
|
int return_code;
|
||||||
|
|
||||||
// LAB 4: Your code here.
|
if((return_code = envid2env(srcenvid, &srcenv, 1)) < 0) return return_code;
|
||||||
panic("sys_page_map not implemented");
|
if((return_code = envid2env(dstenvid, &dstenv, 1)) < 0) return return_code;
|
||||||
|
|
||||||
|
if(!SYS_CHECKADDR(srcva)) return -E_INVAL;
|
||||||
|
if(!SYS_CHECKADDR(dstva)) return -E_INVAL;
|
||||||
|
if(!SYS_CHECKPERMS(perm)) return -E_INVAL;
|
||||||
|
|
||||||
|
struct PageInfo* page = page_lookup(srcenv->env_pgdir, srcva, &srcpte);
|
||||||
|
if(page == NULL) return -E_INVAL;
|
||||||
|
if(perm & PTE_W && !(*srcpte & PTE_W)) return -E_INVAL;
|
||||||
|
|
||||||
|
if((return_code = page_insert(dstenv->env_pgdir, page, dstva, perm)) < 0)
|
||||||
|
return return_code;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmap the page of memory at 'va' in the address space of 'envid'.
|
// Unmap the page of memory at 'va' in the address space of 'envid'.
|
||||||
@@ -192,9 +243,14 @@ static int
|
|||||||
sys_page_unmap(envid_t envid, void *va)
|
sys_page_unmap(envid_t envid, void *va)
|
||||||
{
|
{
|
||||||
// Hint: This function is a wrapper around page_remove().
|
// Hint: This function is a wrapper around page_remove().
|
||||||
|
struct Env* env;
|
||||||
|
int return_code;
|
||||||
|
|
||||||
// LAB 4: Your code here.
|
if((return_code = envid2env(envid, &env, 1)) < 0) return return_code;
|
||||||
panic("sys_page_unmap not implemented");
|
if(!SYS_CHECKADDR(va)) return -E_INVAL;
|
||||||
|
|
||||||
|
page_remove(env->env_pgdir, va);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to send 'value' to the target env 'envid'.
|
// Try to send 'value' to the target env 'envid'.
|
||||||
@@ -238,8 +294,38 @@ sys_page_unmap(envid_t envid, void *va)
|
|||||||
static int
|
static int
|
||||||
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
|
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
|
||||||
{
|
{
|
||||||
// LAB 4: Your code here.
|
struct Env* dest_env;
|
||||||
panic("sys_ipc_try_send not implemented");
|
struct Env* src_env;
|
||||||
|
int return_code;
|
||||||
|
|
||||||
|
if((return_code = envid2env(0, &src_env, 0)) < 0)
|
||||||
|
return return_code;
|
||||||
|
if((return_code = envid2env(envid, &dest_env, 0)) < 0)
|
||||||
|
return return_code;
|
||||||
|
|
||||||
|
if(!dest_env->env_ipc_recving)
|
||||||
|
return -E_IPC_NOT_RECV;
|
||||||
|
|
||||||
|
if((uintptr_t) srcva < UTOP && dest_env->env_ipc_dstva) {
|
||||||
|
if(!SYS_CHECKADDR(srcva)) return -E_INVAL;
|
||||||
|
if(!SYS_CHECKPERMS(perm)) return -E_INVAL;
|
||||||
|
|
||||||
|
pte_t* srcpte;
|
||||||
|
struct PageInfo* page = page_lookup(src_env->env_pgdir, srcva, &srcpte);
|
||||||
|
if(page == NULL) return -E_INVAL;
|
||||||
|
if(perm & PTE_W && !(*srcpte & PTE_W)) return -E_INVAL;
|
||||||
|
|
||||||
|
page_insert(dest_env->env_pgdir, page, dest_env->env_ipc_dstva, perm);
|
||||||
|
dest_env->env_ipc_perm = perm;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_env->env_ipc_from = src_env->env_id;
|
||||||
|
dest_env->env_ipc_value = value;
|
||||||
|
dest_env->env_ipc_recving = false;
|
||||||
|
if(dest_env->env_status == ENV_NOT_RUNNABLE)
|
||||||
|
dest_env->env_status = ENV_RUNNABLE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block until a value is ready. Record that you want to receive
|
// Block until a value is ready. Record that you want to receive
|
||||||
@@ -256,8 +342,20 @@ sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
|
|||||||
static int
|
static int
|
||||||
sys_ipc_recv(void *dstva)
|
sys_ipc_recv(void *dstva)
|
||||||
{
|
{
|
||||||
|
struct Env* env;
|
||||||
|
int return_code;
|
||||||
|
|
||||||
|
if((return_code = envid2env(0, &env, 1)) < 0)
|
||||||
|
return return_code;
|
||||||
|
|
||||||
// LAB 4: Your code here.
|
// LAB 4: Your code here.
|
||||||
panic("sys_ipc_recv not implemented");
|
if((uintptr_t) dstva < UTOP) {
|
||||||
|
if(!SYS_CHECKADDR(dstva)) return -E_INVAL;
|
||||||
|
env->env_ipc_dstva = dstva;
|
||||||
|
}
|
||||||
|
env->env_ipc_recving = true;
|
||||||
|
env->env_status = ENV_NOT_RUNNABLE;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +377,25 @@ syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
|
|||||||
return sys_getenvid();
|
return sys_getenvid();
|
||||||
case SYS_env_destroy:
|
case SYS_env_destroy:
|
||||||
return sys_env_destroy(a1);
|
return sys_env_destroy(a1);
|
||||||
|
case SYS_yield:
|
||||||
|
sys_yield();
|
||||||
|
return 0;
|
||||||
|
case SYS_exofork:
|
||||||
|
return sys_exofork();
|
||||||
|
case SYS_env_set_status:
|
||||||
|
return sys_env_set_status(a1, a2);
|
||||||
|
case SYS_env_set_pgfault_upcall:
|
||||||
|
return sys_env_set_pgfault_upcall(a1, (void*) a2);
|
||||||
|
case SYS_page_alloc:
|
||||||
|
return sys_page_alloc(a1, (void*) a2, a3);
|
||||||
|
case SYS_page_map:
|
||||||
|
return sys_page_map(a1, (void*) a2, a3, (void*) a4, a5);
|
||||||
|
case SYS_page_unmap:
|
||||||
|
return sys_page_unmap(a1, (void*) a2);
|
||||||
|
case SYS_ipc_try_send:
|
||||||
|
return sys_ipc_try_send(a1, a2, (void*) a3, a4);
|
||||||
|
case SYS_ipc_recv:
|
||||||
|
return sys_ipc_recv((void*) a1);
|
||||||
default:
|
default:
|
||||||
return -E_INVAL;
|
return -E_INVAL;
|
||||||
}
|
}
|
||||||
|
|||||||
62
kern/trap.c
62
kern/trap.c
@@ -89,6 +89,13 @@ void t_simderr();
|
|||||||
void t_syscall();
|
void t_syscall();
|
||||||
void t_default();
|
void t_default();
|
||||||
|
|
||||||
|
void irq_timer();
|
||||||
|
void irq_kbd();
|
||||||
|
void irq_serial();
|
||||||
|
void irq_spurious();
|
||||||
|
void irq_ide();
|
||||||
|
void irq_error();
|
||||||
|
|
||||||
void
|
void
|
||||||
trap_init(void)
|
trap_init(void)
|
||||||
{
|
{
|
||||||
@@ -125,6 +132,13 @@ trap_init(void)
|
|||||||
SETGATE(idt[T_SYSCALL], 0, GD_KT, t_syscall, 3);
|
SETGATE(idt[T_SYSCALL], 0, GD_KT, t_syscall, 3);
|
||||||
SETGATE(idt[T_DEFAULT], 0, GD_KT, t_default, 0);
|
SETGATE(idt[T_DEFAULT], 0, GD_KT, t_default, 0);
|
||||||
|
|
||||||
|
SETGATE(idt[IRQ_OFFSET + IRQ_TIMER], 0, GD_KT, irq_timer, 0);
|
||||||
|
SETGATE(idt[IRQ_OFFSET + IRQ_KBD], 0, GD_KT, irq_kbd, 0);
|
||||||
|
SETGATE(idt[IRQ_OFFSET + IRQ_SERIAL], 0, GD_KT, irq_serial, 0);
|
||||||
|
SETGATE(idt[IRQ_OFFSET + IRQ_SPURIOUS], 0, GD_KT, irq_spurious, 0);
|
||||||
|
SETGATE(idt[IRQ_OFFSET + IRQ_IDE], 0, GD_KT, irq_ide, 0);
|
||||||
|
SETGATE(idt[IRQ_OFFSET + IRQ_ERROR], 0, GD_KT, irq_error, 0);
|
||||||
|
|
||||||
// Per-CPU setup
|
// Per-CPU setup
|
||||||
trap_init_percpu();
|
trap_init_percpu();
|
||||||
}
|
}
|
||||||
@@ -160,18 +174,18 @@ trap_init_percpu(void)
|
|||||||
|
|
||||||
// Setup a TSS so that we get the right stack
|
// Setup a TSS so that we get the right stack
|
||||||
// when we trap to the kernel.
|
// when we trap to the kernel.
|
||||||
ts.ts_esp0 = KSTACKTOP;
|
thiscpu->cpu_ts.ts_esp0 = KSTACKTOP - thiscpu->cpu_id * (KSTKSIZE + KSTKGAP);
|
||||||
ts.ts_ss0 = GD_KD;
|
thiscpu->cpu_ts.ts_ss0 = GD_KD;
|
||||||
ts.ts_iomb = sizeof(struct Taskstate);
|
thiscpu->cpu_ts.ts_iomb = sizeof(struct Taskstate);
|
||||||
|
|
||||||
// Initialize the TSS slot of the gdt.
|
// Initialize the TSS slot of the gdt.
|
||||||
gdt[GD_TSS0 >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
|
gdt[(GD_TSS0 >> 3) + cpunum()] = SEG16(STS_T32A, (uint32_t) (&thiscpu->cpu_ts),
|
||||||
sizeof(struct Taskstate) - 1, 0);
|
sizeof(struct Taskstate) - 1, 0);
|
||||||
gdt[GD_TSS0 >> 3].sd_s = 0;
|
gdt[(GD_TSS0 >> 3) + cpunum()].sd_s = 0;
|
||||||
|
|
||||||
// Load the TSS selector (like other segment selectors, the
|
// Load the TSS selector (like other segment selectors, the
|
||||||
// bottom three bits are special; we leave them 0)
|
// bottom three bits are special; we leave them 0)
|
||||||
ltr(GD_TSS0);
|
ltr(GD_TSS0 + (cpunum() << 3));
|
||||||
|
|
||||||
// Load the IDT
|
// Load the IDT
|
||||||
lidt(&idt_pd);
|
lidt(&idt_pd);
|
||||||
@@ -231,7 +245,7 @@ trap_dispatch(struct Trapframe *tf)
|
|||||||
if (tf->tf_trapno == T_PGFLT) {
|
if (tf->tf_trapno == T_PGFLT) {
|
||||||
page_fault_handler(tf);
|
page_fault_handler(tf);
|
||||||
return;
|
return;
|
||||||
} else if (tf->tf_trapno == T_BRKPT) {
|
} else if (tf->tf_trapno == T_BRKPT || tf->tf_trapno == T_DEBUG) {
|
||||||
monitor(tf);
|
monitor(tf);
|
||||||
return;
|
return;
|
||||||
} else if (tf->tf_trapno == T_SYSCALL) {
|
} else if (tf->tf_trapno == T_SYSCALL) {
|
||||||
@@ -243,6 +257,9 @@ trap_dispatch(struct Trapframe *tf)
|
|||||||
tf->tf_regs.reg_esi);
|
tf->tf_regs.reg_esi);
|
||||||
tf->tf_regs.reg_eax = returned;
|
tf->tf_regs.reg_eax = returned;
|
||||||
return;
|
return;
|
||||||
|
} else if (tf->tf_trapno == IRQ_OFFSET + IRQ_TIMER) {
|
||||||
|
lapic_eoi();
|
||||||
|
sched_yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle spurious interrupts
|
// Handle spurious interrupts
|
||||||
@@ -294,6 +311,7 @@ trap(struct Trapframe *tf)
|
|||||||
// Acquire the big kernel lock before doing any
|
// Acquire the big kernel lock before doing any
|
||||||
// serious kernel work.
|
// serious kernel work.
|
||||||
// LAB 4: Your code here.
|
// LAB 4: Your code here.
|
||||||
|
lock_kernel();
|
||||||
assert(curenv);
|
assert(curenv);
|
||||||
|
|
||||||
// Garbage collect if current enviroment is a zombie
|
// Garbage collect if current enviroment is a zombie
|
||||||
@@ -373,11 +391,39 @@ page_fault_handler(struct Trapframe *tf)
|
|||||||
// (the 'tf' variable points at 'curenv->env_tf').
|
// (the 'tf' variable points at 'curenv->env_tf').
|
||||||
|
|
||||||
// LAB 4: Your code here.
|
// LAB 4: Your code here.
|
||||||
|
if(!curenv->env_pgfault_upcall) {
|
||||||
// Destroy the environment that caused the fault.
|
// Destroy the environment that caused the fault.
|
||||||
cprintf("[%08x] user fault va %08x ip %08x\n",
|
cprintf("[%08x] user fault va %08x ip %08x\n",
|
||||||
curenv->env_id, fault_va, tf->tf_eip);
|
curenv->env_id, fault_va, tf->tf_eip);
|
||||||
print_trapframe(tf);
|
print_trapframe(tf);
|
||||||
env_destroy(curenv);
|
env_destroy(curenv);
|
||||||
|
}
|
||||||
|
user_mem_assert(curenv, curenv->env_pgfault_upcall, 1, PTE_U | PTE_P);
|
||||||
|
user_mem_assert(curenv, (void*) UXSTACKTOP - 1, 1, PTE_U | PTE_P | PTE_W);
|
||||||
|
|
||||||
|
uintptr_t top_addr = UXSTACKTOP;
|
||||||
|
if(tf->tf_esp <= UXSTACKTOP && tf->tf_esp >= (UXSTACKTOP - PGSIZE)) {
|
||||||
|
top_addr = tf->tf_esp - 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UTrapframe utf;
|
||||||
|
utf.utf_eflags = tf->tf_eflags;
|
||||||
|
utf.utf_eip = tf->tf_eip;
|
||||||
|
utf.utf_err = tf->tf_err;
|
||||||
|
utf.utf_esp = tf->tf_esp;
|
||||||
|
utf.utf_fault_va = fault_va;
|
||||||
|
utf.utf_regs = tf->tf_regs;
|
||||||
|
|
||||||
|
struct UTrapframe* push_to = (struct UTrapframe*) top_addr - 1;
|
||||||
|
if((uintptr_t) push_to < USTACKTOP - PGSIZE) {
|
||||||
|
cprintf("[%08x] stack overflow in page fault handler\n",
|
||||||
|
curenv->env_id);
|
||||||
|
env_destroy(curenv);
|
||||||
|
}
|
||||||
|
|
||||||
|
*push_to = utf;
|
||||||
|
curenv->env_tf.tf_eip = (uintptr_t) curenv->env_pgfault_upcall;
|
||||||
|
curenv->env_tf.tf_esp = (uintptr_t) push_to;
|
||||||
|
env_run(curenv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,21 @@
|
|||||||
|
|
||||||
.text
|
.text
|
||||||
|
|
||||||
|
.globl sysenter_handler
|
||||||
|
sysenter_handler:
|
||||||
|
push %ebp // holds env's stack pointer
|
||||||
|
push %esi // holds the env's return addr
|
||||||
|
push %edi
|
||||||
|
push %ebx
|
||||||
|
push %ecx
|
||||||
|
push %edx
|
||||||
|
push %eax
|
||||||
|
call syscall
|
||||||
|
add $0x14, %esp
|
||||||
|
pop %edx
|
||||||
|
pop %ecx
|
||||||
|
sysexit
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lab 3: Your code here for generating entry points for the different traps.
|
* Lab 3: Your code here for generating entry points for the different traps.
|
||||||
*/
|
*/
|
||||||
@@ -67,6 +82,12 @@ TRAPHANDLER_NOEC(t_mchk, T_MCHK);
|
|||||||
TRAPHANDLER_NOEC(t_simderr, T_SIMDERR);
|
TRAPHANDLER_NOEC(t_simderr, T_SIMDERR);
|
||||||
TRAPHANDLER_NOEC(t_syscall, T_SYSCALL);
|
TRAPHANDLER_NOEC(t_syscall, T_SYSCALL);
|
||||||
TRAPHANDLER(t_default, T_DEFAULT);
|
TRAPHANDLER(t_default, T_DEFAULT);
|
||||||
|
TRAPHANDLER_NOEC(irq_timer, IRQ_OFFSET + IRQ_TIMER);
|
||||||
|
TRAPHANDLER_NOEC(irq_kbd, IRQ_OFFSET + IRQ_KBD);
|
||||||
|
TRAPHANDLER_NOEC(irq_serial, IRQ_OFFSET + IRQ_SERIAL);
|
||||||
|
TRAPHANDLER_NOEC(irq_spurious, IRQ_OFFSET + IRQ_SPURIOUS);
|
||||||
|
TRAPHANDLER_NOEC(irq_ide, IRQ_OFFSET + IRQ_IDE);
|
||||||
|
TRAPHANDLER_NOEC(irq_error, IRQ_OFFSET + IRQ_ERROR);
|
||||||
|
|
||||||
// HINT 1 : TRAPHANDLER_NOEC(t_divide, T_DIVIDE);
|
// HINT 1 : TRAPHANDLER_NOEC(t_divide, T_DIVIDE);
|
||||||
// Do something like this if there is no error code for the trap
|
// Do something like this if there is no error code for the trap
|
||||||
|
|||||||
75
lib/fork.c
75
lib/fork.c
@@ -23,18 +23,22 @@ pgfault(struct UTrapframe *utf)
|
|||||||
// Hint:
|
// Hint:
|
||||||
// Use the read-only page table mappings at uvpt
|
// Use the read-only page table mappings at uvpt
|
||||||
// (see <inc/memlayout.h>).
|
// (see <inc/memlayout.h>).
|
||||||
|
if(!((err & FEC_WR) && (uvpt[(uintptr_t) addr >> PGSHIFT] & PTE_COW)))
|
||||||
// LAB 4: Your code here.
|
panic("page fault (addr %p)! %c", addr, (err & FEC_WR) ? 'w' : 'r');
|
||||||
|
|
||||||
// Allocate a new page, map it at a temporary location (PFTEMP),
|
// 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
|
// copy the data from the old page to the new page, then move the new
|
||||||
// page to the old page's address.
|
// page to the old page's address.
|
||||||
// Hint:
|
// Hint:
|
||||||
// You should make three system calls.
|
// You should make three system calls.
|
||||||
|
void* temp_addr = (void*) PFTEMP;
|
||||||
|
void* fault_addr = ROUNDDOWN(addr, PGSIZE);
|
||||||
|
if(sys_page_alloc(0, temp_addr, PTE_P | PTE_W | PTE_U) < 0)
|
||||||
|
panic("failed to allocate new page");
|
||||||
|
|
||||||
// LAB 4: Your code here.
|
memcpy(temp_addr, fault_addr, PGSIZE);
|
||||||
|
sys_page_map(0, temp_addr, 0, fault_addr, PTE_P | PTE_U | PTE_W);
|
||||||
panic("pgfault not implemented");
|
sys_page_unmap(0, temp_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -52,9 +56,27 @@ static int
|
|||||||
duppage(envid_t envid, unsigned pn)
|
duppage(envid_t envid, unsigned pn)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
bool change_own = false;
|
||||||
|
pte_t new_pte = uvpt[pn];
|
||||||
|
pte_t perms = new_pte & (PTE_P | PTE_U | PTE_W | PTE_AVAIL);
|
||||||
|
void* addr = (void*) (pn * PGSIZE);
|
||||||
|
|
||||||
|
// If we're writable, remove write permission
|
||||||
|
if((new_pte & PTE_W) || (new_pte & PTE_COW)) {
|
||||||
|
perms = (perms & ~PTE_W) | PTE_COW;
|
||||||
|
change_own = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map either with the same permissions or with COW.
|
||||||
|
if((r = sys_page_map(0, addr, envid, addr, perms)) < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
// Update our own permissions if necessary
|
||||||
|
if(change_own) {
|
||||||
|
if((r = sys_page_map(0, addr, 0, addr, perms)) < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
// LAB 4: Your code here.
|
|
||||||
panic("duppage not implemented");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,8 +99,43 @@ duppage(envid_t envid, unsigned pn)
|
|||||||
envid_t
|
envid_t
|
||||||
fork(void)
|
fork(void)
|
||||||
{
|
{
|
||||||
// LAB 4: Your code here.
|
set_pgfault_handler(pgfault);
|
||||||
panic("fork not implemented");
|
|
||||||
|
int return_code;
|
||||||
|
envid_t forked;
|
||||||
|
|
||||||
|
forked = sys_exofork();
|
||||||
|
if(forked < 0) return forked;
|
||||||
|
if(forked == 0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; }
|
||||||
|
|
||||||
|
// Map all accessible page directory entries
|
||||||
|
for(int pde_i = 0; pde_i < PDX(UTOP); pde_i++) {
|
||||||
|
pde_t pde = uvpd[pde_i];
|
||||||
|
if(!(pde & PTE_P)) continue;
|
||||||
|
|
||||||
|
// For each PDE, map all the underlying PTEs
|
||||||
|
for(int pte_i = 0; pte_i < NPTENTRIES; pte_i++) {
|
||||||
|
int pn = pde_i * NPTENTRIES + pte_i;
|
||||||
|
pte_t pte = uvpt[pn];
|
||||||
|
if(!(pte & PTE_P)) continue;
|
||||||
|
|
||||||
|
// Do not map user exception stack, though
|
||||||
|
if(pn == ((UXSTACKTOP - PGSIZE) >> PGSHIFT)) continue;
|
||||||
|
|
||||||
|
if((return_code = duppage(forked, pn)) < 0) return return_code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate new page for the exception stack
|
||||||
|
return_code = sys_page_alloc(forked, (void*) UXSTACKTOP - PGSIZE,
|
||||||
|
PTE_P | PTE_U | PTE_W);
|
||||||
|
if(return_code < 0) return return_code;
|
||||||
|
|
||||||
|
// Set the upcall entry point
|
||||||
|
sys_env_set_pgfault_upcall(forked, thisenv->env_pgfault_upcall);
|
||||||
|
sys_env_set_status(forked, ENV_RUNNABLE);
|
||||||
|
|
||||||
|
return forked;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Challenge!
|
// Challenge!
|
||||||
|
|||||||
19
lib/ipc.c
19
lib/ipc.c
@@ -22,9 +22,14 @@
|
|||||||
int32_t
|
int32_t
|
||||||
ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)
|
ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)
|
||||||
{
|
{
|
||||||
// LAB 4: Your code here.
|
int return_code;
|
||||||
panic("ipc_recv not implemented");
|
if((return_code = sys_ipc_recv(pg ? pg : (void*) ~0)) < 0)
|
||||||
return 0;
|
return return_code;
|
||||||
|
|
||||||
|
if(from_env_store) *from_env_store = thisenv->env_ipc_from;
|
||||||
|
if(perm_store) *perm_store = thisenv->env_ipc_perm;
|
||||||
|
|
||||||
|
return thisenv->env_ipc_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send 'val' (and 'pg' with 'perm', if 'pg' is nonnull) to 'toenv'.
|
// Send 'val' (and 'pg' with 'perm', if 'pg' is nonnull) to 'toenv'.
|
||||||
@@ -38,8 +43,12 @@ ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)
|
|||||||
void
|
void
|
||||||
ipc_send(envid_t to_env, uint32_t val, void *pg, int perm)
|
ipc_send(envid_t to_env, uint32_t val, void *pg, int perm)
|
||||||
{
|
{
|
||||||
// LAB 4: Your code here.
|
int return_code = -E_IPC_NOT_RECV;
|
||||||
panic("ipc_send not implemented");
|
while(return_code == -E_IPC_NOT_RECV) {
|
||||||
|
return_code = sys_ipc_try_send(to_env, val, pg ? pg : (void*) ~0, perm);
|
||||||
|
sys_yield();
|
||||||
|
}
|
||||||
|
if(return_code != 0) panic("failed to send\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the first environment of the given type. We'll use this to
|
// Find the first environment of the given type. We'll use this to
|
||||||
|
|||||||
@@ -65,18 +65,29 @@ _pgfault_upcall:
|
|||||||
// ways as registers become unavailable as scratch space.
|
// ways as registers become unavailable as scratch space.
|
||||||
//
|
//
|
||||||
// LAB 4: Your code here.
|
// LAB 4: Your code here.
|
||||||
|
mov 40(%esp), %eax // Take the EIP from memory
|
||||||
|
mov 48(%esp), %ebp // Take the ESP from memory
|
||||||
|
sub $4, %ebp // Push onto trap-time ESP
|
||||||
|
mov %eax, (%ebp)
|
||||||
|
mov %ebp, 48(%esp) // Put ESP back
|
||||||
|
|
||||||
// Restore the trap-time registers. After you do this, you
|
// Restore the trap-time registers. After you do this, you
|
||||||
// can no longer modify any general-purpose registers.
|
// can no longer modify any general-purpose registers.
|
||||||
// LAB 4: Your code here.
|
// LAB 4: Your code here.
|
||||||
|
add $0x8, %esp
|
||||||
|
popal
|
||||||
|
|
||||||
// Restore eflags from the stack. After you do this, you can
|
// Restore eflags from the stack. After you do this, you can
|
||||||
// no longer use arithmetic operations or anything else that
|
// no longer use arithmetic operations or anything else that
|
||||||
// modifies eflags.
|
// modifies eflags.
|
||||||
// LAB 4: Your code here.
|
// LAB 4: Your code here.
|
||||||
|
add $0x4, %esp
|
||||||
|
popfl
|
||||||
|
|
||||||
// Switch back to the adjusted trap-time stack.
|
// Switch back to the adjusted trap-time stack.
|
||||||
// LAB 4: Your code here.
|
// LAB 4: Your code here.
|
||||||
|
pop %esp
|
||||||
|
|
||||||
// Return to re-execute the instruction that faulted.
|
// Return to re-execute the instruction that faulted.
|
||||||
// LAB 4: Your code here.
|
// LAB 4: Your code here.
|
||||||
|
ret
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ set_pgfault_handler(void (*handler)(struct UTrapframe *utf))
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (_pgfault_handler == 0) {
|
if (_pgfault_handler == 0) {
|
||||||
// First time through!
|
if(sys_page_alloc(0, (void*) UXSTACKTOP - PGSIZE, PTE_U | PTE_P | PTE_W) < 0)
|
||||||
// LAB 4: Your code here.
|
panic("set_pgfault_handler");
|
||||||
panic("set_pgfault_handler not implemented");
|
sys_env_set_pgfault_upcall(0, _pgfault_upcall);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save handler pointer for assembly to call.
|
// Save handler pointer for assembly to call.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <inc/syscall.h>
|
#include <inc/syscall.h>
|
||||||
#include <inc/lib.h>
|
#include <inc/lib.h>
|
||||||
|
#include <inc/x86.h>
|
||||||
|
|
||||||
static inline int32_t
|
static inline int32_t
|
||||||
syscall(int num, int check, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
|
syscall(int num, int check, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
|
||||||
@@ -37,6 +38,20 @@ syscall(int num, int check, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
fast_syscall(int num, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4) {
|
||||||
|
asm volatile(
|
||||||
|
"push %%ebp\n\t"
|
||||||
|
"mov %%esp, %%ebp\n\t"
|
||||||
|
"lea syscall_ret_%=, %%esi\n\t"
|
||||||
|
"sysenter\n\t"
|
||||||
|
"syscall_ret_%=: pop %%ebp\n\t"
|
||||||
|
: "+a" (num)
|
||||||
|
: "d" (a1), "c" (a2), "b" (a3), "D" (a4)
|
||||||
|
: "esi");
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sys_cputs(const char *s, size_t len)
|
sys_cputs(const char *s, size_t len)
|
||||||
{
|
{
|
||||||
|
|||||||
9
user/getc.c
Normal file
9
user/getc.c
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include <inc/lib.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
umain(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
while(!(c = sys_cgetc()));
|
||||||
|
cprintf("got character %c\n", c);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user