From 2aa0c7a859924d33bc36c56db789e886a3dae8cb Mon Sep 17 00:00:00 2001 From: leonkei Date: Sat, 14 May 2022 23:43:13 +0800 Subject: [PATCH 1/4] clear my mid --- .vscode/settings.json | 7 +- a.S | 42 ++- include/cpio.h | 2 +- include/sched.h | 60 +++++ include/syscall.h | 29 +++ include/utils.h | 9 + initramfs.cpio | Bin 3584 -> 23552 bytes src/allocator.c | 16 +- src/cpio.c | 16 +- src/main.c | 105 +++----- src/sched.c | 157 ++++++++++++ src/shell.c | 13 +- src/syscall.c | 87 +++++++ user/Makefile | 43 ++++ user/a.S | 6 + user/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 31790 bytes user/include/allocator.h | 62 +++++ user/include/cpio.h | 13 + user/include/dtb.h | 39 +++ user/include/exception.h | 16 ++ user/include/list.h | 45 ++++ user/include/mailbox.h | 16 ++ user/include/mini_uart.h | 75 ++++++ user/include/reboot.h | 3 + user/include/shell.h | 29 +++ user/include/stdlib.h | 8 + user/include/string.h | 5 + user/include/task.h | 16 ++ user/include/timer.h | 22 ++ user/include/usr_syscall.h | 8 + user/include/utils.h | 58 +++++ user/initramfs.cpio | Bin 0 -> 3584 bytes user/linker.ld | 19 ++ user/src/allocator.c | 469 ++++++++++++++++++++++++++++++++++ user/src/cpio.c | 193 ++++++++++++++ user/src/dtb.c | 78 ++++++ user/src/exception.c | 175 +++++++++++++ user/src/mailbox.c | 125 +++++++++ user/src/main.c | 38 +++ user/src/mini_uart.c | 317 +++++++++++++++++++++++ user/src/reboot.c | 20 ++ user/src/shell.c | 420 ++++++++++++++++++++++++++++++ user/src/stdlib.c | 14 + user/src/string.c | 61 +++++ user/src/task.c | 61 +++++ user/src/timer.c | 156 +++++++++++ user/src/utils.c | 16 ++ user/syscall.S | 47 ++++ 48 files changed, 3124 insertions(+), 92 deletions(-) create mode 100644 include/sched.h create mode 100644 include/syscall.h create mode 100644 src/sched.c create mode 100644 src/syscall.c create mode 100644 user/Makefile create mode 100644 user/a.S create mode 100644 user/bcm2710-rpi-3-b-plus.dtb create mode 100644 user/include/allocator.h create mode 100644 user/include/cpio.h create mode 100644 user/include/dtb.h create mode 100644 user/include/exception.h create mode 100644 user/include/list.h create mode 100644 user/include/mailbox.h create mode 100644 user/include/mini_uart.h create mode 100644 user/include/reboot.h create mode 100644 user/include/shell.h create mode 100644 user/include/stdlib.h create mode 100644 user/include/string.h create mode 100644 user/include/task.h create mode 100644 user/include/timer.h create mode 100644 user/include/usr_syscall.h create mode 100644 user/include/utils.h create mode 100644 user/initramfs.cpio create mode 100644 user/linker.ld create mode 100644 user/src/allocator.c create mode 100644 user/src/cpio.c create mode 100644 user/src/dtb.c create mode 100644 user/src/exception.c create mode 100644 user/src/mailbox.c create mode 100644 user/src/main.c create mode 100644 user/src/mini_uart.c create mode 100644 user/src/reboot.c create mode 100644 user/src/shell.c create mode 100644 user/src/stdlib.c create mode 100644 user/src/string.c create mode 100644 user/src/task.c create mode 100644 user/src/timer.c create mode 100644 user/src/utils.c create mode 100644 user/syscall.S diff --git a/.vscode/settings.json b/.vscode/settings.json index bd128e451..ff8477435 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,11 @@ { "files.associations": { "utils.h": "c", - "algorithm": "c" + "algorithm": "c", + "thread.h": "c", + "array": "c", + "string_view": "c", + "initializer_list": "c", + "utility": "c" } } \ No newline at end of file diff --git a/a.S b/a.S index cb6b7e4f7..2d0276c20 100644 --- a/a.S +++ b/a.S @@ -66,17 +66,26 @@ main_loop: stp x24, x25, [sp ,16 * 12] stp x26, x27, [sp ,16 * 13] stp x28, x29, [sp ,16 * 14] - str x30, [sp, 16 * 15] + + str x30, [sp, 16 * 15] // for nested interrupt mrs x0, spsr_el1 mrs x1, elr_el1 stp x0,x1, [sp, 16 * 16] - ldp x0, x1, [sp ,16 * 0] + + // ldp x0, x1, [sp ,16 * 0] + + // for el0 user stack pointer + mrs x0, sp_el0 + str x0, [sp, 16 * 17] .endm // load general registers from stack .macro load_all + ldr x0, [sp, 16 * 17] + msr sp_el0,x0 + ldp x0,x1,[sp, 16 * 16] msr spsr_el1,x0 msr elr_el1,x1 @@ -188,4 +197,31 @@ core_timer_handler: add x0,x0,x0 // add x0,x0,x1 msr cntp_tval_el0, x0 - ret \ No newline at end of file + ret + +.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 get_current +get_current: + mrs x0, tpidr_el1 + ret \ No newline at end of file diff --git a/include/cpio.h b/include/cpio.h index bc53ee991..faa71bb04 100644 --- a/include/cpio.h +++ b/include/cpio.h @@ -5,7 +5,7 @@ extern uint32_t* cpio_addr; void cpio_ls(); void cpio_cat(); -unsigned long long cpio_get_addr(); +void cpio_get_addr(char* filedata,unsigned long* filesize); //void* initramfs_callback(fdt_prop* prop,char * name,uint32_t len_prop); void* initramfs_start_callback(fdt_prop* prop,char * name,uint32_t len_prop); void* initramfs_end_callback(fdt_prop* prop,char * name,uint32_t len_prop); diff --git a/include/sched.h b/include/sched.h new file mode 100644 index 000000000..2bef464d7 --- /dev/null +++ b/include/sched.h @@ -0,0 +1,60 @@ +#ifndef _SCHEDULE_HEADER_ +#define _SCHEDULE_HEADER_ +#define THREAD_STACK_SIZE 4096 +enum task_state +{ + EMPTY, + RUNNABLE, + WAITING, + RUNNING, + FINISHED, + ZOMBIE, +}; +typedef struct cpu_context +{ + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long lr; + unsigned long sp; +}cpu_context; +typedef struct Thread_struct +{ + cpu_context cpu_context; + enum task_state state; + unsigned int id; + void* user_stack; + void* kernel_stack; + struct Thread_struct *next,*prev; + // long counter; + // int priority; + // long preempt_count; +}Thread_struct; +typedef struct task_queue +{ + Thread_struct* task; + struct task_queue *next,*prev; +}task_queue; + +void thread_create(void (*f)()); +Thread_struct current_thread(); +void schedule(); +void idle(); +void kill_zombie(); +void init_sched(); +void push_thread(Thread_struct*); +void iter_runqueue(); +void exec_thread(); +void context_switch(Thread_struct* next); +Thread_struct* pop_thread(); +void thread_exit(); +void thread_exec(); +#endif \ No newline at end of file diff --git a/include/syscall.h b/include/syscall.h new file mode 100644 index 000000000..d41e314d3 --- /dev/null +++ b/include/syscall.h @@ -0,0 +1,29 @@ +#ifndef _SYSCALL_HEADER_ +#define _SYSCALL_HEADER_ + +#define SYS_GETPID 0 +#define SYS_UART_READ 1 +#define SYS_UART_WRITE 2 +#define SYS_EXEC 3 +#define SYS_FORK 4 +#define SYS_EXIT 5 +#define SYS_MBOX_CALL 6 +#define SYS_KILL 7 + +typedef struct trap_frame{ + unsigned long long x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, + x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, + x21, x22, x23, x24, x25, x26, x27, x28, x29, x30; + unsigned long sp_el0, spsr_el1, elr_el1; +}trap_frame; + +int sys_getpid(trap_frame*); +unsigned int sys_uart_read(trap_frame*,char buf[],unsigned int size); +unsigned int sys_uart_write(trap_frame*,const char* name,unsigned int size); +int sys_exec(trap_frame*,const char* name, char *const argv[]); +int sys_fork(trap_frame*); +void sys_exit(trap_frame*); +int sys_mbox_call(trap_frame*,unsigned char ch, unsigned int *mbox); +void sys_kill(trap_frame*,int pid); + +#endif \ No newline at end of file diff --git a/include/utils.h b/include/utils.h index be320f56d..8f9fad65f 100644 --- a/include/utils.h +++ b/include/utils.h @@ -54,5 +54,14 @@ static inline unsigned int powOf2ToExponent(int n){ } return exp; } +static inline void * +memcpy (void *dest, const void *src, size_t len) +{ + char *d = dest; + const char *s = src; + while (len--) + *d++ = *s++; + return dest; +} #endif \ No newline at end of file diff --git a/initramfs.cpio b/initramfs.cpio index 8f5c6ab590d5d3e974d1622c9e88f4f1581cfcdb..1d29c7b1af290d08dd0a1f340c5b59a74482da71 100644 GIT binary patch literal 23552 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 diff --git a/src/allocator.c b/src/allocator.c index b71a442b6..47fc172b5 100644 --- a/src/allocator.c +++ b/src/allocator.c @@ -104,10 +104,10 @@ void* get_freeframe_addr(unsigned int size){ for (i = 0; i <= MAX_CONTIBLOCK_SIZE; i++) { if(frame_freelist[i]!=nullptr && BLOCK_SIZE*power(2,i)>=size){ - writes_uart("Require "); - write_int_uart(size,FALSE); - writes_uart(" ,Min free block size: "); - write_int_uart(BLOCK_SIZE *power(2,i),TRUE); + // writes_uart("Require "); + // write_int_uart(size,FALSE); + // writes_uart(" ,Min free block size: "); + // write_int_uart(BLOCK_SIZE *power(2,i),TRUE); break; } } @@ -154,8 +154,8 @@ void* get_freeframe_addr(unsigned int size){ // frame_freelist[i] = frame_freelist[i]->next; - writes_uart("Got block size: "); - write_int_uart(-frame_array[node->_index]->size,TRUE); + // writes_uart("Got block size: "); + // write_int_uart(-frame_array[node->_index]->size,TRUE); unsigned long long freeframe_addr = ALLOCATOR_START + node->_index*BLOCK_SIZE; return (void*)freeframe_addr; @@ -406,10 +406,10 @@ void* get_freechunk_addr(int size){ void* my_malloc(unsigned int size){ void* malloc_addr = nullptr; if(size<=chunk_size_arr[chunk_arr_len-1]){ - writes_uart("Chunk malloc "); + // writes_uart("Chunk malloc "); int chunk_size = getBestChunkSize(size); - write_int_uart(chunk_size,TRUE); + // write_int_uart(chunk_size,TRUE); malloc_addr = get_freechunk_addr(chunk_size); // unsigned int chunk_frame_idx = frameAddrToIdx(malloc_addr); diff --git a/src/cpio.c b/src/cpio.c index cfb46a1d5..46099c8d4 100644 --- a/src/cpio.c +++ b/src/cpio.c @@ -108,7 +108,7 @@ void cpio_cat(){ writes_uart("Filename: "); char* read_name; read_string(&read_name); - + while(1){ int parse_result = cpio_parse_header(cnh,&filename,&filesize,&filedata,&next_header); if(parse_result!=0){ @@ -132,29 +132,31 @@ void cpio_cat(){ } } -unsigned long long cpio_get_addr(){ +void cpio_get_addr(char* filedata,unsigned long* filesize){ cpio_newc_header* cnh = (cpio_newc_header*)cpio_addr; cpio_newc_header* next_header; char *filename; - char *filedata; - unsigned long filesize; + // char *filedata; + // unsigned long filesize; writes_uart("Filename: "); char* read_name; read_string(&read_name); while(1){ - if(cpio_parse_header(cnh,&filename,&filesize,&filedata,&next_header)!=0){ + if(cpio_parse_header(cnh,&filename,filesize,&filedata,&next_header)!=0){ writes_uart("File not found!\r\n"); + *filesize=0; break; } if(strncmp(read_name,".",strlen(read_name))==0){ writes_uart(".: Is a directory\r\n"); + *filesize=0; break; } else if(strncmp(read_name,filename,strlen(read_name))==0){ // writes_n_uart(filedata,parse_hex_str(cnh->c_filesize,sizeof(cnh->c_filesize))); // writes_uart("\r\n"); - return (unsigned long long)filedata; + // return (unsigned long long)filedata; break; } //writes_n_uart(filename,parse_hex_str(cnh->c_namesize,sizeof(cnh->c_namesize))); @@ -163,7 +165,7 @@ unsigned long long cpio_get_addr(){ // writes_uart("\r\n"); cnh = next_header; } - return 0; + // return 0; } void* initramfs_start_callback(fdt_prop* prop,char * name,uint32_t len_prop){ diff --git a/src/main.c b/src/main.c index f74aee944..916e80859 100644 --- a/src/main.c +++ b/src/main.c @@ -8,29 +8,30 @@ #include "timer.h" #include "task.h" #include "allocator.h" +#include "sched.h" extern unsigned long _head_start_brk; +extern Thread_struct* get_current(); +void foo() +{ + for(int i = 0; i < 10; ++i) { + writes_uart("Thread id: "); + write_int_uart(get_current()->id,FALSE); + writes_uart(" "); + write_int_uart(i,TRUE); + // delay(1000000); + // unsigned long long time_count=0; + // unsigned long long time_freq=0; + // get_current_time(&time_count,&time_freq); + // unsigned long long time_target = time_count + time_freq*0.01; + // while(time_count < time_target){ + // get_current_time(&time_count,&time_freq); + // } + schedule(); + } + thread_exit(); + // get_current()->state = FINISHED; +} -// uint32_t* cpio_addr; -// bool initramfs_callback(fdt_prop* prop,char * name,uint32_t len_prop){ -// if(strncmp(name,"linux,initrd-start",18)==0){ // start address of initrd -// writes_uart("Found target: \""); -// writes_n_uart(name,18); -// writes_uart("\" at address "); -// cpio_addr = (unsigned int*)((unsigned long)big2little(*((uint32_t*)(prop+1)))); -// writehex_uart((unsigned long)cpio_addr,TRUE); -// return TRUE; -// } -// else if(strncmp(name,"linux,initrd-end",18)==0) -// { -// writes_uart("Found target: \""); -// writes_n_uart(name,18); -// writes_uart("\" at address "); -// cpio_addr = (unsigned int*)((unsigned long)big2little(*((uint32_t*)(prop+1)))); -// writehex_uart((unsigned long)cpio_addr,TRUE); -// return TRUE; -// } -// return FALSE; -// } int main(){ // register unsigned long dtb_reg asm ("x15"); @@ -41,64 +42,26 @@ int main(){ init_taskq(); init_memory(); init_timer(); - + init_sched(); *AUX_MU_IER_REG = 1; // 3 for RX, TX interrupt enable *IRQ_ENABLE1 = 1<<29; writes_uart("\r\n"); - writes_uart("██╗ ██╗███████╗██╗ ██████╗ ██████╗ ███╗ ███╗███████╗\r\n"); - writes_uart("██║ ██║██╔════╝██║ ██╔════╝██╔═══██╗████╗ ████║██╔════╝\r\n"); - writes_uart("██║ █╗ ██║█████╗ ██║ ██║ ██║ ██║██╔████╔██║█████╗ \r\n"); - writes_uart("██║███╗██║██╔══╝ ██║ ██║ ██║ ██║██║╚██╔╝██║██╔══╝ \r\n"); - writes_uart("╚███╔███╔╝███████╗███████╗╚██████╗╚██████╔╝██║ ╚═╝ ██║███████╗\r\n"); - writes_uart("╚══╝╚══╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝\r\n"); - - // writes_uart("Hello World!\r\n"); - - // unsigned long long cur_excep_lvl; - // asm volatile( - // "mrs x0, CurrentEL\n\t" - // "mov %0,x0\n\t" - // :"=r" (cur_excep_lvl) - // ); - // writes_uart("Current exceotion level:"); - // writehex_uart(cur_excep_lvl>>2,1); - - // writes_uart("Loaded dtb address: "); - // writehex_uart(dtb_reg); - // writes_uart("\r\n"); - - // fdt_traverse(initramfs_start_callback); - // fdt_traverse(initramfs_end_callback); - - // list_freeChunkNode(); - // list_freeFrameNode(); + // writes_uart("██╗ ██╗███████╗██╗ ██████╗ ██████╗ ███╗ ███╗███████╗\r\n"); + // writes_uart("██║ ██║██╔════╝██║ ██╔════╝██╔═══██╗████╗ ████║██╔════╝\r\n"); + // writes_uart("██║ █╗ ██║█████╗ ██║ ██║ ██║ ██║██╔████╔██║█████╗ \r\n"); + // writes_uart("██║███╗██║██╔══╝ ██║ ██║ ██║ ██║██║╚██╔╝██║██╔══╝ \r\n"); + // writes_uart("╚███╔███╔╝███████╗███████╗╚██████╗╚██████╔╝██║ ╚═╝ ██║███████╗\r\n"); + // writes_uart("╚══╝╚══╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝\r\n"); - // unsigned long long got_freeaddr[16]; - // for (int i = 0; i < 16; i++) - // { - // unsigned int* f_addr; - // writes_uart("Mallocing "); - // write_int_uart(power(2,i),TRUE); - // f_addr = my_malloc(power(2,i)); - - // got_freeaddr[i]=f_addr; - // writes_uart("Got address "); - // writehex_uart((unsigned int)f_addr,TRUE); - // // list_freeFrameNode(); - // } - // list_freeChunkNode(); - // list_freeFrameNode(); - - // for (int i = 0; i < 16; i++) + writes_uart("Hello World!\r\n"); + // for (int i = 0; i < 10; i++) // { - // writes_uart("Free address "); - // writehex_uart(got_freeaddr[i],TRUE); - // free(got_freeaddr[i]); + // thread_create(foo); // } - // list_freeChunkNode(); - // list_freeFrameNode(); + // idle(); + while(1) { diff --git a/src/sched.c b/src/sched.c new file mode 100644 index 000000000..28372af8a --- /dev/null +++ b/src/sched.c @@ -0,0 +1,157 @@ + +#include "mini_uart.h" +#include "allocator.h" +#include "sched.h" +#include "exception.h" +#include "cpio.h" +#define TASK_POOL_SIZE 20 + +extern void switch_to(Thread_struct* prev, Thread_struct* next); +extern Thread_struct* get_current(); + +Thread_struct* thread_pool; +Thread_struct* run_queue; +Thread_struct* wait_queue; + +void thread_create(void (*f)()){ + int i; + for (i = 0; i < TASK_POOL_SIZE; i++) + { + if(thread_pool[i].state == EMPTY){ + break; + } + } + thread_pool[i].state = RUNNING; + thread_pool[i].user_stack = my_malloc(THREAD_STACK_SIZE); + thread_pool[i].kernel_stack = my_malloc(THREAD_STACK_SIZE); + thread_pool[i].cpu_context.lr = (unsigned long)f; + thread_pool[i].cpu_context.fp = (unsigned long)(thread_pool[i].kernel_stack + THREAD_STACK_SIZE); + thread_pool[i].cpu_context.sp = (unsigned long)(thread_pool[i].kernel_stack + THREAD_STACK_SIZE); + writes_uart("Create Thread "); + write_int_uart(i,TRUE); + push_thread(&thread_pool[i]); +} +void schedule() +{ + // disable_interrupt(); + if(run_queue != nullptr) + { + Thread_struct* next = pop_thread(run_queue); + // context_switch(next); + Thread_struct* cur = get_current(); + if (cur->state == RUNNING) + { + push_thread(cur); + } + writes_uart("From "); + write_int_uart(cur->id,FALSE); + writes_uart(" schedule to "); + write_int_uart(next->id,TRUE); + iter_runqueue(); + switch_to(cur,next); + } + // enable_interrupt(); +} +void context_switch(Thread_struct* next) { + + // Thread_struct *current = get_current(); + // asm volatile("msr sp_el0, %0" : : "r"(&ustack_pool[current->id][USTACK_TOP_IDX])); + // asm volatile("msr elr_el1, %0": : "r"(func)); + // asm volatile("msr spsr_el1, %0" : : "r"(SPSR_EL1_VALUE)); + // asm volatile("eret"); +} +void init_sched() +{ + run_queue = nullptr; + thread_pool = my_malloc(TASK_POOL_SIZE * sizeof(Thread_struct)); + for (int i = 0; i < TASK_POOL_SIZE; i++) + { + thread_pool[i].state = EMPTY; + thread_pool[i].id = i; + thread_pool[i].cpu_context.sp = (unsigned long)nullptr; + } + thread_pool[0].state = RUNNING; // idle task; + asm volatile( + "msr tpidr_el1, %0" + :: "r" (&thread_pool[0]) + ); +} +void idle() +{ + // iter_runqueue(); + while(TRUE) + { + kill_zombie(); + schedule(); + } +} +void kill_zombie() +{ + +} +void thread_exit() +{ + get_current()->state = ZOMBIE; + schedule(); +} +void iter_runqueue() +{ + Thread_struct* node = run_queue; + while(node != nullptr){ + write_int_uart(node->id,FALSE); + writes_uart("->"); + node = node->next; + } + writes_uart("\r\n"); +} +void push_thread(Thread_struct* t) +{ + if(run_queue == nullptr){ + // run_queue = my_malloc(sizeof(Thread_struct)); + run_queue = t; + run_queue->next = nullptr; + run_queue->prev = nullptr; + + } + else{ + Thread_struct* node; + node = run_queue; + while(node->next != nullptr){ + node = node->next; + } + node->next = t; + t->prev = node; + t->next = nullptr; + // writes_uart("Pushed in to queue: "); + // write_int_uart(t->id,TRUE); + } +} +Thread_struct* pop_thread() +{ + Thread_struct* q = run_queue; + if(run_queue!=nullptr){ + if(q->next){ + q->next->prev = nullptr; + } + run_queue = run_queue->next; + } + return q; +} +void thread_exec() +{ + char *file_start = nullptr; + unsigned long filesize; + cpio_get_addr(file_start,&filesize); + char *new_start = my_malloc(filesize); + memcpy(new_start,file_start,filesize); + asm volatile( + "mov x0, 0\n\t" // + "msr spsr_el1, x0\n\t" + "msr elr_el1, %0\n\t" + "msr sp_el0,%1\n\t" + "eret\n\t" // + ::"r" (new_start), + "r" (get_current()->user_stack) + : "x0" + ); +} \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index c7a21e5d8..67876d502 100644 --- a/src/shell.c +++ b/src/shell.c @@ -6,6 +6,7 @@ #include "stdlib.h" #include "timer.h" #include "allocator.h" +#include "sched.h" int match_command(char *buffer){ if(strcmp(buffer,"help")==0){ @@ -244,7 +245,14 @@ void handle_command(enum Action action, char *buffer){ break; case prog: { - unsigned long long prog_addr = cpio_get_addr(); + // origin + char *filedata = nullptr; + unsigned long filesize; + cpio_get_addr(filedata,&filesize); + if(filesize == 0){ + break; + } + unsigned long long prog_addr = (unsigned long long)filedata; unsigned long *e0_stack = (unsigned long*)simple_malloc(2000); writehex_uart(prog_addr,1); // writehex_uart(e0_stack); @@ -265,6 +273,9 @@ void handle_command(enum Action action, char *buffer){ : "x0" ); writes_nl_uart("Run userprogram done"); + + // thread_create(&thread_exec); + // idle(); break; } case timeout: diff --git a/src/syscall.c b/src/syscall.c new file mode 100644 index 000000000..cf860cdb3 --- /dev/null +++ b/src/syscall.c @@ -0,0 +1,87 @@ +#include "syscall.h" +#include "sched.h" +#include "mini_uart.h" +#include "cpio.h" +#include "allocator.h" +#include "utils.h" +extern Thread_struct* get_current(); +int sys_getpid(trap_frame* tf){ + tf->x0 = get_current()->id; + return get_current()->id; +} +unsigned int sys_uart_read(trap_frame* tf,char buf[],unsigned int size) +{ + for (int i = 0; i < size; i++) + { + // buf[i] = read_uart(); + do{asm volatile("nop");}while(is_empty_read()); + buf[i] = uart_buf_read_pop(); + } + tf->x0 = size; + return size; +} +unsigned int sys_uart_write(trap_frame* tf,const char* name,unsigned int size) +{ + for (int i = 0; i < size; i++) + { + // busy_wait_writec(name[i]); + writec_uart(name[i]); + } + tf->x0 = size; + return size; +} +int kernel_exec(trap_frame* tf,const char* name, char *const argv[]) +{ + // char *file_start = nullptr; + // unsigned long filesize; + // cpio_get_addr(file_start,&filesize); + // char *new_start = my_malloc(filesize); + // memcpy(new_start,file_start,filesize); + // thread_exec(new_start); + + + // if(filesize!=0){ // file not found if filesize == 0 + // tf->sp_el0 = (unsigned long)(get_current()->user_stack + THREAD_STACK_SIZE); + // tf->elr_el1 = (unsigned long)new_start; + // tf->spsr_el1 = 0; + // // asm volatile("msr sp_el0, %0" : : "r"(get_current()->user_stack + THREAD_STACK_SIZE)); + // // asm volatile("msr elr_el1, %0": : "r"(file_start)); + // // asm volatile("msr spsr_el1, %0" : : "r"(SPSR_EL1_VALUE)); + // // asm volatile("eret"); + // } + return 0; +} +int sys_exec(trap_frame* tf,const char* name, char *const argv[]) +{ + char *file_start = nullptr; + unsigned long filesize; + cpio_get_addr(file_start,&filesize); + char *new_start = my_malloc(filesize); + memcpy(new_start,file_start,filesize); + if(filesize!=0){ // file not found if filesize == 0 + tf->sp_el0 = (unsigned long)(get_current()->user_stack + THREAD_STACK_SIZE); + tf->elr_el1 = (unsigned long)new_start; + tf->spsr_el1 = 0; + // asm volatile("msr sp_el0, %0" : : "r"(get_current()->user_stack + THREAD_STACK_SIZE)); + // asm volatile("msr elr_el1, %0": : "r"(file_start)); + // asm volatile("msr spsr_el1, %0" : : "r"(SPSR_EL1_VALUE)); + // asm volatile("eret"); + } + return 0; +} +int sys_fork(trap_frame* tf) +{ + +} +void sys_exit(trap_frame* tf) +{ + +} +int sys_mbox_call(trap_frame* tf, unsigned char ch, unsigned int *mbox) +{ + +} +void sys_kill(trap_frame* tf, int pid) +{ + +} \ No newline at end of file diff --git a/user/Makefile b/user/Makefile new file mode 100644 index 000000000..4b4c99913 --- /dev/null +++ b/user/Makefile @@ -0,0 +1,43 @@ +SRCS = $(wildcard src/*.c) +OBJS = $(SRCS:.c=.o) +INCLUDE = -I ./include/ +ASMS = a +LINK = linker +CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles + +all: clean usr1.img run + +%.o: %.S + aarch64-linux-gnu-gcc $(CFLAGS) $(INCLUDE) -c $(ASMS).S -o $(ASMS).o -g + +%.o: %.c + aarch64-linux-gnu-gcc $(CFLAGS) $(INCLUDE) -c $< -o $@ -g + +usr1.img: $(ASMS).o $(OBJS) + aarch64-linux-gnu-ld -nostdlib -nostartfiles $(ASMS).o $(OBJS) -T $(LINK).ld -o usr1.elf + aarch64-linux-gnu-objcopy -O binary usr1.elf usr1.img + +clean: + rm usr1.elf usr1.img src/*.o *.o>/dev/null 2>/dev/null || true + +run: + qemu-system-aarch64 -M raspi3 -kernel usr1.img --display none -serial null -serial stdio -s -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + + +flash: + sudo dd if=usr1.img of=/dev/sdb + +screen: + sudo screen /dev/ttyUSB0 115200 + +ptty: + qemu-system-aarch64 -M raspi3 -kernel usr1.img -s -display none -serial null -serial pty -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +boot: + python3 uart_boot.py +screenb: + sudo screen /dev/pts/4 115200 +cpio: + cd rootfs + find . | cpio -o -H newc > ../initramfs.cpio + cd .. \ No newline at end of file diff --git a/user/a.S b/user/a.S new file mode 100644 index 000000000..bc6a78346 --- /dev/null +++ b/user/a.S @@ -0,0 +1,6 @@ +.section ".text" +.global _start + +_start: + bl main +// b exit diff --git a/user/bcm2710-rpi-3-b-plus.dtb b/user/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 0000000000000000000000000000000000000000..3934b3a26eb82fd65dbcdfca6f6916da427a3fae GIT binary patch literal 31790 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 literal 0 HcmV?d00001 diff --git a/user/include/allocator.h b/user/include/allocator.h new file mode 100644 index 000000000..1d4835b53 --- /dev/null +++ b/user/include/allocator.h @@ -0,0 +1,62 @@ +// #include "list.h" +#ifndef __ALLCATOR_H +#define __ALLCATOR_H + +#define ALLOCATOR_BASE 0x00000000 +#define ALLOCATOR_START ALLOCATOR_BASE +#define ALLOCATOR_END ALLOCATOR_BASE+ 0x3C000000 +#define BLOCK_SIZE 0x1000 +#define MAX_CONTIBLOCK_SIZE 12 + +typedef struct _frame_node +{ + int _block_exponent; + int _index; + struct _frame_node* next; + struct _frame_node* prev; + //struct list_head list; +}_frame_node; +//_frame_node* frame_freelist[MAX_CONTIBLOCK_SIZE+1]; +enum _frame_status{ + _R=-1, + _F=-2, + _X=-3 +}; +#define FRAME_ARRAY_SIZE (ALLOCATOR_END-ALLOCATOR_START)/BLOCK_SIZE +//int frame_array[FRAME_ARRAY_SIZE]; +void init_frame_freelist(); +void* get_freeframe_addr(unsigned int); +_frame_node* create_frame_node(int idx,int exp,_frame_node* next,_frame_node* prev); +void frame_list_addtail(int i,_frame_node *element); +void free(void* frame_addr); +int find_buddy(int,int); +void merge_buddy(); +void _F_frame_array(int idx, int exp); +void _X_frame_array(int idx, int exp); + + +typedef struct _frame_chunk_node +{ + void* addr; + struct _frame_chunk_node* next; + +}_frame_chunk_node; + +typedef struct _frame_array_node +{ + int size; + struct _frame_node* node; +}_frame_array_node; + +void* my_malloc(unsigned int); +void* get_freechunk_addr(int size); +void chunkNode_append(void* addr); +int getBestChunkSize(int require_size); +unsigned int frameAddrToIdx(void* frame_addr); +void list_freeChunkNode(); +void list_freeFrameNode(); +void memory_reserve(unsigned long long start, unsigned long long end); +void init_memory(); +void pop_frame(int idx); + +#endif diff --git a/user/include/cpio.h b/user/include/cpio.h new file mode 100644 index 000000000..faa71bb04 --- /dev/null +++ b/user/include/cpio.h @@ -0,0 +1,13 @@ +#ifndef _CPIO_HEADER_ +#define _CPIO_HEADER_ +#include "utils.h" +#include "dtb.h" +extern uint32_t* cpio_addr; +void cpio_ls(); +void cpio_cat(); +void cpio_get_addr(char* filedata,unsigned long* filesize); +//void* initramfs_callback(fdt_prop* prop,char * name,uint32_t len_prop); +void* initramfs_start_callback(fdt_prop* prop,char * name,uint32_t len_prop); +void* initramfs_end_callback(fdt_prop* prop,char * name,uint32_t len_prop); + +#endif \ No newline at end of file diff --git a/user/include/dtb.h b/user/include/dtb.h new file mode 100644 index 000000000..b3531056f --- /dev/null +++ b/user/include/dtb.h @@ -0,0 +1,39 @@ +#ifndef _DTB_HEADER +#define _DTB_HEADER + +#include "utils.h" +void* fdt_traverse(void* (*f)()); + +#define FDT_HEADER_MAGIC 0xd00dfeed + +#define FDT_BEGIN_NODE (0x00000001) +#define FDT_END_NODE (0x00000002) +#define FDT_PROPERTY (0x00000003) +#define FDT_NOP (0x00000004) +#define FDT_END (0x00000009) + + + +typedef struct fdt_header { + uint32_t magic; + uint32_t totalsize; + uint32_t off_dt_struct; + uint32_t off_dt_strings; + uint32_t off_mem_rsvmap; + uint32_t version; + uint32_t last_comp_version; + uint32_t boot_cpuid_phys; + uint32_t size_dt_strings; + uint32_t size_dt_struct; +}fdt_header; +typedef struct fdt_reserve_entry{ + uint64_t address; + uint64_t size; +}fdt_reserve_entry; +typedef struct fdt_prop +{ + uint32_t len; + uint32_t nameoff; +}fdt_prop; + +#endif \ No newline at end of file diff --git a/user/include/exception.h b/user/include/exception.h new file mode 100644 index 000000000..1c241eb88 --- /dev/null +++ b/user/include/exception.h @@ -0,0 +1,16 @@ +#define GPU_INTERRUPTS_ROUTING ((volatile uint32_t *)(0x4000000C)) +#define core0_interrupt_source ((volatile unsigned int*)(0x40000060)) + +#define INTERRUPT_PRIVILEGE_TIMER 1 +#define INTERRUPT_PRIVILEGE_READ 2 +#define INTERRUPT_PRIVILEGE_WRITE 3 + +void enable_interrupt(); +void disable_interrupt(); +void exception_entry(); +void irq_entry(); +void GPU_interrupt_handler(); +void Timer_interrupt_handler(); +void rx_interrupt_handler(); +void tx_interrupt_handler(); + diff --git a/user/include/list.h b/user/include/list.h new file mode 100644 index 000000000..d81475f9c --- /dev/null +++ b/user/include/list.h @@ -0,0 +1,45 @@ +#ifndef __TOOLS_LINUX_LIST_H +#define __TOOLS_LINUX_LIST_H +struct list_head { + struct list_head *next, *prev; +}; +#define WRITE_ONCE(var, val) \ + (*((volatile typeof(val) *)(&(var))) = (val)) +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + WRITE_ONCE(list->next, list); + list->prev = list; +} +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} +static inline void list_add(struct list_head *new, struct list_head *head){ + __list_add(new, head, head->next); +} + +static inline void list_add_tail(struct list_head *new, struct list_head *head){ + __list_add(new, head->prev, head); +} + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + // in include/linux/kernel.h + +/** +* container_of – cast a member of a structure out to the containing structure +* @ptr: the pointer to the member. +* @type: the type of the container struct this is embedded in. +* @member: the name of the member within the struct. +* +*/ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr – offsetof(type,member) );}) + +#endif \ No newline at end of file diff --git a/user/include/mailbox.h b/user/include/mailbox.h new file mode 100644 index 000000000..bcac0f93b --- /dev/null +++ b/user/include/mailbox.h @@ -0,0 +1,16 @@ +#include "mini_uart.h" + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +void get_board_revision(); +void get_ARM_memory(); +int mailbox_call(volatile unsigned int*,unsigned char); diff --git a/user/include/mini_uart.h b/user/include/mini_uart.h new file mode 100644 index 000000000..ff7e53ade --- /dev/null +++ b/user/include/mini_uart.h @@ -0,0 +1,75 @@ +#include "utils.h" +#define MMIO_BASE 0x3F000000 + +#define AUXENB ((volatile unsigned int*)(MMIO_BASE+0x00215004)) +#define AUX_MU_IO_REG ((volatile unsigned int*)(MMIO_BASE+0x00215040)) +#define AUX_MU_IER_REG ((volatile unsigned int*)(MMIO_BASE+0x00215044)) +#define AUX_MU_IIR_REG ((volatile unsigned int*)(MMIO_BASE+0x00215048)) +#define AUX_MU_LCR_REG ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) +#define AUX_MU_MCR_REG ((volatile unsigned int*)(MMIO_BASE+0x00215050)) +#define AUX_MU_LSR_REG ((volatile unsigned int*)(MMIO_BASE+0x00215054)) +#define AUX_MU_MSR_REG ((volatile unsigned int*)(MMIO_BASE+0x00215058)) +#define AUX_MU_SCRATCH_REG ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) +#define AUX_MU_CNTL_REG ((volatile unsigned int*)(MMIO_BASE+0x00215060)) +#define AUX_MU_STAT_REG ((volatile unsigned int*)(MMIO_BASE+0x00215064)) +#define AUX_MU_BAUD_REG ((volatile unsigned int*)(MMIO_BASE+0x00215068)) +void init_uart(); +char read_uart(); +int read_int(); +void writec_uart(unsigned int s); +void writes_uart(char *s); +void writes_n_uart(char *s, unsigned int size); +void writes_nl_uart(char *s); +void writehex_uart(unsigned int h,int newline); +void write_int_uart(unsigned int,bool newline); + +//void writeaddr_uart(unsigned int*); +#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) +#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) +#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008)) +#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C)) +#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010)) +#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014)) +#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C)) +#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020)) +#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028)) +#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034)) +#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038)) +#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040)) +#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044)) +#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064)) +#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068)) +#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098)) +#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C)) + +#define IRQ_ENABLE1 ((volatile unsigned *)(0x3F00B210)) +char uart_buf_read[1024]; +char uart_buf_write[1024]; +int uart_read_i_l; +int uart_read_i_r; +int uart_write_i_l; +int uart_write_i_r; +void init_uart_buf(); +void uart_buf_read_push(char c); +void uart_buf_write_push(char c); +void uart_buf_writes_push(char *s); +char uart_buf_read_pop(); +char uart_buf_write_pop(); +void busy_wait_writes(char *s,bool newline); +void busy_wait_writec(char s); +void busy_wait_writeint(int i,bool newline); +int is_empty_write(); +int is_empty_read(); + +#ifdef __DEBUG_LOG + static inline void writes_uart_debug(char* s, bool newline){ + while(*s){ + if(*s=='\n') + writec_uart('\r'); + writec_uart(*s++); + } + if(newline) + writes_uart("\r\n"); + } +#endif \ No newline at end of file diff --git a/user/include/reboot.h b/user/include/reboot.h new file mode 100644 index 000000000..59eb24fbf --- /dev/null +++ b/user/include/reboot.h @@ -0,0 +1,3 @@ +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); \ No newline at end of file diff --git a/user/include/shell.h b/user/include/shell.h new file mode 100644 index 000000000..7a25b85b5 --- /dev/null +++ b/user/include/shell.h @@ -0,0 +1,29 @@ +#include "mini_uart.h" +enum Action{ + help, + hello, + revision, + memory, + reboot, + ccreboot, + bootload, + version, + ls, + cat, + prog, + timeout, + mmalloc, + mfree, + mlistc, + mlistf, + mtest, + unknown +}; + +void read_command(); +void read_string(char**); +void handle_command(enum Action action, char *buffer); +int match_command(char *buffer); +int get_para_num(char* s); +char* get_para_by_num(int num,char *buffer); +void read_uart_buf(); \ No newline at end of file diff --git a/user/include/stdlib.h b/user/include/stdlib.h new file mode 100644 index 000000000..aed4fc27a --- /dev/null +++ b/user/include/stdlib.h @@ -0,0 +1,8 @@ +#ifndef __STDLIB_H +#define __STDLIB_H + +#include "utils.h" +void* simple_malloc(size_t size); + +void* get_smalloc_end(); +#endif \ No newline at end of file diff --git a/user/include/string.h b/user/include/string.h new file mode 100644 index 000000000..4ab34b4e0 --- /dev/null +++ b/user/include/string.h @@ -0,0 +1,5 @@ +#include "mini_uart.h" +int strcmp (const char *p1, const char *p2); +int strncmp(const char *s1, const char *s2, unsigned int n); +int strlen(char *s); +unsigned int str2int(char *s); \ No newline at end of file diff --git a/user/include/task.h b/user/include/task.h new file mode 100644 index 000000000..630ac14e3 --- /dev/null +++ b/user/include/task.h @@ -0,0 +1,16 @@ +#include "utils.h" +#include "mini_uart.h" +#include "stdlib.h" +struct taskq +{ + struct taskq *next; + void (*handler)(); + int privilege; +}; +typedef struct taskq taskq; +taskq *taskq_head; + +void init_taskq(); +void add_task(void (*handler)(),int privilege); +bool is_taskq_empty(); +void do_task(int* last_privilege); \ No newline at end of file diff --git a/user/include/timer.h b/user/include/timer.h new file mode 100644 index 000000000..a6cac5890 --- /dev/null +++ b/user/include/timer.h @@ -0,0 +1,22 @@ +#include "utils.h" +struct timer +{ + struct timer *next; + void (*callback)(char* s); + char *message; + unsigned int value; +}; +typedef struct timer timer; +timer *head; + +void init_timer(); +void add_timer(void (*callback)(char* s),char *message,int after); +bool timer_is_empty(); +void itr_timer_queue(); +void disable_timer_interrupt(); +void enable_timer_interrupt(); +bool is_timerq_empty(); +void set_expired_time(int ); +void get_current_time(unsigned long long *time_count,unsigned long long *time_freq); +timer* to_next_timer(); +timer* get_head_timer(); \ No newline at end of file diff --git a/user/include/usr_syscall.h b/user/include/usr_syscall.h new file mode 100644 index 000000000..ebf780eae --- /dev/null +++ b/user/include/usr_syscall.h @@ -0,0 +1,8 @@ +extern int getpid(); +extern unsigned int uart_read(char buf[],unsigned int size); +extern unsigned int uart_write(const char* name,unsigned int size); +extern int exec(const char* name, char *const argv[]); +extern int fork(); +extern void exit(); +extern int mbox_call(unsigned char ch, unsigned int *mbox); +extern void kill(int pid); \ No newline at end of file diff --git a/user/include/utils.h b/user/include/utils.h new file mode 100644 index 000000000..be320f56d --- /dev/null +++ b/user/include/utils.h @@ -0,0 +1,58 @@ +#ifndef __UTILS_H_ +#define __UTILS_H_ +#ifndef uint32_t + #define uint32_t unsigned int +#endif +#ifndef size_t + #define size_t unsigned long +#endif +#ifndef uint64_t + #define uint64_t unsigned long long +#endif + +#define TRUE (1==1) +#define FALSE (!TRUE) +#define null 0 +#define nullptr ((void *)0) +typedef int bool; + + + +uint32_t big2little(uint32_t); +unsigned long align_up(unsigned long n, unsigned long align); +/* Function to calculate x raised to the power y in O(logn)*/ +static inline int power(int x, unsigned int y) +{ + int temp; + if( y == 0) + return 1; + temp = power(x, y/2); + if (y%2 == 0) + return temp*temp; + else + return x*temp*temp; +} +static inline unsigned int findPreviousPowerOf2(unsigned int n) +{ + unsigned int x=n; + // do till only one bit is left + while (x & (x - 1)) { + + //writehex_uart(x&(x-1)); + x = x & (x - 1); // unset rightmost bit + } + + // `n` is now a power of two (less than or equal to `n`) + return x; +} +static inline unsigned int powOf2ToExponent(int n){ + int num = n; + int exp = -1; + while(num>0){ + num = num >> 1; + ++ exp; + } + return exp; +} + +#endif \ No newline at end of file diff --git a/user/initramfs.cpio b/user/initramfs.cpio new file mode 100644 index 0000000000000000000000000000000000000000..8f5c6ab590d5d3e974d1622c9e88f4f1581cfcdb GIT binary patch literal 3584 zcmeGe+e#Zz@Tlo+3&nyDLZRJAp=#}Nb`#B3Ddb{O1hJq#^etq~8iPqzvRg?jQa_>n zj($Mj`w68V;bWyAU}w%{FUJju`c&vackXBAoH;WSTA&4LQdnlLmPeR3YwHMUu4*SB zrPhj-t6Ams0^>&?u1D!|#7bb6qznSyq`!PVhkV;CGruYROzyApn%fsjVxLj|q#pg? z_mBEs%kYWeyL&;~>*;ew;0}U0&1iKzr_s^te$eO#8V9SI4y)@O>jS!^Q_bXzMzhHn z$TXRXf4m1`RNm_zG1)SsoKB#dj zZoJ#t(N0*+8~Pia4pH>+(wgEPu=Msay9K#)9Q}r z1$Dpu$ps#>c_o_VnpVGJq;g)ul|Vu)x|ZmFxf+`hBl1+XDh1yED3uLxRGwJ=@eS;^ zJFZEBgSM~3AEOK7?O=1Y=4tlkW0QyZl4l5Z)KF`i(51+SU{;iAoXvsT}aM--9 z;631y^Uv+QAMc#4C__c2L?hf>S)|v_5}%}es|M3 z677I4F{})^xD4G3g!dUPjmsVZF%9~*(s`c>zKm1aEHM7neW>8iD*NPy@a-XdBGcg! zoLI>kB2m4`VTM%>l}o~EA3ff{^X=EwxyJJ_5L>JFmdp~*Q`%gS^W?YK2YWx-jyqS* z#JemDdkF+vl4RIi`5_dup(aOE`@~$SVI7T8qvAKQDQi>0v1_#5ZLx6DYbA;a;~BBo f@A(lrY2vbE?rxVhHmlp&ta??-&HX3;^&9vLPBOV@ literal 0 HcmV?d00001 diff --git a/user/linker.ld b/user/linker.ld new file mode 100644 index 000000000..301372b6c --- /dev/null +++ b/user/linker.ld @@ -0,0 +1,19 @@ +SECTIONS +{ + . = 0x80000; + .text : { *(.text) } + + .rodata : { *(.rodata) } + .data : { *(.data) } + . = ALIGN(8); + bss_begin = .; + .bss : { *(.bss*) } + bss_end = .; + _end = .; + + _head_start_brk = .; + +} + +_boot_size = _end - _start; +_head_start_brk = _head_start_brk + 0x00100; \ No newline at end of file diff --git a/user/src/allocator.c b/user/src/allocator.c new file mode 100644 index 000000000..47fc172b5 --- /dev/null +++ b/user/src/allocator.c @@ -0,0 +1,469 @@ +#include "allocator.h" +#include "stdlib.h" +#include "mini_uart.h" +#include "cpio.h" +#ifndef __DEBUG_LOG +#define __DEBUG_LOG +#endif +int chunk_size_arr[] = { + // 0x1, //2^0 + // 0x2, //2^1 + 0x4, //2^2 + 0x8, //2^3 + 0x10, //2^4 + 0x20, //2^5 + 0x40, //2^6 + 0x80, //2^7 + 0x100, //2^8 + 0x200, //2^9 + 0x400, //2^10 + 0x800 //2^11 + }; +int chunk_arr_len = 10; +_frame_node* frame_freelist[MAX_CONTIBLOCK_SIZE+1]; +_frame_chunk_node* chunk_freelist[10]; + +// int frame_array[FRAME_ARRAY_SIZE] = {_F}; +_frame_array_node** frame_array;//[FRAME_ARRAY_SIZE]; +void init_frame_freelist(){ + for (int i = 0; i <= MAX_CONTIBLOCK_SIZE; i++) + { + frame_freelist[i]=nullptr; + } + // _F_frame_array(0,MAX_CONTIBLOCK_SIZE); + // frame_freelist[MAX_CONTIBLOCK_SIZE] = simple_malloc(sizeof(struct _frame_node)); + // frame_freelist[MAX_CONTIBLOCK_SIZE]->next = nullptr; + // frame_freelist[MAX_CONTIBLOCK_SIZE]->_block_exponent = MAX_CONTIBLOCK_SIZE; + // frame_freelist[MAX_CONTIBLOCK_SIZE]->_index = 0; + + for (int i = 0; i < chunk_arr_len; i++) + { + chunk_freelist[i] = nullptr; + } + + +} +void frame_list_addtail(int i,_frame_node *element){ + _frame_node* node = frame_freelist[i]; + if(node==nullptr){ + frame_freelist[i]=element; + } + else{ + while(node->next!=nullptr){ + node = node->next; + } + node->next = element; + element->prev=node; + } +} +void frame_list_addhead(int i,_frame_node *element){ + _frame_node* node = frame_freelist[i]; + if(node==nullptr){ + element->next=nullptr; + element->prev=nullptr; + frame_freelist[i]=element; + } + else{ + node->prev = element; + element->next = node; + element->prev = nullptr; + frame_freelist[i] = element; + } +} +_frame_node* create_frame_node(int idx,int exp,_frame_node* next,_frame_node* prev){ + _frame_node* new_node = simple_malloc(sizeof(_frame_node)); + new_node->next = next; + new_node->prev = prev; + new_node->_block_exponent = exp; + new_node->_index=idx; + frame_array[idx]->node = new_node; + return new_node; +} + +void _F_frame_array(int idx, int exp){ + frame_array[idx]->size = power(2,exp)*BLOCK_SIZE; + frame_array[idx]->node->_block_exponent = exp; + frame_array[idx]->node->_index=idx; + for (int i = idx + 1; i < idx+power(2,exp); i++) + { + frame_array[i]->size = _F; + } + +} + +void _X_frame_array(int idx, int exp){ + frame_array[idx]->size = -power(2,exp)*BLOCK_SIZE; + for (int i = idx+1; i < idx + power(2,exp); i++) + { + frame_array[i]->size = _X; + } +} + +void* get_freeframe_addr(unsigned int size){ + int i; + for (i = 0; i <= MAX_CONTIBLOCK_SIZE; i++) + { + if(frame_freelist[i]!=nullptr && BLOCK_SIZE*power(2,i)>=size){ + // writes_uart("Require "); + // write_int_uart(size,FALSE); + // writes_uart(" ,Min free block size: "); + // write_int_uart(BLOCK_SIZE *power(2,i),TRUE); + break; + } + } + if(frame_freelist[i]==nullptr) + { + // writes_uart("ALL FULL\r\n"); + return nullptr; + } + _frame_node* node; + while(BLOCK_SIZE*power(2,i)/2>=size && i>0){ + node = frame_freelist[i]; + // writes_uart("From "); + // write_int_uart(node->_index,FALSE); + // writes_uart(" - "); + // write_int_uart(node->_index+frame_array[node->_index]->size/BLOCK_SIZE-1,FALSE); + pop_frame(node->_index); + //frame_freelist[i] = frame_freelist[i]->next; + + i-=1; + + //_frame_node* new_node1 = create_frame_node(node->_index,i,nullptr,nullptr); + _frame_node* new_node1 = frame_array[node->_index]->node; + _F_frame_array(new_node1->_index,i); + frame_list_addtail(i,new_node1); + _frame_node* new_node2 = frame_array[node->_index+power(2,i)]->node; + //_frame_node* new_node2 = create_frame_node(node->_index+power(2,i),i,nullptr,nullptr); + _F_frame_array(new_node2->_index,i); + frame_list_addtail(i,new_node2); + + // writes_uart(" To "); + // write_int_uart(new_node1->_index,FALSE); + // writes_uart(" - "); + // write_int_uart(new_node1->_index+frame_array[new_node1->_index]->size/BLOCK_SIZE-1,FALSE); + // writes_uart(" And "); + // write_int_uart(new_node2->_index,FALSE); + // writes_uart(" - "); + // write_int_uart(new_node2->_index+frame_array[new_node2->_index]->size/BLOCK_SIZE-1,TRUE); + + } + node = frame_freelist[i]; + pop_frame(node->_index); + _X_frame_array(node->_index,node->_block_exponent); + + + // frame_freelist[i] = frame_freelist[i]->next; + + // writes_uart("Got block size: "); + // write_int_uart(-frame_array[node->_index]->size,TRUE); + unsigned long long freeframe_addr = ALLOCATOR_START + node->_index*BLOCK_SIZE; + return (void*)freeframe_addr; + +} + + +void pop_frame(int idx){ + int exp = powOf2ToExponent(frame_array[idx]->size / BLOCK_SIZE); + _frame_node* node = frame_array[idx]->node; + _frame_node** head = &frame_freelist[exp]; + if(*head==nullptr || node==nullptr) return; + + if(*head==node) *head = node->next; + if(node->next!=nullptr) node->next->prev = node->prev; + if(node->prev!=nullptr) node->prev->next = node->next; + + node->next=nullptr; + node->prev=nullptr; + + return; + + // if(node != nullptr){ + // if(node->prev!=nullptr){ + // node->prev->next = node->next; + // if(node->next != nullptr){ + // node->next->prev = node->prev; + // } + // } + // else{ + // if(frame_freelist[exp]->next!=nullptr){ + // frame_freelist[exp]->next->prev = nullptr; + // } + // frame_freelist[exp] = frame_freelist[exp]->next; + // } + // node->next=nullptr; + // node->prev=nullptr; + // } + +} +int find_buddy(int frame_idx, int frame_exp){ + // if(frame_exp==MAX_CONTIBLOCK_SIZE) + // return frame_idx; + int buddy_frame_idx = frame_idx^(power(2,frame_exp)); + return buddy_frame_idx; +} +void merge_buddy(int frame_idx, int buddy_idx){ + if( frame_idx == buddy_idx || + frame_array[frame_idx]->size != frame_array[buddy_idx]->size || + frame_array[frame_idx]->sizesizesize>= BLOCK_SIZE* power(2,MAX_CONTIBLOCK_SIZE) || + frame_array[buddy_idx]->size>= BLOCK_SIZE* power(2,MAX_CONTIBLOCK_SIZE)) + { + + // busy_wait_writes("Can't merge",TRUE); + // writes_uart("[*] No buddy can be merged. \r\n"); + // if( frame_array[frame_idx]->size >=BLOCK_SIZE && + // frame_array[frame_idx]->size <=power(2,MAX_CONTIBLOCK_SIZE)){ + + // int exp = powOf2ToExponent(frame_array[frame_idx]->size/BLOCK_SIZE); + // frame_array[frame_idx]->node->_block_exponent = exp; + // frame_array[frame_idx]->node->_index = frame_idx; + // frame_list_addhead(exp,frame_array[frame_idx]->node); + // } + + return; + } + else{ + int smaller_idx_frame = (frame_idx < buddy_idx)?frame_idx : buddy_idx; + int larger_idx_frame = (smaller_idx_frame == frame_idx)?buddy_idx : frame_idx; + // writes_uart("From "); + // write_int_uart(smaller_idx_frame,FALSE); + // writes_uart(" - "); + // write_int_uart(smaller_idx_frame+frame_array[smaller_idx_frame]->size/BLOCK_SIZE-1,FALSE); + // writes_uart(" And "); + // write_int_uart(larger_idx_frame,FALSE); + // writes_uart(" - "); + // write_int_uart(larger_idx_frame+frame_array[larger_idx_frame]->size/BLOCK_SIZE-1,FALSE); + + frame_array[smaller_idx_frame]->size+=frame_array[larger_idx_frame]->size; + frame_array[smaller_idx_frame]->node->_block_exponent+=1; + + pop_frame(larger_idx_frame); + frame_array[larger_idx_frame]->size = _F; + // _F_frame_array(larger_idx_frame,frame_array[larger_idx_frame]->node->_block_exponent); + + + // writes_uart(" To "); + // write_int_uart(smaller_idx_frame,FALSE); + // writes_uart(" - "); + // write_int_uart(smaller_idx_frame+frame_array[smaller_idx_frame]->size/BLOCK_SIZE-1,TRUE); + int new_buddy_idx = find_buddy(smaller_idx_frame,powOf2ToExponent(frame_array[smaller_idx_frame]->size/BLOCK_SIZE)); + // writes_uart("[*] merging "); + // write_int_uart(smaller_idx_frame,FALSE); + // writes_uart(" and "); + // write_int_uart(new_buddy_idx,TRUE); + merge_buddy(smaller_idx_frame,new_buddy_idx); + + } +} +void free(void* frame_addr){ + + int frame_idx = frameAddrToIdx(frame_addr);//(frame_addr-ALLOCATOR_START)/BLOCK_SIZE; + if(frame_array[frame_idx]->size>_X) + return; + else if( -frame_array[frame_idx]->size <= chunk_size_arr[chunk_arr_len-1]){ + chunkNode_append(frame_addr); + } + else{ + int frame_exp = powOf2ToExponent((-frame_array[frame_idx]->size)/BLOCK_SIZE); + // write_int_uart(frame_idx,TRUE); + // write_int_uart(frame_exp,TRUE); + _F_frame_array(frame_idx,frame_exp); + // write_int_uart(frame_idx,TRUE); + // write_int_uart(frame_exp,TRUE); + int buddy_frame_idx = find_buddy(frame_idx,frame_exp); + // write_int_uart(frame_idx,TRUE); + // write_int_uart(buddy_frame_idx,TRUE); + + merge_buddy(frame_idx,buddy_frame_idx); + frame_idx = (frame_idx > 0)?frame_idx : buddy_frame_idx; + //busy_wait_writeint(frame_array[buddy_frame_idx]->size,TRUE); + // while(frame_array[frame_idx]->size==_F) + // frame_idx--; + frame_exp = frame_array[frame_idx]->node->_block_exponent;//powOf2ToExponent(frame_array[frame_idx]->size/BLOCK_SIZE); + + // _frame_node* new_node = frame_array[frame_idx]->node; //create_frame_node(frame_idx,frame_exp,nullptr,nullptr); + // new_node->_index = frame_idx; + // new_node->_block_exponent = frame_exp; + // busy_wait_writeint(frame_idx,FALSE); + // busy_wait_writes(" ",FALSE); + + frame_list_addhead(frame_exp,frame_array[frame_idx]->node); + //list_freeFrameNode(); + } + +} + +unsigned int frameAddrToIdx(void* frame_addr){ + if(frame_addr < ALLOCATOR_START) + { + // writes_uart("Address not in the range of frame array\r\n"); + return null; + } + + return (unsigned int)((unsigned long long)frame_addr-ALLOCATOR_START)/BLOCK_SIZE; +} + +int getBestChunkSize(int require_size){ + for (int i = 0 ; i size; + int chunk_exp = powOf2ToExponent(chunk_size); + // _frame_chunk_node** headChunkNode = &chunk_freelist[chunk_exp-2]; + _frame_chunk_node* newChunkNode = simple_malloc(sizeof(_frame_chunk_node)); + newChunkNode->addr = addr; + newChunkNode->next = chunk_freelist[chunk_exp-2]; + chunk_freelist[chunk_exp-2] = newChunkNode; + // while(*headChunkNode) + // headChunkNode = &((*headChunkNode)->next); + // *headChunkNode = newChunkNode; +} +void list_freeChunkNode() +{ + for (int i = 0; i < chunk_arr_len; i++) + { + writes_uart("[>] Chunk "); + write_int_uart(chunk_size_arr[i],FALSE); + if(i<10) + writes_uart(" "); + writes_uart(" "); + _frame_chunk_node *node = chunk_freelist[i]; + int count=0; + while(node != nullptr){ + //writes_uart("["); + count++; + // writehex_uart((unsigned long long)node->addr,FALSE); + // writes_uart("]"); + node = node->next; + } + write_int_uart(count,TRUE); + //writes_uart("\r\n"); + } + +} +void list_freeFrameNode() +{ + for (int i = 0; i <= MAX_CONTIBLOCK_SIZE; i++) + { + // writes_uart("[>] Frame "); + // write_int_uart(BLOCK_SIZE*power(2,i),FALSE); + // writes_uart(" "); + busy_wait_writes("[>] Frame ",FALSE); + busy_wait_writeint(BLOCK_SIZE*power(2,i),FALSE); + busy_wait_writes(" ",FALSE); + _frame_node *node = frame_freelist[i]; + int count=0; + while(node != nullptr){ + //writes_uart("["); + count++; + // writehex_uart((unsigned long long)node->addr,FALSE); + // writes_uart("]"); + node = node->next; + } + busy_wait_writeint(count,TRUE); + // write_int_uart(count,TRUE); + } + +} +void* get_freechunk_addr(int size){ + //int chunk_size = getBestChunkSize(size); + int chunk_exp = powOf2ToExponent(size); + if(chunk_freelist[chunk_exp-2]==nullptr){ + // if no free chunk exist, cut a frame into chunks and return first chunk. + void* freeframe_addr = get_freeframe_addr(BLOCK_SIZE); + int frame_idx = frameAddrToIdx(freeframe_addr); + frame_array[frame_idx]->size = -size; + int chunk_count = BLOCK_SIZE / size; + + for (int i = 1; i < chunk_count; i++) + { + // _frame_chunk_node* newChunkNode= simple_malloc(sizeof(_frame_chunk_node)); + // newChunkNode->addr = freeframe_addr + i*size; + chunkNode_append(freeframe_addr + i*size); + // headChunkNode->next = newChunkNode; + // headChunkNode = headChunkNode->next; + } + // headChunkNode->next = nullptr; + return freeframe_addr; + } + else{ + void* chunk_addr = chunk_freelist[chunk_exp-2]->addr; + chunk_freelist[chunk_exp-2] = chunk_freelist[chunk_exp-2]->next; + return chunk_addr; + } + return nullptr; +} + +void* my_malloc(unsigned int size){ + void* malloc_addr = nullptr; + if(size<=chunk_size_arr[chunk_arr_len-1]){ + // writes_uart("Chunk malloc "); + + int chunk_size = getBestChunkSize(size); + // write_int_uart(chunk_size,TRUE); + malloc_addr = get_freechunk_addr(chunk_size); + + // unsigned int chunk_frame_idx = frameAddrToIdx(malloc_addr); + // frame_array[chunk_frame_idx] = chunk_size; + } + else{ + malloc_addr = get_freeframe_addr(size); + } + return malloc_addr; +} + +void memory_reserve(unsigned long long start, unsigned long long end){ + unsigned int start_idx = frameAddrToIdx((void*)start); + unsigned int end_idx = frameAddrToIdx((void*)end); + for (unsigned int i = start_idx; i <= end_idx; i++) + { + frame_array[i]->size = _R; + } + +} +void free_unreserved_memory(){ + for (long long i = FRAME_ARRAY_SIZE-1; i >=0 ; i--) + { + if(frame_array[i]->size!=_R) + { + + frame_array[i]->node = simple_malloc(sizeof(_frame_node)); + frame_array[i]->node->_block_exponent=0; + frame_array[i]->node->_index=i; + frame_array[i]->node->next=nullptr; + frame_array[i]->node->prev=nullptr; + free((void*)(ALLOCATOR_START+BLOCK_SIZE*i)); + } + } +} +void init_memory(){ + // writes_uart("Initializing memory...\r\n"); + init_frame_freelist(); + frame_array = (_frame_array_node**)simple_malloc(FRAME_ARRAY_SIZE*sizeof(_frame_array_node*)); + + for (unsigned int i = 0; i < FRAME_ARRAY_SIZE; i++) + { + frame_array[i] = (_frame_array_node*)simple_malloc(sizeof(_frame_array_node)); + frame_array[i]->size = -BLOCK_SIZE; + // frame_array[i]->node = simple_malloc(sizeof(_frame_node)); + // frame_array[i]->node->_block_exponent=0; + // frame_array[i]->node->_index=i; + // frame_array[i]->node->next=nullptr; + // frame_array[i]->node->prev=nullptr; + } + + memory_reserve(0,0x1000); //Spin tables for multicore boot + memory_reserve(0x80000,(unsigned long long)get_smalloc_end()); + memory_reserve((unsigned long long)fdt_traverse(initramfs_start_callback),(unsigned long long)fdt_traverse(initramfs_end_callback)); + free_unreserved_memory(); + +} \ No newline at end of file diff --git a/user/src/cpio.c b/user/src/cpio.c new file mode 100644 index 000000000..46099c8d4 --- /dev/null +++ b/user/src/cpio.c @@ -0,0 +1,193 @@ +#include "mini_uart.h" +#include "cpio.h" +#include "string.h" +#include "shell.h" +#include "utils.h" +#include "dtb.h" +#define CPIO_HEADER_MAGIC "070701" +#define CPIO_FOOTER_MAGIC "TRAILER!!!" +#define CPIO_ALIGNMENT 4 +uint32_t* cpio_addr; + //((volatile unsigned int*)(0x8000000)) +typedef struct { + char c_magic[6]; /* Magic header '070701'. */ + char c_ino[8]; /* "i-node" number. */ + char c_mode[8]; /* Permisions. */ + char c_uid[8]; /* User ID. */ + char c_gid[8]; /* Group ID. */ + char c_nlink[8]; /* Number of hard links. */ + char c_mtime[8]; /* Modification time. */ + char c_filesize[8]; /* File size. */ + char c_devmajor[8]; /* Major dev number. */ + char c_devminor[8]; /* Minor dev number. */ + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; /* Length of filename in bytes. */ + char c_check[8]; /* Checksum. */ +}cpio_newc_header; + +/* Transform the string type hex to unsigned long. */ +static unsigned long parse_hex_str(char *s, unsigned int max_len) +{ + unsigned long r = 0; + unsigned long i; + + for (i = 0; i < max_len; i++) { + r *= 16; + if (s[i] >= '0' && s[i] <= '9') { + r += s[i] - '0'; + } else if (s[i] >= 'a' && s[i] <= 'f') { + r += s[i] - 'a' + 10; + } else if (s[i] >= 'A' && s[i] <= 'F') { + r += s[i] - 'A' + 10; + } else { + return r; + } + continue; + } + return r; +} + +int cpio_parse_header(cpio_newc_header *archive, + char **filename, unsigned long *_filesize, char **data, + cpio_newc_header **next) +{ + unsigned long file_size; + unsigned long file_namesize; + char *file_data; + /* Ensure magic header exists. */ + if (strncmp(archive->c_magic, CPIO_HEADER_MAGIC, + sizeof(archive->c_magic)) != 0) + return -1; + + /* Get filename and file size. */ + file_size = parse_hex_str(archive->c_filesize, sizeof(archive->c_filesize)); + file_namesize = parse_hex_str(archive->c_namesize, sizeof(archive->c_namesize)); + + /* filename is in after header. */ + *filename = ((char *)archive) + sizeof(cpio_newc_header); + + /* Ensure filename is not the trailer indicating EOF. */ + if (strncmp(*filename, CPIO_FOOTER_MAGIC, sizeof(CPIO_FOOTER_MAGIC)) == 0) + return 1; + + file_data = (char *)align_up(((unsigned long)archive) + + sizeof(cpio_newc_header) + file_namesize, CPIO_ALIGNMENT); + *next = (cpio_newc_header *)align_up(((unsigned long)file_data) + file_size, CPIO_ALIGNMENT); + *data = file_data; + *_filesize = file_size; + return 0; +} +void cpio_ls(){ + //writehex_uart(cpio_addr); + cpio_newc_header* cnh = (cpio_newc_header*)cpio_addr; + cpio_newc_header* next_header; + char *filename; + char *filedata; + unsigned long filesize; + + while(1){ + if(cpio_parse_header(cnh,&filename,&filesize,&filedata,&next_header)!=0) + break; + writes_n_uart(filename,parse_hex_str(cnh->c_namesize,sizeof(cnh->c_namesize))); + writes_uart("\r\n"); + //writes_n_uart(filedata,parse_hex_str(cnh->c_filesize,sizeof(cnh->c_filesize))); + //writes_uart("\r\n"); + cnh = next_header; + + } + +} + +void cpio_cat(){ + cpio_newc_header* cnh = (cpio_newc_header*)cpio_addr; + cpio_newc_header* next_header; + char *filename; + char *filedata; + unsigned long filesize; + writes_uart("Filename: "); + char* read_name; + read_string(&read_name); + + while(1){ + int parse_result = cpio_parse_header(cnh,&filename,&filesize,&filedata,&next_header); + if(parse_result!=0){ + writes_uart("[!] File not found!\r\n"); + break; + } + if(strncmp(read_name,".",strlen(read_name))==0){ + writes_uart("[!] .: Is a directory\r\n"); + break; + } + else if(strncmp(read_name,filename,strlen(read_name))==0){ + writes_n_uart(filedata,parse_hex_str(cnh->c_filesize,sizeof(cnh->c_filesize))); + writes_uart("\r\n"); + break; + } + //writes_n_uart(filename,parse_hex_str(cnh->c_namesize,sizeof(cnh->c_namesize))); + //writes_uart("\r\n"); + // writes_n_uart(filedata,parse_hex_str(cnh->c_filesize,sizeof(cnh->c_filesize))); + // writes_uart("\r\n"); + cnh = next_header; + } +} + +void cpio_get_addr(char* filedata,unsigned long* filesize){ + cpio_newc_header* cnh = (cpio_newc_header*)cpio_addr; + cpio_newc_header* next_header; + char *filename; + // char *filedata; + // unsigned long filesize; + writes_uart("Filename: "); + char* read_name; + read_string(&read_name); + + while(1){ + if(cpio_parse_header(cnh,&filename,filesize,&filedata,&next_header)!=0){ + writes_uart("File not found!\r\n"); + *filesize=0; + break; + } + if(strncmp(read_name,".",strlen(read_name))==0){ + writes_uart(".: Is a directory\r\n"); + *filesize=0; + break; + } + else if(strncmp(read_name,filename,strlen(read_name))==0){ + // writes_n_uart(filedata,parse_hex_str(cnh->c_filesize,sizeof(cnh->c_filesize))); + // writes_uart("\r\n"); + // return (unsigned long long)filedata; + break; + } + //writes_n_uart(filename,parse_hex_str(cnh->c_namesize,sizeof(cnh->c_namesize))); + //writes_uart("\r\n"); + // writes_n_uart(filedata,parse_hex_str(cnh->c_filesize,sizeof(cnh->c_filesize))); + // writes_uart("\r\n"); + cnh = next_header; + } + // return 0; +} + +void* initramfs_start_callback(fdt_prop* prop,char * name,uint32_t len_prop){ + if(strncmp(name,"linux,initrd-start",18)==0){ // start address of initrd + writes_uart("Found target: \""); + writes_n_uart(name,18); + writes_uart("\" at target_cpio_addraddress "); + cpio_addr = (unsigned int*)((unsigned long)big2little(*((uint32_t*)(prop+1)))); + writehex_uart((unsigned long)cpio_addr,TRUE); + return (void*)cpio_addr; + } + return nullptr; +} +void* initramfs_end_callback(fdt_prop* prop,char * name,uint32_t len_prop){ + if(strncmp(name,"linux,initrd-end",16)==0) + { + writes_uart("Found target: \""); + writes_n_uart(name,18); + writes_uart("\" at address "); + void* target_cpio_addr = (void*)((unsigned long)big2little(*((uint32_t*)(prop+1)))); + writehex_uart((unsigned long)target_cpio_addr,TRUE); + return (void*)target_cpio_addr; + } + return nullptr; +} \ No newline at end of file diff --git a/user/src/dtb.c b/user/src/dtb.c new file mode 100644 index 000000000..c3f770ce6 --- /dev/null +++ b/user/src/dtb.c @@ -0,0 +1,78 @@ +#include "dtb.h" +#include "mini_uart.h" +#include "utils.h" +#include "string.h" +#include "cpio.h" + +void* fdt_traverse(void* (*f)()){ + register unsigned long dtb_reg asm ("x15"); + // writes_uart("Loaded dtb address: "); + // writehex_uart(dtb_reg,1); + fdt_header* header = (fdt_header*)dtb_reg; + + if(big2little(header->magic) != FDT_HEADER_MAGIC){ + writes_uart("Header magic failed\r\n"); + return nullptr; + } + + uint32_t* struct_start = (uint32_t*)((char*)header+ big2little(header->off_dt_struct)); + //uint32_t* string_start = (uint32_t*)((char*)header+ big2little(header->off_dt_strings)); + fdt_prop* prop; + char *name; + // writehex_uart(struct_start); + // writes_uart("\r\n"); + // writehex_uart(big2little(header->totalsize)); + // writes_uart("\r\n"); + + + while(1){ + + uint32_t tok = big2little(*struct_start); + switch (tok) + { + case FDT_BEGIN_NODE: + //writes_uart("Begin node\r\n"); + + name = (char*)(struct_start+1); + // followed node name + + uint32_t name_size = strlen(name); + + struct_start+=align_up(name_size+1,4)/sizeof(uint32_t); + // name have zero padding, aligned up to multiple of 4. + + break; + case FDT_END_NODE: + // writes_uart("End node\r\n"); + break; + case FDT_PROPERTY: + // // writes_uart("PROP\r\n"); + prop = (fdt_prop*)(struct_start+1); + // // followed property information + + name = ((char*)header+big2little(header->off_dt_strings)+ big2little(prop->nameoff)); + + void* result = f(prop,name,big2little(prop->len)); + if(result != nullptr) + return result; + struct_start+=(sizeof(fdt_prop)+align_up(big2little(prop->len),4))/sizeof(uint32_t); + // add size of property name length and name. + // property name have zero padding, up to multiple of 4. + break; + case FDT_END: + //writes_uart("End\r\n"); + return nullptr; + break; + case FDT_NOP: + //writes_uart("NOP\r\n"); + //struct_start+= 1; + break; + default: + //struct_start+= 1; + //writehex_uart(tok); + break; + } + struct_start+=1; + } + return nullptr; +} \ No newline at end of file diff --git a/user/src/exception.c b/user/src/exception.c new file mode 100644 index 000000000..4b4926754 --- /dev/null +++ b/user/src/exception.c @@ -0,0 +1,175 @@ +#include "mini_uart.h" +#include "exception.h" +#include "string.h" +#include "timer.h" +#include "task.h" + +void enable_interrupt(){ + asm volatile( + "msr DAIFClr, 0xf" + ); +} + +void disable_interrupt(){ + asm volatile( + "msr DAIFSet, 0xf" + ); +} + + +void exception_entry(){ + busy_wait_writes("EXCEPTION ENTRY",TRUE); + // spsr_el1, elr_el1, and esr_el1 + unsigned long long reg_spsr_el1, reg_elr_el1,reg_esr_el1; + asm volatile( + "mrs %0,spsr_el1\n\t" + "mrs %1,elr_el1\n\t" + "mrs %2,esr_el1\n\t" + : "=r" (reg_spsr_el1), + "=r" (reg_elr_el1), + "=r" (reg_esr_el1) + ); + writes_uart("Exception\r\n"); + writes_uart("spsr_el1: "); + writehex_uart(reg_spsr_el1,1); + writes_uart("reg_elr_el1: "); + writehex_uart(reg_elr_el1,1); + writes_uart("reg_esr_el1: "); + writehex_uart(reg_esr_el1,1); + return; +} + +int curr_task_privilege = 100; +void irq_entry(){ + + // writes_uart("IRQ entry\r\n"); + // writes_uart("Interrupt Source:"); + // writehex_uart(*core0_interrupt_source,1); + if(*core0_interrupt_source & (1<<8)){ //GPU interrupt + //*AUX_MU_IER_REG = 0; + // add_task(GPU_interrupt_handler,0); + /* AUX_MU_IIR_REG bits 2:1 + 00 : No interrupts + 01 : Transmit holding register empty + 10 : Receiver holds valid byte + 11 : */ + + if((*AUX_MU_IIR_REG & 0b0010)) //write interrupt + { + // disable_interrupt(); + *AUX_MU_IER_REG &= ~2; //disable write interrupt + add_task(tx_interrupt_handler,INTERRUPT_PRIVILEGE_WRITE); + if(curr_task_privilegecallback(h->message); + // writes_uart("DEBUG:"); + // writes_nl_uart(h->message); + if(h->next==nullptr){ + writes_uart("next timer is not exist.\r\n"); + h = to_next_timer(); + disable_timer_interrupt(); + } + else{ + h = to_next_timer(); + writes_uart("Found next timer in "); + write_int_uart(h->value,TRUE); + unsigned long long time_count=0; + unsigned long long time_freq=0; + get_current_time(&time_count,&time_freq); + set_expired_time(h->value - time_count/time_freq); + enable_timer_interrupt(); + } + } + +} \ No newline at end of file diff --git a/user/src/mailbox.c b/user/src/mailbox.c new file mode 100644 index 000000000..4c0e27891 --- /dev/null +++ b/user/src/mailbox.c @@ -0,0 +1,125 @@ +/* +The mailbox mechanism consists of three components mailbox registers, channels, and messages. +mailbox0: CPU(ARM) read from GPU(VideoCoreIV), +mailbox0 status: check GPU status. +mailbox1: CPU write to GPU. + +Mailbox 0 defines the following channels: + +0: Power management +1: Framebuffer +2: Virtual UART +3: VCHIQ +4: LEDs +5: Buttons +6: Touch screen +7: +8: Property tags (ARM -> VC) +9: Property tags (VC -> ARM) +*/ +#include "mailbox.h" +// mailbox address and flags + +//#define MMIO_BASE 0x3F000000 +#define MAILBOX_BASE MMIO_BASE + 0xb880 +// mailbox0: CPU read from GPU +#define MAILBOX0_RW ((volatile unsigned int*)(MAILBOX_BASE+0x0)) //read write register. +#define MAILBOX0_POLL ((volatile unsigned int*)(MAILBOX_BASE+0x10)) +#define MAILBOX0_SENDER ((volatile unsigned int*)(MAILBOX_BASE+0x14)) +#define MAILBOX0_STATUS ((volatile unsigned int*)(MAILBOX_BASE+0x18)) +#define MAILBOX0_CONFIG ((volatile unsigned int*)(MAILBOX_BASE+0x1C)) +// mailbox1: CPU write to GPU +#define MAILBOX1_RW ((volatile unsigned int*)(MAILBOX_BASE+0x20)) +#define MAILBOX1_POLL ((volatile unsigned int*)(MAILBOX_BASE+0x30)) +#define MAILBOX1_SENDER ((volatile unsigned int*)(MAILBOX_BASE+0x34)) +#define MAILBOX1_STATUS ((volatile unsigned int*)(MAILBOX_BASE+0x38)) +#define MAILBOX1_CONFIG ((volatile unsigned int*)(MAILBOX_BASE+0x3C)) + + +#define MBOX_REQUEST 0 + +#define MAILBOX_RESPONSE 0x80000000 +#define MAILBOX_FULL 0x80000000 +#define MAILBOX_EMPTY 0x40000000 +#define TAG_REQUEST_CODE 0x00000000 +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 + +#define END_TAG 0x00000000 + +int mailbox_call(volatile unsigned int* mailbox,unsigned char ch){ + // combine mailbox message address(upper 28 bits) and channel number(4bits). + unsigned int r = (unsigned int)(((unsigned long)mailbox) & (~0xF)) | ch;//(ch & 0xF); + // wait for the mailbox1 not full. + do{asm volatile("nop");}while(*MAILBOX1_STATUS & MAILBOX_FULL); + + // write the message address(28 bits) and channel number (4bits) to mailbox write register. + *MAILBOX1_RW = r; + + while(1) { + // is there any response in mailbox + while(*MAILBOX0_STATUS & MAILBOX_EMPTY){asm volatile("nop");}; + if(r == *MAILBOX0_RW) + { + return mailbox[1]==MAILBOX_RESPONSE; // check if it is the response, if failed: 0x80000001 + } + } + return 0; + +} + +//board revision number: identify what model of pi it is. +void get_board_revision(){ + //unsigned int mailbox[7]; + volatile unsigned int __attribute__((aligned(16))) mailbox[7]; + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = MBOX_REQUEST; + // 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; + + if(mailbox_call(mailbox,MBOX_CH_PROP)) // message passing procedure call, you should implement it following the 6 steps provided above. + { + writes_uart("Get Board revision: "); + writehex_uart(mailbox[5],1); // it should be 0xa020d3 for rpi3 b+ + } + else{ + writes_uart("Get Board revision failed!\r\n"); + } + +} + +/*Get ARM memory +Tag: 0x00010005 +Request: +Length: 0 +Response: +Length: 8 +Value: +u32: base address in bytes +u32: size in bytes +Future formats may specify multiple base+size combinations.*/ + +void get_ARM_memory(){ + volatile unsigned int __attribute__((aligned(16))) mailbox[8]; + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = MBOX_REQUEST; + // 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; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; // value buffer + // tags end + mailbox[7] = END_TAG; + + mailbox_call(mailbox,MBOX_CH_PROP); // message passing procedure call, you should implement it following the 6 steps provided above. + writes_uart("Get ARM Memory address: "); + writehex_uart(mailbox[5],1); + writes_uart("Get ARM Memory size: "); + writehex_uart(mailbox[6],1); +} diff --git a/user/src/main.c b/user/src/main.c new file mode 100644 index 000000000..ed9471ee9 --- /dev/null +++ b/user/src/main.c @@ -0,0 +1,38 @@ +#include "mini_uart.h" +// #include "usr_syscall.h" +// void fork_test(){ +// printf("\nFork Test, pid %d\n", get_pid()); +// int cnt = 1; +// int ret = 0; +// if ((ret = fork()) == 0) { // child +// long long cur_sp; +// asm volatile("mov %0, sp" : "=r"(cur_sp)); +// printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); +// ++cnt; + +// if ((ret = fork()) != 0){ +// asm volatile("mov %0, sp" : "=r"(cur_sp)); +// printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); +// } +// else{ +// while (cnt < 5) { +// asm volatile("mov %0, sp" : "=r"(cur_sp)); +// printf("second child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); +// delay(1000000); +// ++cnt; +// } +// } +// exit(); +// } +// else { +// printf("parent here, pid %d, child %d\n", get_pid(), ret); +// } +// } +int main(){ + while(1) + { + // busy_wait_writes("HI, here is user.\r\n",FALSE); + } + + return 0; +} \ No newline at end of file diff --git a/user/src/mini_uart.c b/user/src/mini_uart.c new file mode 100644 index 000000000..9c074dd94 --- /dev/null +++ b/user/src/mini_uart.c @@ -0,0 +1,317 @@ +#include "mini_uart.h" +#include "stdlib.h" +#include "exception.h" +#include "string.h" +void init_uart(){ + *AUXENB |=1; // enable mini UART, then mini uart register can be accessed. + *AUX_MU_CNTL_REG = 0; // Disable transmitter and receiver during configuration. + *AUX_MU_IER_REG = 0; // 0: Disable interrupt, 1: enable interrupt + *AUX_MU_LCR_REG = 3; // set data size to 8 bits. + *AUX_MU_MCR_REG = 0; // no flow control + *AUX_MU_BAUD_REG = 270; // 250MHz / (115200 + 1)*8 + *AUX_MU_IIR_REG = 6; // No FIFO + *AUX_MU_CNTL_REG = 3; // Enable the transmitter and receiver. + + + + /* configure gpio*/ + + register unsigned int tmp_reg; // hope the register can be stored in CPU register. + // GPFSELn: define the operation of the GPIO pins + // GPFSEL1: FSEL10(0~2) ~ FSEL19(27~29) + 30,31 reserved + /* FSEL: 3bits, in GPFSELn + + 000 = GPIO Pin 9 is an input + 001 = GPIO Pin 9 is an output + 100 = GPIO Pin 9 takes alternate function 0 + 101 = GPIO Pin 9 takes alternate function 1 + 110 = GPIO Pin 9 takes alternate function 2 + 111 = GPIO Pin 9 takes alternate function 3 + 011 = GPIO Pin 9 takes alternate function 4 + 010 = GPIO Pin 9 takes alternate function 5 + */ + tmp_reg = *GPFSEL1; // load the GPIO Function Select Registers SEL1 to tmp_reg. + tmp_reg &= 0xfffc0fff; // use a mask to clear the 12~17 bits(FSEL14 & FSEL15) of the register. + // FSEL14: 12~14bits. + // FSEL15: 15~17bits. + tmp_reg |= (0b010 << 12) | (0b010 << 15); // to make the 12~14bits and 15~17 bits of the register to b010, takes alternate function 5. + *GPFSEL1 = tmp_reg; + /* + 1. Write to GPPUD to set the required control signal (i.e. Pull-up or Pull-Down or neither + to remove the current Pull-up/down) + 2. Wait 150 cycles – this provides the required set-up time for the control signal + 3. Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to + modify – NOTE only the pads which receive a clock will be modified, all others will + retain their previous state. + 4. Wait 150 cycles – this provides the required hold time for the control signal + 5. Write to GPPUD to remove the control signal + 6. Write to GPPUDCLK0/1 to remove the clock + */ + *GPPUD = 0; // disable pull-up/down tmp_regregister, allow gpio pins use alternate function, not only basic input-output. + tmp_reg = 150; + while(tmp_reg--){ + asm volatile("nop"); // wait 150 cycles. + } + *GPPUDCLK0 = (1<<14)|(1<<15); // assert clock on 14 and 15, because the gpio state would be modified. + tmp_reg = 150; + while(tmp_reg--){ + asm volatile("nop"); // wait 150 cycles. + } + + *GPPUDCLK0 = 0; // remove the clock. + *AUX_MU_CNTL_REG = 3; // enable tx and rx after configuration. + +} +char read_uart(){ + char r; + while(!(*AUX_MU_LSR_REG & 0x01)){ + asm volatile("nop"); + } + r = (char)(*AUX_MU_IO_REG); + return r=='\r'?'\n':r; +} + +void write_int_uart(unsigned int s, bool newline){ + if(s==0){ + writec_uart('0'); + if(newline) + writes_uart("\r\n"); + return; + } + char a[128]; + int i=0,n=s; + while(n!=0){ + a[i] = '0' + n%10; + n/=10; + i++; + } + a[i]='\0'; + for (int j = i-1; j>=0; j--) + { + writec_uart(a[j]); + /* code */ + } + + if(newline) + writes_uart("\r\n"); +} + +void writec_uart(unsigned int s){ + // unsigned int c = s; + // while(!(*AUX_MU_LSR_REG & 0x20)) asm volatile("nop"); + // *AUX_MU_IO_REG = c; + uart_buf_write_push(s); +} + +void writes_n_uart(char *s, unsigned int size){ + for(int i=0;i=0;c-=4) { + + n=(h>>c)&(0xF); // n = 1,2,3....th byte of h from left to right. + + n+=n>9?0x37:0x30; // int 0~9 -> char '0'~'9', 10~15 -> 'A'~'F' + writec_uart(n); + } + if(newline==1){ + writes_uart("\r\n"); + } +} +void writeint_uart(unsigned int i){ + int iter=0; + char buffer[100]; + int k=i; + while(1){ + if(k==0) + { + buffer[iter]=k%10; + break; + }else{ + buffer[iter++] = k%10; + k = k/10; + } + } + writes_uart(buffer); + writes_uart("\r\n"); +} +// void writeaddr_uart(unsigned int* addrh){ + +// writes_uart("0x"); +// unsigned int n; +// int c; +// for(c=28;c>=0;c-=4) { + +// n=(h>>c)&(0xF); // n = 1,2,3....th byte of h from left to right. + +// n+=n>9?0x37:0x30; // int 0~9 -> char '0'~'9', 10~15 -> 'A'~'F' +// writec_uart(n); +// } +// } +void init_uart_buf(){ + uart_read_i_l=0; + uart_read_i_r=0; + uart_write_i_l=0; + uart_write_i_r=0; + //uart_buf_read = simple_malloc(2560); + uart_buf_read[0]='\0'; + // uart_buf_write = simple_malloc(2560); + uart_buf_write[0] = '\0'; +} +void uart_buf_read_push(char c){ + disable_interrupt(); + if(uart_read_i_r<1024) + { + uart_buf_read[uart_read_i_r++] = c; + uart_read_i_r= uart_read_i_r % 1024; + // uart_buf_read[uart_read_i_r] = '\0'; + } + enable_interrupt(); +} +void uart_buf_write_push(char c){ + disable_interrupt(); + if(uart_write_i_r<1024) + { + uart_buf_write[uart_write_i_r++] = c; + uart_write_i_r = uart_write_i_r % 1024; + // uart_buf_write[uart_write_i_r] = '\0'; + + // if(*AUX_MU_IER_REG != 3) + // *AUX_MU_IER_REG = 3; + if(!(*AUX_MU_IER_REG & 2)) + *AUX_MU_IER_REG |= 2; + } + enable_interrupt(); +} +void uart_buf_writes_push(char *s){ + // writehex_uart(strlen(s),1); + // writes_uart(s); + // *AUX_MU_IER_REG = 1; + + for (int i = 0; i < strlen(s); i++) + { + /* code */ + if(s[i]=='\n') + uart_buf_write_push('\r'); + uart_buf_write_push(s[i]); + } + + // while(*s){ + // if(*s=='\n') + // uart_buf_write_push('\r'); + // uart_buf_write_push(*s++); + // } + // *AUX_MU_IER_REG = 3; + +} + +char uart_buf_read_pop(){ + char c='0'; + if(uart_read_i_l != uart_read_i_r){ + + c = uart_buf_read[uart_read_i_l++]; + uart_read_i_l=uart_read_i_l%1024; + + } + return c; +} +char uart_buf_write_pop(){ + char c='0'; + if(uart_write_i_l != uart_write_i_r){ + + c = uart_buf_write[uart_write_i_l++]; + uart_write_i_l= uart_write_i_l % 1024; + + } + return c; +} + +int is_empty_write(){ + if(uart_write_i_l==uart_write_i_r){ + return 1; // return 1 if empty. + }else{ + return 0; // return 0 if not empty. + } +} +int is_empty_read(){ + if(uart_read_i_l==uart_read_i_r){ + return 1; // return 1 if empty. + }else{ + return 0; // return 0 if not empty. + } +} +void busy_wait_writec(char s){ + unsigned int c = s; + while(!(*AUX_MU_LSR_REG & 0x20)) asm volatile("nop"); + *AUX_MU_IO_REG = c; +} +void busy_wait_writes(char *s,bool newline){ + while(*s){ + if(*s=='\n') + busy_wait_writec('\r'); + busy_wait_writec(*s++); + } + if(newline){ + busy_wait_writec('\r'); + busy_wait_writec('\n'); + } + +} +void busy_wait_writeint(int s,bool newline){ + if(s==0){ + busy_wait_writec('0'); + if(newline) + busy_wait_writes("\r\n",FALSE); + return; + } + char a[128]; + int i=0,n=s; + while(n!=0){ + a[i] = '0' + n%10; + n/=10; + i++; + } + a[i]='\0'; + for (int j = i-1; j>=0; j--) + { + busy_wait_writec(a[j]); + /* code */ + } + + if(newline) + busy_wait_writes("\r\n",FALSE); +} \ No newline at end of file diff --git a/user/src/reboot.c b/user/src/reboot.c new file mode 100644 index 000000000..0346e57c1 --- /dev/null +++ b/user/src/reboot.c @@ -0,0 +1,20 @@ +#include "reboot.h" +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} +//500 ms =2000 ticks. + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/user/src/shell.c b/user/src/shell.c new file mode 100644 index 000000000..5e307df2c --- /dev/null +++ b/user/src/shell.c @@ -0,0 +1,420 @@ +#include "shell.h" +#include "string.h" +#include "mailbox.h" +#include "reboot.h" +#include "cpio.h" +#include "stdlib.h" +#include "timer.h" +#include "allocator.h" +int match_command(char *buffer){ + + if(strcmp(buffer,"help")==0){ + return help; + } + else if(strcmp(buffer,"hello")==0){ + return hello; + }else if(strcmp(buffer,"revision")==0){ + return revision; + }else if(strcmp(buffer,"memory")==0){ + return memory; + } + else if(strcmp(buffer,"reboot")==0){ + return reboot; + } + else if(strcmp(buffer,"ccreboot")==0){ + return ccreboot; + } + else if(strcmp(buffer,"version")==0){ + return version; + } + else if(strcmp(buffer,"ls")==0){ + return ls; + } + else if(strcmp(buffer,"cat")==0){ + return cat; + } + else if(strcmp(buffer,"prog")==0){ + return prog; + } + else if(strncmp(buffer,"timeout",strlen("timeout"))==0){ + return timeout; + } + else if(strncmp(buffer,"mmalloc",strlen("mmalloc"))==0){ + return mmalloc; + } + else if(strncmp(buffer,"mfree",strlen("mfree"))==0){ + return mfree; + } + else if(strncmp(buffer,"mlistc",strlen("mlistc"))==0){ + return mlistc; + } + else if(strncmp(buffer,"mlistf",strlen("mlistf"))==0){ + return mlistf; + } + else if(strncmp(buffer,"mtest",strlen("mtest"))==0){ + return mtest; + } + else{ + return unknown; + } +} + + +void read_command(){ + char buffer[512]; + int count=0; + int action = 0; + writes_uart("# "); + while(1){ + do{asm volatile("nop");}while(is_empty_read()); + char c = uart_buf_read_pop(); + // writehex_uart(uart_write_i_l,0); + // writehex_uart(uart_write_i_r,1); + if(c!='\n' && count<256){ + if(c=='\x7f'){ + if(count >0 ){ + uart_buf_write_push('\b'); + uart_buf_write_push(' '); + uart_buf_write_push('\b'); + buffer[--count]='\0'; + } + + } + else if(c>=0 && c<=127){ // only accept the value is inside 0~127(ASCII). + uart_buf_write_push(c); + buffer[count++] = c; + buffer[count] = '\0'; + } + + }else{ + uart_buf_write_push('\r'); + uart_buf_write_push('\n'); + buffer[count]='\0'; + if(buffer[0] != '\0'){ + action = match_command(buffer); + handle_command(action, buffer); + } + break; + } + + } + return; +} + +void read_string(char **s){ + char *buffer= simple_malloc(256); + int count=0; + while(1){ + do{asm volatile("nop");}while(is_empty_read()); + char c = uart_buf_read_pop(); + if(c!='\n' && count<256){ + if(c=='\x7f'){ + if(count >0 ){ + writec_uart('\b'); + writec_uart(' '); + writec_uart('\b'); + buffer[--count]='\0'; + } + + } + else if(c>=0 && c<=127){ // only accept the value is inside 0~127(ASCII). + writec_uart(c); + buffer[count++] = c; + } + + }else{ + writec_uart('\r'); + writec_uart('\n'); + + buffer[count]='\0'; + if(buffer[0] != '\0'){ + *s = buffer; + return; + } + break; + } + + } + return; +} +int read_int(){ + char* s; + read_string(&s); + int n=0; + for (int i = 0; i < strlen(s); i++) + { + char c = s[i]; + n = n *10; + n += c-'0'; + /* code */ + } + return n; + +} + +int get_para_num(char *s){ + int n=0; + for (int i = 0; i < strlen(s); i++) + { + if(s[i]==' ') n++; + } + return n; +} + +char* get_para_by_num(int num,char *buffer){ + int space_num=0; + int start=0,end=0; + for (int i = 0; i < strlen(buffer); i++) + { + if(buffer[i]==' ') + { + space_num++; + if(space_num==num){ + start = i+1; + } + else if(space_num==num+1){ + end = i; + } + } + } + if(space_num 0) + { + u1 = (unsigned char) *s1++; + u2 = (unsigned char) *s2++; + if (u1 != u2) + return u1 - u2; + if (u1 == '\0') + return 0; + } + return 0; +} + + +int strlen(char *s){ + unsigned int count = 0; + char *tmps = s; + while(*tmps!='\0') + { + count++; + tmps++; + } + return count; +} + +unsigned int str2int(char *s){ + unsigned int n=0; + //busy_wait_writes("Enter str2int",TRUE); + for (int i = 0; i < strlen(s); i++) + { + if(s[i]<'0' || s[i]>'9') + return n; + //busy_wait_writes("Lopping str2int",TRUE); + n*=10; + n+=s[i]-'0'; + } + //busy_wait_writes("Return str2int",TRUE); + return n; +} \ No newline at end of file diff --git a/user/src/task.c b/user/src/task.c new file mode 100644 index 000000000..6ef02e953 --- /dev/null +++ b/user/src/task.c @@ -0,0 +1,61 @@ +#include "task.h" +#include "exception.h" +#include "timer.h" +void init_taskq(){ + taskq_head = nullptr; + return; +} +void add_task(void (*handler)(),int privilege){ + taskq *node = (taskq*)simple_malloc(sizeof(taskq)); + node->handler = handler; + node->privilege = privilege; + node->next = nullptr; + if(taskq_head==nullptr){ + taskq_head = node; + } + else{ + // taskq* newNode = (taskq*)simple_malloc(sizeof(taskq)); + + if(privilege < taskq_head->privilege){ + node->next = taskq_head; + taskq_head = node; + // set_expired_time(after); + } + else{ + taskq *itr_node = taskq_head; + while(itr_node->next!=null){ + if(itr_node->next->privilege>=privilege){ + break; + } + itr_node = itr_node->next; + } + node->next = itr_node->next; + itr_node->next = node; + } + } + return; +} +void do_task(int* curr_task_privilege){ + while(!is_taskq_empty()){ + disable_interrupt(); + + taskq *node = taskq_head; + int last_task_privilege = *curr_task_privilege; + *curr_task_privilege = node->privilege; + taskq_head = taskq_head->next; + + enable_interrupt(); + + node->handler(); + disable_interrupt(); + *curr_task_privilege = last_task_privilege; + enable_interrupt(); + } +} + +bool is_taskq_empty(){ + if(taskq_head == nullptr) + return TRUE; + else + return FALSE; +} \ No newline at end of file diff --git a/user/src/timer.c b/user/src/timer.c new file mode 100644 index 000000000..0fa74a870 --- /dev/null +++ b/user/src/timer.c @@ -0,0 +1,156 @@ +#include "timer.h" +#include "mini_uart.h" +#include "stdlib.h" +#include "shell.h" +#include "string.h" +#define CORE0_TIMER_IRQ_CTRL ((volatile unsigned int*)(0x40000040)) +void init_timer(){ + // head->next = nullptr; + // head->value = null; + + head = nullptr; + disable_timer_interrupt(); + // writes_uart("Core timer: "); + //writehex_uart(*CORE0_TIMER_IRQ_CTRL,1); +} +void get_current_time(unsigned long long *time_count,unsigned long long *time_freq){ + unsigned long long _time_count=0; + unsigned long long _time_freq=0; + asm volatile( + "mrs %0,cntpct_el0\n\t" + "mrs %1,cntfrq_el0\n\t" + :"=r" (_time_count), + "=r" (_time_freq) + ); + *time_count = _time_count; + *time_freq = _time_freq; +} +void set_expired_time(int after){ + unsigned long long time_count=0; + unsigned long long time_freq=0; + get_current_time(&time_count,&time_freq); + // write_int_uart((int)(time_count/time_freq),1); + unsigned long long time_expired = time_freq*after; + // write_int_uart(time_expired,1); + asm volatile( + "msr cntp_tval_el0, %0\n\t" + ::"r" (time_expired) + ); + return; +} + +void add_timer(void (*callback)(char* s),char *message,int after){ + //busy_wait_writes("Enter add timer",TRUE); + timer* node ; + unsigned long long time_count=0; + unsigned long long time_freq=0; + // char* tmp_message = simple_malloc(strlen(message)); + // for (int i = 0; i < strlen(message); i++) + // { + // tmp_message[i] = message[i]; + // } + + if(head==nullptr){ + writes_nl_uart("Adding new timer to empty timer queue"); + node = (timer*)simple_malloc(sizeof(timer)); + node->next=nullptr; + get_current_time(&time_count,&time_freq); + node->value=(time_count/time_freq) + after; + node->message = message; + node->callback = callback; + head = node; + set_expired_time(after); + enable_timer_interrupt(); + }else{ + // busy_wait_writes("ADDing new timer busy2",TRUE); + writes_nl_uart("Adding new timer to non-empty queue"); + timer* newNode = (timer*)simple_malloc(sizeof(timer)); + get_current_time(&time_count,&time_freq); + newNode->value=(time_count/time_freq) + after; + newNode->message=message; + newNode->callback = callback; + if((time_count/time_freq + after) < head->value){ + newNode->next = head; + head = newNode; + set_expired_time(after); + } + else{ + timer *node = head; + get_current_time(&time_count,&time_freq); + while(node->next!=null){ + if(node->next->value>=(time_count/time_freq + after)){ + break; + } + node = node->next; + } + newNode->next = node->next; + node->next = newNode; + } + } + //callback(message); + itr_timer_queue(); + return; +} + +void itr_timer_queue(){ + timer *node = head; + while(node!=nullptr){ + writes_uart(node->message); + writes_uart(" "); + write_int_uart(node->value,TRUE); + node = node->next; + } + return; +} + +bool timer_is_empty(){ + if(head==null){ + return TRUE; + } + else{ + return FALSE; + } +} + +void disable_timer_interrupt(){ + // head = nullptr; + *CORE0_TIMER_IRQ_CTRL = 0; + // asm volatile( + // "mrs x0, cntfrq_el0\n\t" + // "mov x1,0x00000fff\n\t" + // "mul x0,x0,x1\n\t" + // "msr cntp_tval_el0, x0\n\t" + // //"mov x0, 0\n\t" + // //"msr cntp_ctl_el0, x0\n\t" + // :::"x0","x1" + // ); + + //*CORE0_TIMER_IRQ_CTRL &= ~(1 << 2); + +} +void enable_timer_interrupt(){ + *CORE0_TIMER_IRQ_CTRL = 2; + // asm volatile( + // "mov x0,1\n\t" + // "msr cntp_ctl_el0, x0\n\t" + // :: + // : "x0" + // ); + // asm volatile( + // "bl core_timer_enable" + // ); +} +bool is_timerq_empty(){ + if(head==nullptr) + return TRUE; + else + return FALSE; +} + +timer* to_next_timer(){ + head = head->next; + return head; +} +timer* get_head_timer(){ + return head; +} \ No newline at end of file diff --git a/user/src/utils.c b/user/src/utils.c new file mode 100644 index 000000000..4cbfe3e94 --- /dev/null +++ b/user/src/utils.c @@ -0,0 +1,16 @@ +#include "utils.h" + +/* transfer big endian to little endian */ +uint32_t big2little(uint32_t big){ + // use instruction + uint32_t little = (0x000000ff & (big >> 24)) | + (0x0000ff00 & (big >> 8)) | + (0x00ff0000 & (big << 8)) | + (0xff000000 & (big << 24)); + return little; +} + +unsigned long align_up(unsigned long n, unsigned long align) +{ + return (n + align - 1) & (~(align - 1)); +} \ No newline at end of file diff --git a/user/syscall.S b/user/syscall.S new file mode 100644 index 000000000..deb51b4c6 --- /dev/null +++ b/user/syscall.S @@ -0,0 +1,47 @@ +.global get_pid +get_pid: + mov x8,0 + svc #0 + ret + +.global uart_read +uart_read: + mov x8,1 + svc #0 + ret + +.global uart_write +uart_write: + mov x8,2 + svc #0 + ret + +.global exec +exec: + mov x8,3 + svc #0 + ret + +.global fork +fork: + mov x8,4 + svc #0 + ret + +.global exit +exit: + mov x8,5 + svc #0 + ret + +.global mbox_call +mbox_call: + mov x8,6 + svc #0 + ret + +.global kill +kill: + mov x8,7 + svc #0 + ret \ No newline at end of file From b436ad639e72a37407400ef32819ea3e0e5fc4e1 Mon Sep 17 00:00:00 2001 From: leonkei Date: Sat, 14 May 2022 23:54:23 +0800 Subject: [PATCH 2/4] 16*18 --- a.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/a.S b/a.S index 2d0276c20..746378ffd 100644 --- a/a.S +++ b/a.S @@ -50,7 +50,7 @@ main_loop: b busy_loop .macro save_all - sub sp, sp, 32 * 9 + sub sp, sp, 16 * 18 stp x0, x1, [sp ,16 * 0] stp x2, x3, [sp ,16 * 1] stp x4, x5, [sp ,16 * 2] @@ -107,7 +107,7 @@ main_loop: ldp x28, x29, [sp ,16 * 14] ldr x30, [sp, 16 * 15] - add sp, sp, 32 * 9 + add sp, sp, 16 * 18 .endm exception_handler: From ef83d629b23a429170759e0a5d15343e7e396b9e Mon Sep 17 00:00:00 2001 From: leonkei Date: Tue, 17 May 2022 23:38:19 +0800 Subject: [PATCH 3/4] can threadexec normal prog --- a.S | 1 + include/cpio.h | 2 +- initramfs.cpio | Bin 23552 -> 23552 bytes src/cpio.c | 7 ++-- src/exception.c | 52 +++++++++++++++++++++++------ src/sched.c | 12 ++++--- src/shell.c | 55 +++++++++++++++---------------- src/syscall.c | 10 +++--- user/a.S | 50 +++++++++++++++++++++++++++- user/src/main.c | 80 ++++++++++++++++++++++++++------------------- user/src/syscall.S | 0 user/syscall.S | 47 -------------------------- 12 files changed, 183 insertions(+), 133 deletions(-) create mode 100644 user/src/syscall.S delete mode 100644 user/syscall.S diff --git a/a.S b/a.S index 746378ffd..780c12bd3 100644 --- a/a.S +++ b/a.S @@ -112,6 +112,7 @@ main_loop: exception_handler: save_all + mov x0,sp bl exception_entry load_all eret diff --git a/include/cpio.h b/include/cpio.h index faa71bb04..ddc8c9c6f 100644 --- a/include/cpio.h +++ b/include/cpio.h @@ -5,7 +5,7 @@ extern uint32_t* cpio_addr; void cpio_ls(); void cpio_cat(); -void cpio_get_addr(char* filedata,unsigned long* filesize); +unsigned long cpio_get_addr(char** filedata,unsigned long* filesize); //void* initramfs_callback(fdt_prop* prop,char * name,uint32_t len_prop); void* initramfs_start_callback(fdt_prop* prop,char * name,uint32_t len_prop); void* initramfs_end_callback(fdt_prop* prop,char * name,uint32_t len_prop); diff --git a/initramfs.cpio b/initramfs.cpio index 1d29c7b1af290d08dd0a1f340c5b59a74482da71..658eea127045e77a076f4fac4843de9b68e04aef 100644 GIT binary patch delta 3431 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 diff --git a/src/cpio.c b/src/cpio.c index 46099c8d4..695a44e51 100644 --- a/src/cpio.c +++ b/src/cpio.c @@ -132,7 +132,7 @@ void cpio_cat(){ } } -void cpio_get_addr(char* filedata,unsigned long* filesize){ +unsigned long cpio_get_addr(char** filedata,unsigned long* filesize){ cpio_newc_header* cnh = (cpio_newc_header*)cpio_addr; cpio_newc_header* next_header; char *filename; @@ -143,7 +143,7 @@ void cpio_get_addr(char* filedata,unsigned long* filesize){ read_string(&read_name); while(1){ - if(cpio_parse_header(cnh,&filename,filesize,&filedata,&next_header)!=0){ + if(cpio_parse_header(cnh,&filename,filesize,filedata,&next_header)!=0){ writes_uart("File not found!\r\n"); *filesize=0; break; @@ -156,7 +156,8 @@ void cpio_get_addr(char* filedata,unsigned long* filesize){ else if(strncmp(read_name,filename,strlen(read_name))==0){ // writes_n_uart(filedata,parse_hex_str(cnh->c_filesize,sizeof(cnh->c_filesize))); // writes_uart("\r\n"); - // return (unsigned long long)filedata; + + return (unsigned long long)filedata; break; } //writes_n_uart(filename,parse_hex_str(cnh->c_namesize,sizeof(cnh->c_namesize))); diff --git a/src/exception.c b/src/exception.c index 4b4926754..7d6054f82 100644 --- a/src/exception.c +++ b/src/exception.c @@ -3,7 +3,7 @@ #include "string.h" #include "timer.h" #include "task.h" - +#include "syscall.h" void enable_interrupt(){ asm volatile( "msr DAIFClr, 0xf" @@ -17,10 +17,11 @@ void disable_interrupt(){ } -void exception_entry(){ - busy_wait_writes("EXCEPTION ENTRY",TRUE); +void exception_entry(trap_frame* tf){ + // busy_wait_writes("EXCEPTION ENTRY",TRUE); // spsr_el1, elr_el1, and esr_el1 unsigned long long reg_spsr_el1, reg_elr_el1,reg_esr_el1; + unsigned int svc_num; asm volatile( "mrs %0,spsr_el1\n\t" "mrs %1,elr_el1\n\t" @@ -29,13 +30,44 @@ void exception_entry(){ "=r" (reg_elr_el1), "=r" (reg_esr_el1) ); - writes_uart("Exception\r\n"); - writes_uart("spsr_el1: "); - writehex_uart(reg_spsr_el1,1); - writes_uart("reg_elr_el1: "); - writehex_uart(reg_elr_el1,1); - writes_uart("reg_esr_el1: "); - writehex_uart(reg_esr_el1,1); + unsigned long long ec = reg_esr_el1>>26; + if(ec == 0b010101){ + switch (tf->x8) + { + case 0: // getpid + sys_getpid(tf); + break; + case 1: // uart_read + sys_uart_read(tf,tf->x0,tf->x1); + break; + case 2: // uart_write + sys_uart_write(tf,tf->x0,tf->x1); + break; + case 3: // exec + + break; + case 4: // fork + break; + case 5: // exit + break; + case 6: // mbox_call + break; + case 7: // kill + break; + default: + break; + } + } + else{ + writes_uart("Exception\r\n"); + writes_uart("spsr_el1: "); + writehex_uart(reg_spsr_el1,1); + writes_uart("reg_elr_el1: "); + writehex_uart(reg_elr_el1,1); + writes_uart("reg_esr_el1: "); + writehex_uart(reg_esr_el1,1); + } + return; } diff --git a/src/sched.c b/src/sched.c index 28372af8a..d49c0d3de 100644 --- a/src/sched.c +++ b/src/sched.c @@ -139,11 +139,13 @@ Thread_struct* pop_thread() } void thread_exec() { - char *file_start = nullptr; - unsigned long filesize; - cpio_get_addr(file_start,&filesize); - char *new_start = my_malloc(filesize); - memcpy(new_start,file_start,filesize); + char **file_start = my_malloc(sizeof(char*)); + unsigned long *filesize = my_malloc(sizeof(unsigned long)); + // cpio_get_addr(file_start,&filesize); + cpio_get_addr(file_start,filesize); + + char *new_start = my_malloc(*filesize); + memcpy(new_start,*file_start,*filesize); asm volatile( "mov x0, 0\n\t" // "msr spsr_el1, x0\n\t" diff --git a/src/shell.c b/src/shell.c index 67876d502..ff95d579d 100644 --- a/src/shell.c +++ b/src/shell.c @@ -245,37 +245,36 @@ void handle_command(enum Action action, char *buffer){ break; case prog: { - // origin - char *filedata = nullptr; - unsigned long filesize; - cpio_get_addr(filedata,&filesize); - if(filesize == 0){ - break; - } - unsigned long long prog_addr = (unsigned long long)filedata; - unsigned long *e0_stack = (unsigned long*)simple_malloc(2000); - writehex_uart(prog_addr,1); - // writehex_uart(e0_stack); - // writes_uart("\r\n"); + // // origin + // char *filedata = nullptr; + // unsigned long filesize; + + // unsigned long long prog_addr = cpio_get_addr(filedata,&filesize); + + // // unsigned long long prog_addr = (unsigned long long)filedata; + // unsigned long *e0_stack = (unsigned long*)simple_malloc(2000); + // writehex_uart(prog_addr,1); + // // writehex_uart(e0_stack); + // // writes_uart("\r\n"); + // // asm volatile( + // // "bl core_timer_enable\n\t" + // // // "bl core_timer_handler\n\t" + // // ); // asm volatile( - // "bl core_timer_enable\n\t" - // // "bl core_timer_handler\n\t" - // ); - asm volatile( - "mov x0, 0\n\t" // - "msr spsr_el1, x0\n\t" - "msr elr_el1, %0\n\t" - "msr sp_el0,%1\n\t" + // "mov x0, 0\n\t" // + // "msr spsr_el1, x0\n\t" + // "msr elr_el1, %0\n\t" + // "msr sp_el0,%1\n\t" - "eret\n\t" // - ::"r" (prog_addr), - "r" (e0_stack) - : "x0" - ); - writes_nl_uart("Run userprogram done"); + // "eret\n\t" // + // ::"r" (prog_addr), + // "r" (e0_stack) + // : "x0" + // ); + // writes_nl_uart("Run userprogram done"); - // thread_create(&thread_exec); - // idle(); + thread_create(&thread_exec); + idle(); break; } case timeout: diff --git a/src/syscall.c b/src/syscall.c index cf860cdb3..1a94928ea 100644 --- a/src/syscall.c +++ b/src/syscall.c @@ -53,11 +53,11 @@ int kernel_exec(trap_frame* tf,const char* name, char *const argv[]) } int sys_exec(trap_frame* tf,const char* name, char *const argv[]) { - char *file_start = nullptr; - unsigned long filesize; - cpio_get_addr(file_start,&filesize); - char *new_start = my_malloc(filesize); - memcpy(new_start,file_start,filesize); + char **file_start = my_malloc(sizeof(char*)); + unsigned long* filesize = my_malloc(sizeof(unsigned long)); + cpio_get_addr(file_start,filesize); + char *new_start = my_malloc(*filesize); + memcpy(new_start,*file_start,*filesize); if(filesize!=0){ // file not found if filesize == 0 tf->sp_el0 = (unsigned long)(get_current()->user_stack + THREAD_STACK_SIZE); tf->elr_el1 = (unsigned long)new_start; diff --git a/user/a.S b/user/a.S index bc6a78346..628c966da 100644 --- a/user/a.S +++ b/user/a.S @@ -1,6 +1,54 @@ .section ".text" .global _start - _start: bl main + +.global get_pid +get_pid: + mov x8,0 + svc #0 + ret + +.global uart_read +uart_read: + mov x8,1 + svc #0 + ret + +.global uart_write +uart_write: + mov x8,2 + svc #0 + ret + +.global exec +exec: + mov x8,3 + svc #0 + ret + +.global fork +fork: + mov x8,4 + svc #0 + ret + +.global exit +exit: + mov x8,5 + svc #0 + ret + +.global mbox_call +mbox_call: + mov x8,6 + svc #0 + ret + +.global kill +kill: + mov x8,7 + svc #0 + ret + // b exit diff --git a/user/src/main.c b/user/src/main.c index ed9471ee9..2a3510ee5 100644 --- a/user/src/main.c +++ b/user/src/main.c @@ -1,38 +1,52 @@ #include "mini_uart.h" -// #include "usr_syscall.h" -// void fork_test(){ -// printf("\nFork Test, pid %d\n", get_pid()); -// int cnt = 1; -// int ret = 0; -// if ((ret = fork()) == 0) { // child -// long long cur_sp; -// asm volatile("mov %0, sp" : "=r"(cur_sp)); -// printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); -// ++cnt; +extern int get_pid(); +extern unsigned int uart_read(char buf[],unsigned int size); +extern unsigned int uart_write(const char* name,unsigned int size); +extern int exec(const char* name, char *const argv[]); +extern int fork(); +extern void exit(); +extern int mbox_call(unsigned char ch, unsigned int *mbox); +extern void kill(int pid); +void fork_test(){ + // printf("\nFork Test, pid %d\n", get_pid()); + busy_wait_writes("\nFork Test, pid ",FALSE); + busy_wait_writeint(get_pid(),TRUE); + int cnt = 1; + int ret = 0; + if ((ret = fork()) == 0) { // child + long long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + ++cnt; -// if ((ret = fork()) != 0){ -// asm volatile("mov %0, sp" : "=r"(cur_sp)); -// printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); -// } -// else{ -// while (cnt < 5) { -// asm volatile("mov %0, sp" : "=r"(cur_sp)); -// printf("second child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); -// delay(1000000); -// ++cnt; -// } -// } -// exit(); -// } -// else { -// printf("parent here, pid %d, child %d\n", get_pid(), ret); -// } -// } -int main(){ - while(1) - { - // busy_wait_writes("HI, here is user.\r\n",FALSE); + if ((ret = fork()) != 0){ + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + } + else{ + while (cnt < 5) { + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("second child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + delay(1000000); + ++cnt; + } + } + exit(); + } + else { + // printf("parent here, pid %d, child %d\n", get_pid(), ret); + busy_wait_writes("parent here, pid ",FALSE); + busy_wait_writeint(get_pid(),FALSE); + busy_wait_writes(", child ",FALSE); + busy_wait_writeint(ret,TRUE); } - +} +int main(){ + // while(1) + // { + // busy_wait_writes("HI, here is user ",FALSE); + // busy_wait_writeint(get_pid(),TRUE); + // } + fork_test(); return 0; } \ No newline at end of file diff --git a/user/src/syscall.S b/user/src/syscall.S new file mode 100644 index 000000000..e69de29bb diff --git a/user/syscall.S b/user/syscall.S deleted file mode 100644 index deb51b4c6..000000000 --- a/user/syscall.S +++ /dev/null @@ -1,47 +0,0 @@ -.global get_pid -get_pid: - mov x8,0 - svc #0 - ret - -.global uart_read -uart_read: - mov x8,1 - svc #0 - ret - -.global uart_write -uart_write: - mov x8,2 - svc #0 - ret - -.global exec -exec: - mov x8,3 - svc #0 - ret - -.global fork -fork: - mov x8,4 - svc #0 - ret - -.global exit -exit: - mov x8,5 - svc #0 - ret - -.global mbox_call -mbox_call: - mov x8,6 - svc #0 - ret - -.global kill -kill: - mov x8,7 - svc #0 - ret \ No newline at end of file From 9ae821e6d841c9ae18fdccbae76a843a8ba9c571 Mon Sep 17 00:00:00 2001 From: leonkei Date: Mon, 23 May 2022 21:30:06 +0800 Subject: [PATCH 4/4] seems ok.... --- .vscode/settings.json | 7 ++- Makefile | 4 +- a.S | 59 ++++++++++++++++----- include/filesys.h | 0 include/mini_uart.h | 1 + include/sched.h | 19 +++++-- include/signal.h | 9 ++++ include/syscall.h | 9 ++-- initramfs.cpio | Bin 23552 -> 271872 bytes src/cpio.c | 3 +- src/exception.c | 112 +++++++++++++++++++++++++-------------- src/filesys.c | 0 src/main.c | 13 ++++- src/mini_uart.c | 16 ++++++ src/sched.c | 63 ++++++++++++++++------ src/shell.c | 2 +- src/signal.c | 59 +++++++++++++++++++++ src/syscall.c | 90 ++++++++++++++++++++++++++----- src/timer.c | 4 +- user/include/mini_uart.h | 2 +- user/src/main.c | 44 +++++++++++++-- user/src/mini_uart.c | 16 ++++++ 22 files changed, 427 insertions(+), 105 deletions(-) create mode 100644 include/filesys.h create mode 100644 include/signal.h create mode 100644 src/filesys.c create mode 100644 src/signal.c diff --git a/.vscode/settings.json b/.vscode/settings.json index ff8477435..7b24d33f3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,11 @@ "array": "c", "string_view": "c", "initializer_list": "c", - "utility": "c" + "utility": "c", + "*.tcc": "cpp", + "functional": "cpp", + "fstream": "cpp", + "istream": "cpp", + "streambuf": "cpp" } } \ No newline at end of file diff --git a/Makefile b/Makefile index 8dd400a04..7be4e558d 100644 --- a/Makefile +++ b/Makefile @@ -21,8 +21,8 @@ clean: rm kernel8.elf kernel8.img src/*.o *.o>/dev/null 2>/dev/null || true run: - qemu-system-aarch64 -M raspi3 -kernel kernel8.img --display none -serial null -serial stdio -s -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb - + # qemu-system-aarch64 -M raspi3 -kernel kernel8.img --display none -serial null -serial stdio -s -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial null -serial stdio -s -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb flash: sudo dd if=kernel8.img of=/dev/sdb diff --git a/a.S b/a.S index 780c12bd3..94c19c846 100644 --- a/a.S +++ b/a.S @@ -50,7 +50,7 @@ main_loop: b busy_loop .macro save_all - sub sp, sp, 16 * 18 + sub sp, sp, 16 * 17 stp x0, x1, [sp ,16 * 0] stp x2, x3, [sp ,16 * 1] stp x4, x5, [sp ,16 * 2] @@ -67,28 +67,29 @@ main_loop: stp x26, x27, [sp ,16 * 13] stp x28, x29, [sp ,16 * 14] - str x30, [sp, 16 * 15] + mrs x9, sp_el0 + stp x30,x9, [sp, 16 * 15] // for nested interrupt - mrs x0, spsr_el1 - mrs x1, elr_el1 - stp x0,x1, [sp, 16 * 16] + mrs x9, spsr_el1 + mrs x10, elr_el1 + stp x9,x10, [sp, 16 * 16] // ldp x0, x1, [sp ,16 * 0] // for el0 user stack pointer - mrs x0, sp_el0 - str x0, [sp, 16 * 17] + .endm // load general registers from stack .macro load_all - ldr x0, [sp, 16 * 17] - msr sp_el0,x0 - ldp x0,x1,[sp, 16 * 16] - msr spsr_el1,x0 - msr elr_el1,x1 + ldp x30,x9, [sp, 16 * 15] + msr sp_el0,x9 + + ldp x9,x10,[sp, 16 * 16] + msr spsr_el1,x9 + msr elr_el1,x10 ldp x0, x1, [sp ,16 * 0] ldp x2, x3, [sp ,16 * 1] @@ -105,11 +106,16 @@ main_loop: ldp x24, x25, [sp ,16 * 12] ldp x26, x27, [sp ,16 * 13] ldp x28, x29, [sp ,16 * 14] - ldr x30, [sp, 16 * 15] + // ldr x30, [sp, 16 * 15] - add sp, sp, 16 * 18 + add sp, sp, 16 * 17 .endm +.global load_eret +load_eret: + load_all + eret + exception_handler: save_all mov x0,sp @@ -119,6 +125,7 @@ exception_handler: irq_handler: save_all + mov x0,sp bl irq_entry load_all eret @@ -225,4 +232,28 @@ switch_to: .global get_current get_current: mrs x0, tpidr_el1 + ret + +.global save_cpu_context +save_cpu_context: + 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_cpu_context +load_cpu_context: + 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 \ No newline at end of file diff --git a/include/filesys.h b/include/filesys.h new file mode 100644 index 000000000..e69de29bb diff --git a/include/mini_uart.h b/include/mini_uart.h index ff7e53ade..d43580458 100644 --- a/include/mini_uart.h +++ b/include/mini_uart.h @@ -59,6 +59,7 @@ char uart_buf_write_pop(); void busy_wait_writes(char *s,bool newline); void busy_wait_writec(char s); void busy_wait_writeint(int i,bool newline); +void busy_wait_writehex(unsigned long long h,bool newline); int is_empty_write(); int is_empty_read(); diff --git a/include/sched.h b/include/sched.h index 2bef464d7..5ec0edc5d 100644 --- a/include/sched.h +++ b/include/sched.h @@ -1,6 +1,7 @@ #ifndef _SCHEDULE_HEADER_ #define _SCHEDULE_HEADER_ -#define THREAD_STACK_SIZE 4096 +#define THREAD_STACK_SIZE 4096//4096 +#include "signal.h" enum task_state { EMPTY, @@ -34,9 +35,13 @@ typedef struct Thread_struct void* user_stack; void* kernel_stack; struct Thread_struct *next,*prev; - // long counter; - // int priority; - // long preempt_count; + // void (*singal_handler[10])(); + void (*signal_handler[20])(); + unsigned int signal_count[20]; + void* signal_ustack; + void (*run_handler)(); + cpu_context saved_context; + }Thread_struct; typedef struct task_queue { @@ -44,7 +49,7 @@ typedef struct task_queue struct task_queue *next,*prev; }task_queue; -void thread_create(void (*f)()); +int thread_create(void (*f)()); Thread_struct current_thread(); void schedule(); void idle(); @@ -57,4 +62,8 @@ void context_switch(Thread_struct* next); Thread_struct* pop_thread(); void thread_exit(); void thread_exec(); +Thread_struct* get_thread(int); +void kill_thread(int); +extern Thread_struct* get_current(); +void raise_signal(int pid,int signal); #endif \ No newline at end of file diff --git a/include/signal.h b/include/signal.h new file mode 100644 index 000000000..04e5041fd --- /dev/null +++ b/include/signal.h @@ -0,0 +1,9 @@ +#ifndef _SIGNAL_HEADER_ +#define _SIGNAL_HEADER_ +#include "syscall.h" + +void run_signal(trap_frame*); +void signal_default_handler(int); +void sigreturn(); +void signal_registed_handler(void (*handler)()); +#endif \ No newline at end of file diff --git a/include/syscall.h b/include/syscall.h index d41e314d3..05914ea28 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -14,16 +14,17 @@ typedef struct trap_frame{ unsigned long long x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30; - unsigned long sp_el0, spsr_el1, elr_el1; + unsigned long long sp_el0, spsr_el1, elr_el1; }trap_frame; int sys_getpid(trap_frame*); -unsigned int sys_uart_read(trap_frame*,char buf[],unsigned int size); -unsigned int sys_uart_write(trap_frame*,const char* name,unsigned int size); +unsigned int sys_uart_read(trap_frame*,char buf[],unsigned long long size); +unsigned int sys_uart_write(trap_frame*,const char* name,unsigned long long size); int sys_exec(trap_frame*,const char* name, char *const argv[]); int sys_fork(trap_frame*); void sys_exit(trap_frame*); int sys_mbox_call(trap_frame*,unsigned char ch, unsigned int *mbox); void sys_kill(trap_frame*,int pid); - +void signal_register(int signal,void (*handler)()); +void signal_kill(int pid,int signal); #endif \ No newline at end of file diff --git a/initramfs.cpio b/initramfs.cpio index 658eea127045e77a076f4fac4843de9b68e04aef..c32da6749d300b9a5662b7bb26ad74bf6c1a8a12 100644 GIT binary patch literal 271872 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

