lab5 extra task ok

This commit is contained in:
ridethepig 2022-11-04 13:57:40 +08:00
parent f13d09f336
commit 32b816a4e1
9 changed files with 153 additions and 43 deletions

View File

@ -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[];

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -12,6 +12,7 @@
#include <kern/process.h>
#include <kern/protect.h>
#include <kern/trap.h>
#include <kern/syscall.h>
// 标志着内核是否处理完成
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;
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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))

38
user/hack.c Normal file
View File

@ -0,0 +1,38 @@
#include <assert.h>
#include <user/stdio.h>
#include <user/syscall.h>
#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;
}