diff --git a/include/address.h b/include/address.h index 90ee60781..c65effe5f 100644 --- a/include/address.h +++ b/include/address.h @@ -1,10 +1,11 @@ #ifndef ADDRESS #define ADDRESS +#include "mmu.h" -#define MMIO_BASE 0x3F000000 +#define MMIO_BASE PHY_TO_VIR(0x3F000000) -#define LOAD_ADDR (volatile unsigned int*)(0x80000) -#define INITRAMFS_ADDR (volatile unsigned int*)(0x8000000) +#define LOAD_ADDR (volatile unsigned int*)(PHY_TO_VIR(0x80000)) +#define INITRAMFS_ADDR (volatile unsigned int*)(PHY_TO_VIR(0x8000000)) // GPIO registers #define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) @@ -60,6 +61,6 @@ #define MBOX_EMPTY 0x40000000 // Interrupt -#define IRQS1 ((volatile unsigned int*)(0x3f00b210)) +#define IRQS1 ((volatile unsigned int*)(PHY_TO_VIR(0x3f00b210))) #endif \ No newline at end of file diff --git a/include/cpio.h b/include/cpio.h index 3b011c2db..8eee97675 100644 --- a/include/cpio.h +++ b/include/cpio.h @@ -3,9 +3,11 @@ #include "type.h" -#define MAX_INITRAMFS_SIZE 0x10000 +#define MAX_INITRAMFS_SIZE 0x100000 +unsigned int hex2num(char *s, unsigned int max_len); void extract_cpio(char* address, int ls, int cat, char* name); +char* extract_section(char* context, char* p, char* address, int len); char* load_user_program(char* address, char* program_address, char* name); uint64 get_program_size(char* address, char* name); #endif \ No newline at end of file diff --git a/include/dev_framebuffer.h b/include/dev_framebuffer.h new file mode 100644 index 000000000..6cbd5b03e --- /dev/null +++ b/include/dev_framebuffer.h @@ -0,0 +1,21 @@ +#ifndef H_DEV_FRAMEBUFFER +#define H_DEV_FRAMEBUFFER + +#include "vfs.h" + +extern file_operations_t dev_framebuffer_file_operations; +extern unsigned int width, height, pitch, isrgb; + +typedef struct framebuffer_info { + unsigned int width; + unsigned int height; + unsigned int pitch; + unsigned int isrgb; +} framebuffer_info_t; + +void init_dev_framebuffer(); +int dev_framebuffer_write(file_t *file, const void *buf, size_t len); +int dev_framebuffer_open(vnode_t *file_node, file_t **target); +int dev_framebuffer_close(file_t *file); + +#endif \ No newline at end of file diff --git a/include/dev_uart.h b/include/dev_uart.h new file mode 100644 index 000000000..8648be503 --- /dev/null +++ b/include/dev_uart.h @@ -0,0 +1,13 @@ +#ifndef H_DEV_UART +#define H_DEV_UART + +#include "vfs.h" + +extern file_operations_t dev_uart_file_operations; + +int dev_uart_write(file_t *file, const void *buf, size_t len); +int dev_uart_read(file_t *file, void *buf, size_t len); +int dev_uart_open(vnode_t *file_node, file_t **target); +int dev_uart_close(file_t *file); + +#endif \ No newline at end of file diff --git a/include/exception.h b/include/exception.h index 7e50facb8..943d4b44c 100644 --- a/include/exception.h +++ b/include/exception.h @@ -2,10 +2,11 @@ #define EXCEPTION #include "type.h" +#include "mmu.h" -#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int*)(0x40000060)) +#define CORE0_INTERRUPT_SOURCE ((volatile unsigned int*)(PHY_TO_VIR(0x40000060))) -#define PBASE 0x3F000000 +#define PBASE PHY_TO_VIR(0x3F000000) #define IRQ_BASIC_PENDING ((volatile unsigned int*)(PBASE+0x0000B200)) #define IRQ_PENDING_1 ((volatile unsigned int*)(PBASE+0x0000B204)) #define IRQ_PENDING_2 ((volatile unsigned int*)(PBASE+0x0000B208)) @@ -23,6 +24,15 @@ #define SIGRETURN 115 +#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 + + typedef struct trapFrame { uint64 x0; uint64 x1; @@ -63,5 +73,5 @@ typedef struct trapFrame { void raise_exc(); void el1_to_el0(char* program_address, char* user_stack_address); - +void svc_handle(trapFrame_t *frame, uint64 x1); #endif \ No newline at end of file diff --git a/include/fdt.h b/include/fdt.h index e21f9cddf..26f14dcb2 100644 --- a/include/fdt.h +++ b/include/fdt.h @@ -9,7 +9,7 @@ #define FDT_NOP (0x00000004) #define FDT_END (0x00000009) -extern uint32* initramfs; +extern uint64 initramfs; struct fdt_header { uint32 magic; // 0xd00dfeed diff --git a/include/initramfs.h b/include/initramfs.h new file mode 100644 index 000000000..3d29c6593 --- /dev/null +++ b/include/initramfs.h @@ -0,0 +1,32 @@ +#ifndef H_INITRAMFS +#define H_INITRAMFS + +#include "vfs.h" + +typedef struct initramfs_internal { + enum NodeType ntype; + char name[MAX_COMPONENT_LENGTH]; + vnode_t *entry[MAX_ENTRY]; + char *data; + uint64 datasize; +} initramfs_internal_t; + +filesystem_t *get_initramfs(); +int setup_initramfs_mount(filesystem_t *fs, mount_t *mount); +vnode_t *create_initramfs_vnode(mount_t *mount, enum NodeType ntype); +int initramfs_write(file_t *file, const void *buf, size_t len); +int initramfs_read(file_t *file, void *buf, size_t len); +int initramfs_open(vnode_t *file_node, file_t **target); +int initramfs_close(file_t *file); +int initramfs_getsize(vnode_t *target); + +int initramfs_lookup(vnode_t *dir, vnode_t **target, const char *component_name); +int initramfs_create(vnode_t *dir, vnode_t **target, const char *component_name); +int initramfs_mkdir(vnode_t *dir, vnode_t **target, const char *component_name); + + + + + + +#endif \ No newline at end of file diff --git a/include/interrupt.h b/include/interrupt.h index 51f351179..7c6dc5030 100644 --- a/include/interrupt.h +++ b/include/interrupt.h @@ -3,7 +3,7 @@ #define UART_INTERRUPT_TX_PRIORITY 2 #define UART_INTERRUPT_RX_PRIORITY 3 -#define TIMER_INTERRUPT_PRIORITY 5 +#define TIMER_INTERRUPT_PRIORITY 4 #define WAIT_INTERRUPT_PRIORITY 999 typedef struct interrupt_event diff --git a/include/memory.h b/include/memory.h index cb9cb9b6e..f0f53505f 100644 --- a/include/memory.h +++ b/include/memory.h @@ -1,91 +1,46 @@ -#ifndef MEMORY -#define MEMORY -#include "type.h" - -extern unsigned long long _heap_start; // linker script symbol -extern unsigned long long _heap_end; // linker script symbol -static char* heap = (char*)&_heap_start; -static char* heap_end = (char*)&_heap_end; - -void* simple_malloc(unsigned int size); -char* memcpy (void *dest, const void *src, unsigned long long len); - -#define MAX_ORDER 12 -#define MAX_PAGES 2048 -#define MINI_PAGE_SIZE 4 // kB -#define PAGE_BEGIN_ADDRESS 0x00000000 -#define BASE_NUM 64 // can't change so far -#define NUM_POOL 1 -#define KB 1 << 10 - -typedef struct node { - struct node* prevNode; - struct node* nextNode; - uint64 address; -} node_t; - -typedef struct memoryPool { - uint64 address; - uint32 size; - uint64 stateBitMap; - uint64 mask; -} memoryPool_t; - -typedef struct page { - uint32 order; - uint64 address; - int state; - struct page* prevPage; - struct page* nextPage; - struct page* buddyPage; - struct page* parentPage; - struct page* appendPage; - memoryPool_t* pool; -} page_t; - -typedef struct pageHeader { - page_t* firstFree; - page_t* firstEmpty; -} pageHeader_t; +#ifndef MEMORY_H +#define MEMORY_H + +#include "list.h" +#include "uart.h" +#include "cpio.h" +#include "address.h" +#include "interrupt.h" +#include "mmu.h" + +#define MAXORDER 7 +#define MAXCACHEORDER 4 // 32, 64, 128, 256, 512 (for every 32bytes) + +// simple_malloc +void *simple_malloc(unsigned int size); +char *memcpy (void *dest, const void *src, unsigned long long len); +void *memset(void *s, int c, size_t n); + +#define BUDDYSYSTEM_START PHY_TO_VIR(0x000000L) +#define BUDDYSYSTEM_PAGE_COUNT 0x3C000 // 0x3C000000 is total size of memory, page size is 0x1000 +//buddy system (for >= 4K pages) +void *allocpage(unsigned int size); +void freepage(void *ptr); + +void *alloccache(unsigned int size); +void freecache(void *ptr); +void page2caches(int order); + +void *malloc(unsigned int size); +void free(void *ptr); + +typedef struct frame +{ + struct list_head listhead; + int val; // val is order + int isused; + int cacheorder; // -1 means isn't used for cache + unsigned int idx; +} frame_t; void initMemoryPages(); -page_t* createPage(uint32 order, uint64 address, int state); -void initPool(memoryPool_t* pool, uint32 maxSize, uint32 size, uint64 address); -void* malloc(uint32 size); -uint32 sizeToSmallestOrder(uint32 size); -void appendNewPage(page_t* parentPage, page_t* newPage); -void showAppendPage(page_t *parentPage); -bool isAllFull(page_t* page, uint32 size); -bool isFull(page_t* page, uint32 size); -bool isPoolFull(memoryPool_t* pool, uint32 size); -void* allocateMemoryFromPage(page_t* page, uint32 size); -void registerUsedAddress(page_t* page); -uint32 addressToBlockIdx(uint64 address); -void removeUsedAddress(page_t* page); - -page_t* getFreePageAtOrder(uint32 order); -void loggingPage(page_t* page); -void loggingPool(memoryPool_t* pool); -bool hasFreePageAtOrder(uint32 order); -bool hasNoFreePageAtOrder(uint32 order); -void dividePageToLowerOrder(page_t* page); -page_t* addPageAtOrder(uint32 order, uint64 address, page_t* parentPage); -uint64 getPageSizeAtOrder(uint32 order); -uint64 getPageNumAtOrder(uint32 order); -void bindAsBuddy(page_t* page1, page_t* page2); -void freePage(page_t* page); -bool isNotPageHead(page_t* page); -bool isNotPageTail(page_t* page); -bool isFirstFree(page_t* page); -bool isFirstEmpty(page_t* page); -void mergePagesToHigherOrder(page_t* page); -void moveToTail(page_t* page); -void loggingAllPageState(); -void free(uint64 address); -void init_reserve(); -void reserveMemory(uint64 start, uint64 end); -void reservePage(uint32 order, uint64 address); -bool inRange(page_t* page, uint64 address); -bool inPool(memoryPool_t* pool, uint64 address); - +frame_t *release_redundant(frame_t *frame); +frame_t *get_buddy(frame_t *frame); +frame_t *coalesce(frame_t* f); +void memory_reserve(unsigned long long start, unsigned long long end); #endif \ No newline at end of file diff --git a/include/mmu.h b/include/mmu.h new file mode 100644 index 000000000..d1a7e5894 --- /dev/null +++ b/include/mmu.h @@ -0,0 +1,71 @@ +#ifndef MMU_H +#define MMU_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 PERIPHERAL_START 0x3c000000L +#define PERIPHERAL_END 0x3f000000L +#define PERIPHERAL_BASE 0x3f000000L +#define PAGE_TABLE_BASE 0x10000000L +#define USER_KERNEL_BASE 0x00000000L +#define THREAD_STACK_SIZE 0x4000L +#define USER_STACK_BASE 0xfffffffff000L - THREAD_STACK_SIZE + +#define PGD_BASE (PAGE_TABLE_BASE + 0x0000) +#define PUD_BASE (PAGE_TABLE_BASE + 0x1000) +#define PMD_BASE (PAGE_TABLE_BASE + 0x2000) +#define PTE_BASE (PAGE_TABLE_BASE + 0x4000) + +#define PD_TABLE 0b11L +#define PD_BLOCK 0b01L +#define PD_PAGE 0b11L +#define PD_NE_EL0 (1L << 54) +#define PD_NE_EL1 (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_TABLE) +#define BOOT_PMD_ATTR (PD_TABLE) + +#define BOOT_PTE_DEVICE_nGnRnE_ATTR \ + (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_PAGE | PD_UK_ACCESS | PD_NE_EL0 | PD_NE_EL1) +#define BOOT_PTE_NORMAL_NOCACHE_ATTR \ + (PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_PAGE) + +#define PHY_TO_VIR(x) ((x) | 0xffff000000000000L) +#define VIR_TO_PHY(x) ((x) & ~0xffff000000000000L) + +#ifndef __ASSEMBLER__ + +#include "type.h" +#include "thread.h" + +typedef struct thread thread_t; + +typedef struct{ + unsigned int iss : 25, // Instruction specific syndrome + il : 1, // Instruction length bit + ec : 6; // Exception class +} esr_el1_t; + +void init_page_table(uint64 **table, int level); +void set_page_tables_for_thread(thread_t *thread); +void free_page_tables_for_thread(thread_t *thread); +void map_page_table(thread_t *thread, uint64 *pgd, uint64 vir_addr, uint64 phy_addr, bool readOnly); +void parser_table(uint64 vir_addr); +void set_vm_list_for_thread(thread_t *thread); +void free_vm_list_for_thread(thread_t *thread); +void handle_abort(esr_el1_t *esr_el1); +void seg_fault(); +#endif //__ASSEMBLER__ + +#endif \ No newline at end of file diff --git a/include/signal.h b/include/signal.h index e494da8d4..d06883ee0 100644 --- a/include/signal.h +++ b/include/signal.h @@ -2,14 +2,9 @@ #define _SIGNAL_H #include "type.h" -#include "exception.h" -#define SIGMAX 16 -typedef struct signal_pair { - uint64 spsr_el1; - int pid; - int code; -} signal_pair_t; + +typedef struct trapFrame trapFrame_t; void signal_default_handlder(); void signal_register(int code, void (*handler)()); diff --git a/include/sprintf.h b/include/sprintf.h new file mode 100644 index 000000000..101e564e3 --- /dev/null +++ b/include/sprintf.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); \ No newline at end of file diff --git a/include/string.h b/include/string.h index 468a47c00..f61a3bfe3 100644 --- a/include/string.h +++ b/include/string.h @@ -1,11 +1,16 @@ #ifndef STRING #define STRING +#define MAX_LEN 1025 + int strcmp (const char* str1, const char* str2); void strcpy(char* dst, const char* src); int startwith (const char* str1, const char* str2); int strlen (const char* str1); unsigned int str2num(char* str, int len); char* find_token(const char* str, char sep); +char *get_dirname(char* dst, const char* src); +char *get_rootname(char* dst, const char* src); +void get_abspath(char *abs_path, char *path, const char *curr_path); #endif \ No newline at end of file diff --git a/include/syscall.h b/include/syscall.h index bfb6cc7d5..de524b320 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -4,14 +4,26 @@ #include "thread.h" #include "exception.h" #include "type.h" +#include "dev_framebuffer.h" int getpid(); size_t uart_read(char buf[], size_t size); size_t uart_write(const char buf[], size_t size); -int exec(trapFrame_t *frame, const char *name, char *const argv[]); +int exec(trapFrame_t *frame, char *name, char *const argv[]); int fork(trapFrame_t *frame); void exit(int status); int mbox_call(unsigned char ch, unsigned int *mbox); void kill(int pid); void fork_test(); +uint64 sys_mmap(void *addr, size_t len, int prot, int flags, int fd, int file_offset); + +int call_vfs_open(const char *pathname, int flags); +int call_vfs_close(int fd); +long call_vfs_write(int fd, const char *buf, unsigned long count); +long call_vfs_read(int fd, char *buf, unsigned long count); +int call_vfs_mkdir(const char *pathname, unsigned mode); +int call_vfs_mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data); +int call_vfs_chdir(const char *path); +long call_vfs_lseek64(int fd, long offset, int whence); +int call_vfs_ioctl(int fd, unsigned long request, framebuffer_info_t *fb_info); #endif diff --git a/include/thread.h b/include/thread.h index c02882b08..bb99fc18a 100644 --- a/include/thread.h +++ b/include/thread.h @@ -4,14 +4,26 @@ #include "type.h" #include "list.h" #include "signal.h" +#include "exception.h" +#include "mmu.h" +#include "vfs.h" #define PIDMAX 16 -#define THREAD_STACK_SIZE 0x10000 +#define SIGMAX 16 +#define USER_SIG_WRAPPER_VIRT_ADDR_ALIGNED 0xffffffff9000L + +typedef struct signal_pair { + uint64 spsr_el1; + int pid; + int code; +} signal_pair_t; extern void switch_to(void *curr_context, void *next_context); -extern void read_context(void *context); -extern void write_context(void *context); +extern void store_context(void *context); +extern void load_context(void *context); extern void *get_current(); +extern void switch_pgd(uint64 pgd); +extern uint64 *get_pgd(); typedef struct threadContext { uint64 x19; @@ -27,8 +39,17 @@ typedef struct threadContext { uint64 fp; uint64 lr; uint64 sp; + uint64 *pgd; // for mmu } threadContext_t; +typedef struct vm_cell { + list_head_t listHead; + uint64 vir_addr; + uint64 phy_addr; + uint64 size; +} vm_cell_t; + + typedef struct thread { list_head_t listHead; threadContext_t context; @@ -42,19 +63,23 @@ typedef struct thread { signal_pair_t signal_pair; bool has_signal; threadContext_t signal_context; + list_head_t used_vm; + char pwd[MAX_PATHNAME]; + file_t *file_descriptor_table[MAX_FD]; } thread_t; - extern thread_t *currThread; extern thread_t threads[PIDMAX + 1]; extern list_head_t *run_queue, *wait_queue; void initThreads(); -thread_t *createThread(void *program); +thread_t *createThread(void *program, uint64 datasize); void idle(); +void kill_zombies(); +void free_file_descriptor_table_for_thread(thread_t *thread); void schedule(); -void execThread(char *program, uint64 program_size); +void execThread(char *pathname); void testThread(); void thread_exit(); void set_schedule_timer(); diff --git a/include/timer.h b/include/timer.h index 352815307..18e62c9d0 100644 --- a/include/timer.h +++ b/include/timer.h @@ -1,8 +1,14 @@ #ifndef TIMER #define TIMER -typedef struct timer_event -{ +#include "type.h" +#include "uart.h" +#include "string.h" +#include "memory.h" +#include "interrupt.h" +#include "mmu.h" + +typedef struct timer_event { unsigned long long timeout_tick; unsigned long long begin_tick; char* message; @@ -15,7 +21,7 @@ typedef struct timer_event #define STR(x) #x #define XSTR(s) STR(s) -#define CORE0_TIMER_IRQ_CTRL 0x40000040 +#define CORE0_TIMER_IRQ_CTRL PHY_TO_VIR(0x40000040) void add_timer(void (*callback)(char* message), unsigned long long timeout_tick, char *message); void core_timer_handler(); @@ -24,9 +30,11 @@ void disable_core_timer(); unsigned long long get_current_tick(); void set_core_timer_by_tick(unsigned long long tick); void set_core_timer_by_second(unsigned long long second); +uint64 get_timer_frequency(); unsigned long long tick2second(unsigned long long tick); unsigned long long second2tick(unsigned long long second); void show_message(char* message); void increment_timeout_2_seconds(char* message); +bool hasTimerEvent(); #endif \ No newline at end of file diff --git a/include/tmpfs.h b/include/tmpfs.h new file mode 100644 index 000000000..baae6e649 --- /dev/null +++ b/include/tmpfs.h @@ -0,0 +1,28 @@ +#ifndef H_TMPFS +#define H_TMPFS + +#include "vfs.h" + +typedef struct tmpfs_internal { + enum NodeType ntype; + char name[MAX_COMPONENT_LENGTH]; + vnode_t *entry[MAX_ENTRY]; + char *data; + uint64 datasize; +} tmpfs_internal_t; + +filesystem_t *get_tmpfs(); +int setup_tmpfs_mount(filesystem_t *fs, mount_t *mount); +vnode_t *create_tmpfs_vnode(mount_t *mount, enum NodeType ntype); +int tmpfs_write(file_t *file, const void *buf, size_t len); +int tmpfs_read(file_t *file, void *buf, size_t len); +int tmpfs_open(vnode_t *file_node, file_t **target); +int tmpfs_close(file_t *file); +int tmpfs_getsize(vnode_t *target); + +int tmpfs_lookup(vnode_t *dir, vnode_t **target, const char *component_name); +int tmpfs_create(vnode_t *dir, vnode_t **target, const char *component_name); +int tmpfs_mkdir(vnode_t *dir, vnode_t **target, const char *component_name); + + +#endif \ No newline at end of file diff --git a/include/type.h b/include/type.h index 88595f659..54b4e9bd6 100644 --- a/include/type.h +++ b/include/type.h @@ -11,11 +11,12 @@ typedef int int32; typedef long long int64; typedef unsigned char bool; typedef int state_t; -typedef int size_t; +typedef unsigned long long size_t; #define IDLE 1 #define USED 0 #define DEAD -1 +#define NEW_BORN 2 #define FREE 1 #define BUSY 0 diff --git a/include/uart.h b/include/uart.h index fa660dddf..9981c09fe 100644 --- a/include/uart.h +++ b/include/uart.h @@ -2,7 +2,8 @@ #define UART #include "type.h" -#define MAX_BUF_SIZE 1024 +#include "sprintf.h" +#define MAX_BUF_SIZE 256 void uart_init(); void uart_enable(); @@ -36,4 +37,6 @@ void disable_uart_interrupt(); void disable_uart_r_interrupt(); void disable_uart_w_interrupt(); void raiseError(char *message); +int uart_printf(char *fmt, ...); +int uart_async_printf(char *fmt, ...); #endif diff --git a/include/vfs.h b/include/vfs.h new file mode 100644 index 000000000..cd74aef10 --- /dev/null +++ b/include/vfs.h @@ -0,0 +1,81 @@ +#ifndef H_VFS +#define H_VFS + +#include "type.h" + +#define MAX_COMPONENT_LENGTH 15 +#define MAX_PATHNAME 257 +#define MAX_ENTRY 16 +#define MAX_FILE_SIZE 4096 +#define MAX_FD 16 +#define MAX_REG_FS 16 +#define MAX_REG_DEV 16 + +#define O_CREAT 00000100 +#define SEEK_SET 0 + +enum NodeType { nt_dir, nt_file }; + +typedef struct vnode { + struct mount* mount; + struct vnode_operations* v_ops; + struct file_operations* f_ops; + void* internal; +} vnode_t; + +// file handle +typedef struct file { + struct vnode* vnode; + size_t f_pos; // RW position of this file handle + struct file_operations* f_ops; + int flags; +} file_t; + +typedef struct mount { + struct vnode* root; + struct filesystem* fs; +} mount_t; + +typedef struct filesystem { + const char* name; + int (*setup_mount)(struct filesystem* fs, struct mount* mount); +} filesystem_t; + +typedef struct file_operations { + int (*write)(struct file* file, const void* buf, size_t len); + int (*read)(struct file* file, void* buf, size_t len); + int (*open)(struct vnode* file_node, struct file** target); + int (*close)(struct file* file); + long (*lseek64)(struct file* file, long offset, int whence); + int (*getsize)(struct vnode* target); +} file_operations_t; + +typedef 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); +} vnode_operations_t; + +struct mount* rootfs; +filesystem_t registered_fs[MAX_REG_FS]; +file_operations_t registered_dev_fops[MAX_REG_FS]; + +int register_filesystem(struct filesystem* fs); +int vfs_open(const char* pathname, int flags, struct file** target); +int vfs_close(struct file* file); +int vfs_write(struct file* file, const void* buf, size_t len); +int vfs_read(struct file* file, void* buf, size_t len); +long vfs_lseek64(struct file* file, long offset, int whence); +int vfs_mkdir(const char* pathname); +int vfs_mount(const char* target, const char* filesystem); +int vfs_lookup(const char* pathname, struct vnode** target); +int nop_op(); + +int register_dev_fop(file_operations_t *fop); +int vfs_mknod(const char *pathname, int dev_id); +void init_vfs(); + +#endif \ No newline at end of file diff --git a/lab6_virtual_memory/README.md b/lab6_virtual_memory/README.md new file mode 100644 index 000000000..cd011ad03 --- /dev/null +++ b/lab6_virtual_memory/README.md @@ -0,0 +1,10 @@ +# Operating Systems Capstone 2022 + +||| +|:-:|:-:| +|Name|陳沐融| +|ID|310551063| +|GitHub|PersonalWorkingSpace| +|Email|TonyCHEN3000Tony@gmail.com| +||| +--- \ No newline at end of file diff --git a/lab6_virtual_memory/kernel/Makefile b/lab6_virtual_memory/kernel/Makefile new file mode 100644 index 000000000..b264132d6 --- /dev/null +++ b/lab6_virtual_memory/kernel/Makefile @@ -0,0 +1,61 @@ +BUILD = ./build +LIB_DIR = ../../lib +LIB_BUILD_DIR = ../../lib/build +INC_DIR = ../../include + +SRCS = $(wildcard *.c) +LIBS = $(notdir $(wildcard $(LIB_DIR)/*.c)) + +OBJS = $(patsubst %.c, $(BUILD)/%.o, $(SRCS)) $(patsubst %.c, $(LIB_BUILD_DIR)/%.o, $(LIBS)) +CFLAGS = -Wall -nostdinc -nostdlib -nostartfiles -ffreestanding -I $(INC_DIR) + +all: img + +$(BUILD)/start.o: start.S + aarch64-linux-gnu-gcc $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD)/exception_table.o: exception_table.S + aarch64-linux-gnu-gcc $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD)/switch.o: switch.S + aarch64-linux-gnu-gcc $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD)/%.o: %.c + aarch64-linux-gnu-gcc $(CFLAGS) -MMD -c $< -o $@ + +$(LIB_BUILD_DIR)/%.o: $(LIB_DIR)/%.c + aarch64-linux-gnu-gcc $(CFLAGS) -MMD -c $< -o $@ + +img: $(BUILD)/start.o $(BUILD)/exception_table.o $(BUILD)/switch.o $(OBJS) + aarch64-linux-gnu-ld $(BUILD)/start.o $(BUILD)/exception_table.o $(BUILD)/switch.o $(OBJS) -T linker.ld -o $(BUILD)/kernel8.elf + aarch64-linux-gnu-objcopy -O binary $(BUILD)/kernel8.elf $(BUILD)/kernel8.img + +clean: + rm $(BUILD)/* + +clean_lib: + rm $(LIB_BUILD_DIR)/*.o + +run: + qemu-system-aarch64 -M raspi3b -kernel $(BUILD)/kernel8.img -serial null -serial stdio -initrd ../user_program/initramfs.cpio -dtb ../../files_tools/bcm2710-rpi-3-b-plus.dtb + +run_debug: + qemu-system-aarch64 -M raspi3b -kernel $(BUILD)/kernel8.img -d in_asm -serial null -serial pty -initrd ../user_program/initramfs.cpio -dtb ../../files_tools/bcm2710-rpi-3-b-plus.dtb + +run_gdb: + qemu-system-aarch64 -M raspi3b -kernel $(BUILD)/kernel8.img -display none -serial null -serial pty -S -s -initrd ../user_program/initramfs.cpio -dtb ../../files_tools/bcm2710-rpi-3-b-plus.dtb& + gdb-multiarch +dump: + aarch64-linux-gnu-objdump -D -z $(BUILD)/kernel8.elf + +firm: + dd if=/dev/zero of=$(BUILD)/lab.img count=50 bs=1M + (echo o; echo n; echo p; echo 1; echo 2048; echo 102399; echo t; echo c; echo w) | fdisk $(BUILD)/lab.img + mkfs.vfat $(BUILD)/lab.img + sudo mkdir /mnt/lab + sudo mount $(BUILD)/lab.img /mnt/lab + sudo cp ../../firmware/* /mnt/lab + sudo cp $(BUILD)/kernel8.img /mnt/lab + sudo cp ../user_program/initramfs.cpio ./config.txt ../../files_tools/bcm2710-rpi-3-b-plus.dtb /mnt/lab + sudo umount /mnt/lab + sudo rmdir /mnt/lab diff --git a/lab6_virtual_memory/kernel/config.txt b/lab6_virtual_memory/kernel/config.txt new file mode 100644 index 000000000..f82b18ca9 --- /dev/null +++ b/lab6_virtual_memory/kernel/config.txt @@ -0,0 +1 @@ +initramfs initramfs.cpio 0x8000000 \ No newline at end of file diff --git a/lab6_virtual_memory/kernel/exception_table.S b/lab6_virtual_memory/kernel/exception_table.S new file mode 100644 index 000000000..069c7ad41 --- /dev/null +++ b/lab6_virtual_memory/kernel/exception_table.S @@ -0,0 +1,201 @@ +.section ".text" +.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_invalid_el1t // Synchronous EL1t + ventry irq_invalid_el1t // IRQ EL1t + ventry fiq_invalid_el1t // FIQ EL1t + ventry error_invalid_el1t // Error EL1t + + //Exception from the current EL while using SP_ELx + ventry sync_el1h // Synchronous EL1h + ventry irq_el1h // IRQ EL1h + ventry fiq_invalid_el1h // FIQ EL1h + ventry error_invalid_el1h // 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_invalid_el0_64 // FIQ 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 + + //Exception from a lower EL and at least all lower EL are AArch32 + ventry sync_invalid_el0_32 // Synchronous 32-bit EL0 + ventry irq_invalid_el0_32 // IRQ 32-bit EL0 + ventry fiq_invalid_el0_32 // FIQ 32-bit EL0 + ventry error_invalid_el0_32 // Error 32-bit EL0 + +// 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] + + //using for nested interrupt + mrs x0, spsr_el1 + mrs x1, elr_el1 + stp x0, x1, [sp, 16 * 15 + 8] + + mrs x0, sp_el0 + str x0, [sp, 16 * 16 + 8] + + ldp x0, x1, [sp, 16 * 0] // restore x0 +.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] + + ldp x0, x1, [sp, 16 * 15 + 8] + msr spsr_el1, x0 + msr elr_el1, x1 + + ldr x0, [sp, 16 * 16 + 8] + msr sp_el0, x0 + + ldp x0, x1, [sp, 16 * 0] + add sp, sp, 32 * 9 +.endm + +sync_invalid_el1t: + //save_all + mov x0,0 + bl exc_dump + //load_all + eret +irq_invalid_el1t: + save_all + mov x0,1 + bl exc_dump + load_all + eret +fiq_invalid_el1t: + save_all + mov x0,2 + bl exc_dump + load_all + eret +error_invalid_el1t: + save_all + mov x0,3 + bl exc_dump + load_all + eret + + + +sync_el1h: + //save_all + mov x0,4 + bl exc_dump + //load_all + eret +irq_el1h: + save_all + mov x0, sp // trap_frame + bl irq_dump + load_all + eret +fiq_invalid_el1h: + save_all + mov x0,6 + bl exc_dump + load_all + eret +error_invalid_el1h: + save_all + mov x0,7 + bl exc_dump + load_all + eret + + + +sync_el0_64: + save_all + mov x0, sp // trap_frame + mrs x1, esr_el1 + bl svc_handle + load_all + eret +irq_el0_64: + save_all + mov x0, sp // trap_frame + bl irq_dump + load_all + eret +fiq_invalid_el0_64: + save_all + mov x0,10 + bl exc_dump + load_all + eret +error_invalid_el0_64: + save_all + mov x0,11 + bl exc_dump + load_all + eret + + + +sync_invalid_el0_32: + save_all + mov x0,12 + bl exc_dump + load_all + eret +irq_invalid_el0_32: + save_all + mov x0,13 + bl exc_dump + load_all + eret +fiq_invalid_el0_32: + save_all + mov x0,14 + bl exc_dump + load_all + eret +error_invalid_el0_32: + save_all + mov x0,15 + bl exc_dump + load_all + eret \ No newline at end of file diff --git a/lab6_virtual_memory/kernel/linker.ld b/lab6_virtual_memory/kernel/linker.ld new file mode 100644 index 000000000..2cd4ebe1c --- /dev/null +++ b/lab6_virtual_memory/kernel/linker.ld @@ -0,0 +1,28 @@ +SECTIONS +{ + . = 0xffff000000000000; /* kernel space */ + . += 0x80000; /* kernel load address */ + _load_start = . ; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss : { + . = ALIGN(16); + _bss_start = .; + *(.bss .bss.*) + *(COMMON) + /* align is to ensure the size of bss section + is times of 64bits. Use 16bytes is a common strategy */ + . = ALIGN(16); + _bss_end = .; + } + _end = .; + _heap_start = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} + +/*>>3 = /8 => 8bytes*/ +_bss_size = (_bss_end - _bss_start)>>3; +_loader_size = (_end - _load_start)>>3; diff --git a/lab6_virtual_memory/kernel/main.c b/lab6_virtual_memory/kernel/main.c new file mode 100644 index 000000000..6540474a5 --- /dev/null +++ b/lab6_virtual_memory/kernel/main.c @@ -0,0 +1,42 @@ +#include "uart.h" +#include "power.h" +#include "string.h" +#include "utils.h" +#include "address.h" +#include "cpio.h" +#include "type.h" +#include "memory.h" +#include "timer.h" +#include "interrupt.h" +#include "thread.h" +#include "exception.h" + +int main(void) { + uart_init(); + uart_getc(); // flush init signal(0xE0) + uart_puts("Push any key to start ...\n"); + uart_getc(); + uart_puts("Push any key to start ...\n"); + uart_getc(); + + initMemoryPages(); + initThreads(); + + enable_interrupt(); + enable_uart_interrupt(); + enable_core_timer(); + set_core_timer_by_second(1); + + uint64 tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + + char* program_address = load_user_program((char*)INITRAMFS_ADDR, NULL, "vm.img"); + uint64 program_size = get_program_size((char*)INITRAMFS_ADDR, "vm.img"); + uart_printf("Start run user program at 0x%x, with size = %dB\n", program_address, program_size); + uart_dem(); + execThread(program_address, program_size); + + return 0; +} \ No newline at end of file diff --git a/lab6_virtual_memory/kernel/start.S b/lab6_virtual_memory/kernel/start.S new file mode 100644 index 000000000..ad8671801 --- /dev/null +++ b/lab6_virtual_memory/kernel/start.S @@ -0,0 +1,81 @@ +#include "mmu.h" + +.section ".text" +.global _start // decdie entry point + +_start: + // only run program on core-0, others(1-3) are idle + mrs x1, mpidr_el1 // core identification, [7:0] - individual threads within a core + and x1, x1, #3 // 3 => 0~3 (rpi3 has 4 cores) + cbz x1, core0 // run progrm if core=0 else idle + +idle: + wfe // wait for event (idle) + b idle + +core0: + bl from_el2_to_el1 // switch exception level from 2 to 1 (Must at begining) + + // set paging configuration (up : 0xffff000000000000 low : 0x0000000000000000) + ldr x0, = TCR_CONFIG_DEFAULT + msr tcr_el1, x0 + + // set used memory attributes + ldr x0, =( \ + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | \ + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8)) \ + ) + msr mair_el1, x0 + + mov sp, 0x3c000000 + bl set_PGD + bl set_PUD + bl set_PMD + bl set_PTE + + ldr x0, =PGD_BASE + msr ttbr0_el1, x0 // load PGD to the bottom translation-based register. + msr ttbr1_el1, x0 // also load PGD to the upper translation based register. + + mrs x2, sctlr_el1 + orr x2 , x2, 1 + msr sctlr_el1, x2 // enable MMU, cache remains disabled + + ldr x2, =set_exception_vector_table // indirect branch to the virtual address + br x2 + +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + + // set the stack pointer at the top of memory (virtual address: 0xffff00003c000000) + movz x0, 0x0000 + movk x0, 0x3c00, lsl 16 // 3c000000 is the size of memory + movk x0, 0xffff, lsl 48 // 0xffff000000000000 is the start address of virtual kernel address + mov sp, x0 + + // set the uninitialized variable (bss section) to zero + // x - 64bits, w - 32bits (4bytes is large enough for size) + ldr x1, =_bss_start // _bss_start described in linker script + ldr w2, =_bss_size // _bss_size described in linker script + + +init_loop: + cbz w2, main_loop + str xzr, [x1], #8 // set x1 to zero(xzr), and x1's address + 8bytes + sub w2, w2, #1 + b init_loop + +main_loop: + bl main // branch with link (main function in c code, a while loop) + b idle // just in case fail + +from_el2_to_el1: + mov x0, #(3 << 20) // Make el0, el1 can use Floating point and Advanced SIMD + msr cpacr_el1, x0 + mov x0, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x0 + mov x0, 0x3c5 // EL1h (SPSel = 1) with interrupt disabled + msr spsr_el2, x0 + msr elr_el2, lr + eret // return to EL1 diff --git a/lab6_virtual_memory/kernel/switch.S b/lab6_virtual_memory/kernel/switch.S new file mode 100644 index 000000000..cb27827f0 --- /dev/null +++ b/lab6_virtual_memory/kernel/switch.S @@ -0,0 +1,72 @@ +.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 + + ldr x9, [x1, 8 * 13] + //and x9, x9, #0x0000FFFFFFFFFFFF + dsb ish // ensure write has completed + msr ttbr0_el1, x9 // switch translation based address. + tlbi vmalle1is // invalidate all TLB entries + dsb ish // ensure completion of TLB invalidatation + isb // clear pipeline + ret + +.global switch_pgd +switch_pgd: + dsb ish // ensure write has completed + msr ttbr0_el1, x0 // switch translation based address. + tlbi vmalle1is // invalidate all TLB entries + dsb ish // ensure completion of TLB invalidatation + isb // clear pipeline + ret + +.global get_pgd +get_pgd: + mrs x0, ttbr0_el1 + 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 \ No newline at end of file diff --git a/lab7_virtual_filesystem/README.md b/lab7_virtual_filesystem/README.md new file mode 100644 index 000000000..cd011ad03 --- /dev/null +++ b/lab7_virtual_filesystem/README.md @@ -0,0 +1,10 @@ +# Operating Systems Capstone 2022 + +||| +|:-:|:-:| +|Name|陳沐融| +|ID|310551063| +|GitHub|PersonalWorkingSpace| +|Email|TonyCHEN3000Tony@gmail.com| +||| +--- \ No newline at end of file diff --git a/lab7_virtual_filesystem/kernel/Makefile b/lab7_virtual_filesystem/kernel/Makefile new file mode 100644 index 000000000..b264132d6 --- /dev/null +++ b/lab7_virtual_filesystem/kernel/Makefile @@ -0,0 +1,61 @@ +BUILD = ./build +LIB_DIR = ../../lib +LIB_BUILD_DIR = ../../lib/build +INC_DIR = ../../include + +SRCS = $(wildcard *.c) +LIBS = $(notdir $(wildcard $(LIB_DIR)/*.c)) + +OBJS = $(patsubst %.c, $(BUILD)/%.o, $(SRCS)) $(patsubst %.c, $(LIB_BUILD_DIR)/%.o, $(LIBS)) +CFLAGS = -Wall -nostdinc -nostdlib -nostartfiles -ffreestanding -I $(INC_DIR) + +all: img + +$(BUILD)/start.o: start.S + aarch64-linux-gnu-gcc $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD)/exception_table.o: exception_table.S + aarch64-linux-gnu-gcc $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD)/switch.o: switch.S + aarch64-linux-gnu-gcc $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD)/%.o: %.c + aarch64-linux-gnu-gcc $(CFLAGS) -MMD -c $< -o $@ + +$(LIB_BUILD_DIR)/%.o: $(LIB_DIR)/%.c + aarch64-linux-gnu-gcc $(CFLAGS) -MMD -c $< -o $@ + +img: $(BUILD)/start.o $(BUILD)/exception_table.o $(BUILD)/switch.o $(OBJS) + aarch64-linux-gnu-ld $(BUILD)/start.o $(BUILD)/exception_table.o $(BUILD)/switch.o $(OBJS) -T linker.ld -o $(BUILD)/kernel8.elf + aarch64-linux-gnu-objcopy -O binary $(BUILD)/kernel8.elf $(BUILD)/kernel8.img + +clean: + rm $(BUILD)/* + +clean_lib: + rm $(LIB_BUILD_DIR)/*.o + +run: + qemu-system-aarch64 -M raspi3b -kernel $(BUILD)/kernel8.img -serial null -serial stdio -initrd ../user_program/initramfs.cpio -dtb ../../files_tools/bcm2710-rpi-3-b-plus.dtb + +run_debug: + qemu-system-aarch64 -M raspi3b -kernel $(BUILD)/kernel8.img -d in_asm -serial null -serial pty -initrd ../user_program/initramfs.cpio -dtb ../../files_tools/bcm2710-rpi-3-b-plus.dtb + +run_gdb: + qemu-system-aarch64 -M raspi3b -kernel $(BUILD)/kernel8.img -display none -serial null -serial pty -S -s -initrd ../user_program/initramfs.cpio -dtb ../../files_tools/bcm2710-rpi-3-b-plus.dtb& + gdb-multiarch +dump: + aarch64-linux-gnu-objdump -D -z $(BUILD)/kernel8.elf + +firm: + dd if=/dev/zero of=$(BUILD)/lab.img count=50 bs=1M + (echo o; echo n; echo p; echo 1; echo 2048; echo 102399; echo t; echo c; echo w) | fdisk $(BUILD)/lab.img + mkfs.vfat $(BUILD)/lab.img + sudo mkdir /mnt/lab + sudo mount $(BUILD)/lab.img /mnt/lab + sudo cp ../../firmware/* /mnt/lab + sudo cp $(BUILD)/kernel8.img /mnt/lab + sudo cp ../user_program/initramfs.cpio ./config.txt ../../files_tools/bcm2710-rpi-3-b-plus.dtb /mnt/lab + sudo umount /mnt/lab + sudo rmdir /mnt/lab diff --git a/lab7_virtual_filesystem/kernel/config.txt b/lab7_virtual_filesystem/kernel/config.txt new file mode 100644 index 000000000..f82b18ca9 --- /dev/null +++ b/lab7_virtual_filesystem/kernel/config.txt @@ -0,0 +1 @@ +initramfs initramfs.cpio 0x8000000 \ No newline at end of file diff --git a/lab7_virtual_filesystem/kernel/exception_table.S b/lab7_virtual_filesystem/kernel/exception_table.S new file mode 100644 index 000000000..069c7ad41 --- /dev/null +++ b/lab7_virtual_filesystem/kernel/exception_table.S @@ -0,0 +1,201 @@ +.section ".text" +.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_invalid_el1t // Synchronous EL1t + ventry irq_invalid_el1t // IRQ EL1t + ventry fiq_invalid_el1t // FIQ EL1t + ventry error_invalid_el1t // Error EL1t + + //Exception from the current EL while using SP_ELx + ventry sync_el1h // Synchronous EL1h + ventry irq_el1h // IRQ EL1h + ventry fiq_invalid_el1h // FIQ EL1h + ventry error_invalid_el1h // 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_invalid_el0_64 // FIQ 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 + + //Exception from a lower EL and at least all lower EL are AArch32 + ventry sync_invalid_el0_32 // Synchronous 32-bit EL0 + ventry irq_invalid_el0_32 // IRQ 32-bit EL0 + ventry fiq_invalid_el0_32 // FIQ 32-bit EL0 + ventry error_invalid_el0_32 // Error 32-bit EL0 + +// 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] + + //using for nested interrupt + mrs x0, spsr_el1 + mrs x1, elr_el1 + stp x0, x1, [sp, 16 * 15 + 8] + + mrs x0, sp_el0 + str x0, [sp, 16 * 16 + 8] + + ldp x0, x1, [sp, 16 * 0] // restore x0 +.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] + + ldp x0, x1, [sp, 16 * 15 + 8] + msr spsr_el1, x0 + msr elr_el1, x1 + + ldr x0, [sp, 16 * 16 + 8] + msr sp_el0, x0 + + ldp x0, x1, [sp, 16 * 0] + add sp, sp, 32 * 9 +.endm + +sync_invalid_el1t: + //save_all + mov x0,0 + bl exc_dump + //load_all + eret +irq_invalid_el1t: + save_all + mov x0,1 + bl exc_dump + load_all + eret +fiq_invalid_el1t: + save_all + mov x0,2 + bl exc_dump + load_all + eret +error_invalid_el1t: + save_all + mov x0,3 + bl exc_dump + load_all + eret + + + +sync_el1h: + //save_all + mov x0,4 + bl exc_dump + //load_all + eret +irq_el1h: + save_all + mov x0, sp // trap_frame + bl irq_dump + load_all + eret +fiq_invalid_el1h: + save_all + mov x0,6 + bl exc_dump + load_all + eret +error_invalid_el1h: + save_all + mov x0,7 + bl exc_dump + load_all + eret + + + +sync_el0_64: + save_all + mov x0, sp // trap_frame + mrs x1, esr_el1 + bl svc_handle + load_all + eret +irq_el0_64: + save_all + mov x0, sp // trap_frame + bl irq_dump + load_all + eret +fiq_invalid_el0_64: + save_all + mov x0,10 + bl exc_dump + load_all + eret +error_invalid_el0_64: + save_all + mov x0,11 + bl exc_dump + load_all + eret + + + +sync_invalid_el0_32: + save_all + mov x0,12 + bl exc_dump + load_all + eret +irq_invalid_el0_32: + save_all + mov x0,13 + bl exc_dump + load_all + eret +fiq_invalid_el0_32: + save_all + mov x0,14 + bl exc_dump + load_all + eret +error_invalid_el0_32: + save_all + mov x0,15 + bl exc_dump + load_all + eret \ No newline at end of file diff --git a/lab7_virtual_filesystem/kernel/linker.ld b/lab7_virtual_filesystem/kernel/linker.ld new file mode 100644 index 000000000..2cd4ebe1c --- /dev/null +++ b/lab7_virtual_filesystem/kernel/linker.ld @@ -0,0 +1,28 @@ +SECTIONS +{ + . = 0xffff000000000000; /* kernel space */ + . += 0x80000; /* kernel load address */ + _load_start = . ; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss : { + . = ALIGN(16); + _bss_start = .; + *(.bss .bss.*) + *(COMMON) + /* align is to ensure the size of bss section + is times of 64bits. Use 16bytes is a common strategy */ + . = ALIGN(16); + _bss_end = .; + } + _end = .; + _heap_start = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} + +/*>>3 = /8 => 8bytes*/ +_bss_size = (_bss_end - _bss_start)>>3; +_loader_size = (_end - _load_start)>>3; diff --git a/lab7_virtual_filesystem/kernel/main.c b/lab7_virtual_filesystem/kernel/main.c new file mode 100644 index 000000000..6f1829675 --- /dev/null +++ b/lab7_virtual_filesystem/kernel/main.c @@ -0,0 +1,55 @@ +#include "uart.h" +#include "power.h" +#include "string.h" +#include "utils.h" +#include "address.h" +#include "cpio.h" +#include "type.h" +#include "memory.h" +#include "timer.h" +#include "interrupt.h" +#include "thread.h" +#include "exception.h" +#include "vfs.h" + +// void test_path(char *path, char *currPath) { +// char dirname[200], rootName[200], abspath[200]; +// char *basename = get_dirname(dirname, path); +// char *leafname = get_rootname(rootName, path); +// get_abspath(abspath, path, currPath); + +// uart_printf("input: %s, %s\n", path, currPath); +// uart_printf("dirname: %s\n", dirname); +// uart_printf("basename: %s\n", basename); +// uart_printf("rootName: %s\n", rootName); +// uart_printf("leafname: %s\n", leafname); +// uart_printf("abspath: %s\n", abspath); +// uart_dem(); +// } + +int main(void) { + uart_init(); + uart_getc(); // flush init signal(0xE0) + uart_puts("Push any key to start ...\n"); + uart_getc(); + uart_puts("Push any key to start ...\n"); + uart_getc(); + + initMemoryPages(); + initThreads(); + init_vfs(); + + enable_interrupt(); + enable_uart_interrupt(); + enable_core_timer(); + set_core_timer_by_second(1); + + uint64 tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + + uart_dem(); + execThread("/initramfs/vfs1.img"); + return 0; +} \ No newline at end of file diff --git a/lab7_virtual_filesystem/kernel/start.S b/lab7_virtual_filesystem/kernel/start.S new file mode 100644 index 000000000..ad8671801 --- /dev/null +++ b/lab7_virtual_filesystem/kernel/start.S @@ -0,0 +1,81 @@ +#include "mmu.h" + +.section ".text" +.global _start // decdie entry point + +_start: + // only run program on core-0, others(1-3) are idle + mrs x1, mpidr_el1 // core identification, [7:0] - individual threads within a core + and x1, x1, #3 // 3 => 0~3 (rpi3 has 4 cores) + cbz x1, core0 // run progrm if core=0 else idle + +idle: + wfe // wait for event (idle) + b idle + +core0: + bl from_el2_to_el1 // switch exception level from 2 to 1 (Must at begining) + + // set paging configuration (up : 0xffff000000000000 low : 0x0000000000000000) + ldr x0, = TCR_CONFIG_DEFAULT + msr tcr_el1, x0 + + // set used memory attributes + ldr x0, =( \ + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | \ + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8)) \ + ) + msr mair_el1, x0 + + mov sp, 0x3c000000 + bl set_PGD + bl set_PUD + bl set_PMD + bl set_PTE + + ldr x0, =PGD_BASE + msr ttbr0_el1, x0 // load PGD to the bottom translation-based register. + msr ttbr1_el1, x0 // also load PGD to the upper translation based register. + + mrs x2, sctlr_el1 + orr x2 , x2, 1 + msr sctlr_el1, x2 // enable MMU, cache remains disabled + + ldr x2, =set_exception_vector_table // indirect branch to the virtual address + br x2 + +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + + // set the stack pointer at the top of memory (virtual address: 0xffff00003c000000) + movz x0, 0x0000 + movk x0, 0x3c00, lsl 16 // 3c000000 is the size of memory + movk x0, 0xffff, lsl 48 // 0xffff000000000000 is the start address of virtual kernel address + mov sp, x0 + + // set the uninitialized variable (bss section) to zero + // x - 64bits, w - 32bits (4bytes is large enough for size) + ldr x1, =_bss_start // _bss_start described in linker script + ldr w2, =_bss_size // _bss_size described in linker script + + +init_loop: + cbz w2, main_loop + str xzr, [x1], #8 // set x1 to zero(xzr), and x1's address + 8bytes + sub w2, w2, #1 + b init_loop + +main_loop: + bl main // branch with link (main function in c code, a while loop) + b idle // just in case fail + +from_el2_to_el1: + mov x0, #(3 << 20) // Make el0, el1 can use Floating point and Advanced SIMD + msr cpacr_el1, x0 + mov x0, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x0 + mov x0, 0x3c5 // EL1h (SPSel = 1) with interrupt disabled + msr spsr_el2, x0 + msr elr_el2, lr + eret // return to EL1 diff --git a/lab7_virtual_filesystem/kernel/switch.S b/lab7_virtual_filesystem/kernel/switch.S new file mode 100644 index 000000000..cb27827f0 --- /dev/null +++ b/lab7_virtual_filesystem/kernel/switch.S @@ -0,0 +1,72 @@ +.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 + + ldr x9, [x1, 8 * 13] + //and x9, x9, #0x0000FFFFFFFFFFFF + dsb ish // ensure write has completed + msr ttbr0_el1, x9 // switch translation based address. + tlbi vmalle1is // invalidate all TLB entries + dsb ish // ensure completion of TLB invalidatation + isb // clear pipeline + ret + +.global switch_pgd +switch_pgd: + dsb ish // ensure write has completed + msr ttbr0_el1, x0 // switch translation based address. + tlbi vmalle1is // invalidate all TLB entries + dsb ish // ensure completion of TLB invalidatation + isb // clear pipeline + ret + +.global get_pgd +get_pgd: + mrs x0, ttbr0_el1 + 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 \ No newline at end of file diff --git a/lib/cpio.c b/lib/cpio.c index 7a7ab7983..3031afa0c 100644 --- a/lib/cpio.c +++ b/lib/cpio.c @@ -101,17 +101,6 @@ char* load_user_program(char* address, char* program_address, char* name) { continue; } else if(strcmp(filename, name)) { - // uart_puts("Start loading file, size = "); - // uart_num(filesize); - // uart_newline(); - // char* kernel = program_address; - // while(filesize--) { - // *(kernel++) = *(p++); - // } - - // uart_puts("Loading done\n"); - // delay_ms(10); - break; } else { @@ -119,7 +108,7 @@ char* load_user_program(char* address, char* program_address, char* name) { } } while(strcmp(filename, "TRAILER!!!") == 0); - uart_async_puts("Get user program\n"); + // uart_puts("Get user program\n"); return p; } diff --git a/lib/dev_framebuffer.c b/lib/dev_framebuffer.c new file mode 100644 index 000000000..5d8459e8c --- /dev/null +++ b/lib/dev_framebuffer.c @@ -0,0 +1,94 @@ +#include "dev_framebuffer.h" +#include "vfs.h" +#include "uart.h" +#include "mbox.h" +#include "memory.h" +#include "type.h" + +file_operations_t dev_framebuffer_file_operations = {dev_framebuffer_write, (void*)nop_op, dev_framebuffer_open, dev_framebuffer_close, (void *)nop_op, (void *)nop_op}; + +unsigned int width, height, pitch, isrgb; /* dimensions and channel order */ +unsigned char *lfb; /* raw frame buffer address */ + +void init_dev_framebuffer() { + mbox[0] = 35 * 4; + mbox[1] = MBOX_REQUEST; + + mbox[2] = 0x48003; // set phy wh + mbox[3] = 8; + mbox[4] = 8; + mbox[5] = 1024; // FrameBufferInfo.width + mbox[6] = 768; // FrameBufferInfo.height + + mbox[7] = 0x48004; // set virt wh + mbox[8] = 8; + mbox[9] = 8; + mbox[10] = 1024; // FrameBufferInfo.virtual_width + mbox[11] = 768; // FrameBufferInfo.virtual_height + + mbox[12] = 0x48009; // set virt offset + mbox[13] = 8; + mbox[14] = 8; + mbox[15] = 0; // FrameBufferInfo.x_offset + mbox[16] = 0; // FrameBufferInfo.y.offset + + mbox[17] = 0x48005; // set depth + mbox[18] = 4; + mbox[19] = 4; + mbox[20] = 32; // FrameBufferInfo.depth + + mbox[21] = 0x48006; // set pixel order + mbox[22] = 4; + mbox[23] = 4; + mbox[24] = 1; // RGB, not BGR preferably + + mbox[25] = 0x40001; // get framebuffer, gets alignment on request + mbox[26] = 8; + mbox[27] = 8; + mbox[28] = 4096; // FrameBufferInfo.pointer + mbox[29] = 0; // FrameBufferInfo.size + + mbox[30] = 0x40008; // get pitch + mbox[31] = 4; + mbox[32] = 4; + mbox[33] = 0; // FrameBufferInfo.pitch + + mbox[34] = MBOX_TAG_LAST; + + // this might not return exactly what we asked for, could be + // the closest supported resolution instead + if (_mbox_call(MBOX_CH_PROP) && mbox[20] == 32 && mbox[28] != 0) { + mbox[28] &= 0x3FFFFFFF; // convert GPU address to ARM address + width = mbox[5]; // get actual physical width + height = mbox[6]; // get actual physical height + pitch = mbox[33]; // get number of bytes per line + isrgb = mbox[24]; // get the actual channel order + lfb = (void*)PHY_TO_VIR((uint64)mbox[28]); + } + else { + uart_printf("Unable to set screen resolution to 1024x768x32\n"); + } +} + +int dev_framebuffer_write(file_t *file, const void *buf, size_t len) { + lock_interrupt(); + int framebuffer_size = pitch * height; + len = (file->f_pos + len > framebuffer_size) ? framebuffer_size - file->f_pos : len; + memcpy(lfb + file->f_pos, buf, len); + file->f_pos += len; + unlock_interrupt(); + + return len; +} + +int dev_framebuffer_open(vnode_t *file_node, file_t **target) { + (*target)->vnode = file_node; + (*target)->f_ops = &dev_framebuffer_file_operations; + (*target)->f_pos = 0; + return 0; +} + +int dev_framebuffer_close(file_t *file) { + free((void*)file); + return 0; +} \ No newline at end of file diff --git a/lib/dev_uart.c b/lib/dev_uart.c new file mode 100644 index 000000000..3e8623457 --- /dev/null +++ b/lib/dev_uart.c @@ -0,0 +1,34 @@ +#include "dev_uart.h" +#include "vfs.h" +#include "uart.h" +#include "memory.h" + +file_operations_t dev_uart_file_operations = {dev_uart_write, dev_uart_read, dev_uart_open, dev_uart_close, (void *)nop_op, (void *)nop_op}; + + +int dev_uart_write(file_t *file, const void *buf, size_t len) { + for(int i = 0; i < len; i++) { + uart_putc(((char*)buf)[i]); + } + return len; +} + +int dev_uart_read(file_t *file, void *buf, size_t len) { + for(int i = 0; i < len; i++) { + do { + ((char*)buf)[i] = uart_async_getc(); + } while(((char*)buf)[i] == NULL); + } + return len; +} + +int dev_uart_open(vnode_t *file_node, file_t **target) { + (*target)->vnode = file_node; + (*target)->f_ops = &dev_uart_file_operations; + return 0; +} + +int dev_uart_close(file_t *file) { + free((void*)file); + return 0; +} \ No newline at end of file diff --git a/lib/exception.c b/lib/exception.c index b0ad7e180..212ac30ca 100644 --- a/lib/exception.c +++ b/lib/exception.c @@ -33,15 +33,14 @@ #include "syscall.h" #include "thread.h" #include "signal.h" +#include "mmu.h" -void raise_exc() -{ +void raise_exc() { asm volatile ("svc 0"); } -void el1_to_el0(char* program_address, char* user_stack_address) -{ +void el1_to_el0(char* program_address, char* user_stack_address) { asm volatile( "msr elr_el1, %0\n\t" // "mov x1, 0x3c0\n\t" @@ -54,28 +53,58 @@ void el1_to_el0(char* program_address, char* user_stack_address) ); } -void svc_handle(trapFrame_t *frame) { +void svc_handle(trapFrame_t *frame, uint64 x1) { uint64 mode = frame->x8; uint64 *returnValue = &frame->x0; - // uart_puts("SVC Handle Mode = "); uart_num(mode); uart_newline(); + // MMU page fault + esr_el1_t *esr; + esr = (esr_el1_t *)&x1; + if (esr->ec == DATA_ABORT_LOWER) { + raiseError("DATA_ABORT_LOWER Fault\n"); + // handle_abort(esr); + return; + } + else if(esr->ec == INS_ABORT_LOWER) { + raiseError("INS_ABORT_LOWER Fault\n"); + // handle_abort(esr); + return; + } + + // uart_printf("SVC Handle Mode = %d\n", mode); //delay_ms(100); enable_interrupt(); switch(mode) { case 0: *returnValue = getpid(); break; case 1: *returnValue = uart_read((char *)frame->x0, (size_t)frame->x1); break; case 2: *returnValue = uart_write((char *)frame->x0, (size_t)frame->x1); break; case 3: *returnValue = exec(frame, (char *)frame->x0, (char **)frame->x1); break; - case 4: *returnValue = fork(frame); /*uart_puts("fork return = "); uart_num(*returnValue); uart_newline();*/ break; + case 4: *returnValue = fork(frame); + // uart_printf("Return %d Done\n", *returnValue); + break; case 5: exit((int)frame->x0); break; case 6: *returnValue = mbox_call((unsigned char)frame->x0, (unsigned int *)frame->x1); break; case 7: kill((int)frame->x0); break; + case 8: signal_register(frame->x0, (void (*)())frame->x1); break; case 9: signal_kill(frame->spsr_el1, frame->x0, frame->x1); break; case 115: signal_return(frame); break; + + case 11: *returnValue = call_vfs_open((char*)frame->x0, frame->x1); break; + case 12: *returnValue = call_vfs_close(frame->x0); break; + case 13: *returnValue = call_vfs_write(frame->x0, (char*)frame->x1, frame->x2); break; + case 14: *returnValue = call_vfs_read(frame->x0, (char*)frame->x1, frame->x2); break; + case 15: *returnValue = call_vfs_mkdir((char*)frame->x0, frame->x1); break; + case 16: *returnValue = call_vfs_mount((char*)frame->x0, (char*)frame->x1, (char*)frame->x2, frame->x3, (void*)frame->x4); break; + case 17: *returnValue = call_vfs_chdir((char*)frame->x0); break; + case 18: *returnValue = call_vfs_lseek64(frame->x0, frame->x1, frame->x2); break; + case 19: *returnValue = call_vfs_ioctl(frame->x0, frame->x1, (void*)frame->x2); break; + default: break; } - lock_interrupt(); - unlock_interrupt(); + + // if(mode == 4) { + // uart_printf("SVC Handle Mode %d Done: 0x%x\n", mode, *returnValue); + // } } void exc_dump(unsigned long num, unsigned long esr, unsigned long elr, unsigned long spsr, unsigned long type) { @@ -146,50 +175,43 @@ void uart_dump() { 11: */ - // buffer read, write - if (*AUX_MU_IIR & (0b01 << 1)) //can write - { - // uart_puts("Interrupt-UART TX\n"); + // buffer write + if (*AUX_MU_IIR & (0b01 << 1)) { + // uart_printf("UART TX Interrupt\n"); disable_uart_w_interrupt(); add_interrupt(uart_interrupt_w_handler, UART_INTERRUPT_TX_PRIORITY); - // uart_interrupt_w_handler(); - // enable_uart_w_interrupt(); + // uart_printf("UART TX Done\n"); } - else if (*AUX_MU_IIR & (0b10 << 1)) // can read - { - // uart_puts("Interrupt-UART RX\n"); + // buffer read + else if (*AUX_MU_IIR & (0b10 << 1)) { + // uart_printf("UART RX Interrupt\n"); disable_uart_r_interrupt(); add_interrupt(uart_interrupt_r_handler, UART_INTERRUPT_RX_PRIORITY); - // uart_interrupt_r_handler(); - // enable_uart_r_interrupt(); + // uart_printf("UART RX Done\n"); } - else - { + else { uart_puts("UART Interrupt error\n"); } } void irq_dump(trapFrame_t *frame){ - - if(*IRQ_PENDING_1 & IRQ_PENDING_1_AUX_INT && *CORE0_INTERRUPT_SOURCE & INTERRUPT_SOURCE_GPU) // from aux && from GPU0 -> uart exception - { + // from aux && from GPU0 -> uart exception + if(*IRQ_PENDING_1 & IRQ_PENDING_1_AUX_INT && *CORE0_INTERRUPT_SOURCE & INTERRUPT_SOURCE_GPU) { + // uart_printf("UART Interrupt\n"); uart_dump(); } - else if(*CORE0_INTERRUPT_SOURCE & INTERRUPT_SOURCE_CNTPNSIRQ) //from CNTPNS (core_timer) - { - // uart_puts("Interrupt-Timer\n"); + //from CNTPNS (core_timer) + else if(*CORE0_INTERRUPT_SOURCE & INTERRUPT_SOURCE_CNTPNSIRQ) { disable_core_timer(); + // uart_printf("Timer Interrupt\n"); add_interrupt(core_timer_handler, TIMER_INTERRUPT_PRIORITY); if (run_queue->next->next != run_queue) schedule(); - // uart_puts("Done\n"); - // core_timer_handler(); - // enable_core_timer(); + // uart_printf("Timer Add Interrupt Done\n"); } else { uart_puts("No support this irq\n"); } - if ((frame->spsr_el1 & 0b1111) == 0) {; signal_execute(); } diff --git a/lib/fdt.c b/lib/fdt.c index 2b49f1059..c24c82806 100644 --- a/lib/fdt.c +++ b/lib/fdt.c @@ -3,15 +3,16 @@ #include "string.h" #include "address.h" #include "utils.h" +#include "mmu.h" -uint32* initramfs = INITRAMFS_ADDR; +uint64 initramfs = (uint64)INITRAMFS_ADDR; int initramfs_callback(char* data, char* name, char* prop_name) { // get init ramfs location if(strcmp(name, "chosen") && strcmp(prop_name, "linux,initrd-start")) { - uint32 value = *((uint32*)data); + uint64 value = *((uint64*)data); value = SWAP32(value); // big endian - initramfs = (volatile uint32*)value; + initramfs = PHY_TO_VIR(value); uart_puts("Get initramfs: "); uart_hex(value); uart_newline(); diff --git a/lib/initramfs.c b/lib/initramfs.c new file mode 100644 index 000000000..9c2e0b2c8 --- /dev/null +++ b/lib/initramfs.c @@ -0,0 +1,133 @@ +#include "initramfs.h" +#include "string.h" +#include "memory.h" +#include "cpio.h" +#include "utils.h" + +file_operations_t initramfs_file_operations = {initramfs_write, initramfs_read, initramfs_open, initramfs_close, vfs_lseek64, initramfs_getsize}; +vnode_operations_t initramfs_vnode_operations = {initramfs_lookup, initramfs_create, initramfs_mkdir}; + +filesystem_t *get_initramfs() { + filesystem_t *initramfs = (filesystem_t*)malloc(sizeof(filesystem_t)); + initramfs->name = "initramfs"; + initramfs->setup_mount = setup_initramfs_mount; + return initramfs; +} + +int setup_initramfs_mount(filesystem_t *fs, mount_t *mount) { + uart_printf("Mount initramfs\n"); + mount->root = create_initramfs_vnode(NULL, nt_dir); + mount->fs = fs; + + initramfs_internal_t *root_internal = (initramfs_internal_t*)mount->root->internal; + // add all files under root of initramfs + + char filename[MAX_PATHNAME]; + char *p = (char*)INITRAMFS_ADDR; + char *initram_address = (char*)INITRAMFS_ADDR; + uint64 namesize, filesize; + uint64 idx = 0; + + do { + filesize = hex2num(p + 54, 8); + namesize = hex2num(p + 94, 8); + p = extract_section(filename, p + 110, initram_address, namesize); // read filename + + if(strcmp(filename, "TRAILER!!!")) { // ending string + break; + } + + if(strcmp(filename, ".")) { // always the first file without any content + continue; + } + + // create entry under root + vnode_t *new_entry = create_initramfs_vnode(NULL, nt_file); + initramfs_internal_t *new_entry_internal = (initramfs_internal_t*)new_entry->internal; + free((void*)new_entry_internal->data); + + uart_printf("(initramfs) Add %s (0x%x)\n", filename, p); + new_entry_internal->data = p; + new_entry_internal->datasize = filesize; + strcpy(new_entry_internal->name, filename); + root_internal->entry[idx++] = new_entry; + + // jump to next file + p += filesize; + if((*p) == 0x00) { //4 bytes padding if necessary + p += 4 - ((uint64)(p - initram_address) % 4); + } + + } while(strcmp(filename, "TRAILER!!!") == 0); + + + return 0; +} + +vnode_t *create_initramfs_vnode(mount_t *mount, enum NodeType ntype) { + vnode_t *vn = (vnode_t*)malloc(sizeof(vnode_t)); + vn->mount = mount; + vn->v_ops = &initramfs_vnode_operations; + vn->f_ops = &initramfs_file_operations; + + vn->internal = malloc(sizeof(initramfs_internal_t)); + memset(vn->internal, 0, sizeof(initramfs_internal_t)); + + initramfs_internal_t *vn_internal = (initramfs_internal_t*)vn->internal; + vn_internal->ntype = ntype; + vn_internal->data = (char*)malloc(MAX_FILE_SIZE); + vn_internal->datasize = MAX_FILE_SIZE; + return vn; +} + +int initramfs_write(file_t *file, const void *buf, size_t len) { + return -1; +} + +int initramfs_read(file_t *file, void *buf, size_t len) { + initramfs_internal_t *internal = (initramfs_internal_t*)file->vnode->internal; + len = (file->f_pos + len < internal->datasize) ? len : internal->datasize - file->f_pos; + // uart_printf("(initramfs) read from 0x%x(%d) to 0x%x, %d bytes\n", internal->data + file->f_pos, file->f_pos, buf, len); + memcpy(buf, internal->data + file->f_pos, len); + file->f_pos += len; + + return len; +} + +int initramfs_open(vnode_t *file_node, file_t **target) { + (*target)->vnode = file_node; + (*target)->f_ops = file_node->f_ops; + (*target)->f_pos = 0; + return 0; +} + +int initramfs_close(file_t *file) { + free((void*)file); + return 0; +} + +int initramfs_getsize(vnode_t *target) { + return ((initramfs_internal_t*)target->internal)->datasize; +} + +int initramfs_lookup(vnode_t *dir, vnode_t **target, const char *component_name) { + for(int i = 0; i < MAX_ENTRY; i++) { + vnode_t *ent = ((initramfs_internal_t*)dir->internal)->entry[i]; + if(ent && strcmp(component_name, ((initramfs_internal_t*)ent->internal)->name)) { + *target = ent; + return 0; + } + } + + uart_printf("[ERROR](initramfs) fail to lookup\n"); + return -1; +} + +int initramfs_create(vnode_t *dir, vnode_t **target, const char *component_name) { + return -1; +} + +int initramfs_mkdir(vnode_t *dir, vnode_t **target, const char *component_name) { + return -1; +} + diff --git a/lib/interrupt.c b/lib/interrupt.c index e2ac81604..ea76cbe11 100644 --- a/lib/interrupt.c +++ b/lib/interrupt.c @@ -4,9 +4,10 @@ #include "string.h" #include "memory.h" #include "utils.h" +#include "timer.h" -volatile interrupt_event_t* interrupt_event_pointer = NULL; -volatile interrupt_event_t* preemption_event_pointer = NULL; +interrupt_event_t* interrupt_event_pointer = NULL; +interrupt_event_t* preemption_event_pointer = NULL; volatile int flag = 0; // 0 - wait loop, 1 - preemption wait loop @@ -137,17 +138,19 @@ void run_interrupt() lock_interrupt(); interrupt_event_pointer = next_event_p; } + // uart_printf("Run Interrupt Done\n"); } void exec_handler(interrupt_event_t* event_p) { - // uart_puts("Exec Handler: "); uart_num(event_p->priority); uart_newline(); + // if(event_p->priority == 1) + // uart_printf("Exec Handler(%d) at 0x%x (0x%x)\n", event_p->priority, event_p->handler, core_timer_handler); ((void (*)())event_p->handler)(); free(event_p); + // uart_printf("Exec Interrupt Handle Done\n"); } -unsigned long long is_disable_interrupt() -{ +unsigned long long is_disable_interrupt() { unsigned long long daif; __asm__ __volatile__("mrs %0, daif\n\t" : "=r"(daif)); diff --git a/lib/mbox.c b/lib/mbox.c index 1f6095258..e5fef4532 100644 --- a/lib/mbox.c +++ b/lib/mbox.c @@ -1,10 +1,11 @@ #include "address.h" #include "mbox.h" +#include "mmu.h" volatile unsigned int __attribute__((aligned(16))) mbox[36]; int _mbox_call(unsigned char ch) { - unsigned int r = (((unsigned int)((unsigned long)&mbox) & ~0xF) | (ch & 0xF)); + unsigned long r = (((unsigned long)((unsigned long)&mbox) & ~0xF) | (ch & 0xF)); // wait for ready do { asm volatile("nop"); @@ -20,7 +21,7 @@ int _mbox_call(unsigned char ch) { } while(*MBOX_STATUS & MBOX_EMPTY); // make sure it is a response to our message - if(r == *MBOX_READ) { + if(r == PHY_TO_VIR(*MBOX_READ)) { // is it a valid successful response return mbox[1] == MBOX_RESPONSE; } diff --git a/lib/memory.c b/lib/memory.c index 65accc195..6adca63eb 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -1,32 +1,24 @@ -#include "address.h" #include "memory.h" -#include "cpio.h" -#include "uart.h" -#include "math.h" -#include "type.h" -#include "interrupt.h" - -uint64 _stack_size = 0x10000ULL; -page_t* usedPage = NULL; - -void* simple_malloc(unsigned int size) { - char* r = heap + 0x10; - if(size < 0x18) - size = 0x18; // minimum size 0x20 //like ptmalloc + +extern char _end; // linker script symbol +extern char _heap_start; // linker script symbol +static char *heap = &_heap_start; +static char *kernel_end = &_end; + +void *simple_malloc(unsigned int size) { + char *r = heap + 0x10; + if (size < 0x18) { + size = 0x18; // minimum size 0x20 //like ptmalloc + } size = size + 0x7; size = 0x10 + size - size % 0x10; - *(unsigned int*)(r - 0x8) = size; + *(unsigned int *)(r - 0x8) = size; heap += size; - if(heap > heap_end) { - raiseError("Run out of heap\n"); - } - return r; } -char* memcpy (void *dest, const void *src, unsigned long long len) -{ +char *memcpy (void *dest, const void *src, unsigned long long len) { char *d = dest; const char *s = src; while (len--) @@ -34,546 +26,255 @@ char* memcpy (void *dest, const void *src, unsigned long long len) return dest; } -pageHeader_t pagesAtOrder[MAX_ORDER]; -uint64 usedAddress[MAX_PAGES]; - -void initMemoryPages() { - for(int order = 0; order < (MAX_ORDER - 1); order++) { - pagesAtOrder[order].firstFree = createPage(order, PAGE_BEGIN_ADDRESS, EMPTY); - pagesAtOrder[order].firstEmpty = pagesAtOrder[order].firstFree; - - /* - The memory used by paging is allocated by simple_malloc which isn't free-able. - To avoid memory leaking, we allocate all the memory used by paging at once. - */ - page_t* page = pagesAtOrder[order].firstFree; - int pageNum = getPageNumAtOrder(order); - // uart_puts("There are "); uart_num(pageNum); uart_puts(" pages in order: "); uart_num(order); uart_newline(); - - for(int i = 1; i < pageNum; i++) { - page->nextPage = createPage(order, PAGE_BEGIN_ADDRESS + i * getPageSizeAtOrder(order), EMPTY); - page->nextPage->prevPage = page; - page = page->nextPage; - } - } - - // uart_puts("There are 1 page in max order: "); uart_num(MAX_ORDER - 1); uart_newline(); - pagesAtOrder[MAX_ORDER - 1].firstFree = createPage(MAX_ORDER - 1, PAGE_BEGIN_ADDRESS, FREE); - pagesAtOrder[MAX_ORDER - 1].firstEmpty = NULL; - - init_reserve(); - for(int i = 0; i < MAX_PAGES; i++) { - usedAddress[i] = NULL; - } - - // loggingAllPageState(); -} - -page_t* createPage(uint32 order, uint64 address, int state) { - page_t* newPage = (page_t*)simple_malloc(sizeof(page_t)); - newPage->order = order; - newPage->address = address; - newPage->state = state; - newPage->prevPage = NULL; - newPage->nextPage = NULL; - newPage->buddyPage = NULL; - newPage->parentPage = NULL; - newPage->appendPage = NULL; - newPage->pool = (memoryPool_t*)simple_malloc(sizeof(memoryPool_t)); - return newPage; -} +void *memset(void *s, int c, size_t n) { + char *start = s; + for (size_t i = 0; i < n; i++) { + start[i] = c; + } -void initPool(memoryPool_t* pool, uint32 maxSize, uint32 size, uint64 address) { - pool->address = address; - pool->size = size; - pool->stateBitMap = ~(0x00ULL); - int num = maxSize / size; - pool->mask = pool->stateBitMap >> (64 - num); + return s; } -void* malloc(uint32 size) { - lock_interrupt(); - uint32 order = sizeToSmallestOrder(size); - size = exp2(order); - order = log2(size / (MINI_PAGE_SIZE * KB)); - - // uart_puts("size = "); uart_num(size); uart_newline(); - // uart_puts("order = "); uart_num(order); uart_newline(); - - if(usedPage == NULL) { - // uart_puts("Init used page\n"); - usedPage = getFreePageAtOrder(order); - initPool(usedPage->pool, getPageSizeAtOrder(order), size, usedPage->address); - } - else if(isAllFull(usedPage, size)) { - // uart_puts("Allocate new page\n"); - page_t* newPage = getFreePageAtOrder(order); - initPool(newPage->pool, getPageSizeAtOrder(order), size, newPage->address); - appendNewPage(usedPage, newPage); - } - - // showAppendPage(usedPage); - void *address = allocateMemoryFromPage(usedPage, size); - unlock_interrupt(); +static frame_t* framearray; +static list_head_t freelist[MAXORDER + 1]; // 4K * (idx**ORDER) (for every 4K) (page) +static list_head_t cachelist[MAXCACHEORDER + 1]; // 32, 64, 128, 256, 512 (for every 32bytes) - return address; -} +void initMemoryPages() { + framearray = simple_malloc(BUDDYSYSTEM_PAGE_COUNT * sizeof(frame_t)); -uint32 sizeToSmallestOrder(uint32 size) { - uint32 order = log2(size); - if(size > exp2(order)) { - order++; + // init framearray + for (int i = 0; i < BUDDYSYSTEM_PAGE_COUNT; i++) { + if (i % (1 << MAXORDER) == 0) { + framearray[i].isused = 0; + framearray[i].val = MAXORDER; + } } - return order; -} - -void appendNewPage(page_t* parentPage, page_t* newPage) { - page_t* page = parentPage; - while(page->appendPage != NULL) { - page = page->appendPage; + //init frame freelist + for (int i = 0; i <= MAXORDER; i++) { + INIT_LIST_HEAD(&freelist[i]); } - newPage->appendPage = NULL; - page->appendPage = newPage; -} - -void showAppendPage(page_t *parentPage) { - page_t* page = parentPage; - while(page != NULL) { - loggingPage(page); - page = page->appendPage; - } -} + for (int i = 0; i < BUDDYSYSTEM_PAGE_COUNT; i++) { + //init listhead for each frame + INIT_LIST_HEAD(&framearray[i].listhead); + framearray[i].idx = i; + framearray[i].cacheorder = -1; -bool isAllFull(page_t* page, uint32 size) { - while(page != NULL) { - if(isFull(page, size)) { - page = page->appendPage; - } - else { - return false; + //add init frame into freelist + if (i % (1 << MAXORDER) == 0) { + list_add(&framearray[i].listhead, &freelist[MAXORDER]); } } - return true; -} - -bool isFull(page_t* page, uint32 size) { - return isPoolFull(page->pool, size); -} -bool isPoolFull(memoryPool_t* pool, uint32 size) { - return size > pool->size || (pool->stateBitMap & pool->mask) == 0ULL; -} + //init cachelist + for (int i = 0; i <= MAXCACHEORDER; i++) { + INIT_LIST_HEAD(&cachelist[i]); + } -void* allocateMemoryFromPage(page_t* page, uint32 size) { - page_t* allocatedPage = NULL; - // uart_puts("Allocate page for memory\n"); - while(page != NULL) { - if(!isFull(page, size)) { - allocatedPage = page; + /* should reserve these memory region + Spin tables for multicore boot (0x0000 - 0x1000) + Kernel image in the physical memory + Initramfs + Devicetree (Optional, if you have implement it) + Your simple allocator (startup allocator) + stack + */ + + memory_reserve(PHY_TO_VIR(0x0000), PHY_TO_VIR(0x1000)); + memory_reserve(PHY_TO_VIR(PGD_BASE), PHY_TO_VIR((PTE_BASE + 512 * 512 * 2 * 8))); + memory_reserve((unsigned long long)LOAD_ADDR, (unsigned long long)kernel_end); + memory_reserve((unsigned long long)&_heap_start, (unsigned long long)heap); //simple + memory_reserve((unsigned long long)INITRAMFS_ADDR, (unsigned long long)INITRAMFS_ADDR + MAX_INITRAMFS_SIZE); + memory_reserve(PHY_TO_VIR(0x2c000000), PHY_TO_VIR(0x3c000000)); //0x2c000000L - 0x3c000000L (stack) +} + +// smallest 4K +void *allocpage(unsigned int size) { + // get real val size + // int allocsize; + int val; + for (int i = 0; i <= MAXORDER; i++) { + if (size <= (0x1000 << i)) { + val = i; break; } - page = page->appendPage; + if (i == MAXORDER) { + raiseError("Too large to malloc!!!\n"); + } } - if(allocatedPage == NULL) { - raiseError("Can't allocate any memory from pages\n"); + // find the smallest larger frame in freelist + int target_list_val; + for (target_list_val = val; target_list_val <= MAXORDER; target_list_val++) { + if (!list_empty(&freelist[target_list_val])) + break; } - // uart_puts("Allocate pool for memory\n"); - memoryPool_t* allocatedPool = allocatedPage->pool; - - if(allocatedPool == NULL) { - raiseError("Can't allocate any memory from pools (NULL)\n"); - } - else if(isPoolFull(allocatedPool, size)) { - raiseError("Can't allocate any memory from pools (FULL)\n"); + if (target_list_val > MAXORDER) { + raiseError("malloc ERROR, run out all list that large enough!!!\n"); } - - uint32 shift = log2(allocatedPool->stateBitMap & allocatedPool->mask); - allocatedPool->stateBitMap &= ~(1ULL << shift); - // loggingPool(allocatedPool); - - // uart_puts("Mark as used memory, state = "); - // uart_hex(allocatedPool->stateBitMap >> 32); uart_hex(allocatedPool->stateBitMap); - // uart_newline(); - // uart_puts("AllocatedPage at "); uart_hex(allocatedPage->address); uart_newline(); - registerUsedAddress(allocatedPage); - return (void*)(allocatedPool->address + shift * allocatedPool->size); -} -void registerUsedAddress(page_t* page) { - uint32 idx = addressToBlockIdx(page->address); - uint32 numCoverdPage = exp2(page->order); + //get the frame + frame_t *target_frame_ptr = (frame_t *)freelist[target_list_val].next; + list_del_entry((struct list_head *)target_frame_ptr); - for(int i = 0; i < numCoverdPage; i++) { - usedAddress[i + idx] = page; + // Release redundant memory block + for (int j = target_list_val; j > val; j--) { + release_redundant(target_frame_ptr); } + target_frame_ptr->isused = 1; + return (void *)BUDDYSYSTEM_START + (0x1000 * (target_frame_ptr->idx)); } -uint32 addressToBlockIdx(uint64 address) { - return (address - PAGE_BEGIN_ADDRESS) / (MINI_PAGE_SIZE * KB); -} - -page_t* getFreePageAtOrder(uint32 order) { - if(order >= MAX_ORDER) { - uart_num(order); uart_puts(" is higher than max order: "); uart_num(MAX_ORDER); uart_newline(); - raiseError("Run out of memory\n"); - } +void freepage(void *ptr) { + frame_t *target_frame_ptr = &framearray[((unsigned long long)ptr - BUDDYSYSTEM_START) >> 12]; - if(hasNoFreePageAtOrder(order)) { - // uart_puts("Has no free page at order: "); uart_num(order); uart_puts(", get page from higher order\n"); - page_t* pageAtHigherOrder = getFreePageAtOrder(order + 1); - // uart_puts("Divide page from order: "); uart_num(order + 1); uart_puts(" to order: "); uart_num(order); uart_newline(); - dividePageToLowerOrder(pageAtHigherOrder); + target_frame_ptr->isused = 0; + frame_t* temp; + while ((temp = coalesce(target_frame_ptr)) != (frame_t *)-1) { + target_frame_ptr = temp; } - - // uart_puts("Allocate page at order: "); uart_num(order); uart_newline(); - page_t* page = pagesAtOrder[order].firstFree; - // loggingPage(page); - page->appendPage = NULL; - page->state = BUSY; - - if(isNotPageTail(pagesAtOrder[order].firstFree)) { - pagesAtOrder[order].firstFree = pagesAtOrder[order].firstFree->nextPage; - } - // else { - // uart_puts("Full use at order: "); uart_num(order); uart_newline(); - // } - - return page; -} -void loggingPage(page_t* page) { - uart_puts("Page ("); uart_hex(page); uart_puts(") "); - uart_puts("Order: "); uart_num(page->order); uart_puts(" "); - uart_puts("Address: "); uart_hex(page->address); uart_puts(" ~ "); - uart_hex(page->address + getPageSizeAtOrder(page->order)); uart_puts(" "); - uart_puts("State: "); uart_num(page->state); uart_newline(); - // uart_puts("Previous page: "); uart_hex(page->prevPage); uart_puts(" "); - // uart_puts("Next page: "); uart_hex(page->nextPage); uart_newline(); - // uart_puts("Buddy page: "); uart_hex(page->buddyPage); uart_puts(" "); - // uart_puts("Parent Page: "); uart_hex(page->parentPage); uart_newline(); - - // memoryPool_t* pool = page->headPool; - // for(int i = 0; i < NUM_POOL; i++) { - // loggingPool(pool); - // pool = pool->nextPool; - // } + list_add(&target_frame_ptr->listhead, &freelist[target_frame_ptr->val]); } -void loggingPool(memoryPool_t* pool) { - uart_puts("Pool ("); uart_hex(pool); uart_puts(") "); - uart_puts("Address: "); uart_hex(pool->address); uart_puts(" "); - uart_puts("Size: "); uart_num(pool->size); uart_puts(" "); - uart_puts("Mask: "); uart_hex(pool->mask>>32); uart_hex(pool->mask); uart_newline(); - - uint64 state = pool->stateBitMap & pool->mask; - uart_puts("State: "); uart_hex(state>>32); uart_hex(state); uart_newline(); +frame_t *release_redundant(frame_t *frame_ptr) { + frame_ptr->val -= 1; + frame_t *buddyptr = get_buddy(frame_ptr); + buddyptr->val = frame_ptr->val; + buddyptr->isused = 0; + list_add(&buddyptr->listhead, &freelist[buddyptr->val]); + return frame_ptr; } -bool hasFreePageAtOrder(uint32 order) { - return pagesAtOrder[order].firstFree->state == FREE; +frame_t *get_buddy(frame_t *frame) { + return &framearray[frame->idx ^ (1 << frame->val)]; } -bool hasNoFreePageAtOrder(uint32 order) { - return pagesAtOrder[order].firstFree->state != FREE; -} +//return 0 -> success +//return -1 -> cannot coalesce +frame_t *coalesce(frame_t *frame_ptr) { + frame_t *buddy = get_buddy(frame_ptr); -void dividePageToLowerOrder(page_t* page) { - uint32 order = page->order; - uint64 address = page->address; - page_t* topHalfPage = addPageAtOrder(order - 1, address, page); - page_t* bottomHalfPage = addPageAtOrder(order - 1, address + getPageSizeAtOrder(order - 1), page); - bindAsBuddy(topHalfPage, bottomHalfPage); -} + // MAXORDER + if (frame_ptr->val == MAXORDER) + return (frame_t*)-1; -page_t* addPageAtOrder(uint32 order, uint64 address, page_t* parentPage) { - page_t* page = pagesAtOrder[order].firstEmpty; - page->address = address; - page->state = FREE; - page->parentPage = parentPage; - if(isNotPageTail(pagesAtOrder[order].firstEmpty)) { - pagesAtOrder[order].firstEmpty = pagesAtOrder[order].firstEmpty->nextPage; - } - // else { - // uart_puts("No any empty page at order: "); uart_num(order); uart_newline(); - // } - return page; -} + // val not the same (there is some chunks in the buddy used) + if (frame_ptr->val != buddy->val) + return (frame_t *)-1; -uint64 getPageSizeAtOrder(uint32 order) { - uint64 num = exp2(order); - return num * MINI_PAGE_SIZE * KB; -} + //buddy is used + if (buddy->isused == 1) + return (frame_t *)-1; -uint64 getPageNumAtOrder(uint32 order) { - return exp2(MAX_ORDER - 1 - order); -} + list_del_entry((struct list_head *)buddy); + frame_ptr->val += 1; + buddy->val += 1; -void bindAsBuddy(page_t* page1, page_t* page2) { - page1->buddyPage = page2; - page2->buddyPage = page1; + return buddy < frame_ptr ? buddy : frame_ptr; } -void freePage(page_t* page) { - if(page->state != BUSY) { - uart_puts("Not free-able\n"); - return; - } - - uint32 order = page->order; - page->state = FREE; - - // uart_puts("Free page at order: "); uart_num(order); uart_newline(); - - if(page->order == (MAX_ORDER - 1)) { - return; - } - - if(!isFirstEmpty(page)) { - if(isNotPageHead(page)) { - // uart_puts("Relink page at order: "); uart_num(order); uart_newline(); - page->prevPage->nextPage = page->nextPage; - } - - if(pagesAtOrder[order].firstEmpty->state == EMPTY) { - page->nextPage->prevPage = page->prevPage; - page->nextPage = pagesAtOrder[order].firstEmpty; - page->prevPage = pagesAtOrder[order].firstEmpty->prevPage; - pagesAtOrder[order].firstEmpty->prevPage->nextPage = page; - pagesAtOrder[order].firstEmpty->prevPage = page; - } - else { - // uart_puts("Full use case at order: "); uart_num(order); uart_newline(); - page->nextPage->prevPage = page->prevPage; - page->prevPage = pagesAtOrder[order].firstEmpty; - page->nextPage = pagesAtOrder[order].firstEmpty->nextPage; - pagesAtOrder[order].firstEmpty->nextPage->prevPage = page; - pagesAtOrder[order].firstEmpty->nextPage = page; - pagesAtOrder[order].firstEmpty = page; +void *alloccache(unsigned int size) { + //get order + int order; + for (int i = 0; i <= MAXCACHEORDER; i++) { + if (size <= (32 << i)) { + order = i; + break; } } - if(hasNoFreePageAtOrder(order)) { - // uart_puts("Assign as first free page at order: "); uart_num(order); uart_newline(); - pagesAtOrder[order].firstFree = page; - } - - if(page->buddyPage->state == FREE) { - // uart_puts("Buddy is free too, merge pages from order: "); uart_num(order); uart_puts(" to order: "); uart_num(order + 1); uart_newline(); - mergePagesToHigherOrder(page); + if (list_empty(&cachelist[order])) { + page2caches(order); } -} - -bool isNotPageHead(page_t* page) { - return page->prevPage != NULL; -} - -bool isNotPageTail(page_t* page) { - return page->nextPage != NULL; -} - -bool isFirstFree(page_t* page) { - return page == pagesAtOrder[page->order].firstFree; -} - -bool isFirstEmpty(page_t* page) { - return page == pagesAtOrder[page->order].firstEmpty; -} -void mergePagesToHigherOrder(page_t* page) { - moveToTail(page); - moveToTail(page->buddyPage); - freePage(page->parentPage); + list_head_t *r = cachelist[order].next; + list_del_entry(r); + return r; } -void moveToTail(page_t* page) { - uint32 order = page->order; - page->state = EMPTY; - - if(!isFirstEmpty(page)) { - if(isFirstFree(page)) { - pagesAtOrder[order].firstFree = page->nextPage; - } - - if(isNotPageHead(page)) { - page->prevPage->nextPage = page->nextPage; - } +void page2caches(int order) { + //make caches of the order from a page + char *page = allocpage(0x1000); + frame_t *pageframe_ptr = &framearray[((unsigned long long)page - BUDDYSYSTEM_START) >> 12]; + pageframe_ptr->cacheorder = order; - page->nextPage->prevPage = page->prevPage; - page->prevPage = pagesAtOrder[order].firstEmpty; - page->nextPage = pagesAtOrder[order].firstEmpty->nextPage; - pagesAtOrder[order].firstEmpty->nextPage->prevPage = page; - pagesAtOrder[order].firstEmpty->nextPage = page; + // split page into a lot of caches and push them into cachelist + int cachesize = (32 << order); + for (int i = 0; i < 0x1000; i += cachesize) { + list_head_t *c = (list_head_t *)(page + i); + list_add(c, &cachelist[order]); } } -void loggingAllPageState() { - for(int order = 0; order < MAX_ORDER; order++) { - page_t* page = pagesAtOrder[order].firstFree; - while(isNotPageHead(page)) { - page = page->prevPage; - } - - while(page != NULL) { - switch(page->state) { - case FREE: - uart_putc('F'); - break; - case BUSY: - uart_putc('B'); - break; - case EMPTY: - uart_putc('X'); - break; - default: - uart_putc('?'); - break; - } - - uart_putc(' '); - page = page->nextPage; - } - - uart_newline(); - } +void freecache(void *ptr) { + list_head_t *c = (list_head_t *)ptr; + frame_t *pageframe_ptr = &framearray[((unsigned long long)ptr - BUDDYSYSTEM_START) >> 12]; + list_add(c, &cachelist[pageframe_ptr->cacheorder]); } -void free(uint64 address) { +void *malloc(unsigned int size) { lock_interrupt(); - page_t* page = usedAddress[addressToBlockIdx(address)]; - if(page == NULL) { - uart_puts("Not free-able address (page)\n"); - return; + //For page + if (size > (32 << MAXCACHEORDER)) { + void *r = allocpage(size); + unlock_interrupt(); + return r; } - memoryPool_t* pool = page->pool; - - // uart_puts("Original state = "); - // uart_hex(pool->stateBitMap >> 32); uart_hex(pool->stateBitMap); - // uart_newline(); - - uint32 shift = (address - pool->address) / pool->size; - pool->stateBitMap |= 1ULL << shift; - - // uart_puts("Mark as free memory, state = "); - // uart_hex(pool->stateBitMap >> 32); uart_hex(pool->stateBitMap); - // uart_newline(); - - page_t* page_pointer = usedPage; - if(pool->stateBitMap == ~(0ULL)) { - // uart_puts("All pools are free, free page: "); - // uart_hex(page); - // uart_newline(); - if(page == usedPage) { - usedPage = usedPage->appendPage; - } - else { - while(page_pointer->appendPage != page && page_pointer) { - // uart_puts("page: "); uart_hex(page_pointer); uart_newline(); - page_pointer = page_pointer->appendPage; - } - - if(page_pointer == NULL) { - raiseError("Cant relink usedPage\n"); - } - - page_pointer->appendPage = page->appendPage; - } - - // uart_puts("Remove page: "); - // uart_hex(page); - // uart_newline(); - - removeUsedAddress(page); - freePage(page); - } + void *r = alloccache(size); + //For cache unlock_interrupt(); + return r; } -void removeUsedAddress(page_t* page) { - uint32 idx = addressToBlockIdx(page->address); - uint32 numCoverdPage = exp2(page->order); - - for(int i = 0; i < numCoverdPage; i++) { - usedAddress[i + idx] = NULL; +void free(void *ptr) +{ + lock_interrupt(); + //For page + if ((unsigned long long)ptr % 0x1000 == 0 && framearray[((unsigned long long)ptr - BUDDYSYSTEM_START) >> 12].cacheorder == -1) { + freepage(ptr); + unlock_interrupt(); + return; } -} -void init_reserve() { - uart_puts("Reserve memory\n"); - reserveMemory(0x0000, 0x1000); // spin tables for multicore boot - reserveMemory(LOAD_ADDR - _stack_size, heap_end); // kernel and heap/stack space - reserveMemory(INITRAMFS_ADDR, INITRAMFS_ADDR + MAX_INITRAMFS_SIZE); // initramfs -} - -void reserveMemory(uint64 start, uint64 end) { - uint32 order = 0; - uart_puts("Address: "); uart_hex(start); uart_puts(" to "); uart_hex(end); uart_newline(); - for(uint64 address = start; address <= end; address += MINI_PAGE_SIZE * KB) { - // uart_puts("Reserve address: "); uart_hex(address); uart_newline(); - if(inRange(pagesAtOrder[MAX_ORDER - 1].firstFree, address)) { - reservePage(order, address); - } - else { - // uart_puts("Address: "); uart_hex(address); uart_puts(" is not covered by buddy system\n"); - break; - } - } + //For cache + freecache(ptr); + unlock_interrupt(); } -void reservePage(uint32 order, uint64 address) { - page_t* waitFreePage = NULL; - page_t* page_pointer; - page_t* page; - - page = pagesAtOrder[order].firstFree; - while(isNotPageHead(page)) { - page = page->prevPage; - } +void memory_reserve(unsigned long long start, unsigned long long end) { + uart_printf("reserve 0x%x to 0x%x\n", start, end); + start -= start % 0x1000; // floor (align 0x1000) + end = end % 0x1000 ? end + 0x1000 - (end % 0x1000) : end; // ceiling (align 0x1000) - while(page != NULL) { - if(page->state == BUSY && inRange(page, address)) { - // uart_puts("Already reserved, page: "); uart_hex(page); uart_newline(); - return; - } - page = page->nextPage; - } + //delete page from freelist + for (int order = MAXORDER; order >= 0; order--) { + list_head_t *pos; + list_for_each(pos, &freelist[order]) { + unsigned long long pagestart = ((frame_t *)pos)->idx * 0x1000L + BUDDYSYSTEM_START; + unsigned long long pageend = pagestart + (0x1000L << order); - do { - page = getFreePageAtOrder(order); - if(waitFreePage == NULL) { - waitFreePage = page; - page_pointer = page; - } - else { - page_pointer->appendPage = page; - page_pointer = page; - } - } while(!inRange(page, address)); - - // uart_puts("Reserve page: "); uart_hex(page); uart_newline(); - if(waitFreePage != page) { - page_pointer->appendPage = NULL; - while(waitFreePage != NULL) { - if(waitFreePage != page) - freePage(waitFreePage); - waitFreePage = waitFreePage->appendPage; + if (start <= pagestart && end >= pageend) { // if page all in reserved memory -> delete it from freelist + ((frame_t *)pos)->isused = 1; + list_del_entry(pos); + } + else if (start >= pageend || end <= pagestart) { // no intersection + continue; + } + else { // partial intersection (or reversed memory all in the page) + list_del_entry(pos); + list_head_t *temppos = pos -> prev; + list_add(&release_redundant((frame_t *)pos)->listhead, &freelist[order - 1]); + pos = temppos; + } } } -} - -bool inRange(page_t* page, uint64 address) { - return page->address <= address && address < (page->address + getPageSizeAtOrder(page->order)); -} - -bool inPool(memoryPool_t* pool, uint64 address) { - return pool->address <= address && address < (pool->address + pool->size * BASE_NUM); } \ No newline at end of file diff --git a/lib/mmu.c b/lib/mmu.c new file mode 100644 index 000000000..bf23c280a --- /dev/null +++ b/lib/mmu.c @@ -0,0 +1,231 @@ +#include "mmu.h" +#include "memory.h" + +extern uint64 *get_pgd(); + +void set_PGD() { + uint64 *pgd_table = (uint64 *)PGD_BASE; + + pgd_table[0] = PUD_BASE | BOOT_PGD_ATTR; +} + +// two-level translation (1G) +void set_PUD() { + uint64 *pud_table = (uint64 *)PUD_BASE; + + pud_table[0] = PMD_BASE | BOOT_PUD_ATTR; + pud_table[1] = (PMD_BASE + 0x1000L) | BOOT_PUD_ATTR; +} + +// three-level translation (2MB) - only first one +void set_PMD() { + uint64 *pmd_table = (uint64 *)PMD_BASE; + + for (int i = 0; i < 512 * 2; i++) { // 1G = 512 * 2M + pmd_table[i] = (PTE_BASE + 0x1000L * i) | BOOT_PMD_ATTR; + } +} + +// four-level translation (4KB) +void set_PTE() { + uint64 *pte_table = (uint64 *)PTE_BASE; + + for (int i = 0; i < 512 * 512 * 2; i++) { // 1G = 512 * 2M, 2M = 512 * 4K + uint64 addr = 0x1000L * i; + if(addr < PERIPHERAL_BASE) { + pte_table[i] = addr | BOOT_PTE_NORMAL_NOCACHE_ATTR; + } + else { + pte_table[i] = addr | BOOT_PTE_DEVICE_nGnRnE_ATTR; + } + } +} + +void init_page_table(uint64 **table, int level) { + lock_interrupt(); + *table = (uint64*)malloc(0x1000); + memset(*table, 0, 0x1000); + // convert to physical address for mmu + *table = (uint64*)(VIR_TO_PHY((uint64)*table)); + unlock_interrupt(); +} + +// static uint64 ttcou = 0; +void map_page_table(thread_t *thread, uint64 *pgd, uint64 vir_addr, uint64 phy_addr, bool readOnly) { + int page_idx[] = { + (vir_addr >> 39) & 0x1ff, (vir_addr >> 30) & 0x1ff, + (vir_addr >> 21) & 0x1ff, (vir_addr >> 12) & 0x1ff + }; + + // if(phy_addr >= 0x3D1FF000 && phy_addr < 0x3D203000) { + // uart_printf("PGD: 0x%x, Virtual Address: 0x%x, Physical Address: 0x%x\n", pgd, vir_addr, phy_addr); + // for(int i = 0; i < 4; i++) { + // uart_printf("Index-%d: %x\n", i, page_idx[i]); + // } + // } + + uint64 *table = (uint64*)PHY_TO_VIR((uint64)pgd); + for(int level = 0; level < 3; level++) { + if(table[page_idx[level]] == 0L) { + init_page_table((uint64**)&table[page_idx[level]], level + 1); + table[page_idx[level]] |= PD_TABLE; + // uart_printf("Create Table(0x%x, %d, 0x%x) at level %d: 0x%x\n", table, page_idx[level], phy_addr, level, table[page_idx[level]]); + // ttcou++; + } + + table = (uint64*)PHY_TO_VIR((table[page_idx[level]] & ~0xfffL)); + // if(phy_addr >= 0x3D1FF000 && phy_addr < 0x3D203000) { + // uart_printf("Next Table(0x%x, %d, 0x%x) at level %d: 0x%x\n", table, page_idx[level], phy_addr, level, table[page_idx[level]]); + // } + } + + if(readOnly) { + table[page_idx[3]] = PD_NE_EL1 | phy_addr | BOOT_PTE_NORMAL_NOCACHE_ATTR | PD_RDONLY | PD_UK_ACCESS; + } + else { + table[page_idx[3]] = phy_addr | BOOT_PTE_NORMAL_NOCACHE_ATTR | PD_UK_ACCESS; + } + // uart_printf("Entry: 0x%x\n", table[page_idx[3]]); +} + +void set_page_tables_for_thread(thread_t *thread) { + // map program + lock_interrupt(); + // ttcou = 0; + // uart_printf("PGD at 0x%x\n", thread->context.pgd); + // uart_printf("DATA MAP\n"); + for (uint64 size = 0; size < thread->datasize; size += 0x1000L) { + uint64 vir_addr = USER_KERNEL_BASE + size; + uint64 phy_addr = VIR_TO_PHY((uint64)thread->data + size); + // uart_printf("0x%x to 0x%x\n", vir_addr, phy_addr); + map_page_table(thread, thread->context.pgd, vir_addr , phy_addr, false); + } + // map stack + // uart_printf("STACK MAP\n"); + for (uint64 size = 0; size < THREAD_STACK_SIZE; size += 0x1000L) { + uint64 vir_addr = USER_STACK_BASE + size; + uint64 phy_addr = VIR_TO_PHY((uint64)thread->stackPtr + size); + // uart_printf("0x%x to 0x%x\n", vir_addr, phy_addr); + map_page_table(thread, thread->context.pgd, vir_addr , phy_addr, false); + } + // map peripheral + // uart_printf("PERIPHERAL MAP\n"); + for (uint64 addr = PERIPHERAL_START; addr < PERIPHERAL_END; addr += 0x1000L) { + // uart_printf("0x%x to 0x%x\n", addr, addr); + map_page_table(thread, thread->context.pgd, addr , addr, false); + } + + // uart_printf("Num of pages: %d\n", ttcou); + unlock_interrupt(); +} + +void free_page_table(uint64 vir_addr) { + void *temp = (void*)(PHY_TO_VIR(vir_addr) & ~0xfff); + memset(temp, 0, 0x1000); + free(temp); +} + +void free_page_tables(uint64 *pgd, int level) { + uint64 *table = (uint64*)(PHY_TO_VIR((uint64)pgd) & ~0xfff); + + for(int idx = 0; idx <= 0x1ff; idx++) { + uint64 entry = table[idx]; + if(entry & PD_TABLE) { + if(level < 2) { + free_page_tables((uint64*)(entry & ~0xfff), level + 1); + } + free_page_table(entry); + // uart_printf("Free Table at level %d: 0x%x\n", level, entry & ~0xfff); + } + } +} + +void free_page_tables_for_thread(thread_t *thread) { + lock_interrupt(); + free_page_tables(thread->context.pgd, 0); + free_page_table((uint64)thread->context.pgd); + unlock_interrupt(); +} + +void parser_table(uint64 vir_addr) { + uint64 *pgd = get_pgd(); + uint64 *table = (uint64*)PHY_TO_VIR((uint64)pgd); + int page_idx[] = { + (vir_addr >> 39) & 0x1ff, (vir_addr >> 30) & 0x1ff, + (vir_addr >> 21) & 0x1ff, (vir_addr >> 12) & 0x1ff + }; + + for(int level = 0; level < 4; level++) { + uart_printf("Table entry(%d) at level %d: 0x%x\n", page_idx[level], level, table[page_idx[level]]); + table = (uint64*)PHY_TO_VIR((table[page_idx[level]] & ~0xfff)); + } +} + +void set_vm_list(list_head_t *list, uint64 vir_addr, uint64 phy_addr, uint64 size) { + vm_cell_t *program_vm_cell = (vm_cell_t *)malloc(sizeof(vm_cell_t)); + program_vm_cell->vir_addr = vir_addr; + program_vm_cell->phy_addr = phy_addr; + program_vm_cell->size = (size % 0x1000) == 0 ? size : size + 0x1000 - (size % 0x1000); + // uart_printf("add vm(0x%x): 0x%x => 0x%x, size = %d\n", program_vm_cell, vir_addr, phy_addr, program_vm_cell->size); + list_add((list_head_t*)program_vm_cell, list); +} + +void set_vm_list_for_thread(thread_t *thread) { + lock_interrupt(); + + set_vm_list(&thread->used_vm, USER_KERNEL_BASE, VIR_TO_PHY((uint64)thread->data), thread->datasize); // set program + set_vm_list(&thread->used_vm, USER_STACK_BASE, VIR_TO_PHY((uint64)thread->stackPtr), THREAD_STACK_SIZE); // set stack + set_vm_list(&thread->used_vm, PERIPHERAL_START, PERIPHERAL_START, PERIPHERAL_END - PERIPHERAL_START); // set peripheral + + unlock_interrupt(); +} + +void free_vm_list_for_thread(thread_t *thread) { + list_head_t *ptr = thread->used_vm.next; + while (ptr != &thread->used_vm) { + list_head_t *next_ptr = ptr->next; + // uart_printf("free vm(0x%x)\n", ptr); + free(ptr); + ptr = next_ptr; + } +} + +void handle_abort(esr_el1_t *esr_el1) { + uint64 fail_addr; + asm("mrs %0, FAR_EL1\n\t": "=r"(fail_addr)); + + list_head_t *ptr; + vm_cell_t *matched_ptr = NULL; + list_for_each(ptr, &currThread->used_vm) { + vm_cell_t *used_vm_cell = (vm_cell_t *)ptr; + if (used_vm_cell->vir_addr <= fail_addr && (used_vm_cell->vir_addr + used_vm_cell->size) >= fail_addr) { + matched_ptr = used_vm_cell; + break; + } + } + + // not covered by this thread + if (!matched_ptr) { + seg_fault(); + } + else { + // Translation fault + uint64 fail_level = esr_el1->iss & 0x3f; + if (fail_level == TF_LEVEL0 || fail_level == TF_LEVEL1 || fail_level == TF_LEVEL2 || fail_level == TF_LEVEL3) { + uart_printf("[Translation fault]: 0x%x\r\n", fail_addr); + + uint64 offset = (fail_addr - matched_ptr->vir_addr); + uint64 aligned_offset = offset - (offset % 0x1000); + map_page_table(currThread, currThread->context.pgd, matched_ptr->vir_addr + aligned_offset, matched_ptr->phy_addr + aligned_offset, false); + } + // Other Faults we don't handle + else { + seg_fault(); + } + } +} + +void seg_fault() { + uart_printf("[Segmentation fault]: Kill Process\r\n"); + thread_exit(); +} diff --git a/lib/signal.c b/lib/signal.c index e1d0c9df0..c704db23d 100644 --- a/lib/signal.c +++ b/lib/signal.c @@ -3,7 +3,9 @@ #include "interrupt.h" #include "exception.h" #include "thread.h" +#include "memory.h" #include "uart.h" +#include "syscall.h" void signal_default_handlder() { kill(currThread->signal_pair.pid); @@ -42,7 +44,7 @@ void signal_execute() { lock_interrupt(); char *signal_user_stack = malloc(THREAD_STACK_SIZE); int i = 0; - read_context(&currThread->signal_context); + store_context(&currThread->signal_context); unlock_interrupt(); if(i == 0) { @@ -66,6 +68,6 @@ void signal_user_mode() { void signal_return(trapFrame_t *frame) { uint64 signal_ustack = frame->sp_el0 - THREAD_STACK_SIZE; - free(signal_ustack); - write_context(&currThread->signal_context); + free((void*)signal_ustack); + load_context(&currThread->signal_context); } diff --git a/lib/sprintf.c b/lib/sprintf.c new file mode 100644 index 000000000..2d501d58f --- /dev/null +++ b/lib/sprintf.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/** + * minimal sprintf implementation + */ +unsigned int vsprintf(char *dst, char* fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + // failsafes + if(dst==(void*)0 || fmt==(void*)0) { + return 0; + } + + // main loop + arg = 0; + while(*fmt) { + // argument access + if(*fmt=='%') { + fmt++; + // literal % + if(*fmt=='%') { + goto put; + } + len=0; + // size modifier + while(*fmt>='0' && *fmt<='9') { + len *= 10; + len += *fmt-'0'; + fmt++; + } + // skip long modifier + if(*fmt=='l') { + fmt++; + } + // character + if(*fmt=='c') { + arg = __builtin_va_arg(args, int); + *dst++ = (char)arg; + fmt++; + continue; + } else + // decimal number + if(*fmt=='d') { + arg = __builtin_va_arg(args, int); + // check input + sign=0; + if((int)arg<0) { + arg*=-1; + sign++; + } + if(arg>99999999999999999L) { + arg=99999999999999999L; + } + // convert to string + i=18; + tmpstr[i]=0; + do { + tmpstr[--i]='0'+(arg%10); + arg/=10; + } while(arg!=0 && i>0); + if(sign) { + tmpstr[--i]='-'; + } + // padding, only space + if(len>0 && len<18) { + while(i>18-len) { + tmpstr[--i]=' '; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // hex number + if(*fmt=='x') { + arg = __builtin_va_arg(args, long int); + // convert to string + i=16; + tmpstr[i]=0; + do { + char n=arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i]=n+(n>9?0x37:0x30); + arg>>=4; + } while(arg!=0 && i>0); + // padding, only leading zeros + if(len>0 && len<=16) { + while(i>16-len) { + tmpstr[--i]='0'; + } + } + p=&tmpstr[i]; + goto copystring; + } else + // string + if(*fmt=='s') { + p = __builtin_va_arg(args, char*); +copystring: if(p==(void*)0) { + p="(null)"; + } + while(*p) { + *dst++ = *p++; + } + } + } else { +put: *dst++ = *fmt; + } + fmt++; + } + *dst=0; + // number of bytes written + return dst-orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, char* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/lib/string.c b/lib/string.c index 624683b18..f04021f4c 100644 --- a/lib/string.c +++ b/lib/string.c @@ -1,3 +1,6 @@ +#include "string.h" +#include "type.h" + int strcmp (const char* str1, const char* str2) { for(int i = 0; ; i++) { if(str1[i] != str2[i]) { @@ -57,4 +60,88 @@ char* find_token(const char* str, char sep) { while(*(str++) != sep); return (char*)str; +} + +void strcat(char* dst, const char* src) { + strcpy(dst + strlen(dst), src); +} + +char *get_dirname(char* dst, const char* src) +{ + int last_slash_idx = -1; + int i = 0; + for(; src[i] != '\0'; i++) { + if(src[i] == '/') { + last_slash_idx = i; + } + dst[i] = src[i]; + } + + if(last_slash_idx >= 0) { + dst[last_slash_idx] = '\0'; + return (char*)src + last_slash_idx + 1; + } + else { + dst[i] = '\0'; + return 0x0000; + } +} + +char *get_rootname(char* dst, const char* src) +{ + if(*src == '/') src++; + while(*src != '/' && *src != '\0') *(dst++) = *(src++); + + *dst = '\0'; + if(*src == '/') return (char*)src + 1; + else return NULL; +} + +void get_abspath(char *abs_path, char *path, const char *curr_path) { + char tmp_path[MAX_LEN]; + if(path[0] != '/') { // use relative address + strcpy(tmp_path, curr_path); + if(!strcmp(curr_path, "/")) { + strcat(tmp_path, "/"); + } + strcat(tmp_path, path); + } + else { + strcpy(tmp_path, path); + } + + abs_path[0] = '/'; + abs_path[1] = '\0'; + int idx = 1; + int prev_len = 1; + char root_path[MAX_LEN]; + char *leaftname = tmp_path; + while(1) { + leaftname = get_rootname(root_path, leaftname); + + if(strcmp(root_path, "..")) { + idx -= (prev_len + 1); + if(idx < 1) { + idx = 1; + abs_path[0] = '/'; + } + abs_path[idx] = '\0'; + } + else if(strcmp(root_path, ".")) { + // pass + } + else { + strcat(abs_path + idx, root_path); + prev_len = strlen(root_path); + idx += prev_len; + abs_path[idx++] = '/'; + abs_path[idx] = '\0'; + } + + if(leaftname == NULL) { + if(abs_path[idx-1] == '/') abs_path[idx-1] = '\0'; + else abs_path[idx] = '\0'; + break; + } + } } \ No newline at end of file diff --git a/lib/syscall.c b/lib/syscall.c index 4fdd8d5f6..663177597 100644 --- a/lib/syscall.c +++ b/lib/syscall.c @@ -1,12 +1,15 @@ #include "syscall.h" #include "mbox.h" #include "uart.h" -#include "exception.h" #include "interrupt.h" #include "address.h" -#include "utils.h" +#include "memory.h" #include "cpio.h" #include "signal.h" +#include "mmu.h" +#include "vfs.h" +#include "string.h" +#include "dev_framebuffer.h" int getpid() { return currThread->pid; @@ -25,26 +28,50 @@ size_t uart_write(const char buf[], size_t size) { for(int i = 0; i < size; i++) { uart_putc(buf[i]); } + return size; } -int exec(trapFrame_t *frame, const char* name, char *const argv[]) { - char* program_address = load_user_program(INITRAMFS_ADDR, NULL, name); - uint64 program_size = get_program_size(INITRAMFS_ADDR, name); - // uart_puts("user exec program at "); uart_hex(program_address); uart_newline(); +int exec(trapFrame_t *frame, char* name, char *const argv[]) { + lock_interrupt(); + char abspath[MAX_PATHNAME]; + get_abspath(abspath, name, currThread->pwd); + + vnode_t *searchNode; + if(vfs_lookup(abspath, &searchNode) == -1) return -1; + uint64 program_size = searchNode->f_ops->getsize(searchNode); + free(currThread->data); currThread->datasize = program_size; - for (int i = 0; i < program_size; i++) { - currThread->data[i] = program_address[i]; - } + currThread->data = (char*)malloc(program_size); + + free_page_tables_for_thread(currThread); // free PGD + init_page_table(&currThread->context.pgd, 0); + set_page_tables_for_thread(currThread); + switch_pgd((uint64)currThread->context.pgd); + + free_file_descriptor_table_for_thread(currThread); + file_t *tmp_f; + if(vfs_open(abspath, 0, &tmp_f) == -1) return -1; + if(vfs_read(tmp_f, currThread->data, program_size) == -1) return -1; + if(vfs_close(tmp_f) == -1) return -1; + + vfs_open("/dev/uart", 0, &currThread->file_descriptor_table[0]); + vfs_open("/dev/uart", 0, &currThread->file_descriptor_table[1]); + vfs_open("/dev/uart", 0, &currThread->file_descriptor_table[2]); currThread->has_signal = 0; for(int i = 0; i <= SIGMAX; i++) { currThread->signal_handlers[i] = signal_default_handlder; } - frame->elr_el1 = (uint64)currThread->data; - frame->sp_el0 = (uint64)currThread->stackPtr + THREAD_STACK_SIZE; + // INIT_LIST_HEAD(&currThread->used_vm); + // set_vm_list_for_thread(currThread); + + frame->elr_el1 = USER_KERNEL_BASE; + frame->sp_el0 = USER_STACK_BASE + THREAD_STACK_SIZE; + + unlock_interrupt(); return 0; } @@ -52,35 +79,51 @@ int fork(trapFrame_t *frame) { lock_interrupt(); int pid = currThread->pid; thread_t *parentThread = currThread; - thread_t *childThread = createThread(parentThread->data); - childThread->datasize = parentThread->datasize; + thread_t *childThread = createThread(parentThread->data, parentThread->datasize); + childThread->state = NEW_BORN; - for(int i = 0; i < THREAD_STACK_SIZE; i++) { - childThread->stackPtr[i] = parentThread->stackPtr[i]; - childThread->kernel_stackPtr[i] = parentThread->kernel_stackPtr[i]; - } + store_context(get_current()); - for(int i = 0; i <= SIGMAX; i++) { - childThread->signal_handlers[i] = parentThread->signal_handlers[i]; - } + if(currThread->pid == pid) { + for(int i = 0; i < parentThread->datasize; i++) { + childThread->data[i] = parentThread->data[i]; + } - read_context(get_current()); + for(int i = 0; i < THREAD_STACK_SIZE; i++) { + childThread->stackPtr[i] = parentThread->stackPtr[i]; + childThread->kernel_stackPtr[i] = parentThread->kernel_stackPtr[i]; + } + strcpy(childThread->pwd, parentThread->pwd); + for(int i = 0; i < MAX_FD; i++) { + if(parentThread->file_descriptor_table[i]) { + childThread->file_descriptor_table[i] = (file_t*)malloc(sizeof(file_t)); + *childThread->file_descriptor_table[i] = *parentThread->file_descriptor_table[i]; + } + } - if(currThread->pid == pid) { - // uart_puts("Parent thread: "); uart_num(parentThread->pid); - // uart_puts(", Current thread: "); uart_num(currThread->pid); uart_newline(); + for(int i = 0; i <= SIGMAX; i++) { + childThread->signal_handlers[i] = parentThread->signal_handlers[i]; + } + + init_page_table(&childThread->context.pgd, 0); + set_page_tables_for_thread(childThread); + // set_vm_list_for_thread(childThread); + + uint64 *temp_pgd = childThread->context.pgd; childThread->context = parentThread->context; + childThread->context.pgd = temp_pgd; + childThread->context.sp += childThread->kernel_stackPtr - parentThread->kernel_stackPtr; childThread->context.fp += childThread->kernel_stackPtr - parentThread->kernel_stackPtr; unlock_interrupt(); return childThread->pid; } else { - // uart_puts("Child thread: "); uart_num(childThread->pid); - // uart_puts(", Current thread: "); uart_num(currThread->pid); uart_newline(); - frame = (trapFrame_t*)((char *)frame + (uint64)childThread->kernel_stackPtr - (uint64)parentThread->kernel_stackPtr); - frame->sp_el0 += childThread->stackPtr - parentThread->stackPtr; + // lock_interrupt(); + // frame = (trapFrame_t*)((char *)frame + (uint64)childThread->kernel_stackPtr - (uint64)parentThread->kernel_stackPtr); + // frame->sp_el0 += childThread->kernel_stackPtr - parentThread->kernel_stackPtr; + // unlock_interrupt(); return 0; } } @@ -91,7 +134,12 @@ void exit(int status) { int mbox_call(unsigned char ch, unsigned int *mbox) { lock_interrupt(); - unsigned long r = (((unsigned long)((unsigned long)mbox) & ~0xF) | (ch & 0xF)); + uint64 size = mbox[0]; + unsigned int kernel_box[36]; + memcpy(kernel_box, mbox, size); + + unsigned long r = (((unsigned long)((unsigned long)kernel_box) & ~0xF) | (ch & 0xF)); + // uart_printf("Mbox: 0x%x, 0x%x\n", mbox, r); // wait for ready do { asm volatile("nop"); @@ -107,8 +155,9 @@ int mbox_call(unsigned char ch, unsigned int *mbox) { } while(*MBOX_STATUS & MBOX_EMPTY); // make sure it is a response to our message - if(r == *MBOX_READ) { + if(r == PHY_TO_VIR(*MBOX_READ)) { // is it a valid successful response + memcpy(mbox, kernel_box, size); unlock_interrupt(); return mbox[1] == MBOX_RESPONSE; } @@ -125,39 +174,102 @@ void kill(int pid) { unlock_interrupt(); } -void fork_test() { - lock_interrupt(); - uart_puts("\nFork Test, pid: "); uart_num(getpid()); uart_newline(); - int cnt = 1; - int ret = 0; - - if ((ret = fork(NULL)) == 0) { // child - long long cur_sp; - asm volatile("mov %0, sp" : "=r"(cur_sp)); - uart_puts("first child pid: "); uart_num(getpid()); uart_puts(", cnt: "); uart_num(cnt); - uart_puts(", ptr: "); uart_hex(&cnt); uart_puts(", sp : "); uart_hex(cur_sp); uart_newline(); - ++cnt; - - if ((ret = fork(NULL)) != 0){ - asm volatile("mov %0, sp" : "=r"(cur_sp)); - uart_puts("first child pid: "); uart_num(getpid()); uart_puts(", cnt: "); uart_num(cnt); - uart_puts(", ptr: "); uart_hex(&cnt); uart_puts(", sp : "); uart_hex(cur_sp); uart_newline(); - } - else{ - while (cnt < 5) { - asm volatile("mov %0, sp" : "=r"(cur_sp)); - uart_puts("second child pid: "); uart_num(getpid()); uart_puts(", cnt: "); uart_num(cnt); - uart_puts(", ptr: "); uart_hex(&cnt); uart_puts(", sp : "); uart_hex(cur_sp); uart_newline(); - delay_ms(1000); - ++cnt; + + +// syscall number : 11 +int call_vfs_open(const char *pathname, int flags) { + char abspath[MAX_PATHNAME]; + get_abspath(abspath, (char*)pathname, currThread->pwd); + + for(int i = 0; i < MAX_FD; i++) { + if(!currThread->file_descriptor_table[i]) { + if(vfs_open(abspath, flags, &currThread->file_descriptor_table[i]) == -1) { + return -1; } + + return i; } } - else { - uart_puts("parent here, pid: "); uart_num(getpid()); uart_puts(", child: "); uart_num(ret); uart_newline(); + + return -1; +} + +// syscall number : 12 +int call_vfs_close(int fd) { + if(currThread->file_descriptor_table[fd]) { + if(vfs_close(currThread->file_descriptor_table[fd]) == -1) { + return -1; + } + currThread->file_descriptor_table[fd] = NULL; + return 0; } - exit(NULL); - unlock_interrupt(); + return -1; +} + +// syscall number : 13 +// remember to return read size or error code +long call_vfs_write(int fd, const char *buf, unsigned long count) { + if(currThread->file_descriptor_table[fd]) { + return vfs_write(currThread->file_descriptor_table[fd], buf, count); + } + + return -1; +} + +// syscall number : 14 +// remember to return read size or error code +long call_vfs_read(int fd, char *buf, unsigned long count) { + if(currThread->file_descriptor_table[fd]) { + return vfs_read(currThread->file_descriptor_table[fd], buf, count); + } + + return -1; +} + +// syscall number : 15 +// you can ignore mode, since there is no access control +int call_vfs_mkdir(const char *pathname, unsigned mode) { + char abspath[MAX_PATHNAME]; + get_abspath(abspath, (char*)pathname, currThread->pwd); + + return vfs_mkdir(abspath); +} + +// syscall number : 16 +// you can ignore arguments other than target (where to mount) and filesystem (fs name) +int call_vfs_mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data) { + char abspath[MAX_PATHNAME]; + get_abspath(abspath, (char*)target, currThread->pwd); + + return vfs_mount(abspath, filesystem); +} + +// syscall number : 17 +int call_vfs_chdir(const char *path) { + get_abspath(currThread->pwd, (char*)path, currThread->pwd); + + return 0; } +// syscall number : 18 +// you only need to implement seek set +long call_vfs_lseek64(int fd, long offset, int whence) { + if(currThread->file_descriptor_table[fd]) { + return vfs_lseek64(currThread->file_descriptor_table[fd], offset, whence); + } + + return -1; +} + +// syscall number : 19 +int call_vfs_ioctl(int fd, unsigned long request, framebuffer_info_t *fb_info) { + if(request == 0) { + fb_info->width = width; + fb_info->height = height; + fb_info->pitch = pitch; + fb_info->isrgb = isrgb; + } + + return 0; +} \ No newline at end of file diff --git a/lib/thread.c b/lib/thread.c index bb87f59ff..b3a0f04d5 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -1,9 +1,9 @@ #include "thread.h" #include "interrupt.h" +#include "exception.h" #include "memory.h" -#include "list.h" -#include "utils.h" -#include "signal.h" +#include "timer.h" +#include "vfs.h" thread_t threads[PIDMAX + 1]; thread_t *currThread, *idleThread; @@ -22,12 +22,14 @@ void initThreads() { threads[i].has_signal = 0; } - currThread = idleThread = createThread(idle); - asm volatile("msr tpidr_el1, %0" ::"r" (&currThread->context)); + currThread = idleThread = createThread(idle, 0x1000); + asm volatile("mrs %0, ttbr1_el1" : "=r"(idleThread->context.pgd)); + // uart_printf("IDLE PGD: 0x%x\n", idleThread->context.pgd); + asm volatile("msr tpidr_el1, %0" ::"r" (&idleThread->context)); unlock_interrupt(); } -thread_t *createThread(void *program) { +thread_t *createThread(void *program, uint64 datasize) { lock_interrupt(); thread_t *thread; for(int i = 0; i <= PIDMAX; i++) { @@ -37,15 +39,23 @@ thread_t *createThread(void *program) { } } + // INIT_LIST_HEAD(&thread->used_vm); thread->state = USED; thread->context.lr = (uint64)program; thread->stackPtr = (char*)malloc(THREAD_STACK_SIZE); thread->kernel_stackPtr = (char*)malloc(THREAD_STACK_SIZE); + thread->data = (char*)malloc(datasize); + thread->datasize = datasize; thread->context.sp = (uint64)thread->stackPtr + THREAD_STACK_SIZE; thread->context.fp = thread->context.sp; + thread->has_signal = 0; + for(int i = 0; i <= SIGMAX; i++) { + thread->signal_handlers[i] = signal_default_handlder; + } + asm volatile("mrs %0, ttbr0_el1" : "=r"(thread->context.pgd)); list_add(&thread->listHead, run_queue); unlock_interrupt(); return thread; @@ -54,7 +64,6 @@ thread_t *createThread(void *program) { void idle() { while(1) { kill_zombies(); - // uart_puts("IDLE\n"); schedule(); } } @@ -65,70 +74,94 @@ void kill_zombies() { list_for_each(list, run_queue) { thread_t *thread = (thread_t*)list; if(thread->state == DEAD) { - // uart_puts("Kill thread "); uart_num(thread->pid); uart_newline(); list_del_entry(list); + free(thread->data); free(thread->stackPtr); free(thread->kernel_stackPtr); + // free_vm_list_for_thread(thread); + free_page_tables_for_thread(thread); // free PGD + free_file_descriptor_table_for_thread(thread); thread->state = IDLE; } } unlock_interrupt(); } +void free_file_descriptor_table_for_thread(thread_t *thread) { + for(int i = 0; i < MAX_FD; i++) { + if(thread->file_descriptor_table[i]) { + vfs_close(thread->file_descriptor_table[i]); + } + } +} + void schedule() { lock_interrupt(); - + // uart_printf("Start Schedule\n"); do { + if(currThread->state == NEW_BORN) currThread->state = USED; currThread = (thread_t*)currThread->listHead.next; - } while(list_is_head(currThread, run_queue) || currThread->state == DEAD); - - // uart_puts("Select currThread "); uart_num(currThread->pid); uart_newline(); + // uart_printf("D"); + } while(list_is_head(&currThread->listHead, run_queue) || currThread->state == DEAD || currThread->state == NEW_BORN); + // uart_printf("Select thread: %d\n", currThread->pid); switch_to(get_current(), &currThread->context); + // uart_printf("Switch Back thread: %d\n", currThread->pid); unlock_interrupt(); + // uart_printf("Schedule Done\n"); // return to context.lr } -void execThread(char *program, uint64 program_size) { +void execThread(char *pathname) { lock_interrupt(); - thread_t *thread = createThread(program); - - thread->data = malloc(program_size); - thread->datasize = program_size; - thread->context.lr = (uint64)thread->data; - - for(int i = 0; i < program_size; i++) { - thread->data[i] = program[i]; + + char abspath[MAX_PATHNAME]; + get_abspath(abspath, pathname, currThread->pwd); + vnode_t *searchNode; + if(vfs_lookup(abspath, &searchNode) == -1) { + uart_printf("(execThread) Can't find %s (%s)\n", abspath, pathname); + raiseError("(execThread) Fail to exec\n"); } + uint64 program_size = searchNode->f_ops->getsize(searchNode); + uart_printf("(execThread) get %s with size (%d)\n", abspath, program_size); + thread_t *thread = createThread(USER_KERNEL_BASE, program_size); + init_page_table(&thread->context.pgd, 0); + + file_t *tmp_f; + if(vfs_open(abspath, 0, &tmp_f) == -1) { raiseError("(execThread) Fail to open\n"); }; + if(vfs_read(tmp_f, thread->data, program_size) == -1) { raiseError("(execThread) Fail to read\n"); }; + if(vfs_close(tmp_f) == -1) { raiseError("(execThread) Fail to close\n"); }; + + vfs_open("/dev/uart", 0, &thread->file_descriptor_table[0]); + vfs_open("/dev/uart", 0, &thread->file_descriptor_table[1]); + vfs_open("/dev/uart", 0, &thread->file_descriptor_table[2]); + + thread->context.sp = USER_STACK_BASE + THREAD_STACK_SIZE; + thread->context.fp = USER_STACK_BASE + THREAD_STACK_SIZE; + thread->context.lr = USER_KERNEL_BASE; + thread->has_signal = 0; for(int i = 0; i <= SIGMAX; i++) { thread->signal_handlers[i] = signal_default_handlder; } - // uart_puts("Start new thread\n"); currThread = thread; + set_page_tables_for_thread(thread); + // set_vm_list_for_thread(thread); + + schedule_callback("Schedule\n"); + uart_printf("Start exec\n"); + switch_pgd((uint64)thread->context.pgd); unlock_interrupt(); - set_schedule_timer(); - - // eret to exception level 0 + + // // eret to exception level 0 asm("msr tpidr_el1, %0\n\t" "msr elr_el1, %1\n\t" "msr spsr_el1, xzr\n\t" // enable interrupt in EL0. You can do it by setting spsr_el1 to 0 before returning to EL0. "msr sp_el0, %2\n\t" "mov sp, %3\n\t" - "eret\n\t" ::"r"(&thread->context),"r"(thread->context.lr), - "r"(thread->context.sp), "r"(thread->kernel_stackPtr + THREAD_STACK_SIZE)); -} - -void testThread() { - for(int i = 0; i < 3; ++i) { - uart_puts("Thread id: "); uart_num(currThread->pid); - uart_puts(" "); uart_num(i); uart_newline(); - delay_ms(1000); - schedule(); - } - - thread_exit(); + "eret\n\t" ::"r"(&thread->context), "r"(thread->context.lr), + "r"(thread->context.sp), "r"(thread->kernel_stackPtr + THREAD_STACK_SIZE)); } void thread_exit() { @@ -138,12 +171,10 @@ void thread_exit() { schedule(); } -void set_schedule_timer() { - uint64 freq = get_timer_frequency(); - add_timer(schedule_callback, freq >> 5, "Schedule\n"); -} - void schedule_callback(char *message) { // uart_puts(message); - set_schedule_timer(); + lock_interrupt(); + uint64 freq = get_timer_frequency(); + add_timer(schedule_callback, freq >> 5, message); + unlock_interrupt(); } \ No newline at end of file diff --git a/lib/timer.c b/lib/timer.c index 6025b70b4..5136709d6 100644 --- a/lib/timer.c +++ b/lib/timer.c @@ -1,38 +1,20 @@ #include "timer.h" -#include "type.h" -#include "uart.h" -#include "string.h" -#include "memory.h" -#include "interrupt.h" -volatile timer_event_t* timer_event_pointer = NULL; +timer_event_t* timer_event_pointer = NULL; -uint64 get_end_tick(timer_event_t* event_p) -{ +uint64 get_end_tick(timer_event_t* event_p) { return event_p->timeout_tick + event_p->begin_tick; } -uint64 get_current_tick() -{ - uint64 current_tick; - asm volatile( - "mrs %0, cntpct_el0\n\t" - : "=r"(current_tick) - ); - return current_tick; -} - -void set_first_timer() -{ +void set_first_timer() { uint64 tick = get_end_tick(timer_event_pointer) - get_current_tick(); if(get_end_tick(timer_event_pointer) < get_current_tick()) { - // int64 diff = get_end_tick(timer_event_pointer) - get_current_tick(); - // uart_puts("Timer is too slow, tick: "); uart_num(get_end_tick(timer_event_pointer)); uart_puts(" vs "); uart_num(get_current_tick()); uart_newline(); - // raiseError("NOOOOOO~~~\n"); - set_core_timer_by_tick(10000); + // uart_puts("Timer is too slow\n"); + set_core_timer_by_tick(6000); } else { + // uart_printf("Set tick: %d\n", tick); set_core_timer_by_tick(tick); } } @@ -42,16 +24,12 @@ int set_next_timer() { free(timer_event_pointer->message); free(timer_event_pointer); timer_event_pointer = next_event_p; - if(is_not_empty(timer_event_pointer)) - { - uint64 tick = get_end_tick(timer_event_pointer) - get_current_tick(); - set_core_timer_by_tick(tick); + if(is_not_empty(timer_event_pointer)) { + set_first_timer(); return 1; } - else - { - return 0; - } + + return 0; } void init_timer_event(timer_event_t* event_p, void (*callback)(char* message), uint64 timeout_tick, char *message) @@ -70,107 +48,98 @@ void init_timer_event(timer_event_t* event_p, void (*callback)(char* message), u event_p->next_event = NULL; } -void insert_after_it(timer_event_t* prev, timer_event_t* next) -{ +void insert_after_it(timer_event_t* prev, timer_event_t* next) { next->next_event = prev->next_event; prev->next_event = next; } -void stack_head(timer_event_t* event_p) -{ +void stack_head(timer_event_t* event_p) { event_p->next_event = timer_event_pointer; timer_event_pointer = event_p; set_first_timer(); } -void insert_timer_event(timer_event_t* event_p) -{ +void insert_timer_event(timer_event_t* event_p) { uint64 end_tick = get_end_tick(event_p); - if(end_tick < get_end_tick(timer_event_pointer)) // less than head - { + + // less than head + if(end_tick < get_end_tick(timer_event_pointer)) { stack_head(event_p); return; } + // middle timer_event_t* current_event_p = timer_event_pointer; - while(is_not_empty(current_event_p->next_event)) - { - if(end_tick < get_end_tick(current_event_p->next_event)) // insert here - { + while(is_not_empty(current_event_p->next_event)) { + // insert here + if(end_tick < get_end_tick(current_event_p->next_event)) { insert_after_it(current_event_p, event_p); return; } - + current_event_p = current_event_p->next_event; // check next } current_event_p->next_event = event_p; // greater than tail } -void add_timer(void (*callback)(char* message), uint64 timeout_tick, char *message) -{ +void add_timer(void (*callback)(char* message), uint64 timeout_tick, char *message) { lock_interrupt(); timer_event_t* new_timer_event = (timer_event_t*)malloc(sizeof(timer_event_t)); init_timer_event(new_timer_event, callback, timeout_tick, message); - if(is_empty(timer_event_pointer)) - { - // uart_puts("Add first events\n"); + if(is_empty(timer_event_pointer)) { timer_event_pointer = new_timer_event; } - else - { - // uart_puts("Insert events\n"); + else { insert_timer_event(new_timer_event); } unlock_interrupt(); } void exec_timer_callback(timer_event_t* event_p) { + // uart_printf("Exec Timer Callback at 0x%x\n", event_p->callback); ((void (*)(char *))event_p->callback)(event_p->message); } -void core_timer_handler() -{ - static int wait = 1; - +static int wait = 1; +void core_timer_handler() { + // uart_printf("Timer Handler\n"); lock_interrupt(); - if(is_not_empty(timer_event_pointer)) - { - if(wait == 0) - { + if(is_not_empty(timer_event_pointer)) { + // uart_printf("Start Handler\n"); + if(wait == 0) { + // uart_printf("Start Exec\n"); exec_timer_callback(timer_event_pointer); - // uart_puts("I am back\n"); int have_next = set_next_timer(); - - if(have_next == 0) - { + if(have_next == 0) { wait = 1; - // uart_puts("Empty events\n"); set_core_timer_by_second(1); // wait 1s for next interrupt } } - else - { - // uart_puts("Set first events\n"); + else { + // uart_printf("Start First\n"); wait = 0; set_first_timer(); } } - else // nothing to do - { - // uart_puts("Nothing to do\n"); + else { + // uart_printf("1s Done\n"); wait = 1; set_core_timer_by_second(1); // wait 1s for next interrupt } + unlock_interrupt(); - // uart_puts("Unlock, is disable? "); uart_num(is_disable_interrupt()); uart_newline(); enable_core_timer(); + // uart_printf("Timer Handler Done\n"); } -void enable_core_timer() -{ +bool hasTimerEvent() { + return is_not_empty(timer_event_pointer); +} + +void enable_core_timer() { asm volatile( "mov x1, 1\n\t" "msr cntp_ctl_el0, x1\n\t" // enable @@ -180,8 +149,7 @@ void enable_core_timer() ); } -void disable_core_timer() -{ +void disable_core_timer() { asm volatile( "mov x2, 0\n\t" "ldr x1, =" XSTR(CORE0_TIMER_IRQ_CTRL) "\n\t" @@ -189,16 +157,14 @@ void disable_core_timer() ); } -void set_core_timer_by_tick(uint64 tick) -{ +void set_core_timer_by_tick(uint64 tick) { asm volatile( "msr cntp_tval_el0, %0\n\t" ::"r" (tick) ); } -void set_core_timer_by_second(uint64 second) -{ +void set_core_timer_by_second(uint64 second) { asm volatile( "mrs x1, cntfrq_el0\n\t" "mul x1, x1, %0\n\t" @@ -207,8 +173,16 @@ void set_core_timer_by_second(uint64 second) ); } -uint64 get_timer_frequency() -{ +uint64 get_current_tick() { + uint64 current_tick; + asm volatile( + "mrs %0, cntpct_el0\n\t" + : "=r"(current_tick) + ); + return current_tick; +} + +uint64 get_timer_frequency() { uint64 freq; asm volatile( "mrs %0, cntfrq_el0\n\t" @@ -218,29 +192,25 @@ uint64 get_timer_frequency() return freq; } -uint64 tick2second(uint64 tick) -{ +uint64 tick2second(uint64 tick) { uint64 freq = get_timer_frequency(); uint64 second = tick / freq; return second; } -uint64 second2tick(uint64 second) -{ +uint64 second2tick(uint64 second) { uint64 freq = get_timer_frequency(); uint64 tick = second * freq; return tick; } -void show_message(char* message) -{ +void show_message(char* message) { uart_puts("MESSAGE: "); uart_puts(message); uart_newline(); } -void increment_timeout_2_seconds(char* message) -{ +void increment_timeout_2_seconds(char* message) { static unsigned long seconds = 0; static unsigned long next_val = 1; unsigned long tick; @@ -250,6 +220,5 @@ void increment_timeout_2_seconds(char* message) tick = second2tick(next_val); add_timer(increment_timeout_2_seconds, tick, NULL); - uart_puts("Pass seconds = "); uart_num(seconds); uart_newline(); } diff --git a/lib/tmpfs.c b/lib/tmpfs.c new file mode 100644 index 000000000..e11c88d98 --- /dev/null +++ b/lib/tmpfs.c @@ -0,0 +1,156 @@ +#include "tmpfs.h" +#include "string.h" +#include "memory.h" + +file_operations_t tmpfs_file_operations = {tmpfs_write, tmpfs_read, tmpfs_open, tmpfs_close, vfs_lseek64, tmpfs_getsize}; +vnode_operations_t tmpfs_vnode_operations = {tmpfs_lookup, tmpfs_create, tmpfs_mkdir}; + +filesystem_t *get_tmpfs() { + filesystem_t *tmpfs = (filesystem_t*)malloc(sizeof(filesystem_t)); + tmpfs->name = "tmpfs"; + tmpfs->setup_mount = setup_tmpfs_mount; + return tmpfs; +} + +int setup_tmpfs_mount(filesystem_t *fs, mount_t *mount) { + uart_printf("Mount tmpfs\n"); + mount->root = create_tmpfs_vnode(NULL, nt_dir); + mount->fs = fs; + return 0; +} + +vnode_t *create_tmpfs_vnode(mount_t *mount, enum NodeType ntype) { + vnode_t *vn = (vnode_t*)malloc(sizeof(vnode_t)); + vn->mount = mount; + vn->v_ops = &tmpfs_vnode_operations; + vn->f_ops = &tmpfs_file_operations; + + vn->internal = malloc(sizeof(tmpfs_internal_t)); + memset(vn->internal, 0, sizeof(tmpfs_internal_t)); + + tmpfs_internal_t *vn_internal = (tmpfs_internal_t*)vn->internal; + vn_internal->ntype = ntype; + vn_internal->data = (char*)malloc(MAX_FILE_SIZE); + vn_internal->datasize = 0; + return vn; +} + +int tmpfs_write(file_t *file, const void *buf, size_t len) { + tmpfs_internal_t *internal = (tmpfs_internal_t*)file->vnode->internal; + len = (file->f_pos + len < MAX_FILE_SIZE) ? len : MAX_FILE_SIZE - file->f_pos; + memcpy(internal->data + file->f_pos, buf, len); + file->f_pos += len; + internal->datasize = file->f_pos; + + return len; +} + +int tmpfs_read(file_t *file, void *buf, size_t len) { + tmpfs_internal_t *internal = (tmpfs_internal_t*)file->vnode->internal; + len = (file->f_pos + len < internal->datasize) ? len : internal->datasize - file->f_pos; + memcpy(buf, internal->data + file->f_pos, len); + file->f_pos += len; + + return len; +} + +int tmpfs_open(vnode_t *file_node, file_t **target) { + (*target)->vnode = file_node; + (*target)->f_ops = file_node->f_ops; + (*target)->f_pos = 0; + return 0; +} + +int tmpfs_close(file_t *file) { + free((void*)file); + return 0; +} + +int tmpfs_getsize(vnode_t *target) { + return ((tmpfs_internal_t*)target->internal)->datasize; +} + +int tmpfs_lookup(vnode_t *dir, vnode_t **target, const char *component_name) { + for(int i = 0; i < MAX_ENTRY; i++) { + vnode_t *ent = ((tmpfs_internal_t*)dir->internal)->entry[i]; + if(ent && strcmp(component_name, ((tmpfs_internal_t*)ent->internal)->name)) { + // uart_printf("[MATCH] (tmpfs) %s, %s\n", component_name, ((tmpfs_internal_t*)ent->internal)->name); + *target = ent; + return 0; + } + } + + // uart_printf("[ERROR] (tmpfs) fail to lookup: %s\n", component_name); + return -1; +} + +int tmpfs_create(vnode_t *dir, vnode_t **target, const char *component_name) { + tmpfs_internal_t *internal = (tmpfs_internal_t*)dir->internal; + + if(internal->ntype != nt_dir) { + uart_printf("[ERROR] (tmpfs) fail to create, dir is not directory\n"); + return -1; + } + + int sel = -1; + for(int i = 0; i < MAX_ENTRY; i++) { + vnode_t *ent = internal->entry[i]; + if(!ent) { + if(sel == -1) sel = i; + } + else { + tmpfs_internal_t *ent_internal = (tmpfs_internal_t*)ent->internal; + if(strcmp(component_name, ent_internal->name) && ent_internal->ntype == nt_file) { + uart_printf("[ERROR] (tmpfs) fail to create, target exists\n"); + return -1; + } + } + } + + if(sel == -1) { + uart_printf("[ERROR] (tmpfs) fail to create, dir is full\n"); + return -1; + } + + internal->entry[sel] = create_tmpfs_vnode(NULL, nt_file); + strcpy(((tmpfs_internal_t*)internal->entry[sel]->internal)->name, component_name); + (*target) = internal->entry[sel]; + + return 0; +} + +int tmpfs_mkdir(vnode_t *dir, vnode_t **target, const char *component_name) { + tmpfs_internal_t *internal = dir->internal; + + if(internal->ntype != nt_dir) { + uart_printf("[ERROR] (tmpfs) fail to mkdir, dir is not directory\n"); + return -1; + } + + int sel = -1; + for(int i = 0; i < MAX_ENTRY; i++) { + vnode_t *ent = internal->entry[i]; + if(!ent) { + if(sel == -1) sel = i; + } + else { + tmpfs_internal_t *ent_internal = (tmpfs_internal_t*)ent->internal; + if(strcmp(component_name, ent_internal->name) && ent_internal->ntype == nt_dir) { + uart_printf("[ERROR] (tmpfs) fail to mkdir, target exists\n"); + return -1; + } + } + } + + if(sel == -1) { + uart_printf("[ERROR] (tmpfs) fail to mkdir, dir is full\n"); + return -1; + } + + internal->entry[sel] = create_tmpfs_vnode(NULL, nt_dir); + strcpy(((tmpfs_internal_t*)internal->entry[sel]->internal)->name, component_name); + (*target) = internal->entry[sel]; + + return 0; +} + diff --git a/lib/uart.c b/lib/uart.c index 7b3e3fa7e..c945e0cc9 100644 --- a/lib/uart.c +++ b/lib/uart.c @@ -47,7 +47,6 @@ void uart_disable() { *AUX_MU_CNTL = 0x00; } -// Send a character void uart_putc(unsigned int c) { /* wait for ready */ do { @@ -57,7 +56,6 @@ void uart_putc(unsigned int c) { *AUX_MU_IO = c; // write character } -// Send a string void uart_puts(char *s) { while(*s) { /* convert newline to carrige return + newline */ @@ -69,22 +67,18 @@ void uart_puts(char *s) { } } -// Show new line void uart_newline() { uart_puts("\n"); } -// Show split line void uart_dem() { uart_puts("\n=================================\n"); } -// show prefix >> void uart_prefix() { uart_puts("\n>> "); } -// Show hex value void uart_hex(uint64 d) { unsigned int n; int c; @@ -98,7 +92,6 @@ void uart_hex(uint64 d) { } } -// Show dec value void uart_num(int64 d) { unsigned int n; char s[16]; @@ -125,7 +118,6 @@ void uart_num(int64 d) { } } -// Receive a binary char uart_getb() { char r; /* wait for input */ @@ -138,7 +130,6 @@ char uart_getb() { return r; } -// Receive a character char uart_getc() { char r; /* wait for input */ @@ -152,7 +143,6 @@ char uart_getc() { return (r == '\r') ? '\n' : r; } -// Receive a number unsigned int uart_getn() { int num = 0; char c; @@ -171,7 +161,6 @@ unsigned int uart_getn() { return num; } -// Get a new kernel via uart char* uart_img_receiver(char* address) { // receive image size (order: little, type: integer, unit: bytes) uart_init(); @@ -184,7 +173,7 @@ char* uart_img_receiver(char* address) { uart_getb() << 24; // echo size info - uart_hex(address); + uart_hex((uint64)address); uart_putc(' '); uart_puts("Image size = "); uart_num(size); @@ -201,7 +190,7 @@ char* uart_img_receiver(char* address) { // echo finish message uart_puts("Receive image done, jump to address "); - uart_hex(address); + uart_hex((uint64)address); uart_dem(); delay_ms(2000); // wait message to be sent before restart new kernel @@ -251,11 +240,9 @@ void uart_async_puts(char *s) { } } -unsigned int uart_async_putc(char c) -{ +unsigned int uart_async_putc(char c) { // full buffer wait - while((tx_buffer_widx + 1) % MAX_BUF_SIZE == tx_buffer_ridx) - { + while((tx_buffer_widx + 1) % MAX_BUF_SIZE == tx_buffer_ridx) { // start asynchronous transfer enable_uart_w_interrupt(); // uart_puts("\n TX fails, uart async tx buffer is full\n"); @@ -277,22 +264,18 @@ unsigned int uart_async_putc(char c) return 0; } -// Show new line void uart_async_newline() { uart_async_puts("\n"); } -// Show split line void uart_async_dem() { uart_async_puts("\n=================================\n"); } -// show prefix >> void uart_async_prefix() { uart_async_puts("\n>> "); } -// Show hex value void uart_async_hex(uint64 d) { unsigned int n; int c; @@ -389,4 +372,47 @@ void raiseError(char *message) { uart_puts("[Error] "); uart_puts(message); while(1); +} + +int uart_printf(char *fmt, ...) { + __builtin_va_list args; + __builtin_va_start(args, fmt); + char buf[MAX_BUF_SIZE]; + // we don't have memory allocation yet, so we + // simply place our string after our code + char *s = (char *)buf; + // use sprintf to format our string + int count = vsprintf(s, fmt, args); + // print out as usual + + while (*s) + { + if(*s == '\n') { + uart_putc('\r'); + } + uart_putc(*s++); + } + __builtin_va_end(args); + return count; +} + +int uart_async_printf(char *fmt, ...) { + __builtin_va_list args; + __builtin_va_start(args, fmt); + char buf[MAX_BUF_SIZE]; + // we don't have memory allocation yet, so we + // simply place our string after our code + char *s = (char *)buf; + // use sprintf to format our string + int count = vsprintf(s, fmt, args); + // print out as usual + while (*s) + { + if(*s == '\n') { + uart_async_putc('\r'); + } + uart_async_putc(*s++); + } + __builtin_va_end(args); + return count; } \ No newline at end of file diff --git a/lib/vfs.c b/lib/vfs.c new file mode 100644 index 000000000..53e8b035b --- /dev/null +++ b/lib/vfs.c @@ -0,0 +1,233 @@ +#include "vfs.h" +#include "tmpfs.h" +#include "initramfs.h" +#include "dev_uart.h" +#include "dev_framebuffer.h" +#include "memory.h" +#include "string.h" + +static uint32 num_registered = 0; +int register_filesystem(filesystem_t *fs) { + // register the file system to the kernel. + // you can also initialize memory pool of the file system here. + + // already registered + for(int i = 0; i < num_registered; i++) { + if(strcmp(fs->name, registered_fs[i].name)) { + return i; + } + } + + // new register + if(num_registered < MAX_REG_FS) { + registered_fs[num_registered].name = fs->name; + registered_fs[num_registered].setup_mount = fs->setup_mount; + return num_registered++; + } + // too many registered fs + else { + return -1; + } +} + +filesystem_t *get_filesystem(const char *name) { + for(int i = 0; i < num_registered; i++) { + if(strcmp(name, registered_fs[i].name)) { + return ®istered_fs[i]; + } + } + + return NULL; +} + +int vfs_open(const char* pathname, int flags, struct file** target) { + // 1. Lookup pathname + // 2. Create a new file handle for this vnode if found. + // 3. Create a new file if O_CREAT is specified in flags and vnode not found + // lookup error code shows if file exist or not or other error occurs + // 4. Return error code if fails + + // uart_printf("(vfs) open %s - start\n", pathname); + vnode_t *searchNode; + bool isExisted = vfs_lookup(pathname, &searchNode) == 0; + if(!isExisted) { + if(flags & O_CREAT) { + // uart_printf("(vfs) O_CREAT %s\n", pathname); + + char dirname[MAX_PATHNAME]; + char *basename = get_dirname(dirname, pathname); + if(vfs_lookup(dirname, &searchNode) != 0) { + uart_printf("[ERROR] (vfs) fail to ocreate, dir doesn't exist\n"); + return -1; + } + + if(searchNode->v_ops->create(searchNode, &searchNode, basename) == -1) { + uart_printf("[ERROR] (vfs) fail to create %s\n", pathname); + return -1; + } + + // uart_printf("(vfs) create %s\n", pathname); + } + else { + uart_printf("[ERROR] (vfs) fail to open, pathname doesn't exist\n"); + return -1; + } + } + + *target = (file_t*)malloc(sizeof(file_t)); + if(searchNode->f_ops->open(searchNode, target) == -1) { + uart_printf("(vfs) open fail: %s\n", pathname); + return -1; + } + (*target)->flags = flags; + // uart_printf("(vfs) open %s - success \n", pathname); + return 0; +} + +int vfs_close(struct file* file) { + // 1. release the file handle + // 2. Return error code if fails + // uart_printf("(vfs) close 0x%x\n", file); + return file->f_ops->close(file); +} + +int vfs_write(struct file* file, const void* buf, size_t len) { + // 1. write len byte from buf to the opened file. + // 2. return written size or error code if an error occurs. + // uart_printf("(vfs) write\n"); + return file->f_ops->write(file, buf, len); +} + +int vfs_read(struct file* file, void* buf, size_t len) { + // 1. read min(len, readable size) byte to buf from the opened file. + // 2. block if nothing to read for FIFO type + // 2. return read size or error code if an error occurs. + + // uart_printf("vfs read(%d): ", len); + return file->f_ops->read(file, buf, len); +} + +long vfs_lseek64(struct file* file, long offset, int whence) { + if(whence == SEEK_SET) { + file->f_pos = offset; + return file->f_pos; + } + return -1; +} + + +int vfs_lookup(const char *pathname, vnode_t **target) { + char rootname[MAX_PATHNAME]; + const char *leaftname = pathname; + + if(strlen(pathname) == 0) { + // uart_printf("(vfs) lookup root\n"); + *target = rootfs->root; + return 0; + } + + vnode_t *dir = rootfs->root; + while(1) { + leaftname = get_rootname(rootname, leaftname); + if(dir->v_ops->lookup(dir, &dir, rootname) == -1) { + uart_printf("[ERROR] (vfs) fail to lookup: %s (%s, %s)\n", pathname, rootname, leaftname); + return -1; + } + + while(dir->mount) dir = dir->mount->root; // if mount then ignore all other entries + + if(leaftname == NULL) { + *target = dir; + // uart_printf("(vfs) lookup %s\n", pathname); + return 0; + } + } +} + +int vfs_mkdir(const char *pathname) { + char dirname[MAX_PATHNAME]; + char *basename = get_dirname(dirname, pathname); + // uart_printf("(vfs) mkdir %s\n", pathname); + + vnode_t *searchNode; + if(vfs_lookup(dirname, &searchNode) == -1) { + uart_printf("[ERROR] (vfs) fail to mkdir, parenet dir doesn't exist\n"); + return -1; + } + + searchNode->v_ops->mkdir(searchNode, &searchNode, basename); + return 0; +} + +int vfs_mount(const char *target, const char *filesystem) { + filesystem_t *fs = get_filesystem(filesystem); + + // uart_printf("(vfs) mount %s at %s - start\n", filesystem, target); + + if(!fs) { + uart_printf("[ERROR] (vfs) %s is not registered\n", filesystem); + return -1; + } + + vnode_t *searchNode; + if(vfs_lookup(target, &searchNode) == -1) { + uart_printf("[ERROR] (vfs) %s doesn't exist\n", target); + return -1; + } + + // uart_printf("(vfs) mount %s at %s - success\n", filesystem, target); + searchNode->mount = (mount_t*)malloc(sizeof(mount_t)); + fs->setup_mount(fs, searchNode->mount); + return 0; +} + +int nop_op() { + return -1; +} + + +static uint32 num_registered_fop = 0; +int register_dev_fop(file_operations_t *fop) { + if(num_registered_fop < MAX_REG_DEV) { + registered_dev_fops[num_registered_fop] = *fop; + return num_registered_fop++; + } + // too many registered fop + else { + return -1; + } +} + +int vfs_mknod(const char *pathname, int dev_id) { + file_t *dev_file; + if(vfs_open(pathname, O_CREAT, &dev_file) == -1) { + uart_printf("[ERROR] mknod fail on %s with id: %d\n", pathname, dev_id); + return -1; + } + + dev_file->vnode->f_ops = ®istered_dev_fops[dev_id]; + free((void*)dev_file); + return 0; +} + +void init_vfs() { + rootfs = malloc(sizeof(mount_t)); + filesystem_t *tmpfs = get_tmpfs(); + int id = register_filesystem(tmpfs); + registered_fs[id].setup_mount(®istered_fs[id], rootfs); + free((void*)tmpfs); + + vfs_mkdir("/initramfs"); + filesystem_t *initramfs = get_initramfs(); + id = register_filesystem(initramfs); + vfs_mount("/initramfs", "initramfs"); + free((void*)initramfs); + + vfs_mkdir("/dev"); + int dev_uart_id = register_dev_fop(&dev_uart_file_operations); + vfs_mknod("/dev/uart", dev_uart_id); + + init_dev_framebuffer(); + int dev_framebuffer_id = register_dev_fop(&dev_framebuffer_file_operations); + vfs_mknod("/dev/framebuffer", dev_framebuffer_id); +} \ No newline at end of file