diff --git a/.vscode/settings.json b/.vscode/settings.json index c4c50aba3..8494957d4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,8 @@ { "files.associations": { - "fork.h": "c" + "fork.h": "c", + "string.h": "c", + "mbr.h": "c", + "vfs.h": "c" } } \ No newline at end of file diff --git a/lab6/bcm2710-rpi-3-b-plus.dtb b/lab6/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..3934b3a26 Binary files /dev/null and b/lab6/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab6/config.txt b/lab6/config.txt new file mode 100644 index 000000000..49fc25695 --- /dev/null +++ b/lab6/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x20000000 diff --git a/lab6/include/cpio.h b/lab6/include/cpio.h new file mode 100644 index 000000000..1735f5fe5 --- /dev/null +++ b/lab6/include/cpio.h @@ -0,0 +1,49 @@ +#ifndef __CPIO_H__ +#define __CPIO_H__ + +/* +Each file system object in a cpio archive comprises a header record with +basic numeric metadata followed by the full pathname of the entry and the +file data. The header record stores a series of integer values that gen- +erally follow the fields in struct stat. (See stat(2) for details.) The +variants differ primarily in how they store those integers (binary, oc- +tal, or hexadecimal). The header is followed by the pathname of the en- +try (the length of the pathname is stored in the header) and any file +data. The end of the archive is indicated by a special record with the +pathname "TRAILER!!!" +*/ + +#define CPIO_HEADER_MAGIC "070701" +#define CPIO_FOOTER_MAGIC "TRAILER!!!" +#define PI_CPIO_BASE ((void*) (0x20000000)) +#define QEMU_CPIO_BASE ((void*) (0x8000000)) + +#include "devtree.h" + +extern void *DEVTREE_CPIO_BASE; + +struct cpio_newc_header { + char c_magic[6]; // 070701 + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; // ignored by readers +}; + +void initramfs_callback (char *, char *, struct fdt_prop *); +void cpio_ls (); +void cpio_cat (); +void cpio_exec (); + +unsigned int hexstr_to_uint(char *s, unsigned int len); + +#endif \ No newline at end of file diff --git a/lab6/include/devtree.h b/lab6/include/devtree.h new file mode 100644 index 000000000..1c3c27899 --- /dev/null +++ b/lab6/include/devtree.h @@ -0,0 +1,64 @@ +#ifndef _DEVTREE_H +#define _DEVTREE_H + +/* + magic; 0xd00dfeed (big-endian) + + totalsize; total size in bytes of the devicetree + data structure + + off_dt_struct; offset in bytes of the structure block + from the beginning of the header + + off_dt_strings; offset in bytes of the strings block + from the beginning of the header + + off_mem_rsvmap; offset in bytes of the memory reservation + block from the beginning of the header + + version; version of the devicetree data structure + + last_comp_version; lowest version of the devicetree data + structure with which the version used is backwards compatible + + boot_cpuid_phys; physical ID of the system’s boot CPU + + size_dt_strings; length in bytes of the strings block + section of the devicetree blob + + size_dt_struct; length in bytes of the structure block + section of the devicetree blob +*/ + +#define FDT_HEADER_MAGIC 0xd00dfeed +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +struct fdt_header { + unsigned int magic; + unsigned int totalsize; + unsigned int off_dt_struct; + unsigned int off_dt_strings; + unsigned int off_mem_rsvmap; + unsigned int version; + unsigned int last_comp_version; + unsigned int boot_cpuid_phys; + unsigned int size_dt_strings; + unsigned int size_dt_struct; +}; + +struct fdt_prop { + unsigned int len; + unsigned int nameoff; +}; + +void devtree_getaddr (); +void fdt_traverse ( void (*callback)(char *, char *, struct fdt_prop *) ); + +// ARM uses little endian +unsigned long to_lendian (unsigned long); + +#endif \ No newline at end of file diff --git a/lab6/include/entry.h b/lab6/include/entry.h new file mode 100644 index 000000000..1a22d0284 --- /dev/null +++ b/lab6/include/entry.h @@ -0,0 +1,39 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#define S_FRAME_SIZE 272 // size of all saved registers +#define S_X0 0 + +#define SYNC_INVALID_EL1t 0 +#define IRQ_INVALID_EL1t 1 +#define FIQ_INVALID_EL1t 2 +#define ERROR_INVALID_EL1t 3 + +#define SYNC_INVALID_EL1h 4 +#define IRQ_INVALID_EL1h 5 +#define FIQ_INVALID_EL1h 6 +#define ERROR_INVALID_EL1h 7 + +#define SYNC_INVALID_EL0_64 8 +#define IRQ_INVALID_EL0_64 9 +#define FIQ_INVALID_EL0_64 10 +#define ERROR_INVALID_EL0_64 11 + +#define SYNC_INVALID_EL0_32 12 +#define IRQ_INVALID_EL0_32 13 +#define FIQ_INVALID_EL0_32 14 +#define ERROR_INVALID_EL0_32 15 + +#define SYNC_ERROR 16 +#define SYSCALL_ERROR 17 + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 + +#ifndef __ASSEMBLER__ + +void ret_from_fork(); + +#endif + +#endif \ No newline at end of file diff --git a/lab6/include/exception.h b/lab6/include/exception.h new file mode 100644 index 000000000..40f4ba532 --- /dev/null +++ b/lab6/include/exception.h @@ -0,0 +1,7 @@ +#ifndef _EXCEPTION_H +#define _EXCEPTION_H + +void enable_interrupt(); +void disable_interrupt(); + +#endif \ No newline at end of file diff --git a/lab6/include/fork.h b/lab6/include/fork.h new file mode 100644 index 000000000..06bc62382 --- /dev/null +++ b/lab6/include/fork.h @@ -0,0 +1,27 @@ +#ifndef _FORK_H +#define _FORK_H + +#include "sched.h" + +#define PSR_MODE_EL0t 0x00000000 +#define PSR_MODE_EL1t 0x00000004 +#define PSR_MODE_EL1h 0x00000005 +#define PSR_MODE_EL2t 0x00000008 +#define PSR_MODE_EL2h 0x00000009 +#define PSR_MODE_EL3t 0x0000000c +#define PSR_MODE_EL3h 0x0000000d + +int copy_process(unsigned long, unsigned long, unsigned long/*, unsigned long*/); +int move_to_user_mode(unsigned long, unsigned long, unsigned long); +struct pt_regs *task_pt_regs(struct task_struct *); +void new_user_process(unsigned long); +int copy_virt_memory(struct task_struct *); + +struct pt_regs { + unsigned long regs[31]; + unsigned long sp; + unsigned long pc; + unsigned long pstate; +}; + +#endif \ No newline at end of file diff --git a/lab6/include/mailbox.h b/lab6/include/mailbox.h new file mode 100644 index 000000000..eeecaa9de --- /dev/null +++ b/lab6/include/mailbox.h @@ -0,0 +1,7 @@ +#ifndef _MAILBOX_H +#define _MAILBOX_H + +void get_board_revision (); +void get_arm_memory (); + +#endif \ No newline at end of file diff --git a/lab6/include/math.h b/lab6/include/math.h new file mode 100644 index 000000000..353ccfb26 --- /dev/null +++ b/lab6/include/math.h @@ -0,0 +1,7 @@ +#ifndef _MATH_H +#define _MATH_H + +int log(int, int); +int pow(int, int); + +#endif \ No newline at end of file diff --git a/lab6/include/memory.h b/lab6/include/memory.h new file mode 100644 index 000000000..956f6e955 --- /dev/null +++ b/lab6/include/memory.h @@ -0,0 +1,8 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#define MAX_HEAP_SIZE 0x10000000 + +void* simple_malloc(unsigned int); + +#endif \ No newline at end of file diff --git a/lab6/include/mini_uart.h b/lab6/include/mini_uart.h new file mode 100644 index 000000000..453ec93f2 --- /dev/null +++ b/lab6/include/mini_uart.h @@ -0,0 +1,10 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void uart_init ( void ); +char uart_recv ( void ); +void uart_send ( char c ); +void uart_send_string ( char* str ); +void printf ( char *fmt, ... ); + +#endif /*_MINI_UART_H */ \ No newline at end of file diff --git a/lab6/include/mm.h b/lab6/include/mm.h new file mode 100644 index 000000000..f74bfd242 --- /dev/null +++ b/lab6/include/mm.h @@ -0,0 +1,61 @@ +#ifndef _MM_H +#define _MM_H + +#define MEM_REGION_BEGIN 0x0 +#define MEM_REGION_END 0x3C000000 +#define PAGE_SIZE 4096 +#define MAX_ORDER 8 // largest: PAGE_SIZE*2^(MAX_ORDER) + +#define ALLOCABLE 0 +#define ALLOCATED -1 +#define C_NALLOCABLE -2 +#define RESERVED -3 + +#define NULL 0 + +#define MAX_POOL_PAGES 8 +#define MAX_POOLS 8 +#define MIN_CHUNK_SIZE 8 + +#define MAX_RESERVABLE 8 + +struct frame { + unsigned int index; + int val; + int state; + struct frame *prev, *next; +}; + +struct node { + struct node *next; +}; + +struct dynamic_pool { + unsigned int chunk_size; + unsigned int chunks_per_page; + unsigned int chunks_allocated; + unsigned int page_new_chunk_off; + unsigned int pages_used; + void *page_base_addrs[MAX_POOL_PAGES]; + struct node *free_head; +}; + +#include "sched.h" + +unsigned long allocate_user_page(struct task_struct *, unsigned long); +unsigned long allocate_kernel_page(); + +void *malloc(unsigned int); +void free(void *); +void init_mm(); +void init_pool(struct dynamic_pool*, unsigned int); +int register_chunk(unsigned int); +void *chunk_alloc(unsigned int); +void chunk_free(void *); +void memory_reserve(void*, void*); +void init_mm_reserve(); + +void memcpy(unsigned long dst, unsigned long src, unsigned long n); +void memzero(unsigned long, unsigned long); + +#endif /*_MM_H */ \ No newline at end of file diff --git a/lab6/include/mmu.h b/lab6/include/mmu.h new file mode 100644 index 000000000..4733595ef --- /dev/null +++ b/lab6/include/mmu.h @@ -0,0 +1,51 @@ +#ifndef _MMU_H +#define _MMU_H + +#define VA_START 0xffff000000000000 +#define VA_MASK 0x0000ffffffffffff + +#define PAGE_MASK 0xfffffffffffff000 + +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 +#define MAIR_VALUE \ +( \ + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | \ + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8)) \ +) + +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PT_ENTRY 0b11 +#define PD_ACCESS (1 << 10) +#define BOOT_PGD_ATTR PD_TABLE +#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) + +#define PTE_USR_RO_PTE (PD_ACCESS | (0b11<<6) | (MAIR_IDX_NORMAL_NOCACHE<<2) | PT_ENTRY) +#define PTE_USR_RW_PTE (PD_ACCESS | (0b01<<6) | (MAIR_IDX_NORMAL_NOCACHE<<2) | PT_ENTRY) + +#define SCTLR_MMU_DISABLED 0 +#define SCTLR_MMU_ENABLED 1 + +#define PGD_SHIFT (12 + 3*9) +#define PUD_SHIFT (12 + 2*9) +#define PMD_SHIFT (12 + 9) + +#ifndef __ASSEMBLER__ + +#include "sched.h" + +void map_page(struct task_struct *task, unsigned long va, unsigned long page); +unsigned long map_table(unsigned long *table, unsigned long shift, unsigned long va, int* new_table); +void map_table_entry(unsigned long *pte, unsigned long va, unsigned long pa); +unsigned long va2phys(unsigned long va); + +#endif + +#endif \ No newline at end of file diff --git a/lab6/include/peripherals/base.h b/lab6/include/peripherals/base.h new file mode 100644 index 000000000..aeb57bd92 --- /dev/null +++ b/lab6/include/peripherals/base.h @@ -0,0 +1,9 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +#include "mmu.h" + +#define DEVICE_BASE 0x3F000000 +#define PBASE (VA_START+DEVICE_BASE) + +#endif /*_P_BASE_H */ \ No newline at end of file diff --git a/lab6/include/peripherals/exception.h b/lab6/include/peripherals/exception.h new file mode 100644 index 000000000..713d05418 --- /dev/null +++ b/lab6/include/peripherals/exception.h @@ -0,0 +1,26 @@ +#ifndef _P_EXCEPTION_H +#define _P_EXCEPTION_H + +#include "peripherals/base.h" +#include "mmu.h" + +#define IRQ_BASIC_PENDING (PBASE+0x0000B200) +#define IRQ_PENDING_1 (PBASE+0x0000B204) +#define IRQ_PENDING_2 (PBASE+0x0000B208) +#define FIQ_CONTROL (PBASE+0x0000B20C) +#define ENABLE_IRQS_1 (PBASE+0x0000B210) +#define ENABLE_IRQS_2 (PBASE+0x0000B214) +#define ENABLE_BASIC_IRQS (PBASE+0x0000B218) +#define DISABLE_IRQS_1 (PBASE+0x0000B21C) +#define DISABLE_IRQS_2 (PBASE+0x0000B220) +#define DISABLE_BASIC_IRQS (PBASE+0x0000B224) + +#define CNTPCT_EL0 (VA_START + 0x4000001C) +#define CNTP_CTL_EL0 (VA_START + 0x40000040) +#define CORE0_INTERRUPT_SRC (VA_START + 0x40000060) + +#define IRQ_PENDING_1_AUX_INT (1<<29) +#define INTERRUPT_SOURCE_GPU (1<<8) +#define INTERRUPT_SOURCE_CNTPNSIRQ (1<<1) + +#endif \ No newline at end of file diff --git a/lab6/include/peripherals/gpio.h b/lab6/include/peripherals/gpio.h new file mode 100644 index 000000000..c5d7d138f --- /dev/null +++ b/lab6/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _P_GPIO_H +#define _P_GPIO_H + +#include "peripherals/base.h" + +#define GPFSEL1 (PBASE+0x00200004) +#define GPSET0 (PBASE+0x0020001C) +#define GPCLR0 (PBASE+0x00200028) +#define GPPUD (PBASE+0x00200094) +#define GPPUDCLK0 (PBASE+0x00200098) + +#endif /*_P_GPIO_H */ \ No newline at end of file diff --git a/lab6/include/peripherals/mailbox.h b/lab6/include/peripherals/mailbox.h new file mode 100644 index 000000000..62225bd47 --- /dev/null +++ b/lab6/include/peripherals/mailbox.h @@ -0,0 +1,25 @@ +#ifndef _P_MAILBOX_H +#define _P_MAILBOX_H + +#include "mmu.h" + +#define MMIO_BASE VA_START + 0x3f000000 +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#define MAILBOX_READ (volatile unsigned int*) (MAILBOX_BASE) +#define MAILBOX_STATUS (volatile unsigned int*) (MAILBOX_BASE + 0x18) +#define MAILBOX_WRITE (volatile unsigned int*) (MAILBOX_BASE + 0x20) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 + +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +#endif \ No newline at end of file diff --git a/lab6/include/peripherals/mini_uart.h b/lab6/include/peripherals/mini_uart.h new file mode 100644 index 000000000..386b6fade --- /dev/null +++ b/lab6/include/peripherals/mini_uart.h @@ -0,0 +1,19 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_ENABLES (PBASE+0x00215004) +#define AUX_MU_IO_REG (PBASE+0x00215040) +#define AUX_MU_IER_REG (PBASE+0x00215044) +#define AUX_MU_IIR_REG (PBASE+0x00215048) +#define AUX_MU_LCR_REG (PBASE+0x0021504C) +#define AUX_MU_MCR_REG (PBASE+0x00215050) +#define AUX_MU_LSR_REG (PBASE+0x00215054) +#define AUX_MU_MSR_REG (PBASE+0x00215058) +#define AUX_MU_SCRATCH (PBASE+0x0021505C) +#define AUX_MU_CNTL_REG (PBASE+0x00215060) +#define AUX_MU_STAT_REG (PBASE+0x00215064) +#define AUX_MU_BAUD_REG (PBASE+0x00215068) + +#endif /*_P_MINI_UART_H */ \ No newline at end of file diff --git a/lab6/include/printf.h b/lab6/include/printf.h new file mode 100644 index 000000000..dfedbe301 --- /dev/null +++ b/lab6/include/printf.h @@ -0,0 +1,31 @@ +/* + * 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. + * + */ +#ifndef _PRINTF_H +#define _PRINTF_H + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); + +#endif \ No newline at end of file diff --git a/lab6/include/reboot.h b/lab6/include/reboot.h new file mode 100644 index 000000000..df4d63a86 --- /dev/null +++ b/lab6/include/reboot.h @@ -0,0 +1,7 @@ +#ifndef _REBOOT_H +#define _REBOOT_H + +void reset ( int ); +void cancel_reset (); + +#endif \ No newline at end of file diff --git a/lab6/include/sched.h b/lab6/include/sched.h new file mode 100644 index 000000000..1c0d56c0d --- /dev/null +++ b/lab6/include/sched.h @@ -0,0 +1,90 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#define THREAD_CPU_CONTEXT 0 + +#ifndef __ASSEMBLER__ + +#define THREAD_SIZE 4096 + +#define NR_TASKS 64 + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 + +#define PF_KTHREAD 0x00000002 + +extern struct task_struct *current; +extern struct task_struct *task[NR_TASKS]; +extern int nr_tasks; + +struct cpu_context { + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long sp; + unsigned long pc; +}; + +#define MAX_PROCESS_PAGES 128 + +struct user_page { + unsigned long phys_addr; + unsigned long virt_addr; +}; + +struct mm_struct { + unsigned long pgd; + int user_pages_count; + struct user_page user_pages[MAX_PROCESS_PAGES]; + int kernel_pages_count; + unsigned long kernel_pages[MAX_PROCESS_PAGES]; +}; + +struct task_struct { + struct cpu_context cpu_context; + long state; + long counter; + long priority; + long preempt_count; + //unsigned long stack; //remove + unsigned long flags; + long id; + struct mm_struct mm; +}; + +extern void sched_init(); +extern void schedule(); +extern void timer_tick(); +extern void preempt_disable(); +extern void preempt_enable(); +extern void switch_to(struct task_struct *); +extern void cpu_switch_to(struct task_struct *, struct task_struct *); +extern void exit_process(); +extern void kill_zombies(); +extern void update_pgd(unsigned long); + +#define INIT_TASK \ +{ \ +{0,0,0,0,0,0,0,0,0,0,0,0,0},\ +0, 0, 1, 0, PF_KTHREAD, 0, \ +{0,0,{{0}},0,{0}}\ +} + +#endif + +#endif \ No newline at end of file diff --git a/lab6/include/shell.h b/lab6/include/shell.h new file mode 100644 index 000000000..828c56763 --- /dev/null +++ b/lab6/include/shell.h @@ -0,0 +1,6 @@ +#ifndef _SHELL_H +#define _SHELL_H + +void shell_loop (); + +#endif \ No newline at end of file diff --git a/lab6/include/string.h b/lab6/include/string.h new file mode 100644 index 000000000..abf24c93f --- /dev/null +++ b/lab6/include/string.h @@ -0,0 +1,8 @@ +#ifndef _STRING_H +#define _STRING_H + +int stringcmp (const char *, const char *); +int stringncmp (const char *, const char *, unsigned int); +unsigned int strlen(const char *); + +#endif \ No newline at end of file diff --git a/lab6/include/syscall.h b/lab6/include/syscall.h new file mode 100644 index 000000000..a1c2215f5 --- /dev/null +++ b/lab6/include/syscall.h @@ -0,0 +1,37 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +#define __NR_SYSCALLS 8 + +#define SYS_GETPID_NUM 0 +#define SYS_UARTREAD_NUM 1 +#define SYS_UARTWRITE_NUM 2 +#define SYS_EXEC_NUM 3 +#define SYS_FORK_NUM 4 +#define SYS_EXIT_NUM 5 +#define SYS_MBOXCALL_NUM 6 +#define SYS_KILL_NUM 7 + +#ifndef __ASSEMBLER__ + +int getpid(); +unsigned uart_read(char buf[], unsigned size); +unsigned uart_write(const char buf[], unsigned size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(int status); +int mbox_call(unsigned char ch, volatile unsigned int *mbox); +void kill(int pid); + +int sys_getpid(); +unsigned sys_uartread(char buf[], unsigned size); +unsigned sys_uartwrite(const char buf[], unsigned size); +int sys_exec(const char *name, char *const argv[]); +int sys_fork(); +void sys_exit(int status); +int sys_mbox_call(unsigned char ch, volatile unsigned int *mbox); +void sys_kill(int pid); + +#endif + +#endif \ No newline at end of file diff --git a/lab6/include/timer.h b/lab6/include/timer.h new file mode 100644 index 000000000..9812a457a --- /dev/null +++ b/lab6/include/timer.h @@ -0,0 +1,14 @@ +#ifndef _TIMER_H +#define _TIMER_H + +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +void timer_init(); +void handle_timer_irq(); +void core_timer_enable(); +void core_timer_disable(); +void set_timer(unsigned int rel_time); +unsigned int read_timer(); +unsigned int read_freq(); + +#endif \ No newline at end of file diff --git a/lab6/include/utils.h b/lab6/include/utils.h new file mode 100644 index 000000000..9d950d477 --- /dev/null +++ b/lab6/include/utils.h @@ -0,0 +1,8 @@ +#ifndef _BOOT_H +#define _BOOT_H + +extern void delay ( unsigned long ); +extern void put32 ( unsigned long, unsigned int ); +extern unsigned int get32 ( unsigned long ); + +#endif /*_BOOT_H */ \ No newline at end of file diff --git a/lab6/initramfs.cpio b/lab6/initramfs.cpio new file mode 100644 index 000000000..e1b3477ce Binary files /dev/null and b/lab6/initramfs.cpio differ diff --git a/lab6/kernel/Makefile b/lab6/kernel/Makefile new file mode 100644 index 000000000..831618b19 --- /dev/null +++ b/lab6/kernel/Makefile @@ -0,0 +1,49 @@ +AARCH64_PREFIX = aarch64-linux-gnu- +CC = $(AARCH64_PREFIX)gcc +LD = $(AARCH64_PREFIX)ld +OBJCPY = $(AARCH64_PREFIX)objcopy +GDB = $(AARCH64_PREFIX)gdb + +CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding -I../include -mgeneral-regs-only +ASMFLAGS = -I../include + +BUILD_DIR = ../build + +.PHONY: all clean qemu gdb_start + +all: kernel8.img + +clean: + rm kernel8.img $(OBJ_FILES) $(BUILD_DIR)/$(DEP_FILES) \ + ../build/kernel8.elf + +$(BUILD_DIR)/%_c.o: %.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: %.S + $(CC) $(ASMFLAGS) -MMD -c $< -o $@ + +C_FILES = $(wildcard *.c) +ASM_FILES = $(wildcard *.S) +OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) + +LIBC_FILES = $(wildcard ../lib/*.c) +LIBASM_FILES = $(wildcard ../lib/*.S) +LIBOBJ_FILES = $(LIBC_FILES:../lib/%.c=$(BUILD_DIR)/%_c.o) +LIBOBJ_FILES += $(LIBASM_FILES:../lib/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) $(LIBOBJ_FILES) + $(LD) -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) $(LIBOBJ_FILES) + $(OBJCPY) $(BUILD_DIR)/kernel8.elf -O binary $@ + +qemu: # all in one qemu command + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -S -s -serial null -serial pty \ + -initrd ../initramfs.cpio -dtb ../bcm2710-rpi-3-b-plus.dtb + +gdb_start: + $(GDB) $(BUILD_DIR)/kernel8.elf diff --git a/lab6/kernel/boot_kernel.S b/lab6/kernel/boot_kernel.S new file mode 100644 index 000000000..27ccfa7f1 --- /dev/null +++ b/lab6/kernel/boot_kernel.S @@ -0,0 +1,88 @@ +#include "mmu.h" +#include "peripherals/base.h" + +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 + and x0, x0, #3 // Check processor id + cbnz x0, proc_hang // Hang for all non-primary CPU + bl from_el2_to_el1 + bl set_exception_vector_table + +master: + mov x2, #VA_START + ldr x0, =__bss_begin + sub x0, x0, x2 + ldr x1, =__bss_end + sub x1, x1, x2 + sub x1, x1, x0 + +memzero: + cbz x1, mmu + str xzr, [x0], #8 + subs x1, x1, #8 + cbnz x1, memzero + +mmu: + mov x0, #VA_START + add sp, x0, #0x80000 + + bl set_tcr + bl set_mair + bl make_page_tables + + mov x0, #SCTLR_MMU_ENABLED + msr sctlr_el1, x0 + + ldr x0, =kernel_main + br x0 + +proc_hang: + wfe + b proc_hang + +set_exception_vector_table: + ldr x0, =exception_vector_table + msr vbar_el1, x0 + ret + +from_el2_to_el1: + 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 + +set_tcr: + ldr x0, =TCR_CONFIG_DEFAULT + msr tcr_el1, x0 + ret + +set_mair: + ldr x0, =MAIR_VALUE + msr mair_el1, x0 + ret + +make_page_tables: + ldr x0, =pg_dir + and x0, x0, #VA_MASK + add x1, x0, 0x1000 + + ldr x2, =BOOT_PGD_ATTR + orr x2, x1, x2 + str x2, [x0] + + ldr x2, =BOOT_PUD_ATTR + mov x3, 0x00000000 + orr x3, x2, x3 + str x3, [x1] + mov x3, 0x40000000 + orr x3, x2, x3 + str x3, [x1, 8] + + msr ttbr0_el1, x0 + msr ttbr1_el1, x0 + ret \ No newline at end of file diff --git a/lab6/kernel/kernel.c b/lab6/kernel/kernel.c new file mode 100644 index 000000000..490719083 --- /dev/null +++ b/lab6/kernel/kernel.c @@ -0,0 +1,26 @@ +#include "mini_uart.h" +#include "shell.h" +#include "devtree.h" +#include "cpio.h" +#include "mm.h" +#include "timer.h" +#include "exception.h" +#include "fork.h" + +void kernel_main(void) +{ + uart_init(); + devtree_getaddr(); + fdt_traverse(initramfs_callback); + init_mm_reserve(); + timer_init(); + enable_interrupt(); + uart_send_string("OSDI 2022 Spring\n"); + + copy_process(PF_KTHREAD, (unsigned long)&shell_loop, 0/*, 0*/); + + while (1) { + kill_zombies(); + schedule(); + } +} \ No newline at end of file diff --git a/lab6/kernel/linker.ld b/lab6/kernel/linker.ld new file mode 100644 index 000000000..48804b7fb --- /dev/null +++ b/lab6/kernel/linker.ld @@ -0,0 +1,24 @@ +SECTIONS +{ + . = 0xffff000000000000; + . += 0x80000; + + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + + . = ALIGN(8); + + __bss_begin = .; + .bss : { *(.bss* .bss.*) } + __bss_end = .; + + . = ALIGN(0x00001000); + pg_dir = .; + .data.pgd : { . += (3 * (1 << 12)); } + + __heap_start = .; + __kernel_end = .; + +} diff --git a/lab6/lib/Makefile b/lab6/lib/Makefile new file mode 100644 index 000000000..66d9bcea3 --- /dev/null +++ b/lab6/lib/Makefile @@ -0,0 +1,29 @@ +AARCH64_PREFIX = aarch64-linux-gnu- +CC = $(AARCH64_PREFIX)gcc + +CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding -I../include -mgeneral-regs-only +ASMFLAGS = -I../include + +BUILD_DIR = ../build + +.PHONY: all clean + +$(BUILD_DIR)/%_c.o: %.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: %.S + $(CC) $(ASMFLAGS) -MMD -c $< -o $@ + +C_FILES = $(wildcard *.c) +ASM_FILES = $(wildcard *.S) +OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +all: $(OBJ_FILES) + +clean: + rm $(OBJ_FILES) $(BUILD_DIR)/$(DEP_FILES) diff --git a/lab6/lib/cpio.c b/lab6/lib/cpio.c new file mode 100644 index 000000000..5e7d2cb6e --- /dev/null +++ b/lab6/lib/cpio.c @@ -0,0 +1,233 @@ +#include "../include/cpio.h" +#include "mini_uart.h" +#include "../include/sched.h" +#include "fork.h" +#include "string.h" +#include "mmu.h" + +void *DEVTREE_CPIO_BASE = 0; + +unsigned int hexstr_to_uint(char *s, unsigned int len) { + + unsigned int n = 0; + + for (int i=0; i= '0' && s[i] <= '9') { + n += s[i] - '0'; + } else if (s[i] >= 'A' && s[i] <= 'F') { + n += s[i] - 'A' + 10; + } + } + + return n; + +} + +void initramfs_callback(char *node_name, char *prop_name, struct fdt_prop *prop) { + + if (stringncmp(node_name, "chosen", 7) == 0 && + stringncmp(prop_name, "linux,initrd-start", 19) == 0) { + + DEVTREE_CPIO_BASE = (void*)to_lendian(*((unsigned int*)(prop + 1))) + VA_START; + + } + +} + +void cpio_ls() { + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + + header = DEVTREE_CPIO_BASE; + + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) break; + + uart_send_string(filename); + uart_send('\n'); + + namesize = hexstr_to_uint(header->c_namesize, 8); + filesize = hexstr_to_uint(header->c_filesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + +} + +void cpio_cat() { + + char input[256]; + char c = '\0'; + int idx = 0; + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + + header = DEVTREE_CPIO_BASE; + + uart_send_string("Filename: "); + + while (1) { + c = uart_recv(); + if (c == '\r' || c == '\n') { + uart_send_string("\n"); + + if (idx < 256) input[idx] = '\0'; + else input[255] = '\0'; + + break; + } else { + uart_send(c); + input[idx++] = c; + } + } + + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) { + uart_send_string("file does not exist!\n"); + break; + } + + namesize = hexstr_to_uint(header->c_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, input, namesize) == 0) { + + char *content = ((void*)header) + offset; + + for (int i=0; ic_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, input, namesize) == 0) { + + char *code_loc = ((void*)header) + offset; + unsigned int sp_val = 0x600000; + asm volatile( + "msr elr_el1, %0\n\t" + "msr spsr_el1, xzr\n\t" + "msr sp_el0, %1\n\t" + "eret\n\t" + :: + "r" (code_loc), + "r" (sp_val) + ); + + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + +} diff --git a/lab6/lib/devtree.c b/lab6/lib/devtree.c new file mode 100644 index 000000000..691dc1a7e --- /dev/null +++ b/lab6/lib/devtree.c @@ -0,0 +1,92 @@ +#include "devtree.h" +#include "mini_uart.h" +#include "string.h" + +static void *DEVTREE_ADDRESS = 0; + +unsigned long to_lendian(unsigned long n) { + return ((n>>24)&0x000000FF) | + ((n>>8) &0x0000FF00) | + ((n<<8) &0x00FF0000) | + ((n<<24)&0xFF000000) ; +} + +void devtree_getaddr() { + + asm volatile("MOV %0, x20" : "=r"(DEVTREE_ADDRESS)); + + char magic[4] = {0xd0, 0x0d, 0xfe, 0xed}; + if(stringncmp((char*)DEVTREE_ADDRESS, magic, 4) != 0) { + uart_send_string("magic failed\n"); + } else { + uart_send_string("devtree magic succeed\n"); + } + +} + +void fdt_traverse( void (*callback)(char *, char *, struct fdt_prop *) ) { + + char magic[4] = {0xd0, 0x0d, 0xfe, 0xed}; + struct fdt_header *devtree_header = DEVTREE_ADDRESS; + + if(stringncmp((char*)devtree_header, magic, 4) != 0) { + uart_send_string("devtree magic failed\n"); + return; + } + + void *dt_struct_addr = DEVTREE_ADDRESS + to_lendian(devtree_header->off_dt_struct); + char *dt_string_addr = DEVTREE_ADDRESS + to_lendian(devtree_header->off_dt_strings); + + char *node_name; + char *prop_name; + unsigned int token; + unsigned int off; + + while (1) { + + token = to_lendian(*((unsigned int *)dt_struct_addr)); + + if (token == FDT_BEGIN_NODE) { + + node_name = dt_struct_addr + 4; + off = 4 + strlen(node_name) + 1; + + if (off%4 != 0) + off = ((off/4)+1)*4; + + dt_struct_addr += off; + + } + else if (token == FDT_END_NODE) { + dt_struct_addr += 4; + } + else if (token == FDT_PROP) { + + struct fdt_prop *prop = (struct fdt_prop*)(dt_struct_addr + 4); + + off = 4 + 8 + to_lendian(prop->len); + if (off%4 != 0) + off = ((off/4)+1)*4; + + dt_struct_addr += off; + + prop_name = dt_string_addr + to_lendian(prop->nameoff); + + callback(node_name, prop_name, prop); + + } + else if (token == FDT_NOP) { + dt_struct_addr += 4; + } + else if (token == FDT_END) { + dt_struct_addr += 4; + break; + } + else { + uart_send_string("TOKEN NOT MATCHED\n"); + break; + } + + } + +} \ No newline at end of file diff --git a/lab6/lib/entry.S b/lab6/lib/entry.S new file mode 100644 index 000000000..e564be0fe --- /dev/null +++ b/lab6/lib/entry.S @@ -0,0 +1,195 @@ +#include "entry.h" +#include "syscall.h" + +.macro handle_invalid_entry el, type + kernel_entry \el + mov x0, #\type + mrs x1, esr_el1 + mrs x2, elr_el1 + bl show_invalid_entry_message + b err_hang +.endm + +.macro ventry label + .align 7 + b \label +.endm + +// save general registers to stack +.macro kernel_entry, el + sub sp, sp, #S_FRAME_SIZE + 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] + + .if \el == 0 + mrs x21, sp_el0 + .else + add x21, sp, #S_FRAME_SIZE + .endif + + mrs x22, elr_el1 + mrs x23, spsr_el1 + + stp x30, x21, [sp, 16 * 15] + stp x22, x23, [sp, 16 * 16] +.endm + +// load general registers from stack +.macro kernel_exit, el + ldp x22, x23, [sp, 16 * 16] + ldp x30, x21, [sp, 16 * 15] + + .if \el == 0 + msr sp_el0, x21 + .endif + + msr elr_el1, x22 + msr spsr_el1, x23 + + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + add sp, sp, #S_FRAME_SIZE + eret +.endm + +.align 11 // vector table should be aligned to 0x800 +.globl exception_vector_table +exception_vector_table: + ventry sync_invalid_el1t // Synchronous EL1t + ventry irq_invalid_el1t // IRQ EL1t + ventry fiq_invalid_el1t // FIQ EL1t + ventry error_invalid_el1t // Error EL1t + + ventry sync_invalid_el1h // Synchronous EL1h + ventry el1_irq // IRQ EL1h + ventry fiq_invalid_el1h // FIQ EL1h + ventry error_invalid_el1h // Error EL1h + + ventry el0_sync // Synchronous 64-bit EL0 + ventry el0_irq // IRQ 64-bit EL0 + ventry fiq_invalid_el0_64 // FIQ 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 + + 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 + +sync_invalid_el1t: + handle_invalid_entry 1, SYNC_INVALID_EL1t + +irq_invalid_el1t: + handle_invalid_entry 1, IRQ_INVALID_EL1t + +fiq_invalid_el1t: + handle_invalid_entry 1, FIQ_INVALID_EL1t + +error_invalid_el1t: + handle_invalid_entry 1, ERROR_INVALID_EL1t + +sync_invalid_el1h: + handle_invalid_entry 1, SYNC_INVALID_EL1h + +el1_irq: + kernel_entry 1 + bl handle_irq + kernel_exit 1 + +fiq_invalid_el1h: + handle_invalid_entry 1, FIQ_INVALID_EL1h + +error_invalid_el1h: + handle_invalid_entry 1, ERROR_INVALID_EL1h + +el0_sync: + kernel_entry 0 + mrs x25, esr_el1 + lsr x24, x25, #ESR_ELx_EC_SHIFT + cmp x24, #ESR_ELx_EC_SVC64 + b.eq el0_svc + handle_invalid_entry 0, SYNC_ERROR + +el0_irq: + kernel_entry 0 + bl handle_irq + kernel_exit 0 + +fiq_invalid_el0_64: + handle_invalid_entry 0, FIQ_INVALID_EL0_64 + +error_invalid_el0_64: + handle_invalid_entry 0, ERROR_INVALID_EL0_64 + +sync_invalid_el0_32: + handle_invalid_entry 0, SYNC_INVALID_EL0_32 + +irq_invalid_el0_32: + handle_invalid_entry 0, IRQ_INVALID_EL0_32 + +fiq_invalid_el0_32: + handle_invalid_entry 0, FIQ_INVALID_EL0_32 + +error_invalid_el0_32: + handle_invalid_entry 0, ERROR_INVALID_EL0_32 + +sc_nr .req x25 +scno .req x26 +stbl .req x27 + +el0_svc: + adr stbl, sys_call_table + uxtw scno, w8 + mov sc_nr, #__NR_SYSCALLS + bl enable_interrupt + cmp scno, sc_nr + b.hs ni_sys + + ldr x16, [stbl, scno, lsl #3] + blr x16 + b ret_from_syscall +ni_sys: + handle_invalid_entry 0, SYSCALL_ERROR +ret_from_syscall: + bl disable_interrupt + str x0, [sp, #S_X0] + kernel_exit 0 + +.globl ret_from_fork +ret_from_fork: + bl schedule_tail + cbz x19, ret_to_user + mov x0, x20 + blr x19 // in theory should not return + //b err_hang // hang fail-safe +ret_to_user: + bl disable_interrupt + kernel_exit 0 + +.globl err_hang +err_hang: b err_hang diff --git a/lab6/lib/exception.c b/lab6/lib/exception.c new file mode 100644 index 000000000..a820ba662 --- /dev/null +++ b/lab6/lib/exception.c @@ -0,0 +1,49 @@ +#include "exception.h" +#include "mini_uart.h" +#include "mailbox.h" +#include "utils.h" +#include "timer.h" +#include "peripherals/exception.h" +#include "peripherals/mini_uart.h" + +void enable_interrupt() {asm volatile("msr DAIFClr, 0xf");} +void disable_interrupt() {asm volatile("msr DAIFSet, 0xf");} + +const char *entry_error_messages[] = { + "SYNC_INVALID_EL1t", + "IRQ_INVALID_EL1t", + "FIQ_INVALID_EL1t", + "ERROR_INVALID_EL1t", + + "SYNC_INVALID_EL1h", + "IRQ_INVALID_EL1h", + "FIQ_INVALID_EL1h", + "ERROR_INVALID_EL1h", + + "SYNC_INVALID_EL0_64", + "IRQ_INVALID_EL0_64", + "FIQ_INVALID_EL0_64", + "ERROR_INVALID_EL0_64", + + "SYNC_INVALID_EL0_32", + "IRQ_INVALID_EL0_32", + "FIQ_INVALID_EL0_32", + "ERROR_INVALID_EL0_32", + + "SYNC_ERROR", + "SYSCALL_ERROR" +}; + +void show_invalid_entry_message(int type, unsigned long esr, unsigned long addr) { + printf("%s, ESR: 0x%x, address: 0x%x\n", entry_error_messages[type], esr, addr); +} + +void handle_irq() { + + if (get32(CORE0_INTERRUPT_SRC)&INTERRUPT_SOURCE_CNTPNSIRQ) { + handle_timer_irq(); + } else { + printf("unknown irq encountered"); + } + +} \ No newline at end of file diff --git a/lab6/lib/fork.c b/lab6/lib/fork.c new file mode 100644 index 000000000..acdf566d6 --- /dev/null +++ b/lab6/lib/fork.c @@ -0,0 +1,176 @@ +#include "fork.h" +#include "mm.h" +#include "mini_uart.h" +#include "../include/sched.h" +#include "../include/entry.h" +#include "mmu.h" + +int copy_process(unsigned long clone_flags, unsigned long fn, unsigned long arg/*, unsigned long stack*/) { + + preempt_disable(); + struct task_struct *p; + + p = (struct task_struct *) allocate_kernel_page(); + if (p == NULL) + return -1; + + memzero((unsigned long)p, sizeof(struct task_struct)); + struct pt_regs *childregs = task_pt_regs(p); + + if (clone_flags & PF_KTHREAD) { + p->cpu_context.x19 = fn; + p->cpu_context.x20 = arg; + } else { + struct pt_regs *cur_regs = task_pt_regs(current); + // *childregs = *cur_regs; (object file generates memcpy) + // therefore the for loop is used below + for(int i=0; iregs[0] = 0; // return value 0 + copy_virt_memory(p); + } + + p->flags = clone_flags; + p->priority = current->priority; + p->state = TASK_RUNNING; + p->counter = p->priority; + p->preempt_count = 1; + + p->cpu_context.pc = (unsigned long)ret_from_fork; + p->cpu_context.sp = (unsigned long)childregs; + + int pid = nr_tasks++; + task[pid] = p; + p->id = pid; + preempt_enable(); + + return pid; + +} + +int move_to_user_mode(unsigned long start, unsigned long size, unsigned long pc) { + + struct pt_regs *regs = task_pt_regs(current); + regs->pc = pc; // virt pc + regs->pstate = PSR_MODE_EL0t; + regs->sp = 0xfffffffff000; + + unsigned long pages = (unsigned long)malloc(size); // phys + if (pages == NULL) + return -1; + + unsigned long va; // might need to map more? bss? currently mapping just enough + for(va=0; vasp; va+=PAGE_SIZE) { + map_page(current, va, stack_bot+(i*PAGE_SIZE)); + i++; + } + + // vc identity mapping + //printf("user page count %d\n", current->mm.user_pages_count); + for(unsigned long va=0x3c000000; va<0x3f000000; va+=PAGE_SIZE) { + unsigned long pgd; + if (!current->mm.pgd) { + pgd = (unsigned long)malloc(PAGE_SIZE); + //printf("pgd not found, created at phys address 0x%x\n", pgd); + memzero(pgd+VA_START, PAGE_SIZE); + current->mm.pgd = pgd; + current->mm.kernel_pages[++current->mm.kernel_pages_count] = current->mm.pgd; + } + pgd = current->mm.pgd; + //printf("pgd at 0x%x\n", pgd); + int new_table; + unsigned long pud = map_table((unsigned long *)(pgd + VA_START), PGD_SHIFT, va, &new_table); + //printf("pud at 0x%x\n", pud); + if (new_table) { + current->mm.kernel_pages[++current->mm.kernel_pages_count] = pud; + } + unsigned long pmd = map_table((unsigned long *)(pud + VA_START), PUD_SHIFT, va, &new_table); + //printf("pmd at 0x%x\n", pmd); + if (new_table) { + current->mm.kernel_pages[++current->mm.kernel_pages_count] = pmd; + } + unsigned long pte = map_table((unsigned long *)(pmd + VA_START), PMD_SHIFT, va, &new_table); + //printf("pte at 0x%x\n", pte); + if (new_table) { + current->mm.kernel_pages[++current->mm.kernel_pages_count] = pte; + } + map_table_entry((unsigned long *)(pte + VA_START), va, va); + //struct user_page p = {page, va}; + //task->mm.user_pages[task->mm.user_pages_count++] = p; + //if (va == 0x3c25e000) printf("0x%x, 0x%x, 0x%x, 0x%x\n", pgd, pud, pmd, pte); + } + //printf("user page count %d\n", current->mm.user_pages_count); + //memcpy(pages+VA_START, start, size); // move code to pages + for(int i=0; imm.pgd); + return 0; + +} + +struct pt_regs *task_pt_regs(struct task_struct *tsk) { + + unsigned long p = (unsigned long)tsk + THREAD_SIZE - sizeof(struct pt_regs); + return (struct pt_regs *)p; + +} + +void new_user_process(unsigned long func){ + printf("Kernel process started, moving to user mode.\n"); + int err = move_to_user_mode(func, 4096, func); + if (err < 0){ + printf("Error while moving process to user mode\n\r"); + } +} + +int copy_virt_memory(struct task_struct *dst) { + struct task_struct* src = current; + for (int i=0; imm.user_pages_count; i++) { + unsigned long kernel_va = allocate_user_page(dst, src->mm.user_pages[i].virt_addr); + if(kernel_va == 0) return -1; + memcpy(kernel_va, src->mm.user_pages[i].virt_addr, PAGE_SIZE); + } + for(unsigned long va=0x3c000000; va<0x3f000000; va+=PAGE_SIZE) { + unsigned long pgd; + if (!dst->mm.pgd) { + pgd = (unsigned long)malloc(PAGE_SIZE); + //printf("pgd not found, created at phys address 0x%x\n", pgd); + memzero(pgd+VA_START, PAGE_SIZE); + dst->mm.pgd = pgd; + dst->mm.kernel_pages[++dst->mm.kernel_pages_count] = dst->mm.pgd; + } + pgd = dst->mm.pgd; + //printf("pgd at 0x%x\n", pgd); + int new_table; + unsigned long pud = map_table((unsigned long *)(pgd + VA_START), PGD_SHIFT, va, &new_table); + //printf("pud at 0x%x\n", pud); + if (new_table) { + dst->mm.kernel_pages[++dst->mm.kernel_pages_count] = pud; + } + unsigned long pmd = map_table((unsigned long *)(pud + VA_START), PUD_SHIFT, va, &new_table); + //printf("pmd at 0x%x\n", pmd); + if (new_table) { + dst->mm.kernel_pages[++dst->mm.kernel_pages_count] = pmd; + } + unsigned long pte = map_table((unsigned long *)(pmd + VA_START), PMD_SHIFT, va, &new_table); + //printf("pte at 0x%x\n", pte); + if (new_table) { + dst->mm.kernel_pages[++dst->mm.kernel_pages_count] = pte; + } + map_table_entry((unsigned long *)(pte + VA_START), va, va); + //struct user_page p = {page, va}; + //task->mm.user_pages[task->mm.user_pages_count++] = p; + if (va == 0x3c25e000) printf("0x%x, 0x%x, 0x%x, 0x%x\n", pgd, pud, pmd, pte); + } + return 0; +} \ No newline at end of file diff --git a/lab6/lib/mailbox.c b/lab6/lib/mailbox.c new file mode 100644 index 000000000..e593af037 --- /dev/null +++ b/lab6/lib/mailbox.c @@ -0,0 +1,49 @@ +#include "peripherals/mailbox.h" +#include "mailbox.h" +#include "mini_uart.h" + +int mailbox_call (volatile unsigned int *mailbox) { + unsigned int msg = ((unsigned long)mailbox & ~0xF) | (0x8 & 0xF); + while (*MAILBOX_STATUS & MAILBOX_FULL) ; + *MAILBOX_WRITE = msg; + while (1) { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) {} + if (msg == *MAILBOX_READ) { + return mailbox[1]; + } + } +} + +void get_board_revision () +{ + volatile unsigned int __attribute__((aligned(16))) mailbox[7]; + mailbox[0] = 7 * 4; + mailbox[1] = REQUEST_CODE; + mailbox[2] = GET_BOARD_REVISION; + mailbox[3] = 4; + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; + mailbox[6] = END_TAG; + + if (mailbox_call(mailbox) == REQUEST_SUCCEED) { + printf("Board Revision:\t\t%x\n", mailbox[5]); + } +} + +void get_arm_memory () +{ + volatile unsigned int __attribute__((aligned(16))) mailbox[8]; + mailbox[0] = 8 * 4; + mailbox[1] = REQUEST_CODE; + mailbox[2] = GET_ARM_MEMORY; + mailbox[3] = 8; + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; + mailbox[6] = 0; + mailbox[7] = END_TAG; + + if (mailbox_call(mailbox) == REQUEST_SUCCEED) { + printf("Memory Base Addresss:\t%x\n", mailbox[5]); + printf("Memory Size:\t\t%x\n", mailbox[6]); + } +} \ No newline at end of file diff --git a/lab6/lib/math.c b/lab6/lib/math.c new file mode 100644 index 000000000..6b6919044 --- /dev/null +++ b/lab6/lib/math.c @@ -0,0 +1,19 @@ +#include "math.h" + +int log(int n, int base) { + int x = 1; + int ret = 0; + while (x <= n) { + x *= base; + ret++; + } + return ret; +} + +int pow(int base, int pow) { + int ret = 1; + for (int i=0; i avail) { + uart_send_string("not enough memory\n"); + } else { + __heap_ptr += size; + avail -= size; + } + + return ptr; + +} \ No newline at end of file diff --git a/lab6/lib/mini_uart.c b/lab6/lib/mini_uart.c new file mode 100644 index 000000000..c209f3a90 --- /dev/null +++ b/lab6/lib/mini_uart.c @@ -0,0 +1,69 @@ +#include "utils.h" +#include "printf.h" +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" +#include "peripherals/exception.h" + +void uart_send ( char c ) +{ + if (c == '\n') uart_send('\r'); + + while (1) { + if (get32(AUX_MU_LSR_REG)&0x20) + break; + } + + put32(AUX_MU_IO_REG,c); +} + +char uart_recv ( void ) +{ + while(1) { + if (get32(AUX_MU_LSR_REG)&0x01) + break; + } + return (get32(AUX_MU_IO_REG)&0xFF); +} + +void uart_send_string ( char* str ) +{ + for (int i = 0; str[i] != '\0'; i++) { + uart_send((char)str[i]); + } +} + +void printf(char *fmt, ...) { + char temp[128]; + __builtin_va_list args; + __builtin_va_start(args, fmt); + vsprintf(temp,fmt,args); + uart_send_string(temp); +} + +void uart_init ( void ) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7<<12); // clean gpio14 + selector |= 2<<12; // set alt5 for gpio14 + selector &= ~(7<<15); // clean gpio15 + selector |= 2<<15; // set alt5 for gpio 15 + put32(GPFSEL1,selector); + + put32(GPPUD,0); + delay(150); + put32(GPPUDCLK0,(1<<14)|(1<<15)); + delay(150); + put32(GPPUDCLK0,0); + + put32(AUX_ENABLES,1); //Enable mini uart (this also enables access to its registers) + put32(AUX_MU_CNTL_REG,0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(AUX_MU_IER_REG,0); //Enable receive and disable transmit interrupts + put32(AUX_MU_LCR_REG,3); //Enable 8 bit mode + put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high + put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200 + put32(AUX_MU_IIR_REG,6); //Interrupt identify no fifo + put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver + +} diff --git a/lab6/lib/mm.S b/lab6/lib/mm.S new file mode 100644 index 000000000..56eef8286 --- /dev/null +++ b/lab6/lib/mm.S @@ -0,0 +1,14 @@ +.globl memcpy +memcpy: + ldr x3, [x1], #8 + str x3, [x0], #8 + subs x2, x2, #8 + b.gt memcpy + ret + +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret \ No newline at end of file diff --git a/lab6/lib/mm.c b/lab6/lib/mm.c new file mode 100644 index 000000000..7c0ef41e6 --- /dev/null +++ b/lab6/lib/mm.c @@ -0,0 +1,394 @@ +#include "mm.h" +#include "mmu.h" +#include "math.h" +#include "memory.h" +#include "mini_uart.h" + +static unsigned int n_frames = 0; +static unsigned int max_size = 0; +static struct frame* frame_list[MAX_ORDER] = {NULL}; +static struct frame frame_array[(MEM_REGION_END-MEM_REGION_BEGIN)/PAGE_SIZE]; +static struct dynamic_pool pools[MAX_POOLS] = { {ALLOCABLE, 0, 0, 0, 0, {NULL}, NULL} }; +static unsigned int reserved_num = 0; +static void* reserved_se[MAX_RESERVABLE][2] = {{0x0, 0x0}}; // expects to be sorted and addresses [,) +extern char __kernel_end; +static char *__kernel_end_ptr = &__kernel_end; + +unsigned long allocate_user_page(struct task_struct *task, unsigned long va) { + unsigned long page = (unsigned long)malloc(PAGE_SIZE); + if (page == 0) + return NULL; + map_page(task, va, page); + return page + VA_START; +} + +unsigned long allocate_kernel_page() { + unsigned long page = (unsigned long)malloc(PAGE_SIZE); + if(page == NULL) + return NULL; + return page + VA_START; +} + +void *malloc(unsigned int size) { + + if (size > max_size) { + printf("[error] Request exceeded allocable continuous size %d.\n", (int)max_size); + return NULL; + } + + int req_order = 0; + for(unsigned int i=PAGE_SIZE; i= MAX_ORDER) { + printf("[error] No memory allocable.\n"); + return NULL; + } + + while (t != req_order) { + struct frame* l_tmp = frame_list[t]; + frame_list[t] = l_tmp->next; + if (frame_list[t] != NULL) + frame_list[t]->prev = NULL; + //printf("[info] Split at order %d, new head is 0x%x.\n", t+1, frame_list[t]); + + unsigned int off = pow(2, l_tmp->val-1); + struct frame* r_tmp = &frame_array[l_tmp->index+off]; + + l_tmp->val -= 1; + l_tmp->state = ALLOCABLE; + l_tmp->prev = NULL; + l_tmp->next = r_tmp; + + r_tmp->val = l_tmp->val; + r_tmp->state = ALLOCABLE; + r_tmp->prev = l_tmp; + r_tmp->next = NULL; + + t--; + if (frame_list[t] != NULL) + frame_list[t]->prev = r_tmp; + r_tmp->next = frame_list[t]; + frame_list[t] = l_tmp; + } + + struct frame* ret = frame_list[req_order]; + frame_list[req_order] = ret->next; + if (frame_list[req_order] != NULL) + frame_list[req_order]->prev = NULL; + + ret->val = ret->val; + ret->state = ALLOCATED; + ret->prev = NULL; + ret->next = NULL; + + //printf("[info] allocated address: 0x%x\n", MEM_REGION_BEGIN+PAGE_SIZE*ret->index); + + return (void*)MEM_REGION_BEGIN+PAGE_SIZE*ret->index; + +} + +void free(void *address) { + + unsigned int idx = ((unsigned long long)address-MEM_REGION_BEGIN) / PAGE_SIZE; + struct frame* target = &frame_array[idx]; + + if (target->state == ALLOCABLE || target->state == C_NALLOCABLE) { + printf("[error] invalid free of already freed memory.\n"); + return; + } + //printf("=========================================================\n"); + //printf("[info] Now freeing address 0x%x with frame index %d.\n", address, (int)idx); + + for (int i=target->val; ival+1, fr_buddy->state); + + if (i < MAX_ORDER-1 && fr_buddy->state == ALLOCABLE && i== fr_buddy->val) { + + //printf("[info] Merging from order %d. Frame indices %d, %d.\n", i+1, (int)buddy, (int)idx); + + if (fr_buddy->prev != NULL) { + fr_buddy->prev->next = fr_buddy->next; + } else { + frame_list[fr_buddy->val] = fr_buddy->next; + } + + if (fr_buddy->next != NULL) { + fr_buddy->next->prev = fr_buddy->prev; + } + + fr_buddy->prev = NULL; + fr_buddy->next = NULL; + fr_buddy->val = C_NALLOCABLE; + fr_buddy->state = C_NALLOCABLE; + target->val = C_NALLOCABLE; + target->state = C_NALLOCABLE; + + if (fr_buddy->index < target->index) { + idx = fr_buddy->index; + target = fr_buddy; + } + + //printf("[info] Frame index of next merge target is %d.\n", (int)idx); + + } else { + + target->val = i; + target->state = ALLOCABLE; + target->prev = NULL; + target->next = frame_list[i]; + if (frame_list[i] != NULL) + frame_list[i]->prev = target; + frame_list[i] = target; + //printf("[info] Frame index %d pushed to frame list of order %d.\n", + // (int)target->index, (int)i+1); + break; + + } + + } + + //printf("[info] Free finished.\n"); + /*for (int i=0; i < MAX_ORDER; i++) { + if (frame_list[i] != NULL) + printf("[info] Head of order %d has frame array index %d.\n",i+1,frame_list[i]->index); + else + printf("[info] Head of order %d has frame array index null.\n",i+1); + }*/ + +} + +void init_mm() { + + n_frames = (MEM_REGION_END-MEM_REGION_BEGIN) / PAGE_SIZE; + unsigned int mul = (unsigned int)pow(2, MAX_ORDER-1); + printf("[info] Frame array start address 0x%x.\n", frame_array); + for (unsigned int i=0; ichunk_size = size; + pool->chunks_per_page = PAGE_SIZE / size; + pool->chunks_allocated = 0; + pool->page_new_chunk_off = 0; + pool->pages_used = 0; + pool->free_head = NULL; +} + +int register_chunk(unsigned int size) { + + unsigned int nsize = 0; + if (size <= 8) nsize = 8; + else { + int rem = size % 4; + if (rem != 0) nsize = (size/4 + 1)*4; + else nsize = size; + } + + if (nsize >= PAGE_SIZE) { + printf("[error] Normalized chunk size request leq page size.\n"); + return -1; + } + + for (int i=0; ifree_head != NULL) { + void *ret = (void*) pool->free_head; + pool->free_head = pool->free_head->next; + //printf("[info] allocate address 0x%x from pool free list.\n", ret); + return ret; + } + + if (pool->chunks_allocated >= MAX_POOL_PAGES*pool->chunks_per_page) { + //printf("[error] Pool maximum reached.\n"); + return NULL; + } + + + if (pool->chunks_allocated >= pool->pages_used*pool->chunks_per_page) { + pool->page_base_addrs[pool->pages_used] = malloc(PAGE_SIZE); + //printf("[info] allocate new page for pool with base address 0x%x.\n", + // pool->page_base_addrs[pool->pages_used]); + pool->pages_used++; + pool->page_new_chunk_off = 0; + } + + void *ret = pool->page_base_addrs[pool->pages_used - 1] + + pool->chunk_size*pool->page_new_chunk_off; + pool->page_new_chunk_off++; + pool->chunks_allocated++; + + //printf("[info] allocate new address 0x%x from pool.\n", ret); + + return ret; + +} + +void chunk_free(void *address) { + + int target = -1; + + void *prefix_addr = (void *)((unsigned long long)address & ~0xFFF); + + for (unsigned int i=0; ifree_head; + pool->free_head = (struct node*) address; + pool->free_head->next = old_head; + pool->chunks_allocated--; + +} + +void memory_reserve(void* start, void* end) { + if (reserved_num >= MAX_RESERVABLE) { + printf("[error] Max reservable locations already reached.\n"); + return; + } + reserved_se[reserved_num][0] = start; + reserved_se[reserved_num][1] = end; + reserved_num++; +} + +void init_mm_reserve() { + + max_size = PAGE_SIZE * pow(2, MAX_ORDER-1); + n_frames = (MEM_REGION_END-MEM_REGION_BEGIN) / PAGE_SIZE; + + memory_reserve((void*)0x0, (void*)((unsigned long long)__kernel_end_ptr&VA_MASK)); // spin tables, kernel image + memory_reserve((void*)0x20000000, (void*)0x20010000); // hard code reserve initramfs + + for (unsigned int i=0; i= reserved_se[i][0] && addr < reserved_se[i][1]) { + frame_array[j].state = RESERVED; + } + if (addr >= reserved_se[i][1]) break; + } + } + + for (int i=0; istate == RESERVED) continue; + if (target->state == C_NALLOCABLE) continue; + + for (int i=target->val; istate == ALLOCABLE && i== fr_buddy->val) { + + if (fr_buddy->prev != NULL) { + fr_buddy->prev->next = fr_buddy->next; + } else { + frame_list[fr_buddy->val] = fr_buddy->next; + } + + if (fr_buddy->next != NULL) { + fr_buddy->next->prev = fr_buddy->prev; + } + + fr_buddy->prev = NULL; + fr_buddy->next = NULL; + fr_buddy->val = C_NALLOCABLE; + fr_buddy->state = C_NALLOCABLE; + target->val = C_NALLOCABLE; + target->state = C_NALLOCABLE; + + if (fr_buddy->index < target->index) { + idx = fr_buddy->index; + target = fr_buddy; + } + + } else { + + target->val = i; + target->state = ALLOCABLE; + target->prev = NULL; + target->next = frame_list[i]; + if (frame_list[i] != NULL) + frame_list[i]->prev = target; + frame_list[i] = target; + break; + + } + + } + + } + +} \ No newline at end of file diff --git a/lab6/lib/mmu.c b/lab6/lib/mmu.c new file mode 100644 index 000000000..ac1978b14 --- /dev/null +++ b/lab6/lib/mmu.c @@ -0,0 +1,74 @@ +#include "mmu.h" +#include "mm.h" +#include "mini_uart.h" + +void map_page(struct task_struct *task, unsigned long va, unsigned long page) { + //printf("===================\n"); + //printf("map virtual address 0x%x to phys address 0x%x\n", va, page); + unsigned long pgd; + if (!task->mm.pgd) { + pgd = (unsigned long)malloc(PAGE_SIZE); + //printf("pgd not found, created at phys address 0x%x\n", pgd); + memzero(pgd+VA_START, PAGE_SIZE); + task->mm.pgd = pgd; + task->mm.kernel_pages[++task->mm.kernel_pages_count] = task->mm.pgd; + } + pgd = task->mm.pgd; + //printf("pgd at 0x%x\n", pgd); + int new_table; + unsigned long pud = map_table((unsigned long *)(pgd + VA_START), PGD_SHIFT, va, &new_table); + //printf("pud at 0x%x\n", pud); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pud; + } + unsigned long pmd = map_table((unsigned long *)(pud + VA_START), PUD_SHIFT, va, &new_table); + //printf("pmd at 0x%x\n", pmd); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pmd; + } + unsigned long pte = map_table((unsigned long *)(pmd + VA_START), PMD_SHIFT, va, &new_table); + //printf("pte at 0x%x\n", pte); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pte; + } + map_table_entry((unsigned long *)(pte + VA_START), va, page); + struct user_page p = {page, va}; + task->mm.user_pages[task->mm.user_pages_count++] = p; + //printf("user pages count %d\n", task->mm.user_pages_count-1); +} + +unsigned long map_table(unsigned long *table, unsigned long shift, unsigned long va, int* new_table) { + unsigned long index = va >> shift; + index = index & (512 - 1); + if (!table[index]) { + *new_table = 1; + unsigned long next_level_table = (unsigned long)malloc(PAGE_SIZE); + memzero(next_level_table+VA_START, PAGE_SIZE); + unsigned long entry = next_level_table | PD_TABLE; + table[index] = entry; + return next_level_table; + } else { + *new_table = 0; + } + return table[index] & PAGE_MASK; +} + +void map_table_entry(unsigned long *pte, unsigned long va, unsigned long pa) { + unsigned long index = va >> 12; + index = index & (512 - 1); + unsigned long entry = pa | PTE_USR_RW_PTE; + pte[index] = entry; + //printf("0x%x[%d] contains 0x%x\n", pte, index, entry); +} + +unsigned long va2phys(unsigned long va) { + printf("translate va: 0x%x\n", va); + unsigned long pgd; + asm volatile("mrs %0, ttbr0_el1\n\t": "=r" (pgd) :: "memory"); + unsigned long pud = ((unsigned long*)(pgd+VA_START))[va>>PGD_SHIFT&(512-1)]&PAGE_MASK; + unsigned long pmd = ((unsigned long*)(pud+VA_START))[va>>PUD_SHIFT&(512-1)]&PAGE_MASK; + unsigned long pte = ((unsigned long*)(pmd+VA_START))[va>>PMD_SHIFT&(512-1)]&PAGE_MASK; + unsigned long phys = ((unsigned long*)(pte+VA_START))[va>>12&(512-1)]&PAGE_MASK; + printf("0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", pgd, pud, pmd, pte, phys); + return phys; +} diff --git a/lab6/lib/printf.c b/lab6/lib/printf.c new file mode 100644 index 000000000..794a37dff --- /dev/null +++ b/lab6/lib/printf.c @@ -0,0 +1,152 @@ +/* + * 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 + */ +#include "printf.h" + +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_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/lab6/lib/reboot.c b/lab6/lib/reboot.c new file mode 100644 index 000000000..043a09fb7 --- /dev/null +++ b/lab6/lib/reboot.c @@ -0,0 +1,18 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab6/lib/sched.S b/lab6/lib/sched.S new file mode 100644 index 000000000..7e4392f23 --- /dev/null +++ b/lab6/lib/sched.S @@ -0,0 +1,32 @@ +#include "sched.h" + +.global cpu_switch_to +cpu_switch_to: + mov x10, #THREAD_CPU_CONTEXT + add x8, x0, x10 + mov x9, sp + stp x19, x20, [x8], #16 // store callee-saved registers + stp x21, x22, [x8], #16 + stp x23, x24, [x8], #16 + stp x25, x26, [x8], #16 + stp x27, x28, [x8], #16 + stp x29, x9, [x8], #16 + str x30, [x8] + add x8, x1, x10 + ldp x19, x20, [x8], #16 // restore callee-saved registers + ldp x21, x22, [x8], #16 + ldp x23, x24, [x8], #16 + ldp x25, x26, [x8], #16 + ldp x27, x28, [x8], #16 + ldp x29, x9, [x8], #16 + ldr x30, [x8] + mov sp, x9 + ret + +.global update_pgd +update_pgd: + 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 \ No newline at end of file diff --git a/lab6/lib/sched.c b/lab6/lib/sched.c new file mode 100644 index 000000000..7f1b3e08a --- /dev/null +++ b/lab6/lib/sched.c @@ -0,0 +1,116 @@ +#include "../include/sched.h" +#include "mm.h" +#include "mmu.h" +#include "exception.h" +#include "mini_uart.h" + +static struct task_struct init_task = INIT_TASK; +struct task_struct *current = &(init_task); +struct task_struct *task[NR_TASKS] = {&(init_task), }; +int nr_tasks = 1; + +void preempt_disable() { + current->preempt_count++; +} + +void preempt_enable() { + current->preempt_count--; +} + +void _schedule() { + + int next, c; + struct task_struct *p; + while (1) { + c = -1; + next = 0; + for (int i=0; istate == TASK_RUNNING && p->counter > c) { + c = p->counter; + next = i; + } + } + if (c) { + break; + } + for (int i=0; icounter = (p->counter >> 1) + p->priority; + } + } + preempt_disable(); // should be fine, if anything breaks move this to the top + switch_to(task[next]); + preempt_enable(); + +} + +void schedule() { + current->counter = 0; + _schedule(); +} + +void switch_to(struct task_struct *next) { + if (current == next) + return; + struct task_struct *prev = current; + current = next; + update_pgd(next->mm.pgd); + cpu_switch_to(prev, next); +} + +void schedule_tail() { + preempt_enable(); +} + +void timer_tick() { + + --current->counter; + if (current->counter > 0 || current->preempt_count > 0) + return; + + current->counter = 0; + enable_interrupt(); + _schedule(); + disable_interrupt(); + +} + +void exit_process() { + // should only be accessed using syscall + // preempt_disable(); + current->state = TASK_ZOMBIE; + //free((void*)current->stack); // free resources + // preempt_enable(); + schedule(); +} + +void kill_zombies() { + + struct task_struct *p; + for (int i=0; istate == TASK_ZOMBIE) { + printf("Zombie found with pid: %d.\n", p->id); + // for loop free user pages and kernel pages + for (int i=0; imm.user_pages_count; i++) { + free((void*)(p->mm.user_pages[i].phys_addr+VA_START)); + } + for (int i=0; imm.kernel_pages_count; i++) { + free((void*)(p->mm.kernel_pages[i]+VA_START)); + } + free(p); // free task struct + task[i] = NULL; + } + + } + +} \ No newline at end of file diff --git a/lab6/lib/shell.c b/lab6/lib/shell.c new file mode 100644 index 000000000..5569fafb3 --- /dev/null +++ b/lab6/lib/shell.c @@ -0,0 +1,155 @@ +#include "shell.h" +#include "mini_uart.h" +#include "utils.h" +#include "mailbox.h" +#include "reboot.h" +#include "string.h" +#include "../include/cpio.h" +#include "memory.h" +#include "timer.h" +#include "exception.h" +#include "math.h" +#include "mm.h" +#include "../include/sched.h" +#include "syscall.h" +#include "peripherals/mailbox.h" +#include "fork.h" +#include "mmu.h" + + +#define MAX_BUFFER_SIZE 256u + +static char buffer[MAX_BUFFER_SIZE]; + +void start_video() { + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + void *code_loc; + + header = DEVTREE_CPIO_BASE; + printf("devtree base: 0x%x\n", DEVTREE_CPIO_BASE); + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) { + uart_send_string("file does not exist!\n"); + break; + } + + namesize = hexstr_to_uint(header->c_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, "vm.img", namesize) == 0) { + code_loc = ((void*)header) + offset; + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + printf("vm.img found in cpio at location 0x%x.\n", code_loc); + printf("vm.img has size of %d bytes.\n", (int)filesize); + + int err = move_to_user_mode((unsigned long)code_loc, filesize, 0); + if (err<0) + printf("failed to start video program\n"); + +} + +void read_cmd() +{ + unsigned int idx = 0; + char c = '\0'; + + while (1) { + c = uart_recv(); + if (c == '\r' || c == '\n') { + uart_send_string("\n"); + + if (idx < MAX_BUFFER_SIZE) buffer[idx] = '\0'; + else buffer[MAX_BUFFER_SIZE-1] = '\0'; + + break; + } else { + uart_send(c); + buffer[idx++] = c; + } + } + +} + +void parse_cmd() +{ + + if (stringcmp(buffer, "\0") == 0) + uart_send_string("\n"); + else if (stringcmp(buffer, "hello") == 0) + uart_send_string("Hello World!\n"); + else if (stringcmp(buffer, "reboot") == 0) { + uart_send_string("rebooting...\n"); + reset(100); + } + else if (stringcmp(buffer, "hwinfo") == 0) { + get_board_revision(); + get_arm_memory(); + } + else if (stringcmp(buffer, "ls") == 0) { + cpio_ls(); + } + else if (stringcmp(buffer, "cat") == 0) { + cpio_cat(); + } + else if (stringcmp(buffer, "execute") == 0) { + cpio_exec(); + } + else if (stringcmp(buffer, "video") == 0) { + preempt_disable(); + current->state = TASK_STOPPED; + unsigned long long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + copy_process(PF_KTHREAD, (unsigned long)&start_video, 0/*, 0*/); + preempt_enable(); + } + else if (stringcmp(buffer, "help") == 0) { + uart_send_string("help:\t\tprint list of available commands\n"); + uart_send_string("hello:\t\tprint Hello World!\n"); + uart_send_string("reboot:\t\treboot device\n"); + uart_send_string("hwinfo:\t\tprint hardware information\n"); + uart_send_string("ls:\t\tlist initramfs files\n"); + uart_send_string("cat:\t\tprint file content in initramfs\n"); + uart_send_string("execute:\trun program from cpio\n"); + } + else + uart_send_string("Command not found! Type help for commands.\n"); + +} + +void shell_loop() +{ + while (1) { + uart_send_string("% "); + read_cmd(); + parse_cmd(); + } +} \ No newline at end of file diff --git a/lab6/lib/string.c b/lab6/lib/string.c new file mode 100644 index 000000000..df9ea89ca --- /dev/null +++ b/lab6/lib/string.c @@ -0,0 +1,39 @@ +#include "string.h" + +int stringcmp(const char *p1, const char *p2) +{ + const unsigned char *s1 = (const unsigned char *) p1; + const unsigned char *s2 = (const unsigned char *) p2; + unsigned char c1, c2; + + do { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0') + return c1 - c2; + } while (c1 == c2); + + return c1 - c2; +} + +int stringncmp(const char *p1, const char *p2, unsigned int n) +{ + for (int i=0; iid; +} + +unsigned sys_uartread(char buf[], unsigned size) { + for(unsigned int i=0; ic_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, name, namesize) == 0) { + code_loc = ((void*)header) + offset; + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + + void *move_loc = malloc(filesize + 4096); // an extra page for bss just in case + if(move_loc == NULL) return -1; + for (int i=0; ipc = 0; // move to beginning of program + p->sp = 0xfffffffff000; + + preempt_enable(); + + return -1; // only on failure*/ + // not real exec, only a restart of current process +} // fix + +int sys_fork() { + return copy_process(0, 0, 0/*, 0*/); +} + +void sys_exit(int status) { + exit_process(); +} + +int sys_mbox_call(unsigned char ch, volatile unsigned int *mbox) { + printf("mbox: 0x%x\n", mbox); + unsigned long ka_mbox = va2phys((unsigned long)mbox) + ((unsigned long)mbox&0xFFF); + printf("mbox kernel addr location: 0x%x\n", ka_mbox); + unsigned int r = (((unsigned int)((unsigned long)ka_mbox)&~0xF) | (ch&0xF)); + while(*MAILBOX_STATUS & MAILBOX_FULL); + *MAILBOX_WRITE = r; + while (1) { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) {} + if (r == *MAILBOX_READ) { + return ((unsigned int *)(ka_mbox+VA_START))[1]==REQUEST_SUCCEED; + } + } + return 0; +} + +void sys_kill(int pid) { + + struct task_struct *p; + for (int i=0; iid == (long)pid) { + preempt_disable(); + printf("Kill target acquired.\n"); + p->state = TASK_ZOMBIE; + //free((void *)p->stack); + preempt_enable(); + break; + } + + } + +} + +void * const sys_call_table[] = +{ + sys_getpid, + sys_uartread, + sys_uartwrite, + sys_exec, + sys_fork, + sys_exit, + sys_mbox_call, + sys_kill +}; \ No newline at end of file diff --git a/lab6/lib/timer.c b/lab6/lib/timer.c new file mode 100644 index 000000000..ae102a2b0 --- /dev/null +++ b/lab6/lib/timer.c @@ -0,0 +1,62 @@ +#include "timer.h" +#include "../include/sched.h" +#include "mini_uart.h" + +void timer_init() { + core_timer_enable(); + set_timer(read_freq()); +} + +void handle_timer_irq() { + //printf("Timer interrupt.\n"); + set_timer(read_freq()>>5); + timer_tick(); +} + +void core_timer_enable() { + + asm volatile( + "mov x0, 1\n\t" + "msr cntp_ctl_el0, x0\n\t" // enable + "mov x0, 2\n\t" + "ldr x1, =0x40000040\n\t" // CORE0_TIMER_IRQ_CTRL + "str w0, [x1]\n\t" // unmask timer interrupt + ); + +} + +void core_timer_disable() { + + asm volatile( + "mov x0, 0\n\t" + "ldr x1, =0x40000040\n\t" + "str w0, [x1]\n\t" + ); + +} + +void set_timer(unsigned int rel_time) { + + asm volatile( + "msr cntp_tval_el0, %0\n\t" + : + : "r" (rel_time) + ); + +} + +unsigned int read_timer() { + + unsigned int time; + asm volatile("mrs %0, cntpct_el0\n\t" : "=r" (time) : : "memory"); + return time; + +} + +unsigned int read_freq() { + + unsigned int freq; + asm volatile("mrs %0, cntfrq_el0\n\t": "=r" (freq) : : "memory"); + return freq; + +} diff --git a/lab6/lib/utils.S b/lab6/lib/utils.S new file mode 100644 index 000000000..aa0e55aa9 --- /dev/null +++ b/lab6/lib/utils.S @@ -0,0 +1,15 @@ +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret \ No newline at end of file diff --git a/lab6/send_img.py b/lab6/send_img.py new file mode 100644 index 000000000..b2261950d --- /dev/null +++ b/lab6/send_img.py @@ -0,0 +1,31 @@ +import argparse +import os +import time +import math +import serial + +parser = argparse.ArgumentParser(description='*.img uart sender') +parser.add_argument('-i', '--img', default='kernel8.img', type=str) +parser.add_argument('-d', '--device', default='/dev/ttyUSB0', type=str) +parser.add_argument('-b', '--baud', default=115200, type=int) + +args = parser.parse_args() + +img_size = os.path.getsize(args.img) + +with open(args.img, 'rb') as f: + with serial.Serial(args.device, args.baud) as tty: + + print(f'{args.img} is {img_size} bytes') + print('img file is now sending') + + tty.write(img_size.to_bytes(4, 'big')) + + input() + + for i in range(img_size): + tty.write(f.read(1)) + tty.flush() + #time.sleep(0.0001) + + print('img sent') diff --git a/lab7/bcm2710-rpi-3-b-plus.dtb b/lab7/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..3934b3a26 Binary files /dev/null and b/lab7/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab7/config.txt b/lab7/config.txt new file mode 100644 index 000000000..49fc25695 --- /dev/null +++ b/lab7/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x20000000 diff --git a/lab7/include/cpio.h b/lab7/include/cpio.h new file mode 100644 index 000000000..1735f5fe5 --- /dev/null +++ b/lab7/include/cpio.h @@ -0,0 +1,49 @@ +#ifndef __CPIO_H__ +#define __CPIO_H__ + +/* +Each file system object in a cpio archive comprises a header record with +basic numeric metadata followed by the full pathname of the entry and the +file data. The header record stores a series of integer values that gen- +erally follow the fields in struct stat. (See stat(2) for details.) The +variants differ primarily in how they store those integers (binary, oc- +tal, or hexadecimal). The header is followed by the pathname of the en- +try (the length of the pathname is stored in the header) and any file +data. The end of the archive is indicated by a special record with the +pathname "TRAILER!!!" +*/ + +#define CPIO_HEADER_MAGIC "070701" +#define CPIO_FOOTER_MAGIC "TRAILER!!!" +#define PI_CPIO_BASE ((void*) (0x20000000)) +#define QEMU_CPIO_BASE ((void*) (0x8000000)) + +#include "devtree.h" + +extern void *DEVTREE_CPIO_BASE; + +struct cpio_newc_header { + char c_magic[6]; // 070701 + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; // ignored by readers +}; + +void initramfs_callback (char *, char *, struct fdt_prop *); +void cpio_ls (); +void cpio_cat (); +void cpio_exec (); + +unsigned int hexstr_to_uint(char *s, unsigned int len); + +#endif \ No newline at end of file diff --git a/lab7/include/devtree.h b/lab7/include/devtree.h new file mode 100644 index 000000000..1c3c27899 --- /dev/null +++ b/lab7/include/devtree.h @@ -0,0 +1,64 @@ +#ifndef _DEVTREE_H +#define _DEVTREE_H + +/* + magic; 0xd00dfeed (big-endian) + + totalsize; total size in bytes of the devicetree + data structure + + off_dt_struct; offset in bytes of the structure block + from the beginning of the header + + off_dt_strings; offset in bytes of the strings block + from the beginning of the header + + off_mem_rsvmap; offset in bytes of the memory reservation + block from the beginning of the header + + version; version of the devicetree data structure + + last_comp_version; lowest version of the devicetree data + structure with which the version used is backwards compatible + + boot_cpuid_phys; physical ID of the system’s boot CPU + + size_dt_strings; length in bytes of the strings block + section of the devicetree blob + + size_dt_struct; length in bytes of the structure block + section of the devicetree blob +*/ + +#define FDT_HEADER_MAGIC 0xd00dfeed +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +struct fdt_header { + unsigned int magic; + unsigned int totalsize; + unsigned int off_dt_struct; + unsigned int off_dt_strings; + unsigned int off_mem_rsvmap; + unsigned int version; + unsigned int last_comp_version; + unsigned int boot_cpuid_phys; + unsigned int size_dt_strings; + unsigned int size_dt_struct; +}; + +struct fdt_prop { + unsigned int len; + unsigned int nameoff; +}; + +void devtree_getaddr (); +void fdt_traverse ( void (*callback)(char *, char *, struct fdt_prop *) ); + +// ARM uses little endian +unsigned long to_lendian (unsigned long); + +#endif \ No newline at end of file diff --git a/lab7/include/entry.h b/lab7/include/entry.h new file mode 100644 index 000000000..1a22d0284 --- /dev/null +++ b/lab7/include/entry.h @@ -0,0 +1,39 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#define S_FRAME_SIZE 272 // size of all saved registers +#define S_X0 0 + +#define SYNC_INVALID_EL1t 0 +#define IRQ_INVALID_EL1t 1 +#define FIQ_INVALID_EL1t 2 +#define ERROR_INVALID_EL1t 3 + +#define SYNC_INVALID_EL1h 4 +#define IRQ_INVALID_EL1h 5 +#define FIQ_INVALID_EL1h 6 +#define ERROR_INVALID_EL1h 7 + +#define SYNC_INVALID_EL0_64 8 +#define IRQ_INVALID_EL0_64 9 +#define FIQ_INVALID_EL0_64 10 +#define ERROR_INVALID_EL0_64 11 + +#define SYNC_INVALID_EL0_32 12 +#define IRQ_INVALID_EL0_32 13 +#define FIQ_INVALID_EL0_32 14 +#define ERROR_INVALID_EL0_32 15 + +#define SYNC_ERROR 16 +#define SYSCALL_ERROR 17 + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 + +#ifndef __ASSEMBLER__ + +void ret_from_fork(); + +#endif + +#endif \ No newline at end of file diff --git a/lab7/include/exception.h b/lab7/include/exception.h new file mode 100644 index 000000000..40f4ba532 --- /dev/null +++ b/lab7/include/exception.h @@ -0,0 +1,7 @@ +#ifndef _EXCEPTION_H +#define _EXCEPTION_H + +void enable_interrupt(); +void disable_interrupt(); + +#endif \ No newline at end of file diff --git a/lab7/include/fork.h b/lab7/include/fork.h new file mode 100644 index 000000000..06bc62382 --- /dev/null +++ b/lab7/include/fork.h @@ -0,0 +1,27 @@ +#ifndef _FORK_H +#define _FORK_H + +#include "sched.h" + +#define PSR_MODE_EL0t 0x00000000 +#define PSR_MODE_EL1t 0x00000004 +#define PSR_MODE_EL1h 0x00000005 +#define PSR_MODE_EL2t 0x00000008 +#define PSR_MODE_EL2h 0x00000009 +#define PSR_MODE_EL3t 0x0000000c +#define PSR_MODE_EL3h 0x0000000d + +int copy_process(unsigned long, unsigned long, unsigned long/*, unsigned long*/); +int move_to_user_mode(unsigned long, unsigned long, unsigned long); +struct pt_regs *task_pt_regs(struct task_struct *); +void new_user_process(unsigned long); +int copy_virt_memory(struct task_struct *); + +struct pt_regs { + unsigned long regs[31]; + unsigned long sp; + unsigned long pc; + unsigned long pstate; +}; + +#endif \ No newline at end of file diff --git a/lab7/include/mailbox.h b/lab7/include/mailbox.h new file mode 100644 index 000000000..eeecaa9de --- /dev/null +++ b/lab7/include/mailbox.h @@ -0,0 +1,7 @@ +#ifndef _MAILBOX_H +#define _MAILBOX_H + +void get_board_revision (); +void get_arm_memory (); + +#endif \ No newline at end of file diff --git a/lab7/include/math.h b/lab7/include/math.h new file mode 100644 index 000000000..353ccfb26 --- /dev/null +++ b/lab7/include/math.h @@ -0,0 +1,7 @@ +#ifndef _MATH_H +#define _MATH_H + +int log(int, int); +int pow(int, int); + +#endif \ No newline at end of file diff --git a/lab7/include/memory.h b/lab7/include/memory.h new file mode 100644 index 000000000..956f6e955 --- /dev/null +++ b/lab7/include/memory.h @@ -0,0 +1,8 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#define MAX_HEAP_SIZE 0x10000000 + +void* simple_malloc(unsigned int); + +#endif \ No newline at end of file diff --git a/lab7/include/mini_uart.h b/lab7/include/mini_uart.h new file mode 100644 index 000000000..453ec93f2 --- /dev/null +++ b/lab7/include/mini_uart.h @@ -0,0 +1,10 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void uart_init ( void ); +char uart_recv ( void ); +void uart_send ( char c ); +void uart_send_string ( char* str ); +void printf ( char *fmt, ... ); + +#endif /*_MINI_UART_H */ \ No newline at end of file diff --git a/lab7/include/mm.h b/lab7/include/mm.h new file mode 100644 index 000000000..f74bfd242 --- /dev/null +++ b/lab7/include/mm.h @@ -0,0 +1,61 @@ +#ifndef _MM_H +#define _MM_H + +#define MEM_REGION_BEGIN 0x0 +#define MEM_REGION_END 0x3C000000 +#define PAGE_SIZE 4096 +#define MAX_ORDER 8 // largest: PAGE_SIZE*2^(MAX_ORDER) + +#define ALLOCABLE 0 +#define ALLOCATED -1 +#define C_NALLOCABLE -2 +#define RESERVED -3 + +#define NULL 0 + +#define MAX_POOL_PAGES 8 +#define MAX_POOLS 8 +#define MIN_CHUNK_SIZE 8 + +#define MAX_RESERVABLE 8 + +struct frame { + unsigned int index; + int val; + int state; + struct frame *prev, *next; +}; + +struct node { + struct node *next; +}; + +struct dynamic_pool { + unsigned int chunk_size; + unsigned int chunks_per_page; + unsigned int chunks_allocated; + unsigned int page_new_chunk_off; + unsigned int pages_used; + void *page_base_addrs[MAX_POOL_PAGES]; + struct node *free_head; +}; + +#include "sched.h" + +unsigned long allocate_user_page(struct task_struct *, unsigned long); +unsigned long allocate_kernel_page(); + +void *malloc(unsigned int); +void free(void *); +void init_mm(); +void init_pool(struct dynamic_pool*, unsigned int); +int register_chunk(unsigned int); +void *chunk_alloc(unsigned int); +void chunk_free(void *); +void memory_reserve(void*, void*); +void init_mm_reserve(); + +void memcpy(unsigned long dst, unsigned long src, unsigned long n); +void memzero(unsigned long, unsigned long); + +#endif /*_MM_H */ \ No newline at end of file diff --git a/lab7/include/mmu.h b/lab7/include/mmu.h new file mode 100644 index 000000000..4733595ef --- /dev/null +++ b/lab7/include/mmu.h @@ -0,0 +1,51 @@ +#ifndef _MMU_H +#define _MMU_H + +#define VA_START 0xffff000000000000 +#define VA_MASK 0x0000ffffffffffff + +#define PAGE_MASK 0xfffffffffffff000 + +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 +#define MAIR_NORMAL_NOCACHE 0b01000100 +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 +#define MAIR_VALUE \ +( \ + (MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | \ + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8)) \ +) + +#define PD_TABLE 0b11 +#define PD_BLOCK 0b01 +#define PT_ENTRY 0b11 +#define PD_ACCESS (1 << 10) +#define BOOT_PGD_ATTR PD_TABLE +#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) + +#define PTE_USR_RO_PTE (PD_ACCESS | (0b11<<6) | (MAIR_IDX_NORMAL_NOCACHE<<2) | PT_ENTRY) +#define PTE_USR_RW_PTE (PD_ACCESS | (0b01<<6) | (MAIR_IDX_NORMAL_NOCACHE<<2) | PT_ENTRY) + +#define SCTLR_MMU_DISABLED 0 +#define SCTLR_MMU_ENABLED 1 + +#define PGD_SHIFT (12 + 3*9) +#define PUD_SHIFT (12 + 2*9) +#define PMD_SHIFT (12 + 9) + +#ifndef __ASSEMBLER__ + +#include "sched.h" + +void map_page(struct task_struct *task, unsigned long va, unsigned long page); +unsigned long map_table(unsigned long *table, unsigned long shift, unsigned long va, int* new_table); +void map_table_entry(unsigned long *pte, unsigned long va, unsigned long pa); +unsigned long va2phys(unsigned long va); + +#endif + +#endif \ No newline at end of file diff --git a/lab7/include/peripherals/base.h b/lab7/include/peripherals/base.h new file mode 100644 index 000000000..aeb57bd92 --- /dev/null +++ b/lab7/include/peripherals/base.h @@ -0,0 +1,9 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +#include "mmu.h" + +#define DEVICE_BASE 0x3F000000 +#define PBASE (VA_START+DEVICE_BASE) + +#endif /*_P_BASE_H */ \ No newline at end of file diff --git a/lab7/include/peripherals/exception.h b/lab7/include/peripherals/exception.h new file mode 100644 index 000000000..713d05418 --- /dev/null +++ b/lab7/include/peripherals/exception.h @@ -0,0 +1,26 @@ +#ifndef _P_EXCEPTION_H +#define _P_EXCEPTION_H + +#include "peripherals/base.h" +#include "mmu.h" + +#define IRQ_BASIC_PENDING (PBASE+0x0000B200) +#define IRQ_PENDING_1 (PBASE+0x0000B204) +#define IRQ_PENDING_2 (PBASE+0x0000B208) +#define FIQ_CONTROL (PBASE+0x0000B20C) +#define ENABLE_IRQS_1 (PBASE+0x0000B210) +#define ENABLE_IRQS_2 (PBASE+0x0000B214) +#define ENABLE_BASIC_IRQS (PBASE+0x0000B218) +#define DISABLE_IRQS_1 (PBASE+0x0000B21C) +#define DISABLE_IRQS_2 (PBASE+0x0000B220) +#define DISABLE_BASIC_IRQS (PBASE+0x0000B224) + +#define CNTPCT_EL0 (VA_START + 0x4000001C) +#define CNTP_CTL_EL0 (VA_START + 0x40000040) +#define CORE0_INTERRUPT_SRC (VA_START + 0x40000060) + +#define IRQ_PENDING_1_AUX_INT (1<<29) +#define INTERRUPT_SOURCE_GPU (1<<8) +#define INTERRUPT_SOURCE_CNTPNSIRQ (1<<1) + +#endif \ No newline at end of file diff --git a/lab7/include/peripherals/gpio.h b/lab7/include/peripherals/gpio.h new file mode 100644 index 000000000..c5d7d138f --- /dev/null +++ b/lab7/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _P_GPIO_H +#define _P_GPIO_H + +#include "peripherals/base.h" + +#define GPFSEL1 (PBASE+0x00200004) +#define GPSET0 (PBASE+0x0020001C) +#define GPCLR0 (PBASE+0x00200028) +#define GPPUD (PBASE+0x00200094) +#define GPPUDCLK0 (PBASE+0x00200098) + +#endif /*_P_GPIO_H */ \ No newline at end of file diff --git a/lab7/include/peripherals/mailbox.h b/lab7/include/peripherals/mailbox.h new file mode 100644 index 000000000..62225bd47 --- /dev/null +++ b/lab7/include/peripherals/mailbox.h @@ -0,0 +1,25 @@ +#ifndef _P_MAILBOX_H +#define _P_MAILBOX_H + +#include "mmu.h" + +#define MMIO_BASE VA_START + 0x3f000000 +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#define MAILBOX_READ (volatile unsigned int*) (MAILBOX_BASE) +#define MAILBOX_STATUS (volatile unsigned int*) (MAILBOX_BASE + 0x18) +#define MAILBOX_WRITE (volatile unsigned int*) (MAILBOX_BASE + 0x20) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 + +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +#endif \ No newline at end of file diff --git a/lab7/include/peripherals/mini_uart.h b/lab7/include/peripherals/mini_uart.h new file mode 100644 index 000000000..386b6fade --- /dev/null +++ b/lab7/include/peripherals/mini_uart.h @@ -0,0 +1,19 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_ENABLES (PBASE+0x00215004) +#define AUX_MU_IO_REG (PBASE+0x00215040) +#define AUX_MU_IER_REG (PBASE+0x00215044) +#define AUX_MU_IIR_REG (PBASE+0x00215048) +#define AUX_MU_LCR_REG (PBASE+0x0021504C) +#define AUX_MU_MCR_REG (PBASE+0x00215050) +#define AUX_MU_LSR_REG (PBASE+0x00215054) +#define AUX_MU_MSR_REG (PBASE+0x00215058) +#define AUX_MU_SCRATCH (PBASE+0x0021505C) +#define AUX_MU_CNTL_REG (PBASE+0x00215060) +#define AUX_MU_STAT_REG (PBASE+0x00215064) +#define AUX_MU_BAUD_REG (PBASE+0x00215068) + +#endif /*_P_MINI_UART_H */ \ No newline at end of file diff --git a/lab7/include/printf.h b/lab7/include/printf.h new file mode 100644 index 000000000..dfedbe301 --- /dev/null +++ b/lab7/include/printf.h @@ -0,0 +1,31 @@ +/* + * 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. + * + */ +#ifndef _PRINTF_H +#define _PRINTF_H + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); + +#endif \ No newline at end of file diff --git a/lab7/include/reboot.h b/lab7/include/reboot.h new file mode 100644 index 000000000..df4d63a86 --- /dev/null +++ b/lab7/include/reboot.h @@ -0,0 +1,7 @@ +#ifndef _REBOOT_H +#define _REBOOT_H + +void reset ( int ); +void cancel_reset (); + +#endif \ No newline at end of file diff --git a/lab7/include/sched.h b/lab7/include/sched.h new file mode 100644 index 000000000..64f456387 --- /dev/null +++ b/lab7/include/sched.h @@ -0,0 +1,96 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#define THREAD_CPU_CONTEXT 0 + +#ifndef __ASSEMBLER__ + +#include "vfs.h" + +#define THREAD_SIZE 4096 + +#define NR_TASKS 64 + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 + +#define PF_KTHREAD 0x00000002 + +extern struct task_struct *current; +extern struct task_struct *task[NR_TASKS]; +extern int nr_tasks; + +struct cpu_context { + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long sp; + unsigned long pc; +}; + +#define MAX_PROCESS_PAGES 128 + +struct user_page { + unsigned long phys_addr; + unsigned long virt_addr; +}; + +struct mm_struct { + unsigned long pgd; + int user_pages_count; + struct user_page user_pages[MAX_PROCESS_PAGES]; + int kernel_pages_count; + unsigned long kernel_pages[MAX_PROCESS_PAGES]; +}; + +struct task_struct { + struct cpu_context cpu_context; + long state; + long counter; + long priority; + long preempt_count; + //unsigned long stack; //remove + unsigned long flags; + long id; + struct mm_struct mm; + struct fd_table files; + struct vnode *cwd; +}; + +extern void sched_init(); +extern void schedule(); +extern void timer_tick(); +extern void preempt_disable(); +extern void preempt_enable(); +extern void switch_to(struct task_struct *); +extern void cpu_switch_to(struct task_struct *, struct task_struct *); +extern void exit_process(); +extern void kill_zombies(); +extern void update_pgd(unsigned long); + +#define INIT_TASK \ +{ \ +{0,0,0,0,0,0,0,0,0,0,0,0,0},\ +0, 0, 1, 0, PF_KTHREAD, 0, \ +{0,0,{{0}},0,{0}},\ +{0, {0}},\ +0 \ +} + +#endif + +#endif \ No newline at end of file diff --git a/lab7/include/shell.h b/lab7/include/shell.h new file mode 100644 index 000000000..828c56763 --- /dev/null +++ b/lab7/include/shell.h @@ -0,0 +1,6 @@ +#ifndef _SHELL_H +#define _SHELL_H + +void shell_loop (); + +#endif \ No newline at end of file diff --git a/lab7/include/string.h b/lab7/include/string.h new file mode 100644 index 000000000..c71840033 --- /dev/null +++ b/lab7/include/string.h @@ -0,0 +1,10 @@ +#ifndef _STRING_H +#define _STRING_H + +int stringcmp (const char *, const char *); +int stringncmp (const char *, const char *, unsigned int); +unsigned int strlen(const char *); +void strcpy(char *dest, const char *src); +void strncpy(char *dest, const char *src, int n); + +#endif \ No newline at end of file diff --git a/lab7/include/syscall.h b/lab7/include/syscall.h new file mode 100644 index 000000000..d81250876 --- /dev/null +++ b/lab7/include/syscall.h @@ -0,0 +1,59 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +#define __NR_SYSCALLS 18 + +#define SYS_GETPID_NUM 0 +#define SYS_UARTREAD_NUM 1 +#define SYS_UARTWRITE_NUM 2 +#define SYS_EXEC_NUM 3 +#define SYS_FORK_NUM 4 +#define SYS_EXIT_NUM 5 +#define SYS_MBOXCALL_NUM 6 +#define SYS_KILL_NUM 7 + +#define SYS_OPEN_NUM 11 +#define SYS_CLOSE_NUM 12 +#define SYS_WRITE_NUM 13 +#define SYS_READ_NUM 14 +#define SYS_MKDIR_NUM 15 +#define SYS_MOUNT_NUM 16 +#define SYS_CHDIR_NUM 17 + +#ifndef __ASSEMBLER__ + +int getpid(); +unsigned uart_read(char buf[], unsigned size); +unsigned uart_write(const char buf[], unsigned size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(int status); +int mbox_call(unsigned char ch, volatile unsigned int *mbox); +void kill(int pid); +int open(const char *pathname, int flags); +int close(int fd); +long write(int fd, const void *buf, unsigned long count); +long read(int fd, void *buf, unsigned long count); +int mkdir(const char *pathname, unsigned mode); +int mount(const char *src, const char *target, const char *fs, unsigned long flags, const void *data); +int chdir(const char *path); + +int sys_getpid(); +unsigned sys_uartread(char buf[], unsigned size); +unsigned sys_uartwrite(const char buf[], unsigned size); +int sys_exec(const char *name, char *const argv[]); +int sys_fork(); +void sys_exit(int status); +int sys_mbox_call(unsigned char ch, volatile unsigned int *mbox); +void sys_kill(int pid); +int sys_open(const char *pathname, int flags); +int sys_close(int fd); +long sys_write(int fd, const void *buf, unsigned long count); +long sys_read(int fd, void *buf, unsigned long count); +int sys_mkdir(const char *pathname, unsigned mode); +int sys_mount(const char *src, const char *target, const char *fs, unsigned long flags, const void *data); +int sys_chdir(const char *path); + +#endif + +#endif \ No newline at end of file diff --git a/lab7/include/timer.h b/lab7/include/timer.h new file mode 100644 index 000000000..9812a457a --- /dev/null +++ b/lab7/include/timer.h @@ -0,0 +1,14 @@ +#ifndef _TIMER_H +#define _TIMER_H + +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +void timer_init(); +void handle_timer_irq(); +void core_timer_enable(); +void core_timer_disable(); +void set_timer(unsigned int rel_time); +unsigned int read_timer(); +unsigned int read_freq(); + +#endif \ No newline at end of file diff --git a/lab7/include/tmpfs.h b/lab7/include/tmpfs.h new file mode 100644 index 000000000..369622cc2 --- /dev/null +++ b/lab7/include/tmpfs.h @@ -0,0 +1,34 @@ +#ifndef _TMPFS_H +#define _TMPFS_H + +#include "vfs.h" + +#define REGULAR_FILE 0 +#define DIRECTORY 1 + +#define TMPFS_COMP_LEN 16 +#define MAX_DIRENT 16 +#define MAX_FILESIZE 0x1000 + +struct tmpfs_internal { + char name[TMPFS_COMP_LEN]; + int type; + struct tmpfs_internal *parent; + struct tmpfs_internal *child[MAX_DIRENT]; + struct vnode *vnode; + int size; // use for child count and data size + void *data; +}; + +int tmpfs_setup_mount(); +int tmpfs_register(); + +int tmpfs_open(struct vnode *file_node, struct file **target); +int tmpfs_close(struct file *file); +int tmpfs_write(struct file *file, const void *buf, unsigned len); +int tmpfs_read(struct file *file, void *buf, unsigned len); +int tmpfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); + +#endif \ No newline at end of file diff --git a/lab7/include/utils.h b/lab7/include/utils.h new file mode 100644 index 000000000..9d950d477 --- /dev/null +++ b/lab7/include/utils.h @@ -0,0 +1,8 @@ +#ifndef _BOOT_H +#define _BOOT_H + +extern void delay ( unsigned long ); +extern void put32 ( unsigned long, unsigned int ); +extern unsigned int get32 ( unsigned long ); + +#endif /*_BOOT_H */ \ No newline at end of file diff --git a/lab7/include/vfs.h b/lab7/include/vfs.h new file mode 100644 index 000000000..05dc0cd35 --- /dev/null +++ b/lab7/include/vfs.h @@ -0,0 +1,75 @@ +#ifndef _VFS_H +#define _VFS_H + +struct vnode { + struct mount* mount; + struct vnode_operations* v_ops; + struct file_operations* f_ops; + void* internal; +}; + +// file handle +struct file { + struct vnode* vnode; + unsigned f_pos; // RW position of this file handle + struct file_operations* f_ops; + int flags; +}; + +struct mount { + struct vnode* root; + struct filesystem* fs; +}; + +struct filesystem { + char* name; + int (*setup_mount)(struct filesystem* fs, struct mount* mount); +}; + +struct file_operations { + int (*write)(struct file* file, const void* buf, unsigned len); + int (*read)(struct file* file, void* buf, unsigned len); + int (*open)(struct vnode* file_node, struct file** target); + int (*close)(struct file* file); +}; + +struct vnode_operations { + int (*lookup)(struct vnode* dir_node, struct vnode** target, + const char* component_name); + int (*create)(struct vnode* dir_node, struct vnode** target, + const char* component_name); + int (*mkdir)(struct vnode* dir_node, struct vnode** target, + const char* component_name); +}; + +struct fd_table { + int count; + struct file *fds[16]; +}; + +#define VFS_PATHMAX 256 + +#define O_CREAT 00000100 +#define SUCCESS 0 +#define FAIL -1 +#define EOF -1 + +extern struct mount *rootfs; + +void rootfs_init(); + +int register_fs(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, unsigned len); +int vfs_read(struct file *file, void *buf, unsigned len); + +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 vfs_chdir(const char *pathname); + +void traverse(const char* pathname, struct vnode** target_node, char *target_path); +void r_traverse(struct vnode *node, const char *path, struct vnode **target_node, char *target_path); + +#endif \ No newline at end of file diff --git a/lab7/initramfs.cpio b/lab7/initramfs.cpio new file mode 100644 index 000000000..18985b13c Binary files /dev/null and b/lab7/initramfs.cpio differ diff --git a/lab7/kernel/Makefile b/lab7/kernel/Makefile new file mode 100644 index 000000000..831618b19 --- /dev/null +++ b/lab7/kernel/Makefile @@ -0,0 +1,49 @@ +AARCH64_PREFIX = aarch64-linux-gnu- +CC = $(AARCH64_PREFIX)gcc +LD = $(AARCH64_PREFIX)ld +OBJCPY = $(AARCH64_PREFIX)objcopy +GDB = $(AARCH64_PREFIX)gdb + +CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding -I../include -mgeneral-regs-only +ASMFLAGS = -I../include + +BUILD_DIR = ../build + +.PHONY: all clean qemu gdb_start + +all: kernel8.img + +clean: + rm kernel8.img $(OBJ_FILES) $(BUILD_DIR)/$(DEP_FILES) \ + ../build/kernel8.elf + +$(BUILD_DIR)/%_c.o: %.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: %.S + $(CC) $(ASMFLAGS) -MMD -c $< -o $@ + +C_FILES = $(wildcard *.c) +ASM_FILES = $(wildcard *.S) +OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) + +LIBC_FILES = $(wildcard ../lib/*.c) +LIBASM_FILES = $(wildcard ../lib/*.S) +LIBOBJ_FILES = $(LIBC_FILES:../lib/%.c=$(BUILD_DIR)/%_c.o) +LIBOBJ_FILES += $(LIBASM_FILES:../lib/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) $(LIBOBJ_FILES) + $(LD) -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) $(LIBOBJ_FILES) + $(OBJCPY) $(BUILD_DIR)/kernel8.elf -O binary $@ + +qemu: # all in one qemu command + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -S -s -serial null -serial pty \ + -initrd ../initramfs.cpio -dtb ../bcm2710-rpi-3-b-plus.dtb + +gdb_start: + $(GDB) $(BUILD_DIR)/kernel8.elf diff --git a/lab7/kernel/boot_kernel.S b/lab7/kernel/boot_kernel.S new file mode 100644 index 000000000..27ccfa7f1 --- /dev/null +++ b/lab7/kernel/boot_kernel.S @@ -0,0 +1,88 @@ +#include "mmu.h" +#include "peripherals/base.h" + +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 + and x0, x0, #3 // Check processor id + cbnz x0, proc_hang // Hang for all non-primary CPU + bl from_el2_to_el1 + bl set_exception_vector_table + +master: + mov x2, #VA_START + ldr x0, =__bss_begin + sub x0, x0, x2 + ldr x1, =__bss_end + sub x1, x1, x2 + sub x1, x1, x0 + +memzero: + cbz x1, mmu + str xzr, [x0], #8 + subs x1, x1, #8 + cbnz x1, memzero + +mmu: + mov x0, #VA_START + add sp, x0, #0x80000 + + bl set_tcr + bl set_mair + bl make_page_tables + + mov x0, #SCTLR_MMU_ENABLED + msr sctlr_el1, x0 + + ldr x0, =kernel_main + br x0 + +proc_hang: + wfe + b proc_hang + +set_exception_vector_table: + ldr x0, =exception_vector_table + msr vbar_el1, x0 + ret + +from_el2_to_el1: + 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 + +set_tcr: + ldr x0, =TCR_CONFIG_DEFAULT + msr tcr_el1, x0 + ret + +set_mair: + ldr x0, =MAIR_VALUE + msr mair_el1, x0 + ret + +make_page_tables: + ldr x0, =pg_dir + and x0, x0, #VA_MASK + add x1, x0, 0x1000 + + ldr x2, =BOOT_PGD_ATTR + orr x2, x1, x2 + str x2, [x0] + + ldr x2, =BOOT_PUD_ATTR + mov x3, 0x00000000 + orr x3, x2, x3 + str x3, [x1] + mov x3, 0x40000000 + orr x3, x2, x3 + str x3, [x1, 8] + + msr ttbr0_el1, x0 + msr ttbr1_el1, x0 + ret \ No newline at end of file diff --git a/lab7/kernel/kernel.c b/lab7/kernel/kernel.c new file mode 100644 index 000000000..e6b890d3f --- /dev/null +++ b/lab7/kernel/kernel.c @@ -0,0 +1,28 @@ +#include "mini_uart.h" +#include "shell.h" +#include "devtree.h" +#include "cpio.h" +#include "mm.h" +#include "timer.h" +#include "exception.h" +#include "fork.h" +#include "vfs.h" + +void kernel_main(void) +{ + uart_init(); + devtree_getaddr(); + fdt_traverse(initramfs_callback); + init_mm_reserve(); + timer_init(); + rootfs_init(); + enable_interrupt(); + uart_send_string("OSDI 2022 Spring\n"); + + copy_process(PF_KTHREAD, (unsigned long)&shell_loop, 0/*, 0*/); + + while (1) { + kill_zombies(); + schedule(); + } +} \ No newline at end of file diff --git a/lab7/kernel/linker.ld b/lab7/kernel/linker.ld new file mode 100644 index 000000000..48804b7fb --- /dev/null +++ b/lab7/kernel/linker.ld @@ -0,0 +1,24 @@ +SECTIONS +{ + . = 0xffff000000000000; + . += 0x80000; + + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + + . = ALIGN(8); + + __bss_begin = .; + .bss : { *(.bss* .bss.*) } + __bss_end = .; + + . = ALIGN(0x00001000); + pg_dir = .; + .data.pgd : { . += (3 * (1 << 12)); } + + __heap_start = .; + __kernel_end = .; + +} diff --git a/lab7/lib/Makefile b/lab7/lib/Makefile new file mode 100644 index 000000000..66d9bcea3 --- /dev/null +++ b/lab7/lib/Makefile @@ -0,0 +1,29 @@ +AARCH64_PREFIX = aarch64-linux-gnu- +CC = $(AARCH64_PREFIX)gcc + +CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding -I../include -mgeneral-regs-only +ASMFLAGS = -I../include + +BUILD_DIR = ../build + +.PHONY: all clean + +$(BUILD_DIR)/%_c.o: %.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: %.S + $(CC) $(ASMFLAGS) -MMD -c $< -o $@ + +C_FILES = $(wildcard *.c) +ASM_FILES = $(wildcard *.S) +OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +all: $(OBJ_FILES) + +clean: + rm $(OBJ_FILES) $(BUILD_DIR)/$(DEP_FILES) diff --git a/lab7/lib/cpio.c b/lab7/lib/cpio.c new file mode 100644 index 000000000..5e7d2cb6e --- /dev/null +++ b/lab7/lib/cpio.c @@ -0,0 +1,233 @@ +#include "../include/cpio.h" +#include "mini_uart.h" +#include "../include/sched.h" +#include "fork.h" +#include "string.h" +#include "mmu.h" + +void *DEVTREE_CPIO_BASE = 0; + +unsigned int hexstr_to_uint(char *s, unsigned int len) { + + unsigned int n = 0; + + for (int i=0; i= '0' && s[i] <= '9') { + n += s[i] - '0'; + } else if (s[i] >= 'A' && s[i] <= 'F') { + n += s[i] - 'A' + 10; + } + } + + return n; + +} + +void initramfs_callback(char *node_name, char *prop_name, struct fdt_prop *prop) { + + if (stringncmp(node_name, "chosen", 7) == 0 && + stringncmp(prop_name, "linux,initrd-start", 19) == 0) { + + DEVTREE_CPIO_BASE = (void*)to_lendian(*((unsigned int*)(prop + 1))) + VA_START; + + } + +} + +void cpio_ls() { + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + + header = DEVTREE_CPIO_BASE; + + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) break; + + uart_send_string(filename); + uart_send('\n'); + + namesize = hexstr_to_uint(header->c_namesize, 8); + filesize = hexstr_to_uint(header->c_filesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + +} + +void cpio_cat() { + + char input[256]; + char c = '\0'; + int idx = 0; + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + + header = DEVTREE_CPIO_BASE; + + uart_send_string("Filename: "); + + while (1) { + c = uart_recv(); + if (c == '\r' || c == '\n') { + uart_send_string("\n"); + + if (idx < 256) input[idx] = '\0'; + else input[255] = '\0'; + + break; + } else { + uart_send(c); + input[idx++] = c; + } + } + + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) { + uart_send_string("file does not exist!\n"); + break; + } + + namesize = hexstr_to_uint(header->c_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, input, namesize) == 0) { + + char *content = ((void*)header) + offset; + + for (int i=0; ic_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, input, namesize) == 0) { + + char *code_loc = ((void*)header) + offset; + unsigned int sp_val = 0x600000; + asm volatile( + "msr elr_el1, %0\n\t" + "msr spsr_el1, xzr\n\t" + "msr sp_el0, %1\n\t" + "eret\n\t" + :: + "r" (code_loc), + "r" (sp_val) + ); + + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + +} diff --git a/lab7/lib/devtree.c b/lab7/lib/devtree.c new file mode 100644 index 000000000..691dc1a7e --- /dev/null +++ b/lab7/lib/devtree.c @@ -0,0 +1,92 @@ +#include "devtree.h" +#include "mini_uart.h" +#include "string.h" + +static void *DEVTREE_ADDRESS = 0; + +unsigned long to_lendian(unsigned long n) { + return ((n>>24)&0x000000FF) | + ((n>>8) &0x0000FF00) | + ((n<<8) &0x00FF0000) | + ((n<<24)&0xFF000000) ; +} + +void devtree_getaddr() { + + asm volatile("MOV %0, x20" : "=r"(DEVTREE_ADDRESS)); + + char magic[4] = {0xd0, 0x0d, 0xfe, 0xed}; + if(stringncmp((char*)DEVTREE_ADDRESS, magic, 4) != 0) { + uart_send_string("magic failed\n"); + } else { + uart_send_string("devtree magic succeed\n"); + } + +} + +void fdt_traverse( void (*callback)(char *, char *, struct fdt_prop *) ) { + + char magic[4] = {0xd0, 0x0d, 0xfe, 0xed}; + struct fdt_header *devtree_header = DEVTREE_ADDRESS; + + if(stringncmp((char*)devtree_header, magic, 4) != 0) { + uart_send_string("devtree magic failed\n"); + return; + } + + void *dt_struct_addr = DEVTREE_ADDRESS + to_lendian(devtree_header->off_dt_struct); + char *dt_string_addr = DEVTREE_ADDRESS + to_lendian(devtree_header->off_dt_strings); + + char *node_name; + char *prop_name; + unsigned int token; + unsigned int off; + + while (1) { + + token = to_lendian(*((unsigned int *)dt_struct_addr)); + + if (token == FDT_BEGIN_NODE) { + + node_name = dt_struct_addr + 4; + off = 4 + strlen(node_name) + 1; + + if (off%4 != 0) + off = ((off/4)+1)*4; + + dt_struct_addr += off; + + } + else if (token == FDT_END_NODE) { + dt_struct_addr += 4; + } + else if (token == FDT_PROP) { + + struct fdt_prop *prop = (struct fdt_prop*)(dt_struct_addr + 4); + + off = 4 + 8 + to_lendian(prop->len); + if (off%4 != 0) + off = ((off/4)+1)*4; + + dt_struct_addr += off; + + prop_name = dt_string_addr + to_lendian(prop->nameoff); + + callback(node_name, prop_name, prop); + + } + else if (token == FDT_NOP) { + dt_struct_addr += 4; + } + else if (token == FDT_END) { + dt_struct_addr += 4; + break; + } + else { + uart_send_string("TOKEN NOT MATCHED\n"); + break; + } + + } + +} \ No newline at end of file diff --git a/lab7/lib/entry.S b/lab7/lib/entry.S new file mode 100644 index 000000000..e564be0fe --- /dev/null +++ b/lab7/lib/entry.S @@ -0,0 +1,195 @@ +#include "entry.h" +#include "syscall.h" + +.macro handle_invalid_entry el, type + kernel_entry \el + mov x0, #\type + mrs x1, esr_el1 + mrs x2, elr_el1 + bl show_invalid_entry_message + b err_hang +.endm + +.macro ventry label + .align 7 + b \label +.endm + +// save general registers to stack +.macro kernel_entry, el + sub sp, sp, #S_FRAME_SIZE + 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] + + .if \el == 0 + mrs x21, sp_el0 + .else + add x21, sp, #S_FRAME_SIZE + .endif + + mrs x22, elr_el1 + mrs x23, spsr_el1 + + stp x30, x21, [sp, 16 * 15] + stp x22, x23, [sp, 16 * 16] +.endm + +// load general registers from stack +.macro kernel_exit, el + ldp x22, x23, [sp, 16 * 16] + ldp x30, x21, [sp, 16 * 15] + + .if \el == 0 + msr sp_el0, x21 + .endif + + msr elr_el1, x22 + msr spsr_el1, x23 + + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + add sp, sp, #S_FRAME_SIZE + eret +.endm + +.align 11 // vector table should be aligned to 0x800 +.globl exception_vector_table +exception_vector_table: + ventry sync_invalid_el1t // Synchronous EL1t + ventry irq_invalid_el1t // IRQ EL1t + ventry fiq_invalid_el1t // FIQ EL1t + ventry error_invalid_el1t // Error EL1t + + ventry sync_invalid_el1h // Synchronous EL1h + ventry el1_irq // IRQ EL1h + ventry fiq_invalid_el1h // FIQ EL1h + ventry error_invalid_el1h // Error EL1h + + ventry el0_sync // Synchronous 64-bit EL0 + ventry el0_irq // IRQ 64-bit EL0 + ventry fiq_invalid_el0_64 // FIQ 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 + + 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 + +sync_invalid_el1t: + handle_invalid_entry 1, SYNC_INVALID_EL1t + +irq_invalid_el1t: + handle_invalid_entry 1, IRQ_INVALID_EL1t + +fiq_invalid_el1t: + handle_invalid_entry 1, FIQ_INVALID_EL1t + +error_invalid_el1t: + handle_invalid_entry 1, ERROR_INVALID_EL1t + +sync_invalid_el1h: + handle_invalid_entry 1, SYNC_INVALID_EL1h + +el1_irq: + kernel_entry 1 + bl handle_irq + kernel_exit 1 + +fiq_invalid_el1h: + handle_invalid_entry 1, FIQ_INVALID_EL1h + +error_invalid_el1h: + handle_invalid_entry 1, ERROR_INVALID_EL1h + +el0_sync: + kernel_entry 0 + mrs x25, esr_el1 + lsr x24, x25, #ESR_ELx_EC_SHIFT + cmp x24, #ESR_ELx_EC_SVC64 + b.eq el0_svc + handle_invalid_entry 0, SYNC_ERROR + +el0_irq: + kernel_entry 0 + bl handle_irq + kernel_exit 0 + +fiq_invalid_el0_64: + handle_invalid_entry 0, FIQ_INVALID_EL0_64 + +error_invalid_el0_64: + handle_invalid_entry 0, ERROR_INVALID_EL0_64 + +sync_invalid_el0_32: + handle_invalid_entry 0, SYNC_INVALID_EL0_32 + +irq_invalid_el0_32: + handle_invalid_entry 0, IRQ_INVALID_EL0_32 + +fiq_invalid_el0_32: + handle_invalid_entry 0, FIQ_INVALID_EL0_32 + +error_invalid_el0_32: + handle_invalid_entry 0, ERROR_INVALID_EL0_32 + +sc_nr .req x25 +scno .req x26 +stbl .req x27 + +el0_svc: + adr stbl, sys_call_table + uxtw scno, w8 + mov sc_nr, #__NR_SYSCALLS + bl enable_interrupt + cmp scno, sc_nr + b.hs ni_sys + + ldr x16, [stbl, scno, lsl #3] + blr x16 + b ret_from_syscall +ni_sys: + handle_invalid_entry 0, SYSCALL_ERROR +ret_from_syscall: + bl disable_interrupt + str x0, [sp, #S_X0] + kernel_exit 0 + +.globl ret_from_fork +ret_from_fork: + bl schedule_tail + cbz x19, ret_to_user + mov x0, x20 + blr x19 // in theory should not return + //b err_hang // hang fail-safe +ret_to_user: + bl disable_interrupt + kernel_exit 0 + +.globl err_hang +err_hang: b err_hang diff --git a/lab7/lib/exception.c b/lab7/lib/exception.c new file mode 100644 index 000000000..a820ba662 --- /dev/null +++ b/lab7/lib/exception.c @@ -0,0 +1,49 @@ +#include "exception.h" +#include "mini_uart.h" +#include "mailbox.h" +#include "utils.h" +#include "timer.h" +#include "peripherals/exception.h" +#include "peripherals/mini_uart.h" + +void enable_interrupt() {asm volatile("msr DAIFClr, 0xf");} +void disable_interrupt() {asm volatile("msr DAIFSet, 0xf");} + +const char *entry_error_messages[] = { + "SYNC_INVALID_EL1t", + "IRQ_INVALID_EL1t", + "FIQ_INVALID_EL1t", + "ERROR_INVALID_EL1t", + + "SYNC_INVALID_EL1h", + "IRQ_INVALID_EL1h", + "FIQ_INVALID_EL1h", + "ERROR_INVALID_EL1h", + + "SYNC_INVALID_EL0_64", + "IRQ_INVALID_EL0_64", + "FIQ_INVALID_EL0_64", + "ERROR_INVALID_EL0_64", + + "SYNC_INVALID_EL0_32", + "IRQ_INVALID_EL0_32", + "FIQ_INVALID_EL0_32", + "ERROR_INVALID_EL0_32", + + "SYNC_ERROR", + "SYSCALL_ERROR" +}; + +void show_invalid_entry_message(int type, unsigned long esr, unsigned long addr) { + printf("%s, ESR: 0x%x, address: 0x%x\n", entry_error_messages[type], esr, addr); +} + +void handle_irq() { + + if (get32(CORE0_INTERRUPT_SRC)&INTERRUPT_SOURCE_CNTPNSIRQ) { + handle_timer_irq(); + } else { + printf("unknown irq encountered"); + } + +} \ No newline at end of file diff --git a/lab7/lib/fork.c b/lab7/lib/fork.c new file mode 100644 index 000000000..acdf566d6 --- /dev/null +++ b/lab7/lib/fork.c @@ -0,0 +1,176 @@ +#include "fork.h" +#include "mm.h" +#include "mini_uart.h" +#include "../include/sched.h" +#include "../include/entry.h" +#include "mmu.h" + +int copy_process(unsigned long clone_flags, unsigned long fn, unsigned long arg/*, unsigned long stack*/) { + + preempt_disable(); + struct task_struct *p; + + p = (struct task_struct *) allocate_kernel_page(); + if (p == NULL) + return -1; + + memzero((unsigned long)p, sizeof(struct task_struct)); + struct pt_regs *childregs = task_pt_regs(p); + + if (clone_flags & PF_KTHREAD) { + p->cpu_context.x19 = fn; + p->cpu_context.x20 = arg; + } else { + struct pt_regs *cur_regs = task_pt_regs(current); + // *childregs = *cur_regs; (object file generates memcpy) + // therefore the for loop is used below + for(int i=0; iregs[0] = 0; // return value 0 + copy_virt_memory(p); + } + + p->flags = clone_flags; + p->priority = current->priority; + p->state = TASK_RUNNING; + p->counter = p->priority; + p->preempt_count = 1; + + p->cpu_context.pc = (unsigned long)ret_from_fork; + p->cpu_context.sp = (unsigned long)childregs; + + int pid = nr_tasks++; + task[pid] = p; + p->id = pid; + preempt_enable(); + + return pid; + +} + +int move_to_user_mode(unsigned long start, unsigned long size, unsigned long pc) { + + struct pt_regs *regs = task_pt_regs(current); + regs->pc = pc; // virt pc + regs->pstate = PSR_MODE_EL0t; + regs->sp = 0xfffffffff000; + + unsigned long pages = (unsigned long)malloc(size); // phys + if (pages == NULL) + return -1; + + unsigned long va; // might need to map more? bss? currently mapping just enough + for(va=0; vasp; va+=PAGE_SIZE) { + map_page(current, va, stack_bot+(i*PAGE_SIZE)); + i++; + } + + // vc identity mapping + //printf("user page count %d\n", current->mm.user_pages_count); + for(unsigned long va=0x3c000000; va<0x3f000000; va+=PAGE_SIZE) { + unsigned long pgd; + if (!current->mm.pgd) { + pgd = (unsigned long)malloc(PAGE_SIZE); + //printf("pgd not found, created at phys address 0x%x\n", pgd); + memzero(pgd+VA_START, PAGE_SIZE); + current->mm.pgd = pgd; + current->mm.kernel_pages[++current->mm.kernel_pages_count] = current->mm.pgd; + } + pgd = current->mm.pgd; + //printf("pgd at 0x%x\n", pgd); + int new_table; + unsigned long pud = map_table((unsigned long *)(pgd + VA_START), PGD_SHIFT, va, &new_table); + //printf("pud at 0x%x\n", pud); + if (new_table) { + current->mm.kernel_pages[++current->mm.kernel_pages_count] = pud; + } + unsigned long pmd = map_table((unsigned long *)(pud + VA_START), PUD_SHIFT, va, &new_table); + //printf("pmd at 0x%x\n", pmd); + if (new_table) { + current->mm.kernel_pages[++current->mm.kernel_pages_count] = pmd; + } + unsigned long pte = map_table((unsigned long *)(pmd + VA_START), PMD_SHIFT, va, &new_table); + //printf("pte at 0x%x\n", pte); + if (new_table) { + current->mm.kernel_pages[++current->mm.kernel_pages_count] = pte; + } + map_table_entry((unsigned long *)(pte + VA_START), va, va); + //struct user_page p = {page, va}; + //task->mm.user_pages[task->mm.user_pages_count++] = p; + //if (va == 0x3c25e000) printf("0x%x, 0x%x, 0x%x, 0x%x\n", pgd, pud, pmd, pte); + } + //printf("user page count %d\n", current->mm.user_pages_count); + //memcpy(pages+VA_START, start, size); // move code to pages + for(int i=0; imm.pgd); + return 0; + +} + +struct pt_regs *task_pt_regs(struct task_struct *tsk) { + + unsigned long p = (unsigned long)tsk + THREAD_SIZE - sizeof(struct pt_regs); + return (struct pt_regs *)p; + +} + +void new_user_process(unsigned long func){ + printf("Kernel process started, moving to user mode.\n"); + int err = move_to_user_mode(func, 4096, func); + if (err < 0){ + printf("Error while moving process to user mode\n\r"); + } +} + +int copy_virt_memory(struct task_struct *dst) { + struct task_struct* src = current; + for (int i=0; imm.user_pages_count; i++) { + unsigned long kernel_va = allocate_user_page(dst, src->mm.user_pages[i].virt_addr); + if(kernel_va == 0) return -1; + memcpy(kernel_va, src->mm.user_pages[i].virt_addr, PAGE_SIZE); + } + for(unsigned long va=0x3c000000; va<0x3f000000; va+=PAGE_SIZE) { + unsigned long pgd; + if (!dst->mm.pgd) { + pgd = (unsigned long)malloc(PAGE_SIZE); + //printf("pgd not found, created at phys address 0x%x\n", pgd); + memzero(pgd+VA_START, PAGE_SIZE); + dst->mm.pgd = pgd; + dst->mm.kernel_pages[++dst->mm.kernel_pages_count] = dst->mm.pgd; + } + pgd = dst->mm.pgd; + //printf("pgd at 0x%x\n", pgd); + int new_table; + unsigned long pud = map_table((unsigned long *)(pgd + VA_START), PGD_SHIFT, va, &new_table); + //printf("pud at 0x%x\n", pud); + if (new_table) { + dst->mm.kernel_pages[++dst->mm.kernel_pages_count] = pud; + } + unsigned long pmd = map_table((unsigned long *)(pud + VA_START), PUD_SHIFT, va, &new_table); + //printf("pmd at 0x%x\n", pmd); + if (new_table) { + dst->mm.kernel_pages[++dst->mm.kernel_pages_count] = pmd; + } + unsigned long pte = map_table((unsigned long *)(pmd + VA_START), PMD_SHIFT, va, &new_table); + //printf("pte at 0x%x\n", pte); + if (new_table) { + dst->mm.kernel_pages[++dst->mm.kernel_pages_count] = pte; + } + map_table_entry((unsigned long *)(pte + VA_START), va, va); + //struct user_page p = {page, va}; + //task->mm.user_pages[task->mm.user_pages_count++] = p; + if (va == 0x3c25e000) printf("0x%x, 0x%x, 0x%x, 0x%x\n", pgd, pud, pmd, pte); + } + return 0; +} \ No newline at end of file diff --git a/lab7/lib/mailbox.c b/lab7/lib/mailbox.c new file mode 100644 index 000000000..e593af037 --- /dev/null +++ b/lab7/lib/mailbox.c @@ -0,0 +1,49 @@ +#include "peripherals/mailbox.h" +#include "mailbox.h" +#include "mini_uart.h" + +int mailbox_call (volatile unsigned int *mailbox) { + unsigned int msg = ((unsigned long)mailbox & ~0xF) | (0x8 & 0xF); + while (*MAILBOX_STATUS & MAILBOX_FULL) ; + *MAILBOX_WRITE = msg; + while (1) { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) {} + if (msg == *MAILBOX_READ) { + return mailbox[1]; + } + } +} + +void get_board_revision () +{ + volatile unsigned int __attribute__((aligned(16))) mailbox[7]; + mailbox[0] = 7 * 4; + mailbox[1] = REQUEST_CODE; + mailbox[2] = GET_BOARD_REVISION; + mailbox[3] = 4; + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; + mailbox[6] = END_TAG; + + if (mailbox_call(mailbox) == REQUEST_SUCCEED) { + printf("Board Revision:\t\t%x\n", mailbox[5]); + } +} + +void get_arm_memory () +{ + volatile unsigned int __attribute__((aligned(16))) mailbox[8]; + mailbox[0] = 8 * 4; + mailbox[1] = REQUEST_CODE; + mailbox[2] = GET_ARM_MEMORY; + mailbox[3] = 8; + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; + mailbox[6] = 0; + mailbox[7] = END_TAG; + + if (mailbox_call(mailbox) == REQUEST_SUCCEED) { + printf("Memory Base Addresss:\t%x\n", mailbox[5]); + printf("Memory Size:\t\t%x\n", mailbox[6]); + } +} \ No newline at end of file diff --git a/lab7/lib/math.c b/lab7/lib/math.c new file mode 100644 index 000000000..6b6919044 --- /dev/null +++ b/lab7/lib/math.c @@ -0,0 +1,19 @@ +#include "math.h" + +int log(int n, int base) { + int x = 1; + int ret = 0; + while (x <= n) { + x *= base; + ret++; + } + return ret; +} + +int pow(int base, int pow) { + int ret = 1; + for (int i=0; i avail) { + uart_send_string("not enough memory\n"); + } else { + __heap_ptr += size; + avail -= size; + } + + return ptr; + +} \ No newline at end of file diff --git a/lab7/lib/mini_uart.c b/lab7/lib/mini_uart.c new file mode 100644 index 000000000..c209f3a90 --- /dev/null +++ b/lab7/lib/mini_uart.c @@ -0,0 +1,69 @@ +#include "utils.h" +#include "printf.h" +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" +#include "peripherals/exception.h" + +void uart_send ( char c ) +{ + if (c == '\n') uart_send('\r'); + + while (1) { + if (get32(AUX_MU_LSR_REG)&0x20) + break; + } + + put32(AUX_MU_IO_REG,c); +} + +char uart_recv ( void ) +{ + while(1) { + if (get32(AUX_MU_LSR_REG)&0x01) + break; + } + return (get32(AUX_MU_IO_REG)&0xFF); +} + +void uart_send_string ( char* str ) +{ + for (int i = 0; str[i] != '\0'; i++) { + uart_send((char)str[i]); + } +} + +void printf(char *fmt, ...) { + char temp[128]; + __builtin_va_list args; + __builtin_va_start(args, fmt); + vsprintf(temp,fmt,args); + uart_send_string(temp); +} + +void uart_init ( void ) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7<<12); // clean gpio14 + selector |= 2<<12; // set alt5 for gpio14 + selector &= ~(7<<15); // clean gpio15 + selector |= 2<<15; // set alt5 for gpio 15 + put32(GPFSEL1,selector); + + put32(GPPUD,0); + delay(150); + put32(GPPUDCLK0,(1<<14)|(1<<15)); + delay(150); + put32(GPPUDCLK0,0); + + put32(AUX_ENABLES,1); //Enable mini uart (this also enables access to its registers) + put32(AUX_MU_CNTL_REG,0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(AUX_MU_IER_REG,0); //Enable receive and disable transmit interrupts + put32(AUX_MU_LCR_REG,3); //Enable 8 bit mode + put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high + put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200 + put32(AUX_MU_IIR_REG,6); //Interrupt identify no fifo + put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver + +} diff --git a/lab7/lib/mm.S b/lab7/lib/mm.S new file mode 100644 index 000000000..56eef8286 --- /dev/null +++ b/lab7/lib/mm.S @@ -0,0 +1,14 @@ +.globl memcpy +memcpy: + ldr x3, [x1], #8 + str x3, [x0], #8 + subs x2, x2, #8 + b.gt memcpy + ret + +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret \ No newline at end of file diff --git a/lab7/lib/mm.c b/lab7/lib/mm.c new file mode 100644 index 000000000..7c0ef41e6 --- /dev/null +++ b/lab7/lib/mm.c @@ -0,0 +1,394 @@ +#include "mm.h" +#include "mmu.h" +#include "math.h" +#include "memory.h" +#include "mini_uart.h" + +static unsigned int n_frames = 0; +static unsigned int max_size = 0; +static struct frame* frame_list[MAX_ORDER] = {NULL}; +static struct frame frame_array[(MEM_REGION_END-MEM_REGION_BEGIN)/PAGE_SIZE]; +static struct dynamic_pool pools[MAX_POOLS] = { {ALLOCABLE, 0, 0, 0, 0, {NULL}, NULL} }; +static unsigned int reserved_num = 0; +static void* reserved_se[MAX_RESERVABLE][2] = {{0x0, 0x0}}; // expects to be sorted and addresses [,) +extern char __kernel_end; +static char *__kernel_end_ptr = &__kernel_end; + +unsigned long allocate_user_page(struct task_struct *task, unsigned long va) { + unsigned long page = (unsigned long)malloc(PAGE_SIZE); + if (page == 0) + return NULL; + map_page(task, va, page); + return page + VA_START; +} + +unsigned long allocate_kernel_page() { + unsigned long page = (unsigned long)malloc(PAGE_SIZE); + if(page == NULL) + return NULL; + return page + VA_START; +} + +void *malloc(unsigned int size) { + + if (size > max_size) { + printf("[error] Request exceeded allocable continuous size %d.\n", (int)max_size); + return NULL; + } + + int req_order = 0; + for(unsigned int i=PAGE_SIZE; i= MAX_ORDER) { + printf("[error] No memory allocable.\n"); + return NULL; + } + + while (t != req_order) { + struct frame* l_tmp = frame_list[t]; + frame_list[t] = l_tmp->next; + if (frame_list[t] != NULL) + frame_list[t]->prev = NULL; + //printf("[info] Split at order %d, new head is 0x%x.\n", t+1, frame_list[t]); + + unsigned int off = pow(2, l_tmp->val-1); + struct frame* r_tmp = &frame_array[l_tmp->index+off]; + + l_tmp->val -= 1; + l_tmp->state = ALLOCABLE; + l_tmp->prev = NULL; + l_tmp->next = r_tmp; + + r_tmp->val = l_tmp->val; + r_tmp->state = ALLOCABLE; + r_tmp->prev = l_tmp; + r_tmp->next = NULL; + + t--; + if (frame_list[t] != NULL) + frame_list[t]->prev = r_tmp; + r_tmp->next = frame_list[t]; + frame_list[t] = l_tmp; + } + + struct frame* ret = frame_list[req_order]; + frame_list[req_order] = ret->next; + if (frame_list[req_order] != NULL) + frame_list[req_order]->prev = NULL; + + ret->val = ret->val; + ret->state = ALLOCATED; + ret->prev = NULL; + ret->next = NULL; + + //printf("[info] allocated address: 0x%x\n", MEM_REGION_BEGIN+PAGE_SIZE*ret->index); + + return (void*)MEM_REGION_BEGIN+PAGE_SIZE*ret->index; + +} + +void free(void *address) { + + unsigned int idx = ((unsigned long long)address-MEM_REGION_BEGIN) / PAGE_SIZE; + struct frame* target = &frame_array[idx]; + + if (target->state == ALLOCABLE || target->state == C_NALLOCABLE) { + printf("[error] invalid free of already freed memory.\n"); + return; + } + //printf("=========================================================\n"); + //printf("[info] Now freeing address 0x%x with frame index %d.\n", address, (int)idx); + + for (int i=target->val; ival+1, fr_buddy->state); + + if (i < MAX_ORDER-1 && fr_buddy->state == ALLOCABLE && i== fr_buddy->val) { + + //printf("[info] Merging from order %d. Frame indices %d, %d.\n", i+1, (int)buddy, (int)idx); + + if (fr_buddy->prev != NULL) { + fr_buddy->prev->next = fr_buddy->next; + } else { + frame_list[fr_buddy->val] = fr_buddy->next; + } + + if (fr_buddy->next != NULL) { + fr_buddy->next->prev = fr_buddy->prev; + } + + fr_buddy->prev = NULL; + fr_buddy->next = NULL; + fr_buddy->val = C_NALLOCABLE; + fr_buddy->state = C_NALLOCABLE; + target->val = C_NALLOCABLE; + target->state = C_NALLOCABLE; + + if (fr_buddy->index < target->index) { + idx = fr_buddy->index; + target = fr_buddy; + } + + //printf("[info] Frame index of next merge target is %d.\n", (int)idx); + + } else { + + target->val = i; + target->state = ALLOCABLE; + target->prev = NULL; + target->next = frame_list[i]; + if (frame_list[i] != NULL) + frame_list[i]->prev = target; + frame_list[i] = target; + //printf("[info] Frame index %d pushed to frame list of order %d.\n", + // (int)target->index, (int)i+1); + break; + + } + + } + + //printf("[info] Free finished.\n"); + /*for (int i=0; i < MAX_ORDER; i++) { + if (frame_list[i] != NULL) + printf("[info] Head of order %d has frame array index %d.\n",i+1,frame_list[i]->index); + else + printf("[info] Head of order %d has frame array index null.\n",i+1); + }*/ + +} + +void init_mm() { + + n_frames = (MEM_REGION_END-MEM_REGION_BEGIN) / PAGE_SIZE; + unsigned int mul = (unsigned int)pow(2, MAX_ORDER-1); + printf("[info] Frame array start address 0x%x.\n", frame_array); + for (unsigned int i=0; ichunk_size = size; + pool->chunks_per_page = PAGE_SIZE / size; + pool->chunks_allocated = 0; + pool->page_new_chunk_off = 0; + pool->pages_used = 0; + pool->free_head = NULL; +} + +int register_chunk(unsigned int size) { + + unsigned int nsize = 0; + if (size <= 8) nsize = 8; + else { + int rem = size % 4; + if (rem != 0) nsize = (size/4 + 1)*4; + else nsize = size; + } + + if (nsize >= PAGE_SIZE) { + printf("[error] Normalized chunk size request leq page size.\n"); + return -1; + } + + for (int i=0; ifree_head != NULL) { + void *ret = (void*) pool->free_head; + pool->free_head = pool->free_head->next; + //printf("[info] allocate address 0x%x from pool free list.\n", ret); + return ret; + } + + if (pool->chunks_allocated >= MAX_POOL_PAGES*pool->chunks_per_page) { + //printf("[error] Pool maximum reached.\n"); + return NULL; + } + + + if (pool->chunks_allocated >= pool->pages_used*pool->chunks_per_page) { + pool->page_base_addrs[pool->pages_used] = malloc(PAGE_SIZE); + //printf("[info] allocate new page for pool with base address 0x%x.\n", + // pool->page_base_addrs[pool->pages_used]); + pool->pages_used++; + pool->page_new_chunk_off = 0; + } + + void *ret = pool->page_base_addrs[pool->pages_used - 1] + + pool->chunk_size*pool->page_new_chunk_off; + pool->page_new_chunk_off++; + pool->chunks_allocated++; + + //printf("[info] allocate new address 0x%x from pool.\n", ret); + + return ret; + +} + +void chunk_free(void *address) { + + int target = -1; + + void *prefix_addr = (void *)((unsigned long long)address & ~0xFFF); + + for (unsigned int i=0; ifree_head; + pool->free_head = (struct node*) address; + pool->free_head->next = old_head; + pool->chunks_allocated--; + +} + +void memory_reserve(void* start, void* end) { + if (reserved_num >= MAX_RESERVABLE) { + printf("[error] Max reservable locations already reached.\n"); + return; + } + reserved_se[reserved_num][0] = start; + reserved_se[reserved_num][1] = end; + reserved_num++; +} + +void init_mm_reserve() { + + max_size = PAGE_SIZE * pow(2, MAX_ORDER-1); + n_frames = (MEM_REGION_END-MEM_REGION_BEGIN) / PAGE_SIZE; + + memory_reserve((void*)0x0, (void*)((unsigned long long)__kernel_end_ptr&VA_MASK)); // spin tables, kernel image + memory_reserve((void*)0x20000000, (void*)0x20010000); // hard code reserve initramfs + + for (unsigned int i=0; i= reserved_se[i][0] && addr < reserved_se[i][1]) { + frame_array[j].state = RESERVED; + } + if (addr >= reserved_se[i][1]) break; + } + } + + for (int i=0; istate == RESERVED) continue; + if (target->state == C_NALLOCABLE) continue; + + for (int i=target->val; istate == ALLOCABLE && i== fr_buddy->val) { + + if (fr_buddy->prev != NULL) { + fr_buddy->prev->next = fr_buddy->next; + } else { + frame_list[fr_buddy->val] = fr_buddy->next; + } + + if (fr_buddy->next != NULL) { + fr_buddy->next->prev = fr_buddy->prev; + } + + fr_buddy->prev = NULL; + fr_buddy->next = NULL; + fr_buddy->val = C_NALLOCABLE; + fr_buddy->state = C_NALLOCABLE; + target->val = C_NALLOCABLE; + target->state = C_NALLOCABLE; + + if (fr_buddy->index < target->index) { + idx = fr_buddy->index; + target = fr_buddy; + } + + } else { + + target->val = i; + target->state = ALLOCABLE; + target->prev = NULL; + target->next = frame_list[i]; + if (frame_list[i] != NULL) + frame_list[i]->prev = target; + frame_list[i] = target; + break; + + } + + } + + } + +} \ No newline at end of file diff --git a/lab7/lib/mmu.c b/lab7/lib/mmu.c new file mode 100644 index 000000000..ac1978b14 --- /dev/null +++ b/lab7/lib/mmu.c @@ -0,0 +1,74 @@ +#include "mmu.h" +#include "mm.h" +#include "mini_uart.h" + +void map_page(struct task_struct *task, unsigned long va, unsigned long page) { + //printf("===================\n"); + //printf("map virtual address 0x%x to phys address 0x%x\n", va, page); + unsigned long pgd; + if (!task->mm.pgd) { + pgd = (unsigned long)malloc(PAGE_SIZE); + //printf("pgd not found, created at phys address 0x%x\n", pgd); + memzero(pgd+VA_START, PAGE_SIZE); + task->mm.pgd = pgd; + task->mm.kernel_pages[++task->mm.kernel_pages_count] = task->mm.pgd; + } + pgd = task->mm.pgd; + //printf("pgd at 0x%x\n", pgd); + int new_table; + unsigned long pud = map_table((unsigned long *)(pgd + VA_START), PGD_SHIFT, va, &new_table); + //printf("pud at 0x%x\n", pud); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pud; + } + unsigned long pmd = map_table((unsigned long *)(pud + VA_START), PUD_SHIFT, va, &new_table); + //printf("pmd at 0x%x\n", pmd); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pmd; + } + unsigned long pte = map_table((unsigned long *)(pmd + VA_START), PMD_SHIFT, va, &new_table); + //printf("pte at 0x%x\n", pte); + if (new_table) { + task->mm.kernel_pages[++task->mm.kernel_pages_count] = pte; + } + map_table_entry((unsigned long *)(pte + VA_START), va, page); + struct user_page p = {page, va}; + task->mm.user_pages[task->mm.user_pages_count++] = p; + //printf("user pages count %d\n", task->mm.user_pages_count-1); +} + +unsigned long map_table(unsigned long *table, unsigned long shift, unsigned long va, int* new_table) { + unsigned long index = va >> shift; + index = index & (512 - 1); + if (!table[index]) { + *new_table = 1; + unsigned long next_level_table = (unsigned long)malloc(PAGE_SIZE); + memzero(next_level_table+VA_START, PAGE_SIZE); + unsigned long entry = next_level_table | PD_TABLE; + table[index] = entry; + return next_level_table; + } else { + *new_table = 0; + } + return table[index] & PAGE_MASK; +} + +void map_table_entry(unsigned long *pte, unsigned long va, unsigned long pa) { + unsigned long index = va >> 12; + index = index & (512 - 1); + unsigned long entry = pa | PTE_USR_RW_PTE; + pte[index] = entry; + //printf("0x%x[%d] contains 0x%x\n", pte, index, entry); +} + +unsigned long va2phys(unsigned long va) { + printf("translate va: 0x%x\n", va); + unsigned long pgd; + asm volatile("mrs %0, ttbr0_el1\n\t": "=r" (pgd) :: "memory"); + unsigned long pud = ((unsigned long*)(pgd+VA_START))[va>>PGD_SHIFT&(512-1)]&PAGE_MASK; + unsigned long pmd = ((unsigned long*)(pud+VA_START))[va>>PUD_SHIFT&(512-1)]&PAGE_MASK; + unsigned long pte = ((unsigned long*)(pmd+VA_START))[va>>PMD_SHIFT&(512-1)]&PAGE_MASK; + unsigned long phys = ((unsigned long*)(pte+VA_START))[va>>12&(512-1)]&PAGE_MASK; + printf("0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", pgd, pud, pmd, pte, phys); + return phys; +} diff --git a/lab7/lib/printf.c b/lab7/lib/printf.c new file mode 100644 index 000000000..794a37dff --- /dev/null +++ b/lab7/lib/printf.c @@ -0,0 +1,152 @@ +/* + * 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 + */ +#include "printf.h" + +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_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/lab7/lib/reboot.c b/lab7/lib/reboot.c new file mode 100644 index 000000000..043a09fb7 --- /dev/null +++ b/lab7/lib/reboot.c @@ -0,0 +1,18 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab7/lib/sched.S b/lab7/lib/sched.S new file mode 100644 index 000000000..7e4392f23 --- /dev/null +++ b/lab7/lib/sched.S @@ -0,0 +1,32 @@ +#include "sched.h" + +.global cpu_switch_to +cpu_switch_to: + mov x10, #THREAD_CPU_CONTEXT + add x8, x0, x10 + mov x9, sp + stp x19, x20, [x8], #16 // store callee-saved registers + stp x21, x22, [x8], #16 + stp x23, x24, [x8], #16 + stp x25, x26, [x8], #16 + stp x27, x28, [x8], #16 + stp x29, x9, [x8], #16 + str x30, [x8] + add x8, x1, x10 + ldp x19, x20, [x8], #16 // restore callee-saved registers + ldp x21, x22, [x8], #16 + ldp x23, x24, [x8], #16 + ldp x25, x26, [x8], #16 + ldp x27, x28, [x8], #16 + ldp x29, x9, [x8], #16 + ldr x30, [x8] + mov sp, x9 + ret + +.global update_pgd +update_pgd: + 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 \ No newline at end of file diff --git a/lab7/lib/sched.c b/lab7/lib/sched.c new file mode 100644 index 000000000..7f1b3e08a --- /dev/null +++ b/lab7/lib/sched.c @@ -0,0 +1,116 @@ +#include "../include/sched.h" +#include "mm.h" +#include "mmu.h" +#include "exception.h" +#include "mini_uart.h" + +static struct task_struct init_task = INIT_TASK; +struct task_struct *current = &(init_task); +struct task_struct *task[NR_TASKS] = {&(init_task), }; +int nr_tasks = 1; + +void preempt_disable() { + current->preempt_count++; +} + +void preempt_enable() { + current->preempt_count--; +} + +void _schedule() { + + int next, c; + struct task_struct *p; + while (1) { + c = -1; + next = 0; + for (int i=0; istate == TASK_RUNNING && p->counter > c) { + c = p->counter; + next = i; + } + } + if (c) { + break; + } + for (int i=0; icounter = (p->counter >> 1) + p->priority; + } + } + preempt_disable(); // should be fine, if anything breaks move this to the top + switch_to(task[next]); + preempt_enable(); + +} + +void schedule() { + current->counter = 0; + _schedule(); +} + +void switch_to(struct task_struct *next) { + if (current == next) + return; + struct task_struct *prev = current; + current = next; + update_pgd(next->mm.pgd); + cpu_switch_to(prev, next); +} + +void schedule_tail() { + preempt_enable(); +} + +void timer_tick() { + + --current->counter; + if (current->counter > 0 || current->preempt_count > 0) + return; + + current->counter = 0; + enable_interrupt(); + _schedule(); + disable_interrupt(); + +} + +void exit_process() { + // should only be accessed using syscall + // preempt_disable(); + current->state = TASK_ZOMBIE; + //free((void*)current->stack); // free resources + // preempt_enable(); + schedule(); +} + +void kill_zombies() { + + struct task_struct *p; + for (int i=0; istate == TASK_ZOMBIE) { + printf("Zombie found with pid: %d.\n", p->id); + // for loop free user pages and kernel pages + for (int i=0; imm.user_pages_count; i++) { + free((void*)(p->mm.user_pages[i].phys_addr+VA_START)); + } + for (int i=0; imm.kernel_pages_count; i++) { + free((void*)(p->mm.kernel_pages[i]+VA_START)); + } + free(p); // free task struct + task[i] = NULL; + } + + } + +} \ No newline at end of file diff --git a/lab7/lib/shell.c b/lab7/lib/shell.c new file mode 100644 index 000000000..2dacd410b --- /dev/null +++ b/lab7/lib/shell.c @@ -0,0 +1,155 @@ +#include "shell.h" +#include "mini_uart.h" +#include "utils.h" +#include "mailbox.h" +#include "reboot.h" +#include "string.h" +#include "../include/cpio.h" +#include "memory.h" +#include "timer.h" +#include "exception.h" +#include "math.h" +#include "mm.h" +#include "../include/sched.h" +#include "syscall.h" +#include "peripherals/mailbox.h" +#include "fork.h" +#include "mmu.h" + + +#define MAX_BUFFER_SIZE 256u + +static char buffer[MAX_BUFFER_SIZE]; + +void start_video() { + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + void *code_loc; + + header = DEVTREE_CPIO_BASE; + printf("devtree base: 0x%x\n", DEVTREE_CPIO_BASE); + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) { + uart_send_string("file does not exist!\n"); + break; + } + + namesize = hexstr_to_uint(header->c_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, "vfs1.img", namesize) == 0) { + code_loc = ((void*)header) + offset; + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + printf("vfs1.img found in cpio at location 0x%x.\n", code_loc); + printf("vfs1.img has size of %d bytes.\n", (int)filesize); + + int err = move_to_user_mode((unsigned long)code_loc, filesize, 0); + if (err<0) + printf("failed to start video program\n"); + +} + +void read_cmd() +{ + unsigned int idx = 0; + char c = '\0'; + + while (1) { + c = uart_recv(); + if (c == '\r' || c == '\n') { + uart_send_string("\n"); + + if (idx < MAX_BUFFER_SIZE) buffer[idx] = '\0'; + else buffer[MAX_BUFFER_SIZE-1] = '\0'; + + break; + } else { + uart_send(c); + buffer[idx++] = c; + } + } + +} + +void parse_cmd() +{ + + if (stringcmp(buffer, "\0") == 0) + uart_send_string("\n"); + else if (stringcmp(buffer, "hello") == 0) + uart_send_string("Hello World!\n"); + else if (stringcmp(buffer, "reboot") == 0) { + uart_send_string("rebooting...\n"); + reset(100); + } + else if (stringcmp(buffer, "hwinfo") == 0) { + get_board_revision(); + get_arm_memory(); + } + else if (stringcmp(buffer, "ls") == 0) { + cpio_ls(); + } + else if (stringcmp(buffer, "cat") == 0) { + cpio_cat(); + } + else if (stringcmp(buffer, "execute") == 0) { + cpio_exec(); + } + else if (stringcmp(buffer, "video") == 0) { + preempt_disable(); + current->state = TASK_STOPPED; + unsigned long long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + copy_process(PF_KTHREAD, (unsigned long)&start_video, 0/*, 0*/); + preempt_enable(); + } + else if (stringcmp(buffer, "help") == 0) { + uart_send_string("help:\t\tprint list of available commands\n"); + uart_send_string("hello:\t\tprint Hello World!\n"); + uart_send_string("reboot:\t\treboot device\n"); + uart_send_string("hwinfo:\t\tprint hardware information\n"); + uart_send_string("ls:\t\tlist initramfs files\n"); + uart_send_string("cat:\t\tprint file content in initramfs\n"); + uart_send_string("execute:\trun program from cpio\n"); + } + else + uart_send_string("Command not found! Type help for commands.\n"); + +} + +void shell_loop() +{ + while (1) { + uart_send_string("% "); + read_cmd(); + parse_cmd(); + } +} \ No newline at end of file diff --git a/lab7/lib/string.c b/lab7/lib/string.c new file mode 100644 index 000000000..f74819f4d --- /dev/null +++ b/lab7/lib/string.c @@ -0,0 +1,55 @@ +#include "string.h" + +int stringcmp(const char *p1, const char *p2) +{ + const unsigned char *s1 = (const unsigned char *) p1; + const unsigned char *s2 = (const unsigned char *) p2; + unsigned char c1, c2; + + do { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0') + return c1 - c2; + } while (c1 == c2); + + return c1 - c2; +} + +int stringncmp(const char *p1, const char *p2, unsigned int n) +{ + for (int i=0; iid; +} + +unsigned sys_uartread(char buf[], unsigned size) { + for(unsigned int i=0; ic_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, name, namesize) == 0) { + code_loc = ((void*)header) + offset; + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + + void *move_loc = malloc(filesize + 4096); // an extra page for bss just in case + if(move_loc == NULL) return -1; + for (int i=0; ipc = 0; // move to beginning of program + p->sp = 0xfffffffff000; + + preempt_enable(); + + return -1; // only on failure*/ + // not real exec, only a restart of current process +} // fix + +int sys_fork() { + return copy_process(0, 0, 0/*, 0*/); +} + +void sys_exit(int status) { + exit_process(); +} + +int sys_mbox_call(unsigned char ch, volatile unsigned int *mbox) { + printf("mbox: 0x%x\n", mbox); + unsigned long ka_mbox = va2phys((unsigned long)mbox) + ((unsigned long)mbox&0xFFF); + printf("mbox kernel addr location: 0x%x\n", ka_mbox); + unsigned int r = (((unsigned int)((unsigned long)ka_mbox)&~0xF) | (ch&0xF)); + while(*MAILBOX_STATUS & MAILBOX_FULL); + *MAILBOX_WRITE = r; + while (1) { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) {} + if (r == *MAILBOX_READ) { + return ((unsigned int *)(ka_mbox+VA_START))[1]==REQUEST_SUCCEED; + } + } + return 0; +} + +void sys_kill(int pid) { + + struct task_struct *p; + for (int i=0; iid == (long)pid) { + preempt_disable(); + printf("Kill target acquired.\n"); + p->state = TASK_ZOMBIE; + //free((void *)p->stack); + preempt_enable(); + break; + } + + } + +} + +int sys_open(const char *pathname, int flags) { + printf("[debug] start of syscall open\n"); + struct file *f; + printf("[debug] test 0x%x\n", rootfs); + printf("[debug] test 0x%x\n", rootfs->root); + int res = vfs_open(pathname, flags, &f); + struct pt_regs *cur_regs = task_pt_regs(current); + + if (res == FAIL) { + cur_regs->regs[0] = -1; + return; + } + + int fd_num = current->files.count; + + current->files.fds[fd_num] = f; + current->files.count++; + cur_regs->regs[0] = fd_num; + printf("[debug] end of syscall open\n"); +} + +int sys_close(int fd) { + printf("[debug] start of syscall close\n"); + struct pt_regs *cur_regs = task_pt_regs(current); + if (fd < 0) { + cur_regs->regs[0] = -1; + return; + } + struct file *f = current->files.fds[fd]; + cur_regs->regs[0] = vfs_close(f); + current->files.fds[fd] = 0; + printf("[debug] end of syscall close\n"); +} + +long sys_write(int fd, const void *buf, unsigned long count) { + printf("[debug] start of syscall write\n"); + struct pt_regs *cur_regs = task_pt_regs(current); + if (fd < 0) { + cur_regs->regs[0] = -1; + return; + } + struct file *f = current->files.fds[fd]; + if (f == 0) { + cur_regs->regs[0] = 0; + return; + } + cur_regs->regs[0] = vfs_write(f, buf, count); + printf("[debug] end of syscall write\n"); +} + +long sys_read(int fd, void *buf, unsigned long count) { + printf("[debug] start of syscall read\n"); + struct pt_regs *cur_regs = task_pt_regs(current); + if (fd < 0) { + cur_regs->regs[0] = -1; + return; + } + struct file *f = current->files.fds[fd]; + if (f == 0) { + cur_regs->regs[0] = 0; + return; + } + cur_regs->regs[0] = vfs_read(f, buf, count); + printf("[debug] end of syscall read\n"); +} + +int sys_mkdir(const char *pathname, unsigned mode) { + printf("[debug] start of syscall mkdir\n"); + struct pt_regs *cur_regs = task_pt_regs(current); + cur_regs->regs[0] = vfs_mkdir(pathname); + printf("[debug] end of syscall mkdir\n"); +} + +int sys_mount(const char *src, const char *target, const char *fs, unsigned long flags, const void *data) { + printf("[debug] start of syscall mount\n"); + printf("[debug] end of syscall mount\n"); +} + +int sys_chdir(const char *path) { + printf("[debug] start of syscall chdir\n"); + struct pt_regs *cur_regs = task_pt_regs(current); + cur_regs->regs[0] = vfs_chdir(path); + printf("[debug] end of syscall chdir\n"); +} + +void * const sys_call_table[] = +{ + sys_getpid, + sys_uartread, + sys_uartwrite, + sys_exec, + sys_fork, + sys_exit, + sys_mbox_call, + sys_kill, + 0, + 0, + 0, + sys_open, + sys_close, + sys_write, + sys_read, + sys_mkdir, + sys_mount, + sys_chdir +}; \ No newline at end of file diff --git a/lab7/lib/timer.c b/lab7/lib/timer.c new file mode 100644 index 000000000..ae102a2b0 --- /dev/null +++ b/lab7/lib/timer.c @@ -0,0 +1,62 @@ +#include "timer.h" +#include "../include/sched.h" +#include "mini_uart.h" + +void timer_init() { + core_timer_enable(); + set_timer(read_freq()); +} + +void handle_timer_irq() { + //printf("Timer interrupt.\n"); + set_timer(read_freq()>>5); + timer_tick(); +} + +void core_timer_enable() { + + asm volatile( + "mov x0, 1\n\t" + "msr cntp_ctl_el0, x0\n\t" // enable + "mov x0, 2\n\t" + "ldr x1, =0x40000040\n\t" // CORE0_TIMER_IRQ_CTRL + "str w0, [x1]\n\t" // unmask timer interrupt + ); + +} + +void core_timer_disable() { + + asm volatile( + "mov x0, 0\n\t" + "ldr x1, =0x40000040\n\t" + "str w0, [x1]\n\t" + ); + +} + +void set_timer(unsigned int rel_time) { + + asm volatile( + "msr cntp_tval_el0, %0\n\t" + : + : "r" (rel_time) + ); + +} + +unsigned int read_timer() { + + unsigned int time; + asm volatile("mrs %0, cntpct_el0\n\t" : "=r" (time) : : "memory"); + return time; + +} + +unsigned int read_freq() { + + unsigned int freq; + asm volatile("mrs %0, cntfrq_el0\n\t": "=r" (freq) : : "memory"); + return freq; + +} diff --git a/lab7/lib/tmpfs.c b/lab7/lib/tmpfs.c new file mode 100644 index 000000000..234e3e598 --- /dev/null +++ b/lab7/lib/tmpfs.c @@ -0,0 +1,156 @@ +#include "tmpfs.h" +#include "mm.h" +#include "string.h" +#include "mini_uart.h" + + +struct vnode_operations *tmpfs_v_ops; +struct file_operations *tmpfs_f_ops; + +int tmpfs_setup_mount(struct filesystem* fs, struct mount* mount) { + + struct vnode *root_node = (struct vnode *)chunk_alloc(sizeof(struct vnode)); + struct tmpfs_internal *root_internal = (struct tmpfs_internal *)chunk_alloc(sizeof(struct tmpfs_internal)); + + root_internal->parent = root_internal; + root_internal->size = 0; + root_internal->type = DIRECTORY; + root_internal->vnode = root_node; + root_internal->data = 0; + + root_node->f_ops = tmpfs_f_ops; + root_node->v_ops = tmpfs_v_ops; + root_node->internal = (void *)root_internal; + root_node->mount = mount; + + mount->root = root_node; + mount->fs = fs; + + printf("[debug] setup root: 0x%x\n", mount); + printf("[debug] setup root vnode: 0x%x\n", root_node); + + return 0; +} + +int tmpfs_register(struct mount *mnt, struct vnode *root) { + + root->v_ops = (struct vnode_operations *) chunk_alloc(sizeof(struct vnode_operations)); + root->f_ops = (struct file_operations *) chunk_alloc(sizeof(struct file_operations)); + + root->v_ops->lookup = tmpfs_lookup; + root->v_ops->create = tmpfs_create; + root->v_ops->mkdir = tmpfs_mkdir; + + root->f_ops->open = tmpfs_open; + root->f_ops->read = tmpfs_read; + root->f_ops->write = tmpfs_write; + root->f_ops->close = tmpfs_close; + + return 0; +} + +int tmpfs_open(struct vnode* file_node, struct file** target) { + return SUCCESS; +} + +int tmpfs_close(struct file *file) { + if (file) + return SUCCESS; + else + return FAIL; +} + +int tmpfs_write(struct file *file, const void *buf, unsigned len) { + struct tmpfs_internal *internal = (struct tmpfs_internal*)file->vnode->internal; + if (((struct tmpfs_internal *)file->vnode->internal)->type != REGULAR_FILE) + return FAIL; + + char *dest = &((char *)internal->data)[file->f_pos]; + char *src = (char *)buf; + int i = 0; + for (; i < len && src[i] != '\0'; i++) { + dest[i] = src[i]; + } + dest[i] = EOF; + + return i; +} + +int tmpfs_read(struct file *file, void *buf, unsigned len) { + struct tmpfs_internal *internal = (struct tmpfs_internal*)file->vnode->internal; + if (internal->type != REGULAR_FILE) + return FAIL; + + char *dest = (char*)buf; + char *src = &((char *)internal->data)[file->f_pos]; + int i = 0; + for (; idata)+MAX_FILESIZE; i++) { + dest[i] = src[i]; + } + + return i; +} + +int tmpfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name) { + struct tmpfs_internal *file_node = (struct tmpfs_internal *)chunk_alloc(sizeof(struct tmpfs_internal)); + struct vnode *new_node = (struct vnode *)chunk_alloc(sizeof(struct vnode)); + + strcpy(file_node->name, component_name); + file_node->type = REGULAR_FILE; + file_node->parent = (struct tmpfs_internal *)dir_node->internal; + file_node->vnode = new_node; + file_node->size = 0; + file_node->data = malloc(MAX_FILESIZE); + + file_node->vnode->f_ops = tmpfs_f_ops; + file_node->vnode->internal = (void *)file_node; + file_node->vnode->mount = 0; + file_node->vnode->v_ops = 0; + + struct tmpfs_internal *parent_internal = (struct tmpfs_internal *)dir_node->internal; + parent_internal->child[parent_internal->size] = file_node; + parent_internal->size++; + + *target = file_node->vnode; + return SUCCESS; +} + +int tmpfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name) { + struct tmpfs_internal *dir_internal = (struct tmpfs_internal *)chunk_alloc(sizeof(struct tmpfs_internal)); + struct vnode *new_node = (struct vnode *)chunk_alloc(sizeof(struct vnode)); + + strcpy(dir_internal->name, component_name); + dir_internal->type = DIRECTORY; + dir_internal->parent = (struct tmpfs_internal *)dir_node->internal; + dir_internal->vnode = new_node; + dir_internal->size = 0; + dir_internal->data = 0; + + dir_internal->vnode->f_ops = tmpfs_f_ops; + dir_internal->vnode->internal = (void *)dir_internal; + dir_internal->vnode->mount = 0; + dir_internal->vnode->v_ops = tmpfs_v_ops; + + struct tmpfs_internal *parent_internal = (struct tmpfs_internal *)dir_node->internal; + parent_internal->child[parent_internal->size] = dir_internal; + parent_internal->size++; + + *target = dir_internal->vnode; + return SUCCESS; +} + +int tmpfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name) { + struct tmpfs_internal *internal = (struct tmpfs_internal *)dir_node->internal; + if (internal->type != DIRECTORY) { + return FAIL; + } + + for (int i=0; isize; i++) { + if(stringcmp(internal->child[i]->name, component_name) == 0) { + *target = internal->child[i]->vnode; + return i; + } + } + + return FAIL; +} diff --git a/lab7/lib/utils.S b/lab7/lib/utils.S new file mode 100644 index 000000000..aa0e55aa9 --- /dev/null +++ b/lab7/lib/utils.S @@ -0,0 +1,15 @@ +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret \ No newline at end of file diff --git a/lab7/lib/vfs.c b/lab7/lib/vfs.c new file mode 100644 index 000000000..ba581ea97 --- /dev/null +++ b/lab7/lib/vfs.c @@ -0,0 +1,146 @@ +#include "vfs.h" +#include "tmpfs.h" +#include "string.h" +#include "mm.h" +#include "mini_uart.h" + +struct mount *rootfs; + +void rootfs_init() { + + struct filesystem *tmpfs = (struct filesystem *)chunk_alloc(sizeof(struct filesystem)); + tmpfs->name = (char *)chunk_alloc(TMPFS_COMP_LEN); + strcpy(tmpfs->name, "tmpfs"); + tmpfs->setup_mount = tmpfs_setup_mount; + register_fs(tmpfs); + + rootfs = (struct mount *)chunk_alloc(sizeof(struct mount)); + tmpfs->setup_mount(tmpfs, rootfs); + + printf("[debug] confirm root vnode: 0x%x\n", rootfs->root); + +} + +int register_fs(struct filesystem *fs) { + if (stringcmp(fs->name, "tmpfs")) { + return tmpfs_register(); + } + return -1; +} + +int vfs_open(const char *pathname, int flags, struct file **target) { + printf("[debug] start of vfs_open\n"); + *target = 0; + struct vnode *target_dir; + char target_path[VFS_PATHMAX]; + traverse(pathname, &target_dir, target_path); + printf("[debug] traverse complete\n"); + struct vnode *target_file; + if (target_dir->v_ops->lookup(target_dir, &target_file, target_path) == 0) { + printf("[debug] vfs_open: open\n"); + *target = (struct file *)chunk_alloc(sizeof(struct file)); + (*target)->vnode = target_file; + (*target)->f_pos = 0; + (*target)->f_ops = target_file->f_ops; + (*target)->flags = flags; + return (*target)->f_ops->open(target_file, target); + } else if (flags & O_CREAT) { + printf("[debug] vfs_open: create and open\n"); + int res = target_dir->v_ops->create(target_dir, &target_file, target_path); + if (res < 0) return FAIL; + *target = (struct file *)chunk_alloc(sizeof(struct file)); + (*target)->vnode = target_file; + (*target)->f_pos = 0; + (*target)->f_ops = target_file->f_ops; + (*target)->flags = flags; + return (*target)->f_ops->open(target_file, target); + } else return FAIL; +} + +int vfs_close(struct file *file) { + int code = file->f_ops->close(file); + if (code == SUCCESS) + chunk_free(file); + return code; +} + +int vfs_write(struct file *file, const void *buf, unsigned len) { + return file->f_ops->write(file, buf, len); +} + +int vfs_read(struct file *file, void *buf, unsigned len) { + return file->f_ops->read(file, buf, len); +} + +int vfs_mkdir(const char *pathname) { + struct vnode *target_dir; + char child_name[VFS_PATHMAX]; + traverse(pathname, &target_dir, child_name); + struct vnode *child_dir; + int res = target_dir->v_ops->mkdir(target_dir, &child_dir, child_name); + if (res < 0) return res; + return SUCCESS; +} + +int vfs_mount(const char *target, const char *filesystem) { + return SUCCESS; +} + +int vfs_lookup(const char *pathname, struct vnode **target) { + return SUCCESS; // unused +} + +int vfs_chdir(const char *pathname) { + struct vnode *target_dir; + char path_remain[VFS_PATHMAX]; + traverse(pathname, &target_dir, path_remain); + if (stringcmp(path_remain, "") == 0) { + return FAIL; + } else { + current->cwd = target_dir; + return SUCCESS; + } +} + +void traverse(const char* pathname, struct vnode **target_node, char *target_path) { + if (pathname[0] == '/') { + printf("[debug] traverse absolute path: %s\n", pathname); + printf("[debug] root: 0x%x\n", rootfs); + printf("[debug] root vnode: 0x%x\n", rootfs->root); + struct vnode *rootnode = rootfs->root; + printf("[debug] here -1\n"); + r_traverse(rootnode, pathname + 1, target_node, target_path); + } else { + printf("[debug] traverse relative path\n"); + } +} + +void r_traverse(struct vnode *node, const char *path, struct vnode **target_node, char *target_path) { + printf("[debug] begin r_traverse\n"); + int i = 0; + while (path[i]) { + if (path[i] == '/') break; + target_path[i] = path[i]; + i++; + } + printf("[debug] here\n"); + target_path[i++] = '\0'; + *target_node = node; + + printf("[debug] r_traverse target path: %s\n", target_path); + + if (stringcmp(target_path, "") == 0) { + return; + } + else if (stringcmp(target_path, ".") == 0) { + + } + else if (stringcmp(target_path, "..") == 0) { + + } + + int res = node->v_ops->lookup(node, target_node, target_path); + if (res != FAIL) + r_traverse(*target_node, path+i, target_node, target_path); + +} diff --git a/lab7/send_img.py b/lab7/send_img.py new file mode 100644 index 000000000..b2261950d --- /dev/null +++ b/lab7/send_img.py @@ -0,0 +1,31 @@ +import argparse +import os +import time +import math +import serial + +parser = argparse.ArgumentParser(description='*.img uart sender') +parser.add_argument('-i', '--img', default='kernel8.img', type=str) +parser.add_argument('-d', '--device', default='/dev/ttyUSB0', type=str) +parser.add_argument('-b', '--baud', default=115200, type=int) + +args = parser.parse_args() + +img_size = os.path.getsize(args.img) + +with open(args.img, 'rb') as f: + with serial.Serial(args.device, args.baud) as tty: + + print(f'{args.img} is {img_size} bytes') + print('img file is now sending') + + tty.write(img_size.to_bytes(4, 'big')) + + input() + + for i in range(img_size): + tty.write(f.read(1)) + tty.flush() + #time.sleep(0.0001) + + print('img sent') diff --git a/lab7_novm/bcm2710-rpi-3-b-plus.dtb b/lab7_novm/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..3934b3a26 Binary files /dev/null and b/lab7_novm/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab7_novm/config.txt b/lab7_novm/config.txt new file mode 100644 index 000000000..49fc25695 --- /dev/null +++ b/lab7_novm/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x20000000 diff --git a/lab7_novm/include/cpio.h b/lab7_novm/include/cpio.h new file mode 100644 index 000000000..1735f5fe5 --- /dev/null +++ b/lab7_novm/include/cpio.h @@ -0,0 +1,49 @@ +#ifndef __CPIO_H__ +#define __CPIO_H__ + +/* +Each file system object in a cpio archive comprises a header record with +basic numeric metadata followed by the full pathname of the entry and the +file data. The header record stores a series of integer values that gen- +erally follow the fields in struct stat. (See stat(2) for details.) The +variants differ primarily in how they store those integers (binary, oc- +tal, or hexadecimal). The header is followed by the pathname of the en- +try (the length of the pathname is stored in the header) and any file +data. The end of the archive is indicated by a special record with the +pathname "TRAILER!!!" +*/ + +#define CPIO_HEADER_MAGIC "070701" +#define CPIO_FOOTER_MAGIC "TRAILER!!!" +#define PI_CPIO_BASE ((void*) (0x20000000)) +#define QEMU_CPIO_BASE ((void*) (0x8000000)) + +#include "devtree.h" + +extern void *DEVTREE_CPIO_BASE; + +struct cpio_newc_header { + char c_magic[6]; // 070701 + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; // ignored by readers +}; + +void initramfs_callback (char *, char *, struct fdt_prop *); +void cpio_ls (); +void cpio_cat (); +void cpio_exec (); + +unsigned int hexstr_to_uint(char *s, unsigned int len); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/devtree.h b/lab7_novm/include/devtree.h new file mode 100644 index 000000000..d8225b11c --- /dev/null +++ b/lab7_novm/include/devtree.h @@ -0,0 +1,64 @@ +#ifndef _DEVTREE_H +#define _DEVTREE_H + +/* + magic; 0xd00dfeed (big-endian) + + totalsize; total size in bytes of the devicetree + data structure + + off_dt_struct; offset in bytes of the structure block + from the beginning of the header + + off_dt_strings; offset in bytes of the strings block + from the beginning of the header + + off_mem_rsvmap; offset in bytes of the memory reservation + block from the beginning of the header + + version; version of the devicetree data structure + + last_comp_version; lowest version of the devicetree data + structure with which the version used is backwards compatible + + boot_cpuid_phys; physical ID of the system’s boot CPU + + size_dt_strings; length in bytes of the strings block + section of the devicetree blob + + size_dt_struct; length in bytes of the structure block + section of the devicetree blob +*/ + +#define FDT_HEADER_MAGIC 0xd00dfeed +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +struct fdt_header { + unsigned int magic; + unsigned int totalsize; + unsigned int off_dt_struct; + unsigned int off_dt_strings; + unsigned int off_mem_rsvmap; + unsigned int version; + unsigned int last_comp_version; + unsigned int boot_cpuid_phys; + unsigned int size_dt_strings; + unsigned int size_dt_struct; +}; + +struct fdt_prop { + unsigned int len; + unsigned int nameoff; +}; + +void devtree_getaddr (); +void fdt_traverse ( void (*callback)(char *, char *, struct fdt_prop *) ); + +// ARM uses little endian +unsigned int to_lendian (unsigned int); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/entry.h b/lab7_novm/include/entry.h new file mode 100644 index 000000000..1a22d0284 --- /dev/null +++ b/lab7_novm/include/entry.h @@ -0,0 +1,39 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#define S_FRAME_SIZE 272 // size of all saved registers +#define S_X0 0 + +#define SYNC_INVALID_EL1t 0 +#define IRQ_INVALID_EL1t 1 +#define FIQ_INVALID_EL1t 2 +#define ERROR_INVALID_EL1t 3 + +#define SYNC_INVALID_EL1h 4 +#define IRQ_INVALID_EL1h 5 +#define FIQ_INVALID_EL1h 6 +#define ERROR_INVALID_EL1h 7 + +#define SYNC_INVALID_EL0_64 8 +#define IRQ_INVALID_EL0_64 9 +#define FIQ_INVALID_EL0_64 10 +#define ERROR_INVALID_EL0_64 11 + +#define SYNC_INVALID_EL0_32 12 +#define IRQ_INVALID_EL0_32 13 +#define FIQ_INVALID_EL0_32 14 +#define ERROR_INVALID_EL0_32 15 + +#define SYNC_ERROR 16 +#define SYSCALL_ERROR 17 + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 + +#ifndef __ASSEMBLER__ + +void ret_from_fork(); + +#endif + +#endif \ No newline at end of file diff --git a/lab7_novm/include/exception.h b/lab7_novm/include/exception.h new file mode 100644 index 000000000..40f4ba532 --- /dev/null +++ b/lab7_novm/include/exception.h @@ -0,0 +1,7 @@ +#ifndef _EXCEPTION_H +#define _EXCEPTION_H + +void enable_interrupt(); +void disable_interrupt(); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/fork.h b/lab7_novm/include/fork.h new file mode 100644 index 000000000..7b018dc68 --- /dev/null +++ b/lab7_novm/include/fork.h @@ -0,0 +1,26 @@ +#ifndef _FORK_H +#define _FORK_H + +#include "sched.h" + +#define PSR_MODE_EL0t 0x00000000 +#define PSR_MODE_EL1t 0x00000004 +#define PSR_MODE_EL1h 0x00000005 +#define PSR_MODE_EL2t 0x00000008 +#define PSR_MODE_EL2h 0x00000009 +#define PSR_MODE_EL3t 0x0000000c +#define PSR_MODE_EL3h 0x0000000d + +int copy_process(unsigned long, unsigned long, unsigned long, unsigned long); +int move_to_user_mode(unsigned long); +struct pt_regs *task_pt_regs(struct task_struct *); +void new_user_process(unsigned long); + +struct pt_regs { + unsigned long regs[31]; + unsigned long sp; + unsigned long pc; + unsigned long pstate; +}; + +#endif \ No newline at end of file diff --git a/lab7_novm/include/initramfs.h b/lab7_novm/include/initramfs.h new file mode 100644 index 000000000..80e9c9733 --- /dev/null +++ b/lab7_novm/include/initramfs.h @@ -0,0 +1,35 @@ +#ifndef _INITRAMFS_H +#define _INITRAMFS_H + +#include "vfs.h" + +#define INITRAMFS_COMP_LEN 16 +#define MAX_DIRENT 16 +#define MAX_FILESIZE 0x1000 + +struct initramfs_internal { + char name[INITRAMFS_COMP_LEN]; + int type; + struct initramfs_internal *parent; + struct initramfs_internal *child[MAX_DIRENT]; + struct vnode *vnode; + int size; // use for child count and data size + void *data; +}; + +int initramfs_setup_mount(struct filesystem* fs, struct mount* mount); +int initramfs_register(); + +struct vnode* initramfs_new_node(struct initramfs_internal *parent, const char *name, int type); + +int initramfs_open(struct vnode *file_node, struct file **target); +int initramfs_close(struct file *file); +int initramfs_write(struct file *file, const void *buf, unsigned len); +int initramfs_read(struct file *file, void *buf, unsigned len); +int initramfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int initramfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +int initramfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); + +void parse_initramfs(); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/mailbox.h b/lab7_novm/include/mailbox.h new file mode 100644 index 000000000..eeecaa9de --- /dev/null +++ b/lab7_novm/include/mailbox.h @@ -0,0 +1,7 @@ +#ifndef _MAILBOX_H +#define _MAILBOX_H + +void get_board_revision (); +void get_arm_memory (); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/math.h b/lab7_novm/include/math.h new file mode 100644 index 000000000..353ccfb26 --- /dev/null +++ b/lab7_novm/include/math.h @@ -0,0 +1,7 @@ +#ifndef _MATH_H +#define _MATH_H + +int log(int, int); +int pow(int, int); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/memory.h b/lab7_novm/include/memory.h new file mode 100644 index 000000000..956f6e955 --- /dev/null +++ b/lab7_novm/include/memory.h @@ -0,0 +1,8 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#define MAX_HEAP_SIZE 0x10000000 + +void* simple_malloc(unsigned int); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/mini_uart.h b/lab7_novm/include/mini_uart.h new file mode 100644 index 000000000..453ec93f2 --- /dev/null +++ b/lab7_novm/include/mini_uart.h @@ -0,0 +1,10 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void uart_init ( void ); +char uart_recv ( void ); +void uart_send ( char c ); +void uart_send_string ( char* str ); +void printf ( char *fmt, ... ); + +#endif /*_MINI_UART_H */ \ No newline at end of file diff --git a/lab7_novm/include/mm.h b/lab7_novm/include/mm.h new file mode 100644 index 000000000..df97f2b89 --- /dev/null +++ b/lab7_novm/include/mm.h @@ -0,0 +1,55 @@ +#ifndef _MM_H +#define _MM_H + +#define MEM_REGION_BEGIN 0x0 +#define MEM_REGION_END 0x3C000000 +#define PAGE_SIZE 4096 +#define MAX_ORDER 8 // largest: PAGE_SIZE*2^(MAX_ORDER) + +#define ALLOCABLE 0 +#define ALLOCATED -1 +#define C_NALLOCABLE -2 +#define RESERVED -3 + +#define NULL 0 + +#define MAX_POOL_PAGES 8 +#define MAX_POOLS 8 +#define MIN_CHUNK_SIZE 8 + +#define MAX_RESERVABLE 8 + +struct frame { + unsigned int index; + int val; + int state; + struct frame *prev, *next; +}; + +struct node { + struct node *next; +}; + +struct dynamic_pool { + unsigned int chunk_size; + unsigned int chunks_per_page; + unsigned int chunks_allocated; + unsigned int page_new_chunk_off; + unsigned int pages_used; + void *page_base_addrs[MAX_POOL_PAGES]; + struct node *free_head; +}; + +void *malloc(unsigned int); +void free(void *); +void init_mm(); +void init_pool(struct dynamic_pool*, unsigned int); +int register_chunk(unsigned int); +void *chunk_alloc(unsigned int); +void chunk_free(void *); +void memory_reserve(void*, void*); +void init_mm_reserve(); + +void memzero(unsigned long, unsigned long); + +#endif /*_MM_H */ \ No newline at end of file diff --git a/lab7_novm/include/peripherals/base.h b/lab7_novm/include/peripherals/base.h new file mode 100644 index 000000000..8f66cd5fe --- /dev/null +++ b/lab7_novm/include/peripherals/base.h @@ -0,0 +1,6 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +#define PBASE 0x3F000000 + +#endif /*_P_BASE_H */ \ No newline at end of file diff --git a/lab7_novm/include/peripherals/exception.h b/lab7_novm/include/peripherals/exception.h new file mode 100644 index 000000000..bc64c7c53 --- /dev/null +++ b/lab7_novm/include/peripherals/exception.h @@ -0,0 +1,25 @@ +#ifndef _P_EXCEPTION_H +#define _P_EXCEPTION_H + +#include "peripherals/base.h" + +#define IRQ_BASIC_PENDING (PBASE+0x0000B200) +#define IRQ_PENDING_1 (PBASE+0x0000B204) +#define IRQ_PENDING_2 (PBASE+0x0000B208) +#define FIQ_CONTROL (PBASE+0x0000B20C) +#define ENABLE_IRQS_1 (PBASE+0x0000B210) +#define ENABLE_IRQS_2 (PBASE+0x0000B214) +#define ENABLE_BASIC_IRQS (PBASE+0x0000B218) +#define DISABLE_IRQS_1 (PBASE+0x0000B21C) +#define DISABLE_IRQS_2 (PBASE+0x0000B220) +#define DISABLE_BASIC_IRQS (PBASE+0x0000B224) + +#define CNTPCT_EL0 (0x4000001C) +#define CNTP_CTL_EL0 (0x40000040) +#define CORE0_INTERRUPT_SRC (0x40000060) + +#define IRQ_PENDING_1_AUX_INT (1<<29) +#define INTERRUPT_SOURCE_GPU (1<<8) +#define INTERRUPT_SOURCE_CNTPNSIRQ (1<<1) + +#endif \ No newline at end of file diff --git a/lab7_novm/include/peripherals/gpio.h b/lab7_novm/include/peripherals/gpio.h new file mode 100644 index 000000000..c5d7d138f --- /dev/null +++ b/lab7_novm/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _P_GPIO_H +#define _P_GPIO_H + +#include "peripherals/base.h" + +#define GPFSEL1 (PBASE+0x00200004) +#define GPSET0 (PBASE+0x0020001C) +#define GPCLR0 (PBASE+0x00200028) +#define GPPUD (PBASE+0x00200094) +#define GPPUDCLK0 (PBASE+0x00200098) + +#endif /*_P_GPIO_H */ \ No newline at end of file diff --git a/lab7_novm/include/peripherals/mailbox.h b/lab7_novm/include/peripherals/mailbox.h new file mode 100644 index 000000000..0351bd714 --- /dev/null +++ b/lab7_novm/include/peripherals/mailbox.h @@ -0,0 +1,23 @@ +#ifndef _P_MAILBOX_H +#define _P_MAILBOX_H + +#define MMIO_BASE 0x3f000000 +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#define MAILBOX_READ (volatile unsigned int*) (MAILBOX_BASE) +#define MAILBOX_STATUS (volatile unsigned int*) (MAILBOX_BASE + 0x18) +#define MAILBOX_WRITE (volatile unsigned int*) (MAILBOX_BASE + 0x20) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 + +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +#endif \ No newline at end of file diff --git a/lab7_novm/include/peripherals/mini_uart.h b/lab7_novm/include/peripherals/mini_uart.h new file mode 100644 index 000000000..386b6fade --- /dev/null +++ b/lab7_novm/include/peripherals/mini_uart.h @@ -0,0 +1,19 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_ENABLES (PBASE+0x00215004) +#define AUX_MU_IO_REG (PBASE+0x00215040) +#define AUX_MU_IER_REG (PBASE+0x00215044) +#define AUX_MU_IIR_REG (PBASE+0x00215048) +#define AUX_MU_LCR_REG (PBASE+0x0021504C) +#define AUX_MU_MCR_REG (PBASE+0x00215050) +#define AUX_MU_LSR_REG (PBASE+0x00215054) +#define AUX_MU_MSR_REG (PBASE+0x00215058) +#define AUX_MU_SCRATCH (PBASE+0x0021505C) +#define AUX_MU_CNTL_REG (PBASE+0x00215060) +#define AUX_MU_STAT_REG (PBASE+0x00215064) +#define AUX_MU_BAUD_REG (PBASE+0x00215068) + +#endif /*_P_MINI_UART_H */ \ No newline at end of file diff --git a/lab7_novm/include/printf.h b/lab7_novm/include/printf.h new file mode 100644 index 000000000..dfedbe301 --- /dev/null +++ b/lab7_novm/include/printf.h @@ -0,0 +1,31 @@ +/* + * 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. + * + */ +#ifndef _PRINTF_H +#define _PRINTF_H + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/reboot.h b/lab7_novm/include/reboot.h new file mode 100644 index 000000000..df4d63a86 --- /dev/null +++ b/lab7_novm/include/reboot.h @@ -0,0 +1,7 @@ +#ifndef _REBOOT_H +#define _REBOOT_H + +void reset ( int ); +void cancel_reset (); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/sched.h b/lab7_novm/include/sched.h new file mode 100644 index 000000000..d36d6e8ac --- /dev/null +++ b/lab7_novm/include/sched.h @@ -0,0 +1,78 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#define THREAD_CPU_CONTEXT 0 + +#ifndef __ASSEMBLER__ + +#include "vfs.h" + +#define THREAD_SIZE 4096 + +#define NR_TASKS 64 + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 + +#define PF_KTHREAD 0x00000002 + +extern struct task_struct *current; +extern struct task_struct *task[NR_TASKS]; +extern int nr_tasks; + +struct cpu_context { + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long sp; + unsigned long pc; +}; + +struct task_struct { + struct cpu_context cpu_context; + long state; + long counter; + long priority; + long preempt_count; + unsigned long stack; + unsigned long flags; + long id; + struct fd_table files; + struct vnode *cwd; +}; + +extern void sched_init(); +extern void schedule(); +extern void timer_tick(); +extern void preempt_disable(); +extern void preempt_enable(); +extern void switch_to(struct task_struct *); +extern void cpu_switch_to(struct task_struct *, struct task_struct *); +extern void exit_process(); +extern void kill_zombies(); + +#define INIT_TASK \ +{ \ +{0,0,0,0,0,0,0,0,0,0,0,0,0},\ +0, 0, 1, 0, 0, PF_KTHREAD, 0, \ +{0, {0}},\ +0 \ +} + +#endif + +#endif \ No newline at end of file diff --git a/lab7_novm/include/shell.h b/lab7_novm/include/shell.h new file mode 100644 index 000000000..828c56763 --- /dev/null +++ b/lab7_novm/include/shell.h @@ -0,0 +1,6 @@ +#ifndef _SHELL_H +#define _SHELL_H + +void shell_loop (); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/string.h b/lab7_novm/include/string.h new file mode 100644 index 000000000..c71840033 --- /dev/null +++ b/lab7_novm/include/string.h @@ -0,0 +1,10 @@ +#ifndef _STRING_H +#define _STRING_H + +int stringcmp (const char *, const char *); +int stringncmp (const char *, const char *, unsigned int); +unsigned int strlen(const char *); +void strcpy(char *dest, const char *src); +void strncpy(char *dest, const char *src, int n); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/syscall.h b/lab7_novm/include/syscall.h new file mode 100644 index 000000000..429be1390 --- /dev/null +++ b/lab7_novm/include/syscall.h @@ -0,0 +1,59 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +#define __NR_SYSCALLS 18 + +#define SYS_GETPID_NUM 0 +#define SYS_UARTREAD_NUM 1 +#define SYS_UARTWRITE_NUM 2 +#define SYS_EXEC_NUM 3 +#define SYS_FORK_NUM 4 +#define SYS_EXIT_NUM 5 +#define SYS_MBOXCALL_NUM 6 +#define SYS_KILL_NUM 7 + +#define SYS_OPEN_NUM 11 +#define SYS_CLOSE_NUM 12 +#define SYS_WRITE_NUM 13 +#define SYS_READ_NUM 14 +#define SYS_MKDIR_NUM 15 +#define SYS_MOUNT_NUM 16 +#define SYS_CHDIR_NUM 17 + +#ifndef __ASSEMBLER__ + +int getpid(); +unsigned uart_read(char buf[], unsigned size); +unsigned uart_write(const char buf[], unsigned size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(int status); +int mbox_call(unsigned char ch, volatile unsigned int *mbox); +void kill(int pid); +int open(const char *pathname, int flags); +int close(int fd); +long write(int fd, const void *buf, unsigned long count); +long read(int fd, void *buf, unsigned long count); +int mkdir(const char *pathname, unsigned mode); +int mount(const char *src, const char *target, const char *fs, unsigned long flags, const void *data); +int chdir(const char *path); + +int sys_getpid(); +unsigned sys_uartread(char buf[], unsigned size); +unsigned sys_uartwrite(const char buf[], unsigned size); +int sys_exec(const char *name, char *const argv[]); +int sys_fork(); +void sys_exit(int status); +int sys_mbox_call(unsigned char ch, unsigned int *mbox); +void sys_kill(int pid); +int sys_open(const char *pathname, int flags); +int sys_close(int fd); +long sys_write(int fd, const void *buf, unsigned long count); +long sys_read(int fd, void *buf, unsigned long count); +int sys_mkdir(const char *pathname, unsigned mode); +int sys_mount(const char *src, const char *target, const char *fs, unsigned long flags, const void *data); +int sys_chdir(const char *path); + +#endif + +#endif \ No newline at end of file diff --git a/lab7_novm/include/timer.h b/lab7_novm/include/timer.h new file mode 100644 index 000000000..9812a457a --- /dev/null +++ b/lab7_novm/include/timer.h @@ -0,0 +1,14 @@ +#ifndef _TIMER_H +#define _TIMER_H + +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +void timer_init(); +void handle_timer_irq(); +void core_timer_enable(); +void core_timer_disable(); +void set_timer(unsigned int rel_time); +unsigned int read_timer(); +unsigned int read_freq(); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/tmpfs.h b/lab7_novm/include/tmpfs.h new file mode 100644 index 000000000..f01824281 --- /dev/null +++ b/lab7_novm/include/tmpfs.h @@ -0,0 +1,33 @@ +#ifndef _TMPFS_H +#define _TMPFS_H + +#include "vfs.h" + +#define TMPFS_COMP_LEN 16 +#define MAX_DIRENT 16 +#define MAX_FILESIZE 0x1000 + +struct tmpfs_internal { + char name[TMPFS_COMP_LEN]; + int type; + struct tmpfs_internal *parent; + struct tmpfs_internal *child[MAX_DIRENT]; + struct vnode *vnode; + int size; // use for child count and data size + void *data; +}; + +int tmpfs_setup_mount(); +int tmpfs_register(); + +struct vnode* tmpfs_new_node(struct tmpfs_internal *parent, const char *name, int type); + +int tmpfs_open(struct vnode *file_node, struct file **target); +int tmpfs_close(struct file *file); +int tmpfs_write(struct file *file, const void *buf, unsigned len); +int tmpfs_read(struct file *file, void *buf, unsigned len); +int tmpfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); + +#endif \ No newline at end of file diff --git a/lab7_novm/include/utils.h b/lab7_novm/include/utils.h new file mode 100644 index 000000000..9d950d477 --- /dev/null +++ b/lab7_novm/include/utils.h @@ -0,0 +1,8 @@ +#ifndef _BOOT_H +#define _BOOT_H + +extern void delay ( unsigned long ); +extern void put32 ( unsigned long, unsigned int ); +extern unsigned int get32 ( unsigned long ); + +#endif /*_BOOT_H */ \ No newline at end of file diff --git a/lab7_novm/include/vfs.h b/lab7_novm/include/vfs.h new file mode 100644 index 000000000..d6b59781a --- /dev/null +++ b/lab7_novm/include/vfs.h @@ -0,0 +1,81 @@ +#ifndef _VFS_H +#define _VFS_H + +struct vnode { + struct vnode* parent; + struct mount* mount; + struct vnode_operations* v_ops; + struct file_operations* f_ops; + void* internal; +}; + +// file handle +struct file { + struct vnode* vnode; + unsigned f_pos; // RW position of this file handle + struct file_operations* f_ops; + int flags; +}; + +struct mount { + struct vnode* root; + struct filesystem* fs; +}; + +struct filesystem { + char* name; + int (*setup_mount)(struct filesystem* fs, struct mount* mount); +}; + +struct file_operations { + int (*write)(struct file* file, const void* buf, unsigned len); + int (*read)(struct file* file, void* buf, unsigned len); + int (*open)(struct vnode* file_node, struct file** target); + int (*close)(struct file* file); +}; + +struct vnode_operations { + int (*lookup)(struct vnode* dir_node, struct vnode** target, + const char* component_name); + int (*create)(struct vnode* dir_node, struct vnode** target, + const char* component_name); + int (*mkdir)(struct vnode* dir_node, struct vnode** target, + const char* component_name); +}; + +struct fd_table { + int count; + struct file *fds[16]; +}; + +#define VFS_PATHMAX 256 + +#define REGULAR_FILE -2 +#define DIRECTORY -3 + +#define O_CREAT 00000100 +#define SUCCESS 0 +#define FAIL -1 +#define EOF -1 + +extern struct mount *rootfs; + +void rootfs_init(); +void initramfs_init(); + +int register_fs(struct filesystem *fs); +struct file* create_fd(struct vnode* target, int flags); +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, unsigned len); +int vfs_read(struct file *file, void *buf, unsigned len); + +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 vfs_chdir(const char *pathname); + +void traverse(const char* pathname, struct vnode** target_node, char *target_path); +void r_traverse(struct vnode *node, const char *path, struct vnode **target_node, char *target_path); + +#endif \ No newline at end of file diff --git a/lab7_novm/initramfs.cpio b/lab7_novm/initramfs.cpio new file mode 100644 index 000000000..6fcebfdf9 Binary files /dev/null and b/lab7_novm/initramfs.cpio differ diff --git a/lab7_novm/kernel/Makefile b/lab7_novm/kernel/Makefile new file mode 100644 index 000000000..831618b19 --- /dev/null +++ b/lab7_novm/kernel/Makefile @@ -0,0 +1,49 @@ +AARCH64_PREFIX = aarch64-linux-gnu- +CC = $(AARCH64_PREFIX)gcc +LD = $(AARCH64_PREFIX)ld +OBJCPY = $(AARCH64_PREFIX)objcopy +GDB = $(AARCH64_PREFIX)gdb + +CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding -I../include -mgeneral-regs-only +ASMFLAGS = -I../include + +BUILD_DIR = ../build + +.PHONY: all clean qemu gdb_start + +all: kernel8.img + +clean: + rm kernel8.img $(OBJ_FILES) $(BUILD_DIR)/$(DEP_FILES) \ + ../build/kernel8.elf + +$(BUILD_DIR)/%_c.o: %.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: %.S + $(CC) $(ASMFLAGS) -MMD -c $< -o $@ + +C_FILES = $(wildcard *.c) +ASM_FILES = $(wildcard *.S) +OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) + +LIBC_FILES = $(wildcard ../lib/*.c) +LIBASM_FILES = $(wildcard ../lib/*.S) +LIBOBJ_FILES = $(LIBC_FILES:../lib/%.c=$(BUILD_DIR)/%_c.o) +LIBOBJ_FILES += $(LIBASM_FILES:../lib/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) $(LIBOBJ_FILES) + $(LD) -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) $(LIBOBJ_FILES) + $(OBJCPY) $(BUILD_DIR)/kernel8.elf -O binary $@ + +qemu: # all in one qemu command + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -S -s -serial null -serial pty \ + -initrd ../initramfs.cpio -dtb ../bcm2710-rpi-3-b-plus.dtb + +gdb_start: + $(GDB) $(BUILD_DIR)/kernel8.elf diff --git a/lab7_novm/kernel/boot_kernel.S b/lab7_novm/kernel/boot_kernel.S new file mode 100644 index 000000000..649bc4c69 --- /dev/null +++ b/lab7_novm/kernel/boot_kernel.S @@ -0,0 +1,41 @@ +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 + and x0, x0, #3 // Check processor id + cbnz x0, proc_hang // Hang for all non-primary CPU + bl from_el2_to_el1 + bl set_exception_vector_table + +master: + ldr x0, =__bss_begin + ldr x1, =__bss_end + sub x1, x1, x0 + +memzero: + cbz x1, movesp + str xzr, [x0], #8 + subs x1, x1, #8 + cbnz x1, memzero + +movesp: + mov sp, #0x80000 + bl kernel_main + +proc_hang: + wfe + b proc_hang + +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + ret + +from_el2_to_el1: + 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 \ No newline at end of file diff --git a/lab7_novm/kernel/kernel.c b/lab7_novm/kernel/kernel.c new file mode 100644 index 000000000..951b63c64 --- /dev/null +++ b/lab7_novm/kernel/kernel.c @@ -0,0 +1,29 @@ +#include "mini_uart.h" +#include "shell.h" +#include "devtree.h" +#include "cpio.h" +#include "mm.h" +#include "timer.h" +#include "exception.h" +#include "fork.h" +#include "vfs.h" + +void kernel_main(void) +{ + uart_init(); + devtree_getaddr(); + fdt_traverse(initramfs_callback); + init_mm_reserve(); + timer_init(); + rootfs_init(); + initramfs_init(); + enable_interrupt(); + uart_send_string("OSDI 2022 Spring\n"); + + copy_process(PF_KTHREAD, (unsigned long)&shell_loop, 0, 0); + + while (1) { + kill_zombies(); + schedule(); + } +} \ No newline at end of file diff --git a/lab7_novm/kernel/linker.ld b/lab7_novm/kernel/linker.ld new file mode 100644 index 000000000..7ae6ad8c6 --- /dev/null +++ b/lab7_novm/kernel/linker.ld @@ -0,0 +1,21 @@ +SECTIONS +{ + . = 0x80000; + + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + + . = ALIGN(8); + + __bss_begin = .; + .bss : { *(.bss* .bss.*) } + __bss_end = .; + + . = ALIGN(16); + + __heap_start = .; + __kernel_end = .; + +} diff --git a/lab7_novm/lib/Makefile b/lab7_novm/lib/Makefile new file mode 100644 index 000000000..66d9bcea3 --- /dev/null +++ b/lab7_novm/lib/Makefile @@ -0,0 +1,29 @@ +AARCH64_PREFIX = aarch64-linux-gnu- +CC = $(AARCH64_PREFIX)gcc + +CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding -I../include -mgeneral-regs-only +ASMFLAGS = -I../include + +BUILD_DIR = ../build + +.PHONY: all clean + +$(BUILD_DIR)/%_c.o: %.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: %.S + $(CC) $(ASMFLAGS) -MMD -c $< -o $@ + +C_FILES = $(wildcard *.c) +ASM_FILES = $(wildcard *.S) +OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +all: $(OBJ_FILES) + +clean: + rm $(OBJ_FILES) $(BUILD_DIR)/$(DEP_FILES) diff --git a/lab7_novm/lib/cpio.c b/lab7_novm/lib/cpio.c new file mode 100644 index 000000000..db3cc41fc --- /dev/null +++ b/lab7_novm/lib/cpio.c @@ -0,0 +1,232 @@ +#include "../include/cpio.h" +#include "mini_uart.h" +#include "../include/sched.h" +#include "fork.h" +#include "string.h" + +void *DEVTREE_CPIO_BASE = 0; + +unsigned int hexstr_to_uint(char *s, unsigned int len) { + + unsigned int n = 0; + + for (int i=0; i= '0' && s[i] <= '9') { + n += s[i] - '0'; + } else if (s[i] >= 'A' && s[i] <= 'F') { + n += s[i] - 'A' + 10; + } + } + + return n; + +} + +void initramfs_callback(char *node_name, char *prop_name, struct fdt_prop *prop) { + + if (stringncmp(node_name, "chosen", 7) == 0 && + stringncmp(prop_name, "linux,initrd-start", 19) == 0) { + + DEVTREE_CPIO_BASE = (void*)to_lendian(*((unsigned int*)(prop + 1))); + + } + +} + +void cpio_ls() { + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + + header = DEVTREE_CPIO_BASE; + + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) break; + + uart_send_string(filename); + uart_send('\n'); + + namesize = hexstr_to_uint(header->c_namesize, 8); + filesize = hexstr_to_uint(header->c_filesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + +} + +void cpio_cat() { + + char input[256]; + char c = '\0'; + int idx = 0; + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + + header = DEVTREE_CPIO_BASE; + + uart_send_string("Filename: "); + + while (1) { + c = uart_recv(); + if (c == '\r' || c == '\n') { + uart_send_string("\n"); + + if (idx < 256) input[idx] = '\0'; + else input[255] = '\0'; + + break; + } else { + uart_send(c); + input[idx++] = c; + } + } + + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) { + uart_send_string("file does not exist!\n"); + break; + } + + namesize = hexstr_to_uint(header->c_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, input, namesize) == 0) { + + char *content = ((void*)header) + offset; + + for (int i=0; ic_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, input, namesize) == 0) { + + char *code_loc = ((void*)header) + offset; + unsigned int sp_val = 0x600000; + asm volatile( + "msr elr_el1, %0\n\t" + "msr spsr_el1, xzr\n\t" + "msr sp_el0, %1\n\t" + "eret\n\t" + :: + "r" (code_loc), + "r" (sp_val) + ); + + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + +} diff --git a/lab7_novm/lib/devtree.c b/lab7_novm/lib/devtree.c new file mode 100644 index 000000000..18d763c21 --- /dev/null +++ b/lab7_novm/lib/devtree.c @@ -0,0 +1,92 @@ +#include "devtree.h" +#include "mini_uart.h" +#include "string.h" + +static void *DEVTREE_ADDRESS = 0; + +unsigned int to_lendian(unsigned int n) { + return ((n>>24)&0x000000FF) | + ((n>>8) &0x0000FF00) | + ((n<<8) &0x00FF0000) | + ((n<<24)&0xFF000000) ; +} + +void devtree_getaddr() { + + asm volatile("MOV %0, x20" : "=r"(DEVTREE_ADDRESS)); + + char magic[4] = {0xd0, 0x0d, 0xfe, 0xed}; + if(stringncmp((char*)DEVTREE_ADDRESS, magic, 4) != 0) { + uart_send_string("magic failed\n"); + } else { + uart_send_string("devtree magic succeed\n"); + } + +} + +void fdt_traverse( void (*callback)(char *, char *, struct fdt_prop *) ) { + + char magic[4] = {0xd0, 0x0d, 0xfe, 0xed}; + struct fdt_header *devtree_header = DEVTREE_ADDRESS; + + if(stringncmp((char*)devtree_header, magic, 4) != 0) { + uart_send_string("devtree magic failed\n"); + return; + } + + void *dt_struct_addr = DEVTREE_ADDRESS + to_lendian(devtree_header->off_dt_struct); + char *dt_string_addr = DEVTREE_ADDRESS + to_lendian(devtree_header->off_dt_strings); + + char *node_name; + char *prop_name; + unsigned int token; + unsigned int off; + + while (1) { + + token = to_lendian(*((unsigned int *)dt_struct_addr)); + + if (token == FDT_BEGIN_NODE) { + + node_name = dt_struct_addr + 4; + off = 4 + strlen(node_name) + 1; + + if (off%4 != 0) + off = ((off/4)+1)*4; + + dt_struct_addr += off; + + } + else if (token == FDT_END_NODE) { + dt_struct_addr += 4; + } + else if (token == FDT_PROP) { + + struct fdt_prop *prop = (struct fdt_prop*)(dt_struct_addr + 4); + + off = 4 + 8 + to_lendian(prop->len); + if (off%4 != 0) + off = ((off/4)+1)*4; + + dt_struct_addr += off; + + prop_name = dt_string_addr + to_lendian(prop->nameoff); + + callback(node_name, prop_name, prop); + + } + else if (token == FDT_NOP) { + dt_struct_addr += 4; + } + else if (token == FDT_END) { + dt_struct_addr += 4; + break; + } + else { + uart_send_string("TOKEN NOT MATCHED\n"); + break; + } + + } + +} \ No newline at end of file diff --git a/lab7_novm/lib/entry.S b/lab7_novm/lib/entry.S new file mode 100644 index 000000000..e564be0fe --- /dev/null +++ b/lab7_novm/lib/entry.S @@ -0,0 +1,195 @@ +#include "entry.h" +#include "syscall.h" + +.macro handle_invalid_entry el, type + kernel_entry \el + mov x0, #\type + mrs x1, esr_el1 + mrs x2, elr_el1 + bl show_invalid_entry_message + b err_hang +.endm + +.macro ventry label + .align 7 + b \label +.endm + +// save general registers to stack +.macro kernel_entry, el + sub sp, sp, #S_FRAME_SIZE + 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] + + .if \el == 0 + mrs x21, sp_el0 + .else + add x21, sp, #S_FRAME_SIZE + .endif + + mrs x22, elr_el1 + mrs x23, spsr_el1 + + stp x30, x21, [sp, 16 * 15] + stp x22, x23, [sp, 16 * 16] +.endm + +// load general registers from stack +.macro kernel_exit, el + ldp x22, x23, [sp, 16 * 16] + ldp x30, x21, [sp, 16 * 15] + + .if \el == 0 + msr sp_el0, x21 + .endif + + msr elr_el1, x22 + msr spsr_el1, x23 + + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + add sp, sp, #S_FRAME_SIZE + eret +.endm + +.align 11 // vector table should be aligned to 0x800 +.globl exception_vector_table +exception_vector_table: + ventry sync_invalid_el1t // Synchronous EL1t + ventry irq_invalid_el1t // IRQ EL1t + ventry fiq_invalid_el1t // FIQ EL1t + ventry error_invalid_el1t // Error EL1t + + ventry sync_invalid_el1h // Synchronous EL1h + ventry el1_irq // IRQ EL1h + ventry fiq_invalid_el1h // FIQ EL1h + ventry error_invalid_el1h // Error EL1h + + ventry el0_sync // Synchronous 64-bit EL0 + ventry el0_irq // IRQ 64-bit EL0 + ventry fiq_invalid_el0_64 // FIQ 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 + + 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 + +sync_invalid_el1t: + handle_invalid_entry 1, SYNC_INVALID_EL1t + +irq_invalid_el1t: + handle_invalid_entry 1, IRQ_INVALID_EL1t + +fiq_invalid_el1t: + handle_invalid_entry 1, FIQ_INVALID_EL1t + +error_invalid_el1t: + handle_invalid_entry 1, ERROR_INVALID_EL1t + +sync_invalid_el1h: + handle_invalid_entry 1, SYNC_INVALID_EL1h + +el1_irq: + kernel_entry 1 + bl handle_irq + kernel_exit 1 + +fiq_invalid_el1h: + handle_invalid_entry 1, FIQ_INVALID_EL1h + +error_invalid_el1h: + handle_invalid_entry 1, ERROR_INVALID_EL1h + +el0_sync: + kernel_entry 0 + mrs x25, esr_el1 + lsr x24, x25, #ESR_ELx_EC_SHIFT + cmp x24, #ESR_ELx_EC_SVC64 + b.eq el0_svc + handle_invalid_entry 0, SYNC_ERROR + +el0_irq: + kernel_entry 0 + bl handle_irq + kernel_exit 0 + +fiq_invalid_el0_64: + handle_invalid_entry 0, FIQ_INVALID_EL0_64 + +error_invalid_el0_64: + handle_invalid_entry 0, ERROR_INVALID_EL0_64 + +sync_invalid_el0_32: + handle_invalid_entry 0, SYNC_INVALID_EL0_32 + +irq_invalid_el0_32: + handle_invalid_entry 0, IRQ_INVALID_EL0_32 + +fiq_invalid_el0_32: + handle_invalid_entry 0, FIQ_INVALID_EL0_32 + +error_invalid_el0_32: + handle_invalid_entry 0, ERROR_INVALID_EL0_32 + +sc_nr .req x25 +scno .req x26 +stbl .req x27 + +el0_svc: + adr stbl, sys_call_table + uxtw scno, w8 + mov sc_nr, #__NR_SYSCALLS + bl enable_interrupt + cmp scno, sc_nr + b.hs ni_sys + + ldr x16, [stbl, scno, lsl #3] + blr x16 + b ret_from_syscall +ni_sys: + handle_invalid_entry 0, SYSCALL_ERROR +ret_from_syscall: + bl disable_interrupt + str x0, [sp, #S_X0] + kernel_exit 0 + +.globl ret_from_fork +ret_from_fork: + bl schedule_tail + cbz x19, ret_to_user + mov x0, x20 + blr x19 // in theory should not return + //b err_hang // hang fail-safe +ret_to_user: + bl disable_interrupt + kernel_exit 0 + +.globl err_hang +err_hang: b err_hang diff --git a/lab7_novm/lib/exception.c b/lab7_novm/lib/exception.c new file mode 100644 index 000000000..a820ba662 --- /dev/null +++ b/lab7_novm/lib/exception.c @@ -0,0 +1,49 @@ +#include "exception.h" +#include "mini_uart.h" +#include "mailbox.h" +#include "utils.h" +#include "timer.h" +#include "peripherals/exception.h" +#include "peripherals/mini_uart.h" + +void enable_interrupt() {asm volatile("msr DAIFClr, 0xf");} +void disable_interrupt() {asm volatile("msr DAIFSet, 0xf");} + +const char *entry_error_messages[] = { + "SYNC_INVALID_EL1t", + "IRQ_INVALID_EL1t", + "FIQ_INVALID_EL1t", + "ERROR_INVALID_EL1t", + + "SYNC_INVALID_EL1h", + "IRQ_INVALID_EL1h", + "FIQ_INVALID_EL1h", + "ERROR_INVALID_EL1h", + + "SYNC_INVALID_EL0_64", + "IRQ_INVALID_EL0_64", + "FIQ_INVALID_EL0_64", + "ERROR_INVALID_EL0_64", + + "SYNC_INVALID_EL0_32", + "IRQ_INVALID_EL0_32", + "FIQ_INVALID_EL0_32", + "ERROR_INVALID_EL0_32", + + "SYNC_ERROR", + "SYSCALL_ERROR" +}; + +void show_invalid_entry_message(int type, unsigned long esr, unsigned long addr) { + printf("%s, ESR: 0x%x, address: 0x%x\n", entry_error_messages[type], esr, addr); +} + +void handle_irq() { + + if (get32(CORE0_INTERRUPT_SRC)&INTERRUPT_SOURCE_CNTPNSIRQ) { + handle_timer_irq(); + } else { + printf("unknown irq encountered"); + } + +} \ No newline at end of file diff --git a/lab7_novm/lib/fork.c b/lab7_novm/lib/fork.c new file mode 100644 index 000000000..75de715e0 --- /dev/null +++ b/lab7_novm/lib/fork.c @@ -0,0 +1,85 @@ +#include "fork.h" +#include "mm.h" +#include "mini_uart.h" +#include "../include/sched.h" +#include "../include/entry.h" + +int copy_process(unsigned long clone_flags, unsigned long fn, unsigned long arg, unsigned long stack) { + + preempt_disable(); + struct task_struct *p; + + p = (struct task_struct *) malloc(PAGE_SIZE); + if (p == NULL) + return -1; + + struct pt_regs *childregs = task_pt_regs(p); + memzero((unsigned long)childregs, sizeof(struct pt_regs)); + memzero((unsigned long)&p->cpu_context, sizeof(struct cpu_context)); + + if (clone_flags & PF_KTHREAD) { + p->cpu_context.x19 = fn; + p->cpu_context.x20 = arg; + } else { + struct pt_regs *cur_regs = task_pt_regs(current); + // *childregs = *cur_regs; (object file generates memcpy) + // therefore the for loop is used below + for(int i=0; iregs[0] = 0; // return value 0 + childregs->sp = stack + PAGE_SIZE; + p->stack = stack; + } + + p->files = current->files; + p->cwd = current->cwd; + p->flags = clone_flags; + p->priority = current->priority; + p->state = TASK_RUNNING; + p->counter = p->priority; + p->preempt_count = 1; + + p->cpu_context.pc = (unsigned long)ret_from_fork; + p->cpu_context.sp = (unsigned long)childregs; + + int pid = nr_tasks++; + task[pid] = p; + p->id = pid; + preempt_enable(); + + return pid; + +} + +int move_to_user_mode(unsigned long pc) { + + struct pt_regs *regs = task_pt_regs(current); + memzero((unsigned long)regs, sizeof(*regs)); + regs->pc = pc; + regs->pstate = PSR_MODE_EL0t; + unsigned long stack = (unsigned long)malloc(PAGE_SIZE); + + if (stack == NULL) + return -1; + + regs->sp = stack + PAGE_SIZE; + current->stack = stack; + return 0; + +} + +struct pt_regs *task_pt_regs(struct task_struct *tsk) { + + unsigned long p = (unsigned long)tsk + THREAD_SIZE - sizeof(struct pt_regs); + return (struct pt_regs *)p; + +} + +void new_user_process(unsigned long func){ + printf("Kernel process started, moving to user mode.\n"); + int err = move_to_user_mode(func); + if (err < 0){ + printf("Error while moving process to user mode\n\r"); + } +} \ No newline at end of file diff --git a/lab7_novm/lib/initramfs.c b/lab7_novm/lib/initramfs.c new file mode 100644 index 000000000..6d6953500 --- /dev/null +++ b/lab7_novm/lib/initramfs.c @@ -0,0 +1,211 @@ +#include "initramfs.h" +#include "mm.h" +#include "string.h" +#include "mini_uart.h" +#include "vfs.h" +#include "string.h" +#include "../include/cpio.h" + +struct vnode_operations *initramfs_v_ops; +struct file_operations *initramfs_f_ops; +int initramfs_registered = 0; + +int initramfs_setup_mount(struct filesystem* fs, struct mount* mount) { + + mount->fs = fs; + mount->root = initramfs_new_node(NULL, "/", DIRECTORY); + + printf("[debug] setup root: 0x%x\n", mount); + printf("[debug] setup root vnode: 0x%x\n", mount->root); + + return 0; + +} + +int initramfs_register() { + + if (initramfs_registered) return -1; + initramfs_registered = 1; + + initramfs_v_ops = (struct vnode_operations *) chunk_alloc(sizeof(struct vnode_operations)); + initramfs_f_ops = (struct file_operations *) chunk_alloc(sizeof(struct file_operations)); + + initramfs_v_ops->lookup = initramfs_lookup; + initramfs_v_ops->create = initramfs_create; + initramfs_v_ops->mkdir = initramfs_mkdir; + + initramfs_f_ops->open = initramfs_open; + initramfs_f_ops->read = initramfs_read; + initramfs_f_ops->write = initramfs_write; + initramfs_f_ops->close = initramfs_close; + + return 0; + +} + +struct vnode* initramfs_new_node(struct initramfs_internal *parent, const char *name, int type) { + + struct vnode *new_node = (struct vnode *)chunk_alloc(sizeof(struct vnode)); + struct initramfs_internal *new_internal = (struct initramfs_internal *)chunk_alloc(sizeof(struct initramfs_internal)); + + strcpy(new_internal->name, name); + new_internal->type = type; + new_internal->parent = parent; + new_internal->vnode = new_node; + new_internal->size = 0; + if (type == REGULAR_FILE) + new_internal->data = malloc(MAX_FILESIZE); + else + new_internal->data = 0; + + if (parent != NULL) + new_node->parent = parent->vnode; + new_node->f_ops = initramfs_f_ops; + new_node->v_ops = initramfs_v_ops; + new_node->mount = 0; + new_node->internal = (void *)new_internal; + + return new_node; + +} + +int initramfs_open(struct vnode *file_node, struct file **target) { + return SUCCESS; +} + +int initramfs_close(struct file *file) { + if (file) + return SUCCESS; + else + return FAIL; +} + +int initramfs_write(struct file *file, const void *buf, unsigned len) { + return FAIL; +} + +int initramfs_read(struct file *file, void *buf, unsigned len) { + + struct initramfs_internal *internal = (struct initramfs_internal*)file->vnode->internal; + if (internal->type != REGULAR_FILE) + return FAIL; + + char *dest = (char*)buf; + char *src = &((char *)internal->data)[file->f_pos]; + int i = 0; + for (; isize; i++) { + dest[i] = src[i]; + } + + return i; +} + +int initramfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name) { + return FAIL; +} + +int initramfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name) { + return FAIL; +} + +int initramfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name) { + + if (stringcmp(component_name, "") == 0) { + *target = dir_node; + return 0; + } + + struct initramfs_internal *internal = (struct initramfs_internal *)dir_node->internal; + + for (int i=0; isize; i++) { + if(stringcmp(internal->child[i]->name, component_name) == 0) { + *target = internal->child[i]->vnode; + return internal->child[i]->type; + } + } + + return FAIL; + +} + +void parse_initramfs() { + + vfs_chdir("/initramfs"); + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + unsigned int c_mode; + void *data; + char *filename; + + header = DEVTREE_CPIO_BASE; + + while (1) { + + struct vnode *target_node; + char target_path[VFS_PATHMAX]; + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) break; + + //uart_send_string(filename); + //uart_send('\n'); + + namesize = hexstr_to_uint(header->c_namesize, 8); + filesize = hexstr_to_uint(header->c_filesize, 8); + c_mode = hexstr_to_uint(header->c_mode, 5); + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + data = ((void *)header) + offset; + + if (stringncmp(header->c_mode, "00004", 5) == 0) { //dir + + printf("[debug] parse cpio mkdir %s\n", filename); + if (stringcmp(filename, ".") != 0 && stringcmp(filename, "..") != 0) { + traverse(filename, &target_node, target_path); + struct initramfs_internal *parent_internal = (struct initramfs_internal *)target_node->internal; + struct vnode *new_node = initramfs_new_node(parent_internal, target_path, DIRECTORY); + + parent_internal->child[parent_internal->size] = (struct initramfs_internal *)new_node->internal; + parent_internal->size++; + } else { + printf("[debug] mkdir skipped\n"); + } + + } else if (stringncmp(header->c_mode, "00008", 5) == 0) { //reg file + + printf("[debug] parse cpio create file %s, data at 0x%x with size 0x%d\n", filename, data, filesize); + traverse(filename, &target_node, target_path); + struct initramfs_internal *parent_internal = (struct initramfs_internal *)target_node->internal; + struct vnode *new_node = initramfs_new_node(parent_internal, target_path, REGULAR_FILE); + + parent_internal->child[parent_internal->size] = (struct initramfs_internal *)new_node->internal; + parent_internal->size++; + + ((struct initramfs_internal *)new_node->internal)->data = data; + ((struct initramfs_internal *)new_node->internal)->size = filesize; + + } else { + printf("[error] failed to parse cmode %d\n", c_mode); + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + + vfs_chdir("/"); + +} diff --git a/lab7_novm/lib/mailbox.c b/lab7_novm/lib/mailbox.c new file mode 100644 index 000000000..e593af037 --- /dev/null +++ b/lab7_novm/lib/mailbox.c @@ -0,0 +1,49 @@ +#include "peripherals/mailbox.h" +#include "mailbox.h" +#include "mini_uart.h" + +int mailbox_call (volatile unsigned int *mailbox) { + unsigned int msg = ((unsigned long)mailbox & ~0xF) | (0x8 & 0xF); + while (*MAILBOX_STATUS & MAILBOX_FULL) ; + *MAILBOX_WRITE = msg; + while (1) { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) {} + if (msg == *MAILBOX_READ) { + return mailbox[1]; + } + } +} + +void get_board_revision () +{ + volatile unsigned int __attribute__((aligned(16))) mailbox[7]; + mailbox[0] = 7 * 4; + mailbox[1] = REQUEST_CODE; + mailbox[2] = GET_BOARD_REVISION; + mailbox[3] = 4; + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; + mailbox[6] = END_TAG; + + if (mailbox_call(mailbox) == REQUEST_SUCCEED) { + printf("Board Revision:\t\t%x\n", mailbox[5]); + } +} + +void get_arm_memory () +{ + volatile unsigned int __attribute__((aligned(16))) mailbox[8]; + mailbox[0] = 8 * 4; + mailbox[1] = REQUEST_CODE; + mailbox[2] = GET_ARM_MEMORY; + mailbox[3] = 8; + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; + mailbox[6] = 0; + mailbox[7] = END_TAG; + + if (mailbox_call(mailbox) == REQUEST_SUCCEED) { + printf("Memory Base Addresss:\t%x\n", mailbox[5]); + printf("Memory Size:\t\t%x\n", mailbox[6]); + } +} \ No newline at end of file diff --git a/lab7_novm/lib/math.c b/lab7_novm/lib/math.c new file mode 100644 index 000000000..6b6919044 --- /dev/null +++ b/lab7_novm/lib/math.c @@ -0,0 +1,19 @@ +#include "math.h" + +int log(int n, int base) { + int x = 1; + int ret = 0; + while (x <= n) { + x *= base; + ret++; + } + return ret; +} + +int pow(int base, int pow) { + int ret = 1; + for (int i=0; i avail) { + uart_send_string("not enough memory\n"); + } else { + __heap_ptr += size; + avail -= size; + } + + return ptr; + +} \ No newline at end of file diff --git a/lab7_novm/lib/mini_uart.c b/lab7_novm/lib/mini_uart.c new file mode 100644 index 000000000..c209f3a90 --- /dev/null +++ b/lab7_novm/lib/mini_uart.c @@ -0,0 +1,69 @@ +#include "utils.h" +#include "printf.h" +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" +#include "peripherals/exception.h" + +void uart_send ( char c ) +{ + if (c == '\n') uart_send('\r'); + + while (1) { + if (get32(AUX_MU_LSR_REG)&0x20) + break; + } + + put32(AUX_MU_IO_REG,c); +} + +char uart_recv ( void ) +{ + while(1) { + if (get32(AUX_MU_LSR_REG)&0x01) + break; + } + return (get32(AUX_MU_IO_REG)&0xFF); +} + +void uart_send_string ( char* str ) +{ + for (int i = 0; str[i] != '\0'; i++) { + uart_send((char)str[i]); + } +} + +void printf(char *fmt, ...) { + char temp[128]; + __builtin_va_list args; + __builtin_va_start(args, fmt); + vsprintf(temp,fmt,args); + uart_send_string(temp); +} + +void uart_init ( void ) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7<<12); // clean gpio14 + selector |= 2<<12; // set alt5 for gpio14 + selector &= ~(7<<15); // clean gpio15 + selector |= 2<<15; // set alt5 for gpio 15 + put32(GPFSEL1,selector); + + put32(GPPUD,0); + delay(150); + put32(GPPUDCLK0,(1<<14)|(1<<15)); + delay(150); + put32(GPPUDCLK0,0); + + put32(AUX_ENABLES,1); //Enable mini uart (this also enables access to its registers) + put32(AUX_MU_CNTL_REG,0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(AUX_MU_IER_REG,0); //Enable receive and disable transmit interrupts + put32(AUX_MU_LCR_REG,3); //Enable 8 bit mode + put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high + put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200 + put32(AUX_MU_IIR_REG,6); //Interrupt identify no fifo + put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver + +} diff --git a/lab7_novm/lib/mm.S b/lab7_novm/lib/mm.S new file mode 100644 index 000000000..263de4251 --- /dev/null +++ b/lab7_novm/lib/mm.S @@ -0,0 +1,6 @@ +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret \ No newline at end of file diff --git a/lab7_novm/lib/mm.c b/lab7_novm/lib/mm.c new file mode 100644 index 000000000..05a5f6f50 --- /dev/null +++ b/lab7_novm/lib/mm.c @@ -0,0 +1,376 @@ +#include "mm.h" +#include "math.h" +#include "memory.h" +#include "mini_uart.h" + +static unsigned int n_frames = 0; +static unsigned int max_size = 0; +static struct frame* frame_list[MAX_ORDER] = {NULL}; +static struct frame frame_array[(MEM_REGION_END-MEM_REGION_BEGIN)/PAGE_SIZE]; +static struct dynamic_pool pools[MAX_POOLS] = { {ALLOCABLE, 0, 0, 0, 0, {NULL}, NULL} }; +static unsigned int reserved_num = 0; +static void* reserved_se[MAX_RESERVABLE][2] = {{0x0, 0x0}}; // expects to be sorted and addresses [,) +extern char __kernel_end; +static char *__kernel_end_ptr = &__kernel_end; + +void *malloc(unsigned int size) { + + if (size > max_size) { + printf("[error] Request exceeded allocable continuous size %d.\n", (int)max_size); + return NULL; + } + + int req_order = 0; + for(unsigned int i=PAGE_SIZE; i= MAX_ORDER) { + printf("[error] No memory allocable.\n"); + return NULL; + } + + while (t != req_order) { + struct frame* l_tmp = frame_list[t]; + frame_list[t] = l_tmp->next; + frame_list[t]->prev = NULL; + //printf("[info] Split at order %d, new head is 0x%x.\n", t+1, frame_list[t]); + + unsigned int off = pow(2, l_tmp->val-1); + struct frame* r_tmp = &frame_array[l_tmp->index+off]; + + l_tmp->val -= 1; + l_tmp->state = ALLOCABLE; + l_tmp->prev = NULL; + l_tmp->next = r_tmp; + + r_tmp->val = l_tmp->val; + r_tmp->state = ALLOCABLE; + r_tmp->prev = l_tmp; + r_tmp->next = NULL; + + t--; + if (frame_list[t] != NULL) + frame_list[t]->prev = r_tmp; + r_tmp->next = frame_list[t]; + frame_list[t] = l_tmp; + } + + struct frame* ret = frame_list[req_order]; + frame_list[req_order] = ret->next; + frame_list[req_order]->prev = NULL; + + ret->val = ret->val; + ret->state = ALLOCATED; + ret->prev = NULL; + ret->next = NULL; + + //printf("[info] allocated address: 0x%x\n", MEM_REGION_BEGIN+PAGE_SIZE*ret->index); + + return (void*)MEM_REGION_BEGIN+PAGE_SIZE*ret->index; + +} + +void free(void *address) { + + unsigned int idx = ((unsigned long long)address-MEM_REGION_BEGIN) / PAGE_SIZE; + struct frame* target = &frame_array[idx]; + + if (target->state == ALLOCABLE || target->state == C_NALLOCABLE) { + printf("[error] invalid free of already freed memory.\n"); + return; + } + //printf("=========================================================\n"); + //printf("[info] Now freeing address 0x%x with frame index %d.\n", address, (int)idx); + + for (int i=target->val; ival+1, fr_buddy->state); + + if (i < MAX_ORDER-1 && fr_buddy->state == ALLOCABLE && i== fr_buddy->val) { + + //printf("[info] Merging from order %d. Frame indices %d, %d.\n", i+1, (int)buddy, (int)idx); + + if (fr_buddy->prev != NULL) { + fr_buddy->prev->next = fr_buddy->next; + } else { + frame_list[fr_buddy->val] = fr_buddy->next; + } + + if (fr_buddy->next != NULL) { + fr_buddy->next->prev = fr_buddy->prev; + } + + fr_buddy->prev = NULL; + fr_buddy->next = NULL; + fr_buddy->val = C_NALLOCABLE; + fr_buddy->state = C_NALLOCABLE; + target->val = C_NALLOCABLE; + target->state = C_NALLOCABLE; + + if (fr_buddy->index < target->index) { + idx = fr_buddy->index; + target = fr_buddy; + } + + //printf("[info] Frame index of next merge target is %d.\n", (int)idx); + + } else { + + target->val = i; + target->state = ALLOCABLE; + target->prev = NULL; + target->next = frame_list[i]; + if (frame_list[i] != NULL) + frame_list[i]->prev = target; + frame_list[i] = target; + //printf("[info] Frame index %d pushed to frame list of order %d.\n", + // (int)target->index, (int)i+1); + break; + + } + + } + + //printf("[info] Free finished.\n"); + /*for (int i=0; i < MAX_ORDER; i++) { + if (frame_list[i] != NULL) + printf("[info] Head of order %d has frame array index %d.\n",i+1,frame_list[i]->index); + else + printf("[info] Head of order %d has frame array index null.\n",i+1); + }*/ + +} + +void init_mm() { + + n_frames = (MEM_REGION_END-MEM_REGION_BEGIN) / PAGE_SIZE; + unsigned int mul = (unsigned int)pow(2, MAX_ORDER-1); + printf("[info] Frame array start address 0x%x.\n", frame_array); + for (unsigned int i=0; ichunk_size = size; + pool->chunks_per_page = PAGE_SIZE / size; + pool->chunks_allocated = 0; + pool->page_new_chunk_off = 0; + pool->pages_used = 0; + pool->free_head = NULL; +} + +int register_chunk(unsigned int size) { + + unsigned int nsize = 0; + if (size <= 8) nsize = 8; + else { + int rem = size % 4; + if (rem != 0) nsize = (size/4 + 1)*4; + else nsize = size; + } + + if (nsize >= PAGE_SIZE) { + printf("[error] Normalized chunk size request leq page size.\n"); + return -1; + } + + for (int i=0; ifree_head != NULL) { + void *ret = (void*) pool->free_head; + pool->free_head = pool->free_head->next; + //printf("[info] allocate address 0x%x from pool free list.\n", ret); + return ret; + } + + if (pool->chunks_allocated >= MAX_POOL_PAGES*pool->chunks_per_page) { + //printf("[error] Pool maximum reached.\n"); + return NULL; + } + + + if (pool->chunks_allocated >= pool->pages_used*pool->chunks_per_page) { + pool->page_base_addrs[pool->pages_used] = malloc(PAGE_SIZE); + //printf("[info] allocate new page for pool with base address 0x%x.\n", + // pool->page_base_addrs[pool->pages_used]); + pool->pages_used++; + pool->page_new_chunk_off = 0; + } + + void *ret = pool->page_base_addrs[pool->pages_used - 1] + + pool->chunk_size*pool->page_new_chunk_off; + pool->page_new_chunk_off++; + pool->chunks_allocated++; + + //printf("[info] allocate new address 0x%x from pool.\n", ret); + + return ret; + +} + +void chunk_free(void *address) { + + int target = -1; + + void *prefix_addr = (void *)((unsigned long long)address & ~0xFFF); + + for (unsigned int i=0; ifree_head; + pool->free_head = (struct node*) address; + pool->free_head->next = old_head; + pool->chunks_allocated--; + +} + +void memory_reserve(void* start, void* end) { + if (reserved_num >= MAX_RESERVABLE) { + printf("[error] Max reservable locations already reached.\n"); + return; + } + reserved_se[reserved_num][0] = start; + reserved_se[reserved_num][1] = end; + reserved_num++; +} + +void init_mm_reserve() { + + max_size = PAGE_SIZE * pow(2, MAX_ORDER-1); + n_frames = (MEM_REGION_END-MEM_REGION_BEGIN) / PAGE_SIZE; + + memory_reserve((void*)0x0, __kernel_end_ptr); // spin tables, kernel image + memory_reserve((void*)0x20000000, (void*)0x20010000); // hard code reserve initramfs + + for (unsigned int i=0; i= reserved_se[i][0] && addr < reserved_se[i][1]) { + frame_array[j].state = RESERVED; + } + if (addr >= reserved_se[i][1]) break; + } + } + + for (int i=0; istate == RESERVED) continue; + if (target->state == C_NALLOCABLE) continue; + + for (int i=target->val; istate == ALLOCABLE && i== fr_buddy->val) { + + if (fr_buddy->prev != NULL) { + fr_buddy->prev->next = fr_buddy->next; + } else { + frame_list[fr_buddy->val] = fr_buddy->next; + } + + if (fr_buddy->next != NULL) { + fr_buddy->next->prev = fr_buddy->prev; + } + + fr_buddy->prev = NULL; + fr_buddy->next = NULL; + fr_buddy->val = C_NALLOCABLE; + fr_buddy->state = C_NALLOCABLE; + target->val = C_NALLOCABLE; + target->state = C_NALLOCABLE; + + if (fr_buddy->index < target->index) { + idx = fr_buddy->index; + target = fr_buddy; + } + + } else { + + target->val = i; + target->state = ALLOCABLE; + target->prev = NULL; + target->next = frame_list[i]; + if (frame_list[i] != NULL) + frame_list[i]->prev = target; + frame_list[i] = target; + break; + + } + + } + + } + +} \ No newline at end of file diff --git a/lab7_novm/lib/printf.c b/lab7_novm/lib/printf.c new file mode 100644 index 000000000..794a37dff --- /dev/null +++ b/lab7_novm/lib/printf.c @@ -0,0 +1,152 @@ +/* + * 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 + */ +#include "printf.h" + +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_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/lab7_novm/lib/reboot.c b/lab7_novm/lib/reboot.c new file mode 100644 index 000000000..043a09fb7 --- /dev/null +++ b/lab7_novm/lib/reboot.c @@ -0,0 +1,18 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab7_novm/lib/sched.S b/lab7_novm/lib/sched.S new file mode 100644 index 000000000..03f9c56b1 --- /dev/null +++ b/lab7_novm/lib/sched.S @@ -0,0 +1,24 @@ +#include "sched.h" + +.global cpu_switch_to +cpu_switch_to: + mov x10, #THREAD_CPU_CONTEXT + add x8, x0, x10 + mov x9, sp + stp x19, x20, [x8], #16 // store callee-saved registers + stp x21, x22, [x8], #16 + stp x23, x24, [x8], #16 + stp x25, x26, [x8], #16 + stp x27, x28, [x8], #16 + stp x29, x9, [x8], #16 + str x30, [x8] + add x8, x1, x10 + ldp x19, x20, [x8], #16 // restore callee-saved registers + ldp x21, x22, [x8], #16 + ldp x23, x24, [x8], #16 + ldp x25, x26, [x8], #16 + ldp x27, x28, [x8], #16 + ldp x29, x9, [x8], #16 + ldr x30, [x8] + mov sp, x9 + ret diff --git a/lab7_novm/lib/sched.c b/lab7_novm/lib/sched.c new file mode 100644 index 000000000..2ffc32acd --- /dev/null +++ b/lab7_novm/lib/sched.c @@ -0,0 +1,107 @@ +#include "../include/sched.h" +#include "mm.h" +#include "exception.h" +#include "mini_uart.h" + +static struct task_struct init_task = INIT_TASK; +struct task_struct *current = &(init_task); +struct task_struct *task[NR_TASKS] = {&(init_task), }; +int nr_tasks = 1; + +void preempt_disable() { + current->preempt_count++; +} + +void preempt_enable() { + current->preempt_count--; +} + +void _schedule() { + + int next, c; + struct task_struct *p; + while (1) { + c = -1; + next = 0; + for (int i=0; istate == TASK_RUNNING && p->counter > c) { + c = p->counter; + next = i; + } + } + if (c) { + break; + } + for (int i=0; icounter = (p->counter >> 1) + p->priority; + } + } + preempt_disable(); // should be fine, if anything breaks move this to the top + switch_to(task[next]); + preempt_enable(); + +} + +void schedule() { + current->counter = 0; + _schedule(); +} + +void switch_to(struct task_struct *next) { + if (current == next) + return; + struct task_struct *prev = current; + current = next; + cpu_switch_to(prev, next); +} + +void schedule_tail() { + preempt_enable(); +} + +void timer_tick() { + + --current->counter; + if (current->counter > 0 || current->preempt_count > 0) + return; + + current->counter = 0; + enable_interrupt(); + _schedule(); + disable_interrupt(); + +} + +void exit_process() { + // should only be accessed using syscall + // preempt_disable(); + current->state = TASK_ZOMBIE; + free((void*)current->stack); + // preempt_enable(); + schedule(); +} + +void kill_zombies() { + + struct task_struct *p; + for (int i=0; istate == TASK_ZOMBIE) { + printf("Zombie found with pid: %d.\n", p->id); + free(p); + task[i] = NULL; + } + + } + +} \ No newline at end of file diff --git a/lab7_novm/lib/shell.c b/lab7_novm/lib/shell.c new file mode 100644 index 000000000..5adf9634c --- /dev/null +++ b/lab7_novm/lib/shell.c @@ -0,0 +1,200 @@ +#include "shell.h" +#include "mini_uart.h" +#include "utils.h" +#include "mailbox.h" +#include "reboot.h" +#include "string.h" +#include "../include/cpio.h" +#include "memory.h" +#include "timer.h" +#include "exception.h" +#include "math.h" +#include "mm.h" +#include "../include/sched.h" +#include "syscall.h" +#include "peripherals/mailbox.h" +#include "fork.h" + + +#define MAX_BUFFER_SIZE 256u + +static char buffer[MAX_BUFFER_SIZE]; + +void foo() { + for(int i = 0; i < 10; ++i) { + printf("Thread id: %d %d\n", current->id, i); + delay(1000000); + schedule(); + } + + current->state = TASK_ZOMBIE; + while(1); +} + +void user_foo() { + + printf("User thread id: %d\n", getpid()); + char *msg = "hello world\n"; + int fd; + char buf[15]; + buf[14] = '\0'; + + fd = open("/initramfs/msg", 0); + read(fd, buf, 13); + close(fd); + + printf("%s", buf); + + exit(0); + +} + +void start_video() { + // ... go to cpio, find location and size of syscall.img + // allocate pages + // move syscall.img to allocated memory + // preempt disable + // change this shell thread to not runnable + // start sycall.img user process + // preempt enable + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + void *code_loc; + + header = DEVTREE_CPIO_BASE; + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) { + uart_send_string("file does not exist!\n"); + break; + } + + namesize = hexstr_to_uint(header->c_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, "vfs1.img", namesize) == 0) { + code_loc = ((void*)header) + offset; + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + printf("vfs1.img found in cpio at location 0x%x.\n", code_loc); + printf("vfs1.img has size of %d bytes.\n", (int)filesize); + + void *move_loc = malloc(filesize + 4096); // an extra page for bss just in case + if(move_loc == NULL) return; + for (int i=0; istate = TASK_STOPPED; + unsigned long long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + copy_process(PF_KTHREAD, (unsigned long)&new_user_process, (unsigned long)move_loc, 0); + preempt_enable(); + +} + +void read_cmd() +{ + unsigned int idx = 0; + char c = '\0'; + + while (1) { + c = uart_recv(); + if (c == '\r' || c == '\n') { + uart_send_string("\n"); + + if (idx < MAX_BUFFER_SIZE) buffer[idx] = '\0'; + else buffer[MAX_BUFFER_SIZE-1] = '\0'; + + break; + } else { + uart_send(c); + buffer[idx++] = c; + } + } + +} + +void parse_cmd() +{ + + if (stringcmp(buffer, "\0") == 0) + uart_send_string("\n"); + else if (stringcmp(buffer, "hello") == 0) + uart_send_string("Hello World!\n"); + else if (stringcmp(buffer, "reboot") == 0) { + uart_send_string("rebooting...\n"); + reset(100); + } + else if (stringcmp(buffer, "hwinfo") == 0) { + get_board_revision(); + get_arm_memory(); + } + else if (stringcmp(buffer, "ls") == 0) { + cpio_ls(); + } + else if (stringcmp(buffer, "cat") == 0) { + cpio_cat(); + } + else if (stringcmp(buffer, "execute") == 0) { + cpio_exec(); + } + else if (stringcmp(buffer, "thread_test") == 0) { + for (int i=0; i<10; i++) { + copy_process(PF_KTHREAD, (unsigned long)&foo, 0, 0); + } + } + else if (stringcmp(buffer, "to_user") == 0) { + copy_process(PF_KTHREAD, (unsigned long)&new_user_process, (unsigned long)&user_foo, 0); + } + else if (stringcmp(buffer, "video") == 0) { + start_video(); + } + else if (stringcmp(buffer, "help") == 0) { + uart_send_string("help:\t\tprint list of available commands\n"); + uart_send_string("hello:\t\tprint Hello World!\n"); + uart_send_string("reboot:\t\treboot device\n"); + uart_send_string("hwinfo:\t\tprint hardware information\n"); + uart_send_string("ls:\t\tlist initramfs files\n"); + uart_send_string("cat:\t\tprint file content in initramfs\n"); + uart_send_string("execute:\trun program from cpio\n"); + } + else + uart_send_string("Command not found! Type help for commands.\n"); + +} + +void shell_loop() +{ + while (1) { + uart_send_string("% "); + read_cmd(); + parse_cmd(); + } +} \ No newline at end of file diff --git a/lab7_novm/lib/string.c b/lab7_novm/lib/string.c new file mode 100644 index 000000000..f74819f4d --- /dev/null +++ b/lab7_novm/lib/string.c @@ -0,0 +1,55 @@ +#include "string.h" + +int stringcmp(const char *p1, const char *p2) +{ + const unsigned char *s1 = (const unsigned char *) p1; + const unsigned char *s2 = (const unsigned char *) p2; + unsigned char c1, c2; + + do { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0') + return c1 - c2; + } while (c1 == c2); + + return c1 - c2; +} + +int stringncmp(const char *p1, const char *p2, unsigned int n) +{ + for (int i=0; iid; +} + +unsigned sys_uartread(char buf[], unsigned size) { + for(unsigned int i=0; ic_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, name, namesize) == 0) { + code_loc = ((void*)header) + offset; + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + + void *move_loc = malloc(filesize + 4096); // an extra page for bss just in case + if(move_loc == NULL) return -1; + for (int i=0; ipc = (unsigned long)move_loc; // move to beginning of program + p->sp = current->stack+PAGE_SIZE; + + preempt_enable(); + + return -1; // only on failure +} + +int sys_fork() { + return copy_process(0, 0, 0, (unsigned long)malloc(4*4096)); +} + +void sys_exit(int status) { + exit_process(); +} + +int sys_mbox_call(unsigned char ch, unsigned int *mbox) { + unsigned int r = (((unsigned int)((unsigned long)mbox)&~0xF) | (ch&0xF)); + while(*MAILBOX_STATUS & MAILBOX_FULL); + *MAILBOX_WRITE = r; + while (1) { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) {} + if (r == *MAILBOX_READ) { + return mbox[1]==REQUEST_SUCCEED; + } + } + return 0; +} + +void sys_kill(int pid) { + + struct task_struct *p; + for (int i=0; iid == (long)pid) { + preempt_disable(); + printf("Kill target acquired.\n"); + p->state = TASK_ZOMBIE; + free((void *)p->stack); + preempt_enable(); + break; + } + + } + +} + +int sys_open(const char *pathname, int flags) { + printf("[debug] start of syscall open: %s %d\n", pathname, flags); + struct file *f; + int res = vfs_open(pathname, flags, &f); + if (res < 0) return -1; + + int fd_num = current->files.count; + + if (fd_num >= 16) { + for (int i=0; i<16; i++) { + if (current->files.fds[i] == 0) fd_num = i; + } + } + + if (fd_num >= 16) return -1; + + current->files.fds[fd_num] = f; + current->files.count++; + + return fd_num; +} + +int sys_close(int fd) { + printf("[debug] start of syscall close with fd %d\n", fd); + if (fd < 0) return -1; + + struct file *f = current->files.fds[fd]; + current->files.fds[fd] = 0; + + return vfs_close(f); +} + +long sys_write(int fd, const void *buf, unsigned long count) { + printf("[debug] start of syscall write with fd %d\n", fd); + + if (fd < 0) return -1; + + struct file *f = current->files.fds[fd]; + if (f == 0) return 0; + + return vfs_write(f, buf, count); +} + +long sys_read(int fd, void *buf, unsigned long count) { + printf("[debug] start of syscall read with fd %d\n", fd); + + if (fd < 0) return -1; + + struct file *f = current->files.fds[fd]; + if (f == 0) return 0; + + return vfs_read(f, buf, count); +} + +int sys_mkdir(const char *pathname, unsigned mode) { + printf("[debug] start of syscall mkdir\n"); + + return vfs_mkdir(pathname); +} + +int sys_mount(const char *src, const char *target, const char *fs, unsigned long flags, const void *data) { + printf("[debug] start of syscall mount\n"); + return vfs_mount(target, fs); +} + +int sys_chdir(const char *path) { + printf("[debug] start of syscall chdir: %s\n", path); + + return vfs_chdir(path); +} + +void * const sys_call_table[] = +{ + sys_getpid, + sys_uartread, + sys_uartwrite, + sys_exec, + sys_fork, + sys_exit, + sys_mbox_call, + sys_kill, + 0, + 0, + 0, + sys_open, + sys_close, + sys_write, + sys_read, + sys_mkdir, + sys_mount, + sys_chdir +}; \ No newline at end of file diff --git a/lab7_novm/lib/timer.c b/lab7_novm/lib/timer.c new file mode 100644 index 000000000..ae102a2b0 --- /dev/null +++ b/lab7_novm/lib/timer.c @@ -0,0 +1,62 @@ +#include "timer.h" +#include "../include/sched.h" +#include "mini_uart.h" + +void timer_init() { + core_timer_enable(); + set_timer(read_freq()); +} + +void handle_timer_irq() { + //printf("Timer interrupt.\n"); + set_timer(read_freq()>>5); + timer_tick(); +} + +void core_timer_enable() { + + asm volatile( + "mov x0, 1\n\t" + "msr cntp_ctl_el0, x0\n\t" // enable + "mov x0, 2\n\t" + "ldr x1, =0x40000040\n\t" // CORE0_TIMER_IRQ_CTRL + "str w0, [x1]\n\t" // unmask timer interrupt + ); + +} + +void core_timer_disable() { + + asm volatile( + "mov x0, 0\n\t" + "ldr x1, =0x40000040\n\t" + "str w0, [x1]\n\t" + ); + +} + +void set_timer(unsigned int rel_time) { + + asm volatile( + "msr cntp_tval_el0, %0\n\t" + : + : "r" (rel_time) + ); + +} + +unsigned int read_timer() { + + unsigned int time; + asm volatile("mrs %0, cntpct_el0\n\t" : "=r" (time) : : "memory"); + return time; + +} + +unsigned int read_freq() { + + unsigned int freq; + asm volatile("mrs %0, cntfrq_el0\n\t": "=r" (freq) : : "memory"); + return freq; + +} diff --git a/lab7_novm/lib/tmpfs.c b/lab7_novm/lib/tmpfs.c new file mode 100644 index 000000000..b1f51196e --- /dev/null +++ b/lab7_novm/lib/tmpfs.c @@ -0,0 +1,154 @@ +#include "tmpfs.h" +#include "mm.h" +#include "string.h" +#include "mini_uart.h" + + +struct vnode_operations *tmpfs_v_ops; +struct file_operations *tmpfs_f_ops; +int tmpfs_registered = 0; + +int tmpfs_setup_mount(struct filesystem* fs, struct mount* mount) { + + mount->fs = fs; + mount->root = tmpfs_new_node(NULL, "/", DIRECTORY); + + printf("[debug] setup root: 0x%x\n", mount); + printf("[debug] setup root vnode: 0x%x\n", mount->root); + + return 0; +} + +int tmpfs_register() { + + if (tmpfs_registered) return -1; + tmpfs_registered = 1; + + tmpfs_v_ops = (struct vnode_operations *) chunk_alloc(sizeof(struct vnode_operations)); + tmpfs_f_ops = (struct file_operations *) chunk_alloc(sizeof(struct file_operations)); + + tmpfs_v_ops->lookup = tmpfs_lookup; + tmpfs_v_ops->create = tmpfs_create; + tmpfs_v_ops->mkdir = tmpfs_mkdir; + + tmpfs_f_ops->open = tmpfs_open; + tmpfs_f_ops->read = tmpfs_read; + tmpfs_f_ops->write = tmpfs_write; + tmpfs_f_ops->close = tmpfs_close; + + return 0; +} + +struct vnode* tmpfs_new_node(struct tmpfs_internal *parent, const char *name, int type) { + + struct vnode *new_node = (struct vnode *)chunk_alloc(sizeof(struct vnode)); + struct tmpfs_internal *new_internal = (struct tmpfs_internal *)chunk_alloc(sizeof(struct tmpfs_internal)); + + strcpy(new_internal->name, name); + new_internal->type = type; + new_internal->parent = parent; + new_internal->vnode = new_node; + new_internal->size = 0; + if (type == REGULAR_FILE) + new_internal->data = malloc(MAX_FILESIZE); + else + new_internal->data = 0; + + if (parent != NULL) + new_node->parent = parent->vnode; + new_node->f_ops = tmpfs_f_ops; + new_node->v_ops = tmpfs_v_ops; + new_node->mount = 0; + new_node->internal = (void *)new_internal; + + return new_node; + +} + +int tmpfs_open(struct vnode* file_node, struct file** target) { + return SUCCESS; +} + +int tmpfs_close(struct file *file) { + if (file) + return SUCCESS; + else + return FAIL; +} + +int tmpfs_write(struct file *file, const void *buf, unsigned len) { + struct tmpfs_internal *internal = (struct tmpfs_internal*)file->vnode->internal; + if (((struct tmpfs_internal *)file->vnode->internal)->type != REGULAR_FILE) + return FAIL; + + char *dest = &((char *)internal->data)[file->f_pos]; + char *src = (char *)buf; + int i = 0; + for (; i < len && internal->size+i < MAX_FILESIZE; i++) { + dest[i] = src[i]; + } + + internal->size += i; + + return i; +} + +int tmpfs_read(struct file *file, void *buf, unsigned len) { + + struct tmpfs_internal *internal = (struct tmpfs_internal*)file->vnode->internal; + if (internal->type != REGULAR_FILE) + return FAIL; + + char *dest = (char*)buf; + char *src = &((char *)internal->data)[file->f_pos]; + int i = 0; + for (; isize; i++) { + dest[i] = src[i]; + } + + return i; +} + +int tmpfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name) { + + struct tmpfs_internal *parent_internal = (struct tmpfs_internal *)dir_node->internal; + struct vnode *new_node = tmpfs_new_node(parent_internal, component_name, REGULAR_FILE); + + parent_internal->child[parent_internal->size] = (struct tmpfs_internal *)new_node->internal; + parent_internal->size++; + + *target = new_node; + return SUCCESS; +} + +int tmpfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name) { + + struct tmpfs_internal *parent_internal = (struct tmpfs_internal *)dir_node->internal; + struct vnode *new_node = tmpfs_new_node(parent_internal, component_name, DIRECTORY); + + parent_internal->child[parent_internal->size] = (struct tmpfs_internal *)new_node->internal; + parent_internal->size++; + + *target = new_node; + return SUCCESS; +} + +int tmpfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name) { + + if (stringcmp(component_name, "") == 0) { + *target = dir_node; + return 0; + } + + struct tmpfs_internal *internal = (struct tmpfs_internal *)dir_node->internal; + + for (int i=0; isize; i++) { + if(stringcmp(internal->child[i]->name, component_name) == 0) { + *target = internal->child[i]->vnode; + return internal->child[i]->type; + } + } + + return FAIL; + +} diff --git a/lab7_novm/lib/utils.S b/lab7_novm/lib/utils.S new file mode 100644 index 000000000..aa0e55aa9 --- /dev/null +++ b/lab7_novm/lib/utils.S @@ -0,0 +1,15 @@ +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret \ No newline at end of file diff --git a/lab7_novm/lib/vfs.c b/lab7_novm/lib/vfs.c new file mode 100644 index 000000000..0492dfc26 --- /dev/null +++ b/lab7_novm/lib/vfs.c @@ -0,0 +1,197 @@ +#include "vfs.h" +#include "tmpfs.h" +#include "initramfs.h" +#include "string.h" +#include "mm.h" +#include "sched.h" +#include "mini_uart.h" + +struct mount *rootfs; + +void rootfs_init() { + + struct filesystem *tmpfs = (struct filesystem *)chunk_alloc(sizeof(struct filesystem)); + tmpfs->name = (char *)chunk_alloc(16); + strcpy(tmpfs->name, "tmpfs"); + tmpfs->setup_mount = tmpfs_setup_mount; + register_fs(tmpfs); + + rootfs = (struct mount *)chunk_alloc(sizeof(struct mount)); + tmpfs->setup_mount(tmpfs, rootfs); + +} + +void initramfs_init() { + + vfs_mkdir("/initramfs"); + vfs_mount("/initramfs", "initramfs"); + parse_initramfs(); + +} + +int register_fs(struct filesystem *fs) { + if (stringcmp(fs->name, "tmpfs") == 0) { + return tmpfs_register(); + } else if (stringcmp(fs->name, "initramfs") == 0) { + return initramfs_register(); + } + return -1; +} + +struct file* create_fd(struct vnode* target, int flags) { + struct file* fd = (struct file*)chunk_alloc(sizeof(struct file)); + fd->f_ops = target->f_ops; + fd->vnode = target; + fd->f_pos = 0; + fd->flags = flags; + return fd; +} + +int vfs_open(const char *pathname, int flags, struct file **target) { + + *target = 0; + struct vnode *target_dir; + char target_path[VFS_PATHMAX]; + traverse(pathname, &target_dir, target_path); + + struct vnode *target_file; + if (target_dir->v_ops->lookup(target_dir, &target_file, target_path) == REGULAR_FILE) { + + *target = create_fd(target_file, flags); + return (*target)->f_ops->open(target_file, target); + + } else if (flags & O_CREAT) { + + int res = target_dir->v_ops->create(target_dir, &target_file, target_path); + if (res < 0) return FAIL; + *target = create_fd(target_file, flags); + return (*target)->f_ops->open(target_file, target); + + } else return FAIL; + +} + +int vfs_close(struct file *file) { + int code = file->f_ops->close(file); + if (code == SUCCESS) + chunk_free(file); + return code; +} + +int vfs_write(struct file *file, const void *buf, unsigned len) { + return file->f_ops->write(file, buf, len); +} + +int vfs_read(struct file *file, void *buf, unsigned len) { + return file->f_ops->read(file, buf, len); +} + +int vfs_mkdir(const char *pathname) { + struct vnode *target_dir; + char child_name[VFS_PATHMAX]; + traverse(pathname, &target_dir, child_name); + struct vnode *child_dir; + int res = target_dir->v_ops->mkdir(target_dir, &child_dir, child_name); + if (res < 0) return res; + return SUCCESS; +} + +int vfs_mount(const char *target, const char *filesystem) { + + struct vnode *mount_dir; + char path_remain[VFS_PATHMAX]; + + traverse(target, &mount_dir, path_remain); + + struct mount *mt = (struct mount *)chunk_alloc(sizeof(struct mount)); + if (stringcmp(filesystem, "tmpfs") == 0) { + + struct filesystem *tmpfs = (struct filesystem *)chunk_alloc(sizeof(struct filesystem)); + tmpfs->name = (char *)chunk_alloc(16); + strcpy(tmpfs->name, "tmpfs"); + tmpfs->setup_mount = tmpfs_setup_mount; + register_fs(tmpfs); + tmpfs->setup_mount(tmpfs, mt); + mount_dir->mount = mt; + mt->root->parent = mount_dir->parent; + + } else if (stringcmp(filesystem, "initramfs") == 0) { + + struct filesystem *initramfs = (struct filesystem *)chunk_alloc(sizeof(struct filesystem)); + initramfs->name = (char *)chunk_alloc(16); + strcpy(initramfs->name, "initramfs"); + initramfs->setup_mount = initramfs_setup_mount; + register_fs(initramfs); + initramfs->setup_mount(initramfs, mt); + mount_dir->mount = mt; + mt->root->parent = mount_dir->parent; + + } + + return SUCCESS; +} + +int vfs_lookup(const char *pathname, struct vnode **target) { + return SUCCESS; +} + +int vfs_chdir(const char *pathname) { + struct vnode *target_dir; + char path_remain[VFS_PATHMAX]; + traverse(pathname, &target_dir, path_remain); + if (stringcmp(path_remain, "") != 0) { + return FAIL; + } else { + + current->cwd = target_dir; + return SUCCESS; + } +} + +void traverse(const char* pathname, struct vnode **target_node, char *target_path) { + if (pathname[0] == '/') { + printf("[debug] traverse absolute path: %s\n", pathname); + struct vnode *rootnode = rootfs->root; + r_traverse(rootnode, pathname + 1, target_node, target_path); + } else { + printf("[debug] traverse relative path: %s\n", pathname); + struct vnode *rootnode = current->cwd; + r_traverse(rootnode, pathname, target_node, target_path); + } +} + +void r_traverse(struct vnode *node, const char *path, struct vnode **target_node, char *target_path) { + + int i = 0; + while (path[i]) { + if (path[i] == '/') break; + target_path[i] = path[i]; + i++; + } + target_path[i++] = '\0'; + *target_node = node; + + if (stringcmp(target_path, "") == 0) { + return; + } + else if (stringcmp(target_path, ".") == 0) { + r_traverse(node, path + i, target_node, target_path); + return; + } + else if (stringcmp(target_path, "..") == 0) { + if (node->parent == NULL) return; + r_traverse(node->parent, path + i, target_node, target_path); + return; + } + + int res = node->v_ops->lookup(node, target_node, target_path); + if ((*target_node)->mount != NULL) { + printf("[debug] mountpoint found during lookup: vnode 0x%x\n", (*target_node)->mount->root); + r_traverse((*target_node)->mount->root, path+i, target_node, target_path); + } + else if (res == DIRECTORY) + r_traverse(*target_node, path+i, target_node, target_path); + else if (res == REGULAR_FILE) + *target_node = node; + +} diff --git a/lab7_novm/rootfs/msg b/lab7_novm/rootfs/msg new file mode 100644 index 000000000..a04238969 --- /dev/null +++ b/lab7_novm/rootfs/msg @@ -0,0 +1 @@ +hello world! diff --git a/lab7_novm/send_img.py b/lab7_novm/send_img.py new file mode 100644 index 000000000..b2261950d --- /dev/null +++ b/lab7_novm/send_img.py @@ -0,0 +1,31 @@ +import argparse +import os +import time +import math +import serial + +parser = argparse.ArgumentParser(description='*.img uart sender') +parser.add_argument('-i', '--img', default='kernel8.img', type=str) +parser.add_argument('-d', '--device', default='/dev/ttyUSB0', type=str) +parser.add_argument('-b', '--baud', default=115200, type=int) + +args = parser.parse_args() + +img_size = os.path.getsize(args.img) + +with open(args.img, 'rb') as f: + with serial.Serial(args.device, args.baud) as tty: + + print(f'{args.img} is {img_size} bytes') + print('img file is now sending') + + tty.write(img_size.to_bytes(4, 'big')) + + input() + + for i in range(img_size): + tty.write(f.read(1)) + tty.flush() + #time.sleep(0.0001) + + print('img sent') diff --git a/lab8/FAT_R.TXT b/lab8/FAT_R.TXT new file mode 100644 index 000000000..5d2252cd1 --- /dev/null +++ b/lab8/FAT_R.TXT @@ -0,0 +1 @@ +fat_r test \ No newline at end of file diff --git a/lab8/config.txt b/lab8/config.txt new file mode 100644 index 000000000..86adbbb88 --- /dev/null +++ b/lab8/config.txt @@ -0,0 +1,4 @@ +kernel=btl.img +arm_64bit=1 +initramfs initrmfs.cpo 0x20000000 +device_tree=sfn.dtb diff --git a/lab8/include/cpio.h b/lab8/include/cpio.h new file mode 100644 index 000000000..1735f5fe5 --- /dev/null +++ b/lab8/include/cpio.h @@ -0,0 +1,49 @@ +#ifndef __CPIO_H__ +#define __CPIO_H__ + +/* +Each file system object in a cpio archive comprises a header record with +basic numeric metadata followed by the full pathname of the entry and the +file data. The header record stores a series of integer values that gen- +erally follow the fields in struct stat. (See stat(2) for details.) The +variants differ primarily in how they store those integers (binary, oc- +tal, or hexadecimal). The header is followed by the pathname of the en- +try (the length of the pathname is stored in the header) and any file +data. The end of the archive is indicated by a special record with the +pathname "TRAILER!!!" +*/ + +#define CPIO_HEADER_MAGIC "070701" +#define CPIO_FOOTER_MAGIC "TRAILER!!!" +#define PI_CPIO_BASE ((void*) (0x20000000)) +#define QEMU_CPIO_BASE ((void*) (0x8000000)) + +#include "devtree.h" + +extern void *DEVTREE_CPIO_BASE; + +struct cpio_newc_header { + char c_magic[6]; // 070701 + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; // ignored by readers +}; + +void initramfs_callback (char *, char *, struct fdt_prop *); +void cpio_ls (); +void cpio_cat (); +void cpio_exec (); + +unsigned int hexstr_to_uint(char *s, unsigned int len); + +#endif \ No newline at end of file diff --git a/lab8/include/devtree.h b/lab8/include/devtree.h new file mode 100644 index 000000000..d8225b11c --- /dev/null +++ b/lab8/include/devtree.h @@ -0,0 +1,64 @@ +#ifndef _DEVTREE_H +#define _DEVTREE_H + +/* + magic; 0xd00dfeed (big-endian) + + totalsize; total size in bytes of the devicetree + data structure + + off_dt_struct; offset in bytes of the structure block + from the beginning of the header + + off_dt_strings; offset in bytes of the strings block + from the beginning of the header + + off_mem_rsvmap; offset in bytes of the memory reservation + block from the beginning of the header + + version; version of the devicetree data structure + + last_comp_version; lowest version of the devicetree data + structure with which the version used is backwards compatible + + boot_cpuid_phys; physical ID of the system’s boot CPU + + size_dt_strings; length in bytes of the strings block + section of the devicetree blob + + size_dt_struct; length in bytes of the structure block + section of the devicetree blob +*/ + +#define FDT_HEADER_MAGIC 0xd00dfeed +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +struct fdt_header { + unsigned int magic; + unsigned int totalsize; + unsigned int off_dt_struct; + unsigned int off_dt_strings; + unsigned int off_mem_rsvmap; + unsigned int version; + unsigned int last_comp_version; + unsigned int boot_cpuid_phys; + unsigned int size_dt_strings; + unsigned int size_dt_struct; +}; + +struct fdt_prop { + unsigned int len; + unsigned int nameoff; +}; + +void devtree_getaddr (); +void fdt_traverse ( void (*callback)(char *, char *, struct fdt_prop *) ); + +// ARM uses little endian +unsigned int to_lendian (unsigned int); + +#endif \ No newline at end of file diff --git a/lab8/include/entry.h b/lab8/include/entry.h new file mode 100644 index 000000000..1a22d0284 --- /dev/null +++ b/lab8/include/entry.h @@ -0,0 +1,39 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#define S_FRAME_SIZE 272 // size of all saved registers +#define S_X0 0 + +#define SYNC_INVALID_EL1t 0 +#define IRQ_INVALID_EL1t 1 +#define FIQ_INVALID_EL1t 2 +#define ERROR_INVALID_EL1t 3 + +#define SYNC_INVALID_EL1h 4 +#define IRQ_INVALID_EL1h 5 +#define FIQ_INVALID_EL1h 6 +#define ERROR_INVALID_EL1h 7 + +#define SYNC_INVALID_EL0_64 8 +#define IRQ_INVALID_EL0_64 9 +#define FIQ_INVALID_EL0_64 10 +#define ERROR_INVALID_EL0_64 11 + +#define SYNC_INVALID_EL0_32 12 +#define IRQ_INVALID_EL0_32 13 +#define FIQ_INVALID_EL0_32 14 +#define ERROR_INVALID_EL0_32 15 + +#define SYNC_ERROR 16 +#define SYSCALL_ERROR 17 + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 + +#ifndef __ASSEMBLER__ + +void ret_from_fork(); + +#endif + +#endif \ No newline at end of file diff --git a/lab8/include/exception.h b/lab8/include/exception.h new file mode 100644 index 000000000..40f4ba532 --- /dev/null +++ b/lab8/include/exception.h @@ -0,0 +1,7 @@ +#ifndef _EXCEPTION_H +#define _EXCEPTION_H + +void enable_interrupt(); +void disable_interrupt(); + +#endif \ No newline at end of file diff --git a/lab8/include/fat32.h b/lab8/include/fat32.h new file mode 100644 index 000000000..443c5080e --- /dev/null +++ b/lab8/include/fat32.h @@ -0,0 +1,106 @@ +#ifndef _FAT32_H +#define _FAT32_H + +#include "vfs.h" + +#define BLOCK_SIZE 512 +#define FAT_ENTRY_PER_BLOCK (BLOCK_SIZE / sizeof(int)) +#define EOC 0xFFFFFFF + +#define FAT_MAX_DIRENT 16 +#define SFN_COMP_LEN 13 + +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; + +struct fat32_boot_sector { + char jmp[3]; + char oem[8]; + + // BIOS Parameter Block + uint16_t bytes_per_logical_sector; // 0xB-0xC + uint8_t logical_sector_per_cluster; // 0xD + uint16_t n_reserved_sectors; // 0xE-0xF + uint8_t n_file_alloc_tabs; // 0x10 + uint16_t n_max_root_dir_entries_16; // 0x11-0x12 + uint16_t n_logical_sectors_16; // 0x13-0x14 + uint8_t media_descriptor; // 0x15 + uint16_t logical_sector_per_fat_16; // 0x16-0x17 + + // DOS3.31 BPB + uint16_t physical_sector_per_track; // 0x18-0x19 + uint16_t n_heads; // 0x1A-0x1B + uint32_t n_hidden_sectors; // 0x1C-0x1F + uint32_t n_sectors_32; // 0x20-0x23 + + // FAT32 Extended BIOS Parameter Block + uint32_t n_sectors_per_fat_32; // 0x24-0x27 + uint16_t mirror_flag; // 0x28-0x29 + uint16_t version; // 0x2A-0x2B + uint32_t root_dir_start_cluster_num; // 0x2C-0x2F + uint16_t fs_info_sector_num; // 0x30-0x31 + uint16_t boot_sector_bak_first_sector_num; // 0x32-0x33 + uint32_t reserved[3]; // 0x34-0x3F + uint8_t physical_drive_num; // 0x40 + uint8_t unused; // 0x41 + uint8_t extended_boot_signature; // 0x42 + uint32_t volume_id; // 0x43-0x46 + uint8_t volume_label[11]; // 0x47-0x51 + uint8_t fat_system_type[8]; // 0x52-0x59 + +} __attribute__((packed)); + +struct fat32_dirent { + uint8_t name[8]; // 0x0-0x7 + uint8_t ext[3]; // 0x8-0xA + uint8_t attr; // 0xB + uint8_t reserved; // 0xC + uint8_t create_time[3]; // 0xD-0xF + uint16_t create_date; // 0x10-0x11 + uint16_t last_access_date; // 0x12-0x13 + uint16_t cluster_high; // 0x14-0x15 + uint32_t ext_attr; // 0x16-0x19 + uint16_t cluster_low; // 0x1A-0x1B + uint32_t size; // 0x1C-0x1F +} __attribute__((packed)); + +struct fat32_metadata { + uint32_t fat_region_blk_idx; + uint32_t n_fat; + uint32_t sector_per_fat; + uint32_t data_region_blk_idx; + uint32_t first_cluster; + uint8_t sector_per_cluster; +}; + +struct fat32_internal { + char name[SFN_COMP_LEN]; + int type; + struct fat32_internal *parent; + struct fat32_internal *child[FAT_MAX_DIRENT]; + struct vnode *vnode; + //int size; // use for child count and data size + //void *data; + uint32_t first_cluster; + uint32_t dirent_cluster; + uint32_t size; +}; + +int fat32_setup_mount(struct filesystem* fs, struct mount* mount); +int fat32_register(); + +struct vnode* fat32_new_node(struct fat32_internal *parent, const char *name, int type); + +int fat32_open(struct vnode *file_node, struct file **target); +int fat32_close(struct file *file); +int fat32_write(struct file *file, const void *buf, unsigned len); +int fat32_read(struct file *file, void *buf, unsigned len); +int fat32_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fat32_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fat32_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); +int fat32_load_vnode(struct vnode *dir_node, char *component_name); + +void parse_fat32sd(); + +#endif \ No newline at end of file diff --git a/lab8/include/fork.h b/lab8/include/fork.h new file mode 100644 index 000000000..7b018dc68 --- /dev/null +++ b/lab8/include/fork.h @@ -0,0 +1,26 @@ +#ifndef _FORK_H +#define _FORK_H + +#include "sched.h" + +#define PSR_MODE_EL0t 0x00000000 +#define PSR_MODE_EL1t 0x00000004 +#define PSR_MODE_EL1h 0x00000005 +#define PSR_MODE_EL2t 0x00000008 +#define PSR_MODE_EL2h 0x00000009 +#define PSR_MODE_EL3t 0x0000000c +#define PSR_MODE_EL3h 0x0000000d + +int copy_process(unsigned long, unsigned long, unsigned long, unsigned long); +int move_to_user_mode(unsigned long); +struct pt_regs *task_pt_regs(struct task_struct *); +void new_user_process(unsigned long); + +struct pt_regs { + unsigned long regs[31]; + unsigned long sp; + unsigned long pc; + unsigned long pstate; +}; + +#endif \ No newline at end of file diff --git a/lab8/include/initramfs.h b/lab8/include/initramfs.h new file mode 100644 index 000000000..80e9c9733 --- /dev/null +++ b/lab8/include/initramfs.h @@ -0,0 +1,35 @@ +#ifndef _INITRAMFS_H +#define _INITRAMFS_H + +#include "vfs.h" + +#define INITRAMFS_COMP_LEN 16 +#define MAX_DIRENT 16 +#define MAX_FILESIZE 0x1000 + +struct initramfs_internal { + char name[INITRAMFS_COMP_LEN]; + int type; + struct initramfs_internal *parent; + struct initramfs_internal *child[MAX_DIRENT]; + struct vnode *vnode; + int size; // use for child count and data size + void *data; +}; + +int initramfs_setup_mount(struct filesystem* fs, struct mount* mount); +int initramfs_register(); + +struct vnode* initramfs_new_node(struct initramfs_internal *parent, const char *name, int type); + +int initramfs_open(struct vnode *file_node, struct file **target); +int initramfs_close(struct file *file); +int initramfs_write(struct file *file, const void *buf, unsigned len); +int initramfs_read(struct file *file, void *buf, unsigned len); +int initramfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int initramfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +int initramfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); + +void parse_initramfs(); + +#endif \ No newline at end of file diff --git a/lab8/include/mailbox.h b/lab8/include/mailbox.h new file mode 100644 index 000000000..eeecaa9de --- /dev/null +++ b/lab8/include/mailbox.h @@ -0,0 +1,7 @@ +#ifndef _MAILBOX_H +#define _MAILBOX_H + +void get_board_revision (); +void get_arm_memory (); + +#endif \ No newline at end of file diff --git a/lab8/include/math.h b/lab8/include/math.h new file mode 100644 index 000000000..353ccfb26 --- /dev/null +++ b/lab8/include/math.h @@ -0,0 +1,7 @@ +#ifndef _MATH_H +#define _MATH_H + +int log(int, int); +int pow(int, int); + +#endif \ No newline at end of file diff --git a/lab8/include/mbr.h b/lab8/include/mbr.h new file mode 100644 index 000000000..5b9e0cd69 --- /dev/null +++ b/lab8/include/mbr.h @@ -0,0 +1,15 @@ +#ifndef _MBR_H +#define _MBR_H + +struct mbr_partition_tb { + unsigned char status_flag; //0x0 + unsigned char partition_begin_head; //0x1 + unsigned short partition_begin_sector; //0x2-0x3 + unsigned char partition_type; //0x4 + unsigned char partition_end_head; //0x5 + unsigned short partition_end_sector; //0x6-0x7 + unsigned int starting_sector; //0x8-0xB + unsigned int number_of_sector; //0xC-0xF +}; + +#endif \ No newline at end of file diff --git a/lab8/include/memory.h b/lab8/include/memory.h new file mode 100644 index 000000000..956f6e955 --- /dev/null +++ b/lab8/include/memory.h @@ -0,0 +1,8 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#define MAX_HEAP_SIZE 0x10000000 + +void* simple_malloc(unsigned int); + +#endif \ No newline at end of file diff --git a/lab8/include/mini_uart.h b/lab8/include/mini_uart.h new file mode 100644 index 000000000..453ec93f2 --- /dev/null +++ b/lab8/include/mini_uart.h @@ -0,0 +1,10 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void uart_init ( void ); +char uart_recv ( void ); +void uart_send ( char c ); +void uart_send_string ( char* str ); +void printf ( char *fmt, ... ); + +#endif /*_MINI_UART_H */ \ No newline at end of file diff --git a/lab8/include/mm.h b/lab8/include/mm.h new file mode 100644 index 000000000..df97f2b89 --- /dev/null +++ b/lab8/include/mm.h @@ -0,0 +1,55 @@ +#ifndef _MM_H +#define _MM_H + +#define MEM_REGION_BEGIN 0x0 +#define MEM_REGION_END 0x3C000000 +#define PAGE_SIZE 4096 +#define MAX_ORDER 8 // largest: PAGE_SIZE*2^(MAX_ORDER) + +#define ALLOCABLE 0 +#define ALLOCATED -1 +#define C_NALLOCABLE -2 +#define RESERVED -3 + +#define NULL 0 + +#define MAX_POOL_PAGES 8 +#define MAX_POOLS 8 +#define MIN_CHUNK_SIZE 8 + +#define MAX_RESERVABLE 8 + +struct frame { + unsigned int index; + int val; + int state; + struct frame *prev, *next; +}; + +struct node { + struct node *next; +}; + +struct dynamic_pool { + unsigned int chunk_size; + unsigned int chunks_per_page; + unsigned int chunks_allocated; + unsigned int page_new_chunk_off; + unsigned int pages_used; + void *page_base_addrs[MAX_POOL_PAGES]; + struct node *free_head; +}; + +void *malloc(unsigned int); +void free(void *); +void init_mm(); +void init_pool(struct dynamic_pool*, unsigned int); +int register_chunk(unsigned int); +void *chunk_alloc(unsigned int); +void chunk_free(void *); +void memory_reserve(void*, void*); +void init_mm_reserve(); + +void memzero(unsigned long, unsigned long); + +#endif /*_MM_H */ \ No newline at end of file diff --git a/lab8/include/peripherals/base.h b/lab8/include/peripherals/base.h new file mode 100644 index 000000000..8f66cd5fe --- /dev/null +++ b/lab8/include/peripherals/base.h @@ -0,0 +1,6 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +#define PBASE 0x3F000000 + +#endif /*_P_BASE_H */ \ No newline at end of file diff --git a/lab8/include/peripherals/exception.h b/lab8/include/peripherals/exception.h new file mode 100644 index 000000000..bc64c7c53 --- /dev/null +++ b/lab8/include/peripherals/exception.h @@ -0,0 +1,25 @@ +#ifndef _P_EXCEPTION_H +#define _P_EXCEPTION_H + +#include "peripherals/base.h" + +#define IRQ_BASIC_PENDING (PBASE+0x0000B200) +#define IRQ_PENDING_1 (PBASE+0x0000B204) +#define IRQ_PENDING_2 (PBASE+0x0000B208) +#define FIQ_CONTROL (PBASE+0x0000B20C) +#define ENABLE_IRQS_1 (PBASE+0x0000B210) +#define ENABLE_IRQS_2 (PBASE+0x0000B214) +#define ENABLE_BASIC_IRQS (PBASE+0x0000B218) +#define DISABLE_IRQS_1 (PBASE+0x0000B21C) +#define DISABLE_IRQS_2 (PBASE+0x0000B220) +#define DISABLE_BASIC_IRQS (PBASE+0x0000B224) + +#define CNTPCT_EL0 (0x4000001C) +#define CNTP_CTL_EL0 (0x40000040) +#define CORE0_INTERRUPT_SRC (0x40000060) + +#define IRQ_PENDING_1_AUX_INT (1<<29) +#define INTERRUPT_SOURCE_GPU (1<<8) +#define INTERRUPT_SOURCE_CNTPNSIRQ (1<<1) + +#endif \ No newline at end of file diff --git a/lab8/include/peripherals/gpio.h b/lab8/include/peripherals/gpio.h new file mode 100644 index 000000000..c5d7d138f --- /dev/null +++ b/lab8/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _P_GPIO_H +#define _P_GPIO_H + +#include "peripherals/base.h" + +#define GPFSEL1 (PBASE+0x00200004) +#define GPSET0 (PBASE+0x0020001C) +#define GPCLR0 (PBASE+0x00200028) +#define GPPUD (PBASE+0x00200094) +#define GPPUDCLK0 (PBASE+0x00200098) + +#endif /*_P_GPIO_H */ \ No newline at end of file diff --git a/lab8/include/peripherals/mailbox.h b/lab8/include/peripherals/mailbox.h new file mode 100644 index 000000000..0351bd714 --- /dev/null +++ b/lab8/include/peripherals/mailbox.h @@ -0,0 +1,23 @@ +#ifndef _P_MAILBOX_H +#define _P_MAILBOX_H + +#define MMIO_BASE 0x3f000000 +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#define MAILBOX_READ (volatile unsigned int*) (MAILBOX_BASE) +#define MAILBOX_STATUS (volatile unsigned int*) (MAILBOX_BASE + 0x18) +#define MAILBOX_WRITE (volatile unsigned int*) (MAILBOX_BASE + 0x20) + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 + +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +#endif \ No newline at end of file diff --git a/lab8/include/peripherals/mini_uart.h b/lab8/include/peripherals/mini_uart.h new file mode 100644 index 000000000..386b6fade --- /dev/null +++ b/lab8/include/peripherals/mini_uart.h @@ -0,0 +1,19 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_ENABLES (PBASE+0x00215004) +#define AUX_MU_IO_REG (PBASE+0x00215040) +#define AUX_MU_IER_REG (PBASE+0x00215044) +#define AUX_MU_IIR_REG (PBASE+0x00215048) +#define AUX_MU_LCR_REG (PBASE+0x0021504C) +#define AUX_MU_MCR_REG (PBASE+0x00215050) +#define AUX_MU_LSR_REG (PBASE+0x00215054) +#define AUX_MU_MSR_REG (PBASE+0x00215058) +#define AUX_MU_SCRATCH (PBASE+0x0021505C) +#define AUX_MU_CNTL_REG (PBASE+0x00215060) +#define AUX_MU_STAT_REG (PBASE+0x00215064) +#define AUX_MU_BAUD_REG (PBASE+0x00215068) + +#endif /*_P_MINI_UART_H */ \ No newline at end of file diff --git a/lab8/include/printf.h b/lab8/include/printf.h new file mode 100644 index 000000000..dfedbe301 --- /dev/null +++ b/lab8/include/printf.h @@ -0,0 +1,31 @@ +/* + * 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. + * + */ +#ifndef _PRINTF_H +#define _PRINTF_H + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); + +#endif \ No newline at end of file diff --git a/lab8/include/reboot.h b/lab8/include/reboot.h new file mode 100644 index 000000000..df4d63a86 --- /dev/null +++ b/lab8/include/reboot.h @@ -0,0 +1,7 @@ +#ifndef _REBOOT_H +#define _REBOOT_H + +void reset ( int ); +void cancel_reset (); + +#endif \ No newline at end of file diff --git a/lab8/include/sched.h b/lab8/include/sched.h new file mode 100644 index 000000000..d36d6e8ac --- /dev/null +++ b/lab8/include/sched.h @@ -0,0 +1,78 @@ +#ifndef _SCHED_H +#define _SCHED_H + +#define THREAD_CPU_CONTEXT 0 + +#ifndef __ASSEMBLER__ + +#include "vfs.h" + +#define THREAD_SIZE 4096 + +#define NR_TASKS 64 + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 + +#define PF_KTHREAD 0x00000002 + +extern struct task_struct *current; +extern struct task_struct *task[NR_TASKS]; +extern int nr_tasks; + +struct cpu_context { + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long sp; + unsigned long pc; +}; + +struct task_struct { + struct cpu_context cpu_context; + long state; + long counter; + long priority; + long preempt_count; + unsigned long stack; + unsigned long flags; + long id; + struct fd_table files; + struct vnode *cwd; +}; + +extern void sched_init(); +extern void schedule(); +extern void timer_tick(); +extern void preempt_disable(); +extern void preempt_enable(); +extern void switch_to(struct task_struct *); +extern void cpu_switch_to(struct task_struct *, struct task_struct *); +extern void exit_process(); +extern void kill_zombies(); + +#define INIT_TASK \ +{ \ +{0,0,0,0,0,0,0,0,0,0,0,0,0},\ +0, 0, 1, 0, 0, PF_KTHREAD, 0, \ +{0, {0}},\ +0 \ +} + +#endif + +#endif \ No newline at end of file diff --git a/lab8/include/sdhost.h b/lab8/include/sdhost.h new file mode 100644 index 000000000..6273636a5 --- /dev/null +++ b/lab8/include/sdhost.h @@ -0,0 +1,81 @@ +#ifndef _SDHOST_H +#define _SDHOST_H + +// mmio +#define KVA 0x0000000000000000 // vmem not used +#define MMIO_BASE (KVA + 0x3f000000) + +// SD card command +#define GO_IDLE_STATE 0 +#define SEND_OP_CMD 1 +#define ALL_SEND_CID 2 +#define SEND_RELATIVE_ADDR 3 +#define SELECT_CARD 7 +#define SEND_IF_COND 8 +#define VOLTAGE_CHECK_PATTERN 0x1aa +#define STOP_TRANSMISSION 12 +#define SET_BLOCKLEN 16 +#define READ_SINGLE_BLOCK 17 +#define WRITE_SINGLE_BLOCK 24 +#define SD_APP_OP_COND 41 +#define SDCARD_3_3V (1 << 21) +#define SDCARD_ISHCS (1 << 30) +#define SDCARD_READY (1 << 31) +#define APP_CMD 55 + +// gpio +#define GPIO_BASE (MMIO_BASE + 0x200000) +#define GPIO_GPFSEL4 (GPIO_BASE + 0x10) +#define GPIO_GPFSEL5 (GPIO_BASE + 0x14) +#define GPIO_GPPUD (GPIO_BASE + 0x94) +#define GPIO_GPPUDCLK1 (GPIO_BASE + 0x9c) + +// sdhost +#define SDHOST_BASE (MMIO_BASE + 0x202000) +#define SDHOST_CMD (SDHOST_BASE + 0) +#define SDHOST_READ 0x40 +#define SDHOST_WRITE 0x80 +#define SDHOST_LONG_RESPONSE 0x200 +#define SDHOST_NO_REPONSE 0x400 +#define SDHOST_BUSY 0x800 +#define SDHOST_NEW_CMD 0x8000 +#define SDHOST_ARG (SDHOST_BASE + 0x4) +#define SDHOST_TOUT (SDHOST_BASE + 0x8) +#define SDHOST_TOUT_DEFAULT 0xf00000 +#define SDHOST_CDIV (SDHOST_BASE + 0xc) +#define SDHOST_CDIV_MAXDIV 0x7ff +#define SDHOST_CDIV_DEFAULT 0x148 +#define SDHOST_RESP0 (SDHOST_BASE + 0x10) +#define SDHOST_RESP1 (SDHOST_BASE + 0x14) +#define SDHOST_RESP2 (SDHOST_BASE + 0x18) +#define SDHOST_RESP3 (SDHOST_BASE + 0x1c) +#define SDHOST_HSTS (SDHOST_BASE + 0x20) +#define SDHOST_HSTS_MASK (0x7f8) +#define SDHOST_HSTS_ERR_MASK (0xf8) +#define SDHOST_HSTS_DATA (1 << 0) +#define SDHOST_PWR (SDHOST_BASE + 0x30) +#define SDHOST_DBG (SDHOST_BASE + 0x34) +#define SDHOST_DBG_FSM_DATA 1 +#define SDHOST_DBG_FSM_MASK 0xf +#define SDHOST_DBG_MASK (0x1f << 14 | 0x1f << 9) +#define SDHOST_DBG_FIFO (0x4 << 14 | 0x4 << 9) +#define SDHOST_CFG (SDHOST_BASE + 0x38) +#define SDHOST_CFG_DATA_EN (1 << 4) +#define SDHOST_CFG_SLOW (1 << 3) +#define SDHOST_CFG_INTBUS (1 << 1) +#define SDHOST_SIZE (SDHOST_BASE + 0x3c) +#define SDHOST_DATA (SDHOST_BASE + 0x40) +#define SDHOST_CNT (SDHOST_BASE + 0x50) + +// helper +#define set(io_addr, val) \ + asm volatile("str %w1, [%0]" ::"r"(io_addr), "r"(val) : "memory"); + +#define get(io_addr, val) \ + asm volatile("ldr %w0, [%1]" : "=r"(val) : "r"(io_addr) : "memory"); + +void sd_init(); +void readblock(int block_idx, void* buf); +void writeblock(int block_idx, const void* buf); + +#endif \ No newline at end of file diff --git a/lab8/include/shell.h b/lab8/include/shell.h new file mode 100644 index 000000000..828c56763 --- /dev/null +++ b/lab8/include/shell.h @@ -0,0 +1,6 @@ +#ifndef _SHELL_H +#define _SHELL_H + +void shell_loop (); + +#endif \ No newline at end of file diff --git a/lab8/include/string.h b/lab8/include/string.h new file mode 100644 index 000000000..c71840033 --- /dev/null +++ b/lab8/include/string.h @@ -0,0 +1,10 @@ +#ifndef _STRING_H +#define _STRING_H + +int stringcmp (const char *, const char *); +int stringncmp (const char *, const char *, unsigned int); +unsigned int strlen(const char *); +void strcpy(char *dest, const char *src); +void strncpy(char *dest, const char *src, int n); + +#endif \ No newline at end of file diff --git a/lab8/include/syscall.h b/lab8/include/syscall.h new file mode 100644 index 000000000..429be1390 --- /dev/null +++ b/lab8/include/syscall.h @@ -0,0 +1,59 @@ +#ifndef _SYSCALL_H +#define _SYSCALL_H + +#define __NR_SYSCALLS 18 + +#define SYS_GETPID_NUM 0 +#define SYS_UARTREAD_NUM 1 +#define SYS_UARTWRITE_NUM 2 +#define SYS_EXEC_NUM 3 +#define SYS_FORK_NUM 4 +#define SYS_EXIT_NUM 5 +#define SYS_MBOXCALL_NUM 6 +#define SYS_KILL_NUM 7 + +#define SYS_OPEN_NUM 11 +#define SYS_CLOSE_NUM 12 +#define SYS_WRITE_NUM 13 +#define SYS_READ_NUM 14 +#define SYS_MKDIR_NUM 15 +#define SYS_MOUNT_NUM 16 +#define SYS_CHDIR_NUM 17 + +#ifndef __ASSEMBLER__ + +int getpid(); +unsigned uart_read(char buf[], unsigned size); +unsigned uart_write(const char buf[], unsigned size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(int status); +int mbox_call(unsigned char ch, volatile unsigned int *mbox); +void kill(int pid); +int open(const char *pathname, int flags); +int close(int fd); +long write(int fd, const void *buf, unsigned long count); +long read(int fd, void *buf, unsigned long count); +int mkdir(const char *pathname, unsigned mode); +int mount(const char *src, const char *target, const char *fs, unsigned long flags, const void *data); +int chdir(const char *path); + +int sys_getpid(); +unsigned sys_uartread(char buf[], unsigned size); +unsigned sys_uartwrite(const char buf[], unsigned size); +int sys_exec(const char *name, char *const argv[]); +int sys_fork(); +void sys_exit(int status); +int sys_mbox_call(unsigned char ch, unsigned int *mbox); +void sys_kill(int pid); +int sys_open(const char *pathname, int flags); +int sys_close(int fd); +long sys_write(int fd, const void *buf, unsigned long count); +long sys_read(int fd, void *buf, unsigned long count); +int sys_mkdir(const char *pathname, unsigned mode); +int sys_mount(const char *src, const char *target, const char *fs, unsigned long flags, const void *data); +int sys_chdir(const char *path); + +#endif + +#endif \ No newline at end of file diff --git a/lab8/include/timer.h b/lab8/include/timer.h new file mode 100644 index 000000000..9812a457a --- /dev/null +++ b/lab8/include/timer.h @@ -0,0 +1,14 @@ +#ifndef _TIMER_H +#define _TIMER_H + +#define CORE0_TIMER_IRQ_CTRL 0x40000040 + +void timer_init(); +void handle_timer_irq(); +void core_timer_enable(); +void core_timer_disable(); +void set_timer(unsigned int rel_time); +unsigned int read_timer(); +unsigned int read_freq(); + +#endif \ No newline at end of file diff --git a/lab8/include/tmpfs.h b/lab8/include/tmpfs.h new file mode 100644 index 000000000..f01824281 --- /dev/null +++ b/lab8/include/tmpfs.h @@ -0,0 +1,33 @@ +#ifndef _TMPFS_H +#define _TMPFS_H + +#include "vfs.h" + +#define TMPFS_COMP_LEN 16 +#define MAX_DIRENT 16 +#define MAX_FILESIZE 0x1000 + +struct tmpfs_internal { + char name[TMPFS_COMP_LEN]; + int type; + struct tmpfs_internal *parent; + struct tmpfs_internal *child[MAX_DIRENT]; + struct vnode *vnode; + int size; // use for child count and data size + void *data; +}; + +int tmpfs_setup_mount(); +int tmpfs_register(); + +struct vnode* tmpfs_new_node(struct tmpfs_internal *parent, const char *name, int type); + +int tmpfs_open(struct vnode *file_node, struct file **target); +int tmpfs_close(struct file *file); +int tmpfs_write(struct file *file, const void *buf, unsigned len); +int tmpfs_read(struct file *file, void *buf, unsigned len); +int tmpfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); + +#endif \ No newline at end of file diff --git a/lab8/include/utils.h b/lab8/include/utils.h new file mode 100644 index 000000000..9d950d477 --- /dev/null +++ b/lab8/include/utils.h @@ -0,0 +1,8 @@ +#ifndef _BOOT_H +#define _BOOT_H + +extern void delay ( unsigned long ); +extern void put32 ( unsigned long, unsigned int ); +extern unsigned int get32 ( unsigned long ); + +#endif /*_BOOT_H */ \ No newline at end of file diff --git a/lab8/include/vfs.h b/lab8/include/vfs.h new file mode 100644 index 000000000..cfa9d6c2d --- /dev/null +++ b/lab8/include/vfs.h @@ -0,0 +1,83 @@ +#ifndef _VFS_H +#define _VFS_H + +struct vnode { + struct vnode* parent; + struct mount* mount; + struct vnode_operations* v_ops; + struct file_operations* f_ops; + void* internal; +}; + +// file handle +struct file { + struct vnode* vnode; + unsigned f_pos; // RW position of this file handle + struct file_operations* f_ops; + int flags; +}; + +struct mount { + struct vnode* root; + struct filesystem* fs; +}; + +struct filesystem { + char* name; + int (*setup_mount)(struct filesystem* fs, struct mount* mount); +}; + +struct file_operations { + int (*write)(struct file* file, const void* buf, unsigned len); + int (*read)(struct file* file, void* buf, unsigned len); + int (*open)(struct vnode* file_node, struct file** target); + int (*close)(struct file* file); +}; + +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); + int (*load_vnode)(struct vnode* dir_node, char *component_name); +}; + +struct fd_table { + int count; + struct file *fds[16]; +}; + +#define VFS_PATHMAX 256 + +#define REGULAR_FILE -2 +#define DIRECTORY -3 + +#define O_CREAT 00000100 +#define SUCCESS 0 +#define FAIL -1 +#define EOF -1 + +extern struct mount *rootfs; + +void rootfs_init(); +void initramfs_init(); +void fat32_init(); + +int register_fs(struct filesystem *fs); +struct file* create_fd(struct vnode* target, int flags); +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, unsigned len); +int vfs_read(struct file *file, void *buf, unsigned len); + +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 vfs_chdir(const char *pathname); + +void traverse(const char* pathname, struct vnode** target_node, char *target_path); +void r_traverse(struct vnode *node, const char *path, struct vnode **target_node, char *target_path); + +#endif \ No newline at end of file diff --git a/lab8/initrmfs.cpo b/lab8/initrmfs.cpo new file mode 100644 index 000000000..cd77ea77a Binary files /dev/null and b/lab8/initrmfs.cpo differ diff --git a/lab8/kernel/Makefile b/lab8/kernel/Makefile new file mode 100644 index 000000000..831618b19 --- /dev/null +++ b/lab8/kernel/Makefile @@ -0,0 +1,49 @@ +AARCH64_PREFIX = aarch64-linux-gnu- +CC = $(AARCH64_PREFIX)gcc +LD = $(AARCH64_PREFIX)ld +OBJCPY = $(AARCH64_PREFIX)objcopy +GDB = $(AARCH64_PREFIX)gdb + +CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding -I../include -mgeneral-regs-only +ASMFLAGS = -I../include + +BUILD_DIR = ../build + +.PHONY: all clean qemu gdb_start + +all: kernel8.img + +clean: + rm kernel8.img $(OBJ_FILES) $(BUILD_DIR)/$(DEP_FILES) \ + ../build/kernel8.elf + +$(BUILD_DIR)/%_c.o: %.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: %.S + $(CC) $(ASMFLAGS) -MMD -c $< -o $@ + +C_FILES = $(wildcard *.c) +ASM_FILES = $(wildcard *.S) +OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) + +LIBC_FILES = $(wildcard ../lib/*.c) +LIBASM_FILES = $(wildcard ../lib/*.S) +LIBOBJ_FILES = $(LIBC_FILES:../lib/%.c=$(BUILD_DIR)/%_c.o) +LIBOBJ_FILES += $(LIBASM_FILES:../lib/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: linker.ld $(OBJ_FILES) $(LIBOBJ_FILES) + $(LD) -T linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) $(LIBOBJ_FILES) + $(OBJCPY) $(BUILD_DIR)/kernel8.elf -O binary $@ + +qemu: # all in one qemu command + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -S -s -serial null -serial pty \ + -initrd ../initramfs.cpio -dtb ../bcm2710-rpi-3-b-plus.dtb + +gdb_start: + $(GDB) $(BUILD_DIR)/kernel8.elf diff --git a/lab8/kernel/boot_kernel.S b/lab8/kernel/boot_kernel.S new file mode 100644 index 000000000..649bc4c69 --- /dev/null +++ b/lab8/kernel/boot_kernel.S @@ -0,0 +1,41 @@ +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 + and x0, x0, #3 // Check processor id + cbnz x0, proc_hang // Hang for all non-primary CPU + bl from_el2_to_el1 + bl set_exception_vector_table + +master: + ldr x0, =__bss_begin + ldr x1, =__bss_end + sub x1, x1, x0 + +memzero: + cbz x1, movesp + str xzr, [x0], #8 + subs x1, x1, #8 + cbnz x1, memzero + +movesp: + mov sp, #0x80000 + bl kernel_main + +proc_hang: + wfe + b proc_hang + +set_exception_vector_table: + adr x0, exception_vector_table + msr vbar_el1, x0 + ret + +from_el2_to_el1: + 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 \ No newline at end of file diff --git a/lab8/kernel/kernel.c b/lab8/kernel/kernel.c new file mode 100644 index 000000000..2b8609119 --- /dev/null +++ b/lab8/kernel/kernel.c @@ -0,0 +1,32 @@ +#include "mini_uart.h" +#include "shell.h" +#include "devtree.h" +#include "cpio.h" +#include "mm.h" +#include "timer.h" +#include "exception.h" +#include "fork.h" +#include "vfs.h" +#include "sdhost.h" + +void kernel_main(void) +{ + uart_init(); + devtree_getaddr(); + fdt_traverse(initramfs_callback); + init_mm_reserve(); + timer_init(); + rootfs_init(); + initramfs_init(); + sd_init(); + fat32_init(); + enable_interrupt(); + uart_send_string("OSDI 2022 Spring\n"); + + copy_process(PF_KTHREAD, (unsigned long)&shell_loop, 0, 0); + + while (1) { + kill_zombies(); + schedule(); + } +} \ No newline at end of file diff --git a/lab8/kernel/linker.ld b/lab8/kernel/linker.ld new file mode 100644 index 000000000..7ae6ad8c6 --- /dev/null +++ b/lab8/kernel/linker.ld @@ -0,0 +1,21 @@ +SECTIONS +{ + . = 0x80000; + + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + + . = ALIGN(8); + + __bss_begin = .; + .bss : { *(.bss* .bss.*) } + __bss_end = .; + + . = ALIGN(16); + + __heap_start = .; + __kernel_end = .; + +} diff --git a/lab8/lib/Makefile b/lab8/lib/Makefile new file mode 100644 index 000000000..66d9bcea3 --- /dev/null +++ b/lab8/lib/Makefile @@ -0,0 +1,29 @@ +AARCH64_PREFIX = aarch64-linux-gnu- +CC = $(AARCH64_PREFIX)gcc + +CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding -I../include -mgeneral-regs-only +ASMFLAGS = -I../include + +BUILD_DIR = ../build + +.PHONY: all clean + +$(BUILD_DIR)/%_c.o: %.c + mkdir -p $(@D) + $(CC) $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: %.S + $(CC) $(ASMFLAGS) -MMD -c $< -o $@ + +C_FILES = $(wildcard *.c) +ASM_FILES = $(wildcard *.S) +OBJ_FILES = $(C_FILES:%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +all: $(OBJ_FILES) + +clean: + rm $(OBJ_FILES) $(BUILD_DIR)/$(DEP_FILES) diff --git a/lab8/lib/cpio.c b/lab8/lib/cpio.c new file mode 100644 index 000000000..db3cc41fc --- /dev/null +++ b/lab8/lib/cpio.c @@ -0,0 +1,232 @@ +#include "../include/cpio.h" +#include "mini_uart.h" +#include "../include/sched.h" +#include "fork.h" +#include "string.h" + +void *DEVTREE_CPIO_BASE = 0; + +unsigned int hexstr_to_uint(char *s, unsigned int len) { + + unsigned int n = 0; + + for (int i=0; i= '0' && s[i] <= '9') { + n += s[i] - '0'; + } else if (s[i] >= 'A' && s[i] <= 'F') { + n += s[i] - 'A' + 10; + } + } + + return n; + +} + +void initramfs_callback(char *node_name, char *prop_name, struct fdt_prop *prop) { + + if (stringncmp(node_name, "chosen", 7) == 0 && + stringncmp(prop_name, "linux,initrd-start", 19) == 0) { + + DEVTREE_CPIO_BASE = (void*)to_lendian(*((unsigned int*)(prop + 1))); + + } + +} + +void cpio_ls() { + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + + header = DEVTREE_CPIO_BASE; + + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) break; + + uart_send_string(filename); + uart_send('\n'); + + namesize = hexstr_to_uint(header->c_namesize, 8); + filesize = hexstr_to_uint(header->c_filesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + +} + +void cpio_cat() { + + char input[256]; + char c = '\0'; + int idx = 0; + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + + header = DEVTREE_CPIO_BASE; + + uart_send_string("Filename: "); + + while (1) { + c = uart_recv(); + if (c == '\r' || c == '\n') { + uart_send_string("\n"); + + if (idx < 256) input[idx] = '\0'; + else input[255] = '\0'; + + break; + } else { + uart_send(c); + input[idx++] = c; + } + } + + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) { + uart_send_string("file does not exist!\n"); + break; + } + + namesize = hexstr_to_uint(header->c_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, input, namesize) == 0) { + + char *content = ((void*)header) + offset; + + for (int i=0; ic_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, input, namesize) == 0) { + + char *code_loc = ((void*)header) + offset; + unsigned int sp_val = 0x600000; + asm volatile( + "msr elr_el1, %0\n\t" + "msr spsr_el1, xzr\n\t" + "msr sp_el0, %1\n\t" + "eret\n\t" + :: + "r" (code_loc), + "r" (sp_val) + ); + + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + +} diff --git a/lab8/lib/devtree.c b/lab8/lib/devtree.c new file mode 100644 index 000000000..18d763c21 --- /dev/null +++ b/lab8/lib/devtree.c @@ -0,0 +1,92 @@ +#include "devtree.h" +#include "mini_uart.h" +#include "string.h" + +static void *DEVTREE_ADDRESS = 0; + +unsigned int to_lendian(unsigned int n) { + return ((n>>24)&0x000000FF) | + ((n>>8) &0x0000FF00) | + ((n<<8) &0x00FF0000) | + ((n<<24)&0xFF000000) ; +} + +void devtree_getaddr() { + + asm volatile("MOV %0, x20" : "=r"(DEVTREE_ADDRESS)); + + char magic[4] = {0xd0, 0x0d, 0xfe, 0xed}; + if(stringncmp((char*)DEVTREE_ADDRESS, magic, 4) != 0) { + uart_send_string("magic failed\n"); + } else { + uart_send_string("devtree magic succeed\n"); + } + +} + +void fdt_traverse( void (*callback)(char *, char *, struct fdt_prop *) ) { + + char magic[4] = {0xd0, 0x0d, 0xfe, 0xed}; + struct fdt_header *devtree_header = DEVTREE_ADDRESS; + + if(stringncmp((char*)devtree_header, magic, 4) != 0) { + uart_send_string("devtree magic failed\n"); + return; + } + + void *dt_struct_addr = DEVTREE_ADDRESS + to_lendian(devtree_header->off_dt_struct); + char *dt_string_addr = DEVTREE_ADDRESS + to_lendian(devtree_header->off_dt_strings); + + char *node_name; + char *prop_name; + unsigned int token; + unsigned int off; + + while (1) { + + token = to_lendian(*((unsigned int *)dt_struct_addr)); + + if (token == FDT_BEGIN_NODE) { + + node_name = dt_struct_addr + 4; + off = 4 + strlen(node_name) + 1; + + if (off%4 != 0) + off = ((off/4)+1)*4; + + dt_struct_addr += off; + + } + else if (token == FDT_END_NODE) { + dt_struct_addr += 4; + } + else if (token == FDT_PROP) { + + struct fdt_prop *prop = (struct fdt_prop*)(dt_struct_addr + 4); + + off = 4 + 8 + to_lendian(prop->len); + if (off%4 != 0) + off = ((off/4)+1)*4; + + dt_struct_addr += off; + + prop_name = dt_string_addr + to_lendian(prop->nameoff); + + callback(node_name, prop_name, prop); + + } + else if (token == FDT_NOP) { + dt_struct_addr += 4; + } + else if (token == FDT_END) { + dt_struct_addr += 4; + break; + } + else { + uart_send_string("TOKEN NOT MATCHED\n"); + break; + } + + } + +} \ No newline at end of file diff --git a/lab8/lib/entry.S b/lab8/lib/entry.S new file mode 100644 index 000000000..e564be0fe --- /dev/null +++ b/lab8/lib/entry.S @@ -0,0 +1,195 @@ +#include "entry.h" +#include "syscall.h" + +.macro handle_invalid_entry el, type + kernel_entry \el + mov x0, #\type + mrs x1, esr_el1 + mrs x2, elr_el1 + bl show_invalid_entry_message + b err_hang +.endm + +.macro ventry label + .align 7 + b \label +.endm + +// save general registers to stack +.macro kernel_entry, el + sub sp, sp, #S_FRAME_SIZE + 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] + + .if \el == 0 + mrs x21, sp_el0 + .else + add x21, sp, #S_FRAME_SIZE + .endif + + mrs x22, elr_el1 + mrs x23, spsr_el1 + + stp x30, x21, [sp, 16 * 15] + stp x22, x23, [sp, 16 * 16] +.endm + +// load general registers from stack +.macro kernel_exit, el + ldp x22, x23, [sp, 16 * 16] + ldp x30, x21, [sp, 16 * 15] + + .if \el == 0 + msr sp_el0, x21 + .endif + + msr elr_el1, x22 + msr spsr_el1, x23 + + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + add sp, sp, #S_FRAME_SIZE + eret +.endm + +.align 11 // vector table should be aligned to 0x800 +.globl exception_vector_table +exception_vector_table: + ventry sync_invalid_el1t // Synchronous EL1t + ventry irq_invalid_el1t // IRQ EL1t + ventry fiq_invalid_el1t // FIQ EL1t + ventry error_invalid_el1t // Error EL1t + + ventry sync_invalid_el1h // Synchronous EL1h + ventry el1_irq // IRQ EL1h + ventry fiq_invalid_el1h // FIQ EL1h + ventry error_invalid_el1h // Error EL1h + + ventry el0_sync // Synchronous 64-bit EL0 + ventry el0_irq // IRQ 64-bit EL0 + ventry fiq_invalid_el0_64 // FIQ 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 + + 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 + +sync_invalid_el1t: + handle_invalid_entry 1, SYNC_INVALID_EL1t + +irq_invalid_el1t: + handle_invalid_entry 1, IRQ_INVALID_EL1t + +fiq_invalid_el1t: + handle_invalid_entry 1, FIQ_INVALID_EL1t + +error_invalid_el1t: + handle_invalid_entry 1, ERROR_INVALID_EL1t + +sync_invalid_el1h: + handle_invalid_entry 1, SYNC_INVALID_EL1h + +el1_irq: + kernel_entry 1 + bl handle_irq + kernel_exit 1 + +fiq_invalid_el1h: + handle_invalid_entry 1, FIQ_INVALID_EL1h + +error_invalid_el1h: + handle_invalid_entry 1, ERROR_INVALID_EL1h + +el0_sync: + kernel_entry 0 + mrs x25, esr_el1 + lsr x24, x25, #ESR_ELx_EC_SHIFT + cmp x24, #ESR_ELx_EC_SVC64 + b.eq el0_svc + handle_invalid_entry 0, SYNC_ERROR + +el0_irq: + kernel_entry 0 + bl handle_irq + kernel_exit 0 + +fiq_invalid_el0_64: + handle_invalid_entry 0, FIQ_INVALID_EL0_64 + +error_invalid_el0_64: + handle_invalid_entry 0, ERROR_INVALID_EL0_64 + +sync_invalid_el0_32: + handle_invalid_entry 0, SYNC_INVALID_EL0_32 + +irq_invalid_el0_32: + handle_invalid_entry 0, IRQ_INVALID_EL0_32 + +fiq_invalid_el0_32: + handle_invalid_entry 0, FIQ_INVALID_EL0_32 + +error_invalid_el0_32: + handle_invalid_entry 0, ERROR_INVALID_EL0_32 + +sc_nr .req x25 +scno .req x26 +stbl .req x27 + +el0_svc: + adr stbl, sys_call_table + uxtw scno, w8 + mov sc_nr, #__NR_SYSCALLS + bl enable_interrupt + cmp scno, sc_nr + b.hs ni_sys + + ldr x16, [stbl, scno, lsl #3] + blr x16 + b ret_from_syscall +ni_sys: + handle_invalid_entry 0, SYSCALL_ERROR +ret_from_syscall: + bl disable_interrupt + str x0, [sp, #S_X0] + kernel_exit 0 + +.globl ret_from_fork +ret_from_fork: + bl schedule_tail + cbz x19, ret_to_user + mov x0, x20 + blr x19 // in theory should not return + //b err_hang // hang fail-safe +ret_to_user: + bl disable_interrupt + kernel_exit 0 + +.globl err_hang +err_hang: b err_hang diff --git a/lab8/lib/exception.c b/lab8/lib/exception.c new file mode 100644 index 000000000..a820ba662 --- /dev/null +++ b/lab8/lib/exception.c @@ -0,0 +1,49 @@ +#include "exception.h" +#include "mini_uart.h" +#include "mailbox.h" +#include "utils.h" +#include "timer.h" +#include "peripherals/exception.h" +#include "peripherals/mini_uart.h" + +void enable_interrupt() {asm volatile("msr DAIFClr, 0xf");} +void disable_interrupt() {asm volatile("msr DAIFSet, 0xf");} + +const char *entry_error_messages[] = { + "SYNC_INVALID_EL1t", + "IRQ_INVALID_EL1t", + "FIQ_INVALID_EL1t", + "ERROR_INVALID_EL1t", + + "SYNC_INVALID_EL1h", + "IRQ_INVALID_EL1h", + "FIQ_INVALID_EL1h", + "ERROR_INVALID_EL1h", + + "SYNC_INVALID_EL0_64", + "IRQ_INVALID_EL0_64", + "FIQ_INVALID_EL0_64", + "ERROR_INVALID_EL0_64", + + "SYNC_INVALID_EL0_32", + "IRQ_INVALID_EL0_32", + "FIQ_INVALID_EL0_32", + "ERROR_INVALID_EL0_32", + + "SYNC_ERROR", + "SYSCALL_ERROR" +}; + +void show_invalid_entry_message(int type, unsigned long esr, unsigned long addr) { + printf("%s, ESR: 0x%x, address: 0x%x\n", entry_error_messages[type], esr, addr); +} + +void handle_irq() { + + if (get32(CORE0_INTERRUPT_SRC)&INTERRUPT_SOURCE_CNTPNSIRQ) { + handle_timer_irq(); + } else { + printf("unknown irq encountered"); + } + +} \ No newline at end of file diff --git a/lab8/lib/fat32.c b/lab8/lib/fat32.c new file mode 100644 index 000000000..133ac3438 --- /dev/null +++ b/lab8/lib/fat32.c @@ -0,0 +1,377 @@ +#include "fat32.h" +#include "mbr.h" +#include "sdhost.h" +#include "mm.h" +#include "sched.h" +#include "string.h" +#include "mini_uart.h" + +struct vnode_operations *fat32_v_ops; +struct file_operations *fat32_f_ops; +int fat32_registered = 0; + +static struct fat32_metadata fat32_metadata; + +static uint32_t get_cluster_blk_idx(uint32_t cluster_idx) { + return fat32_metadata.data_region_blk_idx + + (cluster_idx - fat32_metadata.first_cluster) * fat32_metadata.sector_per_cluster; +} + +static uint32_t get_fat_blk_idx(uint32_t cluster_idx) { + return fat32_metadata.fat_region_blk_idx + (cluster_idx / FAT_ENTRY_PER_BLOCK); +} + +int fat32_setup_mount(struct filesystem* fs, struct mount* mount) { + + mount->fs = fs; + mount->root = fat32_new_node(NULL, "/", DIRECTORY); + + return 0; + +} + +int fat32_register() { + + if (fat32_registered) return -1; + fat32_registered = 1; + + fat32_v_ops = (struct vnode_operations *) chunk_alloc(sizeof(struct vnode_operations)); + fat32_f_ops = (struct file_operations *) chunk_alloc(sizeof(struct file_operations)); + + fat32_v_ops->lookup = fat32_lookup; + fat32_v_ops->create = fat32_create; + fat32_v_ops->mkdir = fat32_mkdir; + fat32_v_ops->load_vnode = fat32_load_vnode; + + fat32_f_ops->open = fat32_open; + fat32_f_ops->read = fat32_read; + fat32_f_ops->write = fat32_write; + fat32_f_ops->close = fat32_close; + + return 0; + +} + +struct vnode* fat32_new_node(struct fat32_internal *parent, const char *name, int type) { + + struct vnode *new_node = (struct vnode *)chunk_alloc(sizeof(struct vnode)); + struct fat32_internal *new_internal = (struct fat32_internal *)chunk_alloc(sizeof(struct fat32_internal)); + + strcpy(new_internal->name, name); + new_internal->type = type; + new_internal->parent = parent; + new_internal->vnode = new_node; + new_internal->size = 0; + + if (parent != NULL) + new_node->parent = parent->vnode; + new_node->f_ops = fat32_f_ops; + new_node->v_ops = fat32_v_ops; + new_node->mount = 0; + new_node->internal = (void *)new_internal; + + return new_node; + +} + +int fat32_open(struct vnode *file_node, struct file **target) { + return SUCCESS; +} + +int fat32_close(struct file *file) { + if (file) + return SUCCESS; + else + return FAIL; +} + +int fat32_write(struct file *file, const void *buf, unsigned len) { + struct fat32_internal *file_node = (struct fat32_internal *)file->vnode->internal; + unsigned int f_pos_ori = file->f_pos; + int fat[FAT_ENTRY_PER_BLOCK]; + char write_buf[BLOCK_SIZE]; + + uint32_t current_cluster = file_node->first_cluster; + int remain_offset = file->f_pos; + while (remain_offset > 0 && current_cluster >= fat32_metadata.first_cluster && current_cluster != EOC) { + remain_offset -= BLOCK_SIZE; + if (remain_offset > 0) { + readblock(get_fat_blk_idx(current_cluster), fat); + current_cluster = fat[current_cluster % FAT_ENTRY_PER_BLOCK]; + } + } + + int buf_idx, f_pos_offset = file->f_pos % BLOCK_SIZE; + readblock(get_cluster_blk_idx(current_cluster), write_buf); + for (buf_idx = 0; buf_idx < BLOCK_SIZE - f_pos_offset && buf_idx < len; buf_idx++) { + write_buf[buf_idx + f_pos_offset] = ((char *)buf)[buf_idx]; + } + writeblock(get_cluster_blk_idx(current_cluster), write_buf); + file->f_pos += buf_idx; + + int remain_len = len - buf_idx; + while (remain_len > 0 && current_cluster >= fat32_metadata.first_cluster && current_cluster != EOC) { + writeblock(get_cluster_blk_idx(current_cluster), buf + buf_idx); + file->f_pos += (remain_len < BLOCK_SIZE) ? remain_len : BLOCK_SIZE; + remain_len -= BLOCK_SIZE; + buf_idx += BLOCK_SIZE; + + if (remain_len > 0) { + readblock(get_fat_blk_idx(current_cluster), fat); + current_cluster = fat[current_cluster % FAT_ENTRY_PER_BLOCK]; + } + } + + if (file->f_pos > file_node->size) { + file_node->size = file->f_pos; + + uint8_t sector[BLOCK_SIZE]; + readblock(file_node->dirent_cluster, sector); + struct fat32_dirent *sector_dirent = (struct fat32_dirent*)sector; + + for (int i=0; sector_dirent[i].name[0] != '\0'; i++) { + if (sector_dirent[i].name[0] == 0xE5) continue; + + if (((sector_dirent[i].cluster_high << 16) | sector_dirent[i].cluster_low) == file_node->first_cluster) { + sector_dirent[i].size = (uint32_t)file->f_pos; + } + } + writeblock(file_node->dirent_cluster, sector); + } + + return file->f_pos - f_pos_ori; +} + +int fat32_read(struct file *file, void *buf, unsigned len) { + + struct fat32_internal *file_node = (struct fat32_internal *)file->vnode->internal; + unsigned int f_pos_ori = file->f_pos; + uint32_t current_cluster = file_node->first_cluster; + int remain_len = len; + int fat[FAT_ENTRY_PER_BLOCK]; + char tmp[512]; + + while (remain_len > 0 && current_cluster >= fat32_metadata.first_cluster && current_cluster != EOC) { + readblock(get_cluster_blk_idx(current_cluster), tmp+file->f_pos); + for (int i=0; i<512; i++) { + if (tmp[i] == '\0' || remain_len--<0) break; + ((char*)buf)[file->f_pos++] = tmp[i]; + } + + if (remain_len > 0) { + readblock(get_fat_blk_idx(current_cluster), fat); + current_cluster = fat[current_cluster % FAT_ENTRY_PER_BLOCK]; + } + } + + printf("[debug] fat32_read buf cont, len: %s %d\n", buf, file->f_pos - f_pos_ori); + return (file->f_pos - f_pos_ori); +} + +int fat32_create(struct vnode *dir_node, struct vnode **target, const char *component_name) { + + uint8_t sector[BLOCK_SIZE]; + struct fat32_internal *dir_internal = (struct fat32_internal *)dir_node->internal; + readblock(get_cluster_blk_idx(dir_internal->first_cluster), sector); + + struct fat32_dirent *sector_dirent = (struct fat32_dirent *)sector; + printf("[debug] 0\n"); + int idx=0; + while (sector_dirent[idx].name[0] != '\0' && sector_dirent[idx].name[0] != 0xE5) { + printf("[debug] first char: 0x%x\n", sector_dirent[idx].name[0]); + idx++; + } + printf("[debug] 1\n"); + int t=0; + while (component_name[t] != '.') { + sector_dirent[idx].name[t] = component_name[t]; + t++; + } + + int e=t+1; + while (t < 8) { + sector_dirent[idx].name[t] = ' '; + t++; + } + while (component_name[e] != '\0') { + sector_dirent[idx].ext[t-8] = component_name[e]; + e++; + t++; + } + printf("[debug] 2\n"); + // find empty usable cluster + int fat[FAT_ENTRY_PER_BLOCK]; + int found = 0; + uint32_t iter_cluster = fat32_metadata.first_cluster; + while (found != 1) { + readblock(get_fat_blk_idx(iter_cluster), fat); + if (fat[iter_cluster%FAT_ENTRY_PER_BLOCK] == 0x0) { + printf("[debug] create at empty cluster %d\n", iter_cluster); + found = 1; + sector_dirent[idx].cluster_high = iter_cluster >> 16; + sector_dirent[idx].cluster_low = iter_cluster & 0xFFFF; + break; + } + iter_cluster++; + } + if (found == 0) return FAIL; + sector_dirent[idx].attr = 0x20; + sector_dirent[idx].size = 0; + //sector_dirent[idx].cluster_high = 0; + //sector_dirent[idx].cluster_low = 0; + writeblock(get_cluster_blk_idx(dir_internal->first_cluster), sector_dirent); + + struct vnode *new_node = fat32_new_node(dir_internal, component_name, REGULAR_FILE); + struct fat32_internal *new_internal = (struct fat32_internal *)new_node->internal; + + new_internal->dirent_cluster = get_cluster_blk_idx(dir_internal->first_cluster); + new_internal->first_cluster = ((sector_dirent[idx].cluster_high) << 16) | (sector_dirent[idx].cluster_low); + + dir_internal->child[dir_internal->size] = new_internal; + dir_internal->size++; + + *target = new_node; + return SUCCESS; + +} + +int fat32_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name) { + return FAIL; +} + +int fat32_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name) { + printf("[debug] in fat32 lookup\n"); + if (stringcmp(component_name, "") == 0) { + *target = dir_node; + return 0; + } + + struct fat32_internal *internal = (struct fat32_internal *)dir_node->internal; + + for (int i=0; isize; i++) { + printf("[debug] filename: %s\n", internal->child[i]->name); + if(stringcmp(internal->child[i]->name, component_name) == 0) { + *target = internal->child[i]->vnode; + return internal->child[i]->type; + } + } + + return FAIL; + +} + +int fat32_load_vnode(struct vnode *dir_node, char *component_name) { + printf("[debug] load vnodes\n"); + struct fat32_internal *dir_internal = (struct fat32_internal *)dir_node->internal; + uint8_t sector[BLOCK_SIZE]; + uint32_t dirent_cluster = get_cluster_blk_idx(dir_internal->first_cluster); + readblock(dirent_cluster, sector); + + struct fat32_dirent *sector_dirent = (struct fat32_dirent *)sector; + + int found = FAIL; + for (int i=0; sector_dirent[i].name[0] != '\0'; i++) { + + if (sector_dirent[i].name[0] == 0xE5) continue; + if (sector_dirent[i].name[0] == 0x2E) continue; + + char filename[13]; + int len=0; + for (int j=0; j < 8; j++) { + char c = sector_dirent[i].name[j]; + if (c == ' ') break; + filename[len++] = c; + } + filename[len++] = '.'; + for (int j=0; j < 3; j++) { + char c = sector_dirent[i].ext[j]; + if (c == ' ') break; + filename[len++] = c; + } + filename[len++] = '\0'; + + for (int i=0; isize; i++) { + if (stringcmp(filename, dir_internal->child[i]->name) == 0) { + printf("[debug] %s already loaded\n", filename); + continue; + } + } + + printf("[debug] load file: %s\n", filename); + if (stringcmp(filename, component_name) == 0) found = SUCCESS; + + struct vnode* new_node; + struct fat32_internal *p_internal = (struct fat32_internal *)dir_node->internal; + if (sector_dirent[i].attr == 0x10) { + new_node = fat32_new_node(p_internal, filename, DIRECTORY); + + struct fat32_internal *internal = (struct fat32_internal *)new_node->internal; + internal->first_cluster = ((sector_dirent[i].cluster_high) << 16) | (sector_dirent[i].cluster_low); + internal->dirent_cluster = dirent_cluster; + + p_internal->child[p_internal->size] = internal; + } else { + new_node = fat32_new_node(p_internal, filename, REGULAR_FILE); + + struct fat32_internal *internal = (struct fat32_internal *)new_node->internal; + internal->first_cluster = ((sector_dirent[i].cluster_high) << 16) | (sector_dirent[i].cluster_low); + internal->dirent_cluster = dirent_cluster; + internal->size = sector_dirent[i].size; + + p_internal->child[p_internal->size] = internal; + } + + p_internal->size++; + + } + + return found; + +} + +void parse_fat32sd() { + + char buf[BLOCK_SIZE]; + readblock(0, buf); + + if (buf[510] != 0x55 || buf[511] != 0xAA) return; + + struct mbr_partition_tb pt1; + for (int i=0; in_sectors_per_fat_32 * boot_sector->n_file_alloc_tabs + + boot_sector->n_reserved_sectors; + fat32_metadata.fat_region_blk_idx = pt1.starting_sector + boot_sector->n_reserved_sectors; + fat32_metadata.n_fat = boot_sector->n_file_alloc_tabs; + fat32_metadata.sector_per_fat = boot_sector->n_sectors_per_fat_32; + fat32_metadata.first_cluster = boot_sector->root_dir_start_cluster_num; + fat32_metadata.sector_per_cluster = boot_sector->logical_sector_per_cluster; + + struct fat32_internal *root_internal = (struct fat32_internal *)current->cwd->internal; + root_internal->first_cluster = boot_sector->root_dir_start_cluster_num; + + printf("[debug] fat32_metadata:\n"); + printf(" data_region_blk_idx: 0x%x\n", fat32_metadata.data_region_blk_idx); + printf(" fat_region_blk_idx: 0x%x\n", fat32_metadata.fat_region_blk_idx); + printf(" n_fat: %d\n", fat32_metadata.n_fat); + printf(" sector_per_fat: %d\n", fat32_metadata.sector_per_fat); + printf(" first_cluster: 0x%x\n", fat32_metadata.first_cluster); + printf(" sector_per_cluster: %d\n", fat32_metadata.sector_per_cluster); + + vfs_chdir("/"); + + } + + return; + +} \ No newline at end of file diff --git a/lab8/lib/fork.c b/lab8/lib/fork.c new file mode 100644 index 000000000..75de715e0 --- /dev/null +++ b/lab8/lib/fork.c @@ -0,0 +1,85 @@ +#include "fork.h" +#include "mm.h" +#include "mini_uart.h" +#include "../include/sched.h" +#include "../include/entry.h" + +int copy_process(unsigned long clone_flags, unsigned long fn, unsigned long arg, unsigned long stack) { + + preempt_disable(); + struct task_struct *p; + + p = (struct task_struct *) malloc(PAGE_SIZE); + if (p == NULL) + return -1; + + struct pt_regs *childregs = task_pt_regs(p); + memzero((unsigned long)childregs, sizeof(struct pt_regs)); + memzero((unsigned long)&p->cpu_context, sizeof(struct cpu_context)); + + if (clone_flags & PF_KTHREAD) { + p->cpu_context.x19 = fn; + p->cpu_context.x20 = arg; + } else { + struct pt_regs *cur_regs = task_pt_regs(current); + // *childregs = *cur_regs; (object file generates memcpy) + // therefore the for loop is used below + for(int i=0; iregs[0] = 0; // return value 0 + childregs->sp = stack + PAGE_SIZE; + p->stack = stack; + } + + p->files = current->files; + p->cwd = current->cwd; + p->flags = clone_flags; + p->priority = current->priority; + p->state = TASK_RUNNING; + p->counter = p->priority; + p->preempt_count = 1; + + p->cpu_context.pc = (unsigned long)ret_from_fork; + p->cpu_context.sp = (unsigned long)childregs; + + int pid = nr_tasks++; + task[pid] = p; + p->id = pid; + preempt_enable(); + + return pid; + +} + +int move_to_user_mode(unsigned long pc) { + + struct pt_regs *regs = task_pt_regs(current); + memzero((unsigned long)regs, sizeof(*regs)); + regs->pc = pc; + regs->pstate = PSR_MODE_EL0t; + unsigned long stack = (unsigned long)malloc(PAGE_SIZE); + + if (stack == NULL) + return -1; + + regs->sp = stack + PAGE_SIZE; + current->stack = stack; + return 0; + +} + +struct pt_regs *task_pt_regs(struct task_struct *tsk) { + + unsigned long p = (unsigned long)tsk + THREAD_SIZE - sizeof(struct pt_regs); + return (struct pt_regs *)p; + +} + +void new_user_process(unsigned long func){ + printf("Kernel process started, moving to user mode.\n"); + int err = move_to_user_mode(func); + if (err < 0){ + printf("Error while moving process to user mode\n\r"); + } +} \ No newline at end of file diff --git a/lab8/lib/initramfs.c b/lab8/lib/initramfs.c new file mode 100644 index 000000000..8c2e60b0f --- /dev/null +++ b/lab8/lib/initramfs.c @@ -0,0 +1,209 @@ +#include "initramfs.h" +#include "mm.h" +#include "string.h" +#include "mini_uart.h" +#include "vfs.h" +#include "string.h" +#include "../include/cpio.h" + +struct vnode_operations *initramfs_v_ops; +struct file_operations *initramfs_f_ops; +int initramfs_registered = 0; + +int initramfs_setup_mount(struct filesystem* fs, struct mount* mount) { + + mount->fs = fs; + mount->root = initramfs_new_node(NULL, "/", DIRECTORY); + + return 0; + +} + +int initramfs_register() { + + if (initramfs_registered) return -1; + initramfs_registered = 1; + + initramfs_v_ops = (struct vnode_operations *) chunk_alloc(sizeof(struct vnode_operations)); + initramfs_f_ops = (struct file_operations *) chunk_alloc(sizeof(struct file_operations)); + + initramfs_v_ops->lookup = initramfs_lookup; + initramfs_v_ops->create = initramfs_create; + initramfs_v_ops->mkdir = initramfs_mkdir; + initramfs_v_ops->load_vnode = NULL; + + initramfs_f_ops->open = initramfs_open; + initramfs_f_ops->read = initramfs_read; + initramfs_f_ops->write = initramfs_write; + initramfs_f_ops->close = initramfs_close; + + return 0; + +} + +struct vnode* initramfs_new_node(struct initramfs_internal *parent, const char *name, int type) { + + struct vnode *new_node = (struct vnode *)chunk_alloc(sizeof(struct vnode)); + struct initramfs_internal *new_internal = (struct initramfs_internal *)chunk_alloc(sizeof(struct initramfs_internal)); + + strcpy(new_internal->name, name); + new_internal->type = type; + new_internal->parent = parent; + new_internal->vnode = new_node; + new_internal->size = 0; + if (type == REGULAR_FILE) + new_internal->data = malloc(MAX_FILESIZE); + else + new_internal->data = 0; + + if (parent != NULL) + new_node->parent = parent->vnode; + new_node->f_ops = initramfs_f_ops; + new_node->v_ops = initramfs_v_ops; + new_node->mount = 0; + new_node->internal = (void *)new_internal; + + return new_node; + +} + +int initramfs_open(struct vnode *file_node, struct file **target) { + return SUCCESS; +} + +int initramfs_close(struct file *file) { + if (file) + return SUCCESS; + else + return FAIL; +} + +int initramfs_write(struct file *file, const void *buf, unsigned len) { + return FAIL; +} + +int initramfs_read(struct file *file, void *buf, unsigned len) { + + struct initramfs_internal *internal = (struct initramfs_internal*)file->vnode->internal; + if (internal->type != REGULAR_FILE) + return FAIL; + + char *dest = (char*)buf; + char *src = &((char *)internal->data)[file->f_pos]; + int i = 0; + for (; isize; i++) { + dest[i] = src[i]; + } + + return i; +} + +int initramfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name) { + return FAIL; +} + +int initramfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name) { + return FAIL; +} + +int initramfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name) { + + if (stringcmp(component_name, "") == 0) { + *target = dir_node; + return 0; + } + + struct initramfs_internal *internal = (struct initramfs_internal *)dir_node->internal; + + for (int i=0; isize; i++) { + if(stringcmp(internal->child[i]->name, component_name) == 0) { + *target = internal->child[i]->vnode; + return internal->child[i]->type; + } + } + + return FAIL; + +} + +void parse_initramfs() { + + vfs_chdir("/initramfs"); + + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + unsigned int c_mode; + void *data; + char *filename; + + header = DEVTREE_CPIO_BASE; + + while (1) { + + struct vnode *target_node; + char target_path[VFS_PATHMAX]; + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) break; + + //uart_send_string(filename); + //uart_send('\n'); + + namesize = hexstr_to_uint(header->c_namesize, 8); + filesize = hexstr_to_uint(header->c_filesize, 8); + c_mode = hexstr_to_uint(header->c_mode, 5); + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + data = ((void *)header) + offset; + + if (stringncmp(header->c_mode, "00004", 5) == 0) { //dir + + printf("[debug] parse cpio mkdir %s\n", filename); + if (stringcmp(filename, ".") != 0 && stringcmp(filename, "..") != 0) { + traverse(filename, &target_node, target_path); + struct initramfs_internal *parent_internal = (struct initramfs_internal *)target_node->internal; + struct vnode *new_node = initramfs_new_node(parent_internal, target_path, DIRECTORY); + + parent_internal->child[parent_internal->size] = (struct initramfs_internal *)new_node->internal; + parent_internal->size++; + } else { + printf("[debug] mkdir skipped\n"); + } + + } else if (stringncmp(header->c_mode, "00008", 5) == 0) { //reg file + + printf("[debug] parse cpio create file %s, data at 0x%x with size 0x%d\n", filename, data, filesize); + traverse(filename, &target_node, target_path); + struct initramfs_internal *parent_internal = (struct initramfs_internal *)target_node->internal; + struct vnode *new_node = initramfs_new_node(parent_internal, target_path, REGULAR_FILE); + + parent_internal->child[parent_internal->size] = (struct initramfs_internal *)new_node->internal; + parent_internal->size++; + + ((struct initramfs_internal *)new_node->internal)->data = data; + ((struct initramfs_internal *)new_node->internal)->size = filesize; + + } else { + printf("[error] failed to parse cmode %d\n", c_mode); + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + + vfs_chdir("/"); + +} diff --git a/lab8/lib/mailbox.c b/lab8/lib/mailbox.c new file mode 100644 index 000000000..e593af037 --- /dev/null +++ b/lab8/lib/mailbox.c @@ -0,0 +1,49 @@ +#include "peripherals/mailbox.h" +#include "mailbox.h" +#include "mini_uart.h" + +int mailbox_call (volatile unsigned int *mailbox) { + unsigned int msg = ((unsigned long)mailbox & ~0xF) | (0x8 & 0xF); + while (*MAILBOX_STATUS & MAILBOX_FULL) ; + *MAILBOX_WRITE = msg; + while (1) { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) {} + if (msg == *MAILBOX_READ) { + return mailbox[1]; + } + } +} + +void get_board_revision () +{ + volatile unsigned int __attribute__((aligned(16))) mailbox[7]; + mailbox[0] = 7 * 4; + mailbox[1] = REQUEST_CODE; + mailbox[2] = GET_BOARD_REVISION; + mailbox[3] = 4; + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; + mailbox[6] = END_TAG; + + if (mailbox_call(mailbox) == REQUEST_SUCCEED) { + printf("Board Revision:\t\t%x\n", mailbox[5]); + } +} + +void get_arm_memory () +{ + volatile unsigned int __attribute__((aligned(16))) mailbox[8]; + mailbox[0] = 8 * 4; + mailbox[1] = REQUEST_CODE; + mailbox[2] = GET_ARM_MEMORY; + mailbox[3] = 8; + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; + mailbox[6] = 0; + mailbox[7] = END_TAG; + + if (mailbox_call(mailbox) == REQUEST_SUCCEED) { + printf("Memory Base Addresss:\t%x\n", mailbox[5]); + printf("Memory Size:\t\t%x\n", mailbox[6]); + } +} \ No newline at end of file diff --git a/lab8/lib/math.c b/lab8/lib/math.c new file mode 100644 index 000000000..6b6919044 --- /dev/null +++ b/lab8/lib/math.c @@ -0,0 +1,19 @@ +#include "math.h" + +int log(int n, int base) { + int x = 1; + int ret = 0; + while (x <= n) { + x *= base; + ret++; + } + return ret; +} + +int pow(int base, int pow) { + int ret = 1; + for (int i=0; i avail) { + uart_send_string("not enough memory\n"); + } else { + __heap_ptr += size; + avail -= size; + } + + return ptr; + +} \ No newline at end of file diff --git a/lab8/lib/mini_uart.c b/lab8/lib/mini_uart.c new file mode 100644 index 000000000..c209f3a90 --- /dev/null +++ b/lab8/lib/mini_uart.c @@ -0,0 +1,69 @@ +#include "utils.h" +#include "printf.h" +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" +#include "peripherals/exception.h" + +void uart_send ( char c ) +{ + if (c == '\n') uart_send('\r'); + + while (1) { + if (get32(AUX_MU_LSR_REG)&0x20) + break; + } + + put32(AUX_MU_IO_REG,c); +} + +char uart_recv ( void ) +{ + while(1) { + if (get32(AUX_MU_LSR_REG)&0x01) + break; + } + return (get32(AUX_MU_IO_REG)&0xFF); +} + +void uart_send_string ( char* str ) +{ + for (int i = 0; str[i] != '\0'; i++) { + uart_send((char)str[i]); + } +} + +void printf(char *fmt, ...) { + char temp[128]; + __builtin_va_list args; + __builtin_va_start(args, fmt); + vsprintf(temp,fmt,args); + uart_send_string(temp); +} + +void uart_init ( void ) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7<<12); // clean gpio14 + selector |= 2<<12; // set alt5 for gpio14 + selector &= ~(7<<15); // clean gpio15 + selector |= 2<<15; // set alt5 for gpio 15 + put32(GPFSEL1,selector); + + put32(GPPUD,0); + delay(150); + put32(GPPUDCLK0,(1<<14)|(1<<15)); + delay(150); + put32(GPPUDCLK0,0); + + put32(AUX_ENABLES,1); //Enable mini uart (this also enables access to its registers) + put32(AUX_MU_CNTL_REG,0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(AUX_MU_IER_REG,0); //Enable receive and disable transmit interrupts + put32(AUX_MU_LCR_REG,3); //Enable 8 bit mode + put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high + put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200 + put32(AUX_MU_IIR_REG,6); //Interrupt identify no fifo + put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver + +} diff --git a/lab8/lib/mm.S b/lab8/lib/mm.S new file mode 100644 index 000000000..263de4251 --- /dev/null +++ b/lab8/lib/mm.S @@ -0,0 +1,6 @@ +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret \ No newline at end of file diff --git a/lab8/lib/mm.c b/lab8/lib/mm.c new file mode 100644 index 000000000..05a5f6f50 --- /dev/null +++ b/lab8/lib/mm.c @@ -0,0 +1,376 @@ +#include "mm.h" +#include "math.h" +#include "memory.h" +#include "mini_uart.h" + +static unsigned int n_frames = 0; +static unsigned int max_size = 0; +static struct frame* frame_list[MAX_ORDER] = {NULL}; +static struct frame frame_array[(MEM_REGION_END-MEM_REGION_BEGIN)/PAGE_SIZE]; +static struct dynamic_pool pools[MAX_POOLS] = { {ALLOCABLE, 0, 0, 0, 0, {NULL}, NULL} }; +static unsigned int reserved_num = 0; +static void* reserved_se[MAX_RESERVABLE][2] = {{0x0, 0x0}}; // expects to be sorted and addresses [,) +extern char __kernel_end; +static char *__kernel_end_ptr = &__kernel_end; + +void *malloc(unsigned int size) { + + if (size > max_size) { + printf("[error] Request exceeded allocable continuous size %d.\n", (int)max_size); + return NULL; + } + + int req_order = 0; + for(unsigned int i=PAGE_SIZE; i= MAX_ORDER) { + printf("[error] No memory allocable.\n"); + return NULL; + } + + while (t != req_order) { + struct frame* l_tmp = frame_list[t]; + frame_list[t] = l_tmp->next; + frame_list[t]->prev = NULL; + //printf("[info] Split at order %d, new head is 0x%x.\n", t+1, frame_list[t]); + + unsigned int off = pow(2, l_tmp->val-1); + struct frame* r_tmp = &frame_array[l_tmp->index+off]; + + l_tmp->val -= 1; + l_tmp->state = ALLOCABLE; + l_tmp->prev = NULL; + l_tmp->next = r_tmp; + + r_tmp->val = l_tmp->val; + r_tmp->state = ALLOCABLE; + r_tmp->prev = l_tmp; + r_tmp->next = NULL; + + t--; + if (frame_list[t] != NULL) + frame_list[t]->prev = r_tmp; + r_tmp->next = frame_list[t]; + frame_list[t] = l_tmp; + } + + struct frame* ret = frame_list[req_order]; + frame_list[req_order] = ret->next; + frame_list[req_order]->prev = NULL; + + ret->val = ret->val; + ret->state = ALLOCATED; + ret->prev = NULL; + ret->next = NULL; + + //printf("[info] allocated address: 0x%x\n", MEM_REGION_BEGIN+PAGE_SIZE*ret->index); + + return (void*)MEM_REGION_BEGIN+PAGE_SIZE*ret->index; + +} + +void free(void *address) { + + unsigned int idx = ((unsigned long long)address-MEM_REGION_BEGIN) / PAGE_SIZE; + struct frame* target = &frame_array[idx]; + + if (target->state == ALLOCABLE || target->state == C_NALLOCABLE) { + printf("[error] invalid free of already freed memory.\n"); + return; + } + //printf("=========================================================\n"); + //printf("[info] Now freeing address 0x%x with frame index %d.\n", address, (int)idx); + + for (int i=target->val; ival+1, fr_buddy->state); + + if (i < MAX_ORDER-1 && fr_buddy->state == ALLOCABLE && i== fr_buddy->val) { + + //printf("[info] Merging from order %d. Frame indices %d, %d.\n", i+1, (int)buddy, (int)idx); + + if (fr_buddy->prev != NULL) { + fr_buddy->prev->next = fr_buddy->next; + } else { + frame_list[fr_buddy->val] = fr_buddy->next; + } + + if (fr_buddy->next != NULL) { + fr_buddy->next->prev = fr_buddy->prev; + } + + fr_buddy->prev = NULL; + fr_buddy->next = NULL; + fr_buddy->val = C_NALLOCABLE; + fr_buddy->state = C_NALLOCABLE; + target->val = C_NALLOCABLE; + target->state = C_NALLOCABLE; + + if (fr_buddy->index < target->index) { + idx = fr_buddy->index; + target = fr_buddy; + } + + //printf("[info] Frame index of next merge target is %d.\n", (int)idx); + + } else { + + target->val = i; + target->state = ALLOCABLE; + target->prev = NULL; + target->next = frame_list[i]; + if (frame_list[i] != NULL) + frame_list[i]->prev = target; + frame_list[i] = target; + //printf("[info] Frame index %d pushed to frame list of order %d.\n", + // (int)target->index, (int)i+1); + break; + + } + + } + + //printf("[info] Free finished.\n"); + /*for (int i=0; i < MAX_ORDER; i++) { + if (frame_list[i] != NULL) + printf("[info] Head of order %d has frame array index %d.\n",i+1,frame_list[i]->index); + else + printf("[info] Head of order %d has frame array index null.\n",i+1); + }*/ + +} + +void init_mm() { + + n_frames = (MEM_REGION_END-MEM_REGION_BEGIN) / PAGE_SIZE; + unsigned int mul = (unsigned int)pow(2, MAX_ORDER-1); + printf("[info] Frame array start address 0x%x.\n", frame_array); + for (unsigned int i=0; ichunk_size = size; + pool->chunks_per_page = PAGE_SIZE / size; + pool->chunks_allocated = 0; + pool->page_new_chunk_off = 0; + pool->pages_used = 0; + pool->free_head = NULL; +} + +int register_chunk(unsigned int size) { + + unsigned int nsize = 0; + if (size <= 8) nsize = 8; + else { + int rem = size % 4; + if (rem != 0) nsize = (size/4 + 1)*4; + else nsize = size; + } + + if (nsize >= PAGE_SIZE) { + printf("[error] Normalized chunk size request leq page size.\n"); + return -1; + } + + for (int i=0; ifree_head != NULL) { + void *ret = (void*) pool->free_head; + pool->free_head = pool->free_head->next; + //printf("[info] allocate address 0x%x from pool free list.\n", ret); + return ret; + } + + if (pool->chunks_allocated >= MAX_POOL_PAGES*pool->chunks_per_page) { + //printf("[error] Pool maximum reached.\n"); + return NULL; + } + + + if (pool->chunks_allocated >= pool->pages_used*pool->chunks_per_page) { + pool->page_base_addrs[pool->pages_used] = malloc(PAGE_SIZE); + //printf("[info] allocate new page for pool with base address 0x%x.\n", + // pool->page_base_addrs[pool->pages_used]); + pool->pages_used++; + pool->page_new_chunk_off = 0; + } + + void *ret = pool->page_base_addrs[pool->pages_used - 1] + + pool->chunk_size*pool->page_new_chunk_off; + pool->page_new_chunk_off++; + pool->chunks_allocated++; + + //printf("[info] allocate new address 0x%x from pool.\n", ret); + + return ret; + +} + +void chunk_free(void *address) { + + int target = -1; + + void *prefix_addr = (void *)((unsigned long long)address & ~0xFFF); + + for (unsigned int i=0; ifree_head; + pool->free_head = (struct node*) address; + pool->free_head->next = old_head; + pool->chunks_allocated--; + +} + +void memory_reserve(void* start, void* end) { + if (reserved_num >= MAX_RESERVABLE) { + printf("[error] Max reservable locations already reached.\n"); + return; + } + reserved_se[reserved_num][0] = start; + reserved_se[reserved_num][1] = end; + reserved_num++; +} + +void init_mm_reserve() { + + max_size = PAGE_SIZE * pow(2, MAX_ORDER-1); + n_frames = (MEM_REGION_END-MEM_REGION_BEGIN) / PAGE_SIZE; + + memory_reserve((void*)0x0, __kernel_end_ptr); // spin tables, kernel image + memory_reserve((void*)0x20000000, (void*)0x20010000); // hard code reserve initramfs + + for (unsigned int i=0; i= reserved_se[i][0] && addr < reserved_se[i][1]) { + frame_array[j].state = RESERVED; + } + if (addr >= reserved_se[i][1]) break; + } + } + + for (int i=0; istate == RESERVED) continue; + if (target->state == C_NALLOCABLE) continue; + + for (int i=target->val; istate == ALLOCABLE && i== fr_buddy->val) { + + if (fr_buddy->prev != NULL) { + fr_buddy->prev->next = fr_buddy->next; + } else { + frame_list[fr_buddy->val] = fr_buddy->next; + } + + if (fr_buddy->next != NULL) { + fr_buddy->next->prev = fr_buddy->prev; + } + + fr_buddy->prev = NULL; + fr_buddy->next = NULL; + fr_buddy->val = C_NALLOCABLE; + fr_buddy->state = C_NALLOCABLE; + target->val = C_NALLOCABLE; + target->state = C_NALLOCABLE; + + if (fr_buddy->index < target->index) { + idx = fr_buddy->index; + target = fr_buddy; + } + + } else { + + target->val = i; + target->state = ALLOCABLE; + target->prev = NULL; + target->next = frame_list[i]; + if (frame_list[i] != NULL) + frame_list[i]->prev = target; + frame_list[i] = target; + break; + + } + + } + + } + +} \ No newline at end of file diff --git a/lab8/lib/printf.c b/lab8/lib/printf.c new file mode 100644 index 000000000..794a37dff --- /dev/null +++ b/lab8/lib/printf.c @@ -0,0 +1,152 @@ +/* + * 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 + */ +#include "printf.h" + +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_start(args, fmt): "..." is pointed by args + //__builtin_va_arg(args,int): ret=(int)*args;args++;return ret; + __builtin_va_list args; + __builtin_va_start(args, fmt); + return vsprintf(dst,fmt,args); +} \ No newline at end of file diff --git a/lab8/lib/reboot.c b/lab8/lib/reboot.c new file mode 100644 index 000000000..043a09fb7 --- /dev/null +++ b/lab8/lib/reboot.c @@ -0,0 +1,18 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab8/lib/sched.S b/lab8/lib/sched.S new file mode 100644 index 000000000..03f9c56b1 --- /dev/null +++ b/lab8/lib/sched.S @@ -0,0 +1,24 @@ +#include "sched.h" + +.global cpu_switch_to +cpu_switch_to: + mov x10, #THREAD_CPU_CONTEXT + add x8, x0, x10 + mov x9, sp + stp x19, x20, [x8], #16 // store callee-saved registers + stp x21, x22, [x8], #16 + stp x23, x24, [x8], #16 + stp x25, x26, [x8], #16 + stp x27, x28, [x8], #16 + stp x29, x9, [x8], #16 + str x30, [x8] + add x8, x1, x10 + ldp x19, x20, [x8], #16 // restore callee-saved registers + ldp x21, x22, [x8], #16 + ldp x23, x24, [x8], #16 + ldp x25, x26, [x8], #16 + ldp x27, x28, [x8], #16 + ldp x29, x9, [x8], #16 + ldr x30, [x8] + mov sp, x9 + ret diff --git a/lab8/lib/sched.c b/lab8/lib/sched.c new file mode 100644 index 000000000..2ffc32acd --- /dev/null +++ b/lab8/lib/sched.c @@ -0,0 +1,107 @@ +#include "../include/sched.h" +#include "mm.h" +#include "exception.h" +#include "mini_uart.h" + +static struct task_struct init_task = INIT_TASK; +struct task_struct *current = &(init_task); +struct task_struct *task[NR_TASKS] = {&(init_task), }; +int nr_tasks = 1; + +void preempt_disable() { + current->preempt_count++; +} + +void preempt_enable() { + current->preempt_count--; +} + +void _schedule() { + + int next, c; + struct task_struct *p; + while (1) { + c = -1; + next = 0; + for (int i=0; istate == TASK_RUNNING && p->counter > c) { + c = p->counter; + next = i; + } + } + if (c) { + break; + } + for (int i=0; icounter = (p->counter >> 1) + p->priority; + } + } + preempt_disable(); // should be fine, if anything breaks move this to the top + switch_to(task[next]); + preempt_enable(); + +} + +void schedule() { + current->counter = 0; + _schedule(); +} + +void switch_to(struct task_struct *next) { + if (current == next) + return; + struct task_struct *prev = current; + current = next; + cpu_switch_to(prev, next); +} + +void schedule_tail() { + preempt_enable(); +} + +void timer_tick() { + + --current->counter; + if (current->counter > 0 || current->preempt_count > 0) + return; + + current->counter = 0; + enable_interrupt(); + _schedule(); + disable_interrupt(); + +} + +void exit_process() { + // should only be accessed using syscall + // preempt_disable(); + current->state = TASK_ZOMBIE; + free((void*)current->stack); + // preempt_enable(); + schedule(); +} + +void kill_zombies() { + + struct task_struct *p; + for (int i=0; istate == TASK_ZOMBIE) { + printf("Zombie found with pid: %d.\n", p->id); + free(p); + task[i] = NULL; + } + + } + +} \ No newline at end of file diff --git a/lab8/lib/sdhost.c b/lab8/lib/sdhost.c new file mode 100644 index 000000000..21a11a0de --- /dev/null +++ b/lab8/lib/sdhost.c @@ -0,0 +1,172 @@ +#include "sdhost.h" + +static inline void delay(unsigned long tick) { + while (tick--) { + asm volatile("nop"); + } +} + +static int is_hcs; // high capcacity(SDHC) + +static void pin_setup() { + set(GPIO_GPFSEL4, 0x24000000); + set(GPIO_GPFSEL5, 0x924); + set(GPIO_GPPUD, 0); + delay(15000); + set(GPIO_GPPUDCLK1, 0xffffffff); + delay(15000); + set(GPIO_GPPUDCLK1, 0); +} + +static void sdhost_setup() { + unsigned int tmp; + set(SDHOST_PWR, 0); + set(SDHOST_CMD, 0); + set(SDHOST_ARG, 0); + set(SDHOST_TOUT, SDHOST_TOUT_DEFAULT); + set(SDHOST_CDIV, 0); + set(SDHOST_HSTS, SDHOST_HSTS_MASK); + set(SDHOST_CFG, 0); + set(SDHOST_CNT, 0); + set(SDHOST_SIZE, 0); + get(SDHOST_DBG, tmp); + tmp &= ~SDHOST_DBG_MASK; + tmp |= SDHOST_DBG_FIFO; + set(SDHOST_DBG, tmp); + delay(250000); + set(SDHOST_PWR, 1); + delay(250000); + set(SDHOST_CFG, SDHOST_CFG_SLOW | SDHOST_CFG_INTBUS | SDHOST_CFG_DATA_EN); + set(SDHOST_CDIV, SDHOST_CDIV_DEFAULT); +} + +static int wait_sd() { + int cnt = 1000000; + unsigned int cmd; + do { + if (cnt == 0) { + return -1; + } + get(SDHOST_CMD, cmd); + --cnt; + } while (cmd & SDHOST_NEW_CMD); + return 0; +} + +static int sd_cmd(unsigned cmd, unsigned int arg) { + set(SDHOST_ARG, arg); + set(SDHOST_CMD, cmd | SDHOST_NEW_CMD); + return wait_sd(); +} + +static int sdcard_setup() { + unsigned int tmp; + sd_cmd(GO_IDLE_STATE | SDHOST_NO_REPONSE, 0); + sd_cmd(SEND_IF_COND, VOLTAGE_CHECK_PATTERN); + get(SDHOST_RESP0, tmp); + if (tmp != VOLTAGE_CHECK_PATTERN) { + return -1; + } + while (1) { + if (sd_cmd(APP_CMD, 0) == -1) { + // MMC card or invalid card status + // currently not support + continue; + } + sd_cmd(SD_APP_OP_COND, SDCARD_3_3V | SDCARD_ISHCS); + get(SDHOST_RESP0, tmp); + if (tmp & SDCARD_READY) { + break; + } + delay(1000000); + } + + is_hcs = tmp & SDCARD_ISHCS; + sd_cmd(ALL_SEND_CID | SDHOST_LONG_RESPONSE, 0); + sd_cmd(SEND_RELATIVE_ADDR, 0); + get(SDHOST_RESP0, tmp); + sd_cmd(SELECT_CARD, tmp); + sd_cmd(SET_BLOCKLEN, 512); + return 0; +} + +static int wait_fifo() { + int cnt = 1000000; + unsigned int hsts; + do { + if (cnt == 0) { + return -1; + } + get(SDHOST_HSTS, hsts); + --cnt; + } while ((hsts & SDHOST_HSTS_DATA) == 0); + return 0; +} + +static void set_block(int size, int cnt) { + set(SDHOST_SIZE, size); + set(SDHOST_CNT, cnt); +} + +static void wait_finish() { + unsigned int dbg; + do { + get(SDHOST_DBG, dbg); + } while ((dbg & SDHOST_DBG_FSM_MASK) != SDHOST_HSTS_DATA); +} + +void readblock(int block_idx, void* buf) { + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(512, 1); + sd_cmd(READ_SINGLE_BLOCK | SDHOST_READ, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + get(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts; + get(SDHOST_HSTS, hsts); + if (hsts & SDHOST_HSTS_ERR_MASK) { + set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void writeblock(int block_idx, const void* buf) { + unsigned int* buf_u = (unsigned int*)buf; + int succ = 0; + if (!is_hcs) { + block_idx <<= 9; + } + do{ + set_block(512, 1); + sd_cmd(WRITE_SINGLE_BLOCK | SDHOST_WRITE, block_idx); + for (int i = 0; i < 128; ++i) { + wait_fifo(); + set(SDHOST_DATA, buf_u[i]); + } + unsigned int hsts; + get(SDHOST_HSTS, hsts); + if (hsts & SDHOST_HSTS_ERR_MASK) { + set(SDHOST_HSTS, SDHOST_HSTS_ERR_MASK); + sd_cmd(STOP_TRANSMISSION | SDHOST_BUSY, 0); + } else { + succ = 1; + } + } while(!succ); + wait_finish(); +} + +void sd_init() { + pin_setup(); + sdhost_setup(); + sdcard_setup(); +} \ No newline at end of file diff --git a/lab8/lib/shell.c b/lab8/lib/shell.c new file mode 100644 index 000000000..d717325cb --- /dev/null +++ b/lab8/lib/shell.c @@ -0,0 +1,200 @@ +#include "shell.h" +#include "mini_uart.h" +#include "utils.h" +#include "mailbox.h" +#include "reboot.h" +#include "string.h" +#include "../include/cpio.h" +#include "memory.h" +#include "timer.h" +#include "exception.h" +#include "math.h" +#include "mm.h" +#include "../include/sched.h" +#include "syscall.h" +#include "peripherals/mailbox.h" +#include "fork.h" + + +#define MAX_BUFFER_SIZE 256u + +static char buffer[MAX_BUFFER_SIZE]; + +void foo() { + for(int i = 0; i < 10; ++i) { + printf("Thread id: %d %d\n", current->id, i); + delay(1000000); + schedule(); + } + + current->state = TASK_ZOMBIE; + while(1); +} + +void user_foo() { + + printf("User thread id: %d\n", getpid()); + char *msg = "hello world\n"; + int fd; + char buf[15]; + buf[14] = '\0'; + + fd = open("/initramfs/msg", 0); + read(fd, buf, 13); + close(fd); + + printf("%s", buf); + + exit(0); + +} + +void start_video() { + // ... go to cpio, find location and size of syscall.img + // allocate pages + // move syscall.img to allocated memory + // preempt disable + // change this shell thread to not runnable + // start sycall.img user process + // preempt enable + struct cpio_newc_header *header; + unsigned int filesize; + unsigned int namesize; + unsigned int offset; + char *filename; + void *code_loc; + + header = DEVTREE_CPIO_BASE; + while (1) { + + filename = ((void*)header) + sizeof(struct cpio_newc_header); + + if (stringncmp((char*)header, CPIO_HEADER_MAGIC, 6) != 0) { + uart_send_string("invalid magic\n"); + break; + } + if (stringncmp(filename, CPIO_FOOTER_MAGIC, 11) == 0) { + uart_send_string("file does not exist!\n"); + break; + } + + namesize = hexstr_to_uint(header->c_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, "vfs2.img", namesize) == 0) { + code_loc = ((void*)header) + offset; + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + printf("vfs2.img found in cpio at location 0x%x.\n", code_loc); + printf("vfs2.img has size of %d bytes.\n", (int)filesize); + + void *move_loc = malloc(filesize + 4096); // an extra page for bss just in case + if(move_loc == NULL) return; + for (int i=0; istate = TASK_STOPPED; + unsigned long long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + copy_process(PF_KTHREAD, (unsigned long)&new_user_process, (unsigned long)move_loc, 0); + preempt_enable(); + +} + +void read_cmd() +{ + unsigned int idx = 0; + char c = '\0'; + + while (1) { + c = uart_recv(); + if (c == '\r' || c == '\n') { + uart_send_string("\n"); + + if (idx < MAX_BUFFER_SIZE) buffer[idx] = '\0'; + else buffer[MAX_BUFFER_SIZE-1] = '\0'; + + break; + } else { + uart_send(c); + buffer[idx++] = c; + } + } + +} + +void parse_cmd() +{ + + if (stringcmp(buffer, "\0") == 0) + uart_send_string("\n"); + else if (stringcmp(buffer, "hello") == 0) + uart_send_string("Hello World!\n"); + else if (stringcmp(buffer, "reboot") == 0) { + uart_send_string("rebooting...\n"); + reset(100); + } + else if (stringcmp(buffer, "hwinfo") == 0) { + get_board_revision(); + get_arm_memory(); + } + else if (stringcmp(buffer, "ls") == 0) { + cpio_ls(); + } + else if (stringcmp(buffer, "cat") == 0) { + cpio_cat(); + } + else if (stringcmp(buffer, "execute") == 0) { + cpio_exec(); + } + else if (stringcmp(buffer, "thread_test") == 0) { + for (int i=0; i<10; i++) { + copy_process(PF_KTHREAD, (unsigned long)&foo, 0, 0); + } + } + else if (stringcmp(buffer, "to_user") == 0) { + copy_process(PF_KTHREAD, (unsigned long)&new_user_process, (unsigned long)&user_foo, 0); + } + else if (stringcmp(buffer, "video") == 0) { + start_video(); + } + else if (stringcmp(buffer, "help") == 0) { + uart_send_string("help:\t\tprint list of available commands\n"); + uart_send_string("hello:\t\tprint Hello World!\n"); + uart_send_string("reboot:\t\treboot device\n"); + uart_send_string("hwinfo:\t\tprint hardware information\n"); + uart_send_string("ls:\t\tlist initramfs files\n"); + uart_send_string("cat:\t\tprint file content in initramfs\n"); + uart_send_string("execute:\trun program from cpio\n"); + } + else + uart_send_string("Command not found! Type help for commands.\n"); + +} + +void shell_loop() +{ + while (1) { + uart_send_string("% "); + read_cmd(); + parse_cmd(); + } +} \ No newline at end of file diff --git a/lab8/lib/string.c b/lab8/lib/string.c new file mode 100644 index 000000000..f74819f4d --- /dev/null +++ b/lab8/lib/string.c @@ -0,0 +1,55 @@ +#include "string.h" + +int stringcmp(const char *p1, const char *p2) +{ + const unsigned char *s1 = (const unsigned char *) p1; + const unsigned char *s2 = (const unsigned char *) p2; + unsigned char c1, c2; + + do { + c1 = (unsigned char) *s1++; + c2 = (unsigned char) *s2++; + if (c1 == '\0') + return c1 - c2; + } while (c1 == c2); + + return c1 - c2; +} + +int stringncmp(const char *p1, const char *p2, unsigned int n) +{ + for (int i=0; iid; +} + +unsigned sys_uartread(char buf[], unsigned size) { + for(unsigned int i=0; ic_namesize, 8); + + offset = sizeof(struct cpio_newc_header) + namesize; + if (offset % 4 != 0) + offset = ((offset/4) + 1) * 4; + + filesize = hexstr_to_uint(header->c_filesize, 8); + + if (stringncmp(filename, name, namesize) == 0) { + code_loc = ((void*)header) + offset; + break; + } + + if (filesize % 4 != 0) + filesize = ((filesize/4) + 1) * 4; + + offset = offset + filesize; + + header = ((void*)header) + offset; + + } + + void *move_loc = malloc(filesize + 4096); // an extra page for bss just in case + if(move_loc == NULL) return -1; + for (int i=0; ipc = (unsigned long)move_loc; // move to beginning of program + p->sp = current->stack+PAGE_SIZE; + + preempt_enable(); + + return -1; // only on failure +} + +int sys_fork() { + return copy_process(0, 0, 0, (unsigned long)malloc(4*4096)); +} + +void sys_exit(int status) { + exit_process(); +} + +int sys_mbox_call(unsigned char ch, unsigned int *mbox) { + unsigned int r = (((unsigned int)((unsigned long)mbox)&~0xF) | (ch&0xF)); + while(*MAILBOX_STATUS & MAILBOX_FULL); + *MAILBOX_WRITE = r; + while (1) { + while (*MAILBOX_STATUS & MAILBOX_EMPTY) {} + if (r == *MAILBOX_READ) { + return mbox[1]==REQUEST_SUCCEED; + } + } + return 0; +} + +void sys_kill(int pid) { + + struct task_struct *p; + for (int i=0; iid == (long)pid) { + preempt_disable(); + printf("Kill target acquired.\n"); + p->state = TASK_ZOMBIE; + free((void *)p->stack); + preempt_enable(); + break; + } + + } + +} + +int sys_open(const char *pathname, int flags) { + printf("[debug] start of syscall open: %s %d\n", pathname, flags); + struct file *f; + int res = vfs_open(pathname, flags, &f); + if (res < 0) return -1; + + int fd_num = current->files.count; + + if (fd_num >= 16) { + for (int i=0; i<16; i++) { + if (current->files.fds[i] == 0) fd_num = i; + } + } + + if (fd_num >= 16) return -1; + + current->files.fds[fd_num] = f; + current->files.count++; + + return fd_num; +} + +int sys_close(int fd) { + printf("[debug] start of syscall close with fd %d\n", fd); + if (fd < 0) return -1; + + struct file *f = current->files.fds[fd]; + current->files.fds[fd] = 0; + + return vfs_close(f); +} + +long sys_write(int fd, const void *buf, unsigned long count) { + printf("[debug] start of syscall write with fd %d\n", fd); + + if (fd < 0) return -1; + + struct file *f = current->files.fds[fd]; + if (f == 0) return 0; + + return vfs_write(f, buf, count); +} + +long sys_read(int fd, void *buf, unsigned long count) { + printf("[debug] start of syscall read with fd %d\n", fd); + + if (fd < 0) return -1; + + struct file *f = current->files.fds[fd]; + if (f == 0) return 0; + + return vfs_read(f, buf, count); +} + +int sys_mkdir(const char *pathname, unsigned mode) { + printf("[debug] start of syscall mkdir\n"); + + return vfs_mkdir(pathname); +} + +int sys_mount(const char *src, const char *target, const char *fs, unsigned long flags, const void *data) { + printf("[debug] start of syscall mount\n"); + return vfs_mount(target, fs); +} + +int sys_chdir(const char *path) { + printf("[debug] start of syscall chdir: %s\n", path); + + return vfs_chdir(path); +} + +void * const sys_call_table[] = +{ + sys_getpid, + sys_uartread, + sys_uartwrite, + sys_exec, + sys_fork, + sys_exit, + sys_mbox_call, + sys_kill, + 0, + 0, + 0, + sys_open, + sys_close, + sys_write, + sys_read, + sys_mkdir, + sys_mount, + sys_chdir +}; \ No newline at end of file diff --git a/lab8/lib/timer.c b/lab8/lib/timer.c new file mode 100644 index 000000000..ae102a2b0 --- /dev/null +++ b/lab8/lib/timer.c @@ -0,0 +1,62 @@ +#include "timer.h" +#include "../include/sched.h" +#include "mini_uart.h" + +void timer_init() { + core_timer_enable(); + set_timer(read_freq()); +} + +void handle_timer_irq() { + //printf("Timer interrupt.\n"); + set_timer(read_freq()>>5); + timer_tick(); +} + +void core_timer_enable() { + + asm volatile( + "mov x0, 1\n\t" + "msr cntp_ctl_el0, x0\n\t" // enable + "mov x0, 2\n\t" + "ldr x1, =0x40000040\n\t" // CORE0_TIMER_IRQ_CTRL + "str w0, [x1]\n\t" // unmask timer interrupt + ); + +} + +void core_timer_disable() { + + asm volatile( + "mov x0, 0\n\t" + "ldr x1, =0x40000040\n\t" + "str w0, [x1]\n\t" + ); + +} + +void set_timer(unsigned int rel_time) { + + asm volatile( + "msr cntp_tval_el0, %0\n\t" + : + : "r" (rel_time) + ); + +} + +unsigned int read_timer() { + + unsigned int time; + asm volatile("mrs %0, cntpct_el0\n\t" : "=r" (time) : : "memory"); + return time; + +} + +unsigned int read_freq() { + + unsigned int freq; + asm volatile("mrs %0, cntfrq_el0\n\t": "=r" (freq) : : "memory"); + return freq; + +} diff --git a/lab8/lib/tmpfs.c b/lab8/lib/tmpfs.c new file mode 100644 index 000000000..91ec6c447 --- /dev/null +++ b/lab8/lib/tmpfs.c @@ -0,0 +1,155 @@ +#include "tmpfs.h" +#include "mm.h" +#include "string.h" +#include "mini_uart.h" + + +struct vnode_operations *tmpfs_v_ops; +struct file_operations *tmpfs_f_ops; +int tmpfs_registered = 0; + +int tmpfs_setup_mount(struct filesystem* fs, struct mount* mount) { + + mount->fs = fs; + mount->root = tmpfs_new_node(NULL, "/", DIRECTORY); + + printf("[debug] setup root: 0x%x\n", mount); + printf("[debug] setup root vnode: 0x%x\n", mount->root); + + return 0; +} + +int tmpfs_register() { + + if (tmpfs_registered) return -1; + tmpfs_registered = 1; + + tmpfs_v_ops = (struct vnode_operations *) chunk_alloc(sizeof(struct vnode_operations)); + tmpfs_f_ops = (struct file_operations *) chunk_alloc(sizeof(struct file_operations)); + + tmpfs_v_ops->lookup = tmpfs_lookup; + tmpfs_v_ops->create = tmpfs_create; + tmpfs_v_ops->mkdir = tmpfs_mkdir; + tmpfs_v_ops->load_vnode = NULL; + + tmpfs_f_ops->open = tmpfs_open; + tmpfs_f_ops->read = tmpfs_read; + tmpfs_f_ops->write = tmpfs_write; + tmpfs_f_ops->close = tmpfs_close; + + return 0; +} + +struct vnode* tmpfs_new_node(struct tmpfs_internal *parent, const char *name, int type) { + + struct vnode *new_node = (struct vnode *)chunk_alloc(sizeof(struct vnode)); + struct tmpfs_internal *new_internal = (struct tmpfs_internal *)chunk_alloc(sizeof(struct tmpfs_internal)); + + strcpy(new_internal->name, name); + new_internal->type = type; + new_internal->parent = parent; + new_internal->vnode = new_node; + new_internal->size = 0; + if (type == REGULAR_FILE) + new_internal->data = malloc(MAX_FILESIZE); + else + new_internal->data = 0; + + if (parent != NULL) + new_node->parent = parent->vnode; + new_node->f_ops = tmpfs_f_ops; + new_node->v_ops = tmpfs_v_ops; + new_node->mount = 0; + new_node->internal = (void *)new_internal; + + return new_node; + +} + +int tmpfs_open(struct vnode* file_node, struct file** target) { + return SUCCESS; +} + +int tmpfs_close(struct file *file) { + if (file) + return SUCCESS; + else + return FAIL; +} + +int tmpfs_write(struct file *file, const void *buf, unsigned len) { + struct tmpfs_internal *internal = (struct tmpfs_internal*)file->vnode->internal; + if (((struct tmpfs_internal *)file->vnode->internal)->type != REGULAR_FILE) + return FAIL; + + char *dest = &((char *)internal->data)[file->f_pos]; + char *src = (char *)buf; + int i = 0; + for (; i < len && internal->size+i < MAX_FILESIZE; i++) { + dest[i] = src[i]; + } + + internal->size += i; + + return i; +} + +int tmpfs_read(struct file *file, void *buf, unsigned len) { + + struct tmpfs_internal *internal = (struct tmpfs_internal*)file->vnode->internal; + if (internal->type != REGULAR_FILE) + return FAIL; + + char *dest = (char*)buf; + char *src = &((char *)internal->data)[file->f_pos]; + int i = 0; + for (; isize; i++) { + dest[i] = src[i]; + } + + return i; +} + +int tmpfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name) { + + struct tmpfs_internal *parent_internal = (struct tmpfs_internal *)dir_node->internal; + struct vnode *new_node = tmpfs_new_node(parent_internal, component_name, REGULAR_FILE); + + parent_internal->child[parent_internal->size] = (struct tmpfs_internal *)new_node->internal; + parent_internal->size++; + + *target = new_node; + return SUCCESS; +} + +int tmpfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name) { + + struct tmpfs_internal *parent_internal = (struct tmpfs_internal *)dir_node->internal; + struct vnode *new_node = tmpfs_new_node(parent_internal, component_name, DIRECTORY); + + parent_internal->child[parent_internal->size] = (struct tmpfs_internal *)new_node->internal; + parent_internal->size++; + + *target = new_node; + return SUCCESS; +} + +int tmpfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name) { + + if (stringcmp(component_name, "") == 0) { + *target = dir_node; + return 0; + } + + struct tmpfs_internal *internal = (struct tmpfs_internal *)dir_node->internal; + + for (int i=0; isize; i++) { + if(stringcmp(internal->child[i]->name, component_name) == 0) { + *target = internal->child[i]->vnode; + return internal->child[i]->type; + } + } + + return FAIL; + +} diff --git a/lab8/lib/utils.S b/lab8/lib/utils.S new file mode 100644 index 000000000..aa0e55aa9 --- /dev/null +++ b/lab8/lib/utils.S @@ -0,0 +1,15 @@ +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret \ No newline at end of file diff --git a/lab8/lib/vfs.c b/lab8/lib/vfs.c new file mode 100644 index 000000000..fdac169ed --- /dev/null +++ b/lab8/lib/vfs.c @@ -0,0 +1,225 @@ +#include "vfs.h" +#include "tmpfs.h" +#include "initramfs.h" +#include "fat32.h" +#include "string.h" +#include "mm.h" +#include "sched.h" +#include "mini_uart.h" + +struct mount *rootfs; + +void rootfs_init() { + + struct filesystem *tmpfs = (struct filesystem *)chunk_alloc(sizeof(struct filesystem)); + tmpfs->name = (char *)chunk_alloc(16); + strcpy(tmpfs->name, "tmpfs"); + tmpfs->setup_mount = tmpfs_setup_mount; + register_fs(tmpfs); + + rootfs = (struct mount *)chunk_alloc(sizeof(struct mount)); + tmpfs->setup_mount(tmpfs, rootfs); + +} + +void initramfs_init() { + + vfs_mkdir("/initramfs"); + vfs_mount("/initramfs", "initramfs"); + parse_initramfs(); + +} + +void fat32_init() { + + vfs_mkdir("/boot"); + vfs_mount("/boot", "fat32"); + parse_fat32sd(); + +} + +int register_fs(struct filesystem *fs) { + if (stringcmp(fs->name, "tmpfs") == 0) { + return tmpfs_register(); + } else if (stringcmp(fs->name, "initramfs") == 0) { + return initramfs_register(); + } else if (stringcmp(fs->name, "fat32") == 0) { + return fat32_register(); + } + return -1; +} + +struct file* create_fd(struct vnode* target, int flags) { + struct file* fd = (struct file*)chunk_alloc(sizeof(struct file)); + fd->f_ops = target->f_ops; + fd->vnode = target; + fd->f_pos = 0; + fd->flags = flags; + return fd; +} + +int vfs_open(const char *pathname, int flags, struct file **target) { + + *target = 0; + struct vnode *target_dir; + char target_path[VFS_PATHMAX]; + traverse(pathname, &target_dir, target_path); + + struct vnode *target_file; + if (target_dir->v_ops->lookup(target_dir, &target_file, target_path) == REGULAR_FILE) { + + *target = create_fd(target_file, flags); + return (*target)->f_ops->open(target_file, target); + + } else if (flags & O_CREAT) { + + int res = target_dir->v_ops->create(target_dir, &target_file, target_path); + if (res < 0) return FAIL; + *target = create_fd(target_file, flags); + return (*target)->f_ops->open(target_file, target); + + } else return FAIL; + +} + +int vfs_close(struct file *file) { + int code = file->f_ops->close(file); + if (code == SUCCESS) + chunk_free(file); + return code; +} + +int vfs_write(struct file *file, const void *buf, unsigned len) { + return file->f_ops->write(file, buf, len); +} + +int vfs_read(struct file *file, void *buf, unsigned len) { + return file->f_ops->read(file, buf, len); +} + +int vfs_mkdir(const char *pathname) { + struct vnode *target_dir; + char child_name[VFS_PATHMAX]; + traverse(pathname, &target_dir, child_name); + struct vnode *child_dir; + int res = target_dir->v_ops->mkdir(target_dir, &child_dir, child_name); + if (res < 0) return res; + return SUCCESS; +} + +int vfs_mount(const char *target, const char *filesystem) { + + struct vnode *mount_dir; + char path_remain[VFS_PATHMAX]; + + traverse(target, &mount_dir, path_remain); + + struct mount *mt = (struct mount *)chunk_alloc(sizeof(struct mount)); + if (stringcmp(filesystem, "tmpfs") == 0) { + + struct filesystem *tmpfs = (struct filesystem *)chunk_alloc(sizeof(struct filesystem)); + tmpfs->name = (char *)chunk_alloc(16); + strcpy(tmpfs->name, "tmpfs"); + tmpfs->setup_mount = tmpfs_setup_mount; + register_fs(tmpfs); + tmpfs->setup_mount(tmpfs, mt); + mount_dir->mount = mt; + mt->root->parent = mount_dir->parent; + + } else if (stringcmp(filesystem, "initramfs") == 0) { + + struct filesystem *initramfs = (struct filesystem *)chunk_alloc(sizeof(struct filesystem)); + initramfs->name = (char *)chunk_alloc(16); + strcpy(initramfs->name, "initramfs"); + initramfs->setup_mount = initramfs_setup_mount; + register_fs(initramfs); + initramfs->setup_mount(initramfs, mt); + mount_dir->mount = mt; + mt->root->parent = mount_dir->parent; + + } else if (stringcmp(filesystem, "fat32") == 0) { + + struct filesystem *fat32 = (struct filesystem *)chunk_alloc(sizeof(struct filesystem)); + fat32->name = (char *)chunk_alloc(16); + strcpy(fat32->name, "fat32"); + fat32->setup_mount = fat32_setup_mount; + register_fs(fat32); + fat32->setup_mount(fat32, mt); + mount_dir->mount = mt; + mt->root->parent = mount_dir->parent; + + } + + return SUCCESS; +} + +int vfs_lookup(const char *pathname, struct vnode **target) { + return SUCCESS; +} + +int vfs_chdir(const char *pathname) { + struct vnode *target_dir; + char path_remain[VFS_PATHMAX]; + traverse(pathname, &target_dir, path_remain); + if (stringcmp(path_remain, "") != 0) { + return FAIL; + } else { + + current->cwd = target_dir; + return SUCCESS; + } +} + +void traverse(const char* pathname, struct vnode **target_node, char *target_path) { + if (pathname[0] == '/') { + printf("[debug] traverse absolute path: %s\n", pathname); + struct vnode *rootnode = rootfs->root; + r_traverse(rootnode, pathname + 1, target_node, target_path); + } else { + printf("[debug] traverse relative path: %s\n", pathname); + struct vnode *rootnode = current->cwd; + r_traverse(rootnode, pathname, target_node, target_path); + } +} + +void r_traverse(struct vnode *node, const char *path, struct vnode **target_node, char *target_path) { + + int i = 0; + while (path[i]) { + if (path[i] == '/') break; + target_path[i] = path[i]; + i++; + } + target_path[i++] = '\0'; + *target_node = node; + + if (stringcmp(target_path, "") == 0) { + return; + } + else if (stringcmp(target_path, ".") == 0) { + r_traverse(node, path + i, target_node, target_path); + return; + } + else if (stringcmp(target_path, "..") == 0) { + if (node->parent == NULL) return; + r_traverse(node->parent, path + i, target_node, target_path); + return; + } + + int res = node->v_ops->lookup(node, target_node, target_path); printf("[debug] lookup ret: %d\n", res); + if ((*target_node)->mount != NULL) { + printf("[debug] mountpoint found during lookup: vnode 0x%x\n", (*target_node)->mount->root); + r_traverse((*target_node)->mount->root, path+i, target_node, target_path); + } + else if (res == DIRECTORY) + r_traverse(*target_node, path+i, target_node, target_path); + else if (res == REGULAR_FILE) + *target_node = node; + else if (res == FAIL && node->v_ops->load_vnode != NULL) { + int ret = node->v_ops->load_vnode(node, target_path); + if (ret == SUCCESS) { + r_traverse(node, path, target_node, target_path); + } + } + +} diff --git a/lab8/send_img.py b/lab8/send_img.py new file mode 100644 index 000000000..b2261950d --- /dev/null +++ b/lab8/send_img.py @@ -0,0 +1,31 @@ +import argparse +import os +import time +import math +import serial + +parser = argparse.ArgumentParser(description='*.img uart sender') +parser.add_argument('-i', '--img', default='kernel8.img', type=str) +parser.add_argument('-d', '--device', default='/dev/ttyUSB0', type=str) +parser.add_argument('-b', '--baud', default=115200, type=int) + +args = parser.parse_args() + +img_size = os.path.getsize(args.img) + +with open(args.img, 'rb') as f: + with serial.Serial(args.device, args.baud) as tty: + + print(f'{args.img} is {img_size} bytes') + print('img file is now sending') + + tty.write(img_size.to_bytes(4, 'big')) + + input() + + for i in range(img_size): + tty.write(f.read(1)) + tty.flush() + #time.sleep(0.0001) + + print('img sent') diff --git a/lab8/sfn.dtb b/lab8/sfn.dtb new file mode 100644 index 000000000..3934b3a26 Binary files /dev/null and b/lab8/sfn.dtb differ