diff --git a/lab6/bootloader/include/utils.h b/lab6/bootloader/include/utils.h index acd33ddc2..be983f494 100644 --- a/lab6/bootloader/include/utils.h +++ b/lab6/bootloader/include/utils.h @@ -1,6 +1,20 @@ #ifndef _UTILS_H #define _UTILS_H +// Reference from https://elixir.bootlin.com/linux/latest/source/tools/lib/perf/mmap.c#L299 +#define read_sysreg(r) ({ \ + uint64_t __val; \ + asm volatile("mrs %0, " #r : "=r" (__val)); \ + __val; \ +}) + +// Reference from https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/asm/sysreg.h#L1281 +#define write_sysreg(r, v) do { \ + uint64_t __val = (uint64_t)(v); \ + asm volatile("msr " #r ", %x0" \ + : : "rZ" (__val)); \ +} while (0) + extern void delay ( unsigned long); extern void put32 ( unsigned long, unsigned int ); extern unsigned int get32 ( unsigned long ); diff --git a/lab6/bootloader/src/mini_uart.c b/lab6/bootloader/src/mini_uart.c index 55f6b7e4c..6c77c79e0 100644 --- a/lab6/bootloader/src/mini_uart.c +++ b/lab6/bootloader/src/mini_uart.c @@ -1,6 +1,7 @@ #include "utils.h" #include "peripherals/mini_uart.h" #include "peripherals/gpio.h" +#include void uart_send ( char c ) { @@ -39,10 +40,10 @@ void uart_send_string(char* str) } } -void uart_hex(unsigned int d) { +void uart_hex(uint64_t d) { unsigned int n; int c; - for (c = 28; c >= 0; c -= 4) { + for (c = 60; c >= 0; c -= 4) { // get highest tetrad n = (d >> c) & 0xF; // 0-9 => '0'-'9', 10-15 => 'A'-'F' diff --git a/lab6/include/alloc.h b/lab6/include/alloc.h index 0b182a695..499682b79 100644 --- a/lab6/include/alloc.h +++ b/lab6/include/alloc.h @@ -1,8 +1,9 @@ #ifndef _ALLOC_H_ #define _ALLOC_H_ +#include "utils.h" -#define PAGE_BASE (void*)0x0 -#define PAGE_END (void*)0x3b400000 +#define PAGE_BASE (void*)PA2VA(0x0) +#define PAGE_END (void*)PA2VA(0x3b400000) #define PAGE_SIZE 0x1000 // 4KB #define MAX_ORDER 11 diff --git a/lab6/include/exec.h b/lab6/include/exec.h new file mode 100644 index 000000000..650cff151 --- /dev/null +++ b/lab6/include/exec.h @@ -0,0 +1,7 @@ +#ifndef _EXEC_H +#define _EXEC_H + +void exec_user_prog(void *entry, char *user_sp, char *kernel_sp); +void enter_el0_run_user_prog(void *entry, char *user_sp); + +#endif /* _EXEC_H */ \ No newline at end of file diff --git a/lab6/include/initrd.h b/lab6/include/initrd.h index 59f088984..cef7e4927 100644 --- a/lab6/include/initrd.h +++ b/lab6/include/initrd.h @@ -35,5 +35,5 @@ void initrd_callback(unsigned int node_type, char *name, void *value, unsigned i void initrd_exec_prog(char* target); void initrd_exec_syscall(); void initrd_run_syscall(); -void exec_user_prog (); + #endif // INITRD_H \ No newline at end of file diff --git a/lab6/include/mbox.h b/lab6/include/mbox.h index 6a05d1782..b5f3c5ef9 100644 --- a/lab6/include/mbox.h +++ b/lab6/include/mbox.h @@ -1,8 +1,10 @@ #ifndef _MBOX_H #define _MBOX_H +#include "utils.h" + #define MMIO_BASE 0x3f000000 -#define MAILBOX_BASE MMIO_BASE + 0xb880 +#define MAILBOX_BASE PA2VA(MMIO_BASE + 0xb880) #define MAILBOX_READ (unsigned int*)(MAILBOX_BASE) #define MAILBOX_STATUS (unsigned int*)(MAILBOX_BASE + 0x18) diff --git a/lab6/include/mini_uart.h b/lab6/include/mini_uart.h index 83c9d42e9..e209c8d34 100644 --- a/lab6/include/mini_uart.h +++ b/lab6/include/mini_uart.h @@ -3,13 +3,15 @@ #define BUFFER_SIZE 1024 +#include + void uart_init ( void ); void uart_enable_interrupt( void ); void uart_disable_interrupt( void ); char uart_recv ( void ); void uart_send ( char c ); void uart_send_string(const char* str); -void uart_hex(unsigned int d); +void uart_hex(uint64_t d); void uart_irq_handler(void); char uart_async_recv( void ); void uart_async_send_string(const char* buffer); diff --git a/lab6/include/mmu.h b/lab6/include/mmu.h new file mode 100644 index 000000000..d4e1c05d5 --- /dev/null +++ b/lab6/include/mmu.h @@ -0,0 +1,24 @@ +#ifndef _MMU_H +#define _MMU_H + + +#define PAGE_TABLE_SIZE 0x1000 + +#define PT_R 0x0001 +#define PT_W 0x0002 +#define PT_X 0x0004 + +#include + +/* + * Set identity paging, enable MMU + */ +void mmu_init(void); + +uint64_t *pt_create(void); +void pt_free(uint64_t *pt); + +void pt_map(uint64_t *pt, void *va, uint64_t size, void *pa, uint64_t flag); + + +#endif /* _MMU_H */ \ No newline at end of file diff --git a/lab6/include/thread.h b/lab6/include/thread.h index 8a3b24a1b..f9b025b58 100644 --- a/lab6/include/thread.h +++ b/lab6/include/thread.h @@ -2,7 +2,7 @@ #define _THREAD_H -#define T_STACK_SIZE (2 * 0x1000) // 2^12 = 4096 = 4KB = 1 page +#define T_STACK_SIZE (4 * 0x1000) // 2^12 = 4096 = 4KB = 1 page #define SIGNAL_NUM 9 #include @@ -33,8 +33,10 @@ typedef struct callee_reg_t { typedef struct thread_t { // need to be put as the first variable callee_reg_t callee_reg; + uint64_t *page_table; int tid; // thread id thread_state state; + void* user_stack; void* kernel_stack; void* data; @@ -46,6 +48,7 @@ typedef struct thread_t { int waiting_signal[SIGNAL_NUM+1]; int is_processing_signal; callee_reg_t signal_regs; + uint64_t signal_page_table; // use in queue struct thread_t *prev; diff --git a/lab6/include/utils.h b/lab6/include/utils.h new file mode 100644 index 000000000..87cbc6467 --- /dev/null +++ b/lab6/include/utils.h @@ -0,0 +1,42 @@ +#ifndef _UTILS_H +#define _UTILS_H + + +#include + +#define PA2VA(x) (((uint64_t)(x)) | 0xffff000000000000) +#define VA2PA(x) (((uint64_t)(x)) & 0x0000ffffffffffff) +#define ALIGN(num, base) ((num + base - 1) & ~(base - 1)) + + +// Reference from https://elixir.bootlin.com/linux/latest/source/tools/lib/perf/mmap.c#L299 +#define read_sysreg(r) ({ \ + uint64_t __val; \ + asm volatile("mrs %0, " #r : "=r" (__val)); \ + __val; \ +}) + +// Reference from https://elixir.bootlin.com/linux/latest/source/arch/arm64/include/asm/sysreg.h#L1281 +#define write_sysreg(r, v) do { \ + uint64_t __val = (uint64_t)(v); \ + asm volatile("msr " #r ", %x0" \ + : : "rZ" (__val)); \ +} while (0) + +#define set_page_table(thread) do { \ + asm volatile( \ + "mov x9, %0\n" \ + "and x9, x9, #0x0000ffffffffffff\n" \ + "dsb ish\n" \ + "msr ttbr0_el1, x9\n" \ + "tlbi vmalle1is\n" \ + "dsb ish\n" \ + "isb\n" \ + :: "r" (thread->page_table) \ + ); \ +} while (0) + +extern void put32 ( unsigned long, unsigned int ); +extern unsigned int get32 ( unsigned long ); + +#endif /*_UTILS_H */ diff --git a/lab6/initramfs.cpio b/lab6/initramfs.cpio index 0676fb158..06cb275e0 100644 Binary files a/lab6/initramfs.cpio and b/lab6/initramfs.cpio differ diff --git a/lab6/src/alloc.c b/lab6/src/alloc.c index c231259bb..5bbd80677 100644 --- a/lab6/src/alloc.c +++ b/lab6/src/alloc.c @@ -3,6 +3,7 @@ #include "fdt.h" #include "initrd.h" #include "exception.h" +#include "utils.h" #include int debug = 1; @@ -13,6 +14,9 @@ volatile char *heap_top; page* page_arr = 0; uint64_t total_page = 0; +// free_list_t* free_list = 0; +// chunk_info* chunk_info_arr = 0; + free_list_t free_list[MAX_ORDER + 1]; chunk_info chunk_info_arr[MAX_CHUNK + 1]; @@ -296,6 +300,9 @@ void insert_page(page* new_page, int order) { if (free_list[order].head != 0) { free_list[order].head -> prev = new_page; } + if(!new_page){ + uart_send_string("Error: insert_page with new_page = 0\n"); + } free_list[order].head = new_page; free_list[order].cnt++; return; @@ -309,10 +316,10 @@ page* pop_page(int order) { while(1); } page* ret = free_list[order].head; - free_list[order].head = ret->next; if (free_list[order].head -> next != 0) { - free_list[order].head -> prev = 0; + free_list[order].head -> next -> prev = 0; } + free_list[order].head = ret->next; free_list[order].cnt--; return ret; } @@ -430,21 +437,24 @@ void* chunk_free(void* addr) { // Set heap base address void alloc_init() { - heap_top = ((volatile unsigned char *)(0x10000000)); + + heap_top = ((volatile unsigned char *)PA2VA(0x10000000)); char* old_heap_top = heap_top; + // free_list = PA2VA(simple_malloc((MAX_ORDER + 1) * sizeof(free_list_t))); + // chunk_info_arr = PA2VA(simple_malloc((MAX_CHUNK + 1) * sizeof(chunk_info))); // uart_send_string("heap_top: "); // uart_hex((unsigned long long)heap_top); // uart_send_string("\n"); init_page_arr(); // reserve memory - memory_reserve((void*)0x0000, (void*)0x1000); // spin tables + memory_reserve((void*)PA2VA(0x0000), (void*)PA2VA(0x4000)); // spin tables and page tables memory_reserve((void*)ramfs_base, (void*)ramfs_end); // ramfs // memory_reserve((void*)dtb_base, (void*)dtb_end); // dtb // kernel, bss, stack // 0x80000 = _start // 0x0200000 = __stack_end - memory_reserve((void*)0x80000, (void*)0x0200000); + memory_reserve((void*)PA2VA(0x80000), (void*)PA2VA(0x0200000)); if(debug) { uart_send_string("old_heap_top: "); @@ -555,7 +565,7 @@ void* kmalloc(unsigned long long size) { int idx = size2chunkidx(size); void* addr; - int use_page_only = 0; + int use_page_only = 1; if(use_page_only) { addr = page_alloc(size); } else if(idx >= 0) { diff --git a/lab6/src/boot.S b/lab6/src/boot.S index 596e47891..0c698c1ae 100644 --- a/lab6/src/boot.S +++ b/lab6/src/boot.S @@ -1,4 +1,5 @@ #include "mm.h" + #define CORE0_TIMER_IRQ_CTRL 0x40000040 .section ".text.boot" @@ -17,14 +18,15 @@ proc_hang: master: bl from_el2_to_el1 -// core_timer_enable: -// mov x20, 1 -// msr cntp_ctl_el0, x20 // enable timer -// mrs x20, cntfrq_el0 -// msr cntp_tval_el0, x20 // set expired time -// mov x20, 2 -// ldr x1, =CORE0_TIMER_IRQ_CTRL -// str w20, [x1] // unmask timer interrupt + ldr x1, =__PA_stack_end + mov sp, x1 + mov x19, x0 + bl mmu_init + mov x0, x19 + ldr x1, =boot_rest + br x1 + +boot_rest: set_exception_vector: // set exception vector table diff --git a/lab6/src/context_switch.S b/lab6/src/context_switch.S index 467c1c9dc..5a93ae49f 100644 --- a/lab6/src/context_switch.S +++ b/lab6/src/context_switch.S @@ -17,7 +17,19 @@ switch_to: ldp fp, lr, [x1, 16 * 5] ldr x9, [x1, 16 * 6] mov sp, x9 + msr tpidr_el1, x1 + + // switch page table + ldr x9, [x1, 8 * 13] // page_table in thread_t + and x9, x9, #0x0000ffffffffffff + dsb ish // ensure write has completed + msr ttbr0_el1, x9 // switch translation based address. + tlbi vmalle1is // invalidate all TLB entries + dsb ish // ensure completion of TLB invalidatation + isb // clear pipeline + + ret diff --git a/lab6/src/exception.c b/lab6/src/exception.c index b67d2c6e1..8389b1fc7 100644 --- a/lab6/src/exception.c +++ b/lab6/src/exception.c @@ -10,6 +10,7 @@ #include "thread.h" #include "reboot.h" #include "signal.h" +#include "utils.h" extern timer_t *timer_head; @@ -56,8 +57,8 @@ void exception_handler_c() { void user_irq_exception_handler_c() { // uart_send_string("User IRQ Exception Occurs!\n"); el1_interrupt_disable(); - unsigned int irq = *IRQ_PENDING_1; - unsigned int interrupt_source = *CORE0_INTERRUPT_SOURCE; + unsigned int irq = get32(PA2VA(IRQ_PENDING_1)); + unsigned int interrupt_source = get32(PA2VA(CORE0_INTERRUPT_SOURCE)); if((irq & IRQ_PENDING_1_AUX_INT) && (interrupt_source & INTERRUPT_SOURCE_GPU)){ // uart_send_string("UART interrupt\n"); @@ -74,8 +75,8 @@ void user_irq_exception_handler_c() { void irq_exception_handler_c(){ // uart_send_string("IRQ Exception Occurs!\n"); - unsigned int irq = *IRQ_PENDING_1; - unsigned int interrupt_source = *CORE0_INTERRUPT_SOURCE; + unsigned int irq = get32(PA2VA(IRQ_PENDING_1)); + unsigned int interrupt_source = get32(PA2VA(CORE0_INTERRUPT_SOURCE)); if((irq & IRQ_PENDING_1_AUX_INT) && (interrupt_source & INTERRUPT_SOURCE_GPU) ){ // uart_send_string("kernel UART interrupt\n"); @@ -93,7 +94,15 @@ void irq_exception_handler_c(){ } void user_exception_handler_c(trapframe_t* tf) { + unsigned long long esr_el1 = 0; + asm volatile("mrs %0, esr_el1":"=r"(esr_el1)); + unsigned ec = (esr_el1 >> 26) & 0x3F; + if(ec != 0x15) { + exception_handler_c(); + return; + } int syscall_code = tf -> x[8]; + el1_interrupt_enable(); switch (syscall_code) { case 0: @@ -120,6 +129,7 @@ void user_exception_handler_c(trapframe_t* tf) { exit(0); break; case 6: + uart_send_string("[INFO] system call: mbox_call\n"); tf -> x[0] = mbox_call( (unsigned char)tf -> x[0], (unsigned int*)tf -> x[1] ); @@ -137,6 +147,7 @@ void user_exception_handler_c(trapframe_t* tf) { sigreturn(); break; } + el1_interrupt_disable(); return; } @@ -200,6 +211,7 @@ void core_timer_init() { asm volatile("msr cntp_tval_el0, %0" : : "r"(freq)); *CORE0_TIMER_IRQ_CTRL = 2; + uint64_t tmp; asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); @@ -208,9 +220,9 @@ void core_timer_init() { } void core_timer_enable(){ - *CORE0_TIMER_IRQ_CTRL = 2; + put32(PA2VA(CORE0_TIMER_IRQ_CTRL), 2); } void core_timer_disable() { - *CORE0_TIMER_IRQ_CTRL = 0; + put32(PA2VA(CORE0_TIMER_IRQ_CTRL), 0); } \ No newline at end of file diff --git a/lab6/src/exec.S b/lab6/src/exec.S new file mode 100644 index 000000000..8f10058ed --- /dev/null +++ b/lab6/src/exec.S @@ -0,0 +1,39 @@ + +.globl enter_el0_run_user_prog +enter_el0_run_user_prog: + // Set exception return address + msr elr_el1, x0 + + // Set user stack + msr sp_el0, x1 + + // Enable interrupt ({D, A, I, F} = 0 (unmasked)) + // EL0 ({M[3:0]} = 0) + mov x0, 0 + msr spsr_el1, x0 + + // TODO: Clear all general registers + + // return to EL0 + eret + +.globl exec_user_prog +exec_user_prog: + // Set exception return address + msr elr_el1, x0 + + // Set user stack + msr sp_el0, x1 + + // Enable interrupt ({D, A, I, F} = 0 (unmasked)) + // EL0 ({M[3:0]} = 0) + mov x0, 0 + msr spsr_el1, x0 + + // Set kernel stack + mov sp, x2 + + // TODO: Clear all general registers + + // return to EL0 + eret \ No newline at end of file diff --git a/lab6/src/initrd.c b/lab6/src/initrd.c index 5d05f71e8..c558e3265 100644 --- a/lab6/src/initrd.c +++ b/lab6/src/initrd.c @@ -8,11 +8,24 @@ #include "thread.h" #include "exception.h" #include "timer.h" +#include "utils.h" +#include "mmu.h" +#include "exec.h" char *ramfs_base; char *ramfs_end; +void enter_el0_run_user_prog(void *entry, char *user_sp); + +static void user_prog_start(void) +{ + uart_send_string("User program start\n"); + enter_el0_run_user_prog((void *)0, (char *)0xffffffffeff0); + + // User program should call exit() to terminate +} + // Convert hexadecimal string to int // @param s: hexadecimal string // @param n: string length @@ -157,12 +170,14 @@ void initrd_cat(const char *target) void initrd_callback(unsigned int node_type, char *name, void *value, unsigned int name_size){ if(!strcmp(name, "linux,initrd-start")){ ramfs_base = (char *)(unsigned long long)endian_big2little(*(unsigned int *)value); + ramfs_base = (char *)PA2VA(ramfs_base); uart_send_string("ramfs_base: "); uart_hex((unsigned long)ramfs_base); uart_send_string("\n"); } if(!strcmp(name, "linux,initrd-end")){ ramfs_end = (char *)(unsigned long long)endian_big2little(*(unsigned int *)value); + ramfs_end = (char *)PA2VA(ramfs_end); uart_send_string("ramfs_end: "); uart_hex((unsigned long)ramfs_end); uart_send_string("\n"); @@ -234,16 +249,20 @@ void initrd_exec_syscall() { char *filepath; char *filedata; unsigned int filesize; - char* target = "syscall.img"; + char* target = "vm.img"; + thread_t* t = get_current_thread(); + uart_send_string("current thread tid: "); + uart_hex(t -> tid); + uart_send_string("\n"); // current pointer cpio_t *header_pointer = (cpio_t *)(ramfs_base); // print_running(); // print every cpio pathname while (header_pointer) { - // uart_send_string("header_pointer: "); - // uart_hex((unsigned long)header_pointer); - // uart_send_string("\n"); + uart_send_string("header_pointer: "); + uart_hex((unsigned long)header_pointer); + uart_send_string("\n"); int error = cpio_newc_parse_header(header_pointer, &filepath, &filesize, &filedata, &header_pointer); // if parse header error if (error) @@ -257,9 +276,10 @@ void initrd_exec_syscall() { uart_send_string("filesize: "); uart_hex(filesize); uart_send_string("\n"); - target_addr = kmalloc(filesize); + t -> data = (void*)kmalloc(filesize); + t -> data_size = filesize; uart_send_string("Copying user program\n"); - memcpy(target_addr, filedata, filesize); + memcpy(t -> data, filedata, t -> data_size); uart_send_string("Finished\n"); break; } @@ -268,14 +288,13 @@ void initrd_exec_syscall() { // uart_send_string("\n"); // if this is not TRAILER!!! (last of file) if (header_pointer == 0){ - uart_send_string("Program not found\n"); + // uart_send_string("Program not found\n"); return; } } uart_send_string("prog addr: "); - uart_hex(target_addr); + uart_hex(t->data); uart_send_string("\n"); - thread_t* t = get_current_thread(); uart_send_string("thread tid: "); uart_hex(t -> tid); uart_send_string("\n"); @@ -286,26 +305,42 @@ void initrd_exec_syscall() { } unsigned long spsr_el1 = 0x0; // run in el0 and enable all interrupt (DAIF) - unsigned long elr_el1 = target_addr; - unsigned long user_sp = t -> user_stack + T_STACK_SIZE; + unsigned long elr_el1 = 0x0; unsigned long kernel_sp = (unsigned long)t -> kernel_stack + T_STACK_SIZE; // unsigned long kernel_sp = (unsigned long)kmalloc(T_STACK_SIZE) + T_STACK_SIZE; - // reset t call reg - t -> callee_reg.lr = target_addr; - // core_timer_enable(); - // el1_interrupt_enable(); + // t -> callee_reg.lr = user_prog_start; + t -> page_table = pt_create(); + pt_map(t -> page_table, (void*)0, t -> data_size, + (void*)VA2PA(t -> data), PT_R | PT_W | PT_X); // map user program + pt_map(t -> page_table, (void*)0xffffffffb000, T_STACK_SIZE, + (void*)VA2PA(t -> user_stack), PT_R | PT_W); // map user stack + + pt_map(t->page_table, (void *)0x3c000000, 0x04000000, + (void *)0x3c000000, PT_R | PT_W); // map mailbox - asm volatile("msr spsr_el1, %0" : : "r" (spsr_el1)); - asm volatile("msr elr_el1, %0" : : "r" (elr_el1)); - asm volatile("msr sp_el0, %0" : : "r" (user_sp)); - asm volatile("mov sp, %0" :: "r" (kernel_sp)); - // print_running(); + uart_send_string("page table addr: "); + uart_hex(t -> page_table); + uart_send_string("\n"); + + set_page_table(t); core_timer_enable(); // el1_interrupt_enable(); - asm volatile("eret"); // jump to user program - // print_running(); + uart_send_string("exec user prog\n"); + exec_user_prog((void *)0, (char *)0xffffffffeff0, kernel_sp); + // return; + // // core_timer_enable(); + // // el1_interrupt_enable(); + + // asm volatile("msr spsr_el1, %0" : : "r" (spsr_el1)); + // asm volatile("msr elr_el1, %0" : : "r" (elr_el1)); + // asm volatile("msr sp_el0, %0" : : "r" (user_sp)); + // asm volatile("mov sp, %0" :: "r" (kernel_sp)); + // // print_running(); + // // el1_interrupt_enable(); + // asm volatile("eret"); // jump to user program + // // print_running(); } void initrd_run_syscall() { diff --git a/lab6/src/kernel.c b/lab6/src/kernel.c index 991d96633..f9ce3ffd7 100644 --- a/lab6/src/kernel.c +++ b/lab6/src/kernel.c @@ -7,6 +7,7 @@ #include "exception.h" #include "thread.h" #include "timer.h" +#include "utils.h" #include #define TEST_SIZE 30 @@ -46,14 +47,14 @@ void demo_mm() { } void main(char* base) { - dtb_base = base; + dtb_base = PA2VA(base); uart_init(); uart_send_string("DTB base address: "); uart_hex(dtb_base); uart_send_string("\n"); fdt_traverse(initrd_callback); alloc_init(); - // demo_mm(); + // for(int i=0;i<1000;i++) kmalloc(PAGE_SIZE); uart_send_string("mm finished\n"); uart_enable_interrupt(); core_timer_init(); diff --git a/lab6/src/linker.ld b/lab6/src/linker.ld index bd7ba3352..6db10ceb8 100644 --- a/lab6/src/linker.ld +++ b/lab6/src/linker.ld @@ -1,7 +1,8 @@ SECTIONS { - . = 0x80000; + . = 0xffff000000000000; + . += 0x80000; .text : { KEEP(*(.text.boot)) @@ -17,5 +18,6 @@ SECTIONS bss_end = .; } } -__bss_size = (bss_end - bss_begin)>>3; -__stack_end = 0x0200000; \ No newline at end of file +__bss_size = (bss_end - bss_begin)>>3; +__stack_end = 0xffff000000200000; +__PA_stack_end = 0x0000000000200000; \ No newline at end of file diff --git a/lab6/src/mbox.c b/lab6/src/mbox.c index ef7eb085b..4c421aa15 100644 --- a/lab6/src/mbox.c +++ b/lab6/src/mbox.c @@ -1,24 +1,24 @@ #include "mbox.h" #include "mini_uart.h" - +#include "utils.h" int mailbox_call(unsigned char ch, unsigned int* mailbox){ unsigned int r = (((unsigned long) mailbox) & ~0xF) | (ch & 0xf); // ~0xF is used to clear the last 4 bits of the address // 8 is used to set the last 4 bits to 8 (channel 8 is the mailbox channel) - while(*MAILBOX_STATUS & MAILBOX_FULL){ + while(get32(PA2VA(MAILBOX_STATUS)) & MAILBOX_FULL){ delay(1); } // wait until the mailbox is not full - *MAILBOX_WRITE = r; + put32(PA2VA(MAILBOX_WRITE), r); // write the address of the mailbox message to the mailbox write register (channel 8 is the mailbox channel while(1){ - while(*MAILBOX_STATUS & MAILBOX_EMPTY){ + while(get32(PA2VA(MAILBOX_STATUS)) & MAILBOX_EMPTY){ delay(1); } // wait until the mailbox is not empty - if(r == *MAILBOX_READ){ + if(r == get32(PA2VA(MAILBOX_READ))){ return mailbox[1] == REQUEST_SUCCEED; } } diff --git a/lab6/src/mini_uart.c b/lab6/src/mini_uart.c index 63e7585e8..ab3b9bb69 100644 --- a/lab6/src/mini_uart.c +++ b/lab6/src/mini_uart.c @@ -5,6 +5,7 @@ #include "peripherals/gpio.h" #include "peripherals/irq.h" #include "tasklist.h" +#include "utils.h" char uart_read_buffer[BUFFER_SIZE]; char uart_write_buffer[BUFFER_SIZE]; @@ -18,19 +19,19 @@ void uart_send ( char c ) if (c == '\n') uart_send('\r'); while(1) { - if(*AUX_MU_LSR_REG&0x20) + if(get32(PA2VA(AUX_MU_LSR_REG))&0x20) break; } - *AUX_MU_IO_REG = c; + put32(PA2VA(AUX_MU_IO_REG),c); } char uart_recv ( void ) { while(1) { - if(*AUX_MU_LSR_REG&0x01) + if(get32(PA2VA(AUX_MU_LSR_REG))&0x01) break; } - return(*AUX_MU_IO_REG); + return(get32(PA2VA(AUX_MU_IO_REG))); } void uart_send_string(const char* str) @@ -43,13 +44,13 @@ void uart_send_string(const char* str) void irq_uart_rx_exception() { if((uart_read_index + 1) % BUFFER_SIZE == uart_read_head) { // buffer is full, discard the data - unsigned int ier = *AUX_MU_IER_REG; + unsigned int ier = get32(PA2VA(AUX_MU_IER_REG)); // only enable receiver interrupt for now ier &= ~0x01; - *AUX_MU_IER_REG = ier; + put32(PA2VA(AUX_MU_IER_REG), ier); return; } - char c = *AUX_MU_IO_REG&0xFF; + char c = get32(PA2VA(AUX_MU_IO_REG))&0xFF; uart_read_buffer[uart_read_index++] = c; if (uart_read_index >= BUFFER_SIZE) { uart_read_index = 0; @@ -58,7 +59,7 @@ void irq_uart_rx_exception() { void irq_uart_tx_exception() { if (uart_write_index != uart_write_head) { - *AUX_MU_IO_REG = uart_write_buffer[uart_write_index++]; + put32(PA2VA(AUX_MU_IO_REG), uart_write_buffer[uart_write_index++]); // uart_send_string("before delayed\n"); // for(unsigned int i=0;i<100000000;i++){ // asm volatile("nop"); @@ -71,23 +72,23 @@ void irq_uart_tx_exception() { if (uart_write_index >= BUFFER_SIZE) { uart_write_index = 0; } - unsigned int ier = *AUX_MU_IER_REG; + unsigned int ier = get32(PA2VA(AUX_MU_IER_REG)); ier |= 0x02; - *AUX_MU_IER_REG = ier; + put32(PA2VA(AUX_MU_IER_REG), ier); } else { // no more data to send, disable transmit interrupt - unsigned int ier = *AUX_MU_IER_REG; + unsigned int ier = get32(PA2VA(AUX_MU_IER_REG)); ier &= ~0x02; - *AUX_MU_IER_REG = ier; + put32(PA2VA(AUX_MU_IER_REG), ier); } } void uart_irq_handler() { - unsigned int iir = *AUX_MU_IIR_REG; - unsigned int ier = *AUX_MU_IER_REG; + unsigned int iir = get32(PA2VA(AUX_MU_IIR_REG)); + unsigned int ier = get32(PA2VA(AUX_MU_IER_REG)); ier &= ~0x02; ier &= ~0x01; - *AUX_MU_IER_REG = ier; + put32(PA2VA(AUX_MU_IER_REG), ier); // check if it's a receive interrupt if ((iir & 0x06) == 0x04) { // uart_send_string("Receive interrupt\n"); @@ -106,10 +107,10 @@ void uart_irq_handler() { char uart_async_recv( void ) { while (uart_read_index == uart_read_head) { - unsigned int ier = *AUX_MU_IER_REG; + unsigned int ier = get32(PA2VA(AUX_MU_IER_REG)); // only enable receiver interrupt for now ier |= 0x01; - *AUX_MU_IER_REG = ier; + put32(PA2VA(AUX_MU_IER_REG), ier); } el1_interrupt_disable(); @@ -125,10 +126,10 @@ void uart_async_send_string(const char* str){ // if the write buffer is full, wait for it to be empty while ((uart_write_index + 1) % BUFFER_SIZE == uart_write_head) { - unsigned int ier = *AUX_MU_IER_REG; + unsigned int ier = get32(PA2VA(AUX_MU_IER_REG)); // only enable transmit interrupt for now ier |= 0x02; - *AUX_MU_IER_REG = ier; + put32(PA2VA(AUX_MU_IER_REG), ier); } el1_interrupt_disable(); while(*str){ @@ -145,16 +146,16 @@ void uart_async_send_string(const char* str){ } el1_interrupt_enable(); // enable transmit interrupt - unsigned int ier = *AUX_MU_IER_REG; + unsigned int ier = get32(PA2VA(AUX_MU_IER_REG)); ier |= 0x02; - *AUX_MU_IER_REG = ier; + put32(PA2VA(AUX_MU_IER_REG), ier); return; } -void uart_hex(unsigned int d) { +void uart_hex(uint64_t d) { unsigned int n; int c; - for (c = 28; c >= 0; c -= 4) { + for (c = 60; c >= 0; c -= 4) { // get highest tetrad n = (d >> c) & 0xF; // 0-9 => '0'-'9', 10-15 => 'A'-'F' @@ -163,52 +164,55 @@ void uart_hex(unsigned int d) { } } + void uart_init ( void ) { unsigned int selector; - selector = *GPFSEL1; + selector = get32(PA2VA(GPFSEL1)); selector &= ~(7<<12); // clean gpio14 selector |= 2<<12; // set alt5 for gpio14 selector &= ~(7<<15); // clean gpio15 selector |= 2<<15; // set alt5 for gpio15 - *GPFSEL1 = selector; + put32(PA2VA(GPFSEL1),selector); - *GPPUD = 0; + put32(PA2VA(GPPUD),0); delay(150); - *GPPUDCLK0 = (1<<14)|(1<<15); + put32(PA2VA(GPPUDCLK0),(1<<14)|(1<<15)); delay(150); - *GPPUDCLK0 = 0; - - *AUX_ENABLES = 1; //Enable mini uart (this also enables access to its registers) - *AUX_MU_CNTL_REG = 0; //Disable auto flow control and disable receiver and transmitter (for now) - *AUX_MU_IER_REG = 0; //Disable receive and transmit interrupts - *AUX_MU_LCR_REG = 3; //Enable 8 bit mode - *AUX_MU_MCR_REG = 0; //Set RTS line to be always high - *AUX_MU_BAUD_REG = 270; //Set baud rate to 115200 - *AUX_MU_CNTL_REG = 3; //Finally, enable transmitter and receiver + put32(PA2VA(GPPUDCLK0),0); + + put32(PA2VA(AUX_ENABLES),1); //Enable mini uart (this also enables access to its registers) + put32(PA2VA(AUX_MU_CNTL_REG),0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(PA2VA(AUX_MU_IER_REG),0); //Disable receive and transmit interrupts + put32(PA2VA(AUX_MU_LCR_REG),3); //Enable 8 bit mode + put32(PA2VA(AUX_MU_MCR_REG),0); //Set RTS line to be always high + put32(PA2VA(AUX_MU_BAUD_REG),270); //Set baud rate to 115200 + put32(PA2VA(AUX_MU_CNTL_REG),3); //Finally, enable transmitter and receiver } + void uart_enable_interrupt( void ) { - unsigned int ier = *AUX_MU_IER_REG; + unsigned int ier = get32(PA2VA(AUX_MU_IER_REG)); // only enable receiver interrupt for now ier |= 0x01; // ier |= 0x02; - *AUX_MU_IER_REG = ier; + put32(PA2VA(AUX_MU_IER_REG), ier); + - unsigned int enable_irqs_1 = *ENABLE_IRQS_1; + unsigned int enable_irqs_1 = get32(PA2VA(ENABLE_IRQS_1)); enable_irqs_1 |= 0x01 << 29; - *ENABLE_IRQS_1 = enable_irqs_1; + put32(PA2VA(ENABLE_IRQS_1), enable_irqs_1); } void uart_disable_interrupt( void ) { - unsigned int ier = *AUX_MU_IER_REG; + unsigned int ier = get32(PA2VA(AUX_MU_IER_REG)); // only enable receiver interrupt for now ier &= ~0x01; ier &= ~0x02; - *AUX_MU_IER_REG = ier; + put32(PA2VA(AUX_MU_IER_REG), ier); - unsigned int enable_irqs_1 = *ENABLE_IRQS_1; + unsigned int enable_irqs_1 = get32(PA2VA(ENABLE_IRQS_1)); enable_irqs_1 &= ~(0x01 << 29); - *ENABLE_IRQS_1 = enable_irqs_1; + put32(PA2VA(ENABLE_IRQS_1), enable_irqs_1); } diff --git a/lab6/src/mmu.c b/lab6/src/mmu.c new file mode 100644 index 000000000..b275e0992 --- /dev/null +++ b/lab6/src/mmu.c @@ -0,0 +1,165 @@ +#include "mmu.h" +#include "utils.h" +#include "alloc.h" +#include "mini_uart.h" +#include "mm.h" + +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 + +#define PD_TABLE 0b11 // Table Entry +#define PD_BLOCK 0b01 // Block Entry +#define PD_ACCESS (1 << 10) +#define PD_NSTABLE ((uint64_t)1 << 63) +#define PD_UXNTABLE ((uint64_t)1 << 60) +#define PD_PXN (1 << 53) +#define PD_MAIR_DEVICE_IDX (MAIR_IDX_DEVICE_nGnRnE << 2) +#define PD_MAIR_NORMAL_IDX (MAIR_IDX_NORMAL_NOCACHE << 2) +#define PD_L3BE (PD_ACCESS | PD_TABLE) + +// Block Entry +#define PD_BE PD_ACCESS | PD_BLOCK + +#define BOOT_PGD ((uint64_t *)0x1000) +#define BOOT_PUD ((uint64_t *)0x2000) +#define BOOT_PMD ((uint64_t *)0x3000) + + +/* + 000000000 000000000 000000000 000000000 000000000000 +47 39 38 30 29 21 20 12 11 0 + PGD PUD PMD PTE offset + +1 GB = 2^30 = 0x40000000 +*/ + +void mmu_init(void) +{ + uint32_t sctlr_el1; + + // Set Translation Control Register + write_sysreg(TCR_EL1, TCR_CONFIG_DEFAULT); + + // Set Memory Attribute Indirection Register + write_sysreg(MAIR_EL1, + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))); + + // Set Identity Paging + // 0x00000000 ~ 0x3f000000: Normal + // 0x3f000000 ~ 0x40000000: Device (GPU) + // 0x40000000 ~ 0x80000000: Device + /* TODO: Support run user program in EL0 */ + BOOT_PGD[0] = (uint64_t)BOOT_PUD | PD_NSTABLE | PD_UXNTABLE | PD_TABLE; + + BOOT_PUD[0] = (uint64_t)BOOT_PMD | PD_TABLE; + BOOT_PUD[1] = 0x40000000 | PD_MAIR_DEVICE_IDX | PD_BE; + + for (int i = 0; i < 504; ++i) { + BOOT_PMD[i] = (i * (1 << 21)) | PD_MAIR_NORMAL_IDX | PD_BE; // 1 << 21 = 2MB + } + // 504 * 2MB = 0x3f000000 + for (int i = 504; i < 512; ++i) { + BOOT_PMD[i] = (i * (1 << 21)) | PD_MAIR_DEVICE_IDX | PD_BE; + } + + write_sysreg(TTBR0_EL1, BOOT_PGD); + write_sysreg(TTBR1_EL1, BOOT_PGD); + + // Enable MMU + sctlr_el1 = read_sysreg(SCTLR_EL1); + write_sysreg(SCTLR_EL1, sctlr_el1 | 1); +} + + +uint64_t *pt_create(void) +{ + uint64_t *pt = kmalloc(PAGE_TABLE_SIZE); + // uart_send_string("pt_create addr: "); + // uart_hex(pt); + // uart_send_string("\n"); + + memzero(pt, PAGE_TABLE_SIZE); + + return pt; +} + +void pt_free(uint64_t *pt) +{ + // TODO +} + +static void _pt_map(uint64_t *pt, void *va, void *pa, uint64_t flag) +{ + uint64_t pd; + int idx; + + // 47 ~ 39, 38 ~ 30, 29 ~ 21, 20 ~ 12 + for (int layer = 3; layer > 0; --layer) { + idx = ((uint64_t)va >> (12 + 9 * layer)) & 0b111111111; + pd = pt[idx]; + + if (!(pd & 1)) { + // not a table entry + uint64_t *tmp = pt_create(); + pt[idx] = VA2PA(tmp) | PD_TABLE; + pt = tmp; + continue; + } + + // Must be a table entry + pt = (uint64_t *)PA2VA(pd & ~((uint64_t)0xfff)); // Clear lowest 12 bits (for page table entry) + } + // pt is now table entry + idx = ((uint64_t)va >> 12) & 0b111111111; + pd = pt[idx]; + + if (!(pd & 1)) { + // Invalid entry + // Access permissions + uint64_t ap; + uint64_t uxn; + + if (flag & PT_R) { + if (flag & PT_W) { + ap = 0b01; + } else { + ap = 0b11; + } + } else { + ap = 0b00; + } + + if (flag & PT_X) { + uxn = 0; + } else { + uxn = 1; + } + + pt[idx] = (uint64_t)pa | (uxn << 54) | PD_PXN | + PD_MAIR_NORMAL_IDX | (ap << 6) | PD_L3BE; + } +} + +void pt_map(uint64_t *pt, void *va, uint64_t size, void *pa, uint64_t flag) +{ + if ((uint64_t)va & (PAGE_SIZE - 1)) { + return; + } + + if ((uint64_t)pa & (PAGE_SIZE - 1)) { + return; + } + + size = ALIGN(size, PAGE_SIZE); + + for (uint64_t i = 0; i < size; i += PAGE_SIZE) { + _pt_map(pt, (void *)((uint64_t)va + i), (void *)((uint64_t)pa + i), flag); + } +} \ No newline at end of file diff --git a/lab6/src/reboot.c b/lab6/src/reboot.c index a6f370d5d..5c0fd7906 100644 --- a/lab6/src/reboot.c +++ b/lab6/src/reboot.c @@ -1,11 +1,13 @@ #include "reboot.h" +#include "c_utils.h" +#include "utils.h" void reset(int tick) { // reboot after watchdog timer expire - *PM_RSTC = PM_PASSWORD | 0x20; // full reset - *PM_WDOG = PM_PASSWORD | tick; // number of watchdog tick + put32(PA2VA(PM_RSTC), PM_PASSWORD | 0x20); // full reset + put32(PA2VA(PM_WDOG), PM_PASSWORD | tick); // number of watchdog tick } void cancel_reset() { - *PM_RSTC = PM_PASSWORD | 0; // cancel reset - *PM_WDOG = PM_PASSWORD | 0; // set watchdog tick to 0 to prevent reset + put32(PA2VA(PM_RSTC), PM_PASSWORD | 0); // cancel reset + put32(PA2VA(PM_WDOG), PM_PASSWORD | 0); // set watchdog tick to 0 to prevent reset } \ No newline at end of file diff --git a/lab6/src/shell.c b/lab6/src/shell.c index 3c80f0ba2..e34572cdc 100644 --- a/lab6/src/shell.c +++ b/lab6/src/shell.c @@ -11,10 +11,10 @@ #include "thread.h" void shell(){ - uart_async_send_string("Welcome to OSC2024 shell!\n"); + uart_send_string("Welcome to OSC2024 shell!\n"); while(1){ - uart_send_string("# "); char* str = kmalloc(100); + uart_send_string("# "); uart_recv_command(str); uart_send_string("\n"); if(!strcmp(str, "hello")){ @@ -78,14 +78,14 @@ void shell(){ reset(200); break; } else if(!strcmp(str, "help")){ - uart_async_send_string("help\t: print this help menu\n"); - uart_async_send_string("hello\t: print Hello World!\n"); - uart_async_send_string("mailbox\t: print board revision and memory info\n"); - uart_async_send_string("ls\t: list files in the ramdisk\n"); - uart_async_send_string("cat\t: print content of a file\n"); - uart_async_send_string("reboot\t: reboot this device\n"); - uart_async_send_string("exec\t: execute program from initramfs\n"); - uart_async_send_string("setTimeout\t: setTimeout MESSAGE SECONDS\n"); + uart_send_string("help\t: print this help menu\n"); + uart_send_string("hello\t: print Hello World!\n"); + uart_send_string("mailbox\t: print board revision and memory info\n"); + uart_send_string("ls\t: list files in the ramdisk\n"); + uart_send_string("cat\t: print content of a file\n"); + uart_send_string("reboot\t: reboot this device\n"); + uart_send_string("exec\t: execute program from initramfs\n"); + uart_send_string("setTimeout\t: setTimeout MESSAGE SECONDS\n"); } } thread_exit(); diff --git a/lab6/src/signal.c b/lab6/src/signal.c index 0b42e68c2..d1db72e13 100644 --- a/lab6/src/signal.c +++ b/lab6/src/signal.c @@ -4,7 +4,7 @@ #include "syscall.h" #include "string.h" #include "thread.h" - +#include "mmu.h" void check_and_run_signal() { thread_t* cur_thread = get_current_thread(); diff --git a/lab6/src/syscall.c b/lab6/src/syscall.c index 1ea81fb66..98c6757cd 100644 --- a/lab6/src/syscall.c +++ b/lab6/src/syscall.c @@ -5,6 +5,7 @@ #include "exception.h" #include "mbox.h" #include "signal.h" +#include "mmu.h" #include int getpid() { @@ -53,6 +54,7 @@ int exec(const char* name, char *const argv[]) { char *filedata; unsigned int filesize; // current pointer + thread_t* cur_thread = get_current_thread(); cpio_t *header_pointer = (cpio_t *)(ramfs_base); // print every cpio pathname @@ -69,8 +71,14 @@ int exec(const char* name, char *const argv[]) { } if (!strcmp(name, filepath)) { - target_addr = (char*)kmalloc(filesize); - memcpy(target_addr, filedata, filesize); + uart_send_string("filesize: "); + uart_hex(filesize); + uart_send_string("\n"); + cur_thread -> data = (void*)kmalloc(filesize); + cur_thread -> data_size = filesize; + uart_send_string("Copying user program\n"); + memcpy(cur_thread -> data, filedata, cur_thread -> data_size); + uart_send_string("Finished\n"); break; } @@ -80,29 +88,27 @@ int exec(const char* name, char *const argv[]) { return 1; } } - // run program from current thread - thread_t* cur_thread = get_current_thread(); // TODO: signal handling, should clear all signal handler here for(int i=0;i<=SIGNAL_NUM;i++) { cur_thread -> signal_handler[i] = 0; cur_thread -> waiting_signal[i] = 0; } + unsigned long kernel_sp = (unsigned long)cur_thread -> kernel_stack + T_STACK_SIZE; - cur_thread -> callee_reg.lr = (unsigned long)target_addr; + // cur_thread -> callee_reg.lr = (unsigned long)target_addr; + cur_thread -> page_table = pt_create(); + pt_map(cur_thread -> page_table, (void*)0, cur_thread -> data_size, + (void*)VA2PA(cur_thread -> data), PT_R | PT_W | PT_X); // map user program + pt_map(cur_thread -> page_table, (void*)0xffffffffb000, T_STACK_SIZE, + (void*)VA2PA(cur_thread -> user_stack), PT_R | PT_W); // map user stack - unsigned long spsr_el1 = 0x0; // run in el0 and enable all interrupt (DAIF) - unsigned long elr_el1 = cur_thread -> callee_reg.lr; - unsigned long user_sp = cur_thread -> callee_reg.sp; - unsigned long kernel_sp = (unsigned long)cur_thread -> kernel_stack + T_STACK_SIZE; + pt_map(cur_thread->page_table, (void *)0x3c000000, 0x04000000, + (void *)0x3c000000, PT_R | PT_W); // map mailbox + + set_page_table(cur_thread); + exec_user_prog((void *)0, (char *)0xffffffffeff0, kernel_sp); - // "r": Any general-purpose register, except sp - asm volatile("msr tpidr_el1, %0" : : "r" (cur_thread)); - asm volatile("msr spsr_el1, %0" : : "r" (spsr_el1)); - asm volatile("msr elr_el1, %0" : : "r" (elr_el1)); - asm volatile("msr sp_el0, %0" : : "r" (user_sp)); - asm volatile("mov sp, %0" :: "r" (kernel_sp)); - asm volatile("eret"); // jump to user program return 0; } @@ -111,6 +117,9 @@ void fork(trapframe_t* tf) { thread_t* parent_thread = get_current_thread(); thread_t* child_thread = create_fork_thread(); + child_thread -> data = (void*)kmalloc(parent_thread -> data_size); + child_thread -> data_size = parent_thread -> data_size; + memcpy( (void*)child_thread->user_stack, (void*)parent_thread->user_stack, @@ -123,6 +132,24 @@ void fork(trapframe_t* tf) { (void*)parent_thread->kernel_stack, T_STACK_SIZE ); + + memcpy( + (void*)child_thread->data, + (void*)parent_thread->data, + (uint64_t)parent_thread->data_size + ); + + child_thread -> page_table = pt_create(); + + pt_map(child_thread->page_table, (void *)0, child_thread->data_size, + (void *)VA2PA(child_thread->data), PT_R | PT_W | PT_X); + pt_map(child_thread->page_table, (void *)0xffffffffb000, T_STACK_SIZE, + (void *)VA2PA(child_thread->user_stack), PT_R | PT_W); + + // TODO: Why is this needed for the vm.img to run? + pt_map(child_thread->page_table, (void *)0x3c000000, 0x04000000, + (void *)0x3c000000, PT_R | PT_W); + save_regs(parent_thread); copy_regs(&child_thread->callee_reg); @@ -139,6 +166,10 @@ void fork(trapframe_t* tf) { child_thread -> callee_reg.sp = (uint64_t)((uint64_t)parent_sp - (uint64_t)parent_thread->kernel_stack + (uint64_t)child_thread->kernel_stack); child_thread -> callee_reg.fp = (uint64_t)((uint64_t)parent_fp - (uint64_t)parent_thread->kernel_stack + (uint64_t)child_thread->kernel_stack); + trapframe_t *child_tf = (trapframe_t*)(child_thread -> kernel_stack + + ((char*)tf - (char*)(parent_thread -> kernel_stack)) + ); + void* label_address = &&SYSCALL_FORK_END; uart_send_string("Address of SYSCALL_FORK_END: "); uart_hex((uint64_t)label_address); @@ -147,19 +178,23 @@ void fork(trapframe_t* tf) { child_thread -> callee_reg.lr = &&SYSCALL_FORK_END; // set child trapframe - trapframe_t *child_tf = (trapframe_t*)(child_thread -> kernel_stack + - ((char*)tf - (char*)(parent_thread -> kernel_stack)) - ); + // set child user stack sp child_tf -> x[0] = 0; child_tf -> x[30] = tf -> x[30]; - child_tf -> sp_el0 = (void*)((uint64_t)tf -> sp_el0 - (uint64_t)parent_thread->user_stack + (uint64_t)child_thread->user_stack); + child_tf -> sp_el0 = tf -> sp_el0; child_tf -> spsr_el1 = tf -> spsr_el1; child_tf -> elr_el1 = tf -> elr_el1; + uart_send_string("elr_el1: "); + uart_hex(child_tf -> elr_el1); + uart_send_string("\n"); tf -> x[0] = child_thread -> tid; push_running(child_thread); SYSCALL_FORK_END: - // uart_send_string("forked end\n"); + uart_send_string("forked end\n"); + uart_send_string("current tid: "); + uart_hex(get_current_thread()->tid); + uart_send_string("\n"); asm volatile("nop"); return; } @@ -169,7 +204,23 @@ void exit(int status) { } int mbox_call(unsigned char ch, unsigned int *mbox) { - return mailbox_call(ch, mbox); + int mbox_size; + char *kmbox; + + mbox_size = (int)mbox[0]; + + if (mbox_size <= 0) + return; + + kmbox = kmalloc(mbox_size); + + memcpy(kmbox, (char *)mbox, mbox_size); + + mailbox_call(ch, (unsigned int *)kmbox); + + memcpy((char *)mbox, kmbox, mbox_size); + + kfree(kmbox); } void kill(int pid) { diff --git a/lab6/src/thread.c b/lab6/src/thread.c index a4e25ef06..6afeeea79 100644 --- a/lab6/src/thread.c +++ b/lab6/src/thread.c @@ -6,6 +6,7 @@ #include "timer.h" #include "shell.h" #include "alloc.h" +#include "mmu.h" #include // define three queues @@ -144,12 +145,17 @@ void kill_zombies() { } thread_t* create_thread(void (*func)(void)) { + uint64_t* page_table = pt_create(); + thread_t* t = (thread_t*)kmalloc(sizeof(thread_t)); + t -> page_table = page_table; t -> tid = cur_tid ++; t -> state = TASK_RUNNING; t -> callee_reg.lr = (unsigned long)func; t -> user_stack = kmalloc(T_STACK_SIZE); t -> kernel_stack = kmalloc(T_STACK_SIZE); + t -> data = NULL; + t -> data_size = 0; t -> callee_reg.sp = (unsigned long)(t->user_stack + T_STACK_SIZE); t -> callee_reg.fp = t -> callee_reg.sp; // set fp to sp as the pointer that fixed @@ -172,7 +178,11 @@ thread_t* create_thread(void (*func)(void)) { } thread_t* create_fork_thread() { + uart_send_string("creating fork thread\n"); + uint64_t* page_table = pt_create(); + thread_t* t = (thread_t*)kmalloc(sizeof(thread_t)); + t -> page_table = page_table; t -> tid = cur_tid ++; t -> state = TASK_RUNNING; t -> callee_reg.lr = 0; @@ -180,6 +190,8 @@ thread_t* create_fork_thread() { t -> kernel_stack = kmalloc(T_STACK_SIZE); t -> callee_reg.sp = (unsigned long)(t->user_stack + T_STACK_SIZE); t -> callee_reg.fp = t -> callee_reg.sp; // set fp to sp as the pointer that fixed + t -> data = NULL; + t -> data_size = 0; for(int i=0;i<=SIGNAL_NUM;i++) { t -> signal_handler[i] = 0; diff --git a/lab6/src/timer.c b/lab6/src/timer.c index dbbd25dca..028a02a9c 100644 --- a/lab6/src/timer.c +++ b/lab6/src/timer.c @@ -25,13 +25,15 @@ void print_message(void *data) { } void set_timeout(char* message, unsigned long long timeout) { + uart_send_string("Set timeout\n"); char* message_copy = (char*)kmalloc(strlen(message)+1); + uart_send_string("Set timeout\n"); strncpy_(message_copy, message, strlen(message)+1); if(!message_copy) return; if(!timer_head) { // enable timer - *CORE0_TIMER_IRQ_CTRL = 2; + core_timer_enable(); } create_timer(print_message, message_copy, timeout); diff --git a/lab6/src/utils.S b/lab6/src/utils.S new file mode 100644 index 000000000..9fe830f36 --- /dev/null +++ b/lab6/src/utils.S @@ -0,0 +1,9 @@ +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret \ No newline at end of file diff --git a/lab8/.gitignore b/lab8/.gitignore new file mode 100644 index 000000000..70f5b5ae2 --- /dev/null +++ b/lab8/.gitignore @@ -0,0 +1 @@ +!user_prog.img \ No newline at end of file diff --git a/lab8/Makefile b/lab8/Makefile new file mode 100644 index 000000000..c1309f61a --- /dev/null +++ b/lab8/Makefile @@ -0,0 +1,47 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only -ggdb +ASMOPS = -Iinclude -ggdb + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img + +clean : + rm -rf $(BUILD_DIR) *.img + +gui: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +run: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +debug: + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb -s -S + +send: + sudo python bootloader/sender.py -f kernel8.img + +cpio: + rm -f initramfs.cpio + cd rootfs ; find . | cpio -o -H newc > ../initramfs.cpio + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img \ No newline at end of file diff --git a/lab6/a.out b/lab8/a.out similarity index 100% rename from lab6/a.out rename to lab8/a.out diff --git a/lab8/bcm2710-rpi-3-b-plus.dtb b/lab8/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..c83b0817e Binary files /dev/null and b/lab8/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab8/bootloader/Makefile b/lab8/bootloader/Makefile new file mode 100644 index 000000000..2a27bbe77 --- /dev/null +++ b/lab8/bootloader/Makefile @@ -0,0 +1,37 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : bootloader.img + +clean : + rm -rf $(BUILD_DIR) *.img + +run: + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -display none -serial null -serial pty + +send: + sudo python sender.py + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +bootloader.img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/bootloader.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/bootloader.elf -O binary bootloader.img \ No newline at end of file diff --git a/lab8/bootloader/build.sh b/lab8/bootloader/build.sh new file mode 100755 index 000000000..56cbff299 --- /dev/null +++ b/lab8/bootloader/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run --rm -v $(pwd):/app -w /app smatyukevich/raspberry-pi-os-builder make $1 diff --git a/lab8/bootloader/include/mini_uart.h b/lab8/bootloader/include/mini_uart.h new file mode 100644 index 000000000..0ba9ebb32 --- /dev/null +++ b/lab8/bootloader/include/mini_uart.h @@ -0,0 +1,11 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void uart_init ( void ); +char uart_recv ( void ); +char uart_raw_recv ( void ); +void uart_send ( char c ); +void uart_send_string(char* str); +void uart_hex(unsigned int d); + +#endif /*_MINI_UART_H */ diff --git a/lab8/bootloader/include/mm.h b/lab8/bootloader/include/mm.h new file mode 100644 index 000000000..e0827919d --- /dev/null +++ b/lab8/bootloader/include/mm.h @@ -0,0 +1,20 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SHIFT 12 +#define TABLE_SHIFT 9 +#define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) + +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define SECTION_SIZE (1 << SECTION_SHIFT) + +#define LOW_MEMORY (2 * SECTION_SIZE) + +#ifndef __ASSEMBLER__ + +void memzero(unsigned long src, unsigned long n); +void memncpy(char *dst, const char *src, unsigned long n); + +#endif + +#endif /*_MM_H */ diff --git a/lab8/bootloader/include/peripherals/base.h b/lab8/bootloader/include/peripherals/base.h new file mode 100644 index 000000000..63f9c038f --- /dev/null +++ b/lab8/bootloader/include/peripherals/base.h @@ -0,0 +1,6 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +#define PBASE 0x3F000000 + +#endif /*_P_BASE_H */ diff --git a/lab8/bootloader/include/peripherals/gpio.h b/lab8/bootloader/include/peripherals/gpio.h new file mode 100644 index 000000000..a15fce344 --- /dev/null +++ b/lab8/bootloader/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _P_GPIO_H +#define _P_GPIO_H + +#include "peripherals/base.h" + +#define GPFSEL1 (PBASE+0x00200004) +#define GPSET0 (PBASE+0x0020001C) +#define GPCLR0 (PBASE+0x00200028) +#define GPPUD (PBASE+0x00200094) +#define GPPUDCLK0 (PBASE+0x00200098) + +#endif /*_P_GPIO_H */ diff --git a/lab8/bootloader/include/peripherals/mini_uart.h b/lab8/bootloader/include/peripherals/mini_uart.h new file mode 100644 index 000000000..af95a3bee --- /dev/null +++ b/lab8/bootloader/include/peripherals/mini_uart.h @@ -0,0 +1,19 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_ENABLES (PBASE+0x00215004) +#define AUX_MU_IO_REG (PBASE+0x00215040) +#define AUX_MU_IER_REG (PBASE+0x00215044) +#define AUX_MU_IIR_REG (PBASE+0x00215048) +#define AUX_MU_LCR_REG (PBASE+0x0021504C) +#define AUX_MU_MCR_REG (PBASE+0x00215050) +#define AUX_MU_LSR_REG (PBASE+0x00215054) +#define AUX_MU_MSR_REG (PBASE+0x00215058) +#define AUX_MU_SCRATCH (PBASE+0x0021505C) +#define AUX_MU_CNTL_REG (PBASE+0x00215060) +#define AUX_MU_STAT_REG (PBASE+0x00215064) +#define AUX_MU_BAUD_REG (PBASE+0x00215068) + +#endif /*_P_MINI_UART_H */ diff --git a/lab8/bootloader/include/shell.h b/lab8/bootloader/include/shell.h new file mode 100644 index 000000000..5bce9ed65 --- /dev/null +++ b/lab8/bootloader/include/shell.h @@ -0,0 +1,7 @@ +#ifndef SHELL_H +#define SHELL_H + +void shell(); +int atoi(const char* s); + +#endif \ No newline at end of file diff --git a/lab8/bootloader/include/utils.h b/lab8/bootloader/include/utils.h new file mode 100644 index 000000000..acd33ddc2 --- /dev/null +++ b/lab8/bootloader/include/utils.h @@ -0,0 +1,8 @@ +#ifndef _UTILS_H +#define _UTILS_H + +extern void delay ( unsigned long); +extern void put32 ( unsigned long, unsigned int ); +extern unsigned int get32 ( unsigned long ); + +#endif /*_UTILS_H */ diff --git a/lab8/bootloader/sender.py b/lab8/bootloader/sender.py new file mode 100644 index 000000000..3de16f7f5 --- /dev/null +++ b/lab8/bootloader/sender.py @@ -0,0 +1,52 @@ +import argparse +import serial +import os +import time + +parser = argparse.ArgumentParser(description="Send kernel image to bootloader") + +parser.add_argument( + "-p", + "--port", + type=str, + default="/dev/tty.usbserial-0001", + help="Serial port to send the kernel image", +) + +parser.add_argument( + "-f", + "--file", + type=str, + default="../kernel8.img", + help="Path to the kernel image file", +) + +args = parser.parse_args() + +# open serial port +tty = serial.Serial(args.port, 115200, timeout=0.5) +file_stats = os.stat(args.file) + +# send file size +endline = "\n" +tty.write(str(file_stats.st_size).encode("utf-8")) +tty.write(endline.encode("utf-8")) + +time.sleep(0.5) + +size = file_stats.st_size +print(size) + +# send file content byte by byte +with open(args.file, "rb") as fp: + data = fp.read() + tty.write(data) + # byte = fp.read(1) + # while byte: + # tty.write(byte) + # size -= 1 + # byte = fp.read(1) + # time.sleep(0.0005) # delay to avoid buffer overflow + +print("File sent successfully") +print(size) \ No newline at end of file diff --git a/lab8/bootloader/src/boot.S b/lab8/bootloader/src/boot.S new file mode 100644 index 000000000..8e3a8d615 --- /dev/null +++ b/lab8/bootloader/src/boot.S @@ -0,0 +1,47 @@ +#include "mm.h" + +.section ".text.boot" + +.globl _start + +_start: + mov x10, x0 + mov x11, x1 + mov x12, x2 + mov x13, x3 + + mrs x0, mpidr_el1 + and x0, x0,#0xFF // Check processor id + cbz x0, master // Hang for all non-primary CPU + b proc_hang + +proc_hang: + wfe + b proc_hang + +master: + ldr x1, =0x80000 + ldr x2, =__bootloader_start + ldr x3, =__bootloader_size + +relocate: + ldr x4, [x1], #8 + str x4, [x2], #8 + sub x3, x3, #1 + cbnz x3, relocate + + ldr x1, =_start + mov sp, x1 + + ldr x0, =bss_begin + ldr w2, =__bss_size + +bss_reset: + cbz w2, run_main + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, bss_reset + +run_main: + bl main-0x20000 + b run_main \ No newline at end of file diff --git a/lab8/bootloader/src/config.txt b/lab8/bootloader/src/config.txt new file mode 100644 index 000000000..279349696 --- /dev/null +++ b/lab8/bootloader/src/config.txt @@ -0,0 +1,2 @@ +kernel_old=1 +disable_commandline_tags=1 diff --git a/lab8/bootloader/src/kernel.c b/lab8/bootloader/src/kernel.c new file mode 100644 index 000000000..346b694fc --- /dev/null +++ b/lab8/bootloader/src/kernel.c @@ -0,0 +1,10 @@ +#include "mini_uart.h" +#include "utils.h" +#include "shell.h" + + +void main(void) +{ + uart_init(); + shell(); +} diff --git a/lab8/bootloader/src/linker.ld b/lab8/bootloader/src/linker.ld new file mode 100644 index 000000000..3859b0c6a --- /dev/null +++ b/lab8/bootloader/src/linker.ld @@ -0,0 +1,23 @@ + +SECTIONS +{ + . = 0x60000; + __bootloader_start = .; + .text : + { + KEEP(*(.text.boot)) + *(.text) + } + .rodata :{ *(.rodata) } + .data : { *(.data) } + .bss : + { + . = ALIGN(0x8); + bss_begin = .; + *(.bss) + bss_end = .; + } + __bootloader_end = .; +} +__bss_size = (bss_end - bss_begin) >> 3; +__bootloader_size = (__bootloader_end - __bootloader_start) >> 3; \ No newline at end of file diff --git a/lab8/bootloader/src/mini_uart.c b/lab8/bootloader/src/mini_uart.c new file mode 100644 index 000000000..55f6b7e4c --- /dev/null +++ b/lab8/bootloader/src/mini_uart.c @@ -0,0 +1,79 @@ +#include "utils.h" +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" + +void uart_send ( char c ) +{ + while(1) { + if(get32(AUX_MU_LSR_REG)&0x20) + break; + } + put32(AUX_MU_IO_REG,c); +} + +char uart_recv ( void ) +{ + while(1) { + if(get32(AUX_MU_LSR_REG)&0x01) + break; + } + char c = get32(AUX_MU_IO_REG)&0xFF; + return c == '\r' ? '\n' : c; +} + +char uart_raw_recv (void) { + while(1) { + if(get32(AUX_MU_LSR_REG)&0x01) + break; + } + return get32(AUX_MU_IO_REG)&0xFF; +} + +void uart_send_string(char* str) +{ + for (int i = 0; str[i] != '\0'; i ++) { + if(str[i] == '\n'){ + uart_send('\r'); + } + uart_send((char)str[i]); + } +} + +void uart_hex(unsigned int d) { + unsigned int n; + int c; + for (c = 28; c >= 0; c -= 4) { + // get highest tetrad + n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x37 : 0x30; + uart_send(n); + } +} + +void uart_init ( void ) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7<<12); // clean gpio14 + selector |= 2<<12; // set alt5 for gpio14 + selector &= ~(7<<15); // clean gpio15 + selector |= 2<<15; // set alt5 for gpio15 + put32(GPFSEL1,selector); + + put32(GPPUD,0); + delay(150); + put32(GPPUDCLK0,(1<<14)|(1<<15)); + delay(150); + put32(GPPUDCLK0,0); + + put32(AUX_ENABLES,1); //Enable mini uart (this also enables access to its registers) + put32(AUX_MU_CNTL_REG,0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(AUX_MU_IER_REG,0); //Disable receive and transmit interrupts + put32(AUX_MU_LCR_REG,3); //Enable 8 bit mode + put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high + put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200 + + put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver +} diff --git a/lab8/bootloader/src/mm.S b/lab8/bootloader/src/mm.S new file mode 100644 index 000000000..1bd32ff37 --- /dev/null +++ b/lab8/bootloader/src/mm.S @@ -0,0 +1,6 @@ +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret diff --git a/lab8/bootloader/src/shell.c b/lab8/bootloader/src/shell.c new file mode 100644 index 000000000..aabbc592f --- /dev/null +++ b/lab8/bootloader/src/shell.c @@ -0,0 +1,125 @@ +#include "mini_uart.h" + +unsigned int is_visible(unsigned int c){ + if(c >= 32 && c <= 126){ + return 1; + } + return 0; +} + +unsigned int strcmp(char* str1, char* str2){ + int i = 0; + while(str1[i] != '\0' && str2[i] != '\0'){ + if(str1[i] != str2[i]){ + return 0; + } + i++; + } + if(str1[i] != '\0' || str2[i] != '\0'){ + return 0; + } + return 1; +} + + +void uart_recv_command(char *str){ + char c; + int i = 0; + while(1){ + c = uart_recv(); + if(c == '\n'){ + str[i] = '\0'; + break; + } else if(c == 127 || c == 8){ + if(i > 0){ + i--; + uart_send('\b'); + uart_send(' '); + uart_send('\b'); + } + continue; + } + if(is_visible(c)){ + str[i] = c; + i++; + uart_send(c); + } + } + +} + +int atoi(const char *s){ + int sign = 1; + int i = 0; + int result = 0; + + while(s[i] == ' ') + i ++; + + if(s[i] == '-') { + sign = -1; + i++; + } + + while(s[i] >= '0' && s[i] <= '9') { + result = result * 10 + (s[i] - '0'); + i ++; + } + + return sign * result; +} + + +void load_img(){ + char buf[16] = {0}; + for(int i = 0; i < 16; i++) { + buf[i] = uart_recv(); + if (buf[i] == '\n') { + buf[i] = '\0'; + break; + } + } + + uart_send_string("Kernel size: "); + uart_send_string(buf); + uart_send_string(" bytes\n"); + + uart_send_string("Loading kernel...\n"); + unsigned int size = atoi(buf); + char *kernel_addr = (char *)0x80000; + while (size --) { + *kernel_addr++ = uart_raw_recv(); + } + + asm volatile( + "mov x0, x10;" + "mov x1, x11;" + "mov x2, x12;" + "mov x3, x13;" + "mov x30, 0x80000;" + "ret;" + ); + +} + + +void shell(){ + uart_send_string("Welcome to Jayinnn's OSC bootloader!\n"); + while(1){ + uart_send_string("# "); + char str[100]; + uart_recv_command(str); + // uart_send_string(str); + uart_send_string("\n"); + if(strcmp(str, "hello")){ + uart_send_string("Hello World!\n"); + } else if(strcmp(str, "load")){ + load_img(); + return; + } else if(strcmp(str, "help")){ + uart_send_string("help\t: print this help menu\n"); + uart_send_string("hello\t: print Hello World!\n"); + uart_send_string("load\t: load kernel8.img\n"); + } + } +} \ No newline at end of file diff --git a/lab8/bootloader/src/utils.S b/lab8/bootloader/src/utils.S new file mode 100644 index 000000000..c35527a42 --- /dev/null +++ b/lab8/bootloader/src/utils.S @@ -0,0 +1,15 @@ +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret diff --git a/lab8/build.sh b/lab8/build.sh new file mode 100755 index 000000000..56cbff299 --- /dev/null +++ b/lab8/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run --rm -v $(pwd):/app -w /app smatyukevich/raspberry-pi-os-builder make $1 diff --git a/lab8/config.txt b/lab8/config.txt new file mode 100644 index 000000000..49fc25695 --- /dev/null +++ b/lab8/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x20000000 diff --git a/lab8/include/alloc.h b/lab8/include/alloc.h new file mode 100644 index 000000000..0b182a695 --- /dev/null +++ b/lab8/include/alloc.h @@ -0,0 +1,94 @@ +#ifndef _ALLOC_H_ +#define _ALLOC_H_ + +#define PAGE_BASE (void*)0x0 +#define PAGE_END (void*)0x3b400000 +#define PAGE_SIZE 0x1000 // 4KB + +#define MAX_ORDER 11 +#define MAX_CHUNK 5 + +#define BUDDY -1 // buddy memory pages +#define ALLOCATED -2 // allocated memory pages +#define RESERVED -3 // reserved memory pages + +extern int debug; + +typedef struct page { + unsigned char* addr; + unsigned long long idx; + int val; // if val > 0, it is free + int order; // 2^order = size + struct page* next; + struct page* prev; +} page; + +typedef struct free_list_t { + page* head; + int cnt; +} free_list_t; + +typedef struct page_info { + int idx; + struct page_info* next; +} page_info_t; + +typedef struct chunk { + unsigned char* addr; + struct chunk* next; +} chunk; + +typedef struct chunk_info { + int idx; // chunk index + int size; // chunk size + int cnt; // free chunk count + page_info_t* page_head; // page list + chunk* chunk_head; // free chunk list +} chunk_info; + +int buddy(int idx); + +// print information +void page_info(page* p); +void page_info_addr(void* addr); +void print_chunk_info(); +void free_list_info(); +void check_free_list(); + +// helper functions +unsigned long long align_page(unsigned long long size); +int log2(unsigned long long size); +int is_page(void* addr); +int size2chunkidx(unsigned long long size); + +void init_page_arr(); +void init_chunk_info(); +void init_page_allocator(); + +// related to page +void release(page* r_page); +void merge(page* m_page); +page* truncate(page* t_page, int order); + + +// related to free_list +void insert_page(page* new_page, int order); +page* pop_page(int order); +void erase_page(page* e_page, int order); + +// related to chunk +void* chunk_alloc(int idx); +void* chunk_free(void* addr); + +void alloc_init(); // main function + +// APIs +void memory_reserve(void* start, void* end); +void* page_alloc(unsigned long long size); +void page_free(void* addr); +void* kmalloc(unsigned long long size); +void kfree(void* addr); + +void *simple_malloc(unsigned long long size); + +#endif \ No newline at end of file diff --git a/lab8/include/c_utils.h b/lab8/include/c_utils.h new file mode 100644 index 000000000..87dcdbabd --- /dev/null +++ b/lab8/include/c_utils.h @@ -0,0 +1,12 @@ +#ifndef _C_UTILS_H +#define _C_UTILS_H + +#define ALIGN(num, base) ((num + base - 1) & ~(base - 1)) + +void uart_recv_command(char *str); +int align4(int n); +int atoi(const char *s); +unsigned int endian_big2little(unsigned int x); +void delay (unsigned int loop); + +#endif // _C_UTILS_H \ No newline at end of file diff --git a/lab8/include/exception.h b/lab8/include/exception.h new file mode 100644 index 000000000..13ace7719 --- /dev/null +++ b/lab8/include/exception.h @@ -0,0 +1,35 @@ +#ifndef _EXECPTION_H_ +#define _EXECPTION_H_ + +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int *)0x40000060) + +#define INTERRUPT_SOURCE_CNTPNSIRQ (1<<1) +#define INTERRUPT_SOURCE_GPU (1<<8) + +#define IRQ_PENDING_1_AUX_INT (1<<29) + +typedef struct trapframe_t { + unsigned long x[31]; // general purpose register + // three reg that will be used to kernel mode -> user mode + unsigned long spsr_el1; + unsigned long elr_el1; + unsigned long sp_el0; +} trapframe_t; + +void el1_interrupt_enable(); +void el1_interrupt_disable(); + +void core_timer_init(); +void core_timer_enable(); +void core_timer_disable(); + +void exception_handler_c(); +void irq_exception_handler_c(); +void user_exception_handler_c(trapframe_t* tf); + +void irq_timer_exception(); +void user_irq_timer_exception(); +void irq_uart_rx_exception(); +void irq_uart_tx_exception(); + +#endif \ No newline at end of file diff --git a/lab8/include/fdt.h b/lab8/include/fdt.h new file mode 100644 index 000000000..5f70b2a6b --- /dev/null +++ b/lab8/include/fdt.h @@ -0,0 +1,34 @@ +#ifndef _FDT_H +#define _FDT_H + +#include "mini_uart.h" +#include "string.h" +#include "c_utils.h" + +struct fdt_header { + unsigned int magic; + unsigned int totalsize; + unsigned int off_dt_struct; + unsigned int off_dt_strings; + unsigned int off_mem_rsvmap; + unsigned int version; + unsigned int last_comp_version; + unsigned int boot_cpuid_phys; + unsigned int size_dt_strings; + unsigned int size_dt_struct; +}; + +#define FDT_BEGIN_NODE 0x1 /* Start node: full name */ +#define FDT_END_NODE 0x2 /* End node */ +#define FDT_PROP 0x3 /* Property: name off, size, content */ +#define FDT_NOP 0x4 /* nop */ +#define FDT_END 0x9 + +typedef void (*dtb_callback)(unsigned int node_type, char *name, void *value, unsigned int name_size); + +extern char* dtb_base; +extern char* dtb_end; + +void fdt_traverse(dtb_callback callback); + +#endif diff --git a/lab8/include/fs_cpio.h b/lab8/include/fs_cpio.h new file mode 100644 index 000000000..b0e360a10 --- /dev/null +++ b/lab8/include/fs_cpio.h @@ -0,0 +1,76 @@ +#ifndef _FS_CPIO_H +#define _FS_CPIO_H + +#include "fs_vfs.h" +#include "initrd.h" +#include "list.h" +#include "string.h" + +#define TMPFS_FILE_MAXSIZE PAGE_SIZE // define in the spec +#define TMPFS_DIR_MAXSIZE 16 +#define TMPFS_NAME_MAXLEN 16 + +#define CPIOFS_TYPE_UNDEFINE 0x0 +#define CPIOFS_TYPE_FILE 0x1 +#define CPIOFS_TYPE_DIR 0x2 + +#define CPIO_TYPE_MASK 0060000 +#define CPIO_TYPE_DIR 0040000 +#define CPIO_TYPE_FILE 0000000 + +// init fs +filesystem *cpiofs_init(void); + +// static methods +int cpiofs_mount(filesystem *fs, mount *mnt); + +extern filesystem static_cpiofs; + +int cpiofs_lookup(vnode *dir_node, vnode **target, const char *component_name); +int cpiofs_create(vnode *dir_node, vnode **target, const char *component_name); +int cpiofs_mkdir(vnode *dir_node, vnode **target, const char *component_name); +int cpiofs_isdir(vnode *dir_node); +int cpiofs_getname(vnode *dir_node, const char **name); +int cpiofs_getsize(vnode *dir_node); + +extern struct vnode_operations cpiofs_v_ops; + +int cpiofs_open(vnode *file_node, file *target); +int cpiofs_close(file *target); +int cpiofs_write(file *target, const void *buf, size_t len); +int cpiofs_read(file *target, void *buf, size_t len); +long cpiofs_lseek64(file *target, long offset, int whence); +int cpiofs_ioctl(struct file *file, uint64_t request, va_list args); + + +uint32_t cpio_read_8hex(const char *s); +vnode *get_vnode_from_path(vnode *dir_node, const char **name); +void cpio_init_mkdir(const char *pathname); + +extern struct file_operations cpiofs_f_ops; + +typedef struct cpiofs_file { + const char *data; + int size; +} cpiofs_file; + +typedef struct cpiofs_dir { + struct list_head list; +} cpiofs_dir; + +typedef struct cpiofs_internal { + const char* name; + int type; + union { + cpiofs_file file; + cpiofs_dir dir; + }; + vnode* node; + struct list_head list; +} cpiofs_internal; + +extern vnode cpio_root_node; +extern vnode mount_old_node; +extern int cpio_mounted; + +#endif // _FS_CPIO_H \ No newline at end of file diff --git a/lab8/include/fs_framebufferfs.h b/lab8/include/fs_framebufferfs.h new file mode 100644 index 000000000..343a2372b --- /dev/null +++ b/lab8/include/fs_framebufferfs.h @@ -0,0 +1,57 @@ +#ifndef _FS_FRAMEBUFFERFS_H +#define _FS_FRAMEBUFFERFS_H + +#include "fs_vfs.h" +#include "mbox.h" +#include "string.h" + +#define MBOX_REQUEST 0 +#define MBOX_CH_PROP 8 +#define MBOX_TAG_LAST 0 + + +typedef struct fb_info { + uint32_t width; + uint32_t height; + uint32_t pitch; + uint32_t isrgb; +} fb_info; + +filesystem *framebufferfs_init(void); + +int framebufferfs_mount(filesystem *fs, mount *mnt); + +extern filesystem static_framebufferfs; + + +int framebufferfs_lookup(vnode *dir_node, vnode **target, + const char *component_name); +int framebufferfs_create(vnode *dir_node, vnode **target, + const char *component_name); +int framebufferfs_mkdir(vnode *dir_node, vnode **target, + const char *component_name); +int framebufferfs_isdir(vnode *dir_node); +int framebufferfs_getname(vnode *dir_node, const char **name); +int framebufferfs_getsize(vnode *dir_node); + +extern vnode_operations framebufferfs_v_ops; + +int framebufferfs_open(vnode *file_node, file *target); +int framebufferfs_close(file *target); +int framebufferfs_write(file *target, const void *buf, size_t len); +int framebufferfs_read(file *target, void *buf, size_t len); +long framebufferfs_lseek64(file *target, long offset, int whence); +int framebufferfs_ioctl(struct file *file, uint64_t request, va_list args); + +extern file_operations framebufferfs_f_ops; + +typedef struct framebufferfs_internal { + const char *name; + struct vnode oldnode; + /* raw frame buffer address */ + uint8_t *lfb; + uint32_t lfbsize; + int isopened; + int isinit; +} framebufferfs_internal; +#endif // _FS_FRAMEBUFFERFS_H \ No newline at end of file diff --git a/lab8/include/fs_fsinit.h b/lab8/include/fs_fsinit.h new file mode 100644 index 000000000..1ee7ae47b --- /dev/null +++ b/lab8/include/fs_fsinit.h @@ -0,0 +1,13 @@ +#ifndef _FSINIT_H +#define _FSINIT_H + +#include "fs_vfs.h" +#include "fs_tmpfs.h" +#include "fs_cpio.h" +#include "fs_uartfs.h" +#include "fs_framebufferfs.h" + +void fs_early_init(void); +void fs_init(void); + +#endif // _FSINIT_H \ No newline at end of file diff --git a/lab8/include/fs_tmpfs.h b/lab8/include/fs_tmpfs.h new file mode 100644 index 000000000..873352f50 --- /dev/null +++ b/lab8/include/fs_tmpfs.h @@ -0,0 +1,64 @@ +#ifndef _TMPFS_H +#define _TMPFS_H + +#include "fs_vfs.h" + +#define TMPFS_FILE_MAXSIZE PAGE_SIZE // define in the spec +#define TMPFS_DIR_MAXSIZE 16 +#define TMPFS_NAME_MAXLEN 16 + +#define TMPFS_TYPE_UNDEFINE 0x0 +#define TMPFS_TYPE_FILE 0x1 +#define TMPFS_TYPE_DIR 0x2 + +// init fs +filesystem *tmpfs_init(void); + +// static methods +int tmpfs_mount(filesystem *fs, mount *mnt); +int tmpfs_alloc_vnode(filesystem *fs, vnode **target); + +extern filesystem static_tmpfs; + +int tmpfs_lookup(vnode *dir_node, vnode **target, const char *component_name); +int tmpfs_create(vnode *dir_node, vnode **target, const char *component_name); +int tmpfs_mkdir(vnode *dir_node, vnode **target, const char *component_name); +int tmpfs_isdir(vnode *dir_node); +int tmpfs_getname(vnode *dir_node, const char **name); +int tmpfs_getsize(vnode *dir_node); + +extern struct vnode_operations tmpfs_v_ops; + +int tmpfs_open(vnode *file_node, file *target); +int tmpfs_close(file *target); +int tmpfs_write(file *target, const void *buf, size_t len); +int tmpfs_read(file *target, void *buf, size_t len); +long tmpfs_lseek64(file *target, long offset, int whence); +int tmpfs_ioctl(struct file *file, uint64_t request, va_list args); + + +extern struct file_operations tmpfs_f_ops; + +typedef struct tmpfs_file { + char *data; + int size; + int capacity; +} tmpfs_file; + +typedef struct tmpfs_dir { + int size; + vnode *files[TMPFS_DIR_MAXSIZE]; +} tmpfs_dir; + +typedef struct tmpfs_internal { + char name[TMPFS_NAME_MAXLEN]; + int type; + union { + tmpfs_file *file; + tmpfs_dir *dir; + }; + vnode* old_node; +} tmpfs_internal; + + +#endif // _TMPFS_H \ No newline at end of file diff --git a/lab8/include/fs_uartfs.h b/lab8/include/fs_uartfs.h new file mode 100644 index 000000000..5a1fa9bfa --- /dev/null +++ b/lab8/include/fs_uartfs.h @@ -0,0 +1,41 @@ +#ifndef _FS_UARTFS_H +#define _FS_UARTFS_H + +#include "fs_vfs.h" +#include "mini_uart.h" + +filesystem *uartfs_init(void); + +int uartfs_mount(filesystem *fs, mount *mnt); + +extern filesystem static_uartfs; + + +int uartfs_lookup(vnode *dir_node, vnode **target, + const char *component_name); +int uartfs_create(vnode *dir_node, vnode **target, + const char *component_name); +int uartfs_mkdir(vnode *dir_node, vnode **target, + const char *component_name); +int uartfs_isdir(vnode *dir_node); +int uartfs_getname(vnode *dir_node, const char **name); +int uartfs_getsize(vnode *dir_node); + +extern vnode_operations uartfs_v_ops; + +int uartfs_open(vnode *file_node, file *target); +int uartfs_close(file *target); +int uartfs_write(file *target, const void *buf, size_t len); +int uartfs_read(file *target, void *buf, size_t len); +long uartfs_lseek64(file *target, long offset, int whence); +int uartfs_ioctl(struct file *file, uint64_t request, va_list args); + +extern file_operations uartfs_f_ops; + +typedef struct uartfs_internal { + const char *name; + vnode oldnode; +} uartfs_internal; + + +#endif // _FS_UARTFS_H \ No newline at end of file diff --git a/lab8/include/fs_vfs.h b/lab8/include/fs_vfs.h new file mode 100644 index 000000000..e70d85934 --- /dev/null +++ b/lab8/include/fs_vfs.h @@ -0,0 +1,110 @@ +#ifndef _FS_VFS_H +#define _FS_VFS_H + +#include +#include +#include +#include "list.h" +#include "exception.h" + +#define O_CREAT 00000100 + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +typedef struct vnode { + struct mount *mount; + struct vnode_operations *v_ops; + struct file_operations *f_ops; + struct vnode *parent; + void *internal; +} vnode; + +typedef struct file { + vnode *vnode; + unsigned f_pos; + struct file_operations *f_ops; + int flags; +} file; + +typedef struct mount { + struct vnode *root; + struct filesystem *fs; +} mount; + +typedef struct filesystem { + const char *name; + struct list_head fs_list; + int (*mount)(struct filesystem *fs, struct mount *mount); + int (*alloc_vnode)(struct filesystem *fs, struct vnode **target); +} filesystem; + +typedef struct file_operations { + int (*write)(file *f, const void *buf, size_t len); + int (*read)(file *f, void *buf, size_t len); + int (*open)(vnode *file_node, file *target); + int (*close)(file *f); + long (*lseek64)(file *f, long offset, int whence); + int (*ioctl)(file *file, uint64_t request, va_list args); +} file_operations; + +typedef struct vnode_operations { + int (*lookup)(vnode *dir_node, vnode **target, const char *component_name); + int (*create)(vnode *dir_node, vnode **target, const char *component_name); + int (*mkdir)(vnode *dir_node, vnode **target, const char *component_name); + int (*isdir)(vnode *dir_node); + int (*getname)(vnode *dir_node, const char **name); + int (*getsize)(vnode *dir_node); + +} vnode_operations; + + +// root mount point +extern mount *rootfs; + +void vfs_init(); +void vfs_init_rootfs(filesystem *fs); + +int register_filesystem(filesystem *fs); +int vfs_open(const char* pathname, int flags, file* target); +int vfs_close(file *f); +int vfs_write(file *f, const void *buf, size_t len); +int vfs_read(file *f, void *buf, size_t len); +int vfs_mkdir(const char *pathname); +int vfs_mount(const char* target, const char* filesystem); +int vfs_lookup(const char *pathname, vnode **target); +long vfs_lseek64(file *f, long offset, int whence); +int vfs_ioctl(struct file *file, uint64_t request, va_list args); + +void syscall_open(trapframe_t *tf, const char *pathname, int flags); +void syscall_close(trapframe_t *tf, int fd); +void syscall_write(trapframe_t *tf, int fd, const void *buf, size_t len); +void syscall_read(trapframe_t *tf, int fd, void *buf, size_t len); +void syscall_mkdir(trapframe_t *tf, const char *pathname, uint32_t mode); +void syscall_mount( + trapframe_t *tf, + const char *src, + const char *target, + const char *fs_name, + int flags, + const void *data +); +void syscall_chdir(trapframe_t *tf, const char *path); +void syscall_lseek64(trapframe_t *tf, int fd, long offset, int whence); +void syscall_ioctl(trapframe_t *tf, int fd, uint64_t requests, ...); + +// static methods + +int open_wrapper(const char* pathname, int flags); +int close_wrapper(int fd); +int write_wrapper(int fd, const void *buf, size_t len); +int read_wrapper(int fd, void *buf, size_t len); +int mkdir_wrapper(const char* pathname); +int mount_wrapper(const char* target, const char* fs_name); +int chdir_wrapper(const char* path); +long lseek64_wrapper(int fd, long offset, int whence); +int ioctl_wrapper(int fd, uint64_t cmd, va_list args); + + +#endif // _FS_VFS_H \ No newline at end of file diff --git a/lab8/include/initrd.h b/lab8/include/initrd.h new file mode 100644 index 000000000..60af6f43c --- /dev/null +++ b/lab8/include/initrd.h @@ -0,0 +1,40 @@ +#ifndef INITRD_H +#define INITRD_H + +#define CPIO_BASE_QEMU (0x8000000) +#define CPIO_BASE_RPI (0x20000000) + +#define CPIO_NEWC_HEADER_MAGIC "070701" // big endian + + +extern char *ramfs_base; +extern char *ramfs_end; + +// Cpio Archive File Header (New ASCII Format) +typedef struct { + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +} cpio_t; + +int cpio_newc_parse_header(cpio_t *this_header_pointer, char **pathname, unsigned int *filesize, char **data, cpio_t **next_header_pointer); +void initrd_list(); +void initrd_cat(const char *target); +void initrd_callback(unsigned int node_type, char *name, void *value, unsigned int name_size); +void initrd_exec_prog(); +void initrd_run_prog(const char* path_name); +// void initrd_exec_syscall(); +// void initrd_run_syscall(); +// void exec_user_prog (); +#endif // INITRD_H \ No newline at end of file diff --git a/lab8/include/list.h b/lab8/include/list.h new file mode 100644 index 000000000..67d77d14a --- /dev/null +++ b/lab8/include/list.h @@ -0,0 +1,459 @@ +/* Linux-like doubly-linked list implementation */ +#ifndef _LIST_H +#define _LIST_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +/* "typeof" is a GNU extension. + * Reference: https://gcc.gnu.org/onlinedocs/gcc/Typeof.html + */ +#if defined(__GNUC__) +#define __LIST_HAVE_TYPEOF 1 +#endif /* defined(__GNUC__) */ + +/** + * struct list_head - Head and node of a doubly-linked list + * @prev: pointer to the previous node in the list + * @next: pointer to the next node in the list + * + * The simple doubly-linked list consists of a head and nodes attached to + * this head. Both node and head share the same struct type. The list_* + * functions and macros can be used to access and modify this data structure. + * + * The @prev pointer of the list head points to the last list node of the + * list and @next points to the first list node of the list. For an empty list, + * both member variables point to the head. + * + * The list nodes are usually embedded in a container structure which holds the + * actual data. Such an container object is called entry. The helper list_entry + * can be used to calculate the object address from the address of the node. + */ +struct list_head { + struct list_head *prev; + struct list_head *next; +}; + +/** + * container_of() - Calculate address of object that contains address ptr + * @ptr: pointer to member variable + * @type: type of the structure containing ptr + * @member: name of the member variable in struct @type + * + * Return: @type pointer of object containing ptr + */ +#ifndef container_of +#ifdef __LIST_HAVE_TYPEOF +#define container_of(ptr, type, member) \ + __extension__({ \ + const __typeof__(((type *) 0)->member) *__pmember = (ptr); \ + (type *) ((char *) __pmember - offsetof(type, member)); \ + }) +#else /* __LIST_HAVE_TYPEOF */ +#define container_of(ptr, type, member) \ + ((type *) ((char *) (ptr) -offsetof(type, member))) +#endif /* __LIST_HAVE_TYPEOF */ +#endif /* container_of */ + +/** + * LIST_HEAD - Declare list head and initialize it + * @head: name of the new object + */ +#define LIST_HEAD(head) struct list_head head = {&(head), &(head)} + +/** + * INIT_LIST_HEAD() - Initialize empty list head + * @head: pointer to list head + * + * This can also be used to initialize a unlinked list node. + * + * A node is usually linked inside a list, will be added to a list in + * the near future or the entry containing the node will be free'd soon. + * + * But an unlinked node may be given to a function which uses list_del(_init) + * before it ends up in a previously mentioned state. The list_del(_init) on an + * initialized node is well defined and safe. But the result of a + * list_del(_init) on an uninitialized node is undefined (unrelated memory is + * modified, crashes, ...). + */ +static inline void INIT_LIST_HEAD(struct list_head *head) +{ + head->next = head; + head->prev = head; +} + +/** + * list_add() - Add a list node to the beginning of the list + * @node: pointer to the new node + * @head: pointer to the head of the list + */ +static inline void list_add(struct list_head *node, struct list_head *head) +{ + struct list_head *next = head->next; + + next->prev = node; + node->next = next; + node->prev = head; + head->next = node; +} + +/** + * list_add_tail() - Add a list node to the end of the list + * @node: pointer to the new node + * @head: pointer to the head of the list + */ +static inline void list_add_tail(struct list_head *node, struct list_head *head) +{ + struct list_head *prev = head->prev; + + prev->next = node; + node->next = head; + node->prev = prev; + head->prev = node; +} + +/** + * list_del() - Remove a list node from the list + * @node: pointer to the node + * + * The node is only removed from the list. Neither the memory of the removed + * node nor the memory of the entry containing the node is free'd. The node + * has to be handled like an uninitialized node. Accessing the next or prev + * pointer of the node is not safe. + * + * Unlinked, initialized nodes are also uninitialized after list_del. + * + * LIST_POISONING can be enabled during build-time to provoke an invalid memory + * access when the memory behind the next/prev pointer is used after a list_del. + * This only works on systems which prohibit access to the predefined memory + * addresses. + */ +static inline void list_del(struct list_head *node) +{ + struct list_head *next = node->next; + struct list_head *prev = node->prev; + + next->prev = prev; + prev->next = next; + +#ifdef LIST_POISONING + node->prev = (struct list_head *) (0x00100100); + node->next = (struct list_head *) (0x00200200); +#endif /* LIST_POISONING */ +} + +/** + * list_del_init() - Remove a list node from the list and reinitialize it + * @node: pointer to the node + * + * The removed node will not end up in an uninitialized state like when using + * list_del. Instead the node is initialized again to the unlinked state. + */ +static inline void list_del_init(struct list_head *node) +{ + list_del(node); + INIT_LIST_HEAD(node); +} + +/** + * list_empty() - Check if list head has no nodes attached + * @head: pointer to the head of the list + * + * Return: 0 - list is not empty !0 - list is empty + */ +static inline int list_empty(const struct list_head *head) +{ + return (head->next == head); +} + +/** + * list_is_singular() - Check if list head has exactly one node attached + * @head: pointer to the head of the list + * + * Return: 0 - list is not singular !0 -list has exactly one entry + */ +static inline int list_is_singular(const struct list_head *head) +{ + return (!list_empty(head) && head->prev == head->next); +} + +/** + * list_splice() - Add list nodes from a list to beginning of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to the beginning of the list of @head. + * It is similar to list_add but for multiple nodes. The @list head is not + * modified and has to be initialized to be used as a valid list head/node + * again. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + struct list_head *head_first = head->next; + struct list_head *list_first = list->next; + struct list_head *list_last = list->prev; + + if (list_empty(list)) + return; + + head->next = list_first; + list_first->prev = head; + + list_last->next = head_first; + head_first->prev = list_last; +} + +/** + * list_splice_tail() - Add list nodes from a list to end of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to to the end of the list of @head. + * It is similar to list_add_tail but for multiple nodes. The @list head is not + * modified and has to be initialized to be used as a valid list head/node + * again. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + struct list_head *head_last = head->prev; + struct list_head *list_first = list->next; + struct list_head *list_last = list->prev; + + if (list_empty(list)) + return; + + head->prev = list_last; + list_last->next = head; + + list_first->prev = head_last; + head_last->next = list_first; +} + +/** + * list_splice_init() - Move list nodes from a list to beginning of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to to the beginning of the list of @head. + * It is similar to list_add but for multiple nodes. + * + * The @list head will not end up in an uninitialized state like when using + * list_splice. Instead the @list is initialized again to the an empty + * list/unlinked state. + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + list_splice(list, head); + INIT_LIST_HEAD(list); +} + +/** + * list_splice_tail_init() - Move list nodes from a list to end of another list + * @list: pointer to the head of the list with the node entries + * @head: pointer to the head of the list + * + * All nodes from @list are added to to the end of the list of @head. + * It is similar to list_add_tail but for multiple nodes. + * + * The @list head will not end up in an uninitialized state like when using + * list_splice. Instead the @list is initialized again to the an empty + * list/unlinked state. + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + list_splice_tail(list, head); + INIT_LIST_HEAD(list); +} + +/** + * list_cut_position() - Move beginning of a list to another list + * @head_to: pointer to the head of the list which receives nodes + * @head_from: pointer to the head of the list + * @node: pointer to the node in which defines the cutting point + * + * All entries from the beginning of the list @head_from to (including) the + * @node is moved to @head_to. + * + * @head_to is replaced when @head_from is not empty. @node must be a real + * list node from @head_from or the behavior is undefined. + */ +static inline void list_cut_position(struct list_head *head_to, + struct list_head *head_from, + struct list_head *node) +{ + struct list_head *head_from_first = head_from->next; + + if (list_empty(head_from)) + return; + + if (head_from == node) { + INIT_LIST_HEAD(head_to); + return; + } + + head_from->next = node->next; + head_from->next->prev = head_from; + + head_to->prev = node; + node->next = head_to; + head_to->next = head_from_first; + head_to->next->prev = head_to; +} + +/** + * list_move() - Move a list node to the beginning of the list + * @node: pointer to the node + * @head: pointer to the head of the list + * + * The @node is removed from its old position/node and add to the beginning of + * @head + */ +static inline void list_move(struct list_head *node, struct list_head *head) +{ + list_del(node); + list_add(node, head); +} + +/** + * list_move_tail() - Move a list node to the end of the list + * @node: pointer to the node + * @head: pointer to the head of the list + * + * The @node is removed from its old position/node and add to the end of @head + */ +static inline void list_move_tail(struct list_head *node, + struct list_head *head) +{ + list_del(node); + list_add_tail(node, head); +} + +/** + * list_entry() - Calculate address of entry that contains list node + * @node: pointer to list node + * @type: type of the entry containing the list node + * @member: name of the list_head member variable in struct @type + * + * Return: @type pointer of entry containing node + */ +#define list_entry(node, type, member) container_of(node, type, member) + +/** + * list_first_entry() - get first entry of the list + * @head: pointer to the head of the list + * @type: type of the entry containing the list node + * @member: name of the list_head member variable in struct @type + * + * Return: @type pointer of first entry in list + */ +#define list_first_entry(head, type, member) \ + list_entry((head)->next, type, member) + +/** + * list_last_entry() - get last entry of the list + * @head: pointer to the head of the list + * @type: type of the entry containing the list node + * @member: name of the list_head member variable in struct @type + * + * Return: @type pointer of last entry in list + */ +#define list_last_entry(head, type, member) \ + list_entry((head)->prev, type, member) + +/** + * list_for_each - iterate over list nodes + * @node: list_head pointer used as iterator + * @head: pointer to the head of the list + * + * The nodes and the head of the list must be kept unmodified while + * iterating through it. Any modifications to the the list will cause undefined + * behavior. + */ +#define list_for_each(node, head) \ + for (node = (head)->next; node != (head); node = node->next) + +/** + * list_for_each_entry - iterate over list entries + * @entry: pointer used as iterator + * @head: pointer to the head of the list + * @member: name of the list_head member variable in struct type of @entry + * + * The nodes and the head of the list must be kept unmodified while + * iterating through it. Any modifications to the the list will cause undefined + * behavior. + * + * FIXME: remove dependency of __typeof__ extension + */ +#ifdef __LIST_HAVE_TYPEOF +#define list_for_each_entry(entry, head, member) \ + for (entry = list_entry((head)->next, __typeof__(*entry), member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, __typeof__(*entry), member)) +#endif /* __LIST_HAVE_TYPEOF */ + +/** + * iter_for_each_entry - iterate over list entries from @iter + * @entry: pointer used as iterator + * @iter: pointer to the start of this iteration + * @head: pointer to the head of the list + * @member: name of the list_head member variable in struct type of @entry + * + * FIXME: remove dependency of __typeof__ extension + */ +#ifdef __LIST_HAVE_TYPEOF +#define iter_for_each_entry(entry, iter, head, member) \ + for (entry = list_entry(iter, __typeof__(*entry), member); \ + &entry->member != (head); \ + entry = list_entry(entry->member.next, __typeof__(*entry), member)) +#endif /* __LIST_HAVE_TYPEOF */ + +/** + * list_for_each_safe - iterate over list nodes and allow deletes + * @node: list_head pointer used as iterator + * @safe: list_head pointer used to store info for next entry in list + * @head: pointer to the head of the list + * + * The current node (iterator) is allowed to be removed from the list. Any + * other modifications to the the list will cause undefined behavior. + */ +#define list_for_each_safe(node, safe, head) \ + for (node = (head)->next, safe = node->next; node != (head); \ + node = safe, safe = node->next) + +/** + * list_for_each_entry_safe - iterate over list entries and allow deletes + * @entry: pointer used as iterator + * @safe: @type pointer used to store info for next entry in list + * @head: pointer to the head of the list + * @member: name of the list_head member variable in struct type of @entry + * + * The current node (iterator) is allowed to be removed from the list. Any + * other modifications to the the list will cause undefined behavior. + * + * FIXME: remove dependency of __typeof__ extension + */ +#define list_for_each_entry_safe(entry, safe, head, member) \ + for (entry = list_entry((head)->next, __typeof__(*entry), member), \ + safe = list_entry(entry->member.next, __typeof__(*entry), member); \ + &entry->member != (head); entry = safe, \ + safe = list_entry(safe->member.next, __typeof__(*entry), member)) + +#define list_for_each_entry_safe_rev(entry, safe, head, member) \ + for (entry = list_entry((head)->prev, __typeof__(*entry), member), \ + safe = list_entry(entry->member.prev, __typeof__(*entry), member); \ + &entry->member != (head); entry = safe, \ + safe = list_entry(safe->member.prev, __typeof__(*entry), member)) + +#undef __LIST_HAVE_TYPEOF + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _LIST_H */ \ No newline at end of file diff --git a/lab8/include/mbox.h b/lab8/include/mbox.h new file mode 100644 index 000000000..6a05d1782 --- /dev/null +++ b/lab8/include/mbox.h @@ -0,0 +1,26 @@ +#ifndef _MBOX_H +#define _MBOX_H + +#define MMIO_BASE 0x3f000000 +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#define MAILBOX_READ (unsigned int*)(MAILBOX_BASE) +#define MAILBOX_STATUS (unsigned int*)(MAILBOX_BASE + 0x18) +#define MAILBOX_WRITE (unsigned int*)(MAILBOX_BASE + 0x20) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +int mailbox_call(unsigned char ch, unsigned int* mailbox); +void get_board_revision(); +void get_memory_info(); + +#endif \ No newline at end of file diff --git a/lab8/include/mini_uart.h b/lab8/include/mini_uart.h new file mode 100644 index 000000000..2234f1c69 --- /dev/null +++ b/lab8/include/mini_uart.h @@ -0,0 +1,19 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +#define BUFFER_SIZE 1024 + +void uart_init ( void ); +void uart_enable_interrupt( void ); +void uart_disable_interrupt( void ); +char uart_recv ( void ); +void uart_recvn(char *buff, int n); +void uart_send ( char c ); +void uart_sendn (const char* buffer, int n); +void uart_send_string(const char* str); +void uart_hex(unsigned int d); +void uart_irq_handler(void); +char uart_async_recv( void ); +void uart_async_send_string(const char* buffer); + +#endif /*_MINI_UART_H */ diff --git a/lab8/include/mm.h b/lab8/include/mm.h new file mode 100644 index 000000000..9d05242d8 --- /dev/null +++ b/lab8/include/mm.h @@ -0,0 +1,19 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SHIFT 12 +#define TABLE_SHIFT 9 +#define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) + +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define SECTION_SIZE (1 << SECTION_SHIFT) + +#define LOW_MEMORY (2 * SECTION_SIZE) + +#ifndef __ASSEMBLER__ + +void memzero(unsigned long src, unsigned long n); + +#endif + +#endif /*_MM_H */ diff --git a/lab8/include/peripherals/base.h b/lab8/include/peripherals/base.h new file mode 100644 index 000000000..63f9c038f --- /dev/null +++ b/lab8/include/peripherals/base.h @@ -0,0 +1,6 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +#define PBASE 0x3F000000 + +#endif /*_P_BASE_H */ diff --git a/lab8/include/peripherals/gpio.h b/lab8/include/peripherals/gpio.h new file mode 100644 index 000000000..4a1f0f18f --- /dev/null +++ b/lab8/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _P_GPIO_H +#define _P_GPIO_H + +#include "peripherals/base.h" + +#define GPFSEL1 ((volatile unsigned int *)(PBASE+0x00200004)) +#define GPSET0 ((volatile unsigned int *)(PBASE+0x0020001C)) +#define GPCLR0 ((volatile unsigned int *)(PBASE+0x00200028)) +#define GPPUD ((volatile unsigned int *)(PBASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int *)(PBASE+0x00200098)) + +#endif /*_P_GPIO_H */ diff --git a/lab8/include/peripherals/irq.h b/lab8/include/peripherals/irq.h new file mode 100644 index 000000000..885b0b68f --- /dev/null +++ b/lab8/include/peripherals/irq.h @@ -0,0 +1,17 @@ +#ifndef _IRQ_H +#define _IRQ_H +#include "peripherals/base.h" + +#define IRQ_BASIC_PENDING ((volatile unsigned int *)(PBASE+0x0000B200)) +#define IRQ_PENDING_1 ((volatile unsigned int *)(PBASE+0x0000B204)) +#define IRQ_PENDING_2 ((volatile unsigned int *)(PBASE+0x0000B208)) +#define FIQ_CONTROL ((volatile unsigned int *)(PBASE+0x0000B20C)) +#define ENABLE_IRQS_1 ((volatile unsigned int *)(PBASE+0x0000B210)) +#define ENABLE_IRQS_2 ((volatile unsigned int *)(PBASE+0x0000B214)) +#define ENABLE_BASIC_IRQS ((volatile unsigned int *)(PBASE+0x0000B218)) +#define DISABLE_IRQS_1 ((volatile unsigned int *)(PBASE+0x0000B21C)) +#define DISABLE_IRQS_2 ((volatile unsigned int *)(PBASE+0x0000B220)) +#define DISABLE_BASIC_IRQS ((volatile unsigned int *)(PBASE+0x0000B224)) + + +#endif // _IRQ_H \ No newline at end of file diff --git a/lab8/include/peripherals/p_mini_uart.h b/lab8/include/peripherals/p_mini_uart.h new file mode 100644 index 000000000..5e78297d8 --- /dev/null +++ b/lab8/include/peripherals/p_mini_uart.h @@ -0,0 +1,20 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_ENABLES ((volatile unsigned int *)(PBASE+0x00215004)) +#define AUX_MU_IO_REG ((volatile unsigned int *)(PBASE+0x00215040)) +#define AUX_MU_IER_REG ((volatile unsigned int *)(PBASE+0x00215044)) +#define AUX_MU_IIR_REG ((volatile unsigned int *)(PBASE+0x00215048)) +#define AUX_MU_LCR_REG ((volatile unsigned int *)(PBASE+0x0021504C)) +#define AUX_MU_MCR_REG ((volatile unsigned int *)(PBASE+0x00215050)) +#define AUX_MU_LSR_REG ((volatile unsigned int *)(PBASE+0x00215054)) +#define AUX_MU_MSR_REG ((volatile unsigned int *)(PBASE+0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int *)(PBASE+0x0021505C)) +#define AUX_MU_CNTL_REG ((volatile unsigned int *)(PBASE+0x00215060)) +#define AUX_MU_STAT_REG ((volatile unsigned int *)(PBASE+0x00215064)) +#define AUX_MU_BAUD_REG ((volatile unsigned int *)(PBASE+0x00215068)) + + +#endif /*_P_MINI_UART_H */ diff --git a/lab8/include/reboot.h b/lab8/include/reboot.h new file mode 100644 index 000000000..55f2df255 --- /dev/null +++ b/lab8/include/reboot.h @@ -0,0 +1,11 @@ +#ifndef _REBOOT_H +#define _REBOOT_H + +#define PM_PASSWORD (0x5a000000) +#define PM_RSTC ((volatile unsigned int *)(0x3F10001c)) +#define PM_WDOG ((volatile unsigned int *)(0x3F100024)) + +void reset(int tick); +void cancel_reset(); + +#endif /*_REBOOT_H */ diff --git a/lab8/include/shell.h b/lab8/include/shell.h new file mode 100644 index 000000000..d4fc954a6 --- /dev/null +++ b/lab8/include/shell.h @@ -0,0 +1,6 @@ +#ifndef SHELL_H +#define SHELL_H + +void shell(); + +#endif \ No newline at end of file diff --git a/lab8/include/signal.h b/lab8/include/signal.h new file mode 100644 index 000000000..47f1dad30 --- /dev/null +++ b/lab8/include/signal.h @@ -0,0 +1,10 @@ +#ifndef _SIGNAL_H +#define _SIGNAL_H + +#include "thread.h" + +void check_and_run_signal(); +void exec_signal(thread_t* t, int signal); +void default_signal_handler(); +void handler_warper(void (*handler)()); +#endif // _SIGNAL_H \ No newline at end of file diff --git a/lab8/include/string.h b/lab8/include/string.h new file mode 100644 index 000000000..8e2de821c --- /dev/null +++ b/lab8/include/string.h @@ -0,0 +1,14 @@ +#ifndef _STRING_H +#define _STRING_H + +#include + +unsigned int is_visible(unsigned int c); +int strcmp(const char* str1, const char* str2); +int memcmp(const void *str1, const void *str2, int n); +void *memcpy(void *dst, const void *src, size_t len); +char *strncpy_(char *dest, const char *src, int n); +int strlen(const char *str); +int strncmp(const char *s1, const char *s2, int n); +int strcpy(char *dst, const char *src); +#endif // _STRING_H \ No newline at end of file diff --git a/lab8/include/syscall.h b/lab8/include/syscall.h new file mode 100644 index 000000000..a6a2e584b --- /dev/null +++ b/lab8/include/syscall.h @@ -0,0 +1,27 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +#include "thread.h" +#include "mini_uart.h" +#include "exception.h" +#include + +int getpid(); +size_t uart_read(char buf[], size_t size); +size_t uart_write(const char buf[], size_t size); +int exec(const char* name, char *const argv[]); +void fork(trapframe_t* tf); +void exit(int status); +int mbox_call(unsigned char ch, unsigned int *mbox); +void kill(int pid); +void signal(int signal, void (*handler)()); +void posix_kill(int pid, int signal); +void sigreturn(); + + +int sys_getpid(); +int sys_fork(); +void sys_exit(int status); +void sys_sigreturn(); + +#endif \ No newline at end of file diff --git a/lab8/include/tasklist.h b/lab8/include/tasklist.h new file mode 100644 index 000000000..337d7a6f3 --- /dev/null +++ b/lab8/include/tasklist.h @@ -0,0 +1,17 @@ +#ifndef _TASKLIST_H +#define _TASKLIST_H + +typedef void (*task_callback_t)(void); + +typedef struct task_t { + struct task_t *prev; + struct task_t *next; + task_callback_t callback; + unsigned long long priority; +} task_t; + +void execute_tasks(); +void create_task(task_callback_t callback, unsigned long long priority); +void enqueue_task(task_t *task); +void execute_tasks_preemptive(); +#endif \ No newline at end of file diff --git a/lab8/include/thread.h b/lab8/include/thread.h new file mode 100644 index 000000000..fa485eaf3 --- /dev/null +++ b/lab8/include/thread.h @@ -0,0 +1,97 @@ +#ifndef _THREAD_H +#define _THREAD_H + + +#define T_STACK_SIZE (10 * 0x1000) // 2^12 = 4096 = 4KB = 1 page +#define SIGNAL_NUM 9 +#define THREAD_MAX_FD 16 + +#include +#include "fs_vfs.h" + +extern int is_init_thread; + +typedef enum thread_state { + TASK_RUNNING, + TASK_WAITING, + TASK_ZOMBIE, +} thread_state; + +// for callee-saved registers +typedef struct callee_reg_t { + uint64_t x19; + uint64_t x20; + uint64_t x21; + uint64_t x22; + uint64_t x23; + uint64_t x24; + uint64_t x25; + uint64_t x26; + uint64_t x27; + uint64_t x28; + uint64_t fp; + uint64_t lr; + uint64_t sp; +} callee_reg_t; + +typedef struct thread_t { + // need to be put as the first variable + callee_reg_t callee_reg; + int tid; // thread id + thread_state state; + void* user_stack; + void* kernel_stack; + void* data; + void* data_size; + + // signal + void (*signal_handler[SIGNAL_NUM+1])(); + // 0: not waiting, 1: waiting + int waiting_signal[SIGNAL_NUM+1]; + int is_processing_signal; + callee_reg_t signal_regs; + + // use in queue + struct thread_t *prev; + struct thread_t *next; + + // use in file + int max_fd; + file fds[THREAD_MAX_FD]; + vnode *working_dir; +} thread_t; + + + +// defined in context_switch.S +extern void switch_to(thread_t* cur, thread_t* next); +extern thread_t* get_current_thread(); + +// queue-related +void push(thread_t** head, thread_t* t); +void push_running(thread_t* t); +thread_t* pop(thread_t** head); // pop front +void pop_t(thread_t** head, thread_t* t); // pop given thread +void print_queue(thread_t* head); +void print_running(); + +void schedule(); +thread_t* create_thread(void (*func)(void)); +thread_t* create_fork_thread(); +thread_t* get_thread_from_tid(int tid); + +void kill_thread(int tid); +void kill_zombies(); + +void thread_init(); +void thread_exit(); +void thread_wait(int tid); + +void idle(); // function for idle thread +void foo(); +void thread_test(); +void run_fork_test(); +void main_fork_test(); +void fork_test(); + +#endif \ No newline at end of file diff --git a/lab8/include/timer.h b/lab8/include/timer.h new file mode 100644 index 000000000..38f21bed6 --- /dev/null +++ b/lab8/include/timer.h @@ -0,0 +1,30 @@ +#ifndef _TIMER_H +#define _TIMER_H + +#define CORE0_TIMER_IRQ_CTRL ((volatile unsigned int *)(0x40000040)) + +typedef void (*timer_callback_t)(void *data); + +typedef struct timer { + struct timer *next; + timer_callback_t callback; + void *data; + unsigned long long timeout; +} timer_t; + +void set_timeout(char* message, unsigned long long timeout); +void print_message(void *data); +void create_timer( + timer_callback_t callback, + void *data, + unsigned long long timeout +); +void create_timer_freq_shift( + timer_callback_t callback, + void *data, + unsigned long long shift +); +void add_timer(timer_t **timer); +void schedule_task(void* data); + +#endif \ No newline at end of file diff --git a/lab8/initramfs.cpio b/lab8/initramfs.cpio new file mode 100644 index 000000000..7a819231a Binary files /dev/null and b/lab8/initramfs.cpio differ diff --git a/lab6/rootfs/file1 b/lab8/rootfs/dir/file1 similarity index 100% rename from lab6/rootfs/file1 rename to lab8/rootfs/dir/file1 diff --git a/lab6/rootfs/file2.txt b/lab8/rootfs/dir/file2.txt similarity index 100% rename from lab6/rootfs/file2.txt rename to lab8/rootfs/dir/file2.txt diff --git a/lab6/rootfs/test3 b/lab8/rootfs/test3 similarity index 100% rename from lab6/rootfs/test3 rename to lab8/rootfs/test3 diff --git a/lab6/rootfs/user_prog.img b/lab8/rootfs/user_prog.img similarity index 100% rename from lab6/rootfs/user_prog.img rename to lab8/rootfs/user_prog.img diff --git a/lab8/src/alloc.c b/lab8/src/alloc.c new file mode 100644 index 000000000..c231259bb --- /dev/null +++ b/lab8/src/alloc.c @@ -0,0 +1,590 @@ +#include "alloc.h" +#include "mini_uart.h" +#include "fdt.h" +#include "initrd.h" +#include "exception.h" +#include + +int debug = 1; + +// `bss_end` is defined in linker script +extern int __heap_top; +volatile char *heap_top; + +page* page_arr = 0; +uint64_t total_page = 0; +free_list_t free_list[MAX_ORDER + 1]; +chunk_info chunk_info_arr[MAX_CHUNK + 1]; + +int buddy(int idx) { + return idx ^ (1 << page_arr[idx].order); +} + +void page_info_addr(void* addr) { + unsigned int idx = ((unsigned long long)addr - (unsigned long long)PAGE_BASE) / PAGE_SIZE; + page_info(&page_arr[idx]); +} + +void page_info(page* p) { + uart_send_string("(addr: 0x"); + uart_hex((unsigned long long)p->addr); + uart_send_string(", idx: "); + uart_hex(p->idx); + uart_send_string(", val: "); + uart_hex(p->val); + uart_send_string(", order: "); + uart_hex(p->order); + uart_send_string(")"); +} + +void print_chunk_info() { + for(int i=0;ival != i) { + uart_send_string("Error: "); + page_info(p); + uart_send_string(" is in free_list["); + uart_hex(i); + uart_send_string("]\n"); + } + cnt ++; + p = p->next; + } + if(cnt != free_list[i].cnt) { + uart_send_string("Error: free_list["); + uart_hex(i); + uart_send_string("].cnt is "); + uart_hex(free_list[i].cnt); + uart_send_string(" but there are "); + uart_hex(cnt); + uart_send_string(" pages\n"); + } + } +} + +unsigned long long align_page(unsigned long long size) { + return (size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); +} + +int log2(unsigned long long size) { + int order = 0; + while (size > 1) { + size >>= 1; + order++; + } + return order; +} + +int is_page(void* addr) { + return (addr - PAGE_BASE) % PAGE_SIZE == 0; +} + +int size2chunkidx(unsigned long long size) { + // split to 6 size of chunk + // 16, 32, 64, 128, 256, 512 + if (size <= 16) { + return 0; + } + if (size <= 32) { + return 1; + } + if (size <= 64) { + return 2; + } + if (size <= 128) { + return 3; + } + if (size <= 256) { + return 4; + } + if(size <= 512){ + return 5; + } + return -1; // use buddy system instead +} + +void init_page_arr() { + total_page = ((uint64_t)PAGE_END - (uint64_t)PAGE_BASE) / (uint64_t)PAGE_SIZE; + if(0 && debug) { + uart_send_string("total_page: "); + uart_hex(total_page); + uart_send_string("\n"); + } + page_arr = (page*)simple_malloc(total_page * sizeof(page)); + char* addr = PAGE_BASE; + for (uint64_t i = 0; i < total_page; i++) { + page_arr[i].addr = addr; + page_arr[i].idx = i; + page_arr[i].val = ALLOCATED; + page_arr[i].order = 0; + page_arr[i].next = 0; // NULL + page_arr[i].prev = 0; // NULL + addr += PAGE_SIZE; + + if(0 && debug) { + page_info(&page_arr[i]); + uart_send_string("\n"); + } + } +} + +void init_chunk_info() { + for(int i=0;i<=MAX_CHUNK;i++) { + chunk_info_arr[i].idx = i; + chunk_info_arr[i].size = 1 << (i + 4); + chunk_info_arr[i].page_head = 0; + chunk_info_arr[i].chunk_head = 0; + chunk_info_arr[i].cnt = 0; + } + print_chunk_info(); +} + +void init_page_allocator() { + for (int i = 0; i < MAX_ORDER + 1; i++) { + free_list[i].head = 0; // NULL + free_list[i].cnt = 0; + } + for(uint64_t i=0;i val > 0){ + uart_send_string("Error: "); + page_info(r_page); + uart_send_string(" is already free\n"); + while(1); + } + + if(debug) { + uart_send_string("release "); + page_info(r_page); + uart_send_string("\n"); + } + int order = r_page -> order; + r_page->val = order; + insert_page(r_page, order); + merge(r_page); +} + +void merge(page* m_page) { + int a_idx = m_page->idx; + if(page_arr[a_idx].val < 0) { + uart_send_string("Error: "); + page_info(&page_arr[a_idx]); + uart_send_string(" is not free\n"); + while(1); + } + while(page_arr[a_idx].order + 1 < MAX_ORDER) { + int b_idx = buddy(a_idx); + if(buddy(b_idx) != a_idx + || page_arr[a_idx].val < 0 + || page_arr[b_idx].val < 0) { + break; + } + if(a_idx > b_idx) { + // swap a_idx and b_idx + int tmp = a_idx; + a_idx = b_idx; + b_idx = tmp; + } + page* a_page = &page_arr[a_idx]; + page* b_page = &page_arr[b_idx]; + if(0 && debug) { + uart_send_string("merge "); + page_info(a_page); + uart_send_string(" and "); + page_info(b_page); + uart_send_string("\n"); + } + if(b_page->order != a_page->order) { + uart_send_string("Error: "); + page_info(a_page); + uart_send_string(" and "); + page_info(b_page); + uart_send_string(" have different order\n"); + while(1); + } + // b_page becomes a_page's buddy + // b_page->order = a_page->order; + + // remove a_page and b_page from free_list + erase_page(a_page, a_page->order); + erase_page(b_page, b_page->order); + b_page->val = BUDDY; + + // a_page's order increases + a_page -> order++; + a_page -> val++; + // insert a_page to free_list + insert_page(a_page, a_page->order); + } +} + +page* truncate(page* t_page, int order) { + if(debug) { + uart_send_string("truncate "); + page_info(t_page); + uart_send_string(" to order "); + uart_hex(order); + uart_send_string("\n"); + } + int idx = t_page->idx; + while(t_page->order > order) { + t_page->order--; + int buddy_idx = buddy(idx); + page* buddy_page = &(page_arr[buddy_idx]); + buddy_page->val = ALLOCATED; + buddy_page->order = t_page->order; + + if(debug) { + // split page into two buddies + uart_send_string("split "); + page_info(t_page); + uart_send_string(" and "); + page_info(buddy_page); + uart_send_string("\n"); + } + release(buddy_page); + } + + return t_page; +} + +void insert_page(page* new_page, int order) { + if(new_page -> val < 0 || order < 0) { + uart_send_string("Error: insert_page "); + page_info(new_page); + uart_send_string(" with val < 0\n"); + while(1); + } + new_page->val = order; + new_page->order = order; + new_page->next = free_list[order].head; + if (free_list[order].head != 0) { + free_list[order].head -> prev = new_page; + } + free_list[order].head = new_page; + free_list[order].cnt++; + return; +} + +page* pop_page(int order) { + if(free_list[order].cnt == 0) { + uart_send_string("Error: pop_page from free_list["); + uart_hex(order); + uart_send_string("] with cnt = 0\n"); + while(1); + } + page* ret = free_list[order].head; + free_list[order].head = ret->next; + if (free_list[order].head -> next != 0) { + free_list[order].head -> prev = 0; + } + free_list[order].cnt--; + return ret; +} + +void erase_page(page* e_page, int order) { + if(e_page -> val < 0) { + uart_send_string("Error: erase_page "); + page_info(e_page); + uart_send_string(" with val < 0\n"); + while(1); + } + if(e_page -> order != order) { + uart_send_string("Error: erase_page "); + page_info(e_page); + uart_send_string(" with order "); + uart_hex(e_page->order); + uart_send_string(" but want to erase with order "); + uart_hex(order); + uart_send_string("\n"); + while(1); + } + if (e_page -> prev != 0) { + e_page -> prev->next = e_page -> next; + } + else { + free_list[order].head = e_page->next; + } + if (e_page->next != 0) { + e_page->next->prev = e_page->prev; + } + e_page->next = 0; + e_page->prev = 0; + free_list[order].cnt--; +} +void* chunk_alloc(int idx) { + int chunk_size = chunk_info_arr[idx].size; + if(debug) { + uart_send_string("chunk_alloc: "); + uart_hex(idx); + uart_send_string(" (size: "); + uart_hex(chunk_size); + uart_send_string(")\n"); + uart_send_string("\n"); + } + + + if(chunk_info_arr[idx].chunk_head == 0) { + if(debug) { + // no available chunk + uart_send_string("no available chunk\n"); + } + // create a new page + page_info_t* new_page = page_alloc(PAGE_SIZE); + new_page -> idx = idx; + + // insert new_page to page list + new_page -> next = chunk_info_arr[idx].page_head; + chunk_info_arr[idx].page_head = new_page; + + // split page to chunk + for( + unsigned char* addr = new_page + PAGE_SIZE - chunk_size; + addr > new_page + sizeof(page_info_t); + addr -= chunk_size + ) { + chunk* new_chunk = (chunk*)addr; + new_chunk -> addr = addr; + new_chunk -> next = chunk_info_arr[idx].chunk_head; + chunk_info_arr[idx].chunk_head = new_chunk; + chunk_info_arr[idx].cnt ++; + if(debug) { + // uart_hex(chunk_size); + uart_send_string("new chunk: 0x"); + uart_hex((unsigned long long)addr); + uart_send_string("\n"); + uart_hex((unsigned char*)new_page + sizeof(page_info_t)); + uart_send_string("\n"); + } + } + } + if(debug) { + // find available chunk + uart_send_string("find available chunk\n"); + // print addr + uart_send_string("chunk_info_arr["); + uart_hex(idx); + uart_send_string("].chunk_head->addr: 0x"); + uart_hex((unsigned long long)chunk_info_arr[idx].chunk_head->addr); + uart_send_string("\n"); + } + chunk* res_chunk = chunk_info_arr[idx].chunk_head; + chunk_info_arr[idx].chunk_head = res_chunk->next; + chunk_info_arr[idx].cnt --; + return (void*)res_chunk->addr; +} + +void* chunk_free(void* addr) { + if(debug) { + uart_send_string("Releasing chunk: 0x"); + uart_hex((unsigned long long)addr); + uart_send_string("\n"); + } + // convert chunk addr to page addr + void* page_addr = (void*)((uint64_t)addr & (~(PAGE_SIZE - 1))); + page_info_t* chunk_page = (page_info_t*)page_addr; + int idx = chunk_page -> idx; + chunk* new_chunk = (chunk*)addr; + new_chunk -> addr = addr; + // insert new_chunk to free list + new_chunk -> next = chunk_info_arr[idx].chunk_head; + chunk_info_arr[idx].chunk_head = new_chunk; + chunk_info_arr[idx].cnt ++; +} + +// Set heap base address +void alloc_init() +{ + heap_top = ((volatile unsigned char *)(0x10000000)); + char* old_heap_top = heap_top; + // uart_send_string("heap_top: "); + // uart_hex((unsigned long long)heap_top); + // uart_send_string("\n"); + init_page_arr(); + // reserve memory + memory_reserve((void*)0x0000, (void*)0x1000); // spin tables + memory_reserve((void*)ramfs_base, (void*)ramfs_end); // ramfs + // memory_reserve((void*)dtb_base, (void*)dtb_end); // dtb + + // kernel, bss, stack + // 0x80000 = _start + // 0x0200000 = __stack_end + memory_reserve((void*)0x80000, (void*)0x0200000); + + if(debug) { + uart_send_string("old_heap_top: "); + uart_hex((unsigned long)old_heap_top); + uart_send_string("\n"); + uart_send_string("heap_top: "); + uart_hex((unsigned long)heap_top); + uart_send_string("\n"); + } + // heap + memory_reserve((void*)old_heap_top, (void*)heap_top); + debug = 0; + init_page_allocator(); + // debug = 1; + check_free_list(); + // print the number of free pages for each order + // if(debug) { + // } + free_list_info(); + // init chunk info + init_chunk_info(); +} + +void memory_reserve(void* start, void* end) { + if(debug) { + uart_send_string("memory_reserve: "); + uart_hex((unsigned long)start); + uart_send_string(" ~ "); + uart_hex((unsigned long)end); + uart_send_string("\n"); + } + // Align start to the nearest page boundary (round down) + uint64_t aligned_start = (uint64_t)start & ~(PAGE_SIZE - 1); + // Align end to the nearest page boundary (round up) + uint64_t aligned_end = ((uint64_t)end + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + uint64_t s_idx = (aligned_start - (uint64_t)PAGE_BASE) / PAGE_SIZE; + uint64_t e_idx = (aligned_end - (uint64_t)PAGE_BASE) / PAGE_SIZE; + + for (uint64_t i = s_idx; i <= e_idx; i++) { + page_arr[i].val = RESERVED; + page_arr[i].order = 0; + } +} + +void* page_alloc(unsigned long long size) { + int order = log2(align_page(size) / PAGE_SIZE); + if(debug) { + uart_send_string("Requesting "); + uart_hex(size); + uart_send_string(" bytes, order: "); + uart_hex(order); + uart_send_string("\n"); + } + page* res_page = 0; + for(int i=order; i<=MAX_ORDER; i++) { + if(debug) { + uart_send_string("Checking free_list["); + uart_hex(i); + uart_send_string("] = "); + uart_hex(free_list[i].cnt); + uart_send_string("\n"); + } + if(free_list[i].cnt > 0) { + res_page = pop_page(i); + break; + } + } + if(!res_page){ + if(0 && debug) { + uart_send_string("No enough memory\n"); + } + return 0; + } + res_page -> val = ALLOCATED; + truncate(res_page, order); + if(debug) { + uart_send_string("Allocated "); + page_info(res_page); + uart_send_string("\n"); + } + return (void*)res_page->addr; +} + +void page_free(void* addr) { + unsigned int idx = ((unsigned long long)addr - (unsigned long long)PAGE_BASE) / PAGE_SIZE; + if(0 && debug) { + uart_send_string("0x"); + uart_hex((unsigned long long)addr); + uart_send_string(" -> "); + uart_hex(idx); + uart_send_string(" Freeing "); + page_info(&page_arr[idx]); + uart_send_string("\n"); + } + release(&page_arr[idx]); +} + +void* kmalloc(unsigned long long size) { + el1_interrupt_disable(); + if(size == 0){ + el1_interrupt_enable(); + return 0; + } + // void* addr = page_alloc(size); + // free_list_info(); + // return addr; + int idx = size2chunkidx(size); + + void* addr; + int use_page_only = 0; + if(use_page_only) { + addr = page_alloc(size); + } else if(idx >= 0) { + addr = chunk_alloc(idx); + } else { + addr = page_alloc(size); + } + el1_interrupt_enable(); + return addr; +} + +void kfree(void* addr) { + if(!addr) return; + el1_interrupt_disable(); + if(is_page(addr)) { + // uart_send_string("page addr release\n"); + page_free(addr); + } + else { + // uart_send_string("chunk addr release\n"); + chunk_free(addr); + } + // free_list_info(); + el1_interrupt_enable(); +} + +void *simple_malloc(unsigned long long size) +{ + void *p = (void *)heap_top; + heap_top += size; + return p; +} \ No newline at end of file diff --git a/lab8/src/boot.S b/lab8/src/boot.S new file mode 100644 index 000000000..596e47891 --- /dev/null +++ b/lab8/src/boot.S @@ -0,0 +1,182 @@ +#include "mm.h" +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +.section ".text.boot" + +.globl _start + +_start: + mrs x1, mpidr_el1 + and x1, x1,#0xFF // Check processor id + cbz x1, master // Hang for all non-primary CPU + +proc_hang: + wfe + b proc_hang + +master: + bl from_el2_to_el1 + +// core_timer_enable: +// mov x20, 1 +// msr cntp_ctl_el0, x20 // enable timer +// mrs x20, cntfrq_el0 +// msr cntp_tval_el0, x20 // set expired time +// mov x20, 2 +// ldr x1, =CORE0_TIMER_IRQ_CTRL +// str w20, [x1] // unmask timer interrupt + +set_exception_vector: + // set exception vector table + adr x20, exception_vector_table + msr vbar_el1, x20 // vector base address register + +set_stack: + ldr x1, =__stack_end // __stack_end = 0x0200000 + mov sp, x1 + ldr x1, =bss_begin + ldr w2, =__bss_size + +bss_reset: + cbz w2, run_main + // save 0 and plus 8 + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, bss_reset + +run_main: + bl main + b proc_hang // should never come here + + +from_el2_to_el1: + mov x1, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x1 + // 0x3c5 = 0b1111000101 + // 9876543210 + // DAIFRM + // 0x345 = 0b1101000101 + // 9876543210 + // DAIFRM + // M[3:0] = 0101 = EL1h + mov x1, 0x345 // EL1h (SPSel = 1) with interrupt disabled + msr spsr_el2, x1 + msr elr_el2, lr + eret // return to EL1 + + +// save general registers to stack +.macro save_all + sub sp, sp, 32*9 + stp x0, x1, [sp, 16*0] + stp x2, x3, [sp, 16*1] + stp x4, x5, [sp, 16*2] + stp x6, x7, [sp, 16*3] + stp x8, x9, [sp, 16*4] + stp x10, x11, [sp, 16*5] + stp x12, x13, [sp, 16*6] + stp x14, x15, [sp, 16*7] + stp x16, x17, [sp, 16*8] + stp x18, x19, [sp, 16*9] + stp x20, x21, [sp, 16*10] + stp x22, x23, [sp, 16*11] + stp x24, x25, [sp, 16*12] + stp x26, x27, [sp, 16*13] + stp x28, x29, [sp, 16*14] + mrs x0, spsr_el1 + stp x30, x0, [sp, 16*15] + mrs x0, elr_el1 + mrs x1, sp_el0 + stp x0, x1, [sp, 16*16] +.endm + +// load general registers from stack +.macro load_all + ldp x0, x1, [sp, 16*16] + msr elr_el1, x0 + msr sp_el0, x1 + ldp x30, x0, [sp, 16*15] + msr spsr_el1, x0 + ldp x0, x1, [sp, 16*0] + ldp x2, x3, [sp, 16*1] + ldp x4, x5, [sp, 16*2] + ldp x6, x7, [sp, 16*3] + ldp x8, x9, [sp, 16*4] + ldp x10, x11, [sp, 16*5] + ldp x12, x13, [sp, 16*6] + ldp x14, x15, [sp, 16*7] + ldp x16, x17, [sp, 16*8] + ldp x18, x19, [sp, 16*9] + ldp x20, x21, [sp, 16*10] + ldp x22, x23, [sp, 16*11] + ldp x24, x25, [sp, 16*12] + ldp x26, x27, [sp, 16*13] + ldp x28, x29, [sp, 16*14] + add sp, sp, 32*9 +.endm + +exception_handler: + save_all + bl exception_handler_c + load_all + eret + +irq_exception_handler: + save_all + bl irq_exception_handler_c + load_all + eret + +user_exception_handler: + save_all + mov x0, sp // trapframe store in the top of kernel stack + bl user_exception_handler_c + load_all + eret + +user_irq_exception_handler: + save_all + bl user_irq_exception_handler_c + load_all + eret + +// EL1 exception vector table +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table +exception_vector_table: + b exception_handler // branch to a handler function. + .align 7 // entry size is 0x80, .align will pad 0 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + b exception_handler + .align 7 + b irq_exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + b user_exception_handler + .align 7 + b user_irq_exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + b exception_handler + .align 7 + diff --git a/lab8/src/c_utils.c b/lab8/src/c_utils.c new file mode 100644 index 000000000..58abc19e9 --- /dev/null +++ b/lab8/src/c_utils.c @@ -0,0 +1,66 @@ +#include "c_utils.h" +#include "mini_uart.h" +#include "string.h" + +void uart_recv_command(char *str){ + char c; + int i = 0; + while(1){ + c = uart_recv(); + if(c == '\r'){ + str[i] = '\0'; + break; + } else if(c == 127 || c == 8){ + if(i > 0){ + i--; + uart_send('\b'); + uart_send(' '); + uart_send('\b'); + } + continue; + } + if(is_visible(c)){ + str[i] = c; + i++; + uart_send(c); + } + } + +} + +int align4(int n) +{ + return n + (4 - n % 4) % 4; +} + + +int atoi(const char *s){ + int sign = 1; + int i = 0; + int result = 0; + + while(s[i] == ' ') + i ++; + + if(s[i] == '-') { + sign = -1; + i++; + } + + while(s[i] >= '0' && s[i] <= '9') { + result = result * 10 + (s[i] - '0'); + i ++; + } + + return sign * result; +} + +unsigned int endian_big2little(unsigned int x) { + return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | ((x & 0xFF000000) >> 24); +} + +void delay (unsigned int loop) { + while (loop --) { + asm volatile("nop"); + } +} diff --git a/lab8/src/context_switch.S b/lab8/src/context_switch.S new file mode 100644 index 000000000..467c1c9dc --- /dev/null +++ b/lab8/src/context_switch.S @@ -0,0 +1,51 @@ +.global switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + msr tpidr_el1, x1 + ret + + +.global save_regs +save_regs: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + ret + +.global load_regs +load_regs: + ldp x19, x20, [x0, 16 * 0] + ldp x21, x22, [x0, 16 * 1] + ldp x23, x24, [x0, 16 * 2] + ldp x25, x26, [x0, 16 * 3] + ldp x27, x28, [x0, 16 * 4] + ldp fp, lr, [x0, 16 * 5] + ldr x9, [x0, 16 * 6] + mov sp, x9 + ret + +.global get_current_thread +get_current_thread: + mrs x0, tpidr_el1 + ret \ No newline at end of file diff --git a/lab8/src/exception.c b/lab8/src/exception.c new file mode 100644 index 000000000..e39ca1baf --- /dev/null +++ b/lab8/src/exception.c @@ -0,0 +1,290 @@ +#include + +#include "exception.h" +#include "mini_uart.h" +#include "peripherals/irq.h" +#include "timer.h" +#include "tasklist.h" +#include "syscall.h" +#include "alloc.h" +#include "thread.h" +#include "reboot.h" +#include "signal.h" +#include "fs_vfs.h" +#include "c_utils.h" + +extern timer_t *timer_head; + +void el1_interrupt_enable(){ + asm volatile ("msr daifclr, 0xf"); // umask all DAIF +} + +void el1_interrupt_disable(){ + asm volatile ("msr daifset, 0xf"); // mask all DAIF +} + +void exception_handler_c() { + uart_send_string("Exception Occurs!\n"); + + //read spsr_el1 + unsigned long long spsr_el1 = 0; + asm volatile("mrs %0, spsr_el1":"=r"(spsr_el1)); + uart_send_string("spsr_el1: "); + uart_hex(spsr_el1); + uart_send_string("\n"); + + //read elr_el1 + unsigned long long elr_el1 = 0; + asm volatile("mrs %0, elr_el1":"=r"(elr_el1)); + uart_send_string("elr_el1: "); + uart_hex(elr_el1); + uart_send_string("\n"); + + //esr_el1 + unsigned long long esr_el1 = 0; + asm volatile("mrs %0, esr_el1":"=r"(esr_el1)); + uart_send_string("esr_el1: "); + uart_hex(esr_el1); + uart_send_string("\n"); + + //ec + unsigned ec = (esr_el1 >> 26) & 0x3F; //0x3F = 0b111111(6) + uart_send_string("ec: "); + uart_hex(ec); + uart_send_string("\n"); + // while(1); + reset(1); +} + +void user_irq_exception_handler_c() { + // uart_send_string("User IRQ Exception Occurs!\n"); + el1_interrupt_disable(); + unsigned int irq = *IRQ_PENDING_1; + unsigned int interrupt_source = *CORE0_INTERRUPT_SOURCE; + + if((irq & IRQ_PENDING_1_AUX_INT) && (interrupt_source & INTERRUPT_SOURCE_GPU)){ + // uart_send_string("UART interrupt\n"); + uart_irq_handler(); + } + if(interrupt_source & INTERRUPT_SOURCE_CNTPNSIRQ) { + core_timer_disable(); + create_task(user_irq_timer_exception, 10); + execute_tasks_preemptive(); + } + check_and_run_signal(); + schedule(); +} + +void irq_exception_handler_c(){ + // uart_send_string("IRQ Exception Occurs!\n"); + unsigned int irq = *IRQ_PENDING_1; + unsigned int interrupt_source = *CORE0_INTERRUPT_SOURCE; + + if((irq & IRQ_PENDING_1_AUX_INT) && (interrupt_source & INTERRUPT_SOURCE_GPU) ){ + // uart_send_string("kernel UART interrupt\n"); + uart_irq_handler(); + } + else if(interrupt_source & INTERRUPT_SOURCE_CNTPNSIRQ) { + // uart_send_string("\nkernel Timer interrupt"); + core_timer_disable(); + create_task(irq_timer_exception, 10); + execute_tasks_preemptive(); + + } + check_and_run_signal(); + schedule(); +} + +void user_exception_handler_c(trapframe_t* tf) { + // check svc syscall from el0 + unsigned long long esr_el1 = 0; + asm volatile("mrs %0, esr_el1":"=r"(esr_el1)); + unsigned ec = (esr_el1 >> 26) & 0x3F; + + if(ec != 0x15) { + exception_handler_c(); + return; + } + int print_info = 0; + int syscall_code = tf -> x[8]; + el1_interrupt_enable(); + switch (syscall_code) { + case 0: + tf -> x[0] = getpid(); + break; + case 1: + tf -> x[0] = uart_read(tf -> x[0], tf -> x[1]); + break; + case 2: + tf -> x[0] = uart_write(tf -> x[0], tf -> x[1]); + break; + case 3: + tf -> x[0] = exec((const char*)tf -> x[0], tf->x[1]); + break; + case 4: + if(print_info) uart_send_string("[INFO] system call: fork\n"); + core_timer_disable(); + // el1_interrupt_disable(); + fork(tf); + // el1_interrupt_enable(); + core_timer_enable(); + break; + case 5: + exit(0); + break; + case 6: + tf -> x[0] = mbox_call( + (unsigned char)tf -> x[0], (unsigned int*)tf -> x[1] + ); + break; + case 7: + kill((int)tf -> x[0]); + break; + case 8: + signal((int)tf -> x[0], (void*)tf -> x[1]); + break; + case 9: + posix_kill((int)tf -> x[0], (int)tf -> x[1]); + break; + case 11: + if(print_info) uart_send_string("[INFO] system call: open\n"); + syscall_open(tf, (const char*)tf -> x[0], tf -> x[1]); + break; + case 12: + if(print_info) uart_send_string("[INFO] system call: close\n"); + syscall_close(tf, tf -> x[0]); + break; + case 13: + if(print_info) uart_send_string("[INFO] system call: write\n"); + // core_timer_disable(); + // el1_interrupt_disable(); + syscall_write(tf, tf -> x[0], (const void*)tf -> x[1], tf -> x[2]); + // el1_interrupt_enable(); + // core_timer_enable(); + break; + case 14: + if(print_info) uart_send_string("[INFO] system call: read\n"); + syscall_read(tf, tf -> x[0], (void*)tf -> x[1], tf -> x[2]); + break; + case 15: + if(print_info) uart_send_string("[INFO] system call: mkdir\n"); + syscall_mkdir(tf, (const char*)tf -> x[0], tf -> x[1]); + break; + case 16: + if(print_info) uart_send_string("[INFO] system call: mount\n"); + syscall_mount( + tf, + (const char*)tf -> x[0], // ignore source + (const char*)tf -> x[1], + (const char*)tf -> x[2], + 0, // ignore flags + 0 // ignore data + ); + break; + case 17: + if(print_info) uart_send_string("[INFO] system call: chdir\n"); + syscall_chdir(tf, (const char*)tf -> x[0]); + break; + case 18: + if(print_info) uart_send_string("[INFO] system call: lseek64\n"); + // core_timer_disable(); + // el1_interrupt_disable(); + syscall_lseek64(tf, tf -> x[0], tf -> x[1], tf -> x[2]); + // el1_interrupt_enable(); + // core_timer_enable(); + break; + case 19: + if(print_info) uart_send_string("[INFO] system call: ioctl\n"); + syscall_ioctl( + tf, + tf -> x[0], + tf -> x[1], + tf -> x[2], + tf -> x[3], + tf -> x[4], + tf -> x[5] + ); + break; + case 20: + sigreturn(); + break; + } + el1_interrupt_disable(); + // uart_send_string("sysre\n"); + return; +} + +void irq_timer_exception(){ + // uart_send_string("enter timer\n"); + core_timer_disable(); + while(timer_head){ + unsigned long long current_time; + asm volatile("mrs %0, cntpct_el0":"=r"(current_time)); + if(timer_head -> timeout <= current_time) { + timer_t *timer = timer_head; + timer -> callback(timer -> data); + timer_head = timer_head -> next; + kfree(timer); + } else { + break; + } + } + // uart_send_string("exit timer\n"); + if(timer_head){ + // uart_send_string("have timer\n"); + asm volatile("msr cntp_ctl_el0, %0"::"r"(1)); + asm volatile("msr cntp_cval_el0, %0"::"r"(timer_head -> timeout)); + } else { + // uart_send_string("no timer\n"); + asm volatile("msr cntp_ctl_el0, %0" :: "r"(0)); + } + core_timer_enable(); +} + +void user_irq_timer_exception(){ + // uart_send_string("enter timer\n"); + core_timer_disable(); + while(timer_head){ + unsigned long long current_time; + asm volatile("mrs %0, cntpct_el0":"=r"(current_time)); + if(timer_head -> timeout <= current_time) { + timer_t *timer = timer_head; + timer -> callback(timer -> data); + timer_head = timer_head -> next; + kfree(timer); + } else { + break; + } + } + if(timer_head){ + asm volatile("msr cntp_ctl_el0, %0"::"r"(1)); + asm volatile("msr cntp_cval_el0, %0"::"r"(timer_head -> timeout)); + } else { + asm volatile("msr cntp_ctl_el0, %0" :: "r"(0)); + } + core_timer_enable(); +} + + +void core_timer_init() { + asm volatile("msr cntp_ctl_el0, %0"::"r"(1)); + uint64_t freq; + asm volatile("mrs %0, cntfrq_el0" : "=r"(freq)); + freq = freq << 5; + asm volatile("msr cntp_tval_el0, %0" : : "r"(freq)); + + *CORE0_TIMER_IRQ_CTRL = 2; + + uint64_t tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); +} + +void core_timer_enable(){ + *CORE0_TIMER_IRQ_CTRL = 2; +} + +void core_timer_disable() { + *CORE0_TIMER_IRQ_CTRL = 0; +} \ No newline at end of file diff --git a/lab8/src/fdt.c b/lab8/src/fdt.c new file mode 100644 index 000000000..89d1054d3 --- /dev/null +++ b/lab8/src/fdt.c @@ -0,0 +1,98 @@ +#include "fdt.h" + +char* dtb_base; +char* dtb_end; + +void fdt_traverse(dtb_callback callback) +{ + struct fdt_header *header = (struct fdt_header *)dtb_base; + dtb_end = dtb_base + endian_big2little(header->totalsize); + // fdt header magic 0xD00DFEED (big-endian) + if (endian_big2little(header->magic) != 0xD00DFEED) + { + uart_send_string("fdt_traverse: wrong magic in fdt_traverse\n"); + uart_send_string("expect: 0XD00DFEED\nget:"); + uart_hex(endian_big2little(header->magic)); + uart_send_string("\n"); + return; + } + + // length in bytes of structure block section of dtb + unsigned int struct_size = endian_big2little(header->size_dt_struct); + + // check hackmd notes about the picture of DTB structure + // header is address of fdt_header, so we need (char *) + // offset in bytes of the structure block from beginning of header + // to locate struct start + char *dt_struct_ptr = (char *)((char *)header + endian_big2little(header->off_dt_struct)); + // offset in bytes of strings block from beginning of header + // to locate string start + // fdt_prop use string_ptr + nameoff to get the pathname + char *dt_strings_ptr = (char *)((char *)header + endian_big2little(header->off_dt_strings)); + + // parse from struct begin to end + char *end = (char *)dt_struct_ptr + struct_size; + char *pointer = dt_struct_ptr; + + // for the later parsing + unsigned int len; + char* name; + + // according to lexical structure + while (pointer < end) + { + // lexical big-endian-32-bit integer + // all tokens shall be alligned on 32-bit boundary + unsigned int token_type = endian_big2little(*(unsigned int *)pointer); + pointer += 4; + + // lexical structure + switch (token_type) + { + // begin of node's representation + case FDT_BEGIN_NODE: + // move node's unit name + // string end \0 + pointer += strlen(pointer); + // node name is followed by zeroed padding bytes + // allign + pointer += (4 - (unsigned long long)pointer % 4); + break; + + // end of node's representation + case FDT_END_NODE: + break; + + case FDT_PROP: + + // len | name offset | address + // uint32_t + // length of prop values in byte + len = endian_big2little(*(unsigned int *)pointer); + pointer += 4; + + // nameoff save offset of string blocks + // strings_ptr + nameoff get the name + name = (char *)dt_strings_ptr + endian_big2little(*(unsigned int *)pointer); + pointer += 4; + + // check node is initrd-start/end and set cpio_start/end address + callback(token_type, name, pointer, len); + // address, byte string of length len + pointer += len; + // followed by zeroed padding bytes + if ((unsigned long long)pointer % 4 != 0) + pointer += 4 - (unsigned long long)pointer % 4; // alignment 4 byte + break; + // ** cant skip + // ignore NOP + case FDT_NOP: + break; + // marks end of structures block + case FDT_END: + break; + default: + return; + } + } +} diff --git a/lab8/src/fs_cpiofs.c b/lab8/src/fs_cpiofs.c new file mode 100644 index 000000000..4b45e61b4 --- /dev/null +++ b/lab8/src/fs_cpiofs.c @@ -0,0 +1,500 @@ +#include "fs_cpio.h" +#include "initrd.h" +#include "c_utils.h" +#include "mini_uart.h" + +vnode cpio_root_node; +vnode mount_old_node; +int cpio_mounted; + +// define struct +filesystem static_cpiofs = { + .name = "cpiofs", + .mount = cpiofs_mount + // don't need alloc vnode because this fs is read-only +}; + +struct vnode_operations cpiofs_v_ops = { + .lookup = cpiofs_lookup, + .create = cpiofs_create, + .mkdir = cpiofs_mkdir, + .isdir = cpiofs_isdir, + .getname = cpiofs_getname, + .getsize = cpiofs_getsize, +}; + +struct file_operations cpiofs_f_ops = { + .write = cpiofs_write, + .read = cpiofs_read, + .open = cpiofs_open, + .close = cpiofs_close, + .lseek64 = cpiofs_lseek64, + .ioctl = cpiofs_ioctl, +}; + + +// methods +int cpiofs_mount(filesystem *fs, mount *mnt) { + vnode *backup_node, *cur_node; + cpiofs_internal *internal; + const char* name; + + if(cpio_mounted) { + uart_send_string("cpiofs_mount: already mounted\n"); + return -1; + } + + cur_node = mnt->root; + + cur_node -> v_ops -> getname(cur_node, &name); + + internal = cpio_root_node.internal; + + internal -> name = name; + + mount_old_node.mount = cur_node -> mount; + mount_old_node.v_ops = cur_node -> v_ops; + mount_old_node.f_ops = cur_node -> f_ops; + mount_old_node.internal = cur_node -> internal; + mount_old_node.parent = cur_node -> parent; + + cur_node -> mount = mnt; + cur_node -> v_ops = cpio_root_node.v_ops; + cur_node -> f_ops = cpio_root_node.f_ops; + cur_node -> internal = internal; + + cpio_mounted = 1; + + return 0; +} + +int cpiofs_lookup(vnode *dir_node, vnode **target, const char *component_name) { + cpiofs_internal *internal, *entry; + + internal = dir_node -> internal; + + if(internal -> type != CPIOFS_TYPE_DIR) { + uart_send_string("cpiofs_lookup: not a directory\n"); + return -1; + } + + list_for_each_entry(entry, &internal -> dir.list, list) { + uart_send_string("cpiofs_lookup: entry -> name: "); + uart_send_string(entry -> name); + uart_send_string("\n"); + if(strcmp(entry -> name, component_name) == 0) { + break; + } + } + + if(&entry -> list == &internal -> dir.list) { + uart_send_string("cpiofs_lookup: file not found\n"); + return -1; + } + char* name; + uart_send_string("entry -> name: "); + uart_send_string(entry -> name); + uart_send_string("\n"); + uart_send_string("entry -> internal -> name: "); + entry -> node -> v_ops -> getname(entry -> node, &name); + uart_send_string(name); + uart_send_string("\n"); + + *target = entry -> node; + + return 0; +} + +int cpiofs_create(vnode *dir_node, vnode **target, const char *component_name) { + return -1; +} + +int cpiofs_mkdir(vnode *dir_node, vnode **target, const char *component_name) { + return -1; +} + +int cpiofs_isdir(vnode *dir_node) { + cpiofs_internal *internal; + + internal = dir_node -> internal; + + if (internal -> type != CPIOFS_TYPE_DIR) { + return 0; + } + + return 1; +} + +int cpiofs_getname(vnode *dir_node, const char **name) { + cpiofs_internal *internal = dir_node -> internal; + *name = internal -> name; + + return 0; +} + +int cpiofs_getsize(vnode *dir_node) { + cpiofs_internal *internal = dir_node -> internal; + if (internal -> type == CPIOFS_TYPE_DIR) { + uart_send_string("cpiofs_getsize: is a directory\n"); + return -1; + } + + return internal -> file.size; +} + +int cpiofs_open(vnode *file_node, file *target) { + target -> f_ops = file_node -> f_ops; + target -> vnode = file_node; + target -> f_pos = 0; + + return 0; +} + +int cpiofs_close(file *target) { + target -> f_ops = NULL; + target -> vnode = NULL; + target -> f_pos = 0; + + return 0; +} + +int cpiofs_write(file *target, const void *buf, size_t len) { + return -1; +} + +int cpiofs_read(file *target, void *buf, size_t len) { + cpiofs_internal* internal = target -> vnode -> internal; + uart_send_string("cpiofs_read: internal -> name: "); + uart_send_string(internal -> name); + uart_send_string("\n"); + uart_send_string("cpiofs_read: internal -> type: "); + uart_hex(internal -> type); + uart_send_string("\n"); + if(internal -> type != CPIOFS_TYPE_FILE) { + uart_send_string("cpiofs_read: not a file\n"); + return -1; + } + + if(len > internal -> file.size - target -> f_pos) { + len = internal -> file.size - target -> f_pos; + } + + if(!len) { + return 0; + } + memcpy(buf, internal -> file.data + target -> f_pos, len); + target -> f_pos += len; + + return len; +} + +long cpiofs_lseek64(file *target, long offset, int whence) { + int filesize; + int base; + + filesize = target -> vnode -> v_ops -> getsize(target -> vnode); + + if (filesize < 0) { + return -1; + } + + switch(whence) { + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = target -> f_pos; + break; + case SEEK_END: + base = filesize; + break; + default: + return -1; + } + + if(base + offset > filesize) { + return -1; + } + + target -> f_pos = base + offset; + + return 0; +} + +int cpiofs_ioctl(struct file *file, uint64_t request, va_list args) { + return -1; +} + +uint32_t cpio_read_8hex(const char *s) { + int r = 0; + int n = 8; + while (n-- > 0) { + r = r << 4; + if (*s >= 'A') + r += *s++ - 'A' + 10; + else if (*s >= '0') + r += *s++ - '0'; + } + return r; +} + +vnode *cpio_get_vnode_from_path(vnode *dir_node, const char **name) { + vnode* result; + const char* start; + const char* end; + char buf[256]; + + start = end = *name; + + if(*start == '/') { + result = &cpio_root_node; + } else { + result = dir_node; + } + + while(1) { + if(!strncmp("./", start, 2)) { + start += 2; + end = start; + continue; + } else if(!strncmp("../", start, 3)) { + if(result -> parent) { + result = result -> parent; + } + start += 3; + end = start; + continue; + } + + while(*end != '\0' && *end != '/') { + end++; + } + + if(*end == '/') { + int ret; + + if(start == end) { + end ++; + start = end; + continue; + } + + memcpy(buf, start, end - start); + buf[end - start] = '\0'; + + ret = result -> v_ops -> lookup(result, &result, buf); + uart_send_string("cpio_get_vnode_from_path lookup ret: "); + uart_hex(ret); + uart_send_string("\n"); + if(ret < 0) { + return 0; + } + + end ++; + start = end; + } else { + break; + } + } + + *name = *start ? start : 0; + + return result; +} + +void cpio_init_mkdir(const char *pathname) { + char* curname; + vnode *dir_node; + vnode *new_dir_node; + cpiofs_internal *internal; + cpiofs_internal *new_internal; + // use kmalloc to allocate memory + curname = (char *)kmalloc(strlen(pathname) + 1); + strcpy(curname, pathname); + dir_node = cpio_get_vnode_from_path(&cpio_root_node, &curname); + + if(!dir_node) { + uart_send_string("cpio_init_mkdir: directory not found\n"); + return; + } + + if(!curname) { + uart_send_string("cpio_init_mkdir: invalid pathname\n"); + return; + } + + internal = dir_node -> internal; + + uart_send_string("cpio_init_mkdir: internal -> name: "); + if(!internal -> name) { + uart_send_string("/"); + } else { + uart_send_string(internal -> name); + } + uart_send_string("\n"); + + if(internal -> type != CPIOFS_TYPE_DIR) { + uart_send_string("cpio_init_mkdir: not a directory\n"); + return; + } + + new_internal = (cpiofs_internal *)kmalloc(sizeof(cpiofs_internal)); + new_dir_node = (vnode *)kmalloc(sizeof(vnode)); + uart_send_string("cpio_init_mkdir: new_internal -> name: "); + uart_send_string(curname); + uart_send_string("\n"); + uart_send_string("new_dir_node addr: "); + uart_hex((unsigned long)new_dir_node); + uart_send_string("\n"); + new_internal -> name = curname; + new_internal -> type = CPIOFS_TYPE_DIR; + INIT_LIST_HEAD(&new_internal -> dir.list); + new_internal -> node = new_dir_node; + list_add_tail(&new_internal -> list, &internal -> dir.list); + + new_dir_node -> mount = 0; + new_dir_node -> v_ops = &cpiofs_v_ops; + new_dir_node -> f_ops = &cpiofs_f_ops; + new_dir_node -> internal = new_internal; + new_dir_node -> parent = dir_node; + + uart_send_string("[success] cpio_init_mkdir: create directory "); + uart_send_string(curname); + uart_send_string("\n"); + + return; +} + +void cpio_init_create(const char* pathname, const char *data, uint64_t size) { + char *curname; + vnode *dir_node; + vnode *new_file_node; + cpiofs_internal *internal, *new_internal; + + curname = (char *)kmalloc(strlen(pathname) + 1); + strcpy(curname, pathname); + dir_node = cpio_get_vnode_from_path(&cpio_root_node, &curname); + + if(!dir_node){ + uart_send_string("cpio_init_create: directory not found\n"); + return; + } + if(!curname) { + uart_send_string("cpio_init_create: invalid pathname\n"); + return; + } + + char *dir_name = (char*)kmalloc(256); + dir_node -> v_ops -> getname(dir_node, &dir_name); + + + internal = dir_node -> internal; + + if(internal -> type != CPIOFS_TYPE_DIR) { + uart_send_string("cpio_init_create: not a directory\n"); + return; + } + + uart_send_string("cpio_init_create: internal -> name: "); + if(!internal -> name) { + uart_send_string("/"); + } else { + uart_send_string(internal -> name); + } + uart_send_string("\n"); + + + new_internal = (cpiofs_internal *)kmalloc(sizeof(cpiofs_internal)); + new_file_node = (vnode *)kmalloc(sizeof(vnode)); + + new_internal -> name = curname; + new_internal -> type = CPIOFS_TYPE_FILE; + new_internal -> file.data = data; + new_internal -> file.size = size; + new_internal -> node = new_file_node; + list_add_tail(&new_internal -> list, &internal -> dir.list); + + new_file_node -> mount = 0; + new_file_node -> v_ops = &cpiofs_v_ops; + new_file_node -> f_ops = &cpiofs_f_ops; + new_file_node -> internal = new_internal; + new_file_node -> parent = dir_node; + + uart_send_string("[success] cpio_init_create: create file "); + uart_send_string(curname); + uart_send_string("\n"); + + return; +} + +filesystem *cpiofs_init(void) { + cpiofs_internal *internal; + + internal = (cpiofs_internal *)kmalloc(sizeof(cpiofs_internal)); + + internal -> name = 0; + internal -> type = CPIOFS_TYPE_DIR; + INIT_LIST_HEAD(&internal -> dir.list); + internal -> node = &cpio_root_node; + INIT_LIST_HEAD(&internal -> list); + + cpio_root_node.mount = 0; + cpio_root_node.v_ops = &cpiofs_v_ops; + cpio_root_node.f_ops = &cpiofs_f_ops; + cpio_root_node.internal = internal; + cpio_root_node.parent = 0; + + cpio_t* header = ramfs_base; + + while(header) { + char *component_name, *data; + uint32_t namesize, filesize, aligned_namesize, aligned_filesize, type; + + if(strncmp(header -> c_magic, "070701", sizeof(header->c_magic)) != 0) { + uart_send_string("cpiofs_init: invalid cpio format\n"); + break; + } + + namesize = cpio_read_8hex(header -> c_namesize); + filesize = cpio_read_8hex(header -> c_filesize); + type = cpio_read_8hex(header -> c_mode) & CPIO_TYPE_MASK; + + component_name = ((char *)header) + sizeof(cpio_t); + + aligned_namesize = align4(namesize); + aligned_filesize = align4(filesize); + unsigned int offset = namesize + sizeof(cpio_t); + offset = offset % 4 == 0 ? offset : (offset + 4 - offset % 4); // padding + + + // uart_send_string("file name: "); + // uart_send_string(component_name); + // uart_send_string("\n"); + + if (strncmp(component_name, "TRAILER!!!", sizeof("TRAILER!!!")) == 0) { + break; + } + + data = (char*)header + offset; + if(filesize == 0) { + header = (cpio_t *)data; + } else { + offset = filesize; + header = (cpio_t *)(data + (offset % 4 == 0 ? offset : (offset + 4 - offset % 4))); + } + + if(type == CPIO_TYPE_FILE) { + uart_send_string("cpiofs_init: create file "); + uart_send_string(component_name); + uart_send_string("\n"); + cpio_init_create(component_name, data, filesize); + } else if(type == CPIO_TYPE_DIR) { + uart_send_string("cpiofs_init: mkdir "); + uart_send_string(component_name); + uart_send_string("\n"); + cpio_init_mkdir(component_name); + } + } + + return &static_cpiofs; +} diff --git a/lab8/src/fs_framebufferfs.c b/lab8/src/fs_framebufferfs.c new file mode 100644 index 000000000..309d26aaf --- /dev/null +++ b/lab8/src/fs_framebufferfs.c @@ -0,0 +1,272 @@ +#include "fs_framebufferfs.h" +#include "fs_tmpfs.h" +#include "exception.h" +#include "mm.h" + +uint32_t __attribute__((aligned(0x10))) mbox[36]; + +filesystem *framebufferfs_init(void) { + return &static_framebufferfs; +}; + +filesystem static_framebufferfs = { + .name = "framebufferfs", + .mount = framebufferfs_mount, +}; + +vnode_operations framebufferfs_v_ops = { + .lookup = framebufferfs_lookup, + .create = framebufferfs_create, + .mkdir = framebufferfs_mkdir, + .isdir = framebufferfs_isdir, + .getname = framebufferfs_getname, + .getsize = framebufferfs_getsize, +}; + +file_operations framebufferfs_f_ops = { + .write = framebufferfs_write, + .read = framebufferfs_read, + .open = framebufferfs_open, + .close = framebufferfs_close, + .lseek64 = framebufferfs_lseek64, + .ioctl = framebufferfs_ioctl +}; + +int framebufferfs_mount(filesystem *fs, mount *mnt) { + uart_send_string("framebufferfs_mount\n"); + vnode *cur_node; + framebufferfs_internal *internal; + const char* name; + internal = (framebufferfs_internal *)kmalloc(sizeof(framebufferfs_internal)); + + cur_node = mnt -> root; + cur_node -> v_ops -> getname(cur_node, &name); + + uart_send_string("framebufferfs_mount: name = "); + uart_send_string(name); + uart_send_string("\n"); + + internal -> name = name; + internal -> oldnode.mount = cur_node -> mount; + internal -> oldnode.v_ops = cur_node -> v_ops; + internal -> oldnode.f_ops = cur_node -> f_ops; + internal -> oldnode.parent = cur_node -> parent; + internal -> oldnode.internal = cur_node -> internal; + + internal -> lfb = 0; + internal -> isopened = 0; + internal -> isinit = 0; + + cur_node -> mount = mnt; + cur_node -> v_ops = &framebufferfs_v_ops; + cur_node -> f_ops = &framebufferfs_f_ops; + cur_node -> internal = internal; + + + return 0; +} + + +int framebufferfs_lookup(vnode *dir_node, vnode **target, const char *component_name) { + return -1; +} + +int framebufferfs_create(vnode *dir_node, vnode **target, const char *component_name) { + return -1; +} + +int framebufferfs_mkdir(vnode *dir_node, vnode **target, const char *component_name) { + return -1; +} + +int framebufferfs_isdir(vnode *dir_node) { + return 0; +} + +int framebufferfs_getname(vnode *dir_node, const char **name) { + framebufferfs_internal *internal = (framebufferfs_internal *)dir_node -> internal; + + *name = internal -> name; + return 0; +} + +int framebufferfs_getsize(vnode *dir_node) { + return -1; +} + + +int framebufferfs_open(vnode *file_node, file *target) { + framebufferfs_internal *internal; + el1_interrupt_disable(); + internal = (framebufferfs_internal *)file_node -> internal; + + if(internal -> isopened) { + uart_send_string("framebufferfs_open: File already opened\n"); + el1_interrupt_enable(); + return -1; + } + + target -> vnode = file_node; + target -> f_pos = 0; + target -> f_ops = file_node -> f_ops; + uart_send_string("--------------------------------\n"); + + uart_send_string("framebufferfs_open: File opened\n"); + internal -> isopened = 1; + el1_interrupt_enable(); + return 0; +} + +int framebufferfs_close(file *target) { + framebufferfs_internal *internal = (framebufferfs_internal *)target -> vnode -> internal; + + target -> vnode = NULL; + target -> f_pos = 0; + target -> f_ops = NULL; + + internal -> isopened = 0; + + return 0; +} + +int framebufferfs_write(file *target, const void *buf, size_t len) { + // uart_send_string("w "); + framebufferfs_internal *internal = (framebufferfs_internal *)target -> vnode -> internal; + + if(!internal -> isinit) { + uart_send_string("framebufferfs_write: Framebuffer not initialized\n"); + return -1; + } + + if(target -> f_pos + len > internal -> lfbsize) { + uart_send_string("framebufferfs_write: Write out of bounds\n"); + return -1; + } + memncpy((void *)(internal -> lfb + target -> f_pos), buf, len); + target -> f_pos += len; + // uart_send_string("WS\n"); + return len; +} + +int framebufferfs_read(file *target, void *buf, size_t len) { + return -1; +} + +long framebufferfs_lseek64(file *target, long offset, int whence) { + el1_interrupt_disable(); + int base; + framebufferfs_internal *internal = (framebufferfs_internal *)target -> vnode -> internal; + + switch(whence) { + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = target -> f_pos; + break; + case SEEK_END: + base = internal -> lfbsize; + break; + default: + uart_send_string("framebufferfs_lseek64: Invalid whence\n"); + el1_interrupt_enable(); + return -1; + } + + if(base + offset > internal -> lfbsize) { + uart_send_string("framebufferfs_lseek64: Seek out of bounds\n"); + el1_interrupt_enable(); + return -1; + } + + target -> f_pos = base + offset; + el1_interrupt_enable(); + return 0; +} + +int framebufferfs_ioctl(struct file *file, uint64_t request, va_list args) { + if (request != 0) { + return -1; + } + fb_info *info; + + framebufferfs_internal *internal = (framebufferfs_internal *)file -> vnode -> internal; + + if(internal -> isinit) { + return 0; + } + uint32_t width, height, pitch, isrgb; + + mbox[0] = 35 * 4; + mbox[1] = MBOX_REQUEST; + + mbox[2] = 0x48003; // set phy wh + mbox[3] = 8; + mbox[4] = 8; + mbox[5] = 1024; // FrameBufferInfo.width + mbox[6] = 768; // FrameBufferInfo.height + + mbox[7] = 0x48004; // set virt wh + mbox[8] = 8; + mbox[9] = 8; + mbox[10] = 1024; // FrameBufferInfo.virtual_width + mbox[11] = 768; // FrameBufferInfo.virtual_height + + mbox[12] = 0x48009; // set virt offset + mbox[13] = 8; + mbox[14] = 8; + mbox[15] = 0; // FrameBufferInfo.x_offset + mbox[16] = 0; // FrameBufferInfo.y.offset + + mbox[17] = 0x48005; // set depth + mbox[18] = 4; + mbox[19] = 4; + mbox[20] = 32; // FrameBufferInfo.depth + + mbox[21] = 0x48006; // set pixel order + mbox[22] = 4; + mbox[23] = 4; + mbox[24] = 1; // RGB, not BGR preferably + + mbox[25] = 0x40001; // get framebuffer, gets alignment on request + mbox[26] = 8; + mbox[27] = 8; + mbox[28] = 4096; // FrameBufferInfo.pointer + mbox[29] = 0; // FrameBufferInfo.size + + mbox[30] = 0x40008; // get pitch + mbox[31] = 4; + mbox[32] = 4; + mbox[33] = 0; // FrameBufferInfo.pitch + + mbox[34] = MBOX_TAG_LAST; + uart_send_string("Calling mailbox_call\n"); + mailbox_call(MBOX_CH_PROP, mbox); + uart_send_string("Returned from mailbox_call\n"); + + if (mbox[20] == 32 && mbox[28] != 0) { + uart_send_string("FrameBuffer initialized\n"); + mbox[28] &= 0x3FFFFFFF; // convert GPU address to ARM address + width = mbox[5]; // get actual physical width + height = mbox[6]; // get actual physical height + pitch = mbox[33]; // get number of bytes per line + isrgb = mbox[24]; // get the actual channel order + internal->lfb = (void *)((unsigned long)mbox[28]); + internal->lfbsize = mbox[29]; + } else { + // Unable to set screen resolution to 1024x768x32 + uart_send_string("Unable to set screen resolution to 1024x768x32\n"); + return -1; + } + + info = va_arg(args, void*); + + info -> width = width; + info -> height = height; + info -> pitch = pitch; + info -> isrgb = isrgb; + + internal -> isinit = 1; + + return 0; +} \ No newline at end of file diff --git a/lab8/src/fs_fsinit.c b/lab8/src/fs_fsinit.c new file mode 100644 index 000000000..6a2e95b47 --- /dev/null +++ b/lab8/src/fs_fsinit.c @@ -0,0 +1,49 @@ +#include "fs_fsinit.h" +#include "mm.h" + +void fs_early_init(void) { + filesystem *tmpfs, *cpiofs, *uartfs, *framebufferfs; + + vfs_init(); + // init tmpfs + tmpfs = tmpfs_init(); + uart_send_string("tmpfs_init\n"); + // init cpiofs + cpiofs = cpiofs_init(); + // init uartfs + uartfs = uartfs_init(); + + framebufferfs = framebufferfs_init(); + + uart_send_string("cpiofs_init\n"); + register_filesystem(tmpfs); + uart_send_string("register tmpfs\n"); + register_filesystem(cpiofs); + uart_send_string("register cpiofs\n"); + register_filesystem(uartfs); + uart_send_string("register uartfs\n"); + register_filesystem(framebufferfs); + uart_send_string("register framebufferfs\n"); + + vfs_init_rootfs(tmpfs); + uart_send_string("init rootfs\n"); +} + +void fs_init(void) { + // mount rootfs + vfs_mkdir("/initramfs"); + uart_send_string("mkdir /initramfs\n"); + vfs_mount("/initramfs", "cpiofs"); + uart_send_string("mount /initramfs\n"); + + // mount uartfs + vfs_mkdir("/dev"); + uart_send_string("mkdir /dev\n"); + vfs_mkdir("/dev/uart"); + uart_send_string("mkdir /dev/uart\n"); + vfs_mount("/dev/uart", "uartfs"); + + // mount framebufferfs + vfs_mkdir("/dev/framebuffer"); + vfs_mount("/dev/framebuffer", "framebufferfs"); +} \ No newline at end of file diff --git a/lab8/src/fs_tmpfs.c b/lab8/src/fs_tmpfs.c new file mode 100644 index 000000000..9a86a51b1 --- /dev/null +++ b/lab8/src/fs_tmpfs.c @@ -0,0 +1,398 @@ +#include "fs_tmpfs.h" +#include "alloc.h" +#include "string.h" + + +// define struct +filesystem static_tmpfs = { + .name = "tmpfs", + .mount = tmpfs_mount, + .alloc_vnode = tmpfs_alloc_vnode, +}; + +struct vnode_operations tmpfs_v_ops = { + .lookup = tmpfs_lookup, + .create = tmpfs_create, + .mkdir = tmpfs_mkdir, + .isdir = tmpfs_isdir, + .getname = tmpfs_getname, + .getsize = tmpfs_getsize, +}; + +struct file_operations tmpfs_f_ops = { + .write = tmpfs_write, + .read = tmpfs_read, + .open = tmpfs_open, + .close = tmpfs_close, + .lseek64 = tmpfs_lseek64, + .ioctl = tmpfs_ioctl, +}; + +filesystem *tmpfs_init(void) { + return &static_tmpfs; +} + +int tmpfs_mount(filesystem *fs, mount *mnt) { + vnode *backup_node, *cur_node; + tmpfs_internal *internal; + tmpfs_dir *dir; + const char* name; + + cur_node = mnt->root; + + cur_node -> v_ops -> getname(cur_node, &name); + + if(strlen(name) >= TMPFS_NAME_MAXLEN) { + uart_send_string("tmpfs_mount: name too long\n"); + return -1; + } + + backup_node = (vnode *)kmalloc(sizeof(vnode)); + internal = (tmpfs_internal *)kmalloc(sizeof(tmpfs_internal)); + dir = (tmpfs_dir *)kmalloc(sizeof(tmpfs_dir)); + + dir -> size = 0; + + backup_node -> mount = mnt; + backup_node -> v_ops = cur_node -> v_ops; + backup_node -> f_ops = cur_node -> f_ops; + backup_node -> internal = cur_node -> internal; + + strcpy(internal -> name, name); + internal -> type = TMPFS_TYPE_DIR; + internal -> dir = dir; + internal -> old_node = backup_node; + + cur_node -> mount = mnt; + cur_node -> v_ops = &tmpfs_v_ops; + cur_node -> f_ops = &tmpfs_f_ops; + cur_node -> internal = internal; + + return 0; +} + +int tmpfs_alloc_vnode(filesystem *fs, vnode **target) { + vnode *node; + tmpfs_internal *internal; + tmpfs_dir *dir; + + node = (vnode *)kmalloc(sizeof(vnode)); + internal = (tmpfs_internal *)kmalloc(sizeof(tmpfs_internal)); + dir = (tmpfs_dir *)kmalloc(sizeof(tmpfs_dir)); + + dir -> size = 0; + + internal -> name[0] = '\0'; + internal -> type = TMPFS_TYPE_DIR; + internal -> dir = dir; + internal -> old_node = 0; + + node -> mount = 0; + node -> v_ops = &tmpfs_v_ops; + node -> f_ops = &tmpfs_f_ops; + node -> internal = internal; + + *target = node; + + return 0; +} + + +// vnode operations +int tmpfs_lookup(vnode *dir_node, vnode **target, const char *component_name) { + // uart_send_string("tmpfs_lookup\n"); + // uart_send_string(component_name); + // uart_send_string("\n"); + tmpfs_internal *internal; + tmpfs_dir *dir; + vnode *node; + int i; + + internal = (tmpfs_internal *)dir_node -> internal; + + if(internal -> type != TMPFS_TYPE_DIR) { + uart_send_string("tmpfs_lookup: not a dir\n"); + return -1; + } + // uart_send_string("tmpfs_lookup: is a dir size: "); + dir = internal -> dir; + + + // uart_hex(dir -> size); + // uart_send_string("\n"); + + for(i = 0; i < dir -> size; i++) { + // uart_send_string("tmpfs_lookup i: "); + // uart_hex(i); + // uart_send_string("\n"); + const char *name; + int ret; + node = dir -> files[i]; + ret = node -> v_ops -> getname(node, &name); + if(ret < 0){ + continue; + } + if(strcmp(name, component_name) == 0) { + break; + } + } + + + if(i >= dir -> size) { + uart_send_string("tmpfs_lookup: not found\n"); + return -1; + } + + *target = dir -> files[i]; + + return 0; +} + +// create a new file under dir_node +// return 0 on success, -1 on error +int tmpfs_create(vnode *dir_node, vnode **target, const char *component_name) { + tmpfs_internal *internal, *new_internal; + tmpfs_file *file; + tmpfs_dir *dir; + vnode *node; + int ret; + + if(strlen(component_name) >= TMPFS_NAME_MAXLEN) { + uart_send_string("tmpfs_create: name too long\n"); + return -1; + } + + internal = (tmpfs_internal *)dir_node -> internal; + if(internal -> type != TMPFS_TYPE_DIR) { + uart_send_string("tmpfs_create: not a dir\n"); + return -1; + } + + dir = internal -> dir; + + if(dir -> size >= TMPFS_DIR_MAXSIZE) { + uart_send_string("tmpfs_create: dir full\n"); + return -1; + } + + ret = tmpfs_lookup(dir_node, &node, component_name); + + if(!ret){ + uart_send_string("tmpfs_create: file exists\n"); + return -1; + } + + node = (vnode *)kmalloc(sizeof(vnode)); + new_internal = (tmpfs_internal *)kmalloc(sizeof(tmpfs_internal)); + file = (tmpfs_file *)kmalloc(sizeof(tmpfs_file)); + + file -> data = kmalloc(TMPFS_FILE_MAXSIZE); + file -> size = 0; + file -> capacity = TMPFS_FILE_MAXSIZE; + + strcpy(new_internal -> name, component_name); + new_internal -> type = TMPFS_TYPE_FILE; + new_internal -> file = file; + new_internal -> old_node = 0; + + node -> mount = dir_node -> mount; + node -> v_ops = &tmpfs_v_ops; + node -> f_ops = &tmpfs_f_ops; + node -> parent = dir_node; + node -> internal = new_internal; + + dir -> files[dir -> size] = node; + dir -> size ++; + + *target = node; + + return 0; +} + +int tmpfs_mkdir(vnode *dir_node, vnode **target, const char *component_name) { + tmpfs_internal *internal, *new_internal; + tmpfs_dir *dir, *new_dir; + vnode *node; + int ret; + + if(strlen(component_name) >= TMPFS_NAME_MAXLEN) { + uart_send_string("tmpfs_create: name too long\n"); + return -1; + } + + internal = (tmpfs_internal *)dir_node -> internal; + if(internal -> type != TMPFS_TYPE_DIR) { + uart_send_string("tmpfs_create: not a dir\n"); + return -1; + } + + dir = internal -> dir; + + if(dir -> size >= TMPFS_DIR_MAXSIZE) { + uart_send_string("tmpfs_create: dir full\n"); + return -1; + } + + ret = tmpfs_lookup(dir_node, &node, component_name); + + if(!ret){ + uart_send_string("tmpfs_create: file exists\n"); + return -1; + } + + node = (vnode *)kmalloc(sizeof(vnode)); + new_internal = (tmpfs_internal *)kmalloc(sizeof(tmpfs_internal)); + new_dir = (tmpfs_dir *)kmalloc(sizeof(tmpfs_dir)); + + new_dir -> size = 0; + + strcpy(new_internal -> name, component_name); + new_internal -> type = TMPFS_TYPE_DIR; + new_internal -> dir = new_dir; + new_internal -> old_node = 0; + + node -> mount = dir_node -> mount; + node -> v_ops = &tmpfs_v_ops; + node -> f_ops = &tmpfs_f_ops; + node -> parent = dir_node; + node -> internal = new_internal; + + dir -> files[dir -> size] = node; + dir -> size ++; + + *target = node; + + return 0; +} + +int tmpfs_isdir(vnode *dir_node) { + tmpfs_internal *internal = (tmpfs_internal *)dir_node -> internal; + if (internal -> type == TMPFS_TYPE_DIR) { + return 1; + } + + return 0; +} + +int tmpfs_getname(vnode *dir_node, const char **name) { + tmpfs_internal *internal = internal = (tmpfs_internal *)dir_node -> internal; + *name = internal -> name; + return 0; +} + +int tmpfs_getsize(vnode *dir_node) { + tmpfs_internal *internal = (tmpfs_internal *)dir_node -> internal; + return internal -> type == TMPFS_TYPE_FILE ? internal -> file -> size : -1; +} + +// file operations +int tmpfs_open(vnode *file_node, file *target) { + if(((tmpfs_internal*)file_node -> internal) -> type != TMPFS_TYPE_FILE) { + uart_send_string("tmpfs_open: not a file\n"); + return -1; + } + target -> vnode = file_node; + target -> f_pos = 0; + target -> f_ops = file_node -> f_ops; + + return 0; +} + +int tmpfs_close(file *target) { + target -> vnode = 0; + target -> f_ops = 0; + target -> f_pos = 0; + + return 0; +} + +int tmpfs_write(file *target, const void *buf, size_t len) { + tmpfs_internal *internal = (tmpfs_internal *)target -> vnode -> internal; + size_t i; + + if(internal -> type != TMPFS_TYPE_FILE) { + uart_send_string("tmpfs_write: not a file\n"); + return -1; + } + + tmpfs_file *file = internal -> file; + + if(len > file -> capacity - file -> size) { + len = file -> capacity - file -> size; + } + + if(!len) { + uart_send_string("tmpfs_write: no space left\n"); + return 0; + } + + memcpy(&file->data[target->f_pos], buf, len); + + target -> f_pos += len; + + if(target -> f_pos > file -> size) { + file -> size = target -> f_pos; + } + + return len; +} + +int tmpfs_read(file *target, void *buf, size_t len) { + tmpfs_internal *internal = (tmpfs_internal *)target -> vnode -> internal; + + if(internal -> type != TMPFS_TYPE_FILE) { + uart_send_string("tmpfs_read: not a file\n"); + return -1; + } + + tmpfs_file *file = internal -> file; + + if(len > file -> size - target -> f_pos) { + len = file -> size - target -> f_pos; + } + + memcpy(buf, &file -> data[target -> f_pos], len); + + target -> f_pos += len; + + return len; +} + + +long tmpfs_lseek64(file *target, long offset, int whence) { + int filesize; + int base; + + filesize = target -> vnode -> v_ops -> getsize(target -> vnode); + + if(filesize < 0) { + return -1; + } + + switch (whence) { + case SEEK_SET: + base = 0; + break; + case SEEK_CUR: + base = target -> f_pos; + break; + case SEEK_END: + base = filesize; + break; + default: + return -1; + } + + if(base + offset > filesize) { + uart_send_string("tmpfs_lseek64: invalid offset\n"); + return -1; + } + + target -> f_pos = base + offset; + + return 0; +} + +int tmpfs_ioctl(struct file *file, uint64_t request, va_list args) { + return -1; +} diff --git a/lab8/src/fs_uartfs.c b/lab8/src/fs_uartfs.c new file mode 100644 index 000000000..f7201406c --- /dev/null +++ b/lab8/src/fs_uartfs.c @@ -0,0 +1,118 @@ +#include "fs_uartfs.h" +#include "fs_tmpfs.h" + +filesystem *uartfs_init(void) { + return &static_uartfs; +}; + +filesystem static_uartfs = { + .name = "uartfs", + .mount = uartfs_mount, +}; + +vnode_operations uartfs_v_ops = { + .lookup = uartfs_lookup, + .create = uartfs_create, + .mkdir = uartfs_mkdir, + .isdir = uartfs_isdir, + .getname = uartfs_getname, + .getsize = uartfs_getsize, +}; + +file_operations uartfs_f_ops = { + .write = uartfs_write, + .read = uartfs_read, + .open = uartfs_open, + .close = uartfs_close, + .lseek64 = uartfs_lseek64, + .ioctl = uartfs_ioctl, +}; + +int uartfs_mount(filesystem *fs, mount *mnt) { + vnode *cur_node; + uartfs_internal *internal; + const char* name; + internal = (uartfs_internal *)kmalloc(sizeof(uartfs_internal)); + + cur_node = mnt -> root; + cur_node -> v_ops -> getname(cur_node, &name); + + internal -> name = name; + internal -> oldnode.mount = cur_node -> mount; + internal -> oldnode.v_ops = cur_node -> v_ops; + internal -> oldnode.f_ops = cur_node -> f_ops; + internal -> oldnode.parent = cur_node -> parent; + internal -> oldnode.internal = cur_node -> internal; + + cur_node -> mount = mnt; + cur_node -> v_ops = &uartfs_v_ops; + cur_node -> f_ops = &uartfs_f_ops; + cur_node -> internal = internal; + + return 0; +} + + +int uartfs_lookup(vnode *dir_node, vnode **target, const char *component_name) { + return -1; +} + +int uartfs_create(vnode *dir_node, vnode **target, const char *component_name) { + return -1; +} + +int uartfs_mkdir(vnode *dir_node, vnode **target, const char *component_name) { + return -1; +} + +int uartfs_isdir(vnode *dir_node) { + return 0; +} + +int uartfs_getname(vnode *dir_node, const char **name) { + uartfs_internal *internal = (uartfs_internal *)dir_node -> internal; + + *name = internal -> name; + return 0; +} + +int uartfs_getsize(vnode *dir_node) { + return -1; +} + + +int uartfs_open(vnode *file_node, file *target) { + target -> vnode = file_node; + target -> f_pos = 0; + target -> f_ops = file_node -> f_ops; + + return 0; +} + +int uartfs_close(file *target) { + target -> vnode = NULL; + target -> f_pos = 0; + target -> f_ops = NULL; + + return 0; +} + +int uartfs_write(file *target, const void *buf, size_t len) { + uart_sendn(buf, len); + + return len; +} + +int uartfs_read(file *target, void *buf, size_t len) { + uart_recvn(buf, len); + + return len; +} + +long uartfs_lseek64(file *target, long offset, int whence) { + return -1; +} + +int uartfs_ioctl(struct file *file, uint64_t request, va_list args) { + return -1; +} \ No newline at end of file diff --git a/lab8/src/fs_vfs.c b/lab8/src/fs_vfs.c new file mode 100644 index 000000000..e2e17c2d5 --- /dev/null +++ b/lab8/src/fs_vfs.c @@ -0,0 +1,572 @@ +#include "fs_vfs.h" +#include "thread.h" +#include "string.h" +#include "alloc.h" +#include "mini_uart.h" +#include "reboot.h" +#include "thread.h" + +mount* rootfs; + +struct list_head fs_lists; + +vnode* get_vnode_from_path(vnode* dir_node, const char **pathname) { + uart_send_string("get_vnode_from_path\n"); + vnode* result; + const char *start; + const char *end; + char buf[256]; + + start = end = *pathname; + + if(*start == '/') { + result = rootfs->root; + } else { + result = dir_node; + } + uart_send_string("get_vnode_from_path: "); + uart_send_string(*pathname); + uart_send_string("\n"); + + + // find the vnode from the path + while(1) { + // handle ./ and ../ + if(!strncmp("./", start, 2)) { + start += 2; + end = start; + continue; + } else if(!strncmp("../", start, 3)) { + if(result -> parent) { + result = result -> parent; + } + start += 3; + end = start; + continue; + } + + + while(*end != '\0' && *end != '/') { + end++; + } + + if(*end == '/') { + int ret; + + if(start == end) { + // handle the case like /usr//bin + end ++; + start = end; + continue; + } + + memcpy(buf, start, end - start); + buf[end - start] = '\0'; + uart_send_string(buf); + uart_send_string("\n"); + + ret = result -> v_ops -> lookup(result, &result, buf); + // failed + if(ret < 0) { + return NULL; + } + + end ++; + start = end; + } else { + // reach the end of the path + break; + } + } + + *pathname = *start ? start : NULL; + + return result; +} + +filesystem* find_fs(const char *fs_name) { + struct filesystem *fs; + + list_for_each_entry(fs, &fs_lists, fs_list) { + if(!strcmp(fs -> name, fs_name)) { + return fs; + } + } + + return NULL; +} + +void vfs_init() { + INIT_LIST_HEAD(&fs_lists); +} + +void vfs_init_rootfs(filesystem *fs) { + // original code: vnode* new_vnode; + vnode *new_vnode = (vnode*)kmalloc(sizeof(vnode)); + int ret; + + ret = fs -> alloc_vnode(fs, &new_vnode); + if(ret < 0) { + uart_send_string("vfs_init_rootfs: failed to alloc vnode\n"); + reset(1); + return; + } + + rootfs = (mount*)kmalloc(sizeof(mount)); + + rootfs -> fs = fs; + rootfs -> root = new_vnode; + new_vnode -> mount = rootfs; + new_vnode -> parent = NULL; +} + +int register_filesystem(filesystem *fs) { + if(find_fs(fs -> name)) { + uart_send_string("register_filesystem: filesystem already registered\n"); + return -1; + } + + list_add_tail(&fs -> fs_list, &fs_lists); + + return 0; +} + +int vfs_open(const char* pathname, int flags, file* target) { + const char* cur_name = pathname; + vnode* dir_node; + vnode* file_node; + int ret; + + if(is_init_thread){ + dir_node = get_vnode_from_path(get_current_thread() -> working_dir, &cur_name); + } else { + dir_node = get_vnode_from_path(rootfs -> root, &cur_name); + } + + if(!dir_node) { + uart_send_string("vfs_open: failed to get dir node\n"); + return -1; + } + + if(!cur_name) { + uart_send_string("vfs_open: invalid pathname\n"); + return -1; + } + char* name; + dir_node -> v_ops -> getname(dir_node, &name); + + ret = dir_node -> v_ops -> lookup(dir_node, &file_node, cur_name); + + + if(flags & O_CREAT) { + if(ret == 0){ + uart_send_string("vfs_open: file already exists\n"); + return -1; + } + + ret = dir_node -> v_ops -> create(dir_node, &file_node, cur_name); + uart_send_string("vfs_open: create success\n"); + + } + + if (ret < 0) { + uart_send_string("vfs_open: failed to lookup/create file\n"); + return ret; + } + + if(!file_node) { + uart_send_string("vfs_open: failed to get file node\n"); + return -1; + } + char* name2; + file_node -> v_ops -> getname(file_node, &name2); + uart_send_string("vfs_open: "); + uart_send_string(name2); + uart_send_string("\n"); + + ret = file_node -> f_ops -> open(file_node, target); + if(ret < 0){ + uart_send_string("vfs_open: failed to open file\n"); + return ret; + } + + target -> flags = 0; + + return 0; +} + +int vfs_close(file *f) { + return f -> f_ops -> close(f); +} + +int vfs_write(file *f, const void *buf, size_t len) { + return f -> f_ops -> write(f, buf, len); +} + +int vfs_read(file *f, void *buf, size_t len) { + return f -> f_ops -> read(f, buf, len); +} + +int vfs_mkdir(const char* pathname) { + char* cur_name = (char*)kmalloc(strlen(pathname) + 1); + strcpy(cur_name, pathname); + vnode* dir_node; + vnode* new_node; + int ret; + uart_send_string("vfs_mkdir: "); + uart_send_string(cur_name); + uart_send_string("\n"); + + if(is_init_thread){ + dir_node = get_vnode_from_path(get_current_thread() -> working_dir, &cur_name); + } else { + dir_node = get_vnode_from_path(rootfs -> root, &cur_name); + } + + if(!dir_node) { + uart_send_string("vfs_mkdir: failed to get dir node\n"); + return -1; + } + + if(!cur_name) { + uart_send_string("vfs_mkdir: invalid pathname\n"); + return -1; + } + + ret = dir_node -> v_ops -> mkdir(dir_node, &new_node, cur_name); + + if(ret < 0) { + uart_send_string("vfs_mkdir: failed to mkdir\n"); + return ret; + } + + uart_send_string("vfs_mkdir: success\n"); + + return 0; +} + +int vfs_mount(const char* target, const char* fs_name) { + const char* cur_name = target; + vnode* dir_node; + filesystem* fs; + mount* mnt; + int ret; + + if(is_init_thread) { + dir_node = get_vnode_from_path(get_current_thread() -> working_dir, &cur_name); + } else { + dir_node = get_vnode_from_path(rootfs -> root, &cur_name); + } + + if(!dir_node) { + uart_send_string("vfs_mount: failed to get dir node\n"); + return -1; + } + + if(cur_name) { + ret = dir_node -> v_ops -> lookup(dir_node, &dir_node, cur_name); + + if(ret < 0) { + return ret; + } + } + + if(!dir_node -> v_ops -> isdir(dir_node)) { + uart_send_string("vfs_mount: target is not a directory\n"); + return -1; + } + + fs = find_fs(fs_name); + + if(!fs) { + uart_send_string("vfs_mount: filesystem not found\n"); + return -1; + } + + mnt = (mount*)kmalloc(sizeof(mount)); + + mnt -> fs = fs; + mnt -> root = dir_node; + + ret = fs -> mount(fs, mnt); + + if(ret < 0) { + uart_send_string("vfs_mount: failed to mount\n"); + kfree(mnt); + return ret; + } +} + +int vfs_lookup(const char *pathname, vnode **target) { + char* cur_name = pathname; + vnode* dir_node; + vnode* file_node; + int ret; + uart_send_string("vfs_lookup: "); + uart_send_string(cur_name); + uart_send_string("\n"); + dir_node = get_vnode_from_path(get_current_thread() -> working_dir, &cur_name); + uart_send_string("vfs_lookup: "); + uart_send_string(cur_name); + uart_send_string("\n"); + + if(!dir_node) { + uart_send_string("vfs_lookup: failed to get dir node\n"); + return -1; + } + + if(!cur_name) { + // found the directory node as target + *target = dir_node; + return 0; + } + + ret = dir_node -> v_ops -> lookup(dir_node, &file_node, cur_name); + + if(ret < 0) { + uart_send_string("vfs_lookup: failed to lookup file\n"); + return ret; + } + + *target = file_node; + + return 0; +} + +long vfs_lseek64(file *f, long offset, int whence) { + return f -> f_ops -> lseek64(f, offset, whence); +} + +int vfs_ioctl(file *f, uint64_t request, va_list args) { + return f -> f_ops -> ioctl(f, request, args); +} + +// wrapper's +int open_wrapper(const char* pathname, int flags) { + int i, ret; + for(i = 0; i <= get_current_thread() -> max_fd; i++ ) { + if(get_current_thread() -> fds[i].vnode == 0) { + break; + } + } + + if(i > get_current_thread() -> max_fd) { + if(get_current_thread() -> max_fd >= THREAD_MAX_FD) { + uart_send_string("open_wrapper: too many files opened\n"); + return -1; + } + + get_current_thread() -> max_fd ++; + i = get_current_thread() -> max_fd; + } + + // uart_send_string("open_wrapper: "); + // uart_send_string(pathname); + // uart_send_string("\n"); + // int tid = get_current_thread() -> tid; + // uart_send_string("tid: "); + // uart_hex(tid); + // uart_send_string("\n"); + // uart_send_string("i: "); + // uart_hex(i); + // uart_send_string("\n"); + // uart_send_string("flags: "); + // uart_hex(flags); + // uart_send_string("\n"); + + ret = vfs_open(pathname, flags, &get_current_thread() -> fds[i]); + + if(ret < 0) { + uart_send_string("open_wrapper: failed to open file\n"); + get_current_thread() -> fds[i].vnode = 0; + return -1; + } + + return i; +} + +int close_wrapper(int fd) { + if(fd < 0 || fd > get_current_thread() -> max_fd) { + uart_send_string("close_wrapper: invalid fd\n"); + return -1; + } + + if(get_current_thread() -> fds[fd].vnode == 0) { + uart_send_string("close_wrapper: file not opened\n"); + return -1; + } + + int ret; + ret = vfs_close(&get_current_thread() -> fds[fd]); + + if(ret < 0) return ret; + + return 0; +} + +int write_wrapper(int fd, const void *buf, size_t len) { + if(fd < 0 || fd > get_current_thread() -> max_fd) { + uart_send_string("write_wrapper: invalid fd\n"); + return -1; + } + + if(get_current_thread() -> fds[fd].vnode == 0) { + uart_send_string("write_wrapper: file not opened\n"); + return -1; + } + + int ret; + ret = vfs_write(&get_current_thread() -> fds[fd], buf, len); + if(ret < 0) { + uart_send_string("write_wrapper: failed to write\n"); + } + return ret; +} + +int read_wrapper(int fd, void *buf, size_t len) { + if(fd < 0 || fd > get_current_thread() -> max_fd) { + uart_send_string("read_wrapper: invalid fd\n"); + return -1; + } + + if(get_current_thread() -> fds[fd].vnode == 0) { + uart_send_string("read_wrapper: file not opened\n"); + return -1; + } + + int ret; + ret = vfs_read(&get_current_thread() -> fds[fd], buf, len); + + return ret; +} + +int mkdir_wrapper(const char* pathname) { + return vfs_mkdir(pathname); +} + +int mount_wrapper(const char* target, const char* fs_name) { + return vfs_mount(target, fs_name); +} + +int chdir_wrapper(const char* path) { + vnode* target; + int ret; + + ret = vfs_lookup(path, &target); + + if(ret < 0) { + uart_send_string("chdir_wrapper: failed to lookup\n"); + return -1; + } + + if(!target -> v_ops -> isdir(target)) { + uart_send_string("chdir_wrapper: not a directory\n"); + return -1; + } + + get_current_thread() -> working_dir = target; + + return 0; +} + +long lseek64_wrapper(int fd, long offset, int whence) { + // uart_send_string("lseek64_wrapper\n"); + if(fd < 0 || fd > get_current_thread() -> max_fd) { + uart_send_string("lseek64_wrapper: invalid fd\n"); + return -1; + } + + if(get_current_thread() -> fds[fd].vnode == 0) { + uart_send_string("lseek64_wrapper: file not opened\n"); + return -1; + } + + int ret; + ret = vfs_lseek64(&get_current_thread() -> fds[fd], offset, whence); + if(ret < 0) { + uart_send_string("lseek64_wrapper: failed to lseek\n"); + } + return ret; +} + +int ioctl_wrapper(int fd, uint64_t cmd, va_list args) { + if(fd < 0 || fd > get_current_thread() -> max_fd) { + uart_send_string("ioctl_wrapper: invalid fd\n"); + return -1; + } + + if(get_current_thread() -> fds[fd].vnode == 0) { + uart_send_string("ioctl_wrapper: file not opened\n"); + return -1; + } + + int ret; + uart_send_string("ioctl_wrapper\n"); + ret = vfs_ioctl(&get_current_thread() -> fds[fd], cmd, args); + + return ret; +} + +void syscall_open(trapframe_t *tf, const char *pathname, int flags) { + int fd = open_wrapper(pathname, flags); + tf -> x[0] = fd; + return; +} + +void syscall_close(trapframe_t *tf, int fd) { + int ret = close_wrapper(fd); + tf -> x[0] = ret; + return; +} + +void syscall_write(trapframe_t *tf, int fd, const void *buf, size_t len) { + int ret = write_wrapper(fd, buf, len); + tf -> x[0] = ret; + return; +} + +void syscall_read(trapframe_t *tf, int fd, void *buf, size_t len) { + int ret = read_wrapper(fd, buf, len); + tf -> x[0] = ret; + return; +} + +void syscall_mkdir(trapframe_t *tf, const char *pathname, uint32_t mode) { + int ret = mkdir_wrapper(pathname); + tf -> x[0] = ret; + return; +} + +void syscall_mount( + trapframe_t *tf, + const char *src, + const char *target, + const char *fs_name, + int flags, + const void *data +) { + int ret = mount_wrapper(target, fs_name); + tf -> x[0] = ret; +} + +void syscall_chdir(trapframe_t *tf, const char *path) { + int ret = chdir_wrapper(path); + tf -> x[0] = ret; +} + +void syscall_lseek64(trapframe_t *tf, int fd, long offset, int whence) { + long ret = lseek64_wrapper(fd, offset, whence); + tf -> x[0] = ret; +} + +void syscall_ioctl(trapframe_t *tf, int fd, uint64_t requests, ...) { + uart_send_string("syscall_ioctl\n"); + int ret; + va_list args; + + va_start(args, requests); + ret = ioctl_wrapper(fd, requests, args); + va_end(args); + + tf -> x[0] = ret; +} diff --git a/lab8/src/initrd.c b/lab8/src/initrd.c new file mode 100644 index 000000000..49b32f2eb --- /dev/null +++ b/lab8/src/initrd.c @@ -0,0 +1,295 @@ +#include + +#include "initrd.h" +#include "alloc.h" +#include "mini_uart.h" +#include "string.h" +#include "c_utils.h" +#include "thread.h" +#include "exception.h" +#include "timer.h" +#include "fs_vfs.h" +#include "mm.h" + +char *ramfs_base; +char *ramfs_end; +char *exec_path_name; + +// Convert hexadecimal string to int +// @param s: hexadecimal string +// @param n: string length +static int hextoi(char *s, int n) +{ + int r = 0; + while (n-- > 0) { + r = r << 4; + if (*s >= 'A') + r += *s++ - 'A' + 10; + else if (*s >= '0') + r += *s++ - '0'; + } + return r; +} + +int cpio_newc_parse_header(cpio_t *this_header_pointer, char **pathname, unsigned int *filesize, char **data, cpio_t **next_header_pointer) +{ + // Ensure magic header 070701 + // new ascii format + if (strncmp(this_header_pointer->c_magic, CPIO_NEWC_HEADER_MAGIC, sizeof(this_header_pointer->c_magic)) != 0) + return -1; + + // transfer big endian 8 byte hex string to unsinged int + // data size + *filesize = hextoi(this_header_pointer->c_filesize, 8); + + // end of header is the pathname + // header | pathname str | data + *pathname = ((char *)this_header_pointer) + sizeof(cpio_t); + + // get file data, file data is just after pathname + // header | pathname str | data + // check picture on hackmd note + unsigned int pathname_length = hextoi(this_header_pointer->c_namesize, 8); + // get the offset to start of data + // | offset | data + unsigned int offset = pathname_length + sizeof(cpio_t); + // pathname and data might be zero padding + // section % 4 ==0 + offset = offset % 4 == 0 ? offset : (offset + 4 - offset % 4); // padding + // header pointer + offset = start of data + // h| offset | data + *data = (char *)this_header_pointer + offset; + + // get next header pointer + if (*filesize == 0) + // hardlinked files handeld by setting filesize to zero + *next_header_pointer = (cpio_t *)*data; + else + { + // data size + offset = *filesize; + // move pointer to the end of data + *next_header_pointer = (cpio_t *)(*data + (offset % 4 == 0 ? offset : (offset + 4 - offset % 4))); + } + + // if filepath is TRAILER!!! means there is no more files. + // end of archieve + // empty filename : TRAILER!!! + if (strncmp(*pathname, "TRAILER!!!", sizeof("TRAILER!!!")) == 0) + *next_header_pointer = 0; + + return 0; +} + +void initrd_list() +{ + char *filepath; + char *filedata; + unsigned int filesize; + // current pointer + cpio_t *header_pointer = (cpio_t *)(ramfs_base); + + // print every cpio pathname + while (header_pointer) + { + // uart_send_string("header_pointer: "); + // uart_hex((unsigned long)header_pointer); + // uart_send_string("\n"); + int error = cpio_newc_parse_header(header_pointer, &filepath, &filesize, &filedata, &header_pointer); + // if parse header error + if (error) + { + uart_send_string("Error parsing cpio header\n"); + break; + } + // uart_send_string("header_pointer: "); + // uart_hex((unsigned long)header_pointer); + // uart_send_string("\n"); + // if this is not TRAILER!!! (last of file) + if (header_pointer != 0){ + uart_send_string(filepath); + uart_send_string("\n"); + } + } + return; +} + + +void initrd_cat(const char *target) +{ + char *filepath; + char *filedata; + unsigned int filesize; + // current pointer + cpio_t *header_pointer = (cpio_t *)(ramfs_base); + + // print every cpio pathname + while (header_pointer) + { + // uart_send_string("header_pointer: "); + // uart_hex((unsigned long)header_pointer); + // uart_send_string("\n"); + int error = cpio_newc_parse_header(header_pointer, &filepath, &filesize, &filedata, &header_pointer); + // if parse header error + if (error) + { + // uart_printf("error\n"); + uart_send_string("Error parsing cpio header\n"); + break; + } + if (!strcmp(target, filepath)) + { + for (unsigned int i = 0; i < filesize; i++) + uart_send(filedata[i]); + uart_send_string("\n"); + break; + } + // uart_send_string("header_pointer: "); + // uart_hex((unsigned long)header_pointer); + // uart_send_string("\n"); + // if this is not TRAILER!!! (last of file) + if (header_pointer == 0){ + uart_send_string("File not found\n"); + break; + } + } + return; +} + +void initrd_callback(unsigned int node_type, char *name, void *value, unsigned int name_size){ + if(!strcmp(name, "linux,initrd-start")){ + ramfs_base = (char *)(unsigned long long)endian_big2little(*(unsigned int *)value); + uart_send_string("ramfs_base: "); + uart_hex((unsigned long)ramfs_base); + uart_send_string("\n"); + } + if(!strcmp(name, "linux,initrd-end")){ + ramfs_end = (char *)(unsigned long long)endian_big2little(*(unsigned int *)value); + uart_send_string("ramfs_end: "); + uart_hex((unsigned long)ramfs_end); + uart_send_string("\n"); + } +} + +// void initrd_exec_prog(char* target) { +// el1_interrupt_disable(); +// void* target_addr; +// char *filepath; +// char *filedata; +// unsigned int filesize; +// // current pointer +// cpio_t *header_pointer = (cpio_t *)(ramfs_base); + +// // print every cpio pathname +// while (header_pointer) +// { +// // uart_send_string("header_pointer: "); +// // uart_hex((unsigned long)header_pointer); +// // uart_send_string("\n"); +// int error = cpio_newc_parse_header(header_pointer, &filepath, &filesize, &filedata, &header_pointer); +// // if parse header error +// if (error) +// { +// // uart_printf("error\n"); +// uart_send_string("Error parsing cpio header\n"); +// break; +// } +// if (!strcmp(target, filepath)) +// { +// uart_send_string("filesize: "); +// uart_hex(filesize); +// uart_send_string("\n"); +// target_addr = kmalloc(filesize); +// memcpy(target_addr, filedata, filesize); +// break; +// } +// // uart_send_string("header_pointer: "); +// // uart_hex((unsigned long)header_pointer); +// // uart_send_string("\n"); +// // if this is not TRAILER!!! (last of file) +// if (header_pointer == 0){ +// uart_send_string("Program not found\n"); +// return; +// } +// } +// uart_send_string("prog addr: "); +// uart_hex(target_addr); +// uart_send_string("\n"); +// thread_t* t = create_thread(target_addr); +// el1_interrupt_enable(); +// unsigned long spsr_el1 = 0x0; // run in el0 and enable all interrupt (DAIF) +// unsigned long elr_el1 = t -> callee_reg.lr; +// unsigned long user_sp = t -> callee_reg.sp; +// unsigned long kernel_sp = (unsigned long)t -> kernel_stack + T_STACK_SIZE; +// // "r": Any general-purpose register, except sp +// asm volatile("msr tpidr_el1, %0" : : "r" (t)); +// asm volatile("msr spsr_el1, %0" : : "r" (spsr_el1)); +// asm volatile("msr elr_el1, %0" : : "r" (elr_el1)); +// asm volatile("msr sp_el0, %0" : : "r" (user_sp)); +// asm volatile("mov sp, %0" :: "r" (kernel_sp)); +// asm volatile("eret"); // jump to user program +// return; +// } + +void initrd_exec_prog() { + int data_len, aligned_data_len; + file f; + void* data; + int ret; + ret = vfs_open(exec_path_name, 0, &f); + + if(ret < 0) return; + + data_len = f.vnode -> v_ops -> getsize(f.vnode); + aligned_data_len = ALIGN(data_len, PAGE_SIZE); + data = kmalloc(aligned_data_len); + memzero(data, aligned_data_len); // clear data + + ret = vfs_read(&f, data, data_len); + + vfs_close(&f); + + uart_send_string("prog addr: "); + uart_hex(data); + uart_send_string("\n"); + thread_t* t = get_current_thread(); + uart_send_string("thread tid: "); + uart_hex(t -> tid); + uart_send_string("\n"); + + for(int i=0;i<=SIGNAL_NUM;i++) { + t -> signal_handler[i] = 0; + t -> waiting_signal[i] = 0; + } + + unsigned long spsr_el1 = 0x0; // run in el0 and enable all interrupt (DAIF) + unsigned long elr_el1 = data; + unsigned long user_sp = t -> user_stack + T_STACK_SIZE; + unsigned long kernel_sp = (unsigned long)t -> kernel_stack + T_STACK_SIZE; + // unsigned long kernel_sp = (unsigned long)kmalloc(T_STACK_SIZE) + T_STACK_SIZE; + + + // reset t call reg + t -> callee_reg.lr = data; + // core_timer_enable(); + // el1_interrupt_enable(); + + asm volatile("msr spsr_el1, %0" : : "r" (spsr_el1)); + asm volatile("msr elr_el1, %0" : : "r" (elr_el1)); + asm volatile("msr sp_el0, %0" : : "r" (user_sp)); + asm volatile("mov sp, %0" :: "r" (kernel_sp)); + // print_running(); + core_timer_enable(); + // el1_interrupt_enable(); + asm volatile("eret"); // jump to user program + // print_running(); +} + +void initrd_run_prog(const char* path_name) { + exec_path_name = (char*)kmalloc(strlen(path_name) + 1); + strcpy(exec_path_name, path_name); + // core_timer_disable(); + // el1_interrupt_disable(); + int tid = create_thread(initrd_exec_prog) -> tid; + thread_wait(tid); +} \ No newline at end of file diff --git a/lab8/src/kernel.c b/lab8/src/kernel.c new file mode 100644 index 000000000..84553bb60 --- /dev/null +++ b/lab8/src/kernel.c @@ -0,0 +1,74 @@ +#include "mini_uart.h" +#include "shell.h" +#include "alloc.h" +#include "fdt.h" +#include "initrd.h" +#include "c_utils.h" +#include "exception.h" +#include "thread.h" +#include "timer.h" +#include "fs_fsinit.h" +#include + +#define TEST_SIZE 30 + +extern char *dtb_base; + +void demo_mm() { + char* page_addr[TEST_SIZE]; + for(int i=0;i>3; +__stack_end = 0x0200000; \ No newline at end of file diff --git a/lab8/src/mbox.c b/lab8/src/mbox.c new file mode 100644 index 000000000..ef7eb085b --- /dev/null +++ b/lab8/src/mbox.c @@ -0,0 +1,67 @@ +#include "mbox.h" +#include "mini_uart.h" + + +int mailbox_call(unsigned char ch, unsigned int* mailbox){ + unsigned int r = (((unsigned long) mailbox) & ~0xF) | (ch & 0xf); + // ~0xF is used to clear the last 4 bits of the address + // 8 is used to set the last 4 bits to 8 (channel 8 is the mailbox channel) + + while(*MAILBOX_STATUS & MAILBOX_FULL){ + delay(1); + } // wait until the mailbox is not full + + *MAILBOX_WRITE = r; + + while(1){ + while(*MAILBOX_STATUS & MAILBOX_EMPTY){ + delay(1); + } // wait until the mailbox is not empty + + if(r == *MAILBOX_READ){ + return mailbox[1] == REQUEST_SUCCEED; + } + } +} + +void get_board_revision(){ + unsigned int mailbox[7]; + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + mailbox_call((unsigned char)0x8, mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + + uart_send_string("Board revision: "); + uart_hex(mailbox[5]); + uart_send_string("\n"); +} + +void get_memory_info() { + unsigned int mailbox[8]; + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_ARM_MEMORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; // tag code + mailbox[5] = 0; // base address + mailbox[6] = 0; // size in bytes + mailbox[7] = END_TAG; // end tag + // tags end + mailbox_call((unsigned char)0x8, mailbox); + uart_send_string("ARM memory base address : "); + uart_hex(mailbox[5]); + uart_send_string("\n"); + + uart_send_string("ARM memory size : "); + uart_hex(mailbox[6]); + uart_send_string("\n"); + +} \ No newline at end of file diff --git a/lab8/src/mini_uart.c b/lab8/src/mini_uart.c new file mode 100644 index 000000000..17848a8c1 --- /dev/null +++ b/lab8/src/mini_uart.c @@ -0,0 +1,228 @@ +#include "mini_uart.h" +#include "c_utils.h" +#include "exception.h" +#include "peripherals/p_mini_uart.h" +#include "peripherals/gpio.h" +#include "peripherals/irq.h" +#include "tasklist.h" + +char uart_read_buffer[BUFFER_SIZE]; +char uart_write_buffer[BUFFER_SIZE]; +int uart_read_index = 0; +int uart_read_head = 0; +int uart_write_index = 0; +int uart_write_head = 0; + +void uart_send ( char c ) +{ + if (c == '\n') + uart_send('\r'); + while(1) { + if(*AUX_MU_LSR_REG&0x20) + break; + } + *AUX_MU_IO_REG = c; +} + +char uart_recv ( void ) +{ + while(1) { + if(*AUX_MU_LSR_REG&0x01) + break; + } + return(*AUX_MU_IO_REG); +} + +void uart_recvn(char *buffer, int n) +{ + while (n--) { + *buffer++ = uart_recv(); + } +} + +void uart_send_string(const char* str) +{ + while (*str) { + uart_send(*str++); + } +} + +void uart_sendn(const char* buffer, int n) +{ + while (*buffer && n--) { + uart_send(*buffer++); + } +} + +void irq_uart_rx_exception() { + if((uart_read_index + 1) % BUFFER_SIZE == uart_read_head) { + // buffer is full, discard the data + unsigned int ier = *AUX_MU_IER_REG; + // only enable receiver interrupt for now + ier &= ~0x01; + *AUX_MU_IER_REG = ier; + return; + } + char c = *AUX_MU_IO_REG&0xFF; + uart_read_buffer[uart_read_index++] = c; + if (uart_read_index >= BUFFER_SIZE) { + uart_read_index = 0; + } +} + +void irq_uart_tx_exception() { + if (uart_write_index != uart_write_head) { + *AUX_MU_IO_REG = uart_write_buffer[uart_write_index++]; + // uart_send_string("before delayed\n"); + // for(unsigned int i=0;i<100000000;i++){ + // asm volatile("nop"); + // asm volatile("nop"); + // asm volatile("nop"); + // } + // uart_send_string("after delayed\n"); + + // uart_send_string("delayed finished\n"); + if (uart_write_index >= BUFFER_SIZE) { + uart_write_index = 0; + } + unsigned int ier = *AUX_MU_IER_REG; + ier |= 0x02; + *AUX_MU_IER_REG = ier; + } else { + // no more data to send, disable transmit interrupt + unsigned int ier = *AUX_MU_IER_REG; + ier &= ~0x02; + *AUX_MU_IER_REG = ier; + } +} + +void uart_irq_handler() { + unsigned int iir = *AUX_MU_IIR_REG; + unsigned int ier = *AUX_MU_IER_REG; + ier &= ~0x02; + ier &= ~0x01; + *AUX_MU_IER_REG = ier; + // check if it's a receive interrupt + if ((iir & 0x06) == 0x04) { + // uart_send_string("Receive interrupt\n"); + create_task(irq_uart_rx_exception, 2); + execute_tasks_preemptive(); + } + // check if it's a transmit interrupt + if ((iir & 0x06) == 0x02) { + // uart_send_string("Transmit interrupt\n"); + create_task(irq_uart_tx_exception, 1); + execute_tasks_preemptive(); + } +} + + +char uart_async_recv( void ) { + + while (uart_read_index == uart_read_head) { + unsigned int ier = *AUX_MU_IER_REG; + // only enable receiver interrupt for now + ier |= 0x01; + *AUX_MU_IER_REG = ier; + } + + el1_interrupt_disable(); + char c = uart_read_buffer[uart_read_head++]; + if (uart_read_head >= BUFFER_SIZE) { + uart_read_head = 0; + } + el1_interrupt_enable(); + return c; +} + +void uart_async_send_string(const char* str){ + + // if the write buffer is full, wait for it to be empty + while ((uart_write_index + 1) % BUFFER_SIZE == uart_write_head) { + unsigned int ier = *AUX_MU_IER_REG; + // only enable transmit interrupt for now + ier |= 0x02; + *AUX_MU_IER_REG = ier; + } + el1_interrupt_disable(); + while(*str){ + if(*str == '\n') { + uart_write_buffer[uart_write_head++] = '\r'; + uart_write_buffer[uart_write_head++] = '\n'; + str++; + } else { + uart_write_buffer[uart_write_head++] = *str++; + } + if (uart_write_head >= BUFFER_SIZE) { + uart_write_head = 0; + } + } + el1_interrupt_enable(); + // enable transmit interrupt + unsigned int ier = *AUX_MU_IER_REG; + ier |= 0x02; + *AUX_MU_IER_REG = ier; + return; +} + +void uart_hex(unsigned int d) { + unsigned int n; + int c; + for (c = 28; c >= 0; c -= 4) { + // get highest tetrad + n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x37 : 0x30; + uart_send(n); + } +} + +void uart_init ( void ) +{ + unsigned int selector; + + selector = *GPFSEL1; + selector &= ~(7<<12); // clean gpio14 + selector |= 2<<12; // set alt5 for gpio14 + selector &= ~(7<<15); // clean gpio15 + selector |= 2<<15; // set alt5 for gpio15 + *GPFSEL1 = selector; + + *GPPUD = 0; + delay(150); + *GPPUDCLK0 = (1<<14)|(1<<15); + delay(150); + *GPPUDCLK0 = 0; + + *AUX_ENABLES = 1; //Enable mini uart (this also enables access to its registers) + *AUX_MU_CNTL_REG = 0; //Disable auto flow control and disable receiver and transmitter (for now) + *AUX_MU_IER_REG = 0; //Disable receive and transmit interrupts + *AUX_MU_LCR_REG = 3; //Enable 8 bit mode + *AUX_MU_MCR_REG = 0; //Set RTS line to be always high + *AUX_MU_BAUD_REG = 270; //Set baud rate to 115200 + *AUX_MU_CNTL_REG = 3; //Finally, enable transmitter and receiver +} + +void uart_enable_interrupt( void ) { + unsigned int ier = *AUX_MU_IER_REG; + // only enable receiver interrupt for now + ier |= 0x01; + // ier |= 0x02; + *AUX_MU_IER_REG = ier; + + unsigned int enable_irqs_1 = *ENABLE_IRQS_1; + enable_irqs_1 |= 0x01 << 29; + *ENABLE_IRQS_1 = enable_irqs_1; +} + +void uart_disable_interrupt( void ) { + unsigned int ier = *AUX_MU_IER_REG; + // only enable receiver interrupt for now + ier &= ~0x01; + ier &= ~0x02; + *AUX_MU_IER_REG = ier; + + unsigned int enable_irqs_1 = *ENABLE_IRQS_1; + enable_irqs_1 &= ~(0x01 << 29); + *ENABLE_IRQS_1 = enable_irqs_1; +} diff --git a/lab8/src/mm.S b/lab8/src/mm.S new file mode 100644 index 000000000..463c9141e --- /dev/null +++ b/lab8/src/mm.S @@ -0,0 +1,19 @@ +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret + +.globl memncpy +memncpy: + b memncpy_1_cmp +memncpy_1: + ldrb w3, [x1], #1 + strb w3, [x0], #1 + subs x2, x2, #1 +memncpy_1_cmp: + cmp x2, 1 + bge memncpy_1 +memncpy_ok: + ret \ No newline at end of file diff --git a/lab8/src/reboot.c b/lab8/src/reboot.c new file mode 100644 index 000000000..a6f370d5d --- /dev/null +++ b/lab8/src/reboot.c @@ -0,0 +1,11 @@ +#include "reboot.h" + +void reset(int tick) { // reboot after watchdog timer expire + *PM_RSTC = PM_PASSWORD | 0x20; // full reset + *PM_WDOG = PM_PASSWORD | tick; // number of watchdog tick +} + +void cancel_reset() { + *PM_RSTC = PM_PASSWORD | 0; // cancel reset + *PM_WDOG = PM_PASSWORD | 0; // set watchdog tick to 0 to prevent reset +} \ No newline at end of file diff --git a/lab8/src/shell.c b/lab8/src/shell.c new file mode 100644 index 000000000..0a0a0fbda --- /dev/null +++ b/lab8/src/shell.c @@ -0,0 +1,95 @@ +#include "mini_uart.h" +#include "mbox.h" +#include "reboot.h" +#include "c_utils.h" +#include "string.h" +#include "initrd.h" +#include "timer.h" +#include "thread.h" +#include "alloc.h" +#include "exception.h" +#include "thread.h" + +void shell(){ + uart_async_send_string("Welcome to OSC2024 shell!\n"); + while(1){ + uart_send_string("# "); + char* str = kmalloc(100); + uart_recv_command(str); + uart_send_string("\n"); + if(!strcmp(str, "hello")){ + uart_async_send_string("Hello World!\n"); + } else if(!strcmp(str, "mailbox")){ + uart_send_string("Mailbox info: \n"); + get_board_revision(); + get_memory_info(); + } + // else if(!strcmp(str, "ls")){ + // initrd_list(); + // } else if (!strcmp(str, "cat")){ + // uart_async_send_string("Enter file name: "); + // char file_name[100]; + // uart_recv_command(file_name); + // uart_async_send_string("\n"); + // initrd_cat(file_name); + // } + else if (!strcmp(str, "exec")){ + uart_async_send_string("Enter program name: "); + char file_name[100]; + uart_recv_command(file_name); + uart_async_send_string("\n"); + initrd_run_prog(file_name); + } else if(!strcmp(str, "run")){ + initrd_run_prog("/initramfs/vfs1.img"); + } + else if (!strncmp(str, "setTimeout", 10)){ + // str = setTimeout MESSAGE SECONDS + // split the message and seconds into two char* + // without using lib + + // find the first space + int i = 0; + while(str[i] != ' '){ + i++; + } + // find the second space + int j = i + 1; + while(str[j] != ' '){ + j++; + } + // copy the message + char message[100]; + for(int k = i + 1; k < j; k++){ + message[k - i - 1] = str[k]; + } + message[j - i - 1] = '\0'; + // copy the seconds + char seconds[100]; + for(int k = j + 1; k < strlen(str); k++){ + seconds[k - j - 1] = str[k]; + } + seconds[strlen(str) - j - 1] = '\0'; + // convert seconds to int + unsigned int timeout = atoi(seconds); + uart_send_string(message); + uart_send_string(" will be printed in "); + uart_send_string(seconds); + uart_send_string(" seconds\n"); + set_timeout(message, timeout); + } else if (!strcmp(str, "reboot")){ + uart_async_send_string("Rebooting...\n"); + reset(200); + break; + } else if(!strcmp(str, "help")){ + uart_async_send_string("help\t: print this help menu\n"); + uart_async_send_string("hello\t: print Hello World!\n"); + uart_async_send_string("mailbox\t: print board revision and memory info\n"); + // uart_async_send_string("ls\t: list files in the ramdisk\n"); + // uart_async_send_string("cat\t: print content of a file\n"); + uart_async_send_string("reboot\t: reboot this device\n"); + uart_async_send_string("exec\t: execute program from initramfs\n"); + uart_async_send_string("setTimeout\t: setTimeout MESSAGE SECONDS\n"); + } + } + thread_exit(); +} \ No newline at end of file diff --git a/lab8/src/signal.c b/lab8/src/signal.c new file mode 100644 index 000000000..0b42e68c2 --- /dev/null +++ b/lab8/src/signal.c @@ -0,0 +1,66 @@ +#include +#include "alloc.h" +#include "signal.h" +#include "syscall.h" +#include "string.h" +#include "thread.h" + + +void check_and_run_signal() { + thread_t* cur_thread = get_current_thread(); + // if(cur_thread -> tid == 3) { + // uart_send_string("[signal] chcecking for tid: "); + // uart_hex(cur_thread->tid); + // uart_send_string("\n"); + // uart_send_string("[signal] signal 9: "); + // uart_hex(cur_thread->waiting_signal[9]); + // uart_send_string("\n"); + // } + for(int i=0;i<=SIGNAL_NUM;i++) { + if(cur_thread->waiting_signal[i]) { + cur_thread->waiting_signal[i] = 0; + exec_signal(cur_thread, i); + } + } +} + +void exec_signal(thread_t* t, int signal) { + if(t -> is_processing_signal) return; // don't need to handle nested signal + t -> is_processing_signal = 1; + uart_send_string("enter signal handler\n"); + // default signal handler can be run in kernel mode + if(!t->signal_handler[signal]) { + default_signal_handler(); + return; + } + // copy current callee register to thread's callee register + memcpy((void*)&t->signal_regs, (void*)&t->callee_reg, sizeof(callee_reg_t)); + + // set new user stack for signal handler + t -> callee_reg.sp = (uint64_t)kmalloc(T_STACK_SIZE) + T_STACK_SIZE; + t -> callee_reg.fp = t -> callee_reg.sp; + t -> callee_reg.lr = handler_warper; + + unsigned long spsr_el1 = 0x0; // run in el0 and enable all interrupt (DAIF) + unsigned long elr_el1 = (unsigned long)handler_warper; + unsigned long user_sp = t -> callee_reg.sp; + // switch to user mode + asm volatile("msr spsr_el1, %0" : : "r" (spsr_el1)); + asm volatile("msr elr_el1, %0" : : "r" (elr_el1)); + asm volatile("msr sp_el0, %0" : : "r" (user_sp)); + asm volatile("mov x0, %0" : : "r" (t->signal_handler[signal])); + asm volatile("eret"); // jump to user program +} + +void handler_warper(void (*handler)()) { + handler(); + sys_sigreturn(); +} + +void default_signal_handler() { + uart_send_string("Default signal handler\n"); + uart_send_string("current thread tid: "); + uart_hex(get_current_thread()->tid); + uart_send_string("\n"); + kill(get_current_thread()->tid); +} \ No newline at end of file diff --git a/lab8/src/string.c b/lab8/src/string.c new file mode 100644 index 000000000..4b7462373 --- /dev/null +++ b/lab8/src/string.c @@ -0,0 +1,110 @@ +#include "string.h" +#include +#include "mini_uart.h" + +unsigned int is_visible(unsigned int c){ + if(c >= 32 && c <= 126){ + return 1; + } + return 0; +} + +int strcmp(const char *s1, const char *s2) { + while (*s1 && *s2 && (*s1 == *s2)) { + s1++; + s2++; + } + return *s1 - *s2; +} + + +int memcmp(const void *str1, const void *str2, int n) { + const unsigned char *a = str1, *b = str2; + while (n-- > 0) { + if (*a != *b) { + return *a - *b; + } + a++; + b++; + } + return 0; +} + +void *memcpy(void *dst, const void *src, size_t len) +{ + size_t i; + + /* + * memcpy does not support overlapping buffers, so always do it + * forwards. (Don't change this without adjusting memmove.) + * + * For speedy copying, optimize the common case where both pointers + * and the length are word-aligned, and copy word-at-a-time instead + * of byte-at-a-time. Otherwise, copy by bytes. + * + * The alignment logic below should be portable. We rely on + * the compiler to be reasonably intelligent about optimizing + * the divides and modulos out. Fortunately, it is. + */ + + if ((uintptr_t)dst % sizeof(long) == 0 && + (uintptr_t)src % sizeof(long) == 0 && + len % sizeof(long) == 0) { + long *d = dst; + const long *s = src; + + for (i=0; i + +int getpid() { + thread_t* t = get_current_thread(); + return t -> tid; +} + +size_t uart_read(char buf[], size_t size) { + size_t i; + for(i=0;itid); + uart_send_string("\n"); + regs->x19 = get_current_thread()->callee_reg.x19; + regs->x20 = get_current_thread()->callee_reg.x20; + regs->x21 = get_current_thread()->callee_reg.x21; + regs->x22 = get_current_thread()->callee_reg.x22; + regs->x23 = get_current_thread()->callee_reg.x23; + regs->x24 = get_current_thread()->callee_reg.x24; + regs->x25 = get_current_thread()->callee_reg.x25; + regs->x26 = get_current_thread()->callee_reg.x26; + regs->x27 = get_current_thread()->callee_reg.x27; + regs->x28 = get_current_thread()->callee_reg.x28; + regs->fp = get_current_thread()->callee_reg.fp; + regs->lr = get_current_thread()->callee_reg.lr; + regs->sp = get_current_thread()->callee_reg.sp; +} + +int exec(const char* name, char *const argv[]) { + char* target_addr; + char *filepath; + char *filedata; + unsigned int filesize; + // current pointer + cpio_t *header_pointer = (cpio_t *)(ramfs_base); + + // print every cpio pathname + while (header_pointer) + { + + int error = cpio_newc_parse_header(header_pointer, &filepath, &filesize, &filedata, &header_pointer); + // if parse header error + if (error) + { + // uart_printf("error\n"); + uart_send_string("Error parsing cpio header\n"); + break; + } + if (!strcmp(name, filepath)) + { + target_addr = (char*)kmalloc(filesize); + memcpy(target_addr, filedata, filesize); + break; + } + + // if this is not TRAILER!!! (last of file) + if (header_pointer == 0){ + uart_send_string("Program not found\n"); + return 1; + } + } + // run program from current thread + thread_t* cur_thread = get_current_thread(); + + // TODO: signal handling, should clear all signal handler here + for(int i=0;i<=SIGNAL_NUM;i++) { + cur_thread -> signal_handler[i] = 0; + cur_thread -> waiting_signal[i] = 0; + } + + cur_thread -> callee_reg.lr = (unsigned long)target_addr; + + unsigned long spsr_el1 = 0x0; // run in el0 and enable all interrupt (DAIF) + unsigned long elr_el1 = cur_thread -> callee_reg.lr; + unsigned long user_sp = cur_thread -> callee_reg.sp; + unsigned long kernel_sp = (unsigned long)cur_thread -> kernel_stack + T_STACK_SIZE; + + // "r": Any general-purpose register, except sp + asm volatile("msr tpidr_el1, %0" : : "r" (cur_thread)); + asm volatile("msr spsr_el1, %0" : : "r" (spsr_el1)); + asm volatile("msr elr_el1, %0" : : "r" (elr_el1)); + asm volatile("msr sp_el0, %0" : : "r" (user_sp)); + asm volatile("mov sp, %0" :: "r" (kernel_sp)); + asm volatile("eret"); // jump to user program + return 0; +} + +void fork(trapframe_t* tf) { + // uart_send_string("forked\n"); + thread_t* parent_thread = get_current_thread(); + thread_t* child_thread = create_fork_thread(); + + memcpy( + (void*)child_thread->user_stack, + (void*)parent_thread->user_stack, + T_STACK_SIZE + ); + + // copy kernel stack + memcpy( + (void*)child_thread->kernel_stack, + (void*)parent_thread->kernel_stack, + T_STACK_SIZE + ); + save_regs(parent_thread); + copy_regs(&child_thread->callee_reg); + + // copy signal_handler + for(int i=0;i<=SIGNAL_NUM;i++) { + child_thread -> signal_handler[i] = parent_thread -> signal_handler[i]; + child_thread -> waiting_signal[i] = parent_thread -> waiting_signal[i]; + } + + uint64_t parent_sp = get_current_thread() -> callee_reg.sp; + uint64_t parent_fp = get_current_thread() -> callee_reg.fp; + + + child_thread -> callee_reg.sp = (uint64_t)((uint64_t)parent_sp - (uint64_t)parent_thread->kernel_stack + (uint64_t)child_thread->kernel_stack); + child_thread -> callee_reg.fp = (uint64_t)((uint64_t)parent_fp - (uint64_t)parent_thread->kernel_stack + (uint64_t)child_thread->kernel_stack); + + void* label_address = &&SYSCALL_FORK_END; + uart_send_string("Address of SYSCALL_FORK_END: "); + uart_hex((uint64_t)label_address); + uart_send_string("\n"); + + child_thread -> callee_reg.lr = &&SYSCALL_FORK_END; + + // set child trapframe + trapframe_t *child_tf = (trapframe_t*)(child_thread -> kernel_stack + + ((char*)tf - (char*)(parent_thread -> kernel_stack)) + ); + // set child user stack sp + child_tf -> x[0] = 0; + child_tf -> x[30] = tf -> x[30]; + child_tf -> sp_el0 = (void*)((uint64_t)tf -> sp_el0 - (uint64_t)parent_thread->user_stack + (uint64_t)child_thread->user_stack); + child_tf -> spsr_el1 = tf -> spsr_el1; + child_tf -> elr_el1 = tf -> elr_el1; + push_running(child_thread); + tf -> x[0] = child_thread -> tid; +SYSCALL_FORK_END: + int tid = get_current_thread() -> tid; + uart_send_string("forked tid: "); + uart_hex(tid); + uart_send_string("\nforked end\n"); + asm volatile("nop"); + return; +} + +void exit(int status) { + thread_exit(); +} + +int mbox_call(unsigned char ch, unsigned int *mbox) { + return mailbox_call(ch, mbox); +} + +void kill(int pid) { + kill_thread(pid); +} + +void signal(int signal, void (*handler)()) { + thread_t* t = get_current_thread(); + uart_send_string("register signal\n"); + uart_hex(t->tid); + uart_send_string("\n"); + uart_send_string("singal num: "); + uart_hex(signal); + uart_send_string("\n"); + t -> signal_handler[signal] = handler; +} + +void posix_kill(int pid, int signal) { + thread_t* t = get_thread_from_tid(pid); + if(!t) return; + uart_send_string("[set signal] tid: "); + uart_hex(t->tid); + uart_send_string("\n"); + t -> waiting_signal[signal] = 1; +} + +void sigreturn() { + thread_t* t = get_current_thread(); + // uart_send_string("sigreturn\n tid: "); + // uart_hex(t->tid); + // uart_send_string("\n"); + kfree(t -> callee_reg.fp - T_STACK_SIZE); + load_regs(t->signal_regs); + t -> is_processing_signal = 0; + return; +} + + +int sys_getpid() { + int res; + asm volatile("mov x8, 0"); + asm volatile("svc 0"); + asm volatile("mov %0, x0": "=r"(res)); + return res; +} + +int sys_fork() { + int res; + asm volatile("mov x8, 4"); + asm volatile("svc 0"); + asm volatile("mov %0, x0": "=r"(res)); + return res; +} + +void sys_exit(int status){ + asm volatile("mov x8, 5"); + asm volatile("svc 0"); +} + +void sys_posix_kill(){ + asm volatile("mov x8, 9"); + asm volatile("svc 0"); +} + +void sys_sigreturn() { + asm volatile("mov x8, 20"); + asm volatile("svc 0"); +} \ No newline at end of file diff --git a/lab8/src/tasklist.c b/lab8/src/tasklist.c new file mode 100644 index 000000000..f0b742969 --- /dev/null +++ b/lab8/src/tasklist.c @@ -0,0 +1,93 @@ +#include "tasklist.h" +#include "alloc.h" +#include "exception.h" +#include "mini_uart.h" + +task_t *task_head = 0; +int cur_priority = 100; + + +void create_task(task_callback_t callback, unsigned long long priority) { + el1_interrupt_disable(); + task_t* task = (task_t*)kmalloc(sizeof(task_t)); + if(!task) return; + + task->callback = callback; + task->priority = priority; + + enqueue_task(task); + el1_interrupt_enable(); +} + +void enqueue_task(task_t *task) { + el1_interrupt_disable(); + // uart_send_string("enqueue task\n"); + if(!task_head || (task->priority < task_head->priority)) { + task -> next = task_head; + task -> prev = 0; + if(task_head) + task_head->prev = task; + task_head = task; + } else { + task_t *current = task_head; + while(current->next && current->next->priority <= task->priority) { + current = current->next; + } + task->next = current->next; + task->prev = current; + if (current -> next){ + current -> next -> prev = task; + } + current -> next = task; + } + el1_interrupt_enable(); +} + +void execute_tasks() { + // el1_interrupt_disable(); + while(task_head) { + el1_interrupt_disable(); + task_t* cur = task_head; + cur -> callback(); + task_head = cur->next; + if(task_head) { + task_head -> prev = 0; + } + kfree(cur); + el1_interrupt_enable(); + } + // el1_interrupt_enable(); +} + +void execute_tasks_preemptive() { + el1_interrupt_enable(); + while(task_head) { + el1_interrupt_disable(); + task_t* new_task = task_head; + + if(cur_priority <= new_task->priority) { + el1_interrupt_enable(); + break; + } + + task_head = task_head->next; + if(task_head) { + task_head -> prev = 0; + } + int prev_priority = cur_priority; + cur_priority = new_task->priority; + + el1_interrupt_enable(); + // running in preemptive mode + + new_task -> callback(); + + el1_interrupt_disable(); + cur_priority = prev_priority; + kfree(new_task); + + el1_interrupt_enable(); + + // free the task: TDB + } +} \ No newline at end of file diff --git a/lab8/src/thread.c b/lab8/src/thread.c new file mode 100644 index 000000000..85feab104 --- /dev/null +++ b/lab8/src/thread.c @@ -0,0 +1,400 @@ +#include "thread.h" +#include "alloc.h" +#include "mini_uart.h" +#include "c_utils.h" +#include "syscall.h" +#include "timer.h" +#include "shell.h" +#include "alloc.h" +#include + +// define three queues +thread_t* running_q_head = 0; +thread_t* zombie_q_head = 0; + +thread_t* idle_thread = 0; + +int cur_tid = 0; +int cnt_ = 0; + +is_init_thread = 0; + +void push(thread_t** head, thread_t* t) { + // uart_send_string("push thread\n"); + // uart_hex(t->tid); + // uart_send_string("\n"); + // uart_hex(running_q_head->tid); + // uart_send_string("\n"); + // if(running_q_head) + // print_queue(running_q_head); + // uart_hex((*head)->tid); + el1_interrupt_disable(); + if(!(*head)) { + t -> prev = t; + t -> next = t; + (*head) = t; + } else { + t->prev = (*head)->prev; + t->next = (*head); + (*head)->prev->next = t; + (*head)->prev = t; + } + // print_queue(running_q_head); +} + +void print_running() { + if(running_q_head){ + uart_send_string("running q head addr: "); + uart_hex(running_q_head); + uart_send_string("\n"); + print_queue(running_q_head); + page_info_addr(running_q_head); + } +} + +void push_running(thread_t* t) { + push(&running_q_head, t); +} + +thread_t* pop(thread_t** head) { + if(!(*head)) return 0; + thread_t* res = (*head); + el1_interrupt_disable(); + if(res -> next == res){ + (*head) = 0; + } else { + res -> prev -> next = res -> next; + res -> next -> prev = res -> prev; + (*head) = res -> next; + } + el1_interrupt_enable(); + return res; +} + +void pop_t(thread_t** head, thread_t* t) { + el1_interrupt_disable(); + if(!(*head)) return; + if(t -> next == t){ + (*head) = 0; + } else { + t -> prev -> next = t -> next; + t -> next -> prev = t -> prev; + } + el1_interrupt_enable(); +} + +void print_queue(thread_t* head) { + uart_send_string("[INFO] Print Queue:\n["); + thread_t* cur = head; + do { + uart_hex(cur->tid); + uart_send_string(", "); + cur = cur -> next; + } while(cur != head); + uart_send_string("]\n"); +} + +int is_more_than_two_thread() { + thread_t* cur = running_q_head; + int cnt = 0; + do { + cnt++; + cur = cur -> next; + } while(cur != running_q_head); + return cnt > 2; +} + +void schedule() { + el1_interrupt_disable(); + core_timer_disable(); + thread_t* cur_thread = get_current_thread(); + thread_t* next_thread; + if(cur_thread -> state != TASK_RUNNING) { + if(!running_q_head) return; + next_thread = running_q_head; + } else { + next_thread = cur_thread -> next; + } + if (next_thread && next_thread->tid != cur_thread->tid) { + // + // uart_send_string("[SCHEDULE] Switching from "); + // uart_hex(cur_thread->tid); + // uart_send_string(" to "); + // uart_hex(next_thread->tid); + // uart_send_string("\n"); + switch_to(cur_thread, next_thread); + } + core_timer_enable(); + el1_interrupt_enable(); +} + +void kill_zombies() { + el1_interrupt_disable(); + while(zombie_q_head) { + uart_send_string(": "); + print_queue(zombie_q_head); + thread_t* zombie = pop(&zombie_q_head); + uart_send_string("[KILL] killing tid="); + uart_hex(zombie->tid); + uart_send_string("\n"); + kfree(zombie->user_stack); + kfree(zombie->kernel_stack); + // close files + for(int i=0;i <= zombie -> max_fd;i++) { + if(zombie->fds[i].vnode) { + vfs_close(&zombie->fds[i]); + } + } + kfree(zombie); + uart_send_string("[KILL] killed\n"); + } + el1_interrupt_enable(); +} + +thread_t* create_thread(void (*func)(void)) { + thread_t* t = (thread_t*)kmalloc(sizeof(thread_t)); + t -> tid = cur_tid ++; + t -> state = TASK_RUNNING; + t -> callee_reg.lr = (unsigned long)func; + t -> user_stack = kmalloc(T_STACK_SIZE); + t -> kernel_stack = kmalloc(T_STACK_SIZE); + t -> callee_reg.sp = (unsigned long)(t->user_stack + T_STACK_SIZE); + t -> callee_reg.fp = t -> callee_reg.sp; // set fp to sp as the pointer that fixed + + // init signal + for(int i=0;i<=SIGNAL_NUM;i++) { + t -> signal_handler[i] = 0; + t -> waiting_signal[i] = 0; + } + t -> is_processing_signal = 0; + + t -> prev = 0; + t -> next = 0; + + t -> working_dir = rootfs -> root; + for(int i=0;i fds[i].vnode = 0; + } + vfs_open("/dev/uart", 0, &t->fds[0]); + vfs_open("/dev/uart", 0, &t->fds[1]); + vfs_open("/dev/uart", 0, &t->fds[2]); + t -> max_fd = 2; // because we have 3 fds + + // TODO: pass data into function + uart_send_string("creating thread\n"); + // if(running_q_head) + // print_queue(running_q_head); + push(&running_q_head, t); + print_queue(running_q_head); + return t; +} + +thread_t* create_fork_thread() { + thread_t* t = (thread_t*)kmalloc(sizeof(thread_t)); + t -> tid = cur_tid ++; + t -> state = TASK_RUNNING; + t -> callee_reg.lr = 0; + t -> user_stack = kmalloc(T_STACK_SIZE); + t -> kernel_stack = kmalloc(T_STACK_SIZE); + t -> callee_reg.sp = (unsigned long)(t->user_stack + T_STACK_SIZE); + t -> callee_reg.fp = t -> callee_reg.sp; // set fp to sp as the pointer that fixed + + for(int i=0;i<=SIGNAL_NUM;i++) { + t -> signal_handler[i] = 0; + t -> waiting_signal[i] = 0; + } + t -> is_processing_signal = 0; + + t -> prev = 0; + t -> next = 0; + + t -> working_dir = rootfs -> root; + for(int i=0;i fds[i].vnode = 0; + } + + vfs_open("/dev/uart", 0, &t->fds[0]); + vfs_open("/dev/uart", 0, &t->fds[1]); + vfs_open("/dev/uart", 0, &t->fds[2]); + t -> max_fd = 2; + + + return t; +} + + +thread_t* get_thread_from_tid(int tid) { + thread_t* cur = running_q_head; + do { + if(cur -> tid == tid) { + return cur; + } + cur = cur -> next; + } while(cur != running_q_head); + + return 0; +} + +void kill_thread(int tid) { + thread_t* t = get_thread_from_tid(tid); + if(!t) return; + t -> state = TASK_ZOMBIE; + running_q_head = t -> next; + pop_t(&running_q_head, t); + push(&zombie_q_head, t); + uart_send_string("[kill]\n"); + schedule(); +} + +void thread_init() { + uart_send_string("[INFO] Init thread\n"); + idle_thread = create_thread(idle); + asm volatile("msr tpidr_el1, %0" :: "r"(idle_thread)); + is_init_thread = 1; +} + +void thread_exit() { + thread_t* cur = get_current_thread(); + uart_send_string("[EXIT] tid="); + uart_hex(cur->tid); + uart_send_string("\n"); + cur -> state = TASK_ZOMBIE; + running_q_head = cur -> next; + pop_t(&running_q_head, cur); + push(&zombie_q_head, cur); + schedule(); +} + +void thread_wait(int tid) { + thread_t* cur = running_q_head; + + while(1) { + el1_interrupt_disable(); + int running = 0; + thread_t* cur = running_q_head; + do { + if(cur -> tid == tid){ + running = 1; + break; + } + cur = cur -> next; + } while(cur != running_q_head); + if(running) { + schedule(); + } else { + break; + } + el1_interrupt_enable(); + } + el1_interrupt_enable(); +} + +void idle() { + while(1) { + kill_zombies(); + schedule(); + } +} + +void foo(){ + for(int i = 0; i < 10; ++i) { + uart_send_string("Thread id: "); + uart_hex(get_current_thread()->tid); + uart_send_string(" "); + uart_hex(i); + uart_send_string("\n"); + delay(1000000); + schedule(); + } + thread_exit(); +} + +void thread_test() { + for(int i=0;i<3;i++) { + uart_send_string("[INFO] Thread id: "); + uart_hex(i); + uart_send_string("\n"); + create_thread(foo); + } + // print_queue(running_q_head); + idle(); +} + +void run_fork_test() { + thread_t* t = get_current_thread(); + uart_hex(t->tid); + uart_send_string("\n"); + uart_hex(t->callee_reg.sp); + for(int i=0;i<1000000;i++); + asm volatile("msr spsr_el1, %0" ::"r"(0x3c0)); // disable E A I F + asm volatile("msr elr_el1, %0" ::"r"(main_fork_test)); // get back to caller function + asm volatile("msr sp_el0, %0" ::"r"(t->callee_reg.sp)); + asm volatile("mov sp, %0" ::"r"(t->kernel_stack + T_STACK_SIZE)); + asm volatile("eret"); +} + +void main_fork_test(){ + uart_send_string("\nFork Test, pid: "); + uart_hex(sys_getpid()); + uart_send_string("\n"); + int cnt = 1; + int ret = 0; + if ((ret = sys_fork()) == 0) { // child + long long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + uart_send_string("first child pid: "); + uart_hex(sys_getpid()); + uart_send_string(", cnt:"); + uart_hex(cnt); + uart_send_string(", ptr:"); + uart_hex(&cnt); + uart_send_string(", sp: "); + uart_hex(cur_sp); + uart_send_string("\n"); + ++cnt; + + if ((ret = sys_fork()) != 0){ + asm volatile("mov %0, sp" : "=r"(cur_sp)); + uart_send_string("first child pid: "); + uart_hex(sys_getpid()); + uart_send_string(", cnt:"); + uart_hex(cnt); + uart_send_string(", ptr:"); + uart_hex(&cnt); + uart_send_string(", sp: "); + uart_hex(cur_sp); + uart_send_string("\n"); + } + else { + while (cnt < 5) { + asm volatile("mov %0, sp" : "=r"(cur_sp)); + uart_send_string("second child pid: "); + uart_hex(sys_getpid()); + uart_send_string(", cnt: "); + uart_hex(cnt); + uart_send_string(", ptr: "); + uart_hex(&cnt); + uart_send_string(", sp: "); + uart_hex(cur_sp); + uart_send_string("\n"); + for(int i=0;i<1000000;i++); + ++cnt; + } + } + sys_exit(0); + } + else { + uart_send_string("parent here, pid "); + uart_hex(sys_getpid()); + uart_send_string(", child "); + uart_hex(ret); + uart_send_string("\n"); + print_queue(running_q_head); + } + sys_exit(0); +} + +void fork_test() { + create_thread(run_fork_test); + idle(); +} \ No newline at end of file diff --git a/lab8/src/timer.c b/lab8/src/timer.c new file mode 100644 index 000000000..dbbd25dca --- /dev/null +++ b/lab8/src/timer.c @@ -0,0 +1,114 @@ +#include "timer.h" +#include "mini_uart.h" +#include "string.h" +#include "alloc.h" +#include "c_utils.h" +#include "exception.h" +#include "thread.h" +#include "mini_uart.h" + +timer_t *timer_head = 0; + +void print_message(void *data) { + char* message = data; + unsigned long long current_time, cntfrq; + asm volatile("mrs %0, cntpct_el0" : "=r"(current_time)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + + unsigned int sec = current_time / cntfrq; + + uart_send_string("\nTimeout message: "); + uart_send_string(message); + uart_send_string(" at "); + uart_hex(sec); + uart_send_string(" seconds\n# "); +} + +void set_timeout(char* message, unsigned long long timeout) { + char* message_copy = (char*)kmalloc(strlen(message)+1); + strncpy_(message_copy, message, strlen(message)+1); + if(!message_copy) return; + + if(!timer_head) { + // enable timer + *CORE0_TIMER_IRQ_CTRL = 2; + } + + create_timer(print_message, message_copy, timeout); +} + +void create_timer( + timer_callback_t callback, + void *data, + unsigned long long timeout +) { + timer_t *timer = (timer_t*)kmalloc(sizeof(timer_t)); + if(!timer) return; + + timer->callback = callback; + timer->data = data; + timer->next = 0; + + unsigned long long current_time, cntfrq; + asm volatile("mrs %0, cntpct_el0" : "=r"(current_time)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + + timer->timeout = current_time + timeout * cntfrq; + + add_timer(&timer); +} + +void add_timer(timer_t **timer) { + el1_interrupt_disable(); + // uart_send_string("add timer\n"); + // if the timer list is empty or the new timer is the first to expire + if(!timer_head) uart_send_string("timer_head is null\n"); + if(!timer_head || (timer_head -> timeout > (*timer) -> timeout)) { + (*timer) -> next = timer_head; + timer_head = *timer; + asm volatile("msr cntp_ctl_el0, %0" : : "r"(1)); + asm volatile("msr cntp_cval_el0, %0" : : "r"(timer_head -> timeout)); + el1_interrupt_enable(); + return; + } + + timer_t *current = timer_head; + + // find the correct position to insert the new timer + while(current -> next && current -> next -> timeout < (*timer) -> timeout) { + current = current -> next; + } + + (*timer) -> next = current -> next; + current -> next = (*timer); + + el1_interrupt_enable(); +} + + +void create_timer_freq_shift( + timer_callback_t callback, + void *data, + unsigned long long shift +) { + timer_t *timer = (timer_t*)kmalloc(sizeof(timer_t)); + if(!timer) return; + + timer->callback = callback; + timer->data = data; + + unsigned long long current_time, cntfrq; + asm volatile("mrs %0, cntpct_el0" : "=r"(current_time)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq)); + + timer->timeout = current_time + (cntfrq >> shift); + // uart_send_string("timeout: "); + // uart_hex(timer->timeout); + // uart_send_string("\n"); + add_timer(&timer); +} + +void schedule_task(void* data) { + // uart_send_string("Schedule task\n"); + create_timer_freq_shift(schedule_task, 0, 5); +} \ No newline at end of file diff --git a/lab8/user_prog/Makefile b/lab8/user_prog/Makefile new file mode 100644 index 000000000..1cf1797fa --- /dev/null +++ b/lab8/user_prog/Makefile @@ -0,0 +1,28 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only +ASMOPS = -Iinclude + +BUILD_DIR = build + +all : user_prog.img + +clean : + rm -rf $(BUILD_DIR) *.img + + +$(BUILD_DIR)/%_s.o: %.S + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard *.c) +ASM_FILES = $(wildcard *.S) +OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +user_prog.img: linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T linker.ld -o $(BUILD_DIR)/user_prog.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/user_prog.elf -O binary user_prog.img \ No newline at end of file diff --git a/lab8/user_prog/linker.ld b/lab8/user_prog/linker.ld new file mode 100644 index 000000000..8c825e31d --- /dev/null +++ b/lab8/user_prog/linker.ld @@ -0,0 +1,9 @@ + +SECTIONS +{ + . = 0x80000; + .text : + { + *(.text) + } +} \ No newline at end of file diff --git a/lab8/user_prog/user_prog.S b/lab8/user_prog/user_prog.S new file mode 100644 index 000000000..838323763 --- /dev/null +++ b/lab8/user_prog/user_prog.S @@ -0,0 +1,11 @@ +.section ".text" +.global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b +1: + b 1b \ No newline at end of file diff --git a/lab8/user_prog/user_prog.img b/lab8/user_prog/user_prog.img new file mode 100755 index 000000000..1adf648a4 Binary files /dev/null and b/lab8/user_prog/user_prog.img differ