diff --git a/inc/kern/process.h b/inc/kern/process.h index cfab044..e56237f 100644 --- a/inc/kern/process.h +++ b/inc/kern/process.h @@ -60,7 +60,7 @@ typedef union u_proc { // kern/main.c extern PROCESS *p_proc_ready; /* pcb表 */ -#define PCB_SIZE 3 +#define PCB_SIZE 2 // kern/main.c extern PROCESS proc_table[]; diff --git a/inc/kern/syscall.h b/inc/kern/syscall.h index 2668e21..3496181 100644 --- a/inc/kern/syscall.h +++ b/inc/kern/syscall.h @@ -22,4 +22,6 @@ ssize_t do_get_pid(void); ssize_t do_read(int fd, void *buf, size_t count); ssize_t do_write(int fd, const void *buf, size_t count); ssize_t do_delay_ticks(u32 ticks); +ssize_t do_mmap(int pid, void *src, void* dst, size_t length); + #endif /* MINIOS_KERN_SYSCALL_H */ \ No newline at end of file diff --git a/inc/syscall.h b/inc/syscall.h index cf67177..d07ff57 100644 --- a/inc/syscall.h +++ b/inc/syscall.h @@ -7,5 +7,6 @@ #define _NR_read 2 #define _NR_write 3 #define _NR_delay_ticks 4 +#define _NR_mmap 5 #endif /* MINIOS_SYSCALL_H */ diff --git a/inc/user/syscall.h b/inc/user/syscall.h index e5e4169..114dac6 100644 --- a/inc/user/syscall.h +++ b/inc/user/syscall.h @@ -16,4 +16,6 @@ ssize_t get_pid(); ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); ssize_t delay_ticks(u32 ticks); +ssize_t lml_mmap(int pid, void* src, void* dst, size_t length); + #endif \ No newline at end of file diff --git a/kern/main.c b/kern/main.c index 1d67a67..aacf410 100644 --- a/kern/main.c +++ b/kern/main.c @@ -12,6 +12,7 @@ #include #include #include +#include // 标志着内核是否处理完成 bool init_kernel; @@ -19,31 +20,27 @@ bool init_kernel; // 指向当前进程pcb的指针 PROCESS *p_proc_ready; // pcb表 -PROCESS proc_table[PCB_SIZE]; +PROCESS proc_table[PCB_SIZE]; static inline void init_segment_regs(PROCESS *p_proc) { - p_proc->pcb.user_regs.cs = (SELECTOR_FLAT_C & SA_RPL_MASK & SA_TI_MASK) - | SA_TIL | RPL_USER; - p_proc->pcb.user_regs.ds = (SELECTOR_FLAT_RW & SA_RPL_MASK & SA_TI_MASK) - | SA_TIL | RPL_USER; - p_proc->pcb.user_regs.es = (SELECTOR_FLAT_RW & SA_RPL_MASK & SA_TI_MASK) - | SA_TIL | RPL_USER; - p_proc->pcb.user_regs.fs = (SELECTOR_FLAT_RW & SA_RPL_MASK & SA_TI_MASK) - | SA_TIL | RPL_USER; - p_proc->pcb.user_regs.ss = (SELECTOR_FLAT_RW & SA_RPL_MASK & SA_TI_MASK) - | SA_TIL | RPL_USER; - p_proc->pcb.user_regs.gs = (SELECTOR_VIDEO & SA_RPL_MASK & SA_TI_MASK) - | RPL_USER; + p_proc->pcb.user_regs.cs = (SELECTOR_FLAT_C & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_USER; + p_proc->pcb.user_regs.ds = (SELECTOR_FLAT_RW & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_USER; + p_proc->pcb.user_regs.es = (SELECTOR_FLAT_RW & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_USER; + p_proc->pcb.user_regs.fs = (SELECTOR_FLAT_RW & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_USER; + p_proc->pcb.user_regs.ss = (SELECTOR_FLAT_RW & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_USER; + p_proc->pcb.user_regs.gs = (SELECTOR_VIDEO & SA_RPL_MASK & SA_TI_MASK) | RPL_USER; } static inline void -lml_map(phyaddr_t cr3, uintptr_t vaddr, phyaddr_t paddr, u32 flags) { +lml_map(phyaddr_t cr3, uintptr_t vaddr, phyaddr_t paddr, u32 flags) +{ uintptr_t *pde_ptr = (uintptr_t *)K_PHY2LIN(cr3); // get pdx item, pde_ptr + PDX(vaddr) pde_ptr += PDX(vaddr); - if (!(*pde_ptr & PTE_P)) { + if (!(*pde_ptr & PTE_P)) + { // pdx ot exists, allocate a page and assign to pde *pde_ptr = phy_malloc_4k() | PTE_P | flags; } @@ -64,7 +61,8 @@ void kernel_main(void) PROCESS *p_proc = proc_table; - for (int i = 0 ; i < PCB_SIZE ; i++, p_proc++) { + for (int i = 0; i < PCB_SIZE; i++, p_proc++) + { // 初始化进程段寄存器 init_segment_regs(p_proc); // 为进程分配cr3物理内存 @@ -76,13 +74,15 @@ void kernel_main(void) // 如果不先map_kern,执行流会发现执行的代码的线性地址不存在爆出Page Fault // 当然选不选择看个人的想法,评价是都行,各有各的优缺点 // lcr3(p_proc->pcb.cr3); - + static char filename[PCB_SIZE][12] = { // "TESTPID BIN", - // "TESTKEY BIN", - "DELAY BIN", - "DELAY BIN", - "DELAY BIN", + // "TESTKEY BIN", + // "DELAY BIN", + // "DELAY BIN", + // "DELAY BIN", + "SNAKE BIN", + "HACK BIN", }; // 从磁盘中将文件读出,需要注意的是要满足短目录项的文件名长度11, // 前八个为文件名,后三个为后缀名,跟BootLoader做法一致 @@ -90,44 +90,49 @@ void kernel_main(void) read_file(filename[i], (void *)K_PHY2LIN(48 * MB)); // 现在你就需要将从磁盘中读出的ELF文件解析到用户进程的地址空间中 // panic("unimplement! load elf file"); -// ---------------------------- load elf -------------------------------------- - void * elf_start = (void *)K_PHY2LIN(48 * MB); - assert(*(u32*)elf_start == ELF_MAGIC); - Elf32_Ehdr* ehdr = (Elf32_Ehdr*) elf_start; - for (int i = 0; i < ehdr->e_phnum; ++ i) { - Elf32_Phdr* phdr = elf_start + i * ehdr->e_phentsize + ehdr->e_phoff; - if (phdr->p_type == PT_LOAD) { - u32 vpage_fst = phdr->p_va & (~0xfff); // clear low 12 bit, start of the first pg + // ---------------------------- load elf -------------------------------------- + void *elf_start = (void *)K_PHY2LIN(48 * MB); + assert(*(u32 *)elf_start == ELF_MAGIC); + Elf32_Ehdr *ehdr = (Elf32_Ehdr *)elf_start; + for (int i = 0; i < ehdr->e_phnum; ++i) + { + Elf32_Phdr *phdr = elf_start + i * ehdr->e_phentsize + ehdr->e_phoff; + if (phdr->p_type == PT_LOAD) + { + u32 vpage_fst = phdr->p_va & (~0xfff); // clear low 12 bit, start of the first pg u32 vpage_lst = (phdr->p_va + phdr->p_memsz - 1) & (~0xfff); // start of the last pg - // in fact, we allocate 4k aligned vpage to every segment; + // in fact, we allocate 4k aligned vpage to every segment; // its ok because elf32 segment align is 0x1000 u32 page_num = ((vpage_lst - vpage_fst) >> 12) + 1; phyaddr_t newpage = 0; // useless initialization - for (int j = 0; j < page_num; ++ j) { + for (int j = 0; j < page_num; ++j) + { newpage = phy_malloc_4k(); lml_map(p_proc->pcb.cr3, vpage_fst + (j << 12), newpage, PTE_P | PTE_W | PTE_U); } phyaddr_t page_start = newpage - (page_num - 1) * 4 * KB; - memcpy((void*)K_PHY2LIN(page_start), (void*)(elf_start + phdr->p_offset), phdr->p_filesz); - memset((void*)K_PHY2LIN(page_start) + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); + memcpy((void *)K_PHY2LIN(page_start), (void *)(elf_start + phdr->p_offset), phdr->p_filesz); + memset((void *)K_PHY2LIN(page_start) + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz); } } // 上一个实验中,我们开栈是用内核中的一个数组临时充当栈 // 但是现在就不行了,用户是无法访问内核的地址空间(3GB ~ 3GB + 128MB) // 需要你自行处理给用户分配用户栈。 -// ---------------------------- alloc user stack ------------------------------ + // ---------------------------- alloc user stack ------------------------------ phyaddr_t ustack_low = phy_malloc_4k(); - for (int i = 0; i < 6; ++ i) phy_malloc_4k(); + for (int i = 0; i < 6; ++i) + phy_malloc_4k(); phyaddr_t ustack_high = phy_malloc_4k(); // alloc 8 pages, 32KB stack for each program - for (int i = 0; i < 8; ++ i) { - lml_map(p_proc->pcb.cr3, (3*GB - (8-i)*PGSIZE), ustack_low + i*PGSIZE, PTE_P | PTE_W | PTE_U); + for (int i = 0; i < 8; ++i) + { + lml_map(p_proc->pcb.cr3, (3 * GB - (8 - i) * PGSIZE), ustack_low + i * PGSIZE, PTE_P | PTE_W | PTE_U); } - p_proc->pcb.user_regs.esp = 3*GB; // high to low stack + p_proc->pcb.user_regs.esp = 3 * GB; // high to low stack p_proc->pcb.user_regs.eip = ehdr->e_entry; // refer to restart: // 初始化用户寄存器 p_proc->pcb.user_regs.eflags = 0x1202; /* IF=1, IOPL=1 */ - + // panic("unimplement! init user stack and esp"); // 接下来初始化内核寄存器, // 为什么需要初始化内核寄存器原因是加入了系统调用后 @@ -146,7 +151,7 @@ void kernel_main(void) // 初始化其余量 p_proc->pcb.pid = i; - static int priority_table[PCB_SIZE] = {1, 1, 1}; + static int priority_table[PCB_SIZE] = {1, 1}; // priority 预计给每个进程分配的时间片 // ticks 进程剩余的进程片 p_proc->pcb.priority = p_proc->pcb.ticks = priority_table[i]; @@ -157,11 +162,55 @@ void kernel_main(void) // 切换进程页表和tss lcr3(p_proc_ready->pcb.cr3); tss.esp0 = (u32)(&p_proc_ready->pcb.user_regs + 1); - + init_kernel = true; - + // 开个无用的kern_context存当前执行流的寄存器上下文(之后就没用了,直接放在临时变量中) struct kern_context idle; switch_kern_context(&idle, &p_proc_ready->pcb.kern_regs); assert(0); +} + +static inline void +sys_mmap(phyaddr_t cr3_src, phyaddr_t cr3_dst, uintptr_t va_src, uintptr_t va_dst) +{ + uintptr_t *pde_ptr_src = (uintptr_t *)K_PHY2LIN(cr3_src); + uintptr_t *pde_ptr_dst = (uintptr_t *)K_PHY2LIN(cr3_dst); + // its quite okay, kernel space is mapped to all processes + pde_ptr_src += PDX(va_src); + pde_ptr_dst += PDX(va_dst); + assert((*pde_ptr_dst & PTE_P) && (*pde_ptr_src & PTE_P)); + // it is not a map procedure, so pde should be present + uintptr_t *pte_ptr_src = (uintptr_t *)K_PHY2LIN(*pde_ptr_src & (~0xfff)); + uintptr_t *pte_ptr_dst = (uintptr_t *)K_PHY2LIN(*pde_ptr_dst & (~0xfff)); + pte_ptr_src += PTX(va_src); + pte_ptr_dst += PTX(va_dst); + assert((*pte_ptr_dst & PTE_P) && (*pte_ptr_src & PTE_P)); + // make should page table entry also exists + *pte_ptr_dst = *pte_ptr_src; + // simple assign src to dst, no need to recycle, though should be +} + +#define PG_MASK 0x0fff // 12bit mask + +ssize_t do_mmap(int pid, void *src, void *dst, size_t length) +{ + if ((length & PG_MASK) || ((u32)src & PG_MASK) || ((u32)dst & PG_MASK)) + { + // make sure src,dst,len are 4K aligned + assert(0); + return -1; + } + if (pid > PCB_SIZE) + { + assert(0); + return -1; + } + disable_int(); + for (int off = 0; off < length; off += PGSIZE) + { + sys_mmap(proc_table[pid].pcb.cr3, p_proc_ready->pcb.cr3, (uintptr_t)src + off, (uintptr_t)dst + off); + } + enable_int(); + return 0; } \ No newline at end of file diff --git a/kern/syscall.c b/kern/syscall.c index 92bba56..3906d32 100644 --- a/kern/syscall.c +++ b/kern/syscall.c @@ -10,6 +10,7 @@ static ssize_t sys_get_pid(void); static ssize_t sys_read(void); static ssize_t sys_write(void); static ssize_t sys_delay_ticks(void); +static ssize_t sys_mmap(void); ssize_t (*syscall_table[])(void) = { [_NR_get_ticks] sys_get_ticks, @@ -17,6 +18,7 @@ ssize_t (*syscall_table[])(void) = { [_NR_read] sys_read, [_NR_write] sys_write, [_NR_delay_ticks] sys_delay_ticks, +[_NR_mmap] sys_mmap, }; /* @@ -90,4 +92,14 @@ sys_write(void) static ssize_t sys_delay_ticks(void) { return do_delay_ticks(get_arg(0)); +} + +/* + * ssize_t do_mmap(int pid, void *src, void* dst, size_t length); + * 将pid号进程的线性地址[src, src + length)中的页面共享到该进程的线性地址[dst, dst + length) + */ + +static ssize_t +sys_mmap(void) { + return do_mmap(get_arg(0), (void*)get_arg(1), (void*)get_arg(2), get_arg(3)); } \ No newline at end of file diff --git a/lib/user/syscall.c b/lib/user/syscall.c index ad5f5f7..e698dfd 100644 --- a/lib/user/syscall.c +++ b/lib/user/syscall.c @@ -119,4 +119,9 @@ ssize_t delay_ticks(u32 ticks) { return syscall1(_NR_delay_ticks, ticks); +} + +ssize_t lml_mmap(int pid, void* src, void* dst, size_t length) +{ + return syscall4(_NR_mmap, pid, (size_t)src, (size_t)dst, length); } \ No newline at end of file diff --git a/user/Makefrag b/user/Makefrag index e12a7ac..8716dd9 100644 --- a/user/Makefrag +++ b/user/Makefrag @@ -13,6 +13,7 @@ USER_LIBOBJS := $(patsubst %.asm, $(OBJDIR)/%.o, $(USER_LIBOBJS)) USER_SRCS := user/testpid.c \ user/testkey.c \ user/delay.c \ + user/hack.c \ user/snake.bin \ USER_OBJS := $(patsubst %.c, $(OBJDIR)/%.o, $(USER_SRCS)) diff --git a/user/hack.c b/user/hack.c new file mode 100644 index 0000000..6a9611f --- /dev/null +++ b/user/hack.c @@ -0,0 +1,38 @@ +#include +#include +#include + +#define PID_SNAKE 0 +#define PAGE_SIZE 4096 +#define DATA_SEG_SIZE (4 * PAGE_SIZE) + +typedef struct Food { + char hint[16]; + int x; + int y; + int score; +} Food; + +char __attribute__((aligned(0x1000))) snake_seg_data[DATA_SEG_SIZE]; +// this attribute is necessary to make the pointer 4K aligned +int main() +{ + Food* food = NULL; + lml_mmap(PID_SNAKE, (void*)0x0804d000, (void*)snake_seg_data, DATA_SEG_SIZE); + // data segment: + // Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + // LOAD 0x004000 0x0804d000 0x0804d000 0x0163c 0x12500 RW 0x1000 + // 'This is a food' starts @ file offset 0x542c, while .data starts @ 0x4000 + // so, offset is 0x142c + food = (Food*)(snake_seg_data + 0x142c); + // printf("%s\n", food->hint); + while (1) { + // printf("%d %d", food->x, food->y); + if (food->x <= 0) food->x = 1; + if (food->y <= 0) food->y = 1; + if (food->x >= 70) food->x = 69; + if (food->y >= 25) food->y = 24; + // according to some trial, XMAX(right veritcal line border)=69, YMAX(low edge of screen)=24 + } + return 0; +} \ No newline at end of file