diff --git a/bootloader/main.c b/bootloader/main.c index 115257c39..7c1035969 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -1,9 +1,23 @@ +#include "uart.h" + extern char _kernel_start[]; // 0x80000 char* _dtb; +// little endian to unsigned int (4 bytes) +unsigned int LE_to_uint(char *s) { + unsigned int res = 0; + res += (unsigned int)(s[0] & 0xff); + res += (unsigned int)((s[1] & 0xff) << 8); + res += (unsigned int)((s[2] & 0xff) << 16); + res += (unsigned int)((s[3] & 0xff) << 24); + return res; +} + void load_kernel() { + char size_buf[5] = {0}; unsigned int size = 0; - uart_read(&size, 4); // read kernel8.img size + uart_read(size_buf, 4); // read kernel8.img size + size = LE_to_uint(size_buf); uart_write_string("[+] Get kernel8.img size : 0x"); uart_write_hex(size); uart_write_string("\r\n"); diff --git a/bootloader/makefile b/bootloader/makefile index 6e744a8a5..110f6ced6 100644 --- a/bootloader/makefile +++ b/bootloader/makefile @@ -1,4 +1,4 @@ -CROSS = aarch64-unknown-linux-gnu +CROSS = aarch64-linux-gnu CC = $(CROSS)-gcc CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles LD = $(CROSS)-ld diff --git a/config.txt b/config.txt index 13201285b..49fc25695 100644 --- a/config.txt +++ b/config.txt @@ -1,3 +1,3 @@ kernel=bootloader.img arm_64bit=1 -initramfs initramfs.cpio 0x2000000 \ No newline at end of file +initramfs initramfs.cpio 0x20000000 diff --git a/include/cpio.h b/include/cpio.h index 898851bfb..b608184d3 100644 --- a/include/cpio.h +++ b/include/cpio.h @@ -1,8 +1,9 @@ #ifndef CPIO_H #define CPIO_H +#include "sched.h" #include "simple_alloc.h" -// #define INITRD_ADDR (0x8000000) // QEMU: 0x8000000, Rpi3: 0x20000000 +// QEMU: 0x8000000, Rpi3: 0x20000000 extern void* INITRD_ADDR; typedef struct cpio_newc_header { @@ -35,4 +36,13 @@ void cpio_ls_callback(char* param, cpio_newc_header* header, char* file_name, un void cpio_cat_callback(char* param, cpio_newc_header* header, char* file_name, unsigned int name_size, char* file_data, unsigned int data_size); void cpio_prog_callback(char* param, cpio_newc_header* header, char* file_name, unsigned int name_size, char* file_data, unsigned int data_size); +extern char *syscall_file_start_addr; +extern unsigned int syscall_file_size; +void cpio_get_file_start_callback(char* param, cpio_newc_header* header, char* file_name, unsigned int name_size, char* file_data, unsigned int data_size); +void cpio_get_file_size_callback(char* param, cpio_newc_header* header, char* file_name, unsigned int name_size, char* file_data, unsigned int data_size); +char* get_file_start(char* path); +unsigned int get_file_size(char* path); + +void cpio_exec_callback(char* param, cpio_newc_header* header, char* file_name, unsigned int name_size, char* file_data, unsigned int data_size); + #endif \ No newline at end of file diff --git a/include/dtb.h b/include/dtb.h index 8e3d69a14..52c64d5dd 100644 --- a/include/dtb.h +++ b/include/dtb.h @@ -1,6 +1,9 @@ #ifndef DTB_H #define DTB_H +#include "uart.h" +#include "string.h" +extern char* DTB_ADDRESS; extern void* INITRD_ADDR; extern void* INITRD_END; diff --git a/include/esr.h b/include/esr.h new file mode 100644 index 000000000..47fe15490 --- /dev/null +++ b/include/esr.h @@ -0,0 +1,10 @@ +#ifndef ESR_H +#define ESR_H + +typedef struct { + unsigned int iss : 25, // Instruction specific syndrome + il : 1, // Instruction length bit + ec : 6; // Exception class +} esr_el1_t; + +#endif \ No newline at end of file diff --git a/include/exception.h b/include/exception.h index 8c9a6c6ee..ab77666f5 100644 --- a/include/exception.h +++ b/include/exception.h @@ -1,7 +1,11 @@ #ifndef EXCEPTION_H #define EXCEPTION_H -#include "timer.h" +#include "tpf.h" #include "uart.h" +#include "task.h" +#include "timer.h" +#include "sched.h" +#include "syscall.h" // https://github.com/Tekki/raspberrypi-documentation/blob/master/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf (p.16) #define CORE0_INTERRUPT_SOURCE ((volatile unsigned int*)(0x40000060)) @@ -27,10 +31,19 @@ pending base' register different from the other 'base' interrupt registers #define DISABLE_BASIC_IRQS ((volatile unsigned int*)(PBASE+0x0000B224)) #define IRQ_PENDING_1_AUX_INT (1<<29) -void sync_64_router(unsigned long long x0); -void irq_router(unsigned long long x0); +void sync_64_router(trapframe_t *tpf); +void irq_router(trapframe_t *tpf); void invalid_exception_router(unsigned long long x0); -void enable_interrupt(); -void disable_interrupt(); -#endif \ No newline at end of file +static inline void enable_interrupt() { + asm volatile("msr daifclr, 0xf"); +} +static inline void disable_interrupt() { + asm volatile("msr daifset, 0xf"); +} + +unsigned long long is_disable_interrupt(); +void lock(); +void unlock(); + +#endif diff --git a/include/malloc.h b/include/malloc.h index 7d039176f..495497d7e 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -15,6 +15,9 @@ void sc_init(); void *sc_alloc(int size); int sc_free(void *sc); +void *kmalloc(int size); +void kfree(void *ptr); + void sc_test(); #endif \ No newline at end of file diff --git a/include/mmu.h b/include/mmu.h new file mode 100644 index 000000000..44f45cea4 --- /dev/null +++ b/include/mmu.h @@ -0,0 +1,63 @@ +#ifndef MMU_H +#define MMU_H +#include "esr.h" +#include "uart.h" +#include "list.h" +#include "sched.h" +#include "string.h" +#include "malloc.h" +#include "exception.h" + +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 +#define MAIR_CONFIG_DEFAULT ((MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))) + +#define PD_TABLE 0b11L +#define PD_BLOCK 0b01L +#define PD_UNX (1L << 54) +#define PD_KNX (1L << 53) +#define PD_ACCESS (1L << 10) +#define PD_UK_ACCESS (1L << 6) +#define PD_RDONLY (1L << 7) +#define BOOT_PGD_ATTR PD_TABLE +#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) + +#define PHYS_TO_VIRT(x) (x + 0xffff000000000000) +#define VIRT_TO_PHYS(x) (x - 0xffff000000000000) +#define ENTRY_ADDR_MASK 0xfffffffff000L + +#define kernel_pgd_addr 0x1000 +#define kernel_pud_addr 0x2000 + +#define DATA_ABORT_LOWER 0b100100 +#define INS_ABORT_LOWER 0b100000 + +#define TF_LEVEL0 0b000100 +#define TF_LEVEL1 0b000101 +#define TF_LEVEL2 0b000110 +#define TF_LEVEL3 0b000111 + +void *set_2M_kernel_mmu(void *x0); +void map_one_page(unsigned long *pgd_p, unsigned long va, unsigned long pa, unsigned long flag); +void add_vma(struct thread *t, unsigned long va, unsigned long size, unsigned long pa, unsigned long rwx, int is_alloced); +void free_page_tables(unsigned long *page_table, int level); +void handle_abort(esr_el1_t* esr_el1); +void map_one_page_rwx(unsigned long *pgd_p, unsigned long va, unsigned long pa, unsigned long rwxflag); +void seg_fault(); + +typedef struct vm_area_struct { + list_head_t listhead; + unsigned long virt_addr; + unsigned long phys_addr; + unsigned long area_size; + unsigned long rwx; // r = 1, w = 2, x = 4 + int is_alloced; +} vm_area_struct_t; + +#endif \ No newline at end of file diff --git a/include/node.h b/include/node.h new file mode 100644 index 000000000..d5b69fb3c --- /dev/null +++ b/include/node.h @@ -0,0 +1,9 @@ +#ifndef NODE_H +#define NODE_H + +enum node_type { + dir_t, + file_t +}; + +#endif \ No newline at end of file diff --git a/include/reset.h b/include/reset.h index 120556c2a..861238f01 100644 --- a/include/reset.h +++ b/include/reset.h @@ -5,19 +5,8 @@ #define PM_RSTC 0x3f10001c #define PM_WDOG 0x3f100024 -void set(long addr, unsigned int value) { - volatile unsigned int* point = (unsigned int*)addr; - *point = value; -} - -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 -} +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); #endif \ No newline at end of file diff --git a/include/sched.h b/include/sched.h new file mode 100644 index 000000000..dff820db2 --- /dev/null +++ b/include/sched.h @@ -0,0 +1,60 @@ +#ifndef SCHED_H +#define SCHED_H +#include "vfs.h" +#include "list.h" +#include "buddy.h" +#include "signal.h" +#include "malloc.h" +#include "syscall.h" +#include "exception.h" +#include "simple_alloc.h" + +#define PIDMAX 4096 +#define USTACK_SIZE 0x10000 +#define KSTACK_SIZE 0x10000 +#define SIGNAL_MAX 16 + +extern void switch_to(void *curr_context, void *next_context); +extern void store_context(void *curr_context); +extern void load_context(void *curr_context); +extern void *get_current(); + +typedef struct thread_context { + unsigned long x19, x20, x21, x22, x23, x24, x25, x26, x27, x28; + unsigned long fp, lr, sp; +} thread_context_t; + +typedef struct thread { + list_head_t listhead; + thread_context_t context; + char *data; + unsigned int datasize; + int iszombie; + int pid; + int isused; + char* stack_alloced_ptr; + char* kernel_stack_alloced_ptr; + void (*singal_handler[SIGNAL_MAX+1])(); + int sigcount[SIGNAL_MAX + 1]; + void (*curr_signal_handler)(); + int signal_is_checking; + thread_context_t signal_saved_context; + char curr_working_dir[256]; + struct file* file_descriptors_table[16]; +} thread_t; + +extern thread_t *curr_thread; +extern list_head_t *run_queue; +extern list_head_t *wait_queue; +extern thread_t threads[PIDMAX + 1]; + +void init_thread_sched(); +void idle(); +void schedule(); +void kill_zombies(); +thread_t *thread_create(void *start); +void thread_exit(); +int exec_thread(char *data, unsigned int filesize); +void schedule_timer(char *notuse); + +#endif diff --git a/include/shell.h b/include/shell.h index 97cdc33d3..56f775c64 100644 --- a/include/shell.h +++ b/include/shell.h @@ -6,6 +6,7 @@ #include "mbox.h" #include "reset.h" #include "string.h" +#include "sched.h" #include "timer.h" #include "buddy.h" #include "malloc.h" @@ -34,28 +35,11 @@ void cmd_async(); void cmd_prog(); void cmd_sec2(); void cmd_setTimeout(char* param); +void cmd_foo(); void cmd_preempt(); void cmd_pageTest(); void cmd_chunkTest(); +void cmd_exec(char* param); void cmd_unknown(); -struct cmd cmd_list[] = { - {"help", cmd_help, "print this help menu"}, - {"hello", cmd_hello, "print Hello World!"}, - // {"reboot", cmd_reboot, "reboot the device"}, - {"revision", cmd_revision, "print board revision"}, - {"memory", cmd_memory, "print ARM memory base address and size"}, - {"ls", cmd_ls, "list directory contents"}, - {"cat", cmd_cat, "print file content"}, - {"dtb", cmd_dtb, "show device tree"}, - {"initramfs", cmd_initramfs, "show initramfs address"}, - // {"async", cmd_async, "test async print"}, - {"prog", cmd_prog, "load a user program in the initramfs, and jump to it"}, - {"sec2", cmd_sec2, "print the seconds after booting and set the next timeout to 2 seconds later."}, - {"setTimeout",cmd_setTimeout,"prints message after seconds"}, - // {"preempt", cmd_preempt, "test preemption"}, - {"pageTest", cmd_pageTest, "test page frame allocator"}, - {"chunkTest", cmd_chunkTest, "test small chunk allocator"}, -}; - #endif \ No newline at end of file diff --git a/include/signal.h b/include/signal.h new file mode 100644 index 000000000..e748449dc --- /dev/null +++ b/include/signal.h @@ -0,0 +1,14 @@ +#ifndef SIGNAL_H +#define SIGNAL_H +#include "tpf.h" +#include "sched.h" +#include "buddy.h" +#include "syscall.h" +#include "exception.h" + +void check_signal(trapframe_t *tpf); +void run_signal(trapframe_t* tpf, int signal); +void signal_handler_wrapper(); +void signal_default_handler(); + +#endif \ No newline at end of file diff --git a/include/simple_alloc.h b/include/simple_alloc.h index c05aaed9d..980d03084 100644 --- a/include/simple_alloc.h +++ b/include/simple_alloc.h @@ -1,5 +1,6 @@ #ifndef SIMPLE_ALLOC_H #define SIMPLE_ALLOC_H +#include "uart.h" // from linker.ld extern char _simple_alloc_start; diff --git a/include/string.h b/include/string.h index fb9ca4402..e22fba17c 100644 --- a/include/string.h +++ b/include/string.h @@ -3,136 +3,16 @@ #define ENDL "\r\n" -void memcpy(char *s1, const char *s2, unsigned int len) { - for (unsigned int i = 0; i < len; i++) - s1[i] = s2[i]; -} - -void memset(char *s1, const char c, unsigned int len) { - for (unsigned int i = 0; i < len; i++) - s1[i] = c; -} - -unsigned int strlen(char *s) { - unsigned int len = 0; - while (1) { - if (*(s + len) == '\0') - break; - len++; - } - return len; -} - -int strcmp(const char *s1, const char *s2) { - unsigned int i = 0; - for (i = 0; i < strlen(s1); i++) { - if (s1[i] != s2[i]) - return s1[i] - s2[i]; - } - return s1[i] - s2[i]; -} - -int strncmp(const char *s1, const char *s2, unsigned int n) { - unsigned int i = 0; - for (i = 0; i < n; i++) { - if (s1[i] != s2[i]) - return s1[i] - s2[i]; - } - return 0; -} - -void strrev(char *s) { - unsigned int len = strlen(s); - char tmp; - for(unsigned int i = 0; i < len/2; i++){ - tmp = s[i]; - s[i] = s[len-i-1]; - s[len-i-1] = tmp; - } -} - -// string to int -int atoi(char* s) { - int res = 0; - for (int i = 0; s[i] != '\0'; ++i) { - if(s[i] > '9' || s[i] < '0') - return res; - res = res * 10 + s[i] - '0'; - } - return res; -} - -// int to string -char* itoa(int x) { - char str[MAX_BUF_SIZE]; - memset(str, 0, MAX_BUF_SIZE); - int i = 0, negative = 0; - // handle 0 explicitly - if (x == 0) { - str[i++] = '0'; - str[i] = '\0'; - return str; - } - // handle negative numbers - if (x < 0) { - negative = 1; - x = -x; - } - // process individual digits - while (x != 0) { - str[i++] = x % 10 + '0'; - x = x / 10; - } - if (negative) - str[i++] = '-'; - str[i] = '\0'; - strrev(str); - return str; -} - -// unsigned int to hex string -void uint_to_hex(unsigned int x, char *s) { - int i = 0, rem = 0, len = strlen(s); - memset(s, 0, len); - // handle 0 explicitly - if (x == 0) { - s[i++] = '0'; - s[i] = '\0'; - return ; - } - // process individual digits - while (x != 0) { - rem = x % 16; - if (rem >= 10) - s[i++] = rem - 10 + 'A'; - else - s[i++] = rem + '0'; - x = x / 16; - } - s[i] = '\0'; - strrev(s); -} - -// hex string to unsigned int -unsigned int hex_to_uint(const char *s, unsigned int size) { - unsigned int ret = 0; - for (unsigned int i = 0; i < size; i++) { - ret *= 16; - if (s[i] >= '0' && s[i] <= '9') { - ret += s[i] - '0'; - } else if (s[i] >= 'a' && s[i] <= 'f') { - ret += s[i] - 'a' + 10; - } else if (s[i] >= 'A' && s[i] <= 'F') { - ret += s[i] - 'A' + 10; - } - } - return ret; -} - -// big endian to unsigned int -unsigned int BE_to_uint(void *ptr) { - unsigned char *bytes = (unsigned char *)ptr; - return bytes[3] | bytes[2] << 8 | bytes[1] << 16 | bytes[0] << 24; -} +void memcpy(char *s1, char *s2, unsigned int len); +void memset(char *s1, char c, unsigned int len); +unsigned int strlen(char *s); +int strcmp(char *s1, char *s2); +int strncmp(char *s1, char *s2, unsigned int n); +void strrev(char *s); +int atoi(char* s); +char* itoa(int x, char *str); +void uint_to_hex(unsigned int x, char *s); +unsigned int hex_to_uint(char *s, unsigned int size); +unsigned int BE_to_uint(void *ptr); #endif \ No newline at end of file diff --git a/include/syscall.h b/include/syscall.h new file mode 100644 index 000000000..3920de259 --- /dev/null +++ b/include/syscall.h @@ -0,0 +1,33 @@ +#ifndef SYSCALL_H +#define SYSCALL_H +#include "tpf.h" +#include "vfs.h" +#include "cpio.h" +#include "mbox.h" +#include "sched.h" +#include "buddy.h" +#include "exception.h" + +#define MAX_FD 16 + +int getpid(trapframe_t *tpf); +unsigned long uartread(trapframe_t *tpf, char buf[], unsigned long size); +unsigned long uartwrite(trapframe_t *tpf, const char buf[], unsigned long size); +int exec(trapframe_t *tpf, const char *name, char *const argv[]); +int fork(trapframe_t *tpf); +void exit(trapframe_t *tpf, int status); +int syscall_mbox_call(trapframe_t *tpf, unsigned char ch, unsigned int *mbox); +void kill(trapframe_t *tpf, int pid); +void signal_register(int signal, void (*handler)()); +void signal_kill(int pid, int signal); +void sigreturn(trapframe_t *tpf); + +int sys_open(trapframe_t *tpf, const char *pathname, int flags); +int sys_close(trapframe_t *tpf, int fd); +long sys_write(trapframe_t *tpf, int fd, const void *buf, unsigned long count); +long sys_read(trapframe_t *tpf, int fd, void *buf, unsigned long count); +int sys_mkdir(trapframe_t *tpf, const char *pathname, unsigned mode); +int sys_mount(trapframe_t *tpf, const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data); +int sys_chdir(trapframe_t *tpf, const char *path); + +#endif \ No newline at end of file diff --git a/include/task.h b/include/task.h index 255a2ff77..d743dd6d2 100644 --- a/include/task.h +++ b/include/task.h @@ -1,6 +1,8 @@ #ifndef TASK_H #define TASK_H #include "list.h" +#include "malloc.h" +#include "exception.h" #include "simple_alloc.h" typedef struct task { diff --git a/include/timer.h b/include/timer.h index 501fc3e3a..ce887c3f9 100644 --- a/include/timer.h +++ b/include/timer.h @@ -1,6 +1,9 @@ #ifndef TIMER_H #define TIMER_H +#include "uart.h" #include "list.h" +#include "string.h" +#include "malloc.h" #include "simple_alloc.h" // https://github.com/Tekki/raspberrypi-documentation/blob/master/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf (p.13) @@ -22,7 +25,7 @@ void core_timer_enable(); void core_timer_disable(); void core_timer_handler(); -void add_timer(void *function, unsigned long long timeout, char *args); +void add_timer(void *function, unsigned long long timeout, char *args, int bytick); void set_core_timer_interrupt_abs(unsigned long long tick); void set_core_timer_interrupt_rel(unsigned long long expired_time); unsigned long long get_tick_plus_s(unsigned long long second); diff --git a/include/tmpfs.h b/include/tmpfs.h new file mode 100644 index 000000000..f9cec3892 --- /dev/null +++ b/include/tmpfs.h @@ -0,0 +1,34 @@ +#ifndef TMPFS_H +#define TMPFS_H +#include "vfs.h" +#include "node.h" +#include "uart.h" +#include "malloc.h" + +#define FILE_NAME_MAX 32 +#define MAX_DIR_ENTRY 32 +#define MAX_FILE_SIZE 4096 + +struct tmpfs_inode { + enum node_type type; + char name[FILE_NAME_MAX]; + struct vnode *entry[MAX_DIR_ENTRY]; + char *data; + unsigned long datasize; +}; + +int register_tmpfs(); +int tmpfs_setup_mount(struct filesystem *fs, struct mount *_mount); +struct vnode *tmpfs_create_vnode(struct mount *_mount, enum node_type type); + +int tmpfs_write(struct file *file, const void *buf, unsigned long len); +int tmpfs_read(struct file *file, void *buf, unsigned long len); +int tmpfs_open(struct vnode *file_node, struct file **target); +int tmpfs_close(struct file *file); +long tmpfs_getsize(struct vnode *vnode); + +int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); + +#endif \ No newline at end of file diff --git a/include/tpf.h b/include/tpf.h new file mode 100644 index 000000000..dee9bb95e --- /dev/null +++ b/include/tpf.h @@ -0,0 +1,11 @@ +#ifndef TPF_H +#define TPF_H + +typedef struct trapframe { + unsigned long x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10; + unsigned long x11, x12, x13, x14, x15, x16, x17, x18, x19, x20; + unsigned long x21, x22, x23, x24, x25, x26, x27, x28, x29, x30; + unsigned long spsr_el1, elr_el1, sp_el0; +} trapframe_t; + +#endif \ No newline at end of file diff --git a/include/uart.h b/include/uart.h index a642e6518..8e43c908a 100644 --- a/include/uart.h +++ b/include/uart.h @@ -1,8 +1,10 @@ #ifndef UART_H #define UART_H #include "gpio.h" +#include "sprintf.h" +#include "exception.h" -#define MAX_BUF_SIZE 0x100 +#define MAX_BUF_SIZE 0x1000 #define IRQS1 ((volatile unsigned int*)(0x3f00b210)) diff --git a/include/vfs.h b/include/vfs.h new file mode 100644 index 000000000..769daab1c --- /dev/null +++ b/include/vfs.h @@ -0,0 +1,75 @@ +#ifndef VFS_H +#define VFS_H +#include "uart.h" +#include "node.h" +#include "string.h" +#include "malloc.h" +#include "tmpfs.h" + +#define MAX_FS_REG 256 +#define MAX_PATH_NAME 256 +#define O_CREAT 00000100 + +struct vnode { + struct mount *mount; + struct vnode_operations *v_ops; + struct file_operations *f_ops; + void *internal; +}; + +// file handle +struct file { + struct vnode *vnode; + unsigned long f_pos; // RW position of this file handle + struct file_operations *f_ops; + int flags; +}; + +// mounted file system +struct mount { + struct vnode *root; + struct filesystem *fs; +}; + +struct filesystem { + const char *name; + int (*setup_mount)(struct filesystem *fs, struct mount *mount); +}; + +struct file_operations { + int (*write)(struct file *file, const void *buf, unsigned long len); + int (*read)(struct file *file, void *buf, unsigned long len); + int (*open)(struct vnode *file_node, struct file **target); + int (*close)(struct file *file); + long (*getsize)(struct vnode *vnode); +}; + +struct vnode_operations { + int (*lookup)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*create)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*mkdir)(struct vnode *dir_node, struct vnode **target, + const char *component_name); +}; + +struct mount *rootfs; +struct filesystem reg_fs[MAX_FS_REG]; + +int register_filesystem(struct filesystem *fs); +struct filesystem *find_filesystem(const char *fs_name); + +// file operations +int vfs_write(struct file *file, const void *buf, unsigned long len); +int vfs_read(struct file *file, void *buf, unsigned long len); +int vfs_open(const char *pathname, int flags, struct file **target); +int vfs_close(struct file *file); +// vnode operations +int vfs_lookup(const char *pathname, struct vnode **target); +int vfs_mkdir(const char *pathname); +int vfs_mount(const char *target, const char *filesystem); + +void init_rootfs(); +char* path_to_absolute(char* path, char* curr_working_dir); + +#endif \ No newline at end of file diff --git a/initramfs.cpio b/initramfs.cpio index c755722c9..b42cbe5f7 100644 Binary files a/initramfs.cpio and b/initramfs.cpio differ diff --git a/kernel/boot.s b/kernel/boot.s index 76d3b9775..506583212 100644 --- a/kernel/boot.s +++ b/kernel/boot.s @@ -20,8 +20,10 @@ set_exception_vector_table: msr vbar_el1, x1 // set top of stack just before our code (stack grows to a lower address per AAPCS64) - ldr x1, =_start - mov sp, x1 + // ldr x1, =_start + // mov sp, x1 + // set top of stack at 0x3c000000 (last usable memory) + mov sp, 0x3c000000 // clear bss ldr x1, =_bss_start @@ -47,192 +49,3 @@ from_el2_to_el1: msr spsr_el2, x1 msr elr_el2, lr eret // return to EL1 - -// save general registers to stack -.macro save_all - sub sp, sp, 32 * 9 - stp x0, x1, [sp ,16 * 0] - stp x2, x3, [sp ,16 * 1] - stp x4, x5, [sp ,16 * 2] - stp x6, x7, [sp ,16 * 3] - stp x8, x9, [sp ,16 * 4] - stp x10, x11, [sp ,16 * 5] - stp x12, x13, [sp ,16 * 6] - stp x14, x15, [sp ,16 * 7] - stp x16, x17, [sp ,16 * 8] - stp x18, x19, [sp ,16 * 9] - stp x20, x21, [sp ,16 * 10] - stp x22, x23, [sp ,16 * 11] - stp x24, x25, [sp ,16 * 12] - stp x26, x27, [sp ,16 * 13] - stp x28, x29, [sp ,16 * 14] - str x30, [sp, 16 * 15] - -// for nested interrupt - mrs x0, spsr_el1 - str x0, [sp, 16 * 16] - mrs x0, elr_el1 - str x0, [sp, 16 * 17] - ldp x0, x1, [sp ,16 * 0] -.endm - -// load general registers from stack -.macro load_all - ldp x0, x1, [sp ,16 * 0] - ldp x2, x3, [sp ,16 * 1] - ldp x4, x5, [sp ,16 * 2] - ldp x6, x7, [sp ,16 * 3] - ldp x8, x9, [sp ,16 * 4] - ldp x10, x11, [sp ,16 * 5] - ldp x12, x13, [sp ,16 * 6] - ldp x14, x15, [sp ,16 * 7] - ldp x16, x17, [sp ,16 * 8] - ldp x18, x19, [sp ,16 * 9] - ldp x20, x21, [sp ,16 * 10] - ldp x22, x23, [sp ,16 * 11] - ldp x24, x25, [sp ,16 * 12] - ldp x26, x27, [sp ,16 * 13] - ldp x28, x29, [sp ,16 * 14] - ldr x30, [sp, 16 * 15] - -// for nested interrupt - ldr x0, [sp, 16 * 16] - msr spsr_el1, x0 - ldr x0, [sp, 16 * 17] - msr elr_el1, x0 - ldp x0, x1, [sp ,16 * 0] - - add sp, sp, 32 * 9 -.endm - -.macro ventry label - .align 7 - b \label -.endm - -.align 11 // vector table should be aligned to 0x800 -.global exception_vector_table -exception_vector_table: - // Exception from the current EL while using SP_EL0 - ventry sync_el1t_invalid // Synchronous EL1t - ventry irq_el1t_invalid // IRQ EL1t - ventry fiq_el1t_invalid // FIQ EL1t - ventry err_el1t_invalid // Error EL1t - - // Exception from the current EL while using SP_ELx - ventry sync_el1h_invalid // Synchronous EL1h - ventry irq_el1h // IRQ EL1h - ventry fiq_el1h_invalid // FIQ EL1h - ventry err_el1h_invalid // Error EL1h - - // Exception from a lower EL and at least one lower EL is AArch64 - ventry sync_el0_64 // Synchronous 64-bit EL0 - ventry irq_el0_64 // IRQ 64-bit EL0 - ventry fiq_el0_64_invalid // FIQ 64-bit EL0 - ventry err_el0_64_invalid // Error 64-bit EL0 - - // Exception from a lower EL and at least all lower EL are AArch32 - ventry sync_el0_32_invalid // Synchronous 32-bit EL0 - ventry irq_el0_32_invalid // IRQ 32-bit EL0 - ventry fiq_el0_32_invalid // FIQ 32-bit EL0 - ventry err_el0_32_invalid // Error 32-bit EL0 - -sync_el1t_invalid: - save_all - mov x0, 1 - bl invalid_exception_router - load_all - eret -irq_el1t_invalid: - save_all - mov x0, 2 - bl invalid_exception_router - load_all - eret -fiq_el1t_invalid: - save_all - mov x0, 3 - bl invalid_exception_router - load_all - eret -err_el1t_invalid: - save_all - mov x0, 4 - bl invalid_exception_router - load_all - eret - -sync_el1h_invalid: - save_all - mov x0, 5 - bl invalid_exception_router - load_all - eret -irq_el1h: - save_all - mov x0, 6 - bl irq_router - load_all - eret -fiq_el1h_invalid: - save_all - mov x0, 7 - bl invalid_exception_router - load_all - eret -err_el1h_invalid: - save_all - mov x0, 8 - bl invalid_exception_router - load_all - eret - -sync_el0_64: - save_all - mov x0, 9 - bl sync64_router - load_all - eret -irq_el0_64: - save_all - mov x0, 10 - bl irq_router - load_all - eret -fiq_el0_64_invalid: - save_all - mov x0, 11 - bl invalid_exception_router - load_all - eret -err_el0_64_invalid: - save_all - mov x0, 12 - bl invalid_exception_router - load_all - eret - -sync_el0_32_invalid: - save_all - mov x0, 13 - bl invalid_exception_router - load_all - eret -irq_el0_32_invalid: - save_all - mov x0, 14 - bl invalid_exception_router - load_all - eret -fiq_el0_32_invalid: - save_all - mov x0, 15 - bl invalid_exception_router - load_all - eret -err_el0_32_invalid: - save_all - mov x0, 16 - bl invalid_exception_router - load_all - eret diff --git a/kernel/buddy.c b/kernel/buddy.c index 594fcde18..108b020d4 100644 --- a/kernel/buddy.c +++ b/kernel/buddy.c @@ -91,7 +91,6 @@ void page_alloc_init() { } void *alloc_pages(int num) { - uart_printf("------------ In function alloc_pages(%d) ------------\r\n", num); int idx, exp, alloc_exp; frame_hdr *hdr; @@ -113,7 +112,7 @@ void *alloc_pages(int num) { return 0; // start allocate - hdr = freelists[alloc_exp].next; + hdr = (frame_hdr *)freelists[alloc_exp].next; idx = addr_to_idx(hdr); list_del_entry(&hdr->list); @@ -130,12 +129,10 @@ void *alloc_pages(int num) { buddy_hdr = idx_to_addr(buddy_idx); list_add(&buddy_hdr->list, &freelists[alloc_exp]); - uart_printf("[-] Release redundant memory (idx : %d -> %d), this block has exp : %d\r\n", idx, buddy_idx, alloc_exp); } frame_ents[idx].exp = exp; frame_ents[idx].allocated = 1; - uart_printf("[+] Successfully allocate (idx : %d, exp : %d)\r\n", idx, exp); return (void *)hdr; } @@ -149,7 +146,6 @@ static inline void _free_page(frame_hdr *page) { buddy_idx = idx ^ (1 << exp); // merge while (exp < MAX_ORDER - 1 && !frame_ents[buddy_idx].allocated && frame_ents[buddy_idx].exp == exp) { - uart_printf("[*] Coalesce blocks (idx : %d & %d), and their new exp is %d\r\n", idx, buddy_idx, exp + 1); frame_hdr *hdr; exp += 1; hdr = idx_to_addr(idx); @@ -166,11 +162,11 @@ static inline void _free_page(frame_hdr *page) { } void free_page(void *page) { - uart_printf("++++++++++++ In function free_page(idx = %d) ++++++++++++\r\n", addr_to_idx(page)); _free_page((frame_hdr *)page); } void memory_reserve(void *start, void *end) { + uart_printf("Reserve => 0x%x ~ 0x%x\r\n", (unsigned long long int)start, (unsigned long long int)end); start = (void *)((unsigned long long int)start & ~(PAGE_SIZE - 1)); end = (void *)ALIGN((unsigned long long int)end, PAGE_SIZE); // allocated all pages from start to end @@ -178,7 +174,6 @@ void memory_reserve(void *start, void *end) { int idx = addr_to_idx(start); frame_ents[idx].allocated = 1; start = (void *)((unsigned long long int)start + PAGE_SIZE); - // uart_printf("Reserve page idx : %d, address : 0x%x\r\n", idx, idx_to_addr(idx)); } } @@ -193,8 +188,12 @@ void mm_init() { memory_reserve(&_text_start, &_heap_start); // Initramfs memory_reserve(INITRD_ADDR, INITRD_END); + // Device tree (qemu = 83580, rpi3 = 32937) + memory_reserve(DTB_ADDRESS, DTB_ADDRESS + 83580); // for simple_alloc - memory_reserve((void *)0x3b000000, (void *)0x3c000000); + memory_reserve((void *)0x2c000000, (void *)0x2e000000); + // for kernel stack + memory_reserve((void *)0x2e000000, (void *)0x3c000000); // buddy system second stage init page_alloc_init(); // small chunk second stage init @@ -211,23 +210,17 @@ void page_allocator_test() char *ptr5 = alloc_pages(2); // idx = 32786 char *ptr6 = alloc_pages(1); // idx = 32785 - uart_printf("------------------------------------------------------------\r\n"); - // test alloc_pages -> release redundant memory free_page(ptr3); // idx = 4 (idx 5, 6, 7 are also freed) char *ptr7 = alloc_pages(1); // idx = 4 (split ptr3) char *ptr8 = alloc_pages(2); // idx = 6 char *ptr9 = alloc_pages(1); // idx = 5 - uart_printf("------------------------------------------------------------\r\n"); - // test free_page -> coalesce blocks free_page(ptr7); free_page(ptr8); free_page(ptr9); - uart_printf("------------------------------------------------------------\r\n"); - // free all pointer free_page(ptr1); free_page(ptr2); diff --git a/kernel/cpio.c b/kernel/cpio.c index 380151633..ee4cc7891 100644 --- a/kernel/cpio.c +++ b/kernel/cpio.c @@ -2,6 +2,9 @@ cpio_newc_header* header; +char *syscall_file_start_addr; +unsigned int syscall_file_size; + void cpio_init() { header = 0; } @@ -34,7 +37,7 @@ void cpio_newc_parser(cpio_callback_t callback, char* param) { } void cpio_newc_parse_header(char** cpio_ptr, cpio_newc_header** header) { - *header = *cpio_ptr; + *header = (cpio_newc_header *)*cpio_ptr; *cpio_ptr += sizeof(cpio_newc_header); } @@ -59,7 +62,7 @@ void cpio_cat_callback(char* param, cpio_newc_header* header, char* file_name, u uart_write_string("\r\n"); else uart_write_char(*file_data); - *file_data++; + file_data++; } uart_printf("\r\n"); } @@ -77,3 +80,31 @@ void cpio_prog_callback(char* param, cpio_newc_header* header, char* file_name, :: "r" (file_data), "r" (prog_stack + 0x10000) ); } + +void cpio_get_file_start_callback(char* param, cpio_newc_header* header, char* file_name, unsigned int name_size, char* file_data, unsigned int data_size) { + if (strcmp(file_name, param)) + return; + syscall_file_start_addr = file_data; +} + +void cpio_get_file_size_callback(char* param, cpio_newc_header* header, char* file_name, unsigned int name_size, char* file_data, unsigned int data_size) { + if (strcmp(file_name, param)) + return; + syscall_file_size = data_size; +} + +char* get_file_start(char* path) { + cpio_newc_parser(cpio_get_file_start_callback, path); + return syscall_file_start_addr; +} + +unsigned int get_file_size(char* path) { + cpio_newc_parser(cpio_get_file_size_callback, path); + return syscall_file_size; +} + +void cpio_exec_callback(char* param, cpio_newc_header* header, char* file_name, unsigned int name_size, char* file_data, unsigned int data_size) { + if (strcmp(file_name, param)) + return; + exec_thread(file_data, data_size); +} diff --git a/kernel/ctx_switch.s b/kernel/ctx_switch.s new file mode 100644 index 000000000..ce2cafa4d --- /dev/null +++ b/kernel/ctx_switch.s @@ -0,0 +1,50 @@ +.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 store_context +store_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_context +load_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 + +.global get_current +get_current: + mrs x0, tpidr_el1 + ret diff --git a/kernel/dtb.c b/kernel/dtb.c index 5f55235c6..a0077a9f6 100644 --- a/kernel/dtb.c +++ b/kernel/dtb.c @@ -71,11 +71,11 @@ void dtb_parser(dtb_callback_t callback) { void dtb_get_initrd_callback(unsigned int token_type, char* name, char* data) { if (token_type == FDT_PROP && !strcmp(name, "linux,initrd-start")) { - INITRD_ADDR = BE_to_uint(data); + INITRD_ADDR = (void *)(unsigned long long int)BE_to_uint(data); uart_printf("Initramfs address: 0x%x\r\n", INITRD_ADDR); } if (token_type == FDT_PROP && !strcmp(name, "linux,initrd-end")) { - INITRD_END = BE_to_uint(data); + INITRD_END = (void *)(unsigned long long int)BE_to_uint(data); } } diff --git a/kernel/entry.s b/kernel/entry.s new file mode 100644 index 000000000..6c08de890 --- /dev/null +++ b/kernel/entry.s @@ -0,0 +1,195 @@ +// save general registers to stack +.global save_all +.macro save_all + sub sp, sp, 32 * 9 + stp x0, x1, [sp ,16 * 0] + stp x2, x3, [sp ,16 * 1] + stp x4, x5, [sp ,16 * 2] + stp x6, x7, [sp ,16 * 3] + stp x8, x9, [sp ,16 * 4] + stp x10, x11, [sp ,16 * 5] + stp x12, x13, [sp ,16 * 6] + stp x14, x15, [sp ,16 * 7] + stp x16, x17, [sp ,16 * 8] + stp x18, x19, [sp ,16 * 9] + stp x20, x21, [sp ,16 * 10] + stp x22, x23, [sp ,16 * 11] + stp x24, x25, [sp ,16 * 12] + stp x26, x27, [sp ,16 * 13] + stp x28, x29, [sp ,16 * 14] + str x30, [sp, 16 * 15] + +// for nested interrupt + mrs x0, spsr_el1 + str x0, [sp, 16 * 15 + 8] + mrs x0, elr_el1 + str x0, [sp, 16 * 16] + mrs x0, sp_el0 + str x0, [sp, 16 * 16 + 8] +// restore x0 + ldp x0, x1, [sp ,16 * 0] +.endm + +// load general registers from stack +.global load_all +.macro load_all + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + ldr x30, [sp, 16 * 15] + +// for nested interrupt + ldr x0, [sp, 16 * 15 + 8] + msr spsr_el1, x0 + ldr x0, [sp, 16 * 16] + msr elr_el1, x0 + ldr x0, [sp, 16 * 16 + 8] + msr sp_el0, x0 +// restore x0 + ldp x0, x1, [sp ,16 * 0] + add sp, sp, 32 * 9 +.endm + +.macro ventry label + .align 7 + b \label +.endm + +.align 11 // vector table should be aligned to 0x800 +.global exception_vector_table +exception_vector_table: + // Exception from the current EL while using SP_EL0 + ventry sync_el1t_invalid // Synchronous EL1t + ventry irq_el1t_invalid // IRQ EL1t + ventry fiq_el1t_invalid // FIQ EL1t + ventry err_el1t_invalid // Error EL1t + + // Exception from the current EL while using SP_ELx + ventry sync_el1h_invalid // Synchronous EL1h + ventry irq_el1h // IRQ EL1h + ventry fiq_el1h_invalid // FIQ EL1h + ventry err_el1h_invalid // Error EL1h + + // Exception from a lower EL and at least one lower EL is AArch64 + ventry sync_el0_64 // Synchronous 64-bit EL0 + ventry irq_el0_64 // IRQ 64-bit EL0 + ventry fiq_el0_64_invalid // FIQ 64-bit EL0 + ventry err_el0_64_invalid // Error 64-bit EL0 + + // Exception from a lower EL and at least all lower EL are AArch32 + ventry sync_el0_32_invalid // Synchronous 32-bit EL0 + ventry irq_el0_32_invalid // IRQ 32-bit EL0 + ventry fiq_el0_32_invalid // FIQ 32-bit EL0 + ventry err_el0_32_invalid // Error 32-bit EL0 + +sync_el1t_invalid: + // save_all + mov x0, 1 + bl invalid_exception_router + // load_all + eret +irq_el1t_invalid: + save_all + mov x0, 2 + bl invalid_exception_router + load_all + eret +fiq_el1t_invalid: + save_all + mov x0, 3 + bl invalid_exception_router + load_all + eret +err_el1t_invalid: + save_all + mov x0, 4 + bl invalid_exception_router + load_all + eret + +sync_el1h_invalid: + // save_all + mov x0, 5 + bl invalid_exception_router + // load_all + eret +irq_el1h: + save_all + mov x0, sp // trap frame + bl irq_router + load_all + eret +fiq_el1h_invalid: + save_all + mov x0, 7 + bl invalid_exception_router + load_all + eret +err_el1h_invalid: + save_all + mov x0, 8 + bl invalid_exception_router + load_all + eret + +sync_el0_64: + save_all + mov x0, sp // trap frame + bl sync64_router + load_all + eret +irq_el0_64: + save_all + mov x0, sp // trap frame + bl irq_router + load_all + eret +fiq_el0_64_invalid: + save_all + mov x0, 11 + bl invalid_exception_router + load_all + eret +err_el0_64_invalid: + save_all + mov x0, 12 + bl invalid_exception_router + load_all + eret + +sync_el0_32_invalid: + save_all + mov x0, 13 + bl invalid_exception_router + load_all + eret +irq_el0_32_invalid: + save_all + mov x0, 14 + bl invalid_exception_router + load_all + eret +fiq_el0_32_invalid: + save_all + mov x0, 15 + bl invalid_exception_router + load_all + eret +err_el0_32_invalid: + save_all + mov x0, 16 + bl invalid_exception_router + load_all + eret diff --git a/kernel/exception.c b/kernel/exception.c index 1063843a7..0c1579d06 100644 --- a/kernel/exception.c +++ b/kernel/exception.c @@ -1,14 +1,49 @@ #include "exception.h" -void sync64_router(unsigned long long x0) { - unsigned long long spsr_el1, elr_el1, esr_el1; - asm volatile("mrs %0, spsr_el1\n\t" : "=r" (spsr_el1) :: "memory"); - asm volatile("mrs %0, elr_el1\n\t" : "=r" (elr_el1) :: "memory"); - asm volatile("mrs %0, esr_el1\n\t" : "=r" (esr_el1) :: "memory"); - uart_printf("Exception : sync_el0_64, SPSR_EL1 : 0x%x, ELR_EL1 : 0x%x, ESR_EL1 : 0x%x\r\n", spsr_el1, elr_el1, esr_el1); +void sync64_router(trapframe_t *tpf) { + // for sys call + enable_interrupt(); + unsigned long long syscall_no = tpf->x8; + + if (syscall_no == 0) + getpid(tpf); + else if (syscall_no == 1) + uartread(tpf, (char *)tpf->x0, tpf->x1); + else if (syscall_no == 2) + uartwrite(tpf, (char *)tpf->x0, tpf->x1); + else if (syscall_no == 3) + exec(tpf, (char *)tpf->x0, (char **)tpf->x1); + else if (syscall_no == 4) + fork(tpf); + else if (syscall_no == 5) + exit(tpf, tpf->x0); + else if (syscall_no == 6) + syscall_mbox_call(tpf, (unsigned char)tpf->x0, (unsigned int *)tpf->x1); + else if (syscall_no == 7) + kill(tpf, (int)tpf->x0); + else if (syscall_no == 8) + signal_register(tpf->x0, (void (*)())tpf->x1); + else if (syscall_no == 9) + signal_kill(tpf->x0, tpf->x1); + else if (syscall_no == 11) + sys_open(tpf, (char*)tpf->x0, tpf->x1); + else if (syscall_no == 12) + sys_close(tpf, tpf->x0); + else if (syscall_no == 13) + sys_write(tpf, tpf->x0, (char *)tpf->x1, tpf->x2); + else if (syscall_no == 14) + sys_read(tpf, tpf->x0, (char *)tpf->x1, tpf->x2); + else if (syscall_no == 15) + sys_mkdir(tpf, (char *)tpf->x0, tpf->x1); + else if (syscall_no == 16) + sys_mount(tpf, (char *)tpf->x0, (char *)tpf->x1, (char *)tpf->x2, tpf->x3, (void*)tpf->x4); + else if (syscall_no == 17) + sys_chdir(tpf, (char *)tpf->x0); + else if (syscall_no == 31) + sigreturn(tpf); } -void irq_router(unsigned long long x0) { +void irq_router(trapframe_t *tpf) { // from core timer (CNTPNS) IRQ_EL0_64 if (*CORE0_INTERRUPT_SOURCE & INTERRUPT_SOURCE_CNTPNSIRQ) { // masks the device’s interrupt line @@ -19,6 +54,10 @@ void irq_router(unsigned long long x0) { run_preemptive_tasks(); // unmasks the device’s interrupt line core_timer_enable(); + + // at least 2 thread running -> schedule for any timer IRQ + if (run_queue->next->next != run_queue) + schedule(); } // from uart (AUX_INT && GPU0) IRQ_EL1h else if (*IRQ_PENDING_1 & IRQ_PENDING_1_AUX_INT && *CORE0_INTERRUPT_SOURCE & INTERRUPT_SOURCE_GPU) { @@ -41,6 +80,11 @@ void irq_router(unsigned long long x0) { } // can read else if (*AUX_MU_IIR_REG & (0b10 << 1)) { + // NOT SURE == clear fifo + if (!mini_uart_r_interrupt_is_enable()) { + *AUX_MU_IIR_REG = 0xc2; + return; + } // masks the device’s interrupt line (enable by handler) disable_mini_uart_r_interrupt(); // uart IRQ priority = 200 @@ -49,9 +93,14 @@ void irq_router(unsigned long long x0) { run_preemptive_tasks(); } else { - uart_printf("------ UNKNOWN ------\r\n"); + uart_printf("------ UNKNOWN IRQ from UART ------\r\n"); } } + + // only run signal handler when return to user mode + if ((tpf->spsr_el1 & 0b1100) == 0) { + check_signal(tpf); + } } void invalid_exception_router(unsigned long long x0) { @@ -61,10 +110,25 @@ void invalid_exception_router(unsigned long long x0) { while (1); } -void enable_interrupt() { - asm volatile("msr daifclr, 0xf"); +// 0 => enable, 1 => disable +unsigned long long is_disable_interrupt() { + unsigned long long daif; + asm volatile("mrs %0, daif\n\t" : "=r"(daif)); + return daif; } -void disable_interrupt() { - asm volatile("msr daifset, 0xf"); +static unsigned long long lock_count = 0; +void lock() { + disable_interrupt(); + lock_count++; +} + +void unlock() { + lock_count--; + if (lock_count < 0) { + uart_printf("Error : unlock()\r\n"); + while(1); + } + if (lock_count == 0) + enable_interrupt(); } diff --git a/kernel/linker.ld b/kernel/linker.ld index 51a4f53f9..0e69a3494 100644 --- a/kernel/linker.ld +++ b/kernel/linker.ld @@ -1,8 +1,8 @@ /* entry point */ ENTRY(_start) -_simple_alloc_start = 0x3b000000; -_simple_alloc_end = 0x3bffffff; +_simple_alloc_start = 0x2c000000; +_simple_alloc_end = 0x2dffffff; SECTIONS { diff --git a/kernel/main.c b/kernel/main.c index 14a9aaccb..5a21f18fb 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -1,11 +1,25 @@ #include "dtb.h" +#include "cpio.h" +#include "task.h" +#include "shell.h" +#include "buddy.h" +#include "exception.h" +#include "vfs.h" void kernel_main(char* x0) { + // init dtb dtb_init(x0); - + // init memory + mm_init(); + // init file system + init_rootfs(); + // init task task_list_init(); - enable_mini_uart_interrupt(); + // enable interrupt + // enable_mini_uart_interrupt(); enable_interrupt(); // enable interrupt in EL1 -> EL1 + // init cpio (unnecessary) + cpio_init(); shell(); } \ No newline at end of file diff --git a/kernel/makefile b/kernel/makefile index b61af5544..22f4753a1 100644 --- a/kernel/makefile +++ b/kernel/makefile @@ -1,4 +1,4 @@ -CROSS = aarch64-unknown-linux-gnu +CROSS = aarch64-linux-gnu CC = $(CROSS)-gcc CFLAGS = -Wall -ffreestanding -nostdinc -nostdlib -nostartfiles -g LD = $(CROSS)-ld @@ -7,17 +7,19 @@ OBJCPY = $(CROSS)-objcopy INCLUDE = -I ../include SRCS = $(wildcard ./*.c) OBJS = $(patsubst %.c, %.o, $(SRCS)) +SRCS_ASM = $(wildcard ./*.s) +OBJS_ASM = $(patsubst %.s, %.o, $(SRCS_ASM)) all: clean kernel8.img -boot.o: boot.s - $(CC) $(CFLAGS) $(INCLUDE) -c boot.s -o boot.o +%.o: %.s + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ %.o: %.c $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ -kernel8.img: boot.o $(OBJS) - $(LD) -nostdlib -nostartfiles boot.o $(OBJS) -T linker.ld -o kernel8.elf +kernel8.img: $(OBJS) $(OBJS_ASM) + $(LD) -nostdlib -nostartfiles $(OBJS) $(OBJS_ASM) -T linker.ld -o kernel8.elf $(OBJCPY) -O binary kernel8.elf kernel8.img clean: diff --git a/kernel/malloc.c b/kernel/malloc.c index 3d5d3ddb5..34adeed8f 100644 --- a/kernel/malloc.c +++ b/kernel/malloc.c @@ -39,7 +39,11 @@ void sc_init() { } void *sc_alloc(int size) { - uart_printf("------------ In function sc_alloc(0x%x) ------------\r\n", size); + if (size > 0x1000) { + uart_printf("Error : sc_alloc(size), size > 0x1000\r\n"); + return 0; + } + sc_hdr *hdr; unsigned int size_idx = find_size_idx(size); @@ -56,32 +60,29 @@ void *sc_alloc(int size) { hdr = (sc_hdr *)((char *)page + i); list_add_tail(&hdr->list, &sc_freelists[size_idx]); } - uart_printf("[+] In small chunk alloc (alloc page idx : %d, cut into chunk size : 0x%x)\r\n", frame_idx, sc_sizes[size_idx]); } // allocate this chunk and remove from free list - hdr = sc_freelists[size_idx].next; + hdr = (sc_hdr *)sc_freelists[size_idx].next; list_del_entry(&hdr->list); - uart_printf("[-] Successfully allocate a small chunk, addr : 0x%x, chunk size : 0x%x\r\n", hdr, sc_sizes[size_idx]); return hdr; } int sc_free(void *sc) { - uart_printf("++++++++++++ In function sc_free ++++++++++++\r\n"); sc_hdr *hdr; int frame_idx = addr_to_idx(sc); int size_idx; // this chunk is not managed by Small Chunk allocator - if (!sc_frame_ents[frame_idx].splitted) + if (!sc_frame_ents[frame_idx].splitted) { return -1; + } // add this chunk to free list size_idx = sc_frame_ents[frame_idx].size_idx; hdr = (sc_hdr *)sc; list_add(&hdr->list, &sc_freelists[size_idx]); - uart_printf("[+] Successfully free a chunk (addr : 0x%x, chunk size : 0x%x)\r\n", sc, sc_sizes[size_idx]); return 0; } @@ -105,3 +106,34 @@ void sc_test() { char *ptr6 = sc_alloc(0x369); // Allocate a page and create 0x400 chunks sc_free(ptr6); } + +void *kmalloc(int size) { + void *ret; + + lock(); + + if (size <= PAGE_SIZE) { + ret = sc_alloc(size); + } + else { + int page_cnt = ALIGN(size, PAGE_SIZE) / PAGE_SIZE; + ret = alloc_pages(page_cnt); + } + + unlock(); + + return ret; +} + +void kfree(void *ptr) { + lock(); + + if (!sc_free(ptr)) { + unlock(); + return; + } + + free_page(ptr); + unlock(); + return; +} diff --git a/kernel/mbox.c b/kernel/mbox.c index 4c81dfdcb..2730ecbb8 100644 --- a/kernel/mbox.c +++ b/kernel/mbox.c @@ -34,17 +34,17 @@ unsigned int mailbox_call(volatile unsigned int mbox[36], unsigned char ch){ /* Combine the message address (upper 28 bits) with channel number (lower 4 bits) */ unsigned int req = (((unsigned int)((unsigned long)mbox) & (~0xF)) | (ch & 0xF)); /* wait until we can write to the mailbox */ - while(*MAILBOX_STATUS & MAILBOX_FULL){asm volatile("nop");} + do{asm volatile("nop");}while(*MAILBOX_STATUS & MAILBOX_FULL); /* write the address of our message to the mailbox with channel identifier */ *MAILBOX_WRITE = req; /* now wait for the response */ - while(1){ + while (1) { /* wait the response signal */ - while(*MAILBOX_STATUS & MAILBOX_EMPTY){asm volatile("nop");} + do{asm volatile("nop");}while(*MAILBOX_STATUS & MAILBOX_EMPTY); /* read the response to compare our req and request_code */ if(req == *MAILBOX_READ) return mbox[1] == MAILBOX_RESPONSE; } return 0; -} +} \ No newline at end of file diff --git a/kernel/mmu.c b/kernel/mmu.c new file mode 100644 index 000000000..36833c6bb --- /dev/null +++ b/kernel/mmu.c @@ -0,0 +1,129 @@ +#include "mmu.h" + +// PGD's page frame at 0x1000 +// PUD's page frame at 0x2000 + +// 2-level translation (1GB) => 3-level translation (2MB) +void* set_2M_kernel_mmu(void *x0) { + // first entry (0x00000000 ~ 0x3FFFFFFF) + unsigned long *pud_table_1 = (unsigned long *)0x3000; + for (int i = 0; i < 512; i++) { + // 0x3F000000 to 0x3FFFFFFF for peripherals + if ((0x00000000 + (0x200000L) * i) >= 0x3F000000L) + pud_table_1[i] = PD_ACCESS | PD_BLOCK | (0x00000000 + (0x200000L) * i) | (MAIR_DEVICE_nGnRnE << 2) | PD_UK_ACCESS | PD_UNX | PD_KNX; + else + pud_table_1[i] = PD_ACCESS | PD_BLOCK | (0x00000000 | (0x200000L) * i) | (MAIR_IDX_NORMAL_NOCACHE << 2); + } + // second entry (0x40000000 ~ 0x7FFFFFFF) + unsigned long *pud_table_2 = (unsigned long *)0x4000; + for (int i = 0; i < 512; i++) + pud_table_2[i] = PD_ACCESS | PD_BLOCK | (0x40000000L | (0x200000L) * i) | (MAIR_IDX_NORMAL_NOCACHE << 2); + // set PUD + *(unsigned long *)(kernel_pud_addr) = PD_ACCESS | PD_TABLE | (unsigned long)pud_table_1; + *(unsigned long *)(kernel_pud_addr + 0x8) = PD_ACCESS | PD_TABLE | (unsigned long)pud_table_2; + + return x0; +} + +void map_one_page(unsigned long *virt_pgd_p, unsigned long va, unsigned long pa, unsigned long flag) { + unsigned long *table_p = virt_pgd_p; + for (int level = 0; level < 4; level++) { + // get index from VA + unsigned int idx = (va >> (39 - level * 9)) & 0x1ff; + // map page to table + if (level == 3) { + table_p[idx] = pa; + table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_KNX | flag; + return; + } + // malloc for empty entry + if (!table_p[idx]) { + unsigned long* newtable_p = kmalloc(0x1000); + memset(newtable_p, 0, 0x1000); + table_p[idx] = VIRT_TO_PHYS((unsigned long)newtable_p); + table_p[idx] |= PD_ACCESS | PD_TABLE | (MAIR_IDX_NORMAL_NOCACHE << 2); + } + // get next level entry + table_p = (unsigned long*)PHYS_TO_VIRT((unsigned long)(table_p[idx] & ENTRY_ADDR_MASK)); + } +} + +void add_vma(thread_t *t, unsigned long va, unsigned long size, unsigned long pa, unsigned long rwx, int is_alloced) { + // alignment + size = size % 0x1000 ? size + (0x1000 - size % 0x1000) : size; + + vm_area_struct_t *new_area = kmalloc(sizeof(vm_area_struct_t)); + new_area->rwx = rwx; + new_area->area_size = size; + new_area->virt_addr = va; + new_area->phys_addr = pa; + new_area->is_alloced = is_alloced; + list_add_tail((list_head_t *)new_area, &t->vma_list); +} + +void free_page_tables(unsigned long *page_table, int level) { + unsigned long *table_virt = (unsigned long*)PHYS_TO_VIRT((char*)page_table); + for (int i = 0; i < 512; i++) { + if (table_virt[i] != 0) { + unsigned long *next_table = (unsigned long*)(table_virt[i] & ENTRY_ADDR_MASK); + if (table_virt[i] & PD_TABLE) { + if (level!=2) { + free_page_tables(next_table, level + 1); + } + table_virt[i] = 0L; + kfree(PHYS_TO_VIRT((char *)next_table)); + } + } + } +} + +void handle_abort(esr_el1_t* esr_el1) { + // get fault VA + unsigned long long far_el1; + asm volatile("mrs %0, FAR_EL1\n\t" : "=r"(far_el1)); + // check if far_el1 is in VMA + list_head_t *pos; + vm_area_struct_t *the_area_ptr = 0; + list_for_each (pos, &curr_thread->vma_list) { + if (((vm_area_struct_t *)pos)->virt_addr <= far_el1 && ((vm_area_struct_t *)pos)->virt_addr + ((vm_area_struct_t *)pos)->area_size >= far_el1) { + the_area_ptr = (vm_area_struct_t *)pos; + break; + } + } + // far_el1 is not in VMA + if (!the_area_ptr) { + uart_printf("far_el1 is not in VMA\r\n"); + seg_fault(); + } + // for translation fault + if ((esr_el1->iss & 0x3f) == TF_LEVEL0 || (esr_el1->iss & 0x3f) == TF_LEVEL1 || (esr_el1->iss & 0x3f) == TF_LEVEL2 || (esr_el1->iss & 0x3f) == TF_LEVEL3) { + uart_printf("[Translation fault]: 0x%x\r\n", far_el1); + // offset align down 0x1000 + unsigned long addr_offset = (far_el1 - the_area_ptr->virt_addr); + addr_offset = (addr_offset % 0x1000) == 0 ? addr_offset : addr_offset - (addr_offset % 0x1000); + map_one_page_rwx(PHYS_TO_VIRT(curr_thread->context.ttbr0_el1), the_area_ptr->virt_addr + addr_offset, the_area_ptr->phys_addr + +addr_offset, the_area_ptr->rwx); + } + else { + seg_fault(); + } +} + +void map_one_page_rwx(unsigned long *pgd_p, unsigned long va, unsigned long pa, unsigned long rwxflag) { + unsigned long flag = 0; + // read + if (rwxflag & 0b1) + flag |= PD_UK_ACCESS; + // write + if (!(rwxflag & 0b10)) + flag |= PD_RDONLY; + // execute + if (!(rwxflag & 0b100)) + flag |= PD_UNX; + // map page + map_one_page(pgd_p, va, pa, flag); +} + +void seg_fault() { + uart_printf("[Segmentation fault]: Kill Process\r\n"); + thread_exit(); +} diff --git a/kernel/reset.c b/kernel/reset.c new file mode 100644 index 000000000..e5c1f046c --- /dev/null +++ b/kernel/reset.c @@ -0,0 +1,16 @@ +#include "reset.h" + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +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 +} diff --git a/kernel/sched.c b/kernel/sched.c new file mode 100644 index 000000000..d8582a7c3 --- /dev/null +++ b/kernel/sched.c @@ -0,0 +1,128 @@ +#include "sched.h" + +thread_t *curr_thread; +list_head_t *run_queue; +list_head_t *wait_queue; +thread_t threads[PIDMAX + 1]; + +void init_thread_sched() { + lock(); + run_queue = kmalloc(sizeof(list_head_t)); + wait_queue = kmalloc(sizeof(list_head_t)); + INIT_LIST_HEAD(run_queue); + INIT_LIST_HEAD(wait_queue); + + // init pids + for (int i = 0; i <= PIDMAX; i++) { + threads[i].pid = i; + threads[i].isused = 0; + threads[i].iszombie = 0; + } + // malloc a space for current kernel thread to prevent crash + asm volatile("msr tpidr_el1, %0" :: "r"(kmalloc(sizeof(thread_t)))); + + thread_t* idlethread = thread_create(idle); + curr_thread = idlethread; + unlock(); +} + +void idle() { + while (1) { + kill_zombies(); + schedule(); + } +} + +void schedule() { + lock(); + do { + curr_thread = (thread_t *)curr_thread->listhead.next; + } while (list_is_head(&curr_thread->listhead, run_queue) || curr_thread->iszombie); + switch_to(get_current(), &curr_thread->context); + unlock(); +} + +void kill_zombies() { + lock(); + list_head_t *curr; + list_for_each(curr, run_queue) { + if (((thread_t *)curr)->iszombie) { + list_del_entry(curr); + ((thread_t *)curr)->isused = 0; + ((thread_t *)curr)->iszombie = 0; + // free user stack & kernel stack + kfree(((thread_t *)curr)->stack_alloced_ptr); + kfree(((thread_t *)curr)->kernel_stack_alloced_ptr); + } + } + unlock(); +} + +thread_t *thread_create(void *start) { + lock(); + thread_t *r; + for (int i = 0; i <= PIDMAX; i++) { + if (!threads[i].isused) { + r = &threads[i]; + break; + } + } + + r->isused = 1; + r->iszombie = 0; + r->context.lr = (unsigned long long)start; + r->stack_alloced_ptr = kmalloc(USTACK_SIZE); + r->kernel_stack_alloced_ptr = kmalloc(KSTACK_SIZE); + r->context.sp = (unsigned long long )r->stack_alloced_ptr + USTACK_SIZE; + r->context.fp = r->context.sp; + r->signal_is_checking = 0; + memset(r->curr_working_dir, 0, 256); + memcpy(r->curr_working_dir, "/", 1); + + // initial signal handler with signal_default_handler (kill thread) + for (int i = 0; i < SIGNAL_MAX; i++) { + r->singal_handler[i] = signal_default_handler; + r->sigcount[i] = 0; + } + + list_add(&r->listhead, run_queue); + unlock(); + return r; +} + +void thread_exit() { + lock(); + curr_thread->iszombie = 1; + unlock(); + schedule(); +} + +int exec_thread(char *data, unsigned int filesize) { + thread_t *t = thread_create(data); + t->data = kmalloc(filesize); + t->datasize = filesize; + t->context.lr = (unsigned long)t->data; + // copy file into data + for (int i = 0; i < filesize; i++) + t->data[i] = data[i]; + + curr_thread = t; + add_timer(schedule_timer, 1, "", 0); + // eret to EL0 + asm volatile( + "msr spsr_el1, xzr\n\t" + "msr tpidr_el1, %0\n\t" + "msr elr_el1, %1\n\t" + "msr sp_el0, %2\n\t" + "mov sp, %3\n\t" + "eret\n\t" + :: "r"(&t->context), "r"(t->context.lr), "r"(t->context.sp), "r"(t->kernel_stack_alloced_ptr + KSTACK_SIZE) + ); + return 0; +} + +void schedule_timer(char *notuse) { + unsigned long long cntfrq_el0; + asm volatile("mrs %0, cntfrq_el0\n\t" : "=r"(cntfrq_el0)); + add_timer(schedule_timer, cntfrq_el0 >> 5, "", 1); +} diff --git a/kernel/shell.c b/kernel/shell.c index 5cba051b9..b810e6253 100644 --- a/kernel/shell.c +++ b/kernel/shell.c @@ -1,6 +1,27 @@ #include "shell.h" -char buf[0x100]; +char buf[0x1000]; + +struct cmd cmd_list[] = { + {"help", cmd_help, "print this help menu"}, + {"hello", cmd_hello, "print Hello World!"}, + // {"reboot", cmd_reboot, "reboot the device"}, + {"revision", cmd_revision, "print board revision"}, + {"memory", cmd_memory, "print ARM memory base address and size"}, + {"ls", cmd_ls, "list directory contents"}, + {"cat", cmd_cat, "print file content"}, + {"dtb", cmd_dtb, "show device tree"}, + {"initramfs", cmd_initramfs, "show initramfs address"}, + // {"async", cmd_async, "test async print"}, + // {"prog", cmd_prog, "load a user program in the initramfs, and jump to it"}, + // {"sec2", cmd_sec2, "print the seconds after booting and set the next timeout to 2 seconds later."}, + {"setTimeout",cmd_setTimeout,"prints message after seconds"}, + // {"testfoo", cmd_foo, "test thread"}, + // {"preempt", cmd_preempt, "test preemption"}, + // {"pageTest", cmd_pageTest, "test page frame allocator"}, + // {"chunkTest", cmd_chunkTest, "test small chunk allocator"}, + {"exec", cmd_exec, "run img file"}, +}; void welcome_msg() { uart_printf("************************************************\r\n"); @@ -11,7 +32,7 @@ void read_cmd() { unsigned int idx = 0; while (1) { // read char - c = uart_read_char_async(); + uart_read(&c, 1); // handle buffer switch (c) { case '\r': @@ -137,7 +158,7 @@ void cmd_prog(char* param) { } void cmd_sec2() { - add_timer(two_second_alert, 2, ""); + add_timer(two_second_alert, 2, "", 0); } void cmd_setTimeout(char* param) { @@ -150,15 +171,15 @@ void cmd_setTimeout(char* param) { msg[idx++] = '\n'; msg[idx++] = '\0'; char *seconds = param + 1; - add_timer(uart_write_string, atoi(seconds), msg); + add_timer(uart_write_string, atoi(seconds), msg, 0); } void cmd_preempt() { char tmp[0x100]; for (int i = 0; i < 0x100; i++) tmp[i] = ('A' + (i % 26)); - add_timer(uart_write_string, 1, "Timer\r\n"); - uart_write_string_async(tmp); + add_timer(uart_write_string, 1, "Timer\r\n", 0); + uart_write_string(tmp); } void cmd_pageTest() { @@ -169,18 +190,37 @@ void cmd_chunkTest() { sc_test(); } +void cmd_exec(char* param) { + cpio_newc_parser(cpio_exec_callback, param); +} + void cmd_unknown() { uart_printf("Err: command %s not found, try \r\n", buf); } -void shell() { - cpio_init(); - welcome_msg(); +void foo() { + for (int i = 0; i < 10; i++) { + uart_printf("Thread id : %d, i : %d\r\n", curr_thread->pid, i); + nop_delay(100000); + schedule(); + } + thread_exit(); +} - mm_init(); +void cmd_foo() { + for (int i = 0; i < 3; i++) { + thread_create(foo); + } + schedule(); +} +void shell() { + welcome_msg(); + // init thread scheduler + init_thread_sched(); + // init timer timer_list_init(); - core_timer_enable(); + core_timer_enable(); while (1) { uart_printf("# "); diff --git a/kernel/signal.c b/kernel/signal.c new file mode 100644 index 000000000..589bbe0e9 --- /dev/null +++ b/kernel/signal.c @@ -0,0 +1,60 @@ +#include "signal.h" + +void check_signal(trapframe_t *tpf) { + lock(); + // prevent nested signal handler + if (curr_thread->signal_is_checking) { + unlock(); + return; + } + curr_thread->signal_is_checking = 1; + unlock(); + + for (int i = 0; i <= SIGNAL_MAX; i++) { + // store context before running handler + store_context(&curr_thread->signal_saved_context); + // if there is a signal handler + if (curr_thread->sigcount[i] > 0) { + lock(); + curr_thread->sigcount[i]--; + unlock(); + run_signal(tpf, i); + } + } + lock(); + curr_thread->signal_is_checking = 0; + unlock(); +} + +void run_signal(trapframe_t* tpf, int signal) { + // assign signal handler + curr_thread->curr_signal_handler = curr_thread->singal_handler[signal]; + // run default handler in kernel mode + if (curr_thread->curr_signal_handler == signal_default_handler) { + signal_default_handler(); + return; + } + // run signal handler in user mode + char *temp_signal_userstack = kmalloc(USTACK_SIZE); + asm volatile( + "msr elr_el1, %0\n\t" + "msr sp_el0, %1\n\t" + "msr spsr_el1, %2\n\t" + "eret\n\t" + :: "r"(signal_handler_wrapper), "r"(temp_signal_userstack + USTACK_SIZE), "r"(tpf->spsr_el1) + ); +} + +void signal_handler_wrapper() { + // run signal handler + (curr_thread->curr_signal_handler)(); + // sigreturn + asm volatile( + "mov x8, 31\n\t" + "svc 0\n\t" + ); +} + +void signal_default_handler() { + kill(0, curr_thread->pid); +} diff --git a/kernel/string.c b/kernel/string.c new file mode 100644 index 000000000..3b6c025ee --- /dev/null +++ b/kernel/string.c @@ -0,0 +1,131 @@ +#include "string.h" + +void memcpy(char *s1, char *s2, unsigned int len) { + for (unsigned int i = 0; i < len; i++) + s1[i] = s2[i]; +} + +void memset(char *s1, char c, unsigned int len) { + for (unsigned int i = 0; i < len; i++) + s1[i] = c; +} + +unsigned int strlen(char *s) { + unsigned int len = 0; + while (1) { + if (*(s + len) == '\0') + break; + len++; + } + return len; +} + +int strcmp(char *s1, char *s2) { + unsigned int i = 0; + for (i = 0; i < strlen(s1); i++) { + if (s1[i] != s2[i]) + return s1[i] - s2[i]; + } + return s1[i] - s2[i]; +} + +int strncmp(char *s1, char *s2, unsigned int n) { + unsigned int i = 0; + for (i = 0; i < n; i++) { + if (s1[i] != s2[i]) + return s1[i] - s2[i]; + } + return 0; +} + +void strrev(char *s) { + unsigned int len = strlen(s); + char tmp; + for(unsigned int i = 0; i < len/2; i++){ + tmp = s[i]; + s[i] = s[len-i-1]; + s[len-i-1] = tmp; + } +} + +// string to int +int atoi(char* s) { + int res = 0; + for (int i = 0; s[i] != '\0'; ++i) { + if(s[i] > '9' || s[i] < '0') + return res; + res = res * 10 + s[i] - '0'; + } + return res; +} + +// int to string +char* itoa(int x, char *str) { + int i = 0, negative = 0; + // handle 0 explicitly + if (x == 0) { + str[i++] = '0'; + str[i] = '\0'; + return str; + } + // handle negative numbers + if (x < 0) { + negative = 1; + x = -x; + } + // process individual digits + while (x != 0) { + str[i++] = x % 10 + '0'; + x = x / 10; + } + if (negative) + str[i++] = '-'; + str[i] = '\0'; + strrev(str); + return str; +} + +// unsigned int to hex string +void uint_to_hex(unsigned int x, char *s) { + int i = 0, rem = 0, len = strlen(s); + memset(s, 0, len); + // handle 0 explicitly + if (x == 0) { + s[i++] = '0'; + s[i] = '\0'; + return ; + } + // process individual digits + while (x != 0) { + rem = x % 16; + if (rem >= 10) + s[i++] = rem - 10 + 'A'; + else + s[i++] = rem + '0'; + x = x / 16; + } + s[i] = '\0'; + strrev(s); +} + +// hex string to unsigned int +unsigned int hex_to_uint(char *s, unsigned int size) { + unsigned int ret = 0; + for (unsigned int i = 0; i < size; i++) { + ret *= 16; + if (s[i] >= '0' && s[i] <= '9') { + ret += s[i] - '0'; + } else if (s[i] >= 'a' && s[i] <= 'f') { + ret += s[i] - 'a' + 10; + } else if (s[i] >= 'A' && s[i] <= 'F') { + ret += s[i] - 'A' + 10; + } + } + return ret; +} + +// big endian to unsigned int +unsigned int BE_to_uint(void *ptr) { + unsigned char *bytes = (unsigned char *)ptr; + return bytes[3] | bytes[2] << 8 | bytes[1] << 16 | bytes[0] << 24; +} diff --git a/kernel/syscall.c b/kernel/syscall.c new file mode 100644 index 000000000..4c69423da --- /dev/null +++ b/kernel/syscall.c @@ -0,0 +1,269 @@ +#include "syscall.h" + +// syscall no 0 +int getpid(trapframe_t *tpf) { + tpf->x0 = curr_thread->pid; + return curr_thread->pid; +} + +// syscall no 1 +unsigned long uartread(trapframe_t *tpf, char buf[], unsigned long size) { + int i = 0; + for (int i = 0; i < size; i++) + uart_read(&buf[i], 1); + tpf->x0 = i; + return i; +} + +// syscall no 2 +unsigned long uartwrite(trapframe_t *tpf, const char buf[], unsigned long size) { + int i = 0; + for (int i = 0; i < size; i++) + uart_write_char(buf[i]); + tpf->x0 = i; + return i; +} + +// syscall no 3 +int exec(trapframe_t *tpf, const char *name, char *const argv[]) { + // curr_thread->datasize = get_file_size((char*)name); + // char *new_data = get_file_start((char *)name); + // use VFS + char abs_path[MAX_PATH_NAME]; + memset(abs_path, 0, MAX_PATH_NAME); + memcpy(abs_path, name, strlen(name)); + path_to_absolute(abs_path, curr_thread->curr_working_dir); + + struct vnode *target_file; + vfs_lookup(abs_path, &target_file); + curr_thread->datasize = target_file->f_ops->getsize(target_file); + + // copy data + // for (unsigned int i = 0; i < curr_thread->datasize; i++) + // curr_thread->data[i] = new_data[i]; + // use VFS + struct file *tmp_file; + vfs_open(abs_path, 0, &tmp_file); + vfs_read(tmp_file, curr_thread->data, curr_thread->datasize); + vfs_close(tmp_file); + + // clear signal handler + for (int i = 0; i <= SIGNAL_MAX; i++) + curr_thread->singal_handler[i] = signal_default_handler; + // set return address, stack pointer and return value + tpf->elr_el1 = (unsigned long)curr_thread->data; + tpf->sp_el0 = (unsigned long)curr_thread->stack_alloced_ptr + USTACK_SIZE; + tpf->x0 = 0; + return 0; +} + +// syscall no 4 +int fork(trapframe_t *tpf) { + lock(); + thread_t *newt = thread_create(curr_thread->data); + + // copy signal handler + for (int i = 0; i <= SIGNAL_MAX; i++) + newt->singal_handler[i] = curr_thread->singal_handler[i]; + + newt->datasize = curr_thread->datasize; + int parent_pid = curr_thread->pid; + thread_t *parent_thread_t = curr_thread; + + // can not copy data because there are a lot of ret addresses on stack + // copy user stack into new process + for (int i = 0; i < USTACK_SIZE; i++) + newt->stack_alloced_ptr[i] = curr_thread->stack_alloced_ptr[i]; + // copy kernel stack into new process + for (int i = 0; i < KSTACK_SIZE; i++) + newt->kernel_stack_alloced_ptr[i] = curr_thread->kernel_stack_alloced_ptr[i]; + + store_context(get_current()); + // child + if (parent_pid != curr_thread->pid) { + // move trapframe + tpf = (trapframe_t*)((char *)tpf + (unsigned long)newt->kernel_stack_alloced_ptr - (unsigned long)parent_thread_t->kernel_stack_alloced_ptr); + tpf->sp_el0 += newt->stack_alloced_ptr - parent_thread_t->stack_alloced_ptr; + tpf->x0 = 0; + return 0; + } + // parent + else { + newt->context = curr_thread->context; + // move fp + newt->context.fp += newt->kernel_stack_alloced_ptr - curr_thread->kernel_stack_alloced_ptr; + // move kernel sp + newt->context.sp += newt->kernel_stack_alloced_ptr - curr_thread->kernel_stack_alloced_ptr; + + unlock(); + + tpf->x0 = newt->pid; + return newt->pid; + } +} + +// syscall no 5 +void exit(trapframe_t *tpf, int status) { + thread_exit(); +} + +// syscall no 6 +int syscall_mbox_call(trapframe_t *tpf, unsigned char ch, unsigned int *mbox) { + lock(); + unsigned int req = (((unsigned int)((unsigned long)mbox) & (~0xF)) | (ch & 0xF)); + do{asm volatile("nop");}while(*MAILBOX_STATUS & MAILBOX_FULL); + *MAILBOX_WRITE = req; + while (1) { + do{asm volatile("nop");}while(*MAILBOX_STATUS & MAILBOX_EMPTY); + if(req == *MAILBOX_READ) { + tpf->x0 = (mbox[1] == MAILBOX_RESPONSE); + unlock(); + return mbox[1] == MAILBOX_RESPONSE; + } + } + tpf->x0 = 0; + unlock(); + return 0; +} + +// syscall no 7 +void kill(trapframe_t *tpf, int pid) { + lock(); + // check for invalid pid + if (pid >= PIDMAX || pid < 0 || !threads[pid].isused) { + unlock(); + return; + } + + threads[pid].iszombie = 1; + unlock(); + schedule(); +} + +// syscall no 8 +void signal_register(int signal, void (*handler)()) { + // invalid signal + if (signal > SIGNAL_MAX || signal < 0) + return; + curr_thread->singal_handler[signal] = handler; +} + +// syscall no 9 +void signal_kill(int pid, int signal) { + // check for invalid pid + if (pid >= PIDMAX || pid < 0 || !threads[pid].isused) + return; + lock(); + threads[pid].sigcount[signal]++; + unlock(); +} + +// syscall no 31 +void sigreturn(trapframe_t *tpf) { + unsigned long signal_ustack; + if (tpf->sp_el0 % USTACK_SIZE == 0) + signal_ustack = tpf->sp_el0 - USTACK_SIZE; + else + signal_ustack = tpf->sp_el0 & (~(USTACK_SIZE - 1)); + kfree((char*)signal_ustack); + load_context(&curr_thread->signal_saved_context); +} + +// syscall no 11 +int sys_open(trapframe_t *tpf, const char *pathname, int flags) { + // set pathname to absolutely path + char abs_path[MAX_PATH_NAME]; + memset(abs_path, 0, MAX_PATH_NAME); + memcpy(abs_path, pathname, strlen(pathname)); + path_to_absolute(abs_path, curr_thread->curr_working_dir); + // open + for (int i = 0; i < MAX_FD; i++) { + // find empty fd + if (!curr_thread->file_descriptors_table[i]) { + // vfs_open fail + if (vfs_open(abs_path, flags, &curr_thread->file_descriptors_table[i]) != 0) + break; + // normal case + tpf->x0 = i; + return i; + } + } + // open fail + tpf->x0 = -1; + return -1; +} + +// syscall no 12 +int sys_close(trapframe_t *tpf, int fd) { + // file exist + if (curr_thread->file_descriptors_table[fd]) { + vfs_close(curr_thread->file_descriptors_table[fd]); + curr_thread->file_descriptors_table[fd] = 0; + tpf->x0 = 0; + return 0; + } + // else close fail + tpf->x0 = -1; + return -1; +} + +// syscall no 13 +long sys_write(trapframe_t *tpf, int fd, const void *buf, unsigned long count) { + // file exist + if (curr_thread->file_descriptors_table[fd]) { + tpf->x0 = vfs_write(curr_thread->file_descriptors_table[fd], buf, count); + return tpf->x0; + } + // else write fail + tpf->x0 = -1; + return tpf->x0; +} + +// syscall no 14 +long sys_read(trapframe_t *tpf, int fd, void *buf, unsigned long count) { + // file exist + if (curr_thread->file_descriptors_table[fd]) { + tpf->x0 = vfs_read(curr_thread->file_descriptors_table[fd], buf, count); + return tpf->x0; + } + // else read fail + tpf->x0 = -1; + return tpf->x0; +} + +// syscall no 15 +int sys_mkdir(trapframe_t *tpf, const char *pathname, unsigned mode) { + // set pathname to absolutely path + char abs_path[MAX_PATH_NAME]; + memset(abs_path, 0, MAX_PATH_NAME); + memcpy(abs_path, pathname, strlen(pathname)); + path_to_absolute(abs_path, curr_thread->curr_working_dir); + // mkdir + tpf->x0 = vfs_mkdir(abs_path); + return tpf->x0; +} + +// syscall no 16 +int sys_mount(trapframe_t *tpf, const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data) { + // set pathname to absolutely path + char abs_path[MAX_PATH_NAME]; + memset(abs_path, 0, MAX_PATH_NAME); + memcpy(abs_path, target, strlen(target)); + path_to_absolute(abs_path, curr_thread->curr_working_dir); + // mount + tpf->x0 = vfs_mount(abs_path, filesystem); + return tpf->x0; +} + +// syscall no 17 +int sys_chdir(trapframe_t *tpf, const char *path) { + // set pathname to absolutely path + char abs_path[MAX_PATH_NAME]; + memset(abs_path, 0, MAX_PATH_NAME); + memcpy(abs_path, path, strlen(path)); + path_to_absolute(abs_path, curr_thread->curr_working_dir); + // modify curr_working_dir + memset(curr_thread->curr_working_dir, 0, 255); + memcpy(curr_thread->curr_working_dir, abs_path, strlen(abs_path)); + return 0; +} diff --git a/kernel/task.c b/kernel/task.c index 78e34f074..c0ed7f36b 100644 --- a/kernel/task.c +++ b/kernel/task.c @@ -6,23 +6,19 @@ int curr_priority = 9999; struct list_head *task_list; void task_list_init() { + task_list = kmalloc(sizeof(list_head_t)); INIT_LIST_HEAD(task_list); } void add_task(void *function, unsigned long long priority) { - task_t *tmp_task = simple_alloc(sizeof(task_t)); + task_t *tmp_task = kmalloc(sizeof(task_t)); // store function into task tmp_task->func = function; // store priority into task tmp_task->priority = priority; - // init list head - INIT_LIST_HEAD(&tmp_task->listhead); - - // critical section - disable_interrupt(); - // add tmp_task into task_list (sorted) + lock(); struct list_head *curr; list_for_each(curr, task_list) { if (((task_t *)curr)->priority > tmp_task->priority) { @@ -35,41 +31,38 @@ void add_task(void *function, unsigned long long priority) { if (list_is_head(curr, task_list)) list_add_tail(&tmp_task->listhead, task_list); - enable_interrupt(); + unlock(); } void run_preemptive_tasks() { - // do the tasks with interrupts enabled - enable_interrupt(); - - while (!list_empty(task_list)) { + while (1) { // critical section - disable_interrupt(); + lock(); + + // if there is no task + if (list_empty(task_list)) { + unlock(); + break; + } task_t *tmp_task = (task_t *)task_list->next; // check for preemption if (tmp_task->priority >= curr_priority) { - enable_interrupt(); + unlock(); break; } - // verify preemption - // if (curr_priority != 9999) { - // uart_printf("---preemption---\r\n"); - // uart_printf("task priority : %d, curr priority %d\r\n", tmp_task->priority, curr_priority); - // } list_del_entry((struct list_head *)tmp_task); // store previous task priority. if there is not preemption => prev_priority = 9999 int prev_priority = curr_priority; // before running the task, set its priority to curr_priority curr_priority = tmp_task->priority; - enable_interrupt(); // run task + unlock(); ((void (*)())tmp_task->func)(); // after running the task, set prev_priority equals to curr_priority - disable_interrupt(); curr_priority = prev_priority; - enable_interrupt(); + kfree(tmp_task); } } diff --git a/kernel/timer.c b/kernel/timer.c index 3dab56463..f2a0ca1a6 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -4,6 +4,12 @@ struct list_head *timer_event_list; void timer_list_init() { + unsigned long long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" :: "r"(tmp)); + + timer_event_list = kmalloc(sizeof(list_head_t)); INIT_LIST_HEAD(timer_event_list); } @@ -26,29 +32,33 @@ void core_timer_disable() { } void core_timer_handler() { + lock(); // if there is no timer_event => set large tval if (list_empty(timer_event_list)) { set_core_timer_interrupt_abs(get_tick_plus_s(10000)); + unlock(); return; } // next timer_event timer_event_callback((timer_event_t *)timer_event_list->next); + unlock(); } -void add_timer(void *function, unsigned long long timeout, char *args) { - timer_event_t *tmp_timer_event = simple_alloc(sizeof(timer_event_t)); +void add_timer(void *function, unsigned long long timeout, char *args, int bytick) { + timer_event_t *tmp_timer_event = kmalloc(sizeof(timer_event_t)); // store function into timer_event tmp_timer_event->func = function; // store argument string into timer_event - tmp_timer_event->args = simple_alloc(strlen(args) + 1); + tmp_timer_event->args = kmalloc(strlen(args) + 1); memcpy(tmp_timer_event->args, args, strlen(args) + 1); // store interrupt time into timer_event - tmp_timer_event->interrupt_time = get_tick_plus_s(timeout); - - // init list head - INIT_LIST_HEAD(&tmp_timer_event->listhead); + if (bytick == 0) + tmp_timer_event->interrupt_time = get_tick_plus_s(timeout); + else + tmp_timer_event->interrupt_time = get_tick_plus_s(0) + timeout; // add timer_event into timer_event_list (sorted) + lock(); struct list_head *curr; list_for_each (curr, timer_event_list) { // put this timer before the first element larger than it @@ -65,6 +75,7 @@ void add_timer(void *function, unsigned long long timeout, char *args) { // set interrupt to first event set_core_timer_interrupt_abs(((timer_event_t *)timer_event_list->next)->interrupt_time); + unlock(); } // set timer interrupt (absolutely) use cval @@ -95,10 +106,13 @@ unsigned long long get_tick_plus_s(unsigned long long second) { // execute timer_event function and set next timer interrupt void timer_event_callback(timer_event_t *timer_event) { - // delete the event - list_del_entry((struct list_head *)timer_event); // call the callback function in timer_event ((void (*)(char *))timer_event->func)(timer_event->args); + // delete the event + list_del_entry((struct list_head *)timer_event); + // free the timer event and its args + kfree(timer_event->args); + kfree(timer_event); // if next timer_event is existing => set interrupt if (!list_empty(timer_event_list)) @@ -117,5 +131,5 @@ void two_second_alert(char *str) { // print message uart_printf("Core Timer Interrupt -> seconds after booting : %d\r\n", cntpct_el0 / cntfrq_el0); // set next timer - add_timer(two_second_alert, 2, ""); + add_timer(two_second_alert, 2, "", 0); } diff --git a/kernel/tmpfs.c b/kernel/tmpfs.c new file mode 100644 index 000000000..80dc7367c --- /dev/null +++ b/kernel/tmpfs.c @@ -0,0 +1,142 @@ +#include "tmpfs.h" + +struct file_operations tmpfs_file_operations = {tmpfs_write, tmpfs_read, tmpfs_open, tmpfs_close, tmpfs_getsize}; +struct vnode_operations tmpfs_vnode_operations = {tmpfs_lookup, tmpfs_create, tmpfs_mkdir}; + +int register_tmpfs() { + struct filesystem fs; + fs.name = "tmpfs"; + fs.setup_mount = tmpfs_setup_mount; + return register_filesystem(&fs); +} + +int tmpfs_setup_mount(struct filesystem *fs, struct mount *_mount) { + _mount->fs = fs; + _mount->root = tmpfs_create_vnode(0, dir_t); + return 0; +} + +struct vnode* tmpfs_create_vnode(struct mount* _mount, enum node_type type) { + struct vnode *v = kmalloc(sizeof(struct vnode)); + v->f_ops = &tmpfs_file_operations; + v->v_ops = &tmpfs_vnode_operations; + v->mount = 0; + struct tmpfs_inode* inode = kmalloc(sizeof(struct tmpfs_inode)); + memset(inode, 0, sizeof(struct tmpfs_inode)); + inode->type = type; + inode->data = kmalloc(0x1000); + v->internal = inode; + return v; +} + +int tmpfs_write(struct file *file, const void *buf, unsigned long len) { + // copy data into inode & update f_pos + struct tmpfs_inode *inode = file->vnode->internal; + memcpy(inode->data + file->f_pos, buf, len); + file->f_pos += len; + // update datasize + if (inode->datasize < file->f_pos) + inode->datasize = file->f_pos; + return len; +} + +int tmpfs_read(struct file *file, void *buf, unsigned long len) { + struct tmpfs_inode *inode = file->vnode->internal; + // read until EOF + if (file->f_pos + len > inode->datasize) { + len = inode->datasize - file->f_pos; + } + memcpy(buf, inode->data + file->f_pos, len); + file->f_pos += len; + return len; +} + +int tmpfs_open(struct vnode *file_node, struct file **target) { + (*target)->vnode = file_node; + (*target)->f_ops = file_node->f_ops; + (*target)->f_pos = 0; + return 0; +} + +int tmpfs_close(struct file *file) { + kfree(file); + return 0; +} + +int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name) { + struct tmpfs_inode *dir_inode = dir_node->internal; + int child_idx = 0; + // iterate child entry + for (; child_idx < MAX_DIR_ENTRY; child_idx++) { + struct vnode *vnode = dir_inode->entry[child_idx]; + // if there is no such child + if (!vnode) + continue; + // lookup success + struct tmpfs_inode *inode = vnode->internal; + if (strcmp(component_name, inode->name) == 0) { + *target = vnode; + return 0; + } + } + // uart_printf("[WARNING] tmpfs_lookup not found in this level\r\n"); + return -1; +} + +int tmpfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name) { + // check vnode type + struct tmpfs_inode *inode = dir_node->internal; + if (inode->type != dir_t) { + uart_printf("[ERROR] tmpfs_create FAIL, dir_node is not dir_t\r\n"); + return -1; + } + // iterate child + int child_idx = 0; + for (; child_idx < MAX_DIR_ENTRY; child_idx++) { + // if there is an empty entry + if (!inode->entry[child_idx]) + break; + // prevent identical file name + struct tmpfs_inode *child_inode = inode->entry[child_idx]->internal; + if (strcmp(child_inode->name, component_name) == 0) { + uart_printf("[ERROR] tmpfs_create FAIL, file already exist\r\n"); + return -1; + } + } + // assign new vnode to child_idx + struct vnode *tmp_vnode = tmpfs_create_vnode(0, file_t); + inode->entry[child_idx] = tmp_vnode; + // assign name + struct tmpfs_inode *tmp_inode = tmp_vnode->internal; + memcpy(tmp_inode->name, component_name, strlen(component_name)); + *target = tmp_vnode; + return 0; +} + +int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name) { + // check vnode type + struct tmpfs_inode *inode = dir_node->internal; + if (inode->type != dir_t) { + uart_printf("[ERROR] tmpfs_mkdir FAIL, dir_node is not dir_t\r\n"); + return -1; + } + // find first empty child entry + int child_idx = 0; + for (; child_idx < MAX_DIR_ENTRY; child_idx++) { + if (!inode->entry[child_idx]) + break; + } + // assign new vnode to child_idx + struct vnode* tmp_vnode = tmpfs_create_vnode(0, dir_t); + inode->entry[child_idx] = tmp_vnode; + // assign name + struct tmpfs_inode *tmp_inode = tmp_vnode->internal; + memcpy(tmp_inode->name, component_name, strlen(component_name)); + *target = tmp_vnode; + return 0; +} + +long tmpfs_getsize(struct vnode* vnode) { + struct tmpfs_inode *inode = vnode->internal; + return inode->datasize; +} diff --git a/kernel/uart.c b/kernel/uart.c index a41ae1e4b..7f46e8936 100644 --- a/kernel/uart.c +++ b/kernel/uart.c @@ -1,7 +1,7 @@ #include "uart.h" -char uart_read_buf[0x100] = {}; -char uart_write_buf[0x100] = {}; +char uart_read_buf[MAX_BUF_SIZE] = {}; +char uart_write_buf[MAX_BUF_SIZE] = {}; unsigned int uart_read_buf_begin = 0, uart_read_buf_end = 0; unsigned int uart_write_buf_begin = 0, uart_write_buf_end = 0; @@ -52,8 +52,7 @@ void uart_init() { } void uart_write_char(char c) { - while (!(*AUX_MU_LSR_REG & 0x20)) - nop_delay(1); + do{asm volatile("nop");}while(!(*AUX_MU_LSR_REG & 0x20)); *AUX_MU_IO_REG = (unsigned int)c; } @@ -88,8 +87,7 @@ int uart_printf(char *fmt, ...) { void uart_read(char* buf, unsigned int size) { for (unsigned int i = 0; i < size; i++) { - while (!(*AUX_MU_LSR_REG & 0x01)) - nop_delay(1); + do{asm volatile("nop");}while(!(*AUX_MU_LSR_REG & 0x01)); buf[i] = (char)(*AUX_MU_IO_REG); } } @@ -104,14 +102,16 @@ void nop_delay(unsigned int t) { // read data to read buffer void uart_interrupt_r_handler() { // read buffer full => disable read interrupt - if ((uart_read_buf_end + 1) % 0x100 == uart_read_buf_begin) { + if ((uart_read_buf_end + 1) % MAX_BUF_SIZE == uart_read_buf_begin) { + // NOT SURE == clear fifo + *AUX_MU_IIR_REG = 0xc2; disable_mini_uart_r_interrupt(); return; } // read to buffer uart_read(&uart_read_buf[uart_read_buf_end++], 1); // circular buffer - if (uart_read_buf_end >= 0x100) + if (uart_read_buf_end >= MAX_BUF_SIZE) uart_read_buf_end = 0; // unmasks the device’s interrupt line @@ -120,17 +120,16 @@ void uart_interrupt_r_handler() { // write data from write buffer void uart_interrupt_w_handler() { - // verify preemption - // nop_delay(10000); // buffer is empty => disable write interrupt if (uart_write_buf_begin == uart_write_buf_end) { + *AUX_MU_IIR_REG = 0xc4; disable_mini_uart_w_interrupt(); return; } // write from buffer uart_write_char(uart_write_buf[uart_write_buf_begin++]); // circular buffer - if (uart_write_buf_begin >= 0x100) + if (uart_write_buf_begin >= MAX_BUF_SIZE) uart_write_buf_begin = 0; // unmasks the device’s interrupt line @@ -177,19 +176,19 @@ int mini_uart_w_interrupt_is_enable() { // wrtie data to write buffer void uart_write_char_async(char c) { // wait for full buffer - while ((uart_write_buf_end + 1) % 0x100 == uart_write_buf_begin) { + while ((uart_write_buf_end + 1) % MAX_BUF_SIZE == uart_write_buf_begin) { // start asynchronous transfer enable_mini_uart_w_interrupt(); } // critical section - disable_interrupt(); + lock(); // write to buffer uart_write_buf[uart_write_buf_end++] = c; // circular buffer - if (uart_write_buf_end >= 0x100) + if (uart_write_buf_end >= MAX_BUF_SIZE) uart_write_buf_end = 0; // start asynchronous transfer - enable_interrupt(); + unlock(); // enable interrupt to transfer enable_mini_uart_w_interrupt(); } @@ -235,12 +234,12 @@ char uart_read_char_async() { enable_mini_uart_r_interrupt(); // critical section - disable_interrupt(); + lock(); char r = uart_read_buf[uart_read_buf_begin++]; - if (uart_read_buf_begin >= 0x100) + if (uart_read_buf_begin >= MAX_BUF_SIZE) uart_read_buf_begin = 0; - enable_interrupt(); + unlock(); return r; } diff --git a/kernel/vfs.c b/kernel/vfs.c new file mode 100644 index 000000000..01731d73b --- /dev/null +++ b/kernel/vfs.c @@ -0,0 +1,230 @@ +#include "vfs.h" + +int register_filesystem(struct filesystem *fs) { + // find first empty reg_fs entry + for (int i = 0; i < MAX_FS_REG; i++) { + if(!reg_fs[i].name) { + reg_fs[i].name = fs->name; + reg_fs[i].setup_mount = fs->setup_mount; + return i; + } + } + // reg_fs is full + return -1; +} + +struct filesystem* find_filesystem(const char* fs_name) { + // find file system by name + for (int i = 0; i < MAX_FS_REG; i++) { + if (strcmp(reg_fs[i].name, fs_name) == 0) + return ®_fs[i]; + } + return 0; +} + +int vfs_write(struct file *file, const void *buf, unsigned long len) { + // 1. write len byte from buf to the opened file. + // 2. return written size or error code if an error occurs. + return file->f_ops->write(file, buf, len); +} + +int vfs_read(struct file *file, void *buf, unsigned long len) { + // 1. read min(len, readable size) byte to buf from the opened file. + // 2. block if nothing to read for FIFO type + // 3. return read size or error code if an error occurs. + return file->f_ops->read(file, buf, len); +} + +int vfs_open(const char *pathname, int flags, struct file **target) { + // 1. Lookup pathname + // 3. Create a new file if O_CREAT is specified in flags and vnode not found + struct vnode *node; + if (vfs_lookup(pathname, &node) != 0 && (flags & O_CREAT)) { + // find last slash in pathname + int last_slash_idx = 0; + for (int i = 0; i < strlen(pathname); i++) { + if(pathname[i] == '/') + last_slash_idx = i; + } + // find corresponding dirname from pathname + char dirname[MAX_PATH_NAME]; + memcpy(dirname, pathname, strlen(pathname)); + dirname[last_slash_idx] = 0; + // lookup dirname + if (vfs_lookup(dirname, &node) != 0) { + uart_printf("[ERROR] O_CREAT FAIL, no such directory name\r\n"); + return -1; + } + // there is dirname => O_CREAT + node->v_ops->create(node, &node, pathname + last_slash_idx + 1); + // create a new file handle for this vnode + *target = kmalloc(sizeof(struct file)); + node->f_ops->open(node, target); + (*target)->flags = flags; + return 0; + } + // 2. Create a new file handle for this vnode if found. + else { + *target = kmalloc(sizeof(struct file)); + node->f_ops->open(node, target); + (*target)->flags = flags; + return 0; + } + // lookup error code shows if file exist or not or other error occurs + // 4. Return error code if fails + return -1; +} + +int vfs_close(struct file *file) { + // 1. release the file handle + // 2. Return error code if fails + file->f_ops->close(file); + return 0; +} + +int vfs_lookup(const char *pathname, struct vnode **target) { + // root node + if (strlen(pathname) == 0) { + *target = rootfs->root; + return 0; + } + // search from root node + struct vnode *dirnode = rootfs->root; + char component_name[FILE_NAME_MAX+1]; + memset(component_name, 0, FILE_NAME_MAX+1); + int c_idx = 0; + // iterate directory + for (int i = 1; i < strlen(pathname); i++) { + // delimiter + if (pathname[i] == '/') { + // end of component name + component_name[c_idx++] = 0; + // if there is no such dirname, return -1 + if (dirnode->v_ops->lookup(dirnode, &dirnode, component_name) != 0) + return -1; + // redirect to new mounted file system + while (dirnode->mount) { + dirnode = dirnode->mount->root; + } + // reset index + c_idx = 0; + } + // copy pathname + else { + component_name[c_idx++] = pathname[i]; + } + } + // last component + component_name[c_idx++] = 0; + if (dirnode->v_ops->lookup(dirnode, &dirnode, component_name) != 0) + return -1; + // redirect to new mounted file system + while (dirnode->mount) { + dirnode = dirnode->mount->root; + } + + *target = dirnode; + return 0; +} + +int vfs_mkdir(const char *pathname) { + char dirname[MAX_PATH_NAME], newdirname[MAX_PATH_NAME]; + memset(dirname, 0, MAX_PATH_NAME); + memset(newdirname, 0, MAX_PATH_NAME); + // find last slash in pathname + int last_slash_idx = 0; + for (int i = 0; i < strlen(pathname); i++) { + if (pathname[i] == '/') + last_slash_idx = i; + } + // divide into 2 parts + memcpy(dirname, pathname, last_slash_idx); + memcpy(newdirname, pathname + last_slash_idx + 1, strlen(pathname + last_slash_idx + 1)); + + struct vnode *node; + // if there is dirname => mkdir + if (vfs_lookup(dirname, &node) == 0) { + node->v_ops->mkdir(node, &node, newdirname); + return 0; + } + // if there is no such dirname + uart_printf("[ERROR] vfs_mkdir FAIL, no such directory name\r\n"); + return -1; +} + +int vfs_mount(const char *target, const char *filesystem) { + struct vnode *dirnode; + struct filesystem *fs = find_filesystem(filesystem); + // if there is no such file system + if (!fs) { + uart_printf("[ERROR] vfs_mount FAIL, no such file system\r\n"); + return -1; + } + // if there is no such dirname + if (vfs_lookup(target, &dirnode) == -1) { + uart_printf("[ERROR] vfs_mount FAIL, no such directory name\r\n"); + return -1; + } + // mount + else { + dirnode->mount = kmalloc(sizeof(struct mount)); + fs->setup_mount(fs, dirnode->mount); + } + return 0; +} + +void init_rootfs() { + // register tmpfs as rootfs + int idx = register_tmpfs(); + rootfs = kmalloc(sizeof(struct mount)); + reg_fs[idx].setup_mount(®_fs[idx], rootfs); +} + +char* path_to_absolute(char* path, char* curr_working_dir) { + // uart_printf("\r\n[TEST in path2abs] path = %s, curr = %s\r\n\r\n", path, curr_working_dir); + // if path is relative path + if (path[0] != '/') { + char tmp[MAX_PATH_NAME]; + memset(tmp, 0, MAX_PATH_NAME); + memcpy(tmp, curr_working_dir, strlen(curr_working_dir)); + if (strcmp(curr_working_dir, "/") != 0) { + tmp[strlen(tmp)] = '/'; + } + // concatenate curr_working_dir & path + memcpy(tmp + strlen(tmp), path, strlen(path)); + memset(path, 0, strlen(path)); + memcpy(path, tmp, strlen(tmp)); + path[strlen(path)] = 0; + } + + char absolute_path[MAX_PATH_NAME]; + memset(absolute_path, 0, MAX_PATH_NAME); + int idx = 0; + for (int i = 0; i < strlen(path); i++) { + // if there is /.. + if (path[i] == '/' && path[i+1] == '.' && path[i+2] == '.') { + // find previous / + for (int j = idx; j >= 0; j--) { + if(absolute_path[j] == '/') { + absolute_path[j] = 0; + idx = j; + } + } + i += 2; + continue; + } + // ignore /. + if (path[i] == '/' && path[i+1] == '.') { + i++; + continue; + } + // normal case + absolute_path[idx++] = path[i]; + } + // end of absolute_path + absolute_path[idx] = 0; + + memset(path, 0, strlen(path)); + memcpy(path, absolute_path, strlen(absolute_path)); + return path; +} diff --git a/makefile b/makefile index b8fdd5f87..2d3075bd5 100644 --- a/makefile +++ b/makefile @@ -3,10 +3,13 @@ all: make -C bootloader run: - qemu-system-aarch64 -M raspi3b -kernel ./kernel/kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + qemu-system-aarch64 -M raspi3 -kernel ./kernel/kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +run_display: + qemu-system-aarch64 -M raspi3 -kernel ./kernel/kernel8.img -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb debug: - qemu-system-aarch64 -M raspi3b -kernel ./kernel/kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb -s -S + qemu-system-aarch64 -M raspi3 -kernel ./kernel/kernel8.img -display none -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb -s -S cpio: cd rootfs && find . | cpio -o -H newc > ../initramfs.cpio diff --git a/rootfs/vfs1.img b/rootfs/vfs1.img new file mode 100644 index 000000000..2c41bd71a Binary files /dev/null and b/rootfs/vfs1.img differ