5}i9nalra4DT=`V2ec_nr~m)} delta 5752 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 if(ec == 0b010101){ switch (tf->x8) @@ -38,27 +43,40 @@ void exception_entry(trap_frame* tf){ sys_getpid(tf); break; case 1: // uart_read - sys_uart_read(tf,tf->x0,tf->x1); + sys_uart_read(tf,(char*)tf->x0,tf->x1); break; case 2: // uart_write - sys_uart_write(tf,tf->x0,tf->x1); + sys_uart_write(tf,(char*)tf->x0,tf->x1); break; case 3: // exec - + sys_exec(tf,(char*)tf->x0,(char**)tf->x1); break; case 4: // fork + sys_fork(tf); break; case 5: // exit + sys_exit(tf); break; case 6: // mbox_call + sys_mbox_call(tf,(unsigned char)tf->x0,(unsigned int*)tf->x1); break; case 7: // kill + sys_kill(tf,(int)tf->x0); + break; + case 8: + signal_register(tf->x0, (void (*)())(tf->x1)); + break; + case 9: + signal_kill(tf->x0,tf->x1); break; + case 21: + sigreturn(); default: break; } } else{ + disable_timer_interrupt(); writes_uart("Exception\r\n"); writes_uart("spsr_el1: "); writehex_uart(reg_spsr_el1,1); @@ -66,13 +84,13 @@ void exception_entry(trap_frame* tf){ writehex_uart(reg_elr_el1,1); writes_uart("reg_esr_el1: "); writehex_uart(reg_esr_el1,1); + enable_timer_interrupt(); } - return; } int curr_task_privilege = 100; -void irq_entry(){ +void irq_entry(trap_frame* tf){ // writes_uart("IRQ entry\r\n"); // writes_uart("Interrupt Source:"); @@ -124,14 +142,14 @@ void irq_entry(){ add_task(Timer_interrupt_handler,INTERRUPT_PRIVILEGE_TIMER); if(curr_task_privilegespsr_el1 & 0b1111) == 0) + { + run_signal(tf); + } return; } @@ -173,35 +196,42 @@ void Timer_interrupt_handler(){ ); //itr_timer_queue(); // busy_wait_writes("TIMER INT",TRUE); - if(is_timerq_empty()){ - write_int_uart((int)(time_count/time_freq),0); - writes_uart(" seconds After booting\r\n"); - // set_expired_time(0x0fffffff); - disable_timer_interrupt(); - return; - } - else{ - writes_uart("Current time is: "); - write_int_uart((int)(time_count/time_freq),1); - timer* h = get_head_timer(); - h->callback(h->message); - // writes_uart("DEBUG:"); - // writes_nl_uart(h->message); - if(h->next==nullptr){ - writes_uart("next timer is not exist.\r\n"); - h = to_next_timer(); - disable_timer_interrupt(); - } - else{ - h = to_next_timer(); - writes_uart("Found next timer in "); - write_int_uart(h->value,TRUE); - unsigned long long time_count=0; - unsigned long long time_freq=0; - get_current_time(&time_count,&time_freq); - set_expired_time(h->value - time_count/time_freq); - enable_timer_interrupt(); - } - } + // for schedule timer interrupt + asm volatile( + "msr cntp_tval_el0, %0\n\t" + ::"r" (time_freq>>5) + ); + // schedule(); + + // if(is_timerq_empty()){ + // // write_int_uart((int)(time_count/time_freq),0); + // // writes_uart(" seconds After booting\r\n"); + // // set_expired_time(0x0fffffff); + // disable_timer_interrupt(); + // return; + // } + // else{ + // writes_uart("Current time is: "); + // write_int_uart((int)(time_count/time_freq),1); + // timer* h = get_head_timer(); + // h->callback(h->message); + // // writes_uart("DEBUG:"); + // // writes_nl_uart(h->message); + // if(h->next==nullptr){ + // writes_uart("next timer is not exist.\r\n"); + // h = to_next_timer(); + // disable_timer_interrupt(); + // } + // else{ + // h = to_next_timer(); + // writes_uart("Found next timer in "); + // write_int_uart(h->value,TRUE); + // unsigned long long time_count=0; + // unsigned long long time_freq=0; + // get_current_time(&time_count,&time_freq); + // set_expired_time(h->value - time_count/time_freq); + // enable_timer_interrupt(); + // } + // } } \ No newline at end of file diff --git a/src/filesys.c b/src/filesys.c new file mode 100644 index 000000000..e69de29bb diff --git a/src/main.c b/src/main.c index 916e80859..e7254a781 100644 --- a/src/main.c +++ b/src/main.c @@ -14,6 +14,11 @@ extern Thread_struct* get_current(); void foo() { for(int i = 0; i < 10; ++i) { + unsigned long long reg_sp_el0; + asm volatile( + "mrs %0,sp_el0\n\t" + : "=r" (reg_sp_el0) + ); writes_uart("Thread id: "); write_int_uart(get_current()->id,FALSE); writes_uart(" "); @@ -37,6 +42,10 @@ int main(){ // register unsigned long dtb_reg asm ("x15"); //init_frame_freelist(); + uint64_t tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); init_uart(); init_uart_buf(); init_taskq(); @@ -56,13 +65,13 @@ int main(){ // writes_uart("╚══╝╚══╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝\r\n"); writes_uart("Hello World!\r\n"); + // for (int i = 0; i < 10; i++) // { // thread_create(foo); // } // idle(); - - + // disable_timer_interrupt(); while(1) { // writes_uart("main\r\n"); diff --git a/src/mini_uart.c b/src/mini_uart.c index 9c074dd94..907b251b0 100644 --- a/src/mini_uart.c +++ b/src/mini_uart.c @@ -314,4 +314,20 @@ void busy_wait_writeint(int s,bool newline){ if(newline) busy_wait_writes("\r\n",FALSE); +} +void busy_wait_writehex(unsigned long long h,bool newline) +{ + busy_wait_writes("0x",FALSE); + unsigned int n; + int c; + for(c=28;c>=0;c-=4) { + + n=(h>>c)&(0xF); // n = 1,2,3....th byte of h from left to right. + + n+=n>9?0x37:0x30; // int 0~9 -> char '0'~'9', 10~15 -> 'A'~'F' + busy_wait_writec(n); + } + if(newline==1){ + busy_wait_writes("\r\n",FALSE); + } } \ No newline at end of file diff --git a/src/sched.c b/src/sched.c index d49c0d3de..1b68b3827 100644 --- a/src/sched.c +++ b/src/sched.c @@ -4,16 +4,18 @@ #include "sched.h" #include "exception.h" #include "cpio.h" +#include "timer.h" +#include "syscall.h" +#include "signal.h" #define TASK_POOL_SIZE 20 extern void switch_to(Thread_struct* prev, Thread_struct* next); -extern Thread_struct* get_current(); Thread_struct* thread_pool; Thread_struct* run_queue; Thread_struct* wait_queue; -void thread_create(void (*f)()){ +int thread_create(void (*f)()){ int i; for (i = 0; i < TASK_POOL_SIZE; i++) { @@ -27,30 +29,41 @@ void thread_create(void (*f)()){ thread_pool[i].cpu_context.lr = (unsigned long)f; thread_pool[i].cpu_context.fp = (unsigned long)(thread_pool[i].kernel_stack + THREAD_STACK_SIZE); thread_pool[i].cpu_context.sp = (unsigned long)(thread_pool[i].kernel_stack + THREAD_STACK_SIZE); + for(int j=0;j<20;j++) + { + thread_pool[i].signal_handler[j] = signal_default_handler; + thread_pool[i].signal_count[j] = 0; + } + thread_pool[i].signal_ustack = nullptr; + thread_pool[i].run_handler = nullptr; writes_uart("Create Thread "); write_int_uart(i,TRUE); push_thread(&thread_pool[i]); + return i; } void schedule() { - // disable_interrupt(); + disable_interrupt(); if(run_queue != nullptr) { Thread_struct* next = pop_thread(run_queue); // context_switch(next); Thread_struct* cur = get_current(); - if (cur->state == RUNNING) + if (cur->state == RUNNING && cur->id !=0) { push_thread(cur); } - writes_uart("From "); - write_int_uart(cur->id,FALSE); - writes_uart(" schedule to "); - write_int_uart(next->id,TRUE); - iter_runqueue(); + // busy_wait_writes("From ",FALSE); + // busy_wait_writeint(cur->id,FALSE); + // busy_wait_writes(" schedule to ",FALSE); + // busy_wait_writeint(next->id,TRUE); + // iter_runqueue(); + enable_interrupt(); + // enable_timer_interrupt(); switch_to(cur,next); } - // enable_interrupt(); + enable_interrupt(); + return; } void context_switch(Thread_struct* next) { @@ -98,11 +111,11 @@ void iter_runqueue() { Thread_struct* node = run_queue; while(node != nullptr){ - write_int_uart(node->id,FALSE); - writes_uart("->"); + busy_wait_writeint(node->id,FALSE); + busy_wait_writes("->",FALSE); node = node->next; } - writes_uart("\r\n"); + busy_wait_writes("\r\n",FALSE); } void push_thread(Thread_struct* t) { @@ -139,6 +152,7 @@ Thread_struct* pop_thread() } void thread_exec() { + char **file_start = my_malloc(sizeof(char*)); unsigned long *filesize = my_malloc(sizeof(unsigned long)); // cpio_get_addr(file_start,&filesize); @@ -146,14 +160,33 @@ void thread_exec() char *new_start = my_malloc(*filesize); memcpy(new_start,*file_start,*filesize); + Thread_struct* cur_thread = get_current(); asm volatile( "mov x0, 0\n\t" // "msr spsr_el1, x0\n\t" "msr elr_el1, %0\n\t" "msr sp_el0,%1\n\t" - "eret\n\t" // + "mov sp, %2\n\t" + "msr tpidr_el1, %3\n\t" ::"r" (new_start), - "r" (get_current()->user_stack) + "r" ((char*)(cur_thread->user_stack+THREAD_STACK_SIZE)), + "r" ((char*)(cur_thread->kernel_stack+THREAD_STACK_SIZE)), + "r" ((char*)cur_thread) : "x0" ); + + asm volatile( + "eret\n\t" // + ); +} +Thread_struct* get_thread(int id){ + return &(thread_pool[id]); +} +void kill_thread(int id) +{ + thread_pool[id].state = ZOMBIE; +} +void raise_signal(int pid,int signal) +{ + thread_pool[pid].signal_count[signal]++; } \ No newline at end of file diff --git a/src/shell.c b/src/shell.c index ff95d579d..d2e5d73c5 100644 --- a/src/shell.c +++ b/src/shell.c @@ -210,7 +210,7 @@ void handle_command(enum Action action, char *buffer){ writes_uart("ccreboot : cancel reboot the device\r\n"); writes_uart("ls : print the files in rootfs.\r\n"); writes_uart("cat : print the file information\r\n"); - writes_uart("usrprog : load user program and run it\r\n"); + writes_uart("prog : load user program and run it\r\n"); writes_uart("timeout : set timer timeout events\r\n"); writes_uart("mmalloc : test the malloc function\r\n"); writes_uart("mfree : free testing malloc address\r\n"); diff --git a/src/signal.c b/src/signal.c new file mode 100644 index 000000000..e5dc437c2 --- /dev/null +++ b/src/signal.c @@ -0,0 +1,59 @@ +#include "signal.h" +#include "sched.h" +#include "syscall.h" +#include "allocator.h" +#include "exception.h" +#include "mini_uart.h" +void signal_default_handler(int pid) +{ + sys_kill(0,pid); +} +void signal_registed_handler(void (*handler)()) +{ + Thread_struct* cur_thread = get_current(); + cur_thread->run_handler(); + asm volatile + ( + "mov x8,21\n\t" + "svc 0\n\t" + ); +} +extern void save_cpu_context(cpu_context* ctx); +void run_signal(trap_frame* tf) +{ + Thread_struct* cur_thread = get_current(); + save_cpu_context(&(cur_thread->saved_context)); + for(int j=0;j<20;j++) + { + if(cur_thread->signal_count[j] >0 ) + { + cur_thread->signal_count[j]--; + void* sig_func = cur_thread->signal_handler[j]; + if(sig_func == signal_default_handler) // if it is default function, + { + signal_default_handler(cur_thread->id); + } + else + { + cur_thread->signal_ustack = my_malloc(THREAD_STACK_SIZE); + cur_thread->run_handler = sig_func; + asm volatile("mov x0, %0": : "r"(sig_func)); + asm volatile("msr sp_el0, %0" : : "r"(cur_thread->signal_ustack + THREAD_STACK_SIZE)); + asm volatile("msr elr_el1, %0": : "r"(signal_registed_handler)); + // asm volatile("msr spsr_el1, %0" : : "r"(0)); + asm volatile("eret"); + } + + } + } + +} +extern void load_cpu_context(cpu_context* ctx); +void sigreturn() +{ + disable_interrupt(); + Thread_struct* cur_thread = get_current(); + free(cur_thread->signal_ustack); + load_cpu_context(&(cur_thread->saved_context)); + enable_interrupt(); +} \ No newline at end of file diff --git a/src/syscall.c b/src/syscall.c index 1a94928ea..87463e754 100644 --- a/src/syscall.c +++ b/src/syscall.c @@ -4,30 +4,48 @@ #include "cpio.h" #include "allocator.h" #include "utils.h" +#include "exception.h" +#include "mailbox.h" +#include "timer.h" extern Thread_struct* get_current(); int sys_getpid(trap_frame* tf){ - tf->x0 = get_current()->id; - return get_current()->id; + disable_interrupt(); + int pid = get_current()->id; + tf->x0 = pid; + // unsigned long long reg_sp_el0; + // asm volatile( + // "mrs %0,sp_el0\n\t" + // : "=r" (reg_sp_el0) + // ); + // busy_wait_writehex(reg_sp_el0,TRUE); + enable_interrupt(); + return pid; } -unsigned int sys_uart_read(trap_frame* tf,char buf[],unsigned int size) +unsigned int sys_uart_read(trap_frame* tf,char buf[],unsigned long long size) { + enable_interrupt(); for (int i = 0; i < size; i++) { // buf[i] = read_uart(); do{asm volatile("nop");}while(is_empty_read()); buf[i] = uart_buf_read_pop(); } + disable_interrupt(); tf->x0 = size; + enable_interrupt(); return size; } -unsigned int sys_uart_write(trap_frame* tf,const char* name,unsigned int size) +unsigned int sys_uart_write(trap_frame* tf,const char* name,unsigned long long size) { + enable_interrupt(); for (int i = 0; i < size; i++) { - // busy_wait_writec(name[i]); - writec_uart(name[i]); + busy_wait_writec(name[i]); + // writec_uart(name[i]); } + disable_interrupt(); tf->x0 = size; + enable_interrupt(); return size; } int kernel_exec(trap_frame* tf,const char* name, char *const argv[]) @@ -62,26 +80,74 @@ int sys_exec(trap_frame* tf,const char* name, char *const argv[]) tf->sp_el0 = (unsigned long)(get_current()->user_stack + THREAD_STACK_SIZE); tf->elr_el1 = (unsigned long)new_start; tf->spsr_el1 = 0; - // asm volatile("msr sp_el0, %0" : : "r"(get_current()->user_stack + THREAD_STACK_SIZE)); - // asm volatile("msr elr_el1, %0": : "r"(file_start)); - // asm volatile("msr spsr_el1, %0" : : "r"(SPSR_EL1_VALUE)); - // asm volatile("eret"); } return 0; } +extern void load_eret(); int sys_fork(trap_frame* tf) { + disable_interrupt(); + // busy_wait_writehex(tf->sp_el0,TRUE); + Thread_struct* cur_thread = get_current(); + int child_id = thread_create((void*)cur_thread->cpu_context.lr); + + Thread_struct* child_thread = get_thread(child_id); + + for(int i=0;i<20;i++) + { + child_thread->signal_handler[i] = cur_thread->signal_handler[i]; + } + // // copy parent's cpu context to child + memcpy(&(child_thread->cpu_context),&(cur_thread->cpu_context),sizeof(cpu_context)); + // // copy parent's user stack to child + memcpy(child_thread->user_stack,cur_thread->user_stack,THREAD_STACK_SIZE); + // // copy trap frame to child sp + trap_frame* child_tf = (trap_frame*)(child_thread->kernel_stack + THREAD_STACK_SIZE-sizeof(trap_frame)); + memcpy((void*)(child_tf),(void*)tf,sizeof(trap_frame)); + child_tf->x0 = 0; + child_tf->sp_el0 = (unsigned long long)(child_thread->user_stack+THREAD_STACK_SIZE) - (unsigned long long)((unsigned long long)cur_thread->user_stack+THREAD_STACK_SIZE-tf->sp_el0); + + child_thread->cpu_context.sp = (unsigned long long)child_tf; + child_thread->cpu_context.lr = (unsigned long long)(&load_eret); + tf->x0 = child_id; + + enable_interrupt(); + return child_id; } void sys_exit(trap_frame* tf) { - + disable_interrupt(); + get_current()->state = ZOMBIE; + enable_interrupt(); + schedule(); } int sys_mbox_call(trap_frame* tf, unsigned char ch, unsigned int *mbox) { + disable_interrupt(); + int res = mailbox_call(mbox,ch); + tf->x0 = res; + return res; + enable_interrupt(); } void sys_kill(trap_frame* tf, int pid) { - + disable_interrupt(); + kill_thread(pid); + enable_interrupt(); +} + +void signal_register(int signal,void (*handler)()) +{ + disable_interrupt(); + if(!(signal<0 || signal>20)) + get_current()->signal_handler[signal]=handler; + enable_interrupt(); +} +void signal_kill(int pid,int signal) +{ + disable_interrupt(); + raise_signal( pid, signal); + enable_interrupt(); } \ No newline at end of file diff --git a/src/timer.c b/src/timer.c index 0fa74a870..3d9f5543d 100644 --- a/src/timer.c +++ b/src/timer.c @@ -9,7 +9,7 @@ void init_timer(){ // head->value = null; head = nullptr; - disable_timer_interrupt(); + // disable_timer_interrupt(); // writes_uart("Core timer: "); //writehex_uart(*CORE0_TIMER_IRQ_CTRL,1); } @@ -88,7 +88,7 @@ void add_timer(void (*callback)(char* s),char *message,int after){ } } //callback(message); - itr_timer_queue(); + // itr_timer_queue(); return; } diff --git a/user/include/mini_uart.h b/user/include/mini_uart.h index ff7e53ade..90f6cb7c6 100644 --- a/user/include/mini_uart.h +++ b/user/include/mini_uart.h @@ -22,7 +22,7 @@ void writes_n_uart(char *s, unsigned int size); void writes_nl_uart(char *s); void writehex_uart(unsigned int h,int newline); void write_int_uart(unsigned int,bool newline); - +void busy_wait_writehex(unsigned long long h,bool newline); //void writeaddr_uart(unsigned int*); #define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) #define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) diff --git a/user/src/main.c b/user/src/main.c index 2a3510ee5..f89962276 100644 --- a/user/src/main.c +++ b/user/src/main.c @@ -7,26 +7,58 @@ extern int fork(); extern void exit(); extern int mbox_call(unsigned char ch, unsigned int *mbox); extern void kill(int pid); +void delay(int time) +{ + unsigned long long delay_time = time*0x1000; + while(delay_time>1){ + delay_time--; + } +} void fork_test(){ // printf("\nFork Test, pid %d\n", get_pid()); busy_wait_writes("\nFork Test, pid ",FALSE); busy_wait_writeint(get_pid(),TRUE); int cnt = 1; int ret = 0; - if ((ret = fork()) == 0) { // child + if ((ret = fork())== 0) { // child long long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); - printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + // printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + busy_wait_writes("first child pid: ",FALSE); + busy_wait_writeint(get_pid(),FALSE); + busy_wait_writes(", cnt: ",FALSE); + busy_wait_writeint(cnt,FALSE); + busy_wait_writes(", ptr: ",FALSE); + busy_wait_writehex((unsigned long long )(&cnt),FALSE); + busy_wait_writes(", sp: ",FALSE); + busy_wait_writehex((unsigned long long)cur_sp,TRUE); ++cnt; if ((ret = fork()) != 0){ asm volatile("mov %0, sp" : "=r"(cur_sp)); - printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + // printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + busy_wait_writes("first child pid: ",FALSE); + busy_wait_writeint(get_pid(),FALSE); + busy_wait_writes(", cnt: ",FALSE); + busy_wait_writeint(cnt,FALSE); + busy_wait_writes(", ptr: ",FALSE); + busy_wait_writehex((unsigned long long )(&cnt),FALSE); + busy_wait_writes(", sp: ",FALSE); + busy_wait_writehex((unsigned long long)cur_sp,TRUE); } else{ while (cnt < 5) { asm volatile("mov %0, sp" : "=r"(cur_sp)); - printf("second child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + // printf("second child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + busy_wait_writes("second child pid: ",FALSE); + busy_wait_writeint(get_pid(),FALSE); + busy_wait_writes(", cnt: ",FALSE); + busy_wait_writeint(cnt,FALSE); + busy_wait_writes(", ptr: ",FALSE); + busy_wait_writehex((unsigned long long )(&cnt),FALSE); + busy_wait_writes(", sp: ",FALSE); + busy_wait_writehex((unsigned long long)cur_sp,TRUE); delay(1000000); ++cnt; } @@ -39,7 +71,10 @@ void fork_test(){ busy_wait_writeint(get_pid(),FALSE); busy_wait_writes(", child ",FALSE); busy_wait_writeint(ret,TRUE); + } + exit(); + // while(1){asm volatile("nop");} } int main(){ // while(1) @@ -48,5 +83,6 @@ int main(){ // busy_wait_writeint(get_pid(),TRUE); // } fork_test(); + exit(); return 0; } \ No newline at end of file diff --git a/user/src/mini_uart.c b/user/src/mini_uart.c index 9c074dd94..907b251b0 100644 --- a/user/src/mini_uart.c +++ b/user/src/mini_uart.c @@ -314,4 +314,20 @@ void busy_wait_writeint(int s,bool newline){ if(newline) busy_wait_writes("\r\n",FALSE); +} +void busy_wait_writehex(unsigned long long h,bool newline) +{ + busy_wait_writes("0x",FALSE); + unsigned int n; + int c; + for(c=28;c>=0;c-=4) { + + n=(h>>c)&(0xF); // n = 1,2,3....th byte of h from left to right. + + n+=n>9?0x37:0x30; // int 0~9 -> char '0'~'9', 10~15 -> 'A'~'F' + busy_wait_writec(n); + } + if(newline==1){ + busy_wait_writes("\r\n",FALSE); + } } \ No newline at end of file