diff --git a/Lab6/.vscode/c_cpp_properties.json b/Lab6/.vscode/c_cpp_properties.json new file mode 100644 index 000000000..96a36df82 --- /dev/null +++ b/Lab6/.vscode/c_cpp_properties.json @@ -0,0 +1,17 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/include" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "cStandard": "c11", + "cppStandard": "c++14", + "intelliSenseMode": "linux-clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/Lab6/.vscode/settings.json b/Lab6/.vscode/settings.json new file mode 100644 index 000000000..73281d200 --- /dev/null +++ b/Lab6/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "files.associations": { + "stdint.h": "c", + "memory.h": "c", + "array": "c", + "hash_map": "c", + "string_view": "c", + "initializer_list": "c", + "utility": "c", + "task.h": "c", + "allocator.h": "c", + "mini_uart.h": "c", + "exception.h": "c", + "mail_box.h": "c" + } +} \ No newline at end of file diff --git a/Lab6/Makefile b/Lab6/Makefile new file mode 100644 index 000000000..6ac0e3d50 --- /dev/null +++ b/Lab6/Makefile @@ -0,0 +1,45 @@ +.PHONY: all clean qemu-kernel on-board + +ARMGNU ?= aarch64-linux-gnu + +FLAGS = -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC +INC = include +LIB = lib +CPIO = archive/initramfs.cpio +USER_PROG = timer_test + +all: kernel8.img $(CPIO) $(USER_PROG).img + +kernel8.img: kernel/*.S kernel/*.c $(LIB)/*.S $(LIB)/*.c rd.o + $(ARMGNU)-gcc $(FLAGS) -Tkernel/linker.ld $^ -o kernel8.elf -I$(INC) + $(ARMGNU)-objcopy -O binary kernel8.elf kernel8.img + +$(USER_PROG).img: user/$(USER_PROG).c user/$(LIB)/*.c + $(ARMGNU)-gcc $(FLAGS) -Tuser/linker.ld $^ -o $(USER_PROG).elf -Iuser/$(INC) + $(ARMGNU)-objcopy -O binary $(USER_PROG).elf $(USER_PROG).img + +$(CPIO): $(USER_PROG).img + cd archive/rootfs && find . | cpio -o -H newc > ../initramfs.cpio + +rd.o:$(CPIO) + aarch64-linux-gnu-ld -r -b binary -o rd.o $(CPIO) + +qemu-kernel: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd archive/initramfs.cpio + +qemu-debug: + aarch64-linux-gnu-objdump -d kernel8.elf > kernel8.S + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd archive/initramfs.cpio -d in_asm + +# qemu-kernel: +# qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd $(CPIO) + +# qemu-debug: +# aarch64-linux-gnu-objdump -d kernel8.elf > kernel8.S +# qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd $(CPIO) -d in_asm + +on-board: + sudo screen /dev/ttyUSB0 115200 + +clean: + rm -f *.elf *.img *.cpio *.o *.S *.s \ No newline at end of file diff --git a/Lab6/archive/initramfs.cpio b/Lab6/archive/initramfs.cpio new file mode 100644 index 000000000..c64b96fa6 Binary files /dev/null and b/Lab6/archive/initramfs.cpio differ diff --git a/Lab6/archive/rootfs/dummy_test.img b/Lab6/archive/rootfs/dummy_test.img new file mode 100755 index 000000000..bb2aeb37e Binary files /dev/null and b/Lab6/archive/rootfs/dummy_test.img differ diff --git a/Lab6/archive/rootfs/exec_test.img b/Lab6/archive/rootfs/exec_test.img new file mode 100755 index 000000000..5665fbb19 Binary files /dev/null and b/Lab6/archive/rootfs/exec_test.img differ diff --git a/Lab6/archive/rootfs/fork_test.img b/Lab6/archive/rootfs/fork_test.img new file mode 100755 index 000000000..946319aff Binary files /dev/null and b/Lab6/archive/rootfs/fork_test.img differ diff --git a/Lab6/archive/rootfs/mbox_test.img b/Lab6/archive/rootfs/mbox_test.img new file mode 100755 index 000000000..289a5aca0 Binary files /dev/null and b/Lab6/archive/rootfs/mbox_test.img differ diff --git a/Lab6/archive/rootfs/timer_test.img b/Lab6/archive/rootfs/timer_test.img new file mode 100755 index 000000000..f0a191ddc Binary files /dev/null and b/Lab6/archive/rootfs/timer_test.img differ diff --git a/Lab6/archive/rootfs/vm.img b/Lab6/archive/rootfs/vm.img new file mode 100644 index 000000000..8ba674e6c Binary files /dev/null and b/Lab6/archive/rootfs/vm.img differ diff --git a/Lab6/bootloader/boot.S b/Lab6/bootloader/boot.S new file mode 100644 index 000000000..e72c38675 --- /dev/null +++ b/Lab6/bootloader/boot.S @@ -0,0 +1,40 @@ +.section ".text.relo" +.globl _start +# need to relocate the bootloader from 0x80000 to 0x60000 +_start: + adr x10, . //x10=0x80000 + ldr x11, =_blsize + add x11, x11, x10 + ldr x12, =_stext // x12=0x60000 + +moving_relo: + cmp x10, x11 //without bootloader + b.eq end_relo + ldr x13, [x10] + str x13, [x12] //move 0x80000 data to 0x60000 + add x12, x12, #8 + add x10, x10, #8 + b moving_relo +end_relo: + ldr x14, =_bl_entry //jump to boot part + br x14 + + +.section ".text.boot" +.globl _start_bl + mrs x0, mpidr_el1 + and x0, x0,#0xFF // Check processor id + cbz x0, master // Hang for all non-primary CPU + +hang: + b hang + +master: + adr x0, _sbss + adr x1, _ebss + sub x1, x1, x0 + bl memzero + + mov sp, #0x400000 // 4MB + bl main + \ No newline at end of file diff --git a/Lab6/bootloader/linker.ld b/Lab6/bootloader/linker.ld new file mode 100644 index 000000000..60c1e4351 --- /dev/null +++ b/Lab6/bootloader/linker.ld @@ -0,0 +1,28 @@ +ENTRY(_start) +SECTIONS +{ + . = 0x60000; + _stext = .; + .text : { + *(.text.relo) + _bl_entry = .; + *(.text.boot) + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + + _blsize = _ebss - _stext; +} \ No newline at end of file diff --git a/Lab6/bootloader/main.c b/Lab6/bootloader/main.c new file mode 100644 index 000000000..86f193d73 --- /dev/null +++ b/Lab6/bootloader/main.c @@ -0,0 +1,36 @@ +#include "mini_uart.h" +#include "utils.h" + +void load_kernel() { + char buffer[MAX_BUFFER_SIZE]; + + while (compare_string(buffer, "[Load Kernel]") != 0) { + uart_recv_string(buffer); + } + + unsigned long k_addr=0,k_size=0; + uart_send_string("Please enter kernel load address (Hex): "); + + uart_recv_string(buffer); + k_addr = getHexFromString(buffer); + uart_send_string("Please enter kernel size (Dec): "); + uart_recv_string(buffer); + k_size = getIntegerFromString(buffer); + + uart_send_string("Please send kernel image now...\n"); + unsigned char* target=(unsigned char*)k_addr; + while(k_size--){ + *target=uart_getb(); + target++; + uart_send('.'); + } + + uart_send_string("loading...\n"); + asm volatile("br %0\n"::"r"(k_addr)); // GCC inline assembly +} + +int main() { + uart_init(); + load_kernel(); + return 0; // should not reach here +} \ No newline at end of file diff --git a/Lab6/include/allocator.h b/Lab6/include/allocator.h new file mode 100644 index 000000000..24a7ea44d --- /dev/null +++ b/Lab6/include/allocator.h @@ -0,0 +1,40 @@ +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include "memory.h" +#include + +/* + Partition of a 4K page: (size, amount) + (32, 32) (64, 15) (128, 8) (256, 4) + + First 64 byte is used to record usage of each slot, shown below: + uint32_t usage32; + uint16_t usage64; // upper 1 bit is not used + uint8_t usage128; + uint8_t usage258; // upper 4 bits reserve for future use + + [Future use] 4 bits of record of 256-bytes slot can be used to represent fused mode to get larger slot +*/ + +void *kmalloc(size_t size); +void kfree(void *addr); +uint64_t get_slot_record(frame_free_node *page, int size); +void set_slot_record(frame_free_node *page, int size, int which_slot, int value); +int is_full(frame_free_node *page, int size); +int is_empty(frame_free_node *page, int size); +int round_to_smallest(size_t size); +frame_free_node *get_page_with_slot(int size); +void *allocate_slot(frame_free_node *page, int size); +frame_free_node *find_page(void *addr); +void clear_page(frame_free_node *page); +void print_slot_record(frame_free_node *page); +void free_page_if_empty(frame_free_node *page); + +/* + memory reservation +*/ +void memory_reserve(uint64_t start, uint64_t end); +void init_reserve(); + +#endif \ No newline at end of file diff --git a/Lab6/include/cpio.h b/Lab6/include/cpio.h new file mode 100644 index 000000000..5aa3f44ec --- /dev/null +++ b/Lab6/include/cpio.h @@ -0,0 +1,43 @@ +#ifndef __CPIO__ +#define __CPIO__ + +#include "peripherals/base.h" + +#define __USE_QEMU__ + +#ifdef __USE_QEMU__ +#define CPIO_ADDR ((char *)(KVA + 0x8000000)) // qemu +#else +#define CPIO_ADDR ((char *)(KVA + 0x20000000)) // raspi3 +#endif +#define MAX_INITRAMFS_SIZE 0x100000 // 1M + +#define USER_PROGRAM_VA 0x0 +#define MAX_USER_PROGRAM_SIZE 0x100000 // 1M + + +typedef struct +{ + // uses 8-byte hexadecimal fields for all numbers + char magic[6]; //determine whether this archive is written with little-endian or big-endian integers. + char ino[8]; //determine when two entries refer to the same file. + char mode[8]; //specifies both the regular permissions and the file type. + char uid[8]; // numeric user id + char gid[8]; // numeric group id + char nlink[8]; // number of links to this file. + char mtime[8]; // Modification time of the file + char filesize[8]; // size of the file + char devmajor[8]; + char devminor[8]; + char rdevmajor[8]; + char rdevminor[8]; + char namesize[8]; // number of bytes in the pathname + char check[8]; // always set to zero by writers and ignored by readers. +} __attribute__((packed)) cpio_header; + +void cpio_list(); +void cpio_cat(char *filename); +char * findFile(char *name); +void load_program(char *name, void *page_table); + +#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..31b87d1d7 --- /dev/null +++ b/Lab6/include/exception.h @@ -0,0 +1,34 @@ +#ifndef _EXCEPTION_H +#define _EXCEPTION_H + +#include "task.h" +#include + +void enable_interrupt(); +void disable_interrupt(); +void dumpState(); +void lower_sync_handler(); +void lower_iqr_handler(); +void curr_sync_handler(); +void curr_iqr_handler(); +void error_handler(); +void child_return_from_fork(); + +/* Implement system calls */ +int sys_getpid(); +size_t sys_uartread(char buf[], size_t size); +size_t sys_uartwrite(const char buf[], size_t size); +int sys_exec(trap_frame *tf, const char *name, char *const argv[]); +void sys_fork(trap_frame *tf); +void sys_exit(); +int sys_mbox_call(unsigned char ch, volatile unsigned int *mbox); +void sys_kill(int pid); +void sys_signal(int SIGNAL, void (*handler)()); +void sys_signal_kill(int pid, int SIGNAL); + +/* helper functions */ +extern void (*_handler)(); +extern int _pid; +void signal_handler_wrapper(); + +#endif diff --git a/Lab6/include/mail_box.h b/Lab6/include/mail_box.h new file mode 100644 index 000000000..981fcd628 --- /dev/null +++ b/Lab6/include/mail_box.h @@ -0,0 +1,45 @@ +#ifndef _MAIL_BOX_H +#define _MAIL_BOX_H + +/* a properly aligned buffer */ +extern volatile unsigned int mailbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_GETSERIAL 0x10004 +#define MBOX_TAG_LAST 0 +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_EMEORY 0x00010005 + +int mailbox_call(unsigned char ch, volatile unsigned int *mailbox, volatile unsigned int *mailbox_va); + + +/* old macros from lab1 */ +// #define GET_BOARD_REVISION 0x00010002 +// #define GET_ARM_EMEORY 0x00010005 +// #define REQUEST_CODE 0x00000000 +// #define REQUEST_SUCCEED 0x80000000 +// #define REQUEST_FAILED 0x80000001 +// #define TAG_REQUEST_CODE 0x00000000 +// #define END_TAG 0x00000000 + +// extern volatile unsigned int mailbox[8]; + +// int mailbox_call(unsigned char ch, volatile unsigned int *mbox); +void get_board_revision(); +void get_arm_memory(); +void get_serial_number(); + +#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..3d3c34631 --- /dev/null +++ b/Lab6/include/memory.h @@ -0,0 +1,43 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#include +#include +#include "peripherals/base.h" + +#define MEMORY_BASE_ADDR (KVA + 0x10000000) +#define MEMORY_END_ADDR (KVA + 0x10000000 + 0x10000000) +#define PAGE_SIZE_4K ((uint64_t)1 << 12) +#define FRAME_ARRAY_SIZE ((MEMORY_END_ADDR - MEMORY_BASE_ADDR) / PAGE_SIZE_4K) +#define MAX_32K_NUM (FRAME_ARRAY_SIZE / 8) +#define GET_PAGE_ADDR(index) (MEMORY_BASE_ADDR + (index << 12)) +#define GET_PAGE_INDEX(addr) ((addr - MEMORY_BASE_ADDR) >> 12) + + +typedef struct frame_free_node { + uint64_t index; + struct frame_free_node *next; + struct frame_free_node *prev; // double linked list to enable O(1) removal + struct frame_free_node **list_addr; // find out which list it belongs to in Q(1) +} frame_free_node; + +void memory_init(); +uint64_t page_malloc(int sz); +uint64_t request_page(int size); +uint64_t reserve_page(int size, uint64_t addr); +void page_free(uint64_t addr, int size); +void merge_page(uint64_t index, int size); +void pop_front(frame_free_node **list); +void remove_from_list(frame_free_node **list, uint64_t index); +void add_to_list(frame_free_node **list, uint64_t index); +uint64_t getIndex(uint64_t addr, int size); +frame_free_node *get_free_node(); +void return_free_node(frame_free_node *node); +uint64_t get_allocated_num(); +uint64_t get_free_num(); +void clear_4K_page(uint64_t index); + +void print_frame_array(); +void print_frame_free_lists(); + +#endif diff --git a/Lab6/include/mini_uart.h b/Lab6/include/mini_uart.h new file mode 100644 index 000000000..319eb2dd6 --- /dev/null +++ b/Lab6/include/mini_uart.h @@ -0,0 +1,28 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void delay(unsigned int clock); +void uart_init( void ); +char uart_recv( void ); +void uart_send ( char c ); +void uart_send_string(char* str); +unsigned int uart_printf(char* fmt,...); +void uart_recv_string(char *buffer); +unsigned char uart_getb(); +void uart_hex(unsigned int d); + +extern char read_buf[]; +extern char write_buf[]; +extern int read_buf_start, read_buf_end; +extern int write_buf_start, write_buf_end; + +void enable_uart_interrupt(); +void disable_uart_interrupt(); +void set_transmit_interrupt(); +void clear_transmit_interrupt(); +void uart_handler(); +void test_uart_async(); +char uart_async_recv(); +void uart_async_send_string(char *str); + +#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..63d247edd --- /dev/null +++ b/Lab6/include/mm.h @@ -0,0 +1,19 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SHIFT 12 +#define TABLE_SHIFT 9 +#define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) + +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define SECTION_SIZE (1 << SECTION_SHIFT) + +#define LOW_MEMORY (2 * SECTION_SIZE) + +#ifndef __ASSEMBLER__ + +void memzero(unsigned long src, unsigned long n); + +#endif + +#endif /*_MM_H */ \ 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..7c2b1a472 --- /dev/null +++ b/Lab6/include/peripherals/base.h @@ -0,0 +1,10 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +// There is a VideoCore/ARM MMU translating physical addresses to bus addresses. +// The MMU maps physical address 0x3f000000 to bus address 0x7e000000. + +#define KVA 0xffff000000000000 +#define MMIO_BASE (KVA + 0x3F000000) + +#endif /*_P_BASE_H */ \ 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..eaf7c4955 --- /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 ((volatile unsigned int *)(MMIO_BASE + 0x00200004)) +#define GPSET0 ((volatile unsigned int *)(MMIO_BASE + 0x0020001C)) +#define GPCLR0 ((volatile unsigned int *)(MMIO_BASE + 0x00200028)) +#define GPPUD ((volatile unsigned int *)(MMIO_BASE + 0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int *)(MMIO_BASE + 0x00200098)) + +#endif /*_P_GPIO_H */ \ No newline at end of file diff --git a/Lab6/include/peripherals/mail_box.h b/Lab6/include/peripherals/mail_box.h new file mode 100644 index 000000000..49ce6a868 --- /dev/null +++ b/Lab6/include/peripherals/mail_box.h @@ -0,0 +1,25 @@ +#ifndef _P_MAIL_BOX_H +#define _P_MAIL_BOX_H + +#include "base.h" + +#define VIDEOCORE_MBOX (MMIO_BASE + 0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +// #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 + +#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..05b992d82 --- /dev/null +++ b/Lab6/include/peripherals/mini_uart.h @@ -0,0 +1,25 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_ENABLES ((volatile unsigned int *)(MMIO_BASE + 0x00215004)) +#define AUX_MU_IO_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215040)) +#define AUX_MU_IER_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215044)) +#define AUX_MU_IIR_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215048)) +#define AUX_MU_LCR_REG ((volatile unsigned int *)(MMIO_BASE + 0x0021504C)) +#define AUX_MU_MCR_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215050)) +#define AUX_MU_LSR_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215054)) +#define AUX_MU_MSR_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int *)(MMIO_BASE + 0x0021505C)) +#define AUX_MU_CNTL_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215060)) +#define AUX_MU_STAT_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215064)) +#define AUX_MU_BAUD_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215068)) + +#define ARM_IRQ_REG_BASE ((volatile unsigned int*)(MMIO_BASE + 0x0000b000)) +#define IRQ_PENDING_1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b204)) +#define ENB_IRQS1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b210)) +#define DISABLE_IRQS1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b21c)) +#define AUX_IRQ (1 << 29) + +#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..4286af5cf --- /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 __PRINT_H +#define __PRINT_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..8b0a5896d --- /dev/null +++ b/Lab6/include/reboot.h @@ -0,0 +1,8 @@ +#ifndef _REBOOT_H +#define _REBOOT_H + +void set(long addr, unsigned int value); +void reboot(int tick); +void cancel_reboot(); + +#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..a553069bf --- /dev/null +++ b/Lab6/include/shell.h @@ -0,0 +1,9 @@ +#ifndef _SHELL_H +#define _SHELL_H + +void shell(void); +unsigned int debug_printf(char* fmt,...); + +extern int debug_mode; + +#endif \ No newline at end of file diff --git a/Lab6/include/switch.h b/Lab6/include/switch.h new file mode 100644 index 000000000..c550e1bb6 --- /dev/null +++ b/Lab6/include/switch.h @@ -0,0 +1,8 @@ +#ifndef _SWITCH_H +#define _SWITCH_H + +#include "task.h" + +task_struct* get_current(); + +#endif diff --git a/Lab6/include/sysreg.h b/Lab6/include/sysreg.h new file mode 100644 index 000000000..7e605cf5f --- /dev/null +++ b/Lab6/include/sysreg.h @@ -0,0 +1,22 @@ +#ifndef __SYSREG_H_ +#define __SYSREG_H_ + +#define read_sysreg(r) ({ \ + unsigned long __val; \ + asm volatile("mrs %0, " #r : "=r" (__val)); \ + __val; \ +}) + +#define write_sysreg(r, __val) ({ \ + asm volatile("msr " #r ", %0" :: "r" (__val)); \ +}) + +#define ESR_ELx_EC(esr) ((esr & 0xFC000000) >> 26) +#define ESR_ELx_ISS(esr) (esr & 0x03FFFFFF) + +#define ESR_ELx_EC_SVC64 0b010101 +#define ESR_ELx_EC_DABT_LOW 0b100100 +#define ESR_ELx_EC_IABT_LOW 0b100000 +#define ESR_ELx_EC_BRK_LOW 0b110000 + +#endif \ No newline at end of file diff --git a/Lab6/include/system_call.h b/Lab6/include/system_call.h new file mode 100644 index 000000000..4e120b234 --- /dev/null +++ b/Lab6/include/system_call.h @@ -0,0 +1,16 @@ +#ifndef _SYSTEM_CALL_H +#define _SYSTEM_CALL_H + +#include + +/* helper functions for user programs, not the real system calls */ +int get_pid(); +size_t uart_read(char buf[], size_t size); +size_t uart_write(const char buf[], size_t size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(); +int mbox_call(unsigned char ch, unsigned int *mbox); +void kill(int pid); + +#endif \ No newline at end of file diff --git a/Lab6/include/task.h b/Lab6/include/task.h new file mode 100644 index 000000000..e92692954 --- /dev/null +++ b/Lab6/include/task.h @@ -0,0 +1,76 @@ +#ifndef _TASK_H +#define _TASK_H + +#include + +#define TERMINATED 0 +#define RUNNING 1 +#define WAITING 2 + + +typedef struct trap_frame { + unsigned long regs[32]; + unsigned long sp_el0; + unsigned long elr_el1; + unsigned long spsr_el1; +} trap_frame; + +typedef struct cpu_context { + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; //x29: kernel frame pointer + unsigned long lr; //x30: link register for function calls + unsigned long sp; // kernel stack pointer +} cpu_context; + +typedef struct task_struct { + cpu_context context; + int id; + int state; + unsigned long user_fp; + void (*handler)(); + void *page_table; + struct task_struct *prev; + struct task_struct *next; +} task_struct; + +typedef struct task_queue { + char name[10]; + task_struct *begin; + task_struct *end; +} task_queue; + +extern task_queue run_queue; +extern task_queue wait_queue; +extern task_queue terminated_queue; +extern int run_queue_sz; +extern char **_argv; + +extern unsigned long user_addr; +extern unsigned long user_sp; + +task_struct* thread_create(void* func); +void thread_schedule(); +void kill_zombies(); +void idle(); +void create_root_thread(); +void run_user_program(const char* name, char *const argv[]); +void switch_to_user_space(); + +void dump_queue(task_queue *queue); +void push_task_to_queue(task_queue *queue, task_struct *task); +void pop_task_from_queue(task_queue *queue, task_struct *task); + +/* Helper functions */ +void put_args(char *const argv[]); +task_struct *find_task_by_id(task_queue *queue, int pid); + +#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..ae55eba5b --- /dev/null +++ b/Lab6/include/timer.h @@ -0,0 +1,30 @@ +#ifndef __TIMER_H +#define __TIMER_H + +#include +#include "peripherals/base.h" + +#define CORE0_TIMER_IRQ_CTRL ((volatile unsigned int *)(KVA + 0x40000040)) +#define MAX_TIMER_QUEUE_SIZE 10 + +typedef void (*timer_call_back)(void *); +struct Timer { + struct Timer *next; + uint64_t expire_time; + timer_call_back call_back; + void *args; +}; + +void init_timer(); +void core_timer_enable(); +void core_timer_handler(); +void add_timer(unsigned int time, timer_call_back, void *); +void pop_timer(); +void test_timer(); + +/* callbacks */ +void show_time_elapsed(void *); +void print_timer(void *); +void normal_timer(); + +#endif diff --git a/Lab6/include/utils.h b/Lab6/include/utils.h new file mode 100644 index 000000000..613a92528 --- /dev/null +++ b/Lab6/include/utils.h @@ -0,0 +1,13 @@ +#ifndef _UtilS_H +#define _UtilS_H + +#define MAX_BUFFER_SIZE 256u + +int compare_string(const char *s1, const char *s2); +void uintoa(char *out, unsigned int i); +unsigned int getIntegerFromString(const char *str); +unsigned long getHexFromString(const char *str); +unsigned long hexToDec(char *s); +void align_4(void* size); + +#endif \ No newline at end of file diff --git a/Lab6/include/vm.h b/Lab6/include/vm.h new file mode 100644 index 000000000..f5fa4c23e --- /dev/null +++ b/Lab6/include/vm.h @@ -0,0 +1,36 @@ +#ifndef _VM_H +#define _VM_H + +#include + +//number of the most significant bits that must be either all 0s or all 1s +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +//smallest block of memory that can be independently mapped in the translation tables +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 //peripheral access +#define MAIR_NORMAL_NOCACHE 0b01000100 //normal RAM access +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 +#define MAIR_CONFIG_DEFAULT ((MAIR_DEVICE_nGnRnE<<(MAIR_IDX_DEVICE_nGnRnE*8))|(MAIR_NORMAL_NOCACHE<<(MAIR_IDX_NORMAL_NOCACHE*8))) + +#define PD_TABLE 0b11 +#define BOOT_PGD_ATTR PD_TABLE +#define PD_BLOCK 0b01 +#define PD_ACCESS (1 << 10) //access flag, a page fault is generated if not set +#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) //for L1 (ARM peripherals) +#define BOOT_L2D_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) //for L2 (peripherals) +#define BOOT_L2N_ATTR (PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_BLOCK) //for L2 (normal) + +#define VA2PA(x) ((unsigned long)(x) & 0xffffffffffff) +#define PA2VA(x) ((unsigned long)(x) | 0xffff000000000000) + +void mmu_init(); +void initPT(void** page_table); +void freePT(void** page_table); +void map_pages(void* page_table, uint64_t va, int page_num, uint64_t pa); +void dupPT(void* page_table_src, void* page_table_dst, int level); +void vc_identity_mapping(void* page_table_src); + +#endif \ No newline at end of file diff --git a/Lab6/kernel/boot.S b/Lab6/kernel/boot.S new file mode 100644 index 000000000..2d8c6a53f --- /dev/null +++ b/Lab6/kernel/boot.S @@ -0,0 +1,175 @@ +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 // Load value from a system register to one of the general purpose registers (x0–x30) + and x0, x0,#0xFF // Check processor id + cbz x0, master // Hang for all non-primary CPU + b proc_hang + +proc_hang: + b proc_hang + +master: + bl from_el2_to_el1 + ldr x0, =exception_table // setup interrupt vector base + msr vbar_el1, x0 + + bl mmu_init + + ldr x1, =__stk_start + mov sp, x1 + + ldr x1, =__bss_start + ldr w2, =__bss_size +memzero: + cbz w2, main + str xzr, [x1], #8 + sub w2, w2, #1 + b memzero + +main: + bl kernel_main // Perform an unconditional branch and store the return address in x30 + b proc_hang // Should never come here + +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 + + +// save registers to stack +.macro save_regs + sub sp, sp, 36 * 8 + stp x0, x1, [sp, 16 * 0] + stp x2, x3, [sp, 16 * 1] + stp x4, x5, [sp, 16 * 2] + stp x6, x7, [sp, 16 * 3] + stp x8, x9, [sp, 16 * 4] + stp x10, x11, [sp, 16 * 5] + stp x12, x13, [sp, 16 * 6] + stp x14, x15, [sp, 16 * 7] + stp x16, x17, [sp, 16 * 8] + stp x18, x19, [sp, 16 * 9] + stp x20, x21, [sp, 16 * 10] + stp x22, x23, [sp, 16 * 11] + stp x24, x25, [sp, 16 * 12] + stp x26, x27, [sp, 16 * 13] + stp x28, x29, [sp, 16 * 14] + str x30, [sp, 16 * 15] + + mrs x19, sp_el0 + mrs x20, elr_el1 + mrs x21, spsr_el1 + stp x19,x20, [sp, 16 * 16] + str x21, [sp, 16 * 17] +.endm + +// load registers from stack +.macro load_regs + ldp x21, x20, [sp, 16 * 17] + ldp x19, x20, [sp, 16 * 16] + msr spsr_el1, x21 + msr elr_el1, x20 + msr sp_el0, x19 + + ldp x0, x1, [sp, 16 * 0] + ldp x2, x3, [sp, 16 * 1] + ldp x4, x5, [sp, 16 * 2] + ldp x6, x7, [sp, 16 * 3] + ldp x8, x9, [sp, 16 * 4] + ldp x10, x11, [sp, 16 * 5] + ldp x12, x13, [sp, 16 * 6] + ldp x14, x15, [sp, 16 * 7] + ldp x16, x17, [sp, 16 * 8] + ldp x18, x19, [sp, 16 * 9] + ldp x20, x21, [sp, 16 * 10] + ldp x22, x23, [sp, 16 * 11] + ldp x24, x25, [sp, 16 * 12] + ldp x26, x27, [sp, 16 * 13] + ldp x28, x29, [sp, 16 * 14] + ldr x30, [sp, 16 * 15] + add sp, sp, 36 * 8 +.endm + + +//exception table +.align 11 +exception_table: + b TODO + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + + .align 7 + b curr_sync + .align 7 + b curr_iqr + .align 7 + b TODO + .align 7 + b TODO + + .align 7 + b lower_sync + .align 7 + b lower_iqr + .align 7 + b TODO + .align 7 + b TODO + + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + +//Synchronous from lower level +lower_sync: + save_regs + mov x0, sp // points to the kernel stack of the running user thread + bl lower_sync_handler + load_regs + eret + +//IRQ from lower level (sp points to the kernel stack of the running user thread) +lower_iqr: + save_regs + bl lower_iqr_handler + load_regs + eret + +//Synchronous from current level +curr_sync: + save_regs + bl curr_sync_handler + load_regs + eret + +//IRQ from current level +curr_iqr: + save_regs + bl curr_iqr_handler + load_regs + eret + +.globl child_return_from_fork +child_return_from_fork: + load_regs + eret + +TODO: + save_regs + bl error_handler + load_regs + eret \ No newline at end of file diff --git a/Lab6/kernel/exception.c b/Lab6/kernel/exception.c new file mode 100644 index 000000000..e4bf7bfcf --- /dev/null +++ b/Lab6/kernel/exception.c @@ -0,0 +1,283 @@ +#include "utils.h" +#include "mini_uart.h" +#include "peripherals/mini_uart.h" +#include "exception.h" +#include "sysreg.h" +#include "timer.h" +#include "system_call.h" +#include "switch.h" +#include "memory.h" +#include "cpio.h" +#include "shell.h" +#include "mail_box.h" +#include "vm.h" + + +void enable_interrupt() { asm volatile("msr DAIFClr, 0xf"); } +void disable_interrupt() { asm volatile("msr DAIFSet, 0xf"); } + +/* system call */ +void lower_sync_handler(trap_frame *tf) { + unsigned long esr, svc; + asm volatile("mrs %0, esr_el1 \n":"=r"(esr):); + unsigned long *regs = tf->regs; + if (((esr >> 26) & 0x3f) == 0x15) { + svc = esr & 0x1ffffff; + if (svc == 0) { + switch(regs[8]) { + case 0: + regs[0] = sys_getpid(); + thread_schedule(); + break; + case 1: + enable_interrupt(); + regs[0] = sys_uartread((char*)regs[0], (size_t)regs[1]); + disable_interrupt(); + break; + case 2: + enable_interrupt(); + regs[0] = sys_uartwrite((const char*)regs[0], (size_t)regs[1]); + disable_interrupt(); + break; + case 3: + sys_exec(tf, (const char*)regs[0], (char * const*)regs[1]); + thread_schedule(); + break; + case 4: + sys_fork(tf); + thread_schedule(); + break; + case 5: + sys_exit(regs[0]); + thread_schedule(); + break; + case 6: + regs[0] = sys_mbox_call((unsigned char)regs[0], (volatile unsigned int*)regs[1]); + thread_schedule(); + break; + case 7: + sys_kill(regs[0]); + thread_schedule(); + break; + case 8: + sys_signal((int)regs[0], (void (*)())regs[1]); + thread_schedule(); + break; + case 9: + sys_signal_kill((int)regs[0], (int)regs[1]); + thread_schedule(); + break; + default: + uart_printf("[ERROR][lower_sync_handler] unknown svc!\n"); + } + } + else { + uart_printf("[ERROR][lower_sync_handler] unknown exception!\n"); + while(1) {} + } + } + else { + unsigned ec = (esr & 0xFC000000) >> 26; + switch(ec) { + case ESR_ELx_EC_DABT_LOW: + uart_printf("[Segfault] Userland data abort exception! pc: %x\n", read_sysreg(elr_el1)); + while(1) {} + case ESR_ELx_EC_IABT_LOW: + uart_printf("[Segfault] Userland instruction abort exception! pc: %x\n", read_sysreg(elr_el1)); + while(1) {} + default: + uart_printf("[ERROR][lower_sync_handler] unknown exception!\n"); + while(1) {} + } + } +} + +void lower_iqr_handler() { + pop_timer(); +} + +void curr_sync_handler() { + unsigned long elr = read_sysreg(elr_el1); + uart_printf("[ERROR][curr_sync_handler] PC: %x\n", elr); + error_handler(); +} + +void curr_iqr_handler() { + if (*IRQ_PENDING_1 & AUX_IRQ) + uart_handler(); + else + pop_timer(); +} + +void error_handler() { + uart_send_string("[ERROR] unknown exception...\n"); + while(1){} +} + +void dumpState() { + unsigned long esr = read_sysreg(esr_el1); + unsigned long elr = read_sysreg(elr_el1); + unsigned long spsr = read_sysreg(spsr_el1); + uart_printf("--------------------\n"); + uart_printf("SPSR: 0x%x\n", spsr); + uart_printf("ELR: 0x%x\n", elr); + uart_printf("ESR: 0x%x\n", esr); + uart_printf("--------------------\n"); +} + +/* Implement system calls */ +int sys_getpid() { + debug_printf("[DEBUG][sys_getpid] id: %d\n", get_current()->id); + return get_current()->id; +} + +size_t sys_uartread(char buf[], size_t size) { + char recv; + for (int i = 0; i < size; ++i) { + recv = uart_recv(); + buf[i] = recv; + } + debug_printf("[DEBUG][sys_uartread]\n"); + return size; +} + +size_t sys_uartwrite(const char buf[], size_t size) { + for (int i = 0; i < size; ++i) + uart_send((char)buf[i]); + debug_printf("[DEBUG][sys_uartwrite]\n"); + return size; +} + +int sys_exec(trap_frame *tf, const char *name, char *const argv[]) { + task_struct *cur_task = get_current(); + freePT(&(cur_task->page_table)); + initPT(&(cur_task->page_table)); + load_program((char*)name, cur_task->page_table); + for (int i = 0; i < 4; ++i) + map_pages(cur_task->page_table, 0xffffffffb000 + i * 0x1000, 1, VA2PA(page_malloc(0))); + _argv = (char**)argv; + tf->elr_el1 = (unsigned long)USER_PROGRAM_VA; + tf->sp_el0 = cur_task->user_fp; + return 0; +} + +void sys_fork(trap_frame *tf) { + task_struct *parent = get_current(); + task_struct *child = thread_create(NULL); + int child_id = child->id; + //unsigned long user_fp = child->user_fp; + task_struct *prev = child->prev; + task_struct *next = child->next; + + /* copy the task context & kernel stack (including trap frame) of parent to child */ + char* src = (char*)parent; + char* dst = (char*)child; + int size = PAGE_SIZE_4K; + while(size--) { + *dst = *src; + src++; + dst++; + } + + initPT(&(child->page_table)); + dupPT(parent->page_table, child->page_table, 0); + //vc_identity_mapping(new_task->page_table); //for video program + for (uint64_t va = 0x3c000000; va <= 0x3f000000; va += 4096) + map_pages(child->page_table, va, 1, va); + + /* set up the correct value for registers */ + parent->context.sp = (unsigned long)tf; + if ((unsigned long)child > (unsigned long)parent) + child->context.sp = parent->context.sp + ((unsigned long)child - (unsigned long)parent); + else + child->context.sp = parent->context.sp - ((unsigned long)parent - (unsigned long)child); + //int parent_ustack_size = (parent->user_fp) - (tf->sp_el0) + 1; + child->context.fp = (unsigned long)child + PAGE_SIZE_4K - 16; + child->context.lr = (unsigned long)child_return_from_fork; + child->id = child_id; + //child->user_fp = user_fp; + child->prev = prev; + child->next = next; + trap_frame *child_tf = (trap_frame*)(child->context.sp); + //child_tf->sp_el0 = (child->user_fp) - parent_ustack_size + 1; + child_tf->regs[0] = 0; + child_tf->regs[29] = child->context.fp; + tf->regs[0] = child->id; + child->handler = parent->handler; + + /* copy the user stack of parent to child */ + // char *src_stack = (char*)(tf->sp_el0); + // char *dst_stack = (char*)(child_tf->sp_el0); + + // while(parent_ustack_size--) { + // *dst_stack = *src_stack; + // src_stack++; + // dst_stack++; + // } + + debug_printf("[DEBUG][sys_fork] parent: %d, child: %d\n", parent->id, child->id); +} + +void sys_exit() { + task_struct *cur_task = get_current(); + cur_task->state = TERMINATED; + pop_task_from_queue(&run_queue, cur_task); + push_task_to_queue(&terminated_queue, cur_task); + debug_printf("[DEBUG][sys_exit] thread: %d\n", cur_task->id); +} + +int sys_mbox_call(unsigned char ch, volatile unsigned int *mbox) { + debug_printf("[DEBUG][sys_mbox_call]"); + if (((uint64_t)mbox & 0xFFFF000000000000) == 0) { //lower va + //uart_printf("va: %x\n", mbox); + asm volatile("mov x0, %0 \n"::"r"(mbox)); + asm volatile("at s1e0r, x0 \n"); + uint64_t frame_addr = (uint64_t)read_sysreg(par_el1) & (0xFFFFFFFFF << 12); + uint64_t pa = frame_addr | ((uint64_t)mbox & 0xFFF); + //uart_printf("frame_addr: %x, pa: %x\n", frame_addr, pa); + if ((read_sysreg(par_el1) & 0x1) == 1) + uart_printf("[ERROR][sys_mbox_call] va translation fail!\n"); + return mailbox_call(ch, (volatile unsigned int*)pa, mbox); + } + return mailbox_call(ch, (volatile unsigned int*)mbox, mbox); +} + +void sys_kill(int pid) { + task_struct *task = NULL; + if ((task = find_task_by_id(&run_queue, pid))) + pop_task_from_queue(&run_queue, task); + else if ((task = find_task_by_id(&wait_queue, pid))) + pop_task_from_queue(&wait_queue, task); + if (task) { + task->state = TERMINATED; + push_task_to_queue(&terminated_queue, task); + } + debug_printf("[DEBUG][sys_kill]"); +} + +void sys_signal(int SIGNAL, void (*handler)()) { + get_current()->handler = handler; +} + +void sys_signal_kill(int pid, int SIGNAL) { + task_struct *task = NULL; + if (!(task = find_task_by_id(&run_queue, pid))) + task = find_task_by_id(&wait_queue, pid); + if (!task) + return; + _handler = task->handler; + _pid = pid; + task_struct *handler_task = thread_create(switch_to_user_space); + user_addr = (unsigned long)signal_handler_wrapper; + user_sp = handler_task->user_fp; +} + +/* helper functions */ +void (*_handler)() = NULL; +int _pid = 0; +void signal_handler_wrapper() { + if (_handler) + _handler(); + kill(_pid); + exit(); +} \ No newline at end of file diff --git a/Lab6/kernel/kernel.c b/Lab6/kernel/kernel.c new file mode 100644 index 000000000..a767fd276 --- /dev/null +++ b/Lab6/kernel/kernel.c @@ -0,0 +1,18 @@ +#include "mini_uart.h" +#include "shell.h" +#include "exception.h" +#include "timer.h" +#include "memory.h" +#include "allocator.h" +#include "task.h" + + +void kernel_main(void) { + uart_init(); + memory_init(); + init_reserve(); + init_timer(); + enable_interrupt(); + create_root_thread(); + shell(); +} diff --git a/Lab6/kernel/linker.ld b/Lab6/kernel/linker.ld new file mode 100644 index 000000000..df30f2423 --- /dev/null +++ b/Lab6/kernel/linker.ld @@ -0,0 +1,16 @@ +SECTIONS +{ + . = 0xffff000000000000; + . += 0x80000; + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + . = ALIGN(0x8); + __bss_start = .; + .bss : { *(.bss*) } + __bss_end = .; + __stk_start = __bss_end + (1<<16); +} + +__bss_size = (__bss_end - __bss_start) >> 3; \ No newline at end of file diff --git a/Lab6/lib/allocator.c b/Lab6/lib/allocator.c new file mode 100644 index 000000000..3d2a02eb8 --- /dev/null +++ b/Lab6/lib/allocator.c @@ -0,0 +1,178 @@ +#include "allocator.h" +#include "utils.h" +#include "mini_uart.h" +#include "shell.h" +#include "cpio.h" + + +/* record the usage of each slot */ +const int slot_size = 4; +const int slot[] = {32, 64, 128, 256}; +const uint64_t slot_max[] = {UINT32_MAX, UINT16_MAX - 1, UINT8_MAX, 15}; +const int slot_record_bits[] = {32, 15, 8, 4}; +const uint64_t slot_masks[] = {UINT32_MAX, UINT16_MAX, UINT8_MAX, UINT8_MAX}; +const int slot_shift_amout[] = {32, 16, 8, 0}; +const int slot_offset[] = {64, 64 + 32 * 32, 64 + 32 * 32 + 64 * 15, 64 + 32 * 32 + 64 * 15 + 128 * 8}; + +/* mantain pages */ +frame_free_node *allocated_pages = NULL; + +void *kmalloc(size_t size) { + int sz = round_to_smallest(size); + frame_free_node * page = get_page_with_slot(sz); + return allocate_slot(page, sz); +} + +void kfree(void *addr) { + frame_free_node *page = find_page(addr); + uint64_t _addr = (uint64_t)addr - GET_PAGE_ADDR(page->index); + int size; + for (size = 3; size >= 0; --size) { + if (_addr >= slot_offset[size]) + break; + } + _addr -= slot_offset[size]; + int which_slot = _addr / slot[size]; + set_slot_record(page, size, which_slot, 0); + free_page_if_empty(page); +} + +/* get usage record of the slot size in the page */ +uint64_t get_slot_record(frame_free_node *page, int size) { + uint64_t page_addr = GET_PAGE_ADDR(page->index); + uint64_t record = *(uint64_t *)page_addr; + return (record & (slot_masks[size] << slot_shift_amout[size])) >> slot_shift_amout[size]; +} + +/* set/unset the bit in the record for a slot of a size of a page */ +void set_slot_record(frame_free_node *page, int size, int which_slot, int value) { + uint64_t record = get_slot_record(page, size); + uint64_t mask = (uint64_t)1 << which_slot; + if (value == 0) { + mask = ~mask; + record &= mask; + } + else + record |= mask; + uint64_t *full_record_ptr = (uint64_t *)GET_PAGE_ADDR(page->index); + mask = slot_masks[size] << slot_shift_amout[size]; + *full_record_ptr &= ~mask; + *full_record_ptr |= (record << slot_shift_amout[size]); + if (which_slot >= slot_record_bits[size]) + uart_printf("[ERROR] set_slot_record: invlaid slot index!\n"); + debug_printf("[DEBUG][set_slot_record] set %d'th of %d bytes slot to %d\n", which_slot, slot[size], value); +} + +/* check if there is any empty 2^size bytes slot is spedified page */ +int is_full(frame_free_node *page, int size) { + return get_slot_record(page, size) == slot_max[size]; +} + +int is_empty(frame_free_node *page, int size) { + return get_slot_record(page, size) == 0; +} + +int round_to_smallest(size_t size) { + if (size <= 0) + uart_printf("[ERROR] round_to_smallest: invalid size!\n"); + if (size > 256) + uart_printf("[ERROR] round_to_smallest: too large!\n"); + int i; + for (i = 0; i < 4; ++i) { + if (slot[i] >= size) + break; + } + if (i == 4) + uart_printf("[ERROR][round_to_smallest] should not reach here!\n"); + debug_printf("[DEBUG][round_to_smallest] round %d to %d bytes\n", size, slot[i]); + return i; +} + +frame_free_node *get_page_with_slot(int size) { + frame_free_node *page = allocated_pages; + while (page) { + if (!is_full(page, size)) + break; + page = page->next; + } + if (!page) { + uint64_t addr = page_malloc(0); + uint64_t index = GET_PAGE_INDEX(addr); + add_to_list(&allocated_pages, index); + page = allocated_pages; + clear_4K_page(page->index); + } + return page; +} + +void *allocate_slot(frame_free_node *page, int size) { + uint64_t record = get_slot_record(page, size); + uint64_t mask = 1; + int i; + for (i = 0; i < slot_record_bits[size]; ++i) { + if ((record & mask) == 0) + break; + mask <<= 1; + } + set_slot_record(page, size, i, 1); + if (i == slot_record_bits[size]) + uart_printf("[ERROR] allocate_slot: should not reach here!\n"); + uint64_t addr = GET_PAGE_ADDR(page->index) + slot_offset[size] + slot[size] * i; + return (void*)addr; +} + +frame_free_node *find_page(void *addr) { + uint64_t _addr = (uint64_t)addr; + uint64_t mask = (~(uint64_t)0) << 12; + _addr &= mask; + frame_free_node *iter = allocated_pages; + while (iter) { + if (GET_PAGE_ADDR(iter->index) == _addr) + break; + iter = iter->next; + } + return iter; +} + +void clear_page(frame_free_node *page) { + char *addr = (char*)GET_PAGE_ADDR(page->index); + int sz = 1 << 12; + for (int i = 0; i < sz; ++i) + addr[i] = 0; +} + +void print_slot_record(frame_free_node *page) { + if (page) { + uart_printf("[Slot record] (page index: %ld) ", page->index); + for (int i = 0; i < 4; ++i) { + uint64_t record = get_slot_record(page, i); + uart_printf("%x ", record); + } + uart_printf("\n"); + } + else + uart_printf("[Slot record] page already freed!\n"); +} + +void free_page_if_empty(frame_free_node *page) { + for (int i = 0; i < 4; ++i) { + if (!is_empty(page, i)) + return; + } + remove_from_list(&allocated_pages, page->index); + page_free(GET_PAGE_ADDR(page->index), 0); +} + + +void memory_reserve(uint64_t start, uint64_t end) { + for (uint64_t i = start; i < end + PAGE_SIZE_4K; i += PAGE_SIZE_4K) + reserve_page(0, i); +} + +void init_reserve() { + // memory_reserve(KVA + 0x0000, KVA + 0x1000); // spin tables for multicore boot + // reserve_page(0, KVA + 0x2000); // L2 page table for kernel + // reserve_page(0, KVA + 0x3000); // L2 page table for kernel + // memory_reserve(KVA + 0x80000, KVA + 0x800000); // kernel and heap/stack space + debug_printf("[DEBUG][init_reserve] reserves 0X%x 4K pages\n", get_allocated_num()); +} \ No newline at end of file diff --git a/Lab6/lib/cpio.c b/Lab6/lib/cpio.c new file mode 100644 index 000000000..e4fd3d64f --- /dev/null +++ b/Lab6/lib/cpio.c @@ -0,0 +1,107 @@ +#include "peripherals/gpio.h" +#include "mini_uart.h" +#include "utils.h" +#include "shell.h" +#include "cpio.h" +#include "timer.h" +#include "sysreg.h" +#include +#include "vm.h" +#include "memory.h" + + +void cpio_list() { + /* + cpio archive comprises a header record with basic numeric metadata followed by + the full pathname of the entry and the file data. + */ + char *addr = CPIO_ADDR; + + while (compare_string((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) { + cpio_header *header = (cpio_header*)addr; + + unsigned long pathname_size = hexToDec(header->namesize); + unsigned long file_size = hexToDec(header->filesize); + unsigned long headerPathname_size = sizeof(cpio_header) + pathname_size; + + align_4(&headerPathname_size); // The pathname is followed by NUL bytes so that the total size of the fixed header plus pathname is a multiple of four. + align_4(&file_size); // Likewise, the file data is padded to a multiple of four bytes. + uart_send_string(addr + sizeof(cpio_header)); // print the fine name + uart_printf(" %d\n", file_size); + addr += (headerPathname_size + file_size); + } +} + +char *findFile(char *name) { + char *addr = CPIO_ADDR; + while (compare_string((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) { + if ((compare_string((char *)(addr + sizeof(cpio_header)), name) == 0)) { + return addr; + } + cpio_header *header = (cpio_header *)addr; + unsigned long pathname_size = hexToDec(header->namesize); + unsigned long file_size = hexToDec(header->filesize); + unsigned long headerPathname_size = sizeof(cpio_header) + pathname_size; + + align_4(&headerPathname_size); + align_4(&file_size); + addr += (headerPathname_size + file_size); + } + return 0; +} + +void cpio_cat(char *filename) { + char *target = findFile(filename); + if (target) { + cpio_header *header = (cpio_header *)target; + unsigned long pathname_size = hexToDec(header->namesize); + unsigned long file_size = hexToDec(header->filesize); + unsigned long headerPathname_size = sizeof(cpio_header) + pathname_size; + + align_4(&headerPathname_size); + align_4(&file_size); + + char *file_content = target + headerPathname_size; + for (unsigned int i = 0; i < file_size; i++) { + uart_send(file_content[i]); // print the file content + } + uart_send_string("\r\n"); + } + else { + uart_send_string("File not found!\n"); + } +} + +void load_program(char *name, void *page_table) { + unsigned char *target = (unsigned char*)findFile(name); + if (target) { + cpio_header *header = (cpio_header *)target; + unsigned long pathname_size = hexToDec(header->namesize); + unsigned long file_size = hexToDec(header->filesize); + unsigned long headerPathname_size = sizeof(cpio_header) + pathname_size; + + align_4(&headerPathname_size); + align_4(&file_size); + + asm volatile("mov x0, %0 \n"::"r"(page_table)); + asm volatile("dsb ish \n"); //ensure write has completed + asm volatile("msr ttbr0_el1, x0 \n"); //switch translation based address. + asm volatile("tlbi vmalle1is \n"); //invalidates cached copies of translation table entries from L1 TLBs + asm volatile("dsb ish \n"); //ensure completion of TLB invalidatation + asm volatile("isb \n"); //clear pipeline + + unsigned char *file_content = target + headerPathname_size; + int sz = file_size / 4096 + (file_size % 4096 != 0); + for (int i = 0; i < sz; ++i) { + unsigned char *addr = (unsigned char*)page_malloc(0); + map_pages(page_table, USER_PROGRAM_VA + 4096 * i, 1, (uint64_t)VA2PA(addr)); + for (int j = 0; j < 4096; ++j) + *(addr + j) = file_content[i * 4096 + j]; + } + + debug_printf("[DEBUG][load_program] load program: %s\n", name); + } + else { + uart_send_string("File not found!\n"); + } +} \ No newline at end of file diff --git a/Lab6/lib/mail_box.c b/Lab6/lib/mail_box.c new file mode 100644 index 000000000..27e918ec0 --- /dev/null +++ b/Lab6/lib/mail_box.c @@ -0,0 +1,109 @@ +#include "peripherals/mail_box.h" +#include "mail_box.h" +#include "mini_uart.h" +#include "utils.h" + +/* mailbox message buffer */ +volatile unsigned int __attribute__((aligned(16))) mailbox[36]; + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mailbox_call(unsigned char ch, volatile unsigned int *mailbox, volatile unsigned int *mailbox_va) +{ + volatile unsigned int r = (((volatile unsigned int)((volatile unsigned long)mailbox)&~0xF) | (ch&0xF)); + /* wait until we can write to the mailbox */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); + /* write the address of our message to the mailbox with channel identifier */ + + *MBOX_WRITE = r; + + /* now wait for the response */ + while(1) { + /* is there a response? */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); + /* is it a response to our message? */ + if(r == *MBOX_READ) { + /* is it a valid successful response? */ + return mailbox_va[1]==MBOX_RESPONSE; + } + } + return 0; +} + +// volatile unsigned int __attribute__((aligned(16))) mailbox[8]; + +// int mailbox_call(unsigned char ch, volatile unsigned int *mbox) { +// uart_printf("==========\n"); +// for (int i = 0; i < 8; ++i) +// uart_printf("%x\n", mbox[i]); +// uart_printf("==========\n"); +// /* +// 1. Combine the message address (upper 28 bits) with channel number (lower 4 bits) +// 2. Check if Mailbox 0 status register’s full flag is set. +// 3. If not, then you can write to Mailbox 1 Read/Write register. +// 4. Check if Mailbox 0 status register’s empty flag is set. +// 5. If not, then you can read from Mailbox 0 Read/Write register. +// 6. Check if the value is the same as you wrote in step 1. +// */ +// unsigned int msg = (((unsigned int)((unsigned long)mailbox) & ~0xF) | (ch & 0xF)); +// while (*MAILBOX_STATUS & MAILBOX_FULL) {} +// *MAILBOX_WRITE = msg; +// while (1) { +// while (*MAILBOX_STATUS & MAILBOX_EMPTY) {} +// if(msg == *MAILBOX_READ){ +// return mbox[1] == REQUEST_SUCCEED; +// } +// } +// return 0; +// } + +void get_board_revision() { + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = MBOX_REQUEST; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = 8; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = MBOX_TAG_LAST; + if (mailbox_call(MBOX_CH_PROP, mailbox, mailbox)) + uart_printf("board revision number: 0x%x\n", mailbox[5]); + else + uart_printf("can not get board revision number!\n"); +} + +void get_arm_memory() { + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = MBOX_REQUEST; + // tags begin + mailbox[2] = GET_ARM_EMEORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = 8; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; // value buffer + // tags end + mailbox[7] = MBOX_TAG_LAST; + if (mailbox_call(MBOX_CH_PROP, mailbox, mailbox)) { + uart_printf("base address: %x\n", mailbox[5]); + uart_printf("memory size: %x\n", mailbox[6]); + } + else + uart_printf("can not get memory info!\n"); +} + +void get_serial_number() { + mailbox[0] = 8*4; // length of the message + mailbox[1] = MBOX_REQUEST; // this is a request message + mailbox[2] = MBOX_TAG_GETSERIAL; // get serial number command + mailbox[3] = 8; // buffer size + mailbox[4] = 8; + mailbox[5] = 0; // clear output buffer + mailbox[6] = 0; + mailbox[7] = MBOX_TAG_LAST; + if(mailbox_call(MBOX_CH_PROP, mailbox, mailbox)) + uart_printf("serial number is: %x%x\n", mailbox[5], mailbox[6]); + else + uart_printf("can not get serial number!\n"); +} \ No newline at end of file diff --git a/Lab6/lib/memory.c b/Lab6/lib/memory.c new file mode 100644 index 000000000..4d2dcf8d3 --- /dev/null +++ b/Lab6/lib/memory.c @@ -0,0 +1,271 @@ +#include "memory.h" +#include "mini_uart.h" +#include "shell.h" + + +frame_free_node *frame_free_lists[4]; // 4K, 8K, 16K, 32K +char frame_array[FRAME_ARRAY_SIZE]; // 0xBB: buddy, 0xAA: allocated +frame_free_node *node_pool_head; // only mantain the "next" pointer, should not use "prev" +frame_free_node node_pool[FRAME_ARRAY_SIZE]; +frame_free_node *free_node_table[FRAME_ARRAY_SIZE]; // map index to node to enable O(1) search and removal + + +void memory_init() { + for (int i = 0; i < FRAME_ARRAY_SIZE; ++i) { + frame_array[i] = 0xBB; + if (i % 8 == 0) + frame_array[i] = 3; + free_node_table[i] = NULL; + } + + for (int i = 0; i < MAX_32K_NUM - 1; ++i) { + node_pool[i].next = &node_pool[i + 1]; + node_pool[i + 1].prev = &node_pool[i]; + } + node_pool[MAX_32K_NUM - 1].next = NULL; + node_pool[0].prev = NULL; + for (int i = 0; i < MAX_32K_NUM; ++i) { + node_pool[i].index = i << 3; + node_pool[i].list_addr = &frame_free_lists[3]; + free_node_table[i << 3] = &node_pool[i]; + } + + for (int i = MAX_32K_NUM; i < FRAME_ARRAY_SIZE - 1; ++i) + node_pool[i].next = &node_pool[i + 1]; + node_pool[FRAME_ARRAY_SIZE - 1].next = NULL; + + frame_free_lists[0] = NULL; + frame_free_lists[1] = NULL; + frame_free_lists[2] = NULL; + frame_free_lists[3] = &node_pool[0]; + node_pool_head = &node_pool[MAX_32K_NUM]; +} + +uint64_t page_malloc(int sz) { + uint64_t index = request_page(sz); + return GET_PAGE_ADDR(index); +} + +/* currently support 4K page request only, the value of frame array may be wrong otherwise */ +uint64_t request_page(int size) { + // if (!get_free_num()) { + // uart_printf("[ERROR][request_page] run out of memory!\n"); + // while (1) {} + // } + + if (size < 0 || size > 3) { + uart_printf("[ERROR][request_page] request_page(%d): illegal argument!\n", size); + return 0; + } + + frame_free_node *free_node = frame_free_lists[size]; + uint64_t index; + if (free_node) { + index = free_node->index; + pop_front(&frame_free_lists[size]); + } + else { + index = request_page(size + 1); + int end = index + (2 << size) - 1; + int mid = (index + end) / 2; + for (int i = index + 1; i <= end; ++i) + frame_array[i] = 0xBB; + frame_array[mid + 1] = size; + add_to_list(&frame_free_lists[size], mid + 1); + debug_printf("[DEBUG][request_page] release redundant memory, index: %ld, size: %ldK\n", mid + 1, 4 * (1 << size)); + } + for (int i = 0; i < (1 << size); ++i) + frame_array[index + i] = 0xAA; + debug_printf("[DEBUG][request_page] allocate memory, index: %ld, size: %dK\n", index, 4 << size); + + return index; +} + +/* same as request_page but guarantees to cover specified address */ +uint64_t reserve_page(int size, uint64_t addr) { + if (size < 0 || size > 3) { + uart_printf("[ERROR][reserve_page] reserve_page(%d): illegal argument!\n", size); + return 0; + } + + uint64_t index = GET_PAGE_INDEX(addr); + uint64_t aligned_index = index & (~(uint64_t)0 << size); + frame_free_node *free_node = free_node_table[aligned_index]; + if (free_node && free_node->list_addr == &frame_free_lists[size]) { + remove_from_list(&frame_free_lists[size], aligned_index); + debug_printf("[DEBUG][reserve_page] allocate memory, index: %ld, size: %dK\n", aligned_index, 4 << size); + } + else { + aligned_index = reserve_page(size + 1, addr); + int end = aligned_index + (2 << size) - 1; + int mid = (aligned_index + end) / 2; + for (int i = aligned_index + 1; i <= end; ++i) + frame_array[i] = 0xBB; + if (index <= mid) { + frame_array[mid + 1] = size; + add_to_list(&frame_free_lists[size], mid + 1); + debug_printf("[DEBUG][reserve_page] release redundant memory, index: %ld, size: %ldK\n", mid + 1, 4 * (1 << size)); + } + else { + frame_array[aligned_index] = size; + add_to_list(&frame_free_lists[size], aligned_index); + debug_printf("[DEBUG][reserve_page] release redundant memory, index: %ld, size: %ldK\n", aligned_index, 4 * (1 << size)); + } + debug_printf("[DEBUG][reserve_page] allocate memory, index: %ld, size: %dK\n", index, 4 << size); + } + for (int i = 0; i < (1 << size); ++i) + frame_array[index + i] = 0xAA; + + return aligned_index; +} + +void page_free(uint64_t addr, int size) { + uint64_t index = getIndex(addr, size); + if (index >= FRAME_ARRAY_SIZE || frame_array[index] != 0xAA) + uart_printf("[ERROR][page_free] page_free: illegal index!\n"); + + debug_printf("[DEBUG][page_free] free %ldK page, index: %ld\n", 4 << size, index); + frame_array[index] = size; + for (int i = 1; i < (1 << size); ++i) + frame_array[index + i] = 0xBB; + add_to_list(&frame_free_lists[size], index); + merge_page(index, size + 1); +} + +void merge_page(uint64_t index, int size) { + if (size > 3) + return; + + uint64_t mask = (1 << size) - 1; + uint64_t start = index & ~mask; + uint64_t end = index | mask; + int mergable = 1; + for (uint64_t i = start; i <= end; ++i) { + if (frame_array[i] == 0xAA) { + mergable = 0; + break; + } + } + + if (!mergable) + return; + + debug_printf("[DEBUG][merge_page] merge into %ldK page\n", 4 << size); + for (uint64_t i = start + 1; i <= end; ++i) + frame_array[i] = 0xBB; + frame_array[start] = size; + for (uint64_t i = start; i <= end; ++i) { + if (free_node_table[i]) + remove_from_list(&frame_free_lists[size - 1], i); + } + add_to_list(&frame_free_lists[size], start); + + merge_page(index, size + 1); +} + +/* remove the first free node from a list */ +void pop_front(frame_free_node **list) { + frame_free_node *free_node = *list; + *list = (*list)->next; + if (*list) + (*list)->prev = NULL; + return_free_node(free_node); +} + +/* remove the free node holding specify index from a list, if exits */ +void remove_from_list(frame_free_node **list, uint64_t index) { + frame_free_node *target = free_node_table[index]; + if (!target) + uart_printf("[ERROR][remove_from_list] illegal index!\n"); + free_node_table[index] = NULL; + if (target->list_addr != list) + uart_printf("[ERROR][remove_from_list] list address not matched!\n"); + target->list_addr = NULL; + if (target == *list) { + *list = (*list)->next; + (*list)->prev = NULL; + } + else { + if (target->next) + target->next->prev = target->prev; + if (!target->prev) + uart_printf("[ERROR][remove_from_list] should not reach here!\n"); + target->prev->next = target->next; + } + return_free_node(target); +} + +/* add a free node holding specify index to a list */ +void add_to_list(frame_free_node **list, uint64_t index) { + frame_free_node *new_node = get_free_node(); + free_node_table[index] = new_node; + new_node->list_addr = list; + new_node->index = index; + new_node->prev = NULL; + new_node->next = *list; + if (*list) + (*list)->prev = new_node; + (*list) = new_node; +} + +uint64_t getIndex(uint64_t addr, int size) { + uint64_t _addr = addr - MEMORY_BASE_ADDR; + int page_size = (1 << size) << 12; + if (_addr % page_size != 0) + uart_printf("[ERROR][getIndex] getIndex: illegal address: %x\n", _addr); + return _addr / PAGE_SIZE_4K; +} + +frame_free_node *get_free_node() { + frame_free_node *node = node_pool_head; + if (!node) + uart_printf("[ERROR][get_free_node] get_free_node: no more nodes!\n"); + node_pool_head = node_pool_head->next; + return node; +} + +void return_free_node(frame_free_node *node) { + if (!node) + uart_printf("[ERROR][return_free_node] null node!\n"); + node->next = node_pool_head; + node_pool_head = node; +} + +uint64_t get_allocated_num() { + uint64_t cnt = 0; + for (uint64_t i = 0; i < FRAME_ARRAY_SIZE; ++i) { + if (frame_array[i] == 0xAA) + ++cnt; + } + return cnt; +} + +uint64_t get_free_num() { + return (MEMORY_END_ADDR - MEMORY_BASE_ADDR) / 4096 - get_allocated_num(); +} + +/* clear first 64 bytes */ +void clear_4K_page(uint64_t index) { + uint64_t *addr = (uint64_t*)GET_PAGE_ADDR(index); + addr[0] = 0; +} + + +void print_frame_array() { + uart_printf("frame_array: "); + for (uint64_t i = 0; i < 8; ++i) { + uart_printf("(%ld, %x) ", i, frame_array[i]); + } + uart_printf("\n"); +} + +void print_frame_free_lists() { + uart_printf("frame_free_lists: "); + for (int i = 0; i < 4; ++i) { + if (frame_free_lists[i]) + uart_printf("(%d, %ld) ", i, frame_free_lists[i]->index); + else + uart_printf("(%d, NULL) ", i); + } + uart_printf("\n"); +} \ 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..9f4503ef4 --- /dev/null +++ b/Lab6/lib/mini_uart.c @@ -0,0 +1,196 @@ +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" +#include "utils.h" +#include "mini_uart.h" +#include "printf.h" +#include + + +// The AUX_MU_LSR_REG register (8 bits) shows the data status. +// The AUX_MU_IO_REG register (8 bits) is primary used to write data to and read data from the UART FIFOs. +void uart_send ( char c ) { + if (c == '\n') + uart_send('\r'); + while(!(*AUX_MU_LSR_REG & 0x20)) {} // Bit 5, if set to 1, tells us that the transmitter is empty. + *AUX_MU_IO_REG = c; +} + +char uart_recv ( void ) { + while(!(*AUX_MU_LSR_REG & 0x01)) {} // Bit 0, if set to 1, indicates that the data is ready. + char recv = *AUX_MU_IO_REG & 0xFF; + return recv != '\r' ? recv : '\n'; +} + +void uart_recv_string(char *buffer) { + int size = 0; + while(size < MAX_BUFFER_SIZE){ + buffer[size] = uart_recv(); + uart_send(buffer[size]); + if(buffer[size++] == '\n'){ + break; + } + } + buffer[--size] = '\0'; +} + +void uart_send_string(char* str) { + for (int i = 0; str[i] != '\0'; i ++) { + uart_send((char)str[i]); + } +} + +unsigned int uart_printf(char* fmt,...) { + char dst[100]; + //__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); + unsigned int ret=vsprintf(dst,fmt,args); + uart_send_string(dst); + return ret; +} + +void uart_hex(unsigned int d) { + unsigned int n; + int c; + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_send(n); + } +} + +unsigned char uart_getb(){ //for data transfer + unsigned char r; + do{ asm volatile("nop"); } while (!(*AUX_MU_LSR_REG & 0x01)); + r = (unsigned char)(*AUX_MU_IO_REG); + return r; +} + +void delay(unsigned int clock) { + while (clock--) { + asm volatile("nop"); + } +} + +// An alternative function is a number from 0 to 5 that can be set for each pin and configures which device is connected to the pin. +// GPFSEL1 register is used to control alternative functions for pins 10-19. +// pin 14 -> TXD1: set bits 14-12 to 5 +// pin 15 -> RXD1: set bits 17-15 to 5 +void uart_init ( void ) { + // connect Mini UART to the GPIO pins + unsigned int selector; + selector = *GPFSEL1; + selector &= ~(7u << 12); // Clean gpio14 + selector |= 2u << 12; // Set alt5 for gpio14 + selector &= ~(7u << 15); // Clean gpio15 + selector |= 2u << 15; // Set alt5 for gpio15 + *GPFSEL1 = selector; + + // Remove both the pull-up and pull-down states from a pin + *GPPUD = 0; + delay(150u); + *GPPUDCLK0 = (1u << 14) | (1u << 15); + delay(150u); + *GPPUDCLK0 = 0; + + // Initializing the Mini UART + *AUX_ENABLES = 1u; // Enable mini uart (this also enables access to its registers) + *AUX_MU_CNTL_REG = 0u; // Disable auto flow control and disable receiver and transmitter (for now) + *AUX_MU_IER_REG = 1u; // Disable receive and transmit interrupts + *AUX_MU_LCR_REG = 3u; // Enable 8 bit mode + *AUX_MU_MCR_REG = 0u; // Set RTS line to be always high + *AUX_MU_BAUD_REG = 270u; // Set baud rate to 115200 + *AUX_MU_CNTL_REG = 3u; // Finally, enable transmitter and receiver + + *AUX_MU_IIR_REG = 6u; + + read_buf_start = read_buf_end = 0; + write_buf_start = write_buf_end = 0; +} + + + +/* async mini uart */ +char read_buf[MAX_BUFFER_SIZE]; +char write_buf[MAX_BUFFER_SIZE]; +int read_buf_start, read_buf_end; +int write_buf_start, write_buf_end; + +void enable_uart_interrupt() { *ENB_IRQS1 = AUX_IRQ; } +void disable_uart_interrupt() { *DISABLE_IRQS1 = AUX_IRQ; } +void set_transmit_interrupt() { *AUX_MU_IER_REG |= 0x2; } +void clear_transmit_interrupt() { *AUX_MU_IER_REG &= ~(0x2); } + +void uart_handler() { + disable_uart_interrupt(); + int RX = (*AUX_MU_IIR_REG & 0x4); + int TX = (*AUX_MU_IIR_REG & 0x2); + if (RX) { + char c = (char)(*AUX_MU_IO_REG); + read_buf[read_buf_end++] = c; + if (read_buf_end == MAX_BUFFER_SIZE) + read_buf_end = 0; + } + else if (TX) { + while (*AUX_MU_LSR_REG & 0x20) { + if (write_buf_start == write_buf_end) { + clear_transmit_interrupt(); + break; + } + char c = write_buf[write_buf_start++]; + *AUX_MU_IO_REG = c; + if (write_buf_start == MAX_BUFFER_SIZE) + write_buf_start = 0; + } + } + else { + uart_send_string("[Error] uart_handler: should not reach here!\n"); + while (1) { } + } + enable_uart_interrupt(); +} + +char uart_async_recv() { + // wait until there are new data + while (read_buf_start == read_buf_end) + asm volatile("nop"); + char c = read_buf[read_buf_start++]; + if (read_buf_start == MAX_BUFFER_SIZE) + read_buf_start = 0; + return c == '\r' ? '\n' : c; +} + +void uart_async_send_string(char *str) { + + for (int i = 0; str[i]; i++) { + if (str[i] == '\n') { + write_buf[write_buf_end++] = '\r'; + write_buf[write_buf_end++] = '\n'; + continue; + } + write_buf[write_buf_end++] = str[i]; + if (write_buf_end == MAX_BUFFER_SIZE) + write_buf_end = 0; + } + set_transmit_interrupt(); +} + +void test_uart_async() { + uart_send_string("[Please type something]\n"); + enable_uart_interrupt(); + delay(15000); + char buffer[MAX_BUFFER_SIZE]; + size_t index = 0; + while (1) { + buffer[index] = uart_async_recv(); + if (buffer[index] == '\n') + break; + index++; + } + buffer[index + 1] = '\0'; + uart_async_send_string(buffer); + disable_uart_interrupt(); +} diff --git a/Lab6/lib/mm.S b/Lab6/lib/mm.S new file mode 100644 index 000000000..2e2d88c28 --- /dev/null +++ b/Lab6/lib/mm.S @@ -0,0 +1,6 @@ +.globl memzero +memzero: + str xzr, [x0], #8 // Post-index: store 0 to the unmodified address in x0 first, then update x0 (to x0 + #8) + subs x1, x1, #8 + b.gt memzero + ret \ No newline at end of file diff --git a/Lab6/lib/printf.c b/Lab6/lib/printf.c new file mode 100644 index 000000000..f54f6736f --- /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 "../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..bceb3922f --- /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 reboot(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_reboot() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/Lab6/lib/shell.c b/Lab6/lib/shell.c new file mode 100644 index 000000000..91df99a73 --- /dev/null +++ b/Lab6/lib/shell.c @@ -0,0 +1,157 @@ +#include "mini_uart.h" +#include "shell.h" +#include "utils.h" +#include "reboot.h" +#include "peripherals/mail_box.h" +#include "mail_box.h" +#include "cpio.h" +#include "timer.h" +#include "memory.h" +#include "allocator.h" +#include "printf.h" +#include "task.h" +#include "exception.h" + + +int debug_mode = 0; +char buffer[MAX_BUFFER_SIZE]; + +void get_command(); +void parse_command(); + +void get_board_revision(); + +void shell(void) { + while (1) { + uart_send_string("> "); + get_command(); + parse_command(); + } +} + +void get_command() { + unsigned int index = 0; + char recv; + while (1) { + recv = uart_recv(); + if (recv == '\r') + continue; + uart_send(recv); + buffer[index++] = recv; + index = index < MAX_BUFFER_SIZE ? index : MAX_BUFFER_SIZE - 1; + if (recv == '\n') { + buffer[index - 1] = '\0'; + break; + } + } +} + +unsigned int debug_printf(char* fmt,...) { + if (debug_mode) { + char dst[100]; + __builtin_va_list args; + __builtin_va_start(args,fmt); + unsigned int ret=vsprintf(dst,fmt,args); + uart_send_string(dst); + return ret; + } + return 0; +} + +void parse_command() { + if (compare_string(buffer, "\0") == 0) {} + else if (compare_string(buffer, "hello") == 0) + uart_send_string("Hello World!\n"); + else if (compare_string(buffer, "reboot") == 0) { + uart_send_string("rebooting ...\n"); + reboot(100); + while (1) {} + } + else if (compare_string(buffer, "info") == 0) { + get_board_revision(); + get_arm_memory(); + get_serial_number(); + } + else if (compare_string(buffer, "ls") == 0) { + cpio_list(); + } + else if (compare_string(buffer, "cat") == 0) { + uart_send_string("Filename: \n"); + get_command(); + cpio_cat(buffer); + } + else if (compare_string(buffer, "async_uart") == 0) { + test_uart_async(); + } + else if (compare_string(buffer, "test_timer_lab3") == 0) { + test_timer(); + } + else if (compare_string(buffer, "test_page") == 0) { + debug_mode = 1; + const int test_size = 3; + const uint64_t test_address[] = {0x2001, 0x3010, 0x6100}; // covered index 2(4K), 3(4K), 6(8K) + const int page_size[] = {0, 0, 1}; + const uint64_t mask[] = {0xFFF, 0xFFF, 0x1FFF}; + for (int i = 0; i < test_size; ++i) { + reserve_page(page_size[i], test_address[i]); + print_frame_array(); + uart_printf("\n"); + } + for (int i = 0; i < test_size; ++i) { + page_free(test_address[i] & ~mask[i], page_size[i]); + print_frame_array(); + uart_printf("\n"); + } + debug_mode = 0; + } + else if (compare_string(buffer, "test_dyn") == 0) { + debug_mode = 1; + const int test_size = 10; + const int test_cases[] = {31, 2, 32, 63, 120, 256, 129, 155, 240, 250}; + void *addrs[test_size]; + for (int i = 0; i < test_size; ++i) { + addrs[i] = kmalloc(test_cases[i]); + print_slot_record(find_page(addrs[i])); + uart_printf("\n"); + } + for (int i = 0; i < test_size; ++i) { + kfree(addrs[i]); + print_slot_record(find_page(addrs[i])); + uart_printf("\n"); + } + debug_mode = 0; + } + else if (compare_string(buffer, "test_fork") == 0) { + run_user_program("fork_test.img", NULL); + } + else if (compare_string(buffer, "test_exec") == 0) { + run_user_program("exec_test.img", NULL); + } + else if (compare_string(buffer, "test_timer") == 0) { + run_user_program("timer_test.img", NULL); + } + else if (compare_string(buffer, "test_mbox") == 0) { + run_user_program("mbox_test.img", NULL); + } + else if (compare_string(buffer, "test_dummy") == 0) { + run_user_program("dummy_test.img", NULL); + } + else if (compare_string(buffer, "test_vm") == 0) { + run_user_program("vm.img", NULL); + } + else if (compare_string(buffer, "help") == 0) { + uart_send_string("help : print this help menu\n"); + uart_send_string("hello : print Hello World!\n"); + uart_send_string("reboot : reboot the device\n"); + uart_send_string("info : print device info\n"); + uart_send_string("ls : print files in rootfs\n"); + uart_send_string("cat : print file content\n"); + uart_send_string("async_uart : test async uart\n"); + uart_send_string("test_timer_lab3 : test timer multiplexing\n"); + uart_send_string("test_page : test buddy system\n"); + uart_send_string("test_dyn : test dynamic allocator\n"); + uart_send_string("test_fork : test user program\n"); + } + else + uart_send_string("\rcommand not found!\r\n"); +} diff --git a/Lab6/lib/switch.S b/Lab6/lib/switch.S new file mode 100644 index 000000000..6033b5501 --- /dev/null +++ b/Lab6/lib/switch.S @@ -0,0 +1,28 @@ +.section ".text" + +.global switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + msr tpidr_el1, x1 + ret + +.global get_current +get_current: + mrs x0, tpidr_el1 + ret \ No newline at end of file diff --git a/Lab6/lib/task.c b/Lab6/lib/task.c new file mode 100644 index 000000000..da8544d72 --- /dev/null +++ b/Lab6/lib/task.c @@ -0,0 +1,171 @@ +#include "task.h" +#include "allocator.h" +#include "switch.h" +#include "shell.h" +#include "utils.h" +#include "mini_uart.h" +#include "sysreg.h" +#include "cpio.h" +#include "timer.h" +#include "vm.h" + + +task_queue run_queue = {"run", NULL, NULL}; +task_queue wait_queue = {"wait", NULL, NULL}; +task_queue terminated_queue = {"terminated", NULL, NULL}; +int run_queue_sz = 0; +char **_argv = NULL; +static int task_cnt = 0; + +unsigned long user_addr; +unsigned long user_sp; +unsigned long user_page_table; + + +void run_user_program(const char* name, char *const argv[]) { + task_struct *task = thread_create(switch_to_user_space); + load_program((char*)name, task->page_table); + _argv = (char**)argv; + user_addr = USER_PROGRAM_VA; + for (int i = 0; i < 4; ++i) + map_pages(task->page_table, 0xffffffffb000 + i * 0x1000, 1, VA2PA(page_malloc(0))); + user_sp = task->user_fp; + user_page_table = (unsigned long)(task->page_table); + add_timer(read_sysreg(cntfrq_el0) >> 5, normal_timer, NULL); // < 0.1s + core_timer_enable(); + debug_mode = 0; + idle(); +} + +void switch_to_user_space() { + asm volatile("mov x0, 0x340 \n"::); + asm volatile("msr spsr_el1, x0 \n"::); + asm volatile("msr elr_el1, %0 \n"::"r"(user_addr)); + asm volatile("msr sp_el0, %0 \n"::"r"(user_sp)); + debug_printf("[DEBUG][switch_to_user_space]\n"); + asm volatile("eret \n"::); +} + +void create_root_thread() { + task_struct* root_task = thread_create(idle); + write_sysreg(tpidr_el1, root_task); +} + +task_struct* thread_create(void *func) { + task_struct* new_task = (task_struct*)page_malloc(0); + initPT(&(new_task->page_table)); + new_task->context.fp = (unsigned long)new_task + PAGE_SIZE_4K - 16; + new_task->context.lr = (unsigned long)func; + new_task->context.sp = (unsigned long)new_task + PAGE_SIZE_4K - 16; // kernel stack pointer for the thread + new_task->user_fp = 0xfffffffff000 - 16; + new_task->state = RUNNING; + new_task->id = task_cnt++; + new_task->handler = NULL; + + debug_printf("[DEBUG][thread_create] id: %d\n", new_task->id); + + push_task_to_queue(&run_queue, new_task); + return new_task; +} + +void thread_schedule() { + task_struct *next_task = run_queue.begin; + if (!next_task->id && !next_task->next) // escapes idle(), but the call stack will grow forever + shell(); + + pop_task_from_queue(&run_queue, next_task); + push_task_to_queue(&run_queue, next_task); + + asm volatile("mov x0, %0 \n"::"r"(next_task->page_table)); + asm volatile("dsb ish \n"); //ensure write has completed + asm volatile("msr ttbr0_el1, x0 \n"); //switch translation based address. + asm volatile("tlbi vmalle1is \n"); //invalidates cached copies of translation table entries from L1 TLBs + asm volatile("dsb ish \n"); //ensure completion of TLB invalidatation + asm volatile("isb \n"); //clear pipeline + + task_struct *cur = get_current(); + debug_printf("[DEBUG][thread_schedule] switch from thread %d to %d\n", cur->id, next_task->id); + + asm volatile("\ + mov x0, %0\n\ + mov x1, %1\n\ + bl switch_to\n\ + "::"r"(cur), "r"(next_task)); +} + +void idle() { + while(1) { + kill_zombies(); + thread_schedule(); + } +} + +void kill_zombies() { + +} + +void push_task_to_queue(task_queue *queue, task_struct *task) { + if (queue->begin) { + queue->end->next = task; + task->prev = queue->end; + task->next = NULL; + queue->end = task; + } + else { + queue->begin = queue->end = task; + task->prev = task->next = NULL; + } + run_queue_sz += 1; + debug_printf("[DEBUG][push_task_to_queue] push thread %d into %s queue\n", task->id, queue->name); +} + +void pop_task_from_queue(task_queue *queue, task_struct *task) { + task_struct *prev = task->prev; + task_struct *next = task->next; + if (prev && next) { + prev->next = next; + next->prev = prev; + } + else if (!prev && next) { + next->prev = NULL; + queue->begin = next; + } + else if (prev && !next) { + prev->next = NULL; + queue->end = prev; + } + else + queue->begin = queue->end = NULL; + run_queue_sz -= 1; + debug_printf("[DEBUG][pop_task_from_queue] pop thread %d from %s queue\n", task->id, queue->name); +} + +void dump_queue(task_queue *queue) { + task_struct *task = queue->begin; + uart_printf("%s queue: ", queue->name); + while (task) { + uart_printf("%d ", task->id, task); + task = task->next; + } + uart_printf("\n"); +} + +/* Helper functions */ +void put_args(char *const argv[]) { + if (!argv) + return; + + char **iter = (char**) argv; + for (int i = 0; iter[i]; ++i) + asm volatile("mov %0, %1 \n"::"r"(i), "r"(iter[i])); +} + +task_struct *find_task_by_id(task_queue *queue, int pid) { + task_struct *task = queue->begin; + while (task) { + if (task->id == pid) + break; + task = task->next; + } + return task; +} \ No newline at end of file diff --git a/Lab6/lib/timer.c b/Lab6/lib/timer.c new file mode 100644 index 000000000..119188355 --- /dev/null +++ b/Lab6/lib/timer.c @@ -0,0 +1,109 @@ +#include "timer.h" +#include "mini_uart.h" +#include "sysreg.h" +#include "allocator.h" +#include "exception.h" +#include "shell.h" + + +static struct Timer *timer_list = NULL; + + +void init_timer() { + uint64_t tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); +} + +void core_timer_enable() { + write_sysreg(cntp_ctl_el0, 1); // enable + *CORE0_TIMER_IRQ_CTRL = 2; // unmask timer interrupt +} + +void core_timer_disable() { + write_sysreg(cntp_ctl_el0, 0); // disable + *CORE0_TIMER_IRQ_CTRL = 0; // mask timer interrupt +} + +void add_timer(unsigned int time, timer_call_back call_back, void *args) { + struct Timer *timer = (struct Timer*)kmalloc(sizeof(struct Timer)); + timer->expire_time = read_sysreg(cntpct_el0) + time; + timer->call_back = call_back; + timer->args = args; + timer->next = NULL; + int need_update = 0; + //core_timer_disable(); + if (!timer_list) { + timer_list = timer; + need_update = 1; + } + else if (timer_list->expire_time > timer->expire_time) { + timer->next = timer_list; + timer_list = timer; + need_update = 1; + } + else { + struct Timer *pre = timer_list, *next = timer_list->next; + while (next && pre->expire_time < timer->expire_time) { + pre = next; + next = next->next; + } + pre->next = timer; + timer->next = next; + } + if (need_update) + write_sysreg(cntp_tval_el0, time); + //core_timer_enable(); +} + +void pop_timer() { + //core_timer_disable(); + struct Timer *timer = timer_list; + timer_list = timer_list->next; + //core_timer_enable(); + timer->call_back(timer->args); + kfree((void*)timer); + if (!timer_list) + core_timer_disable(); + else + write_sysreg(cntp_tval_el0, timer_list->expire_time - read_sysreg(cntpct_el0)); +} + +void test_timer() { + char* msg1 = (char *)kmalloc(20); + char* msg2 = (char *)kmalloc(20); + char* msg3 = (char *)kmalloc(20); + msg1 = "\nThis is timer 1!\n"; + msg2 = "This is timer 2!\n"; + msg3 = "This is timer 3!\n"; + add_timer(3 * read_sysreg(cntfrq_el0), print_timer, msg3); + add_timer(2 * read_sysreg(cntfrq_el0), print_timer, msg2); + add_timer(1 * read_sysreg(cntfrq_el0), print_timer, msg1); + core_timer_enable(); +} + +/* callbacks */ +void show_time_elapsed(void *args) { + unsigned long cntpct = read_sysreg(cntpct_el0); + unsigned long cntfrq = read_sysreg(cntfrq_el0); + unsigned long tmp = cntpct * 10 / cntfrq; + uart_printf("--------------------\n"); + uart_printf("Time Elapsed: %d.%ds\n", tmp/10, tmp%10); + uart_printf("--------------------\n"); + add_timer(cntfrq << 1, show_time_elapsed, NULL); +} + +void print_timer(void *args) { + char *msg = (char *)args; + uart_send_string(msg); +} + +void normal_timer() { + unsigned long cntpct = read_sysreg(cntpct_el0); + unsigned long cntfrq = read_sysreg(cntfrq_el0); + unsigned long tmp = cntpct * 10 / cntfrq; + debug_printf("[DEBUG][normal_timer] time elapsed: %d.%ds\n", tmp/10, tmp%10); + add_timer(cntfrq >> 5, normal_timer, NULL); + thread_schedule(); +} \ No newline at end of file diff --git a/Lab6/lib/utils.c b/Lab6/lib/utils.c new file mode 100644 index 000000000..99d883e68 --- /dev/null +++ b/Lab6/lib/utils.c @@ -0,0 +1,96 @@ +#include "utils.h" +#include "mini_uart.h" + +int compare_string(const char *s1, const char *s2) { + 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; +} + +void uintoa(char *out, unsigned int i) +{ + unsigned int index = 0; + char tmp[20]; + do { + unsigned char m = i % 16; + i >>= 4; + + char c = m + '0'; + if (m == 10) + c = 'A'; + else if (m == 11) + c = 'B'; + else if (m == 12) + c = 'C'; + else if (m == 13) + c = 'D'; + else if (m == 14) + c = 'E'; + else if (m == 15) + c = 'F'; + + tmp[index++] = c; + + } while (i); + + index--; + for (unsigned int i = 0; i <= index; ++i) + out[i] = tmp[index - i]; + out[index + 1] = '\0'; +} + +unsigned int getIntegerFromString(const char *str) { + unsigned int value = 0u; + + while (*str) { + if(*str >= '0' && *str<= '9'){ + value = value * 10u + (*str - '0'); + } + ++str; + } + return value; +} + +unsigned long getHexFromString(const char *str) { + unsigned long value = 0u; + + while (*str) { + if(*str >= '0' && *str <= '9'){ + value = value*16 + *str - '0'; + }else if(*str >= 'a' && *str <= 'z'){ + value = value*16 + *str - 'a' + 10u; + }else if(*str >= 'A' && *str <= 'Z'){ + value = value*16 + *str - 'A' + 10u; + } + ++str; + } + return value; +} + +// convert hexadecimal string into decimal +unsigned long hexToDec(char *s) { + unsigned long r = 0; + for(int i = 0; i < 8; ++i) { + if(s[i] >= '0' && s[i] <= '9') + r = r * 16 + s[i] -'0'; + else + r = r * 16 + s[i] - 'A' + 10; + } + return r; +} + +/* align to multiple of 4 */ +void align_4(void* size) { + unsigned long* x =(unsigned long*) size; + if((*x)&3){ + (*x) += 4-((*x)&3); + } +} \ No newline at end of file diff --git a/Lab6/lib/vm.c b/Lab6/lib/vm.c new file mode 100644 index 000000000..08a65b8fc --- /dev/null +++ b/Lab6/lib/vm.c @@ -0,0 +1,159 @@ +#include "vm.h" +#include "memory.h" +#include "mini_uart.h" + + +/* map va for pa */ +void map_pages(void* page_table, uint64_t va, int page_num, uint64_t pa) { + if (!page_table) + uart_printf("[ERROR][map_pages] null page table!\n"); + + for (int n = 0; n < page_num; ++n) { + unsigned long _va = (unsigned long)(va + n * 4096); + int index[4]; //index of each table + _va >>= 12; + index[3] = _va & 0x1ff; + _va >>= 9; + index[2] = _va & 0x1ff; + _va >>= 9; + index[1] = _va & 0x1ff; + _va >>= 9; + index[0] = _va & 0x1ff; + unsigned long* table = (unsigned long*)PA2VA(page_table); + for (int i = 0; i <= 2; ++i) { + if (!table[index[i]]) { + initPT((void**)&table[index[i]]); + table[index[i]] |= PD_TABLE; + } + unsigned long entry = table[index[i]]; + entry = entry - (entry & 0xfff); + table = (unsigned long*)PA2VA(entry); //address of the first entry of next level table + } + if (table[index[3]]) + uart_printf("[ERROR][map_pages] the VA: %x has already been mapped!\n", va); + //MAIR_IDX_NORMAL_NOCACHE << 2: index to MAIR (8 * 8bytes register) + table[index[3]] = (pa + n * 4096) | (1<<10) | (1<<6) | MAIR_IDX_NORMAL_NOCACHE << 2 | PD_TABLE; + } +} + +void dupPT(void* page_table_src, void* page_table_dst, int level) { + if (page_table_src == 0 || page_table_dst == 0) + uart_printf("[ERROR][dupPT] invalid table!"); + + //frame + if (level == 4) { + char* src = (char*)PA2VA(page_table_src); + char* dst = (char*)PA2VA(page_table_dst); + for (int i = 0; i < 4096; ++i) + dst[i] = src[i]; + return; + } + + //table + unsigned long* table_src = (unsigned long*)PA2VA(page_table_src); + unsigned long* table_dst = (unsigned long*)PA2VA(page_table_dst); + for (int i = 0; i < 512; ++i) { + if (table_src[i] != 0) { + // if () { + + // } + initPT((void**)&table_dst[i]); + dupPT((void*)(table_src[i] & 0xfffffffff000), (void*)(table_dst[i]), level + 1); + unsigned long tmp = table_src[i] & 0xfff; + table_dst[i] |= tmp; + } + } +} + +void initPT(void** page_table) { + char* table = (char*)page_malloc(0); + for (int i = 0; i < 4096; ++i) + table[i] = 0; + *page_table = (void*)VA2PA(table); +} + +void freePT(void** page_table) {} + +void mmu_init() { + //setup tcr & mair + asm volatile("msr tcr_el1, %0\n"::"r"(TCR_CONFIG_DEFAULT)); + /* + 1000 0000 0001 0000 0000 0000 0001 0000 + [5:0] the number of the most significant bits that must be all 0s + [21:16] the number of the most significant bits that must be all 1s + [15:14] granule size for user space (00=4KB, 01=16KB, 11=64KB) + [31:30] granule size for kernel space + */ + asm volatile("msr mair_el1, %0\n"::"r"(MAIR_CONFIG_DEFAULT)); + /* + 0100 0100 0000 0000 + [7:0] device memory nGnRnE + [15:8] normal memory without cache + */ + + //L1 table init + asm volatile("str %0, [%1]\n"::"r"(0x1000|BOOT_PGD_ATTR),"r"(0)); + //L2 table init + asm volatile("str %0, [%1]\n"::"r"(0x2000|BOOT_PGD_ATTR),"r"(0x1000)); //finer granularity for different memory type + asm volatile("str %0, [%1]\n"::"r"(0x40000000|BOOT_PUD_ATTR),"r"(0x1000+8)); // 1G block for ARM peripherals + //L3 table for 0~1G + asm volatile("\ + mov x10, %0\n\ + mov x11, %1\n\ + mov x0, #0x2000\n\ + mov x1, #512\n\ + mov x2, #0\n\ +beg1:\n\ + cbz x1, end1\n\ + ldr x3, =0x3F000000\n\ + cmp x2, x3\n\ + blt normalmem\n\ +peripheralsmem:\n\ + orr x3, x2, x10\n\ + b end2\n\ +normalmem:\n\ + orr x3, x2, x11\n\ + b end2\n\ +end2:\n\ + str x3, [x0]\n\ + add x0, x0, #8\n\ + sub x1, x1, #1\n\ + add x2, x2, #0x200000\n\ + b beg1\n\ +end1:\n\ + "::"r"(BOOT_L2D_ATTR),"r"(BOOT_L2N_ATTR)); + + //setting L1 table for lower VA region (0000) + asm volatile("msr ttbr0_el1, %0\n"::"r"(0)); //ensure to read correct inst when mmu opened + //setting L1 table for higher VA region (ffff) + asm volatile("msr ttbr1_el1, %0\n"::"r"(0)); + asm volatile("isb \n"); //forces the changes to be seen before the MMU is enabled + + asm volatile("mrs x0, sctlr_el1 \n"); + asm volatile("orr x0 , x0, 1 \n"); //enalble mmu for EL1&0 (bit 0 of sctlr_el1) + asm volatile("msr sctlr_el1, x0 \n"); + asm volatile("isb \n"); //forces the change to be seen by the next instruction + + //no longer running on 0x80000 + asm volatile("\ + ldr x0, =0xffff000000000000\n\ + add x30, x30, x0\n\ + "::); +} + +/* for video program */ +// void vc_identity_mapping(void* page_table) { +// if (!page_table) +// uart_printf("[ERROR][vc_identity_mapping] null page table!\n"); + +// /* +// index for 0x3c000000 & 0x3f000000 (1G frame) +// 0011 1100 0000 0000 00 +// 0011 1111 0000 0000 00 +// */ +// for (uint64_t i = 0b001111000000000000; i < 0b001111110000000000; ++i) { +// uart_printf("%d\n", i); +// uint64_t* table = (uint64_t*)PA2VA(page_table); +// *(table + i * 8) = ((uint64_t)0x3c0000000000 + i * (uint64_t)0x40000000) | BOOT_PUD_ATTR; +// } +// } \ No newline at end of file diff --git a/Lab6/load_kernel.py b/Lab6/load_kernel.py new file mode 100755 index 000000000..13d229249 --- /dev/null +++ b/Lab6/load_kernel.py @@ -0,0 +1,45 @@ +#!/usr/bin/python3 +import os +import time +import serial#pyserial + +def waitFor(target,dev,display=True):#avoid loss data + msgs='' + while True: + cnt=dev.inWaiting() + if cnt>0: + msg=dev.read(cnt).decode() + msgs=msgs+msg + if display: + print(msg,end='') + if target == '.': + if msgs.find(target)!=-1: + return + else: + return + +def dumpImg(dev,k_addr='0x80000',kernel='kernel8.img'): + dev.write(str.encode("[Load Kernel]\n")) + + k_size=os.stat(kernel).st_size + + time.sleep(1) + waitFor('',dev) + dev.write(str.encode(k_addr + '\n')) + + time.sleep(1) + waitFor('',dev) + dev.write(str.encode(str(k_size) + '\n')) + + with open(kernel,"rb") as f: + time.sleep(1) + waitFor('',dev) + for i in range(k_size): + dev.write(f.read(1)) + waitFor('.',dev,False) + +if __name__=='__main__': + br=115200 + #dev=serial.Serial("/dev/ttyUSB0",br) + dev=serial.Serial("/dev/pts/2",br) + dumpImg(dev) diff --git a/Lab6/user/dummy_test.c b/Lab6/user/dummy_test.c new file mode 100644 index 000000000..a3bc71460 --- /dev/null +++ b/Lab6/user/dummy_test.c @@ -0,0 +1,6 @@ +#include "system_call.h" + +void dummy_test() { + printf("\nDummy test!\n"); + exit(); +} \ No newline at end of file diff --git a/Lab6/user/exec_test.c b/Lab6/user/exec_test.c new file mode 100644 index 000000000..72e407abc --- /dev/null +++ b/Lab6/user/exec_test.c @@ -0,0 +1,6 @@ +#include "system_call.h" + +void exec_test() { + printf("\nExec Test, pid %d\n", get_pid()); + exec("dummy_test.img", NULL); +} \ No newline at end of file diff --git a/Lab6/user/fork_test.c b/Lab6/user/fork_test.c new file mode 100644 index 000000000..c2cef3dfb --- /dev/null +++ b/Lab6/user/fork_test.c @@ -0,0 +1,31 @@ +#include "system_call.h" + +void fork_test(){ + printf("\nFork Test, pid %d\n", get_pid()); + int cnt = 1; + int ret = 0; + if ((ret = fork()) == 0) { // child + long long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + ++cnt; + + if ((ret = fork()) != 0){ + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + } + else{ + while (cnt < 5) { + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("second child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + delay(1000000); + ++cnt; + } + } + exit(); + } + else { + printf("parent here, pid %d, child %d\n", get_pid(), ret); + exit(); + } +} \ No newline at end of file diff --git a/Lab6/user/include/mail_box.h b/Lab6/user/include/mail_box.h new file mode 100644 index 000000000..6370ebb4f --- /dev/null +++ b/Lab6/user/include/mail_box.h @@ -0,0 +1,23 @@ +#ifndef _MAIL_BOX_H +#define _MAIL_BOX_H + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_GETSERIAL 0x10004 +#define MBOX_TAG_LAST 0 +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_EMEORY 0x00010005 + +#endif \ No newline at end of file diff --git a/Lab6/user/include/system_call.h b/Lab6/user/include/system_call.h new file mode 100644 index 000000000..1175e7e2e --- /dev/null +++ b/Lab6/user/include/system_call.h @@ -0,0 +1,21 @@ +#ifndef _SYSTEM_CALL_H +#define _SYSTEM_CALL_H + +#include + +/* helper functions for user programs, not the real system calls */ +int get_pid(); +size_t uart_read(char buf[], size_t size); +size_t uart_write(const char buf[], size_t size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(); +int mbox_call(unsigned char ch, unsigned int *mbox); +void kill(int pid); + +/* utility functions */ +unsigned int printf(char* fmt,...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); +void delay(unsigned int clock); + +#endif \ No newline at end of file diff --git a/Lab6/user/lib/system_call.c b/Lab6/user/lib/system_call.c new file mode 100644 index 000000000..8b72e99ff --- /dev/null +++ b/Lab6/user/lib/system_call.c @@ -0,0 +1,187 @@ +#include "system_call.h" + + +/* helper functions for user programs, not the real system calls */ +int get_pid() { + unsigned long ret; + asm volatile("mov x8, 0\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +size_t uart_read(char buf[], size_t size) { + unsigned long ret; + asm volatile("mov x8, 1\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +size_t uart_write(const char buf[], size_t size) { + unsigned long ret; + asm volatile("mov x8, 2\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +int exec(const char *name, char *const argv[]) { + unsigned long ret; + asm volatile("mov x8, 3\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +int fork() { + unsigned long ret; + asm volatile("mov x8, 4\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +void exit() { + asm volatile("mov x8, 5\n"); + asm volatile("svc 0\n"); +} + +int mbox_call(unsigned char ch, unsigned int *mbox) { + unsigned long ret; + asm volatile("mov x8, 6\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +void kill(int pid) { + asm volatile("mov x8, 7\n"); + asm volatile("svc 0\n"); +} + +/* utility functions */ +unsigned int printf(char* fmt,...) { + char dst[100]; + __builtin_va_list args; + __builtin_va_start(args,fmt); + unsigned int ret = vsprintf(dst,fmt,args); + uart_write(dst, 100); + return ret; +} + +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; +} + +void delay(unsigned int clock) { + while (clock--) { + asm volatile("nop"); + } +} \ No newline at end of file diff --git a/Lab6/user/linker.ld b/Lab6/user/linker.ld new file mode 100644 index 000000000..7bb1dde69 --- /dev/null +++ b/Lab6/user/linker.ld @@ -0,0 +1,12 @@ +SECTIONS +{ + . = 0x80000; + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + . = ALIGN(0x10); + bss_begin = .; + .bss : { *(.bss*) } + bss_end = .; +} \ No newline at end of file diff --git a/Lab6/user/mbox_test.c b/Lab6/user/mbox_test.c new file mode 100644 index 000000000..efc50acc1 --- /dev/null +++ b/Lab6/user/mbox_test.c @@ -0,0 +1,58 @@ +#include "system_call.h" +#include "mail_box.h" + + +void mbox_test() { + /* test mbox_call */ + printf("\nTest mbox\n"); + // my_mailbox[0] = 7 * 4; + // my_mailbox[1] = REQUEST_CODE; + // my_mailbox[2] = GET_BOARD_REVISION; + // my_mailbox[3] = 4; + // my_mailbox[4] = TAG_REQUEST_CODE; + // my_mailbox[5] = 0; + // my_mailbox[6] = END_TAG; + // int status = mbox_call(8, my_mailbox); + // printf("\rboard revision: 0x"); + // printf("%x\n", my_mailbox[5]); // it should be 0xa020d3 for rpi3 b+ + // if (status) + // printf("success\n"); + // else + // printf("fail\n"); + + volatile unsigned int __attribute__((aligned(16))) my_mailbox[36]; + my_mailbox[0] = 7 * 4; // buffer size in bytes + my_mailbox[1] = MBOX_REQUEST; + // tags begin + my_mailbox[2] = GET_BOARD_REVISION; // tag identifier + my_mailbox[3] = 4; // maximum of request and response value buffer's length. + my_mailbox[4] = 8; + my_mailbox[5] = 0; // value buffer + // tags end + my_mailbox[6] = MBOX_TAG_LAST; + if (mbox_call(MBOX_CH_PROP, (unsigned int*)my_mailbox)) + printf("board revision number: 0x%x\n", my_mailbox[5]); + else + printf("can not get board revision number!\n"); + + + /* test kill */ + // int child_id[3]; + // int parent_id = 0; + // for (int i = 0; i < 3; ++i) { + // int id = fork(); + // if (!id) // child + // break; + // child_id[i] = id; + // parent_id = get_pid(); + // } + // if (get_pid() == parent_id) { + // for (int i = 0; i < 1000000; ++i) {} + // } + // else { + // printf("Thread %d before kill\n", get_pid()); + // while (1) {} + // } + + exit(); +} diff --git a/Lab6/user/timer_test.c b/Lab6/user/timer_test.c new file mode 100644 index 000000000..f0ca93a5c --- /dev/null +++ b/Lab6/user/timer_test.c @@ -0,0 +1,12 @@ +#include "system_call.h" + +void timer_test() { + fork(); + + for (int i = 1; i <= 10000000; ++i) { + for (int j = 0; j < 1000000; ++j) {} + printf("Thread: %d, counts to %dM\n", get_pid(), i); + } + + exit(); +} \ No newline at end of file diff --git a/Lab7/.vscode/c_cpp_properties.json b/Lab7/.vscode/c_cpp_properties.json new file mode 100644 index 000000000..96a36df82 --- /dev/null +++ b/Lab7/.vscode/c_cpp_properties.json @@ -0,0 +1,17 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/include" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "cStandard": "c11", + "cppStandard": "c++14", + "intelliSenseMode": "linux-clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/Lab7/.vscode/configurationCache.log b/Lab7/.vscode/configurationCache.log new file mode 100644 index 000000000..981a9560f --- /dev/null +++ b/Lab7/.vscode/configurationCache.log @@ -0,0 +1 @@ +{"buildTargets":["all","archive/initramfs.cpio","clean","fs_test.img","kernel8.img","on-board","qemu-debug","qemu-kernel","rd.o"],"launchTargets":["/home/littlelagi/OSC2022/Lab7>fs_test.elf()","/home/littlelagi/OSC2022/Lab7>kernel8.elf()"],"customConfigurationProvider":{"workspaceBrowse":{"browsePath":["/home/littlelagi/OSC2022/Lab7/include","/home/littlelagi/OSC2022/Lab7/kernel","/home/littlelagi/OSC2022/Lab7/lib","/home/littlelagi/OSC2022/Lab7/user","/home/littlelagi/OSC2022/Lab7/user/include","/home/littlelagi/OSC2022/Lab7/user/lib"],"compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","standard":"c11","windowsSdkVersion":""},"fileIndex":[["/home/littlelagi/OSC2022/Lab7/user/fs_test.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/user/fs_test.c","path":"/home/littlelagi/OSC2022/Lab7/user/fs_test.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/user/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tuser/linker.ld","user/fs_test.c","user/lib/system_call.c","-o","fs_test.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tuser/linker.ld user/fs_test.c user/lib/system_call.c -o fs_test.elf -Iuser/include","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/user/fs_test.c"}}],["/home/littlelagi/OSC2022/Lab7/user/lib/system_call.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/user/lib/system_call.c","path":"/home/littlelagi/OSC2022/Lab7/user/lib/system_call.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/user/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tuser/linker.ld","user/fs_test.c","user/lib/system_call.c","-o","fs_test.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tuser/linker.ld user/fs_test.c user/lib/system_call.c -o fs_test.elf -Iuser/include","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/user/lib/system_call.c"}}],["/home/littlelagi/OSC2022/Lab7/kernel/exception.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/kernel/exception.c","path":"/home/littlelagi/OSC2022/Lab7/kernel/exception.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/kernel/exception.c"}}],["/home/littlelagi/OSC2022/Lab7/kernel/kernel.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/kernel/kernel.c","path":"/home/littlelagi/OSC2022/Lab7/kernel/kernel.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/kernel/kernel.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/printf.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/printf.c","path":"/home/littlelagi/OSC2022/Lab7/lib/printf.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/printf.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/tmpfs.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/tmpfs.c","path":"/home/littlelagi/OSC2022/Lab7/lib/tmpfs.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/tmpfs.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/allocator.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/allocator.c","path":"/home/littlelagi/OSC2022/Lab7/lib/allocator.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/allocator.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/shell.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/shell.c","path":"/home/littlelagi/OSC2022/Lab7/lib/shell.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/shell.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/vfs.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/vfs.c","path":"/home/littlelagi/OSC2022/Lab7/lib/vfs.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/vfs.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/task.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/task.c","path":"/home/littlelagi/OSC2022/Lab7/lib/task.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/task.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/mini_uart.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/mini_uart.c","path":"/home/littlelagi/OSC2022/Lab7/lib/mini_uart.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/mini_uart.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/cpio.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/cpio.c","path":"/home/littlelagi/OSC2022/Lab7/lib/cpio.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/cpio.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/memory.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/memory.c","path":"/home/littlelagi/OSC2022/Lab7/lib/memory.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/memory.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/mail_box.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/mail_box.c","path":"/home/littlelagi/OSC2022/Lab7/lib/mail_box.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/mail_box.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/vm.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/vm.c","path":"/home/littlelagi/OSC2022/Lab7/lib/vm.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/vm.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/reboot.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/reboot.c","path":"/home/littlelagi/OSC2022/Lab7/lib/reboot.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/reboot.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/timer.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/timer.c","path":"/home/littlelagi/OSC2022/Lab7/lib/timer.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/timer.c"}}],["/home/littlelagi/OSC2022/Lab7/lib/utils.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/Lab7/lib/utils.c","path":"/home/littlelagi/OSC2022/Lab7/lib/utils.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":["/home/littlelagi/OSC2022/Lab7/include"],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/aarch64-linux-gnu-gcc","compilerArgs":["-O0","-Wall","-nostartfiles","-ffreestanding","-mgeneral-regs-only","-g","-fPIC","-Tkernel/linker.ld","kernel/boot.S","kernel/exception.c","kernel/kernel.c","lib/mm.S","lib/switch.S","lib/printf.c","lib/tmpfs.c","lib/allocator.c","lib/shell.c","lib/vfs.c","lib/task.c","lib/mini_uart.c","lib/cpio.c","lib/memory.c","lib/mail_box.c","lib/vm.c","lib/reboot.c","lib/timer.c","lib/utils.c","rd.o","-o","kernel8.elf"],"windowsSdkVersion":""},"compileCommand":{"command":"aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude","directory":"/home/littlelagi/OSC2022/Lab7","file":"/home/littlelagi/OSC2022/Lab7/lib/utils.c"}}]]}} \ No newline at end of file diff --git a/Lab7/.vscode/dryrun.log b/Lab7/.vscode/dryrun.log new file mode 100644 index 000000000..aa57c6a4d --- /dev/null +++ b/Lab7/.vscode/dryrun.log @@ -0,0 +1,11 @@ +make --dry-run --always-make --keep-going --print-directory +make: Entering directory '/home/littlelagi/OSC2022/Lab7' +aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tuser/linker.ld user/fs_test.c user/lib/system_call.c -o fs_test.elf -Iuser/include +aarch64-linux-gnu-objcopy -O binary fs_test.elf fs_test.img + +cd archive/rootfs && find . | cpio -o -H newc > ../initramfs.cpio +aarch64-linux-gnu-ld -r -b binary -o rd.o archive/initramfs.cpio +aarch64-linux-gnu-gcc -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC -Tkernel/linker.ld kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o -o kernel8.elf -Iinclude +aarch64-linux-gnu-objcopy -O binary kernel8.elf kernel8.img +make: Leaving directory '/home/littlelagi/OSC2022/Lab7' + diff --git a/Lab7/.vscode/settings.json b/Lab7/.vscode/settings.json new file mode 100644 index 000000000..73281d200 --- /dev/null +++ b/Lab7/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "files.associations": { + "stdint.h": "c", + "memory.h": "c", + "array": "c", + "hash_map": "c", + "string_view": "c", + "initializer_list": "c", + "utility": "c", + "task.h": "c", + "allocator.h": "c", + "mini_uart.h": "c", + "exception.h": "c", + "mail_box.h": "c" + } +} \ No newline at end of file diff --git a/Lab7/.vscode/targets.log b/Lab7/.vscode/targets.log new file mode 100644 index 000000000..54963baee --- /dev/null +++ b/Lab7/.vscode/targets.log @@ -0,0 +1,463 @@ +make all --print-data-base --no-builtin-variables --no-builtin-rules --question +# GNU Make 4.2.1 +# Built for x86_64-pc-linux-gnu +# Copyright (C) 1988-2016 Free Software Foundation, Inc. +# License GPLv3+: GNU GPL version 3 or later +# This is free software: you are free to change and redistribute it. +# There is NO WARRANTY, to the extent permitted by law. + + +# Make data base, printed on Mon Jun 6 11:09:57 2022 + +# Variables + +# automatic + ../initramfs.cpio + +# Not a target: + +Makefile: +# Implicit rule search has been done. +# Last modified 2022-05-29 14:36:28.045748705 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/printf.c: +# Implicit rule search has been done. +# Last modified 2022-05-21 14:19:00.854065099 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/cpio.c: +# Implicit rule search has been done. +# Last modified 2022-06-05 18:43:05.87144869 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/switch.S: +# Implicit rule search has been done. +# Last modified 2022-05-21 14:19:00.854065099 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/timer.c: +# Implicit rule search has been done. +# Last modified 2022-05-21 14:19:00.854065099 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/tmpfs.c: +# Implicit rule search has been done. +# Last modified 2022-06-06 00:18:26.010891705 +# File has been updated. +# Successfully updated. + +# Not a target: +kernel/boot.S: +# Implicit rule search has been done. +# Last modified 2022-05-21 14:19:00.85006515 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/task.c: +# Implicit rule search has been done. +# Last modified 2022-06-05 21:40:54.298228048 +# File has been updated. +# Successfully updated. + +# Not a target: +.DEFAULT: +# Implicit rule search has not been done. +# Modification time never checked. +# File has not been updated. + +on-board: +# Phony target (prerequisite of .PHONY). +# Implicit rule search has not been done. +# File does not exist. +# File has not been updated. +# recipe to execute (from 'Makefile', line 42): + sudo screen /dev/ttyUSB0 115200 + +clean: +# Phony target (prerequisite of .PHONY). +# Implicit rule search has not been done. +# File does not exist. +# File has not been updated. +# recipe to execute (from 'Makefile', line 45): + rm -f *.elf *.img *.cpio *.o *.S *.s + +# Not a target: +lib/mail_box.c: +# Implicit rule search has been done. +# Last modified 2022-05-21 14:19:00.854065099 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/memory.c: +# Implicit rule search has been done. +# Last modified 2022-05-25 19:00:38.831637795 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/mini_uart.c: +# Implicit rule search has been done. +# Last modified 2022-05-21 14:19:00.854065099 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/reboot.c: +# Implicit rule search has been done. +# Last modified 2022-05-21 14:19:00.854065099 +# File has been updated. +# Successfully updated. + +# Not a target: +user/fs_test.c: +# Implicit rule search has been done. +# Last modified 2022-05-30 13:04:12.076517392 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/vm.c: +# Implicit rule search has been done. +# Last modified 2022-05-23 12:07:37.714952466 +# File has been updated. +# Successfully updated. + +# Not a target: +kernel/kernel.c: +# Implicit rule search has been done. +# Last modified 2022-06-06 00:34:58.948598455 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/mm.S: +# Implicit rule search has been done. +# Last modified 2022-05-21 14:19:00.854065099 +# File has been updated. +# Successfully updated. + +rd.o: archive/initramfs.cpio +# Implicit rule search has not been done. +# Last modified 2022-06-06 00:37:21.797042824 +# File has been updated. +# Successfully updated. +# recipe to execute (from 'Makefile', line 25): + aarch64-linux-gnu-ld -r -b binary -o rd.o $(CPIO) + +kernel8.img: kernel/boot.S kernel/exception.c kernel/kernel.c lib/mm.S lib/switch.S lib/printf.c lib/tmpfs.c lib/allocator.c lib/shell.c lib/vfs.c lib/task.c lib/mini_uart.c lib/cpio.c lib/memory.c lib/mail_box.c lib/vm.c lib/reboot.c lib/timer.c lib/utils.c rd.o +# Implicit rule search has not been done. +# Last modified 2022-06-06 00:37:22.089036043 +# File has been updated. +# Successfully updated. +# recipe to execute (from 'Makefile', line 14): + $(ARMGNU)-gcc $(FLAGS) -Tkernel/linker.ld $^ -o kernel8.elf -I$(INC) + $(ARMGNU)-objcopy -O binary kernel8.elf kernel8.img + +# Not a target: +user/lib/system_call.c: +# Implicit rule search has been done. + +# Last modified 2022-05-29 14:17:18.893532177 +# File has been updated. +# Successfully updated. + +qemu-debug: +# Implicit rule search has not been done. +# Modification time never checked. +# File has not been updated. +# recipe to execute (from 'Makefile', line 31): + aarch64-linux-gnu-objdump -d kernel8.elf > kernel8.S + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd archive/initramfs.cpio -d in_asm + +# Not a target: +lib/allocator.c: +# Implicit rule search has been done. +# Last modified 2022-05-29 22:39:37.108472581 +# File has been updated. +# Successfully updated. + +# Not a target: +lib/vfs.c: +# Implicit rule search has been done. +# Last modified 2022-06-06 00:34:52.04478362 +# File has been updated. +# Successfully updated. + +# files hash-table stats: +# Load=34/1024=3%, Rehash=0, Collisions=0/83=0% +# VPATH Search Paths + +# No 'vpath' search paths. + +# No general ('VPATH' variable) search path. + +# strcache buffers: 1 (0) / strings = 70 / storage = 734 B / avg = 10 B +# current buf: size = 8162 B / used = 734 B / count = 70 / avg = 10 B + +# strcache performance: lookups = 106 / hit rate = 33% +# hash-table stats: +# Load=70/8192=1%, Rehash=0, Collisions=4/106=4% +# Finished Make data base on Mon Jun 6 11:09:57 2022 + + diff --git a/Lab7/Makefile b/Lab7/Makefile new file mode 100644 index 000000000..535cec8ef --- /dev/null +++ b/Lab7/Makefile @@ -0,0 +1,45 @@ +.PHONY: all clean qemu-kernel on-board + +ARMGNU ?= aarch64-linux-gnu + +FLAGS = -O0 -Wall -nostartfiles -ffreestanding -mgeneral-regs-only -g -fPIC +INC = include +LIB = lib +CPIO = archive/initramfs.cpio +USER_PROG = fs_test + +all: kernel8.img $(CPIO) $(USER_PROG).img + +kernel8.img: kernel/*.S kernel/*.c $(LIB)/*.S $(LIB)/*.c rd.o + $(ARMGNU)-gcc $(FLAGS) -Tkernel/linker.ld $^ -o kernel8.elf -I$(INC) + $(ARMGNU)-objcopy -O binary kernel8.elf kernel8.img + +$(USER_PROG).img: user/$(USER_PROG).c user/$(LIB)/*.c + $(ARMGNU)-gcc $(FLAGS) -Tuser/linker.ld $^ -o $(USER_PROG).elf -Iuser/$(INC) + $(ARMGNU)-objcopy -O binary $(USER_PROG).elf $(USER_PROG).img + +$(CPIO): $(USER_PROG).img + cd archive/rootfs && find . | cpio -o -H newc > ../initramfs.cpio + +rd.o:$(CPIO) + aarch64-linux-gnu-ld -r -b binary -o rd.o $(CPIO) + +qemu-kernel: + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd archive/initramfs.cpio + +qemu-debug: + aarch64-linux-gnu-objdump -d kernel8.elf > kernel8.S + qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd archive/initramfs.cpio -d in_asm + +# qemu-kernel: +# qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd $(CPIO) + +# qemu-debug: +# aarch64-linux-gnu-objdump -d kernel8.elf > kernel8.S +# qemu-system-aarch64 -M raspi3 -kernel kernel8.img -display none -serial null -serial stdio -initrd $(CPIO) -d in_asm + +on-board: + sudo screen /dev/ttyUSB0 115200 + +clean: + rm -f *.elf *.img *.cpio *.o *.S *.s \ No newline at end of file diff --git a/Lab7/archive/initramfs.cpio b/Lab7/archive/initramfs.cpio new file mode 100644 index 000000000..4059edf78 Binary files /dev/null and b/Lab7/archive/initramfs.cpio differ diff --git a/Lab7/archive/rootfs/initramfs/vfs1.img b/Lab7/archive/rootfs/initramfs/vfs1.img new file mode 100644 index 000000000..b021f07b8 Binary files /dev/null and b/Lab7/archive/rootfs/initramfs/vfs1.img differ diff --git a/Lab7/bootloader/boot.S b/Lab7/bootloader/boot.S new file mode 100644 index 000000000..e72c38675 --- /dev/null +++ b/Lab7/bootloader/boot.S @@ -0,0 +1,40 @@ +.section ".text.relo" +.globl _start +# need to relocate the bootloader from 0x80000 to 0x60000 +_start: + adr x10, . //x10=0x80000 + ldr x11, =_blsize + add x11, x11, x10 + ldr x12, =_stext // x12=0x60000 + +moving_relo: + cmp x10, x11 //without bootloader + b.eq end_relo + ldr x13, [x10] + str x13, [x12] //move 0x80000 data to 0x60000 + add x12, x12, #8 + add x10, x10, #8 + b moving_relo +end_relo: + ldr x14, =_bl_entry //jump to boot part + br x14 + + +.section ".text.boot" +.globl _start_bl + mrs x0, mpidr_el1 + and x0, x0,#0xFF // Check processor id + cbz x0, master // Hang for all non-primary CPU + +hang: + b hang + +master: + adr x0, _sbss + adr x1, _ebss + sub x1, x1, x0 + bl memzero + + mov sp, #0x400000 // 4MB + bl main + \ No newline at end of file diff --git a/Lab7/bootloader/linker.ld b/Lab7/bootloader/linker.ld new file mode 100644 index 000000000..60c1e4351 --- /dev/null +++ b/Lab7/bootloader/linker.ld @@ -0,0 +1,28 @@ +ENTRY(_start) +SECTIONS +{ + . = 0x60000; + _stext = .; + .text : { + *(.text.relo) + _bl_entry = .; + *(.text.boot) + *(.text) + *(.rodata) + } + . = ALIGN(0x1000); + _etext = .; + + _sdata = .; + .data : { *(.data) } + . = ALIGN(0x1000); + _edata = .; + + + _sbss = .; + .bss : { *(.bss*) } + . = ALIGN(0x1000); + _ebss = .; + + _blsize = _ebss - _stext; +} \ No newline at end of file diff --git a/Lab7/bootloader/main.c b/Lab7/bootloader/main.c new file mode 100644 index 000000000..86f193d73 --- /dev/null +++ b/Lab7/bootloader/main.c @@ -0,0 +1,36 @@ +#include "mini_uart.h" +#include "utils.h" + +void load_kernel() { + char buffer[MAX_BUFFER_SIZE]; + + while (compare_string(buffer, "[Load Kernel]") != 0) { + uart_recv_string(buffer); + } + + unsigned long k_addr=0,k_size=0; + uart_send_string("Please enter kernel load address (Hex): "); + + uart_recv_string(buffer); + k_addr = getHexFromString(buffer); + uart_send_string("Please enter kernel size (Dec): "); + uart_recv_string(buffer); + k_size = getIntegerFromString(buffer); + + uart_send_string("Please send kernel image now...\n"); + unsigned char* target=(unsigned char*)k_addr; + while(k_size--){ + *target=uart_getb(); + target++; + uart_send('.'); + } + + uart_send_string("loading...\n"); + asm volatile("br %0\n"::"r"(k_addr)); // GCC inline assembly +} + +int main() { + uart_init(); + load_kernel(); + return 0; // should not reach here +} \ No newline at end of file diff --git a/Lab7/include/allocator.h b/Lab7/include/allocator.h new file mode 100644 index 000000000..24a7ea44d --- /dev/null +++ b/Lab7/include/allocator.h @@ -0,0 +1,40 @@ +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H + +#include "memory.h" +#include + +/* + Partition of a 4K page: (size, amount) + (32, 32) (64, 15) (128, 8) (256, 4) + + First 64 byte is used to record usage of each slot, shown below: + uint32_t usage32; + uint16_t usage64; // upper 1 bit is not used + uint8_t usage128; + uint8_t usage258; // upper 4 bits reserve for future use + + [Future use] 4 bits of record of 256-bytes slot can be used to represent fused mode to get larger slot +*/ + +void *kmalloc(size_t size); +void kfree(void *addr); +uint64_t get_slot_record(frame_free_node *page, int size); +void set_slot_record(frame_free_node *page, int size, int which_slot, int value); +int is_full(frame_free_node *page, int size); +int is_empty(frame_free_node *page, int size); +int round_to_smallest(size_t size); +frame_free_node *get_page_with_slot(int size); +void *allocate_slot(frame_free_node *page, int size); +frame_free_node *find_page(void *addr); +void clear_page(frame_free_node *page); +void print_slot_record(frame_free_node *page); +void free_page_if_empty(frame_free_node *page); + +/* + memory reservation +*/ +void memory_reserve(uint64_t start, uint64_t end); +void init_reserve(); + +#endif \ No newline at end of file diff --git a/Lab7/include/cpio.h b/Lab7/include/cpio.h new file mode 100644 index 000000000..bb944d35a --- /dev/null +++ b/Lab7/include/cpio.h @@ -0,0 +1,51 @@ +#ifndef __CPIO__ +#define __CPIO__ + +#include "peripherals/base.h" + +#define __USE_QEMU__ + +#ifdef __USE_QEMU__ +#define CPIO_ADDR ((char *)(KVA + 0x8000000)) // qemu +#else +#define CPIO_ADDR ((char *)(KVA + 0x20000000)) // raspi3 +#endif +#define MAX_INITRAMFS_SIZE 0x100000 // 1M + +#define USER_PROGRAM_VA 0x0 +#define MAX_USER_PROGRAM_SIZE 0x100000 // 1M + + +typedef struct +{ + // uses 8-byte hexadecimal fields for all numbers + char magic[6]; //determine whether this archive is written with little-endian or big-endian integers. + char ino[8]; //determine when two entries refer to the same file. + char mode[8]; //specifies both the regular permissions and the file type. + char uid[8]; // numeric user id + char gid[8]; // numeric group id + char nlink[8]; // number of links to this file. + char mtime[8]; // Modification time of the file + char filesize[8]; // size of the file + char devmajor[8]; + char devminor[8]; + char rdevmajor[8]; + char rdevminor[8]; + char namesize[8]; // number of bytes in the pathname + char check[8]; // always set to zero by writers and ignored by readers. +} __attribute__((packed)) cpio_header; + +void cpio_list(); +void cpio_cat(char *filename); +char * findFile(char *name); +void load_program(char *name, void *page_table); + +/* VFS */ +void* fbase_get(); +int fmode_get(void* _addr); +char* fdata_get(void* _addr, unsigned long* size); +char* fname_get(void* _addr, unsigned long* size); +void* next_fget(void* _addr); +void fdump(); + +#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..6fd1e6244 --- /dev/null +++ b/Lab7/include/exception.h @@ -0,0 +1,44 @@ +#ifndef _EXCEPTION_H +#define _EXCEPTION_H + +#include "task.h" +#include "vfs.h" +#include + +void enable_interrupt(); +void disable_interrupt(); +void dumpState(); +void lower_sync_handler(); +void lower_iqr_handler(); +void curr_sync_handler(); +void curr_iqr_handler(); +void error_handler(); +void child_return_from_fork(); + +/* Implement system calls */ +int sys_getpid(); +size_t sys_uartread(char buf[], size_t size); +size_t sys_uartwrite(const char buf[], size_t size); +int sys_exec(trap_frame *tf, const char *name, char *const argv[]); +void sys_fork(trap_frame *tf); +void sys_exit(); +int sys_mbox_call(unsigned char ch, volatile unsigned int *mbox); +void sys_kill(int pid); +void sys_signal(int SIGNAL, void (*handler)()); +void sys_signal_kill(int pid, int SIGNAL); + +int sys_open(const char *pathname, int flags); +int sys_close(int fd); +int sys_write(int fd, const void *buf, int count); +int sys_read(int fd, void *buf, int count); +int sys_mkdir(const char *pathname); +// you can ignore arguments other than target and filesystem +int sys_mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data); +int sys_chdir(const char *path); + +/* helper functions */ +extern void (*_handler)(); +extern int _pid; +void signal_handler_wrapper(); + +#endif diff --git a/Lab7/include/mail_box.h b/Lab7/include/mail_box.h new file mode 100644 index 000000000..981fcd628 --- /dev/null +++ b/Lab7/include/mail_box.h @@ -0,0 +1,45 @@ +#ifndef _MAIL_BOX_H +#define _MAIL_BOX_H + +/* a properly aligned buffer */ +extern volatile unsigned int mailbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_GETSERIAL 0x10004 +#define MBOX_TAG_LAST 0 +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_EMEORY 0x00010005 + +int mailbox_call(unsigned char ch, volatile unsigned int *mailbox, volatile unsigned int *mailbox_va); + + +/* old macros from lab1 */ +// #define GET_BOARD_REVISION 0x00010002 +// #define GET_ARM_EMEORY 0x00010005 +// #define REQUEST_CODE 0x00000000 +// #define REQUEST_SUCCEED 0x80000000 +// #define REQUEST_FAILED 0x80000001 +// #define TAG_REQUEST_CODE 0x00000000 +// #define END_TAG 0x00000000 + +// extern volatile unsigned int mailbox[8]; + +// int mailbox_call(unsigned char ch, volatile unsigned int *mbox); +void get_board_revision(); +void get_arm_memory(); +void get_serial_number(); + +#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..3d3c34631 --- /dev/null +++ b/Lab7/include/memory.h @@ -0,0 +1,43 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#include +#include +#include "peripherals/base.h" + +#define MEMORY_BASE_ADDR (KVA + 0x10000000) +#define MEMORY_END_ADDR (KVA + 0x10000000 + 0x10000000) +#define PAGE_SIZE_4K ((uint64_t)1 << 12) +#define FRAME_ARRAY_SIZE ((MEMORY_END_ADDR - MEMORY_BASE_ADDR) / PAGE_SIZE_4K) +#define MAX_32K_NUM (FRAME_ARRAY_SIZE / 8) +#define GET_PAGE_ADDR(index) (MEMORY_BASE_ADDR + (index << 12)) +#define GET_PAGE_INDEX(addr) ((addr - MEMORY_BASE_ADDR) >> 12) + + +typedef struct frame_free_node { + uint64_t index; + struct frame_free_node *next; + struct frame_free_node *prev; // double linked list to enable O(1) removal + struct frame_free_node **list_addr; // find out which list it belongs to in Q(1) +} frame_free_node; + +void memory_init(); +uint64_t page_malloc(int sz); +uint64_t request_page(int size); +uint64_t reserve_page(int size, uint64_t addr); +void page_free(uint64_t addr, int size); +void merge_page(uint64_t index, int size); +void pop_front(frame_free_node **list); +void remove_from_list(frame_free_node **list, uint64_t index); +void add_to_list(frame_free_node **list, uint64_t index); +uint64_t getIndex(uint64_t addr, int size); +frame_free_node *get_free_node(); +void return_free_node(frame_free_node *node); +uint64_t get_allocated_num(); +uint64_t get_free_num(); +void clear_4K_page(uint64_t index); + +void print_frame_array(); +void print_frame_free_lists(); + +#endif diff --git a/Lab7/include/mini_uart.h b/Lab7/include/mini_uart.h new file mode 100644 index 000000000..319eb2dd6 --- /dev/null +++ b/Lab7/include/mini_uart.h @@ -0,0 +1,28 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void delay(unsigned int clock); +void uart_init( void ); +char uart_recv( void ); +void uart_send ( char c ); +void uart_send_string(char* str); +unsigned int uart_printf(char* fmt,...); +void uart_recv_string(char *buffer); +unsigned char uart_getb(); +void uart_hex(unsigned int d); + +extern char read_buf[]; +extern char write_buf[]; +extern int read_buf_start, read_buf_end; +extern int write_buf_start, write_buf_end; + +void enable_uart_interrupt(); +void disable_uart_interrupt(); +void set_transmit_interrupt(); +void clear_transmit_interrupt(); +void uart_handler(); +void test_uart_async(); +char uart_async_recv(); +void uart_async_send_string(char *str); + +#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..63d247edd --- /dev/null +++ b/Lab7/include/mm.h @@ -0,0 +1,19 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SHIFT 12 +#define TABLE_SHIFT 9 +#define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) + +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define SECTION_SIZE (1 << SECTION_SHIFT) + +#define LOW_MEMORY (2 * SECTION_SIZE) + +#ifndef __ASSEMBLER__ + +void memzero(unsigned long src, unsigned long n); + +#endif + +#endif /*_MM_H */ \ 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..7c2b1a472 --- /dev/null +++ b/Lab7/include/peripherals/base.h @@ -0,0 +1,10 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +// There is a VideoCore/ARM MMU translating physical addresses to bus addresses. +// The MMU maps physical address 0x3f000000 to bus address 0x7e000000. + +#define KVA 0xffff000000000000 +#define MMIO_BASE (KVA + 0x3F000000) + +#endif /*_P_BASE_H */ \ 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..eaf7c4955 --- /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 ((volatile unsigned int *)(MMIO_BASE + 0x00200004)) +#define GPSET0 ((volatile unsigned int *)(MMIO_BASE + 0x0020001C)) +#define GPCLR0 ((volatile unsigned int *)(MMIO_BASE + 0x00200028)) +#define GPPUD ((volatile unsigned int *)(MMIO_BASE + 0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int *)(MMIO_BASE + 0x00200098)) + +#endif /*_P_GPIO_H */ \ No newline at end of file diff --git a/Lab7/include/peripherals/mail_box.h b/Lab7/include/peripherals/mail_box.h new file mode 100644 index 000000000..49ce6a868 --- /dev/null +++ b/Lab7/include/peripherals/mail_box.h @@ -0,0 +1,25 @@ +#ifndef _P_MAIL_BOX_H +#define _P_MAIL_BOX_H + +#include "base.h" + +#define VIDEOCORE_MBOX (MMIO_BASE + 0x0000B880) +#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x0)) +#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x10)) +#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x14)) +#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x18)) +#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x1C)) +#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x20)) +#define MBOX_RESPONSE 0x80000000 +#define MBOX_FULL 0x80000000 +#define MBOX_EMPTY 0x40000000 + +// #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 + +#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..05b992d82 --- /dev/null +++ b/Lab7/include/peripherals/mini_uart.h @@ -0,0 +1,25 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_ENABLES ((volatile unsigned int *)(MMIO_BASE + 0x00215004)) +#define AUX_MU_IO_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215040)) +#define AUX_MU_IER_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215044)) +#define AUX_MU_IIR_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215048)) +#define AUX_MU_LCR_REG ((volatile unsigned int *)(MMIO_BASE + 0x0021504C)) +#define AUX_MU_MCR_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215050)) +#define AUX_MU_LSR_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215054)) +#define AUX_MU_MSR_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int *)(MMIO_BASE + 0x0021505C)) +#define AUX_MU_CNTL_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215060)) +#define AUX_MU_STAT_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215064)) +#define AUX_MU_BAUD_REG ((volatile unsigned int *)(MMIO_BASE + 0x00215068)) + +#define ARM_IRQ_REG_BASE ((volatile unsigned int*)(MMIO_BASE + 0x0000b000)) +#define IRQ_PENDING_1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b204)) +#define ENB_IRQS1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b210)) +#define DISABLE_IRQS1 ((volatile unsigned int*)(MMIO_BASE + 0x0000b21c)) +#define AUX_IRQ (1 << 29) + +#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..4286af5cf --- /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 __PRINT_H +#define __PRINT_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..8b0a5896d --- /dev/null +++ b/Lab7/include/reboot.h @@ -0,0 +1,8 @@ +#ifndef _REBOOT_H +#define _REBOOT_H + +void set(long addr, unsigned int value); +void reboot(int tick); +void cancel_reboot(); + +#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..a553069bf --- /dev/null +++ b/Lab7/include/shell.h @@ -0,0 +1,9 @@ +#ifndef _SHELL_H +#define _SHELL_H + +void shell(void); +unsigned int debug_printf(char* fmt,...); + +extern int debug_mode; + +#endif \ No newline at end of file diff --git a/Lab7/include/switch.h b/Lab7/include/switch.h new file mode 100644 index 000000000..c550e1bb6 --- /dev/null +++ b/Lab7/include/switch.h @@ -0,0 +1,8 @@ +#ifndef _SWITCH_H +#define _SWITCH_H + +#include "task.h" + +task_struct* get_current(); + +#endif diff --git a/Lab7/include/sysreg.h b/Lab7/include/sysreg.h new file mode 100644 index 000000000..7e605cf5f --- /dev/null +++ b/Lab7/include/sysreg.h @@ -0,0 +1,22 @@ +#ifndef __SYSREG_H_ +#define __SYSREG_H_ + +#define read_sysreg(r) ({ \ + unsigned long __val; \ + asm volatile("mrs %0, " #r : "=r" (__val)); \ + __val; \ +}) + +#define write_sysreg(r, __val) ({ \ + asm volatile("msr " #r ", %0" :: "r" (__val)); \ +}) + +#define ESR_ELx_EC(esr) ((esr & 0xFC000000) >> 26) +#define ESR_ELx_ISS(esr) (esr & 0x03FFFFFF) + +#define ESR_ELx_EC_SVC64 0b010101 +#define ESR_ELx_EC_DABT_LOW 0b100100 +#define ESR_ELx_EC_IABT_LOW 0b100000 +#define ESR_ELx_EC_BRK_LOW 0b110000 + +#endif \ No newline at end of file diff --git a/Lab7/include/system_call.h b/Lab7/include/system_call.h new file mode 100644 index 000000000..4e120b234 --- /dev/null +++ b/Lab7/include/system_call.h @@ -0,0 +1,16 @@ +#ifndef _SYSTEM_CALL_H +#define _SYSTEM_CALL_H + +#include + +/* helper functions for user programs, not the real system calls */ +int get_pid(); +size_t uart_read(char buf[], size_t size); +size_t uart_write(const char buf[], size_t size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(); +int mbox_call(unsigned char ch, unsigned int *mbox); +void kill(int pid); + +#endif \ No newline at end of file diff --git a/Lab7/include/task.h b/Lab7/include/task.h new file mode 100644 index 000000000..8a44d16c6 --- /dev/null +++ b/Lab7/include/task.h @@ -0,0 +1,79 @@ +#ifndef _TASK_H +#define _TASK_H + +#include +#include "vfs.h" + +#define TERMINATED 0 +#define RUNNING 1 +#define WAITING 2 + + +typedef struct trap_frame { + unsigned long regs[32]; + unsigned long sp_el0; + unsigned long elr_el1; + unsigned long spsr_el1; +} trap_frame; + +typedef struct cpu_context { + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; //x29: kernel frame pointer + unsigned long lr; //x30: link register for function calls + unsigned long sp; // kernel stack pointer +} cpu_context; + +typedef struct task_struct { + cpu_context context; + int id; + int state; + unsigned long user_fp; + void (*handler)(); + void *page_table; + struct task_struct *prev; + struct task_struct *next; + file* fd_table[FD_TABLE_SIZE]; + vnode* cur_dir; +} task_struct; + +typedef struct task_queue { + char name[10]; + task_struct *begin; + task_struct *end; +} task_queue; + +extern task_queue run_queue; +extern task_queue wait_queue; +extern task_queue terminated_queue; +extern int run_queue_sz; +extern char **_argv; + +extern unsigned long user_addr; +extern unsigned long user_sp; + +task_struct* thread_create(void* func); +void thread_schedule(); +void kill_zombies(); +void idle(); +void create_root_thread(); +void run_user_program(const char* name, char *const argv[]); +void switch_to_user_space(); + +void dump_queue(task_queue *queue); +void push_task_to_queue(task_queue *queue, task_struct *task); +void pop_task_from_queue(task_queue *queue, task_struct *task); + +/* Helper functions */ +void put_args(char *const argv[]); +task_struct *find_task_by_id(task_queue *queue, int pid); + +#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..ae55eba5b --- /dev/null +++ b/Lab7/include/timer.h @@ -0,0 +1,30 @@ +#ifndef __TIMER_H +#define __TIMER_H + +#include +#include "peripherals/base.h" + +#define CORE0_TIMER_IRQ_CTRL ((volatile unsigned int *)(KVA + 0x40000040)) +#define MAX_TIMER_QUEUE_SIZE 10 + +typedef void (*timer_call_back)(void *); +struct Timer { + struct Timer *next; + uint64_t expire_time; + timer_call_back call_back; + void *args; +}; + +void init_timer(); +void core_timer_enable(); +void core_timer_handler(); +void add_timer(unsigned int time, timer_call_back, void *); +void pop_timer(); +void test_timer(); + +/* callbacks */ +void show_time_elapsed(void *); +void print_timer(void *); +void normal_timer(); + +#endif diff --git a/Lab7/include/tmpfs.h b/Lab7/include/tmpfs.h new file mode 100644 index 000000000..6a00ee811 --- /dev/null +++ b/Lab7/include/tmpfs.h @@ -0,0 +1,34 @@ +#ifndef __TMPHS_H__ +#define __TMPHS_H__ + +#include "vfs.h" +#include + + +typedef struct { + char* name; + int type; + int capacity; + int size; + void* data; // contain a list of child vnodes if this is a dir, real data if this is a file + void* cache;// only for FILE_TYPE +} Content; + +int tmpfs_setup(filesystem* fs, mount* mnt); +int tmpfs_nodeInit(vnode* root); +void tmpfs_dump(vnode* cur, int level); +void cache_init(Content* content); + +// vops +int tmpfs_lookup(vnode* dir_node, vnode** target, const char* component_name); +int tmpfs_creat(vnode* dir_node, vnode** target, const char* component_name); +int tmpfs_mkdir(vnode* dir_node, vnode** target, const char* component_name); + +// fops +int tmpfs_read(file* f, void* buf, size_t len); +int tmpfs_write(file* f, const void* buf, size_t len); +int tmpfs_open(vnode* file_node, file** target); +int tmpfs_close(file* file); + + +#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..68d636b25 --- /dev/null +++ b/Lab7/include/utils.h @@ -0,0 +1,15 @@ +#ifndef _UtilS_H +#define _UtilS_H + +#define MAX_BUFFER_SIZE 256u + +int compare_string(const char *s1, const char *s2); +void uintoa(char *out, unsigned int i); +unsigned int getIntegerFromString(const char *str); +unsigned long getHexFromString(const char *str); +unsigned long getHexFromString8(const char *str); +unsigned long hexToDec(char *s); +void align_4(void* size); +const char* slashIgnore(const char* src, char* dst, int size); + +#endif \ No newline at end of file diff --git a/Lab7/include/vfs.h b/Lab7/include/vfs.h new file mode 100644 index 000000000..4d3a69b31 --- /dev/null +++ b/Lab7/include/vfs.h @@ -0,0 +1,85 @@ +#ifndef __VFS_H__ +#define __VFS_H__ + +#include + +struct vnode { + struct mount* mnt; + struct vnode_operations* v_ops; + struct file_operations* f_ops; + struct vnode* parent; + void* internal; +}; + +// file handle +struct file { + struct vnode* node; + unsigned long f_pos; // The next read/write position of this opened file + struct file_operations* f_ops; + int flags; +}; + +struct mount { + struct vnode* root; + struct filesystem* fs; +}; + +struct filesystem { + const char* name; + int (*setup_mount)(struct filesystem* fs, struct mount* mnt); +}; + +struct file_operations { + int (*write) (struct file* f, const void* buf, unsigned long len); + int (*read) (struct file* f, void* buf, unsigned long len); + int (*open)(struct vnode* file_node, struct file** target); + int (*close)(struct file* file); + //long lseek64(struct file* file, long offset, int whence); +}; + +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 mode_t {}; + +typedef struct mount mount; +typedef struct filesystem filesystem; +typedef struct vnode vnode; +typedef struct vnode_operations vnode_operations; +typedef struct file file; +typedef struct file_operations file_operations; +typedef struct mode_t mode_t; + +#define DIR_TYPE 1 +#define FILE_TYPE 2 +#define DIR_CAP 16 +#define PREFIX_LEN 256 +#define O_CREAT 00000100 +#define FD_TABLE_SIZE 16 + +#define SUCCESS 0 +#define FAIL 1 +#define FILE_NOT_EXIST 2 + +extern struct mount* rootfs; +extern struct mount* initramfs; + +// register the file system to the kernel. +// you can also initialize memory pool of the file system here. +int register_filesystem(filesystem* fs, const char* fs_name); +int vfs_open(const char* pathname, int flags, file** target, vnode* root); +int vfs_close(file* f); +int vfs_read(file* f, void* buf, size_t len); +int vfs_write(file* f, const void* buf, size_t len); +int vfs_create(vnode* dir_node, vnode** target, const char* component_name); +int vfs_mkdir(const char* pathname, vnode* root); +int vfs_mount(const char* target, const char* file_system, vnode* root); +int vfs_lookup(const char* pathname, vnode** target, vnode* root); + +vnode* find_root(const char* pathname, vnode* cur_dir, char** new_pathname); +int isReadOnly(vnode* node); + +#endif \ No newline at end of file diff --git a/Lab7/include/vm.h b/Lab7/include/vm.h new file mode 100644 index 000000000..f5fa4c23e --- /dev/null +++ b/Lab7/include/vm.h @@ -0,0 +1,36 @@ +#ifndef _VM_H +#define _VM_H + +#include + +//number of the most significant bits that must be either all 0s or all 1s +#define TCR_CONFIG_REGION_48bit (((64 - 48) << 0) | ((64 - 48) << 16)) +//smallest block of memory that can be independently mapped in the translation tables +#define TCR_CONFIG_4KB ((0b00 << 14) | (0b10 << 30)) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +#define MAIR_DEVICE_nGnRnE 0b00000000 //peripheral access +#define MAIR_NORMAL_NOCACHE 0b01000100 //normal RAM access +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 +#define MAIR_CONFIG_DEFAULT ((MAIR_DEVICE_nGnRnE<<(MAIR_IDX_DEVICE_nGnRnE*8))|(MAIR_NORMAL_NOCACHE<<(MAIR_IDX_NORMAL_NOCACHE*8))) + +#define PD_TABLE 0b11 +#define BOOT_PGD_ATTR PD_TABLE +#define PD_BLOCK 0b01 +#define PD_ACCESS (1 << 10) //access flag, a page fault is generated if not set +#define BOOT_PUD_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) //for L1 (ARM peripherals) +#define BOOT_L2D_ATTR (PD_ACCESS | (MAIR_IDX_DEVICE_nGnRnE << 2) | PD_BLOCK) //for L2 (peripherals) +#define BOOT_L2N_ATTR (PD_ACCESS | (MAIR_IDX_NORMAL_NOCACHE << 2) | PD_BLOCK) //for L2 (normal) + +#define VA2PA(x) ((unsigned long)(x) & 0xffffffffffff) +#define PA2VA(x) ((unsigned long)(x) | 0xffff000000000000) + +void mmu_init(); +void initPT(void** page_table); +void freePT(void** page_table); +void map_pages(void* page_table, uint64_t va, int page_num, uint64_t pa); +void dupPT(void* page_table_src, void* page_table_dst, int level); +void vc_identity_mapping(void* page_table_src); + +#endif \ No newline at end of file diff --git a/Lab7/kernel/boot.S b/Lab7/kernel/boot.S new file mode 100644 index 000000000..2d8c6a53f --- /dev/null +++ b/Lab7/kernel/boot.S @@ -0,0 +1,175 @@ +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 // Load value from a system register to one of the general purpose registers (x0–x30) + and x0, x0,#0xFF // Check processor id + cbz x0, master // Hang for all non-primary CPU + b proc_hang + +proc_hang: + b proc_hang + +master: + bl from_el2_to_el1 + ldr x0, =exception_table // setup interrupt vector base + msr vbar_el1, x0 + + bl mmu_init + + ldr x1, =__stk_start + mov sp, x1 + + ldr x1, =__bss_start + ldr w2, =__bss_size +memzero: + cbz w2, main + str xzr, [x1], #8 + sub w2, w2, #1 + b memzero + +main: + bl kernel_main // Perform an unconditional branch and store the return address in x30 + b proc_hang // Should never come here + +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 + + +// save registers to stack +.macro save_regs + sub sp, sp, 36 * 8 + stp x0, x1, [sp, 16 * 0] + stp x2, x3, [sp, 16 * 1] + stp x4, x5, [sp, 16 * 2] + stp x6, x7, [sp, 16 * 3] + stp x8, x9, [sp, 16 * 4] + stp x10, x11, [sp, 16 * 5] + stp x12, x13, [sp, 16 * 6] + stp x14, x15, [sp, 16 * 7] + stp x16, x17, [sp, 16 * 8] + stp x18, x19, [sp, 16 * 9] + stp x20, x21, [sp, 16 * 10] + stp x22, x23, [sp, 16 * 11] + stp x24, x25, [sp, 16 * 12] + stp x26, x27, [sp, 16 * 13] + stp x28, x29, [sp, 16 * 14] + str x30, [sp, 16 * 15] + + mrs x19, sp_el0 + mrs x20, elr_el1 + mrs x21, spsr_el1 + stp x19,x20, [sp, 16 * 16] + str x21, [sp, 16 * 17] +.endm + +// load registers from stack +.macro load_regs + ldp x21, x20, [sp, 16 * 17] + ldp x19, x20, [sp, 16 * 16] + msr spsr_el1, x21 + msr elr_el1, x20 + msr sp_el0, x19 + + ldp x0, x1, [sp, 16 * 0] + ldp x2, x3, [sp, 16 * 1] + ldp x4, x5, [sp, 16 * 2] + ldp x6, x7, [sp, 16 * 3] + ldp x8, x9, [sp, 16 * 4] + ldp x10, x11, [sp, 16 * 5] + ldp x12, x13, [sp, 16 * 6] + ldp x14, x15, [sp, 16 * 7] + ldp x16, x17, [sp, 16 * 8] + ldp x18, x19, [sp, 16 * 9] + ldp x20, x21, [sp, 16 * 10] + ldp x22, x23, [sp, 16 * 11] + ldp x24, x25, [sp, 16 * 12] + ldp x26, x27, [sp, 16 * 13] + ldp x28, x29, [sp, 16 * 14] + ldr x30, [sp, 16 * 15] + add sp, sp, 36 * 8 +.endm + + +//exception table +.align 11 +exception_table: + b TODO + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + + .align 7 + b curr_sync + .align 7 + b curr_iqr + .align 7 + b TODO + .align 7 + b TODO + + .align 7 + b lower_sync + .align 7 + b lower_iqr + .align 7 + b TODO + .align 7 + b TODO + + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + .align 7 + b TODO + +//Synchronous from lower level +lower_sync: + save_regs + mov x0, sp // points to the kernel stack of the running user thread + bl lower_sync_handler + load_regs + eret + +//IRQ from lower level (sp points to the kernel stack of the running user thread) +lower_iqr: + save_regs + bl lower_iqr_handler + load_regs + eret + +//Synchronous from current level +curr_sync: + save_regs + bl curr_sync_handler + load_regs + eret + +//IRQ from current level +curr_iqr: + save_regs + bl curr_iqr_handler + load_regs + eret + +.globl child_return_from_fork +child_return_from_fork: + load_regs + eret + +TODO: + save_regs + bl error_handler + load_regs + eret \ No newline at end of file diff --git a/Lab7/kernel/exception.c b/Lab7/kernel/exception.c new file mode 100644 index 000000000..56090ed03 --- /dev/null +++ b/Lab7/kernel/exception.c @@ -0,0 +1,408 @@ +#include "utils.h" +#include "mini_uart.h" +#include "peripherals/mini_uart.h" +#include "exception.h" +#include "sysreg.h" +#include "timer.h" +#include "system_call.h" +#include "switch.h" +#include "memory.h" +#include "cpio.h" +#include "shell.h" +#include "mail_box.h" +#include "vm.h" +#include "allocator.h" +#include "tmpfs.h" + + +void enable_interrupt() { asm volatile("msr DAIFClr, 0xf"); } +void disable_interrupt() { asm volatile("msr DAIFSet, 0xf"); } + +/* system call */ +void lower_sync_handler(trap_frame *tf) { + unsigned long esr, svc; + asm volatile("mrs %0, esr_el1 \n":"=r"(esr):); + unsigned long *regs = tf->regs; + if (((esr >> 26) & 0x3f) == 0x15) { + svc = esr & 0x1ffffff; + if (svc == 0) { + switch(regs[8]) { + case 0: + regs[0] = sys_getpid(); + thread_schedule(); + break; + case 1: + enable_interrupt(); + regs[0] = sys_uartread((char*)regs[0], (size_t)regs[1]); + disable_interrupt(); + break; + case 2: + enable_interrupt(); + regs[0] = sys_uartwrite((const char*)regs[0], (size_t)regs[1]); + disable_interrupt(); + break; + case 3: + sys_exec(tf, (const char*)regs[0], (char * const*)regs[1]); + thread_schedule(); + break; + case 4: + sys_fork(tf); + thread_schedule(); + break; + case 5: + sys_exit(regs[0]); + thread_schedule(); + break; + case 6: + regs[0] = sys_mbox_call((unsigned char)regs[0], (volatile unsigned int*)regs[1]); + thread_schedule(); + break; + case 7: + sys_kill(regs[0]); + thread_schedule(); + break; + case 8: + sys_signal((int)regs[0], (void (*)())regs[1]); + thread_schedule(); + break; + case 9: + sys_signal_kill((int)regs[0], (int)regs[1]); + thread_schedule(); + break; + case 11: + regs[0] = sys_open((const char*)regs[0], (int)regs[1]); + break; + case 12: + regs[0] = sys_close((int)regs[0]); + break; + case 13: + regs[0] = sys_write((int)regs[0], (const void*)regs[1], (int)regs[2]); + break; + case 14: + regs[0] = sys_read((int)regs[0], (void*)regs[1], (int)regs[2]); + break; + case 15: + regs[0] = sys_mkdir((const char*)regs[0]); + break; + case 16: + regs[0] = sys_mount((const char*)regs[0], (const char*)regs[1], (const char*)regs[2], (unsigned long)regs[3], (const void*)regs[4]); + break; + case 17: + regs[0] = sys_chdir((const char*)regs[0]); + break; + default: + uart_printf("[ERROR][lower_sync_handler] unknown svc!\n"); + } + } + else { + uart_printf("[ERROR][lower_sync_handler] unknown exception!\n"); + while(1) {} + } + } + else { + unsigned ec = (esr & 0xFC000000) >> 26; + switch(ec) { + case ESR_ELx_EC_DABT_LOW: + uart_printf("[Segfault] Userland data abort exception! pc: %x\n", read_sysreg(elr_el1)); + while(1) {} + case ESR_ELx_EC_IABT_LOW: + uart_printf("[Segfault] Userland instruction abort exception! pc: %x\n", read_sysreg(elr_el1)); + while(1) {} + default: + uart_printf("[ERROR][lower_sync_handler] unknown exception!\n"); + while(1) {} + } + } +} + +void lower_iqr_handler() { + pop_timer(); +} + +void curr_sync_handler() { + unsigned long elr = read_sysreg(elr_el1); + uart_printf("[ERROR][curr_sync_handler] PC: %x\n", elr); + error_handler(); +} + +void curr_iqr_handler() { + if (*IRQ_PENDING_1 & AUX_IRQ) + uart_handler(); + else + pop_timer(); +} + +void error_handler() { + uart_send_string("[ERROR] unknown exception...\n"); + while(1){} +} + +void dumpState() { + unsigned long esr = read_sysreg(esr_el1); + unsigned long elr = read_sysreg(elr_el1); + unsigned long spsr = read_sysreg(spsr_el1); + uart_printf("--------------------\n"); + uart_printf("SPSR: 0x%x\n", spsr); + uart_printf("ELR: 0x%x\n", elr); + uart_printf("ESR: 0x%x\n", esr); + uart_printf("--------------------\n"); +} + +/* Implement system calls */ +int sys_getpid() { + debug_printf("[DEBUG][sys_getpid] id: %d\n", get_current()->id); + return get_current()->id; +} + +size_t sys_uartread(char buf[], size_t size) { + char recv; + for (int i = 0; i < size; ++i) { + recv = uart_recv(); + buf[i] = recv; + } + debug_printf("[DEBUG][sys_uartread]\n"); + return size; +} + +size_t sys_uartwrite(const char buf[], size_t size) { + for (int i = 0; i < size; ++i) + uart_send((char)buf[i]); + debug_printf("[DEBUG][sys_uartwrite]\n"); + return size; +} + +int sys_exec(trap_frame *tf, const char *name, char *const argv[]) { + char prefix[PREFIX_LEN]; + char* pruned_name = (char*)slashIgnore(name, prefix, PREFIX_LEN); // rip off the leading '/' + task_struct *cur_task = get_current(); + freePT(&(cur_task->page_table)); + initPT(&(cur_task->page_table)); + load_program(pruned_name, cur_task->page_table); + for (int i = 0; i < 4; ++i) + map_pages(cur_task->page_table, 0xffffffffb000 + i * 0x1000, 1, VA2PA(page_malloc(0))); + _argv = (char**)argv; + tf->elr_el1 = (unsigned long)USER_PROGRAM_VA; + tf->sp_el0 = cur_task->user_fp; + return 0; +} + +void sys_fork(trap_frame *tf) { + task_struct *parent = get_current(); + task_struct *child = thread_create(NULL); + int child_id = child->id; + //unsigned long user_fp = child->user_fp; + task_struct *prev = child->prev; + task_struct *next = child->next; + + /* copy the task context & kernel stack (including trap frame) of parent to child */ + char* src = (char*)parent; + char* dst = (char*)child; + int size = PAGE_SIZE_4K; + while(size--) { + *dst = *src; + src++; + dst++; + } + + initPT(&(child->page_table)); + dupPT(parent->page_table, child->page_table, 0); + //vc_identity_mapping for video program + for (uint64_t va = 0x3c000000; va <= 0x3f000000 - 4096; va += 4096) + map_pages(child->page_table, va, 1, va); + + for (int i = 0; i < FD_TABLE_SIZE; ++i) { + if (parent->fd_table[i] != 0) { + file* src_file = parent->fd_table[i]; + file* dst_file = kmalloc(sizeof(file)); + dst_file->node = src_file->node; + dst_file->f_pos = src_file->f_pos; + dst_file->f_ops = src_file->f_ops; + dst_file->flags = src_file->flags; + } + } + + /* set up the correct value for registers */ + parent->context.sp = (unsigned long)tf; + if ((unsigned long)child > (unsigned long)parent) + child->context.sp = parent->context.sp + ((unsigned long)child - (unsigned long)parent); + else + child->context.sp = parent->context.sp - ((unsigned long)parent - (unsigned long)child); + //int parent_ustack_size = (parent->user_fp) - (tf->sp_el0) + 1; + child->context.fp = (unsigned long)child + PAGE_SIZE_4K - 16; + child->context.lr = (unsigned long)child_return_from_fork; + child->id = child_id; + //child->user_fp = user_fp; + child->prev = prev; + child->next = next; + trap_frame *child_tf = (trap_frame*)(child->context.sp); + //child_tf->sp_el0 = (child->user_fp) - parent_ustack_size + 1; + child_tf->regs[0] = 0; + child_tf->regs[29] = child->context.fp; + tf->regs[0] = child->id; + child->handler = parent->handler; + + /* copy the user stack of parent to child */ + // char *src_stack = (char*)(tf->sp_el0); + // char *dst_stack = (char*)(child_tf->sp_el0); + + // while(parent_ustack_size--) { + // *dst_stack = *src_stack; + // src_stack++; + // dst_stack++; + // } + + debug_printf("[DEBUG][sys_fork] parent: %d, child: %d\n", parent->id, child->id); +} + +void sys_exit() { + task_struct *cur_task = get_current(); + cur_task->state = TERMINATED; + pop_task_from_queue(&run_queue, cur_task); + push_task_to_queue(&terminated_queue, cur_task); + debug_printf("[DEBUG][sys_exit] thread: %d\n", cur_task->id); +} + +int sys_mbox_call(unsigned char ch, volatile unsigned int *mbox) { + debug_printf("[DEBUG][sys_mbox_call]"); + if (((uint64_t)mbox & 0xFFFF000000000000) == 0) { //lower va + //uart_printf("va: %x\n", mbox); + asm volatile("mov x0, %0 \n"::"r"(mbox)); + asm volatile("at s1e0r, x0 \n"); + uint64_t frame_addr = (uint64_t)read_sysreg(par_el1) & (0xFFFFFFFFF << 12); + uint64_t pa = frame_addr | ((uint64_t)mbox & 0xFFF); + //uart_printf("frame_addr: %x, pa: %x\n", frame_addr, pa); + if ((read_sysreg(par_el1) & 0x1) == 1) + uart_printf("[ERROR][sys_mbox_call] va translation fail!\n"); + return mailbox_call(ch, (volatile unsigned int*)pa, mbox); + } + return mailbox_call(ch, (volatile unsigned int*)mbox, mbox); +} + +void sys_kill(int pid) { + task_struct *task = NULL; + if ((task = find_task_by_id(&run_queue, pid))) + pop_task_from_queue(&run_queue, task); + else if ((task = find_task_by_id(&wait_queue, pid))) + pop_task_from_queue(&wait_queue, task); + if (task) { + task->state = TERMINATED; + push_task_to_queue(&terminated_queue, task); + } + debug_printf("[DEBUG][sys_kill]"); +} + +void sys_signal(int SIGNAL, void (*handler)()) { + get_current()->handler = handler; +} + +void sys_signal_kill(int pid, int SIGNAL) { + task_struct *task = NULL; + if (!(task = find_task_by_id(&run_queue, pid))) + task = find_task_by_id(&wait_queue, pid); + if (!task) + return; + _handler = task->handler; + _pid = pid; + task_struct *handler_task = thread_create(switch_to_user_space); + user_addr = (unsigned long)signal_handler_wrapper; + user_sp = handler_task->user_fp; +} + +int sys_open(const char *pathname, int flags) { + //uart_printf("sys_open: %s\n", pathname); + task_struct* cur = get_current(); + char* new_path; + vnode* new_root; + new_root = find_root(pathname, cur->cur_dir, &new_path); + for (int i = 0; i < FD_TABLE_SIZE; ++i) { + if ((cur->fd_table)[i] == 0 && (vfs_open(new_path, flags, &(cur->fd_table)[i], new_root) == SUCCESS)) + return i; + } + uart_printf("[sys_open fail]\n"); + return -1; +} + +int sys_close(int fd) { + //uart_printf("sys_close\n"); + if (fd < 0 || fd >= FD_TABLE_SIZE) { + uart_printf("[ERROR][sys_close] Invalid fd: %d\n", fd); + } + task_struct* cur = get_current(); + if ((cur->fd_table)[fd] && (vfs_close((cur->fd_table)[fd]) == SUCCESS)) { + (cur->fd_table)[fd] = 0; + return 0; + } + uart_printf("[sys_close fail]\n"); + return -1; +} + +int sys_write(int fd, const void *buf, int count) { + //uart_printf("sys_write\n"); + if (fd < 0 || fd >= FD_TABLE_SIZE) { + uart_printf("[ERROR][sys_close] Invalid fd: %d\n", fd); + } + task_struct* cur = get_current(); + if ((cur->fd_table)[fd]) + return vfs_write((cur->fd_table)[fd], buf, count); + uart_printf("[sys_write fail]\n"); + return -1; +} + +int sys_read(int fd, void *buf, int count) { + //uart_printf("sys_read\n"); + if (fd < 0 || fd >= FD_TABLE_SIZE) { + uart_printf("[ERROR][sys_close] Invalid fd: %d\n", fd); + } + task_struct* cur = get_current(); + if ((cur->fd_table)[fd]) + return vfs_read((cur->fd_table)[fd], buf, count); + uart_printf("[sys_read fail]\n"); + return -1; +} + +int sys_mkdir(const char *pathname) { + //uart_printf("sys_mkdir: %s\n", pathname); + char* new_path; + vnode* new_root; + new_root = find_root(pathname, get_current()->cur_dir, &new_path); + if (vfs_mkdir(new_path, new_root) == SUCCESS) + return 0; + uart_printf("[sys_mkdir fail]\n"); + return -1; +} + +// you can ignore arguments other than target and filesystem +int sys_mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data) { + //uart_printf("sys_mount: %s\n", target); + char* new_path; + vnode* new_root; + new_root = find_root(target, get_current()->cur_dir, &new_path); + if (vfs_mount(new_path, filesystem, new_root) == SUCCESS) + return 0; + uart_printf("[sys_mount fail]\n"); + return -1; +} + +int sys_chdir(const char *path) { + //uart_printf("sys_chdir: %s\n", path); + if (compare_string(path, "/") == 0) { + get_current()->cur_dir = rootfs->root; + return 0; + } + char* new_path; + vnode* node, *new_root = find_root(path, get_current()->cur_dir, &new_path); + if (vfs_lookup(new_path, &node, new_root) != SUCCESS) + return -1; + get_current()->cur_dir = node; + return 0; +} + +/* helper functions */ +void (*_handler)() = NULL; +int _pid = 0; +void signal_handler_wrapper() { + if (_handler) + _handler(); + kill(_pid); + exit(); +} \ No newline at end of file diff --git a/Lab7/kernel/kernel.c b/Lab7/kernel/kernel.c new file mode 100644 index 000000000..f6f1842af --- /dev/null +++ b/Lab7/kernel/kernel.c @@ -0,0 +1,32 @@ +#include "mini_uart.h" +#include "shell.h" +#include "exception.h" +#include "timer.h" +#include "memory.h" +#include "allocator.h" +#include "task.h" +#include "vfs.h" +#include "tmpfs.h" + + +void kernel_main(void) { + uart_init(); + memory_init(); + init_reserve(); + init_timer(); + enable_interrupt(); + create_root_thread(); + + // setup tmpfs + rootfs = kmalloc(sizeof(mount)); + rootfs->root = kmalloc(sizeof(vnode)); + rootfs->root->mnt = rootfs; + rootfs->fs = kmalloc(sizeof(filesystem)); + register_filesystem(rootfs->fs, "tmpfs"); + rootfs->fs->setup_mount(rootfs->fs, rootfs); + rootfs->root->parent = rootfs->root; + tmpfs_nodeInit(rootfs->root); + tmpfs_dump(rootfs->root, 0); + + shell(); +} diff --git a/Lab7/kernel/linker.ld b/Lab7/kernel/linker.ld new file mode 100644 index 000000000..df30f2423 --- /dev/null +++ b/Lab7/kernel/linker.ld @@ -0,0 +1,16 @@ +SECTIONS +{ + . = 0xffff000000000000; + . += 0x80000; + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + . = ALIGN(0x8); + __bss_start = .; + .bss : { *(.bss*) } + __bss_end = .; + __stk_start = __bss_end + (1<<16); +} + +__bss_size = (__bss_end - __bss_start) >> 3; \ No newline at end of file diff --git a/Lab7/lib/allocator.c b/Lab7/lib/allocator.c new file mode 100644 index 000000000..0f52c5dd1 --- /dev/null +++ b/Lab7/lib/allocator.c @@ -0,0 +1,178 @@ +#include "allocator.h" +#include "utils.h" +#include "mini_uart.h" +#include "shell.h" +#include "cpio.h" + + +/* record the usage of each slot */ +const int slot_size = 4; +const int slot[] = {32, 64, 128, 256}; +const uint64_t slot_max[] = {UINT32_MAX, UINT16_MAX - (1 << 15), UINT8_MAX, 15}; +const int slot_record_bits[] = {32, 15, 8, 4}; +const uint64_t slot_masks[] = {UINT32_MAX, UINT16_MAX, UINT8_MAX, UINT8_MAX}; +const int slot_shift_amout[] = {32, 16, 8, 0}; +const int slot_offset[] = {64, 64 + 32 * 32, 64 + 32 * 32 + 64 * 15, 64 + 32 * 32 + 64 * 15 + 128 * 8}; + +/* mantain pages */ +frame_free_node *allocated_pages = NULL; + +void *kmalloc(size_t size) { + int sz = round_to_smallest(size); + frame_free_node * page = get_page_with_slot(sz); + return allocate_slot(page, sz); +} + +void kfree(void *addr) { + frame_free_node *page = find_page(addr); + uint64_t _addr = (uint64_t)addr - GET_PAGE_ADDR(page->index); + int size; + for (size = 3; size >= 0; --size) { + if (_addr >= slot_offset[size]) + break; + } + _addr -= slot_offset[size]; + int which_slot = _addr / slot[size]; + set_slot_record(page, size, which_slot, 0); + free_page_if_empty(page); +} + +/* get usage record of the slot size in the page */ +uint64_t get_slot_record(frame_free_node *page, int size) { + uint64_t page_addr = GET_PAGE_ADDR(page->index); + uint64_t record = *(uint64_t *)page_addr; + return (record & (slot_masks[size] << slot_shift_amout[size])) >> slot_shift_amout[size]; +} + +/* set/unset the bit in the record for a slot of a size of a page */ +void set_slot_record(frame_free_node *page, int size, int which_slot, int value) { + uint64_t record = get_slot_record(page, size); + uint64_t mask = (uint64_t)1 << which_slot; + if (value == 0) { + mask = ~mask; + record &= mask; + } + else + record |= mask; + uint64_t *full_record_ptr = (uint64_t *)GET_PAGE_ADDR(page->index); + mask = slot_masks[size] << slot_shift_amout[size]; + *full_record_ptr &= ~mask; + *full_record_ptr |= (record << slot_shift_amout[size]); + if (which_slot >= slot_record_bits[size]) + uart_printf("[ERROR] set_slot_record: invlaid slot index!\n"); + debug_printf("[DEBUG][set_slot_record] set %d'th of %d bytes slot to %d\n", which_slot, slot[size], value); +} + +/* check if there is any empty 2^size bytes slot is spedified page */ +int is_full(frame_free_node *page, int size) { + return get_slot_record(page, size) == slot_max[size]; +} + +int is_empty(frame_free_node *page, int size) { + return get_slot_record(page, size) == 0; +} + +int round_to_smallest(size_t size) { + if (size <= 0) + uart_printf("[ERROR] round_to_smallest: invalid size!\n"); + if (size > 256) + uart_printf("[ERROR] round_to_smallest: too large!\n"); + int i; + for (i = 0; i < 4; ++i) { + if (slot[i] >= size) + break; + } + if (i == 4) + uart_printf("[ERROR][round_to_smallest] should not reach here!\n"); + debug_printf("[DEBUG][round_to_smallest] round %d to %d bytes\n", size, slot[i]); + return i; +} + +frame_free_node *get_page_with_slot(int size) { + frame_free_node *page = allocated_pages; + while (page) { + if (!is_full(page, size)) + break; + page = page->next; + } + if (!page) { + uint64_t addr = page_malloc(0); + uint64_t index = GET_PAGE_INDEX(addr); + add_to_list(&allocated_pages, index); + page = allocated_pages; + clear_4K_page(page->index); + } + return page; +} + +void *allocate_slot(frame_free_node *page, int size) { + uint64_t record = get_slot_record(page, size); + uint64_t mask = 1; + int i; + for (i = 0; i < slot_record_bits[size]; ++i) { + if ((record & mask) == 0) + break; + mask <<= 1; + } + set_slot_record(page, size, i, 1); + if (i == slot_record_bits[size]) + uart_printf("[ERROR] allocate_slot: should not reach here!\n"); + uint64_t addr = GET_PAGE_ADDR(page->index) + slot_offset[size] + slot[size] * i; + return (void*)addr; +} + +frame_free_node *find_page(void *addr) { + uint64_t _addr = (uint64_t)addr; + uint64_t mask = (~(uint64_t)0) << 12; + _addr &= mask; + frame_free_node *iter = allocated_pages; + while (iter) { + if (GET_PAGE_ADDR(iter->index) == _addr) + break; + iter = iter->next; + } + return iter; +} + +void clear_page(frame_free_node *page) { + char *addr = (char*)GET_PAGE_ADDR(page->index); + int sz = 1 << 12; + for (int i = 0; i < sz; ++i) + addr[i] = 0; +} + +void print_slot_record(frame_free_node *page) { + if (page) { + uart_printf("[Slot record] (page index: %ld) ", page->index); + for (int i = 0; i < 4; ++i) { + uint64_t record = get_slot_record(page, i); + uart_printf("%x ", record); + } + uart_printf("\n"); + } + else + uart_printf("[Slot record] page already freed!\n"); +} + +void free_page_if_empty(frame_free_node *page) { + for (int i = 0; i < 4; ++i) { + if (!is_empty(page, i)) + return; + } + remove_from_list(&allocated_pages, page->index); + page_free(GET_PAGE_ADDR(page->index), 0); +} + + +void memory_reserve(uint64_t start, uint64_t end) { + for (uint64_t i = start; i < end + PAGE_SIZE_4K; i += PAGE_SIZE_4K) + reserve_page(0, i); +} + +void init_reserve() { + // memory_reserve(KVA + 0x0000, KVA + 0x1000); // spin tables for multicore boot + // reserve_page(0, KVA + 0x2000); // L2 page table for kernel + // reserve_page(0, KVA + 0x3000); // L2 page table for kernel + // memory_reserve(KVA + 0x80000, KVA + 0x800000); // kernel and heap/stack space + debug_printf("[DEBUG][init_reserve] reserves 0X%x 4K pages\n", get_allocated_num()); +} \ No newline at end of file diff --git a/Lab7/lib/cpio.c b/Lab7/lib/cpio.c new file mode 100644 index 000000000..4c5515a28 --- /dev/null +++ b/Lab7/lib/cpio.c @@ -0,0 +1,174 @@ +#include "peripherals/gpio.h" +#include "mini_uart.h" +#include "utils.h" +#include "shell.h" +#include "cpio.h" +#include "timer.h" +#include "sysreg.h" +#include +#include "vm.h" +#include "memory.h" + + +void cpio_list() { + /* + cpio archive comprises a header record with basic numeric metadata followed by + the full pathname of the entry and the file data. + */ + char *addr = CPIO_ADDR; + + while (compare_string((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) { + cpio_header *header = (cpio_header*)addr; + + unsigned long pathname_size = hexToDec(header->namesize); + unsigned long file_size = hexToDec(header->filesize); + unsigned long headerPathname_size = sizeof(cpio_header) + pathname_size; + + align_4(&headerPathname_size); // The pathname is followed by NUL bytes so that the total size of the fixed header plus pathname is a multiple of four. + align_4(&file_size); // Likewise, the file data is padded to a multiple of four bytes. + uart_send_string(addr + sizeof(cpio_header)); // print the fine name + uart_printf(" %d\n", file_size); + addr += (headerPathname_size + file_size); + } +} + +char *findFile(char *name) { + char *addr = CPIO_ADDR; + while (compare_string((char *)(addr + sizeof(cpio_header)), "TRAILER!!!") != 0) { + if ((compare_string((char *)(addr + sizeof(cpio_header)), name) == 0)) { + return addr; + } + cpio_header *header = (cpio_header *)addr; + unsigned long pathname_size = hexToDec(header->namesize); + unsigned long file_size = hexToDec(header->filesize); + unsigned long headerPathname_size = sizeof(cpio_header) + pathname_size; + + align_4(&headerPathname_size); + align_4(&file_size); + addr += (headerPathname_size + file_size); + } + return 0; +} + +void cpio_cat(char *filename) { + char *target = findFile(filename); + if (target) { + cpio_header *header = (cpio_header *)target; + unsigned long pathname_size = hexToDec(header->namesize); + unsigned long file_size = hexToDec(header->filesize); + unsigned long headerPathname_size = sizeof(cpio_header) + pathname_size; + + align_4(&headerPathname_size); + align_4(&file_size); + + char *file_content = target + headerPathname_size; + for (unsigned int i = 0; i < file_size; i++) { + uart_send(file_content[i]); // print the file content + } + uart_send_string("\r\n"); + } + else + uart_printf("File: %s not found!\n", filename); +} + +void load_program(char *name, void *page_table) { + unsigned char *target = (unsigned char*)findFile(name); + if (target) { + cpio_header *header = (cpio_header *)target; + unsigned long pathname_size = hexToDec(header->namesize); + unsigned long file_size = hexToDec(header->filesize); + unsigned long headerPathname_size = sizeof(cpio_header) + pathname_size; + + align_4(&headerPathname_size); + align_4(&file_size); + + asm volatile("mov x0, %0 \n"::"r"(page_table)); + asm volatile("dsb ish \n"); //ensure write has completed + asm volatile("msr ttbr0_el1, x0 \n"); //switch translation based address. + asm volatile("tlbi vmalle1is \n"); //invalidates cached copies of translation table entries from L1 TLBs + asm volatile("dsb ish \n"); //ensure completion of TLB invalidatation + asm volatile("isb \n"); //clear pipeline + + unsigned char *file_content = target + headerPathname_size; + int sz = file_size / 4096 + (file_size % 4096 != 0); + for (int i = 0; i < sz; ++i) { + unsigned char *addr = (unsigned char*)page_malloc(0); + map_pages(page_table, USER_PROGRAM_VA + 4096 * i, 1, (uint64_t)VA2PA(addr)); + for (int j = 0; j < 4096; ++j) + *(addr + j) = file_content[i * 4096 + j]; + } + + debug_printf("[DEBUG][load_program] load program: %s\n", name); + } + else + uart_printf("File: %s not found!\n", name); +} + + +/* VFS */ +void* fbase_get() { + return (void*)CPIO_ADDR; +} + +char* fdata_get(void* _addr, unsigned long* size) { + cpio_header* addr = (cpio_header*)_addr; + unsigned long psize = getHexFromString8(addr->namesize), dsize = getHexFromString8(addr->filesize); + *size = dsize; + if ((sizeof(cpio_header) + psize) & 3) + psize += 4- ((sizeof(cpio_header) + psize) & 3); + if (dsize & 3) + dsize += 4 - (dsize & 3); + + char* path = (char*)(addr + 1); + char* data = path + psize; + + return data; +} + +int fmode_get(void* _addr) { + cpio_header* addr = (cpio_header*)_addr; + unsigned long tmp = VA2PA(getHexFromString8(addr->mode)) >> 12; + if (tmp == 4) + return 1; //dir + else if (tmp == 8) + return 2; //file + return -1; +} + +char* fname_get(void* _addr, unsigned long* size) { + cpio_header* addr = (cpio_header*)_addr; + unsigned long psize = getHexFromString8(addr->namesize), dsize = getHexFromString8(addr->filesize); + *size = psize; + if ((sizeof(cpio_header) + psize) & 3) + psize += 4 - ((sizeof(cpio_header) + psize) & 3); + if (dsize & 3) + dsize += 4 - (dsize & 3); + return (char*)(addr + 1); +} + +void* next_fget(void* _addr) { + cpio_header* addr = (cpio_header*)_addr; + unsigned long psize = getHexFromString8(addr->namesize), dsize = getHexFromString8(addr->filesize); + if ((sizeof(cpio_header) + psize) & 3) + psize += 4 - ((sizeof(cpio_header) + psize) & 3); + if (dsize & 3) + dsize += 4 - (dsize & 3); + + char* path = (char*)(addr + 1); + char* data = path + psize; + + if (compare_string(path,"TRAILER!!!") == 0) + return 0; + addr = (cpio_header*)(data + dsize); + return addr; +} + +void fdump() { + void* addr = CPIO_ADDR; + while(addr) { + unsigned long tmp; + char* str = fname_get(addr, &tmp); + uart_printf("%d, %s\n", tmp, str); + addr = next_fget(addr); + } +} \ No newline at end of file diff --git a/Lab7/lib/mail_box.c b/Lab7/lib/mail_box.c new file mode 100644 index 000000000..27e918ec0 --- /dev/null +++ b/Lab7/lib/mail_box.c @@ -0,0 +1,109 @@ +#include "peripherals/mail_box.h" +#include "mail_box.h" +#include "mini_uart.h" +#include "utils.h" + +/* mailbox message buffer */ +volatile unsigned int __attribute__((aligned(16))) mailbox[36]; + +/** + * Make a mailbox call. Returns 0 on failure, non-zero on success + */ +int mailbox_call(unsigned char ch, volatile unsigned int *mailbox, volatile unsigned int *mailbox_va) +{ + volatile unsigned int r = (((volatile unsigned int)((volatile unsigned long)mailbox)&~0xF) | (ch&0xF)); + /* wait until we can write to the mailbox */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); + /* write the address of our message to the mailbox with channel identifier */ + + *MBOX_WRITE = r; + + /* now wait for the response */ + while(1) { + /* is there a response? */ + do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); + /* is it a response to our message? */ + if(r == *MBOX_READ) { + /* is it a valid successful response? */ + return mailbox_va[1]==MBOX_RESPONSE; + } + } + return 0; +} + +// volatile unsigned int __attribute__((aligned(16))) mailbox[8]; + +// int mailbox_call(unsigned char ch, volatile unsigned int *mbox) { +// uart_printf("==========\n"); +// for (int i = 0; i < 8; ++i) +// uart_printf("%x\n", mbox[i]); +// uart_printf("==========\n"); +// /* +// 1. Combine the message address (upper 28 bits) with channel number (lower 4 bits) +// 2. Check if Mailbox 0 status register’s full flag is set. +// 3. If not, then you can write to Mailbox 1 Read/Write register. +// 4. Check if Mailbox 0 status register’s empty flag is set. +// 5. If not, then you can read from Mailbox 0 Read/Write register. +// 6. Check if the value is the same as you wrote in step 1. +// */ +// unsigned int msg = (((unsigned int)((unsigned long)mailbox) & ~0xF) | (ch & 0xF)); +// while (*MAILBOX_STATUS & MAILBOX_FULL) {} +// *MAILBOX_WRITE = msg; +// while (1) { +// while (*MAILBOX_STATUS & MAILBOX_EMPTY) {} +// if(msg == *MAILBOX_READ){ +// return mbox[1] == REQUEST_SUCCEED; +// } +// } +// return 0; +// } + +void get_board_revision() { + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = MBOX_REQUEST; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = 8; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = MBOX_TAG_LAST; + if (mailbox_call(MBOX_CH_PROP, mailbox, mailbox)) + uart_printf("board revision number: 0x%x\n", mailbox[5]); + else + uart_printf("can not get board revision number!\n"); +} + +void get_arm_memory() { + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = MBOX_REQUEST; + // tags begin + mailbox[2] = GET_ARM_EMEORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = 8; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; // value buffer + // tags end + mailbox[7] = MBOX_TAG_LAST; + if (mailbox_call(MBOX_CH_PROP, mailbox, mailbox)) { + uart_printf("base address: %x\n", mailbox[5]); + uart_printf("memory size: %x\n", mailbox[6]); + } + else + uart_printf("can not get memory info!\n"); +} + +void get_serial_number() { + mailbox[0] = 8*4; // length of the message + mailbox[1] = MBOX_REQUEST; // this is a request message + mailbox[2] = MBOX_TAG_GETSERIAL; // get serial number command + mailbox[3] = 8; // buffer size + mailbox[4] = 8; + mailbox[5] = 0; // clear output buffer + mailbox[6] = 0; + mailbox[7] = MBOX_TAG_LAST; + if(mailbox_call(MBOX_CH_PROP, mailbox, mailbox)) + uart_printf("serial number is: %x%x\n", mailbox[5], mailbox[6]); + else + uart_printf("can not get serial number!\n"); +} \ No newline at end of file diff --git a/Lab7/lib/memory.c b/Lab7/lib/memory.c new file mode 100644 index 000000000..4d2dcf8d3 --- /dev/null +++ b/Lab7/lib/memory.c @@ -0,0 +1,271 @@ +#include "memory.h" +#include "mini_uart.h" +#include "shell.h" + + +frame_free_node *frame_free_lists[4]; // 4K, 8K, 16K, 32K +char frame_array[FRAME_ARRAY_SIZE]; // 0xBB: buddy, 0xAA: allocated +frame_free_node *node_pool_head; // only mantain the "next" pointer, should not use "prev" +frame_free_node node_pool[FRAME_ARRAY_SIZE]; +frame_free_node *free_node_table[FRAME_ARRAY_SIZE]; // map index to node to enable O(1) search and removal + + +void memory_init() { + for (int i = 0; i < FRAME_ARRAY_SIZE; ++i) { + frame_array[i] = 0xBB; + if (i % 8 == 0) + frame_array[i] = 3; + free_node_table[i] = NULL; + } + + for (int i = 0; i < MAX_32K_NUM - 1; ++i) { + node_pool[i].next = &node_pool[i + 1]; + node_pool[i + 1].prev = &node_pool[i]; + } + node_pool[MAX_32K_NUM - 1].next = NULL; + node_pool[0].prev = NULL; + for (int i = 0; i < MAX_32K_NUM; ++i) { + node_pool[i].index = i << 3; + node_pool[i].list_addr = &frame_free_lists[3]; + free_node_table[i << 3] = &node_pool[i]; + } + + for (int i = MAX_32K_NUM; i < FRAME_ARRAY_SIZE - 1; ++i) + node_pool[i].next = &node_pool[i + 1]; + node_pool[FRAME_ARRAY_SIZE - 1].next = NULL; + + frame_free_lists[0] = NULL; + frame_free_lists[1] = NULL; + frame_free_lists[2] = NULL; + frame_free_lists[3] = &node_pool[0]; + node_pool_head = &node_pool[MAX_32K_NUM]; +} + +uint64_t page_malloc(int sz) { + uint64_t index = request_page(sz); + return GET_PAGE_ADDR(index); +} + +/* currently support 4K page request only, the value of frame array may be wrong otherwise */ +uint64_t request_page(int size) { + // if (!get_free_num()) { + // uart_printf("[ERROR][request_page] run out of memory!\n"); + // while (1) {} + // } + + if (size < 0 || size > 3) { + uart_printf("[ERROR][request_page] request_page(%d): illegal argument!\n", size); + return 0; + } + + frame_free_node *free_node = frame_free_lists[size]; + uint64_t index; + if (free_node) { + index = free_node->index; + pop_front(&frame_free_lists[size]); + } + else { + index = request_page(size + 1); + int end = index + (2 << size) - 1; + int mid = (index + end) / 2; + for (int i = index + 1; i <= end; ++i) + frame_array[i] = 0xBB; + frame_array[mid + 1] = size; + add_to_list(&frame_free_lists[size], mid + 1); + debug_printf("[DEBUG][request_page] release redundant memory, index: %ld, size: %ldK\n", mid + 1, 4 * (1 << size)); + } + for (int i = 0; i < (1 << size); ++i) + frame_array[index + i] = 0xAA; + debug_printf("[DEBUG][request_page] allocate memory, index: %ld, size: %dK\n", index, 4 << size); + + return index; +} + +/* same as request_page but guarantees to cover specified address */ +uint64_t reserve_page(int size, uint64_t addr) { + if (size < 0 || size > 3) { + uart_printf("[ERROR][reserve_page] reserve_page(%d): illegal argument!\n", size); + return 0; + } + + uint64_t index = GET_PAGE_INDEX(addr); + uint64_t aligned_index = index & (~(uint64_t)0 << size); + frame_free_node *free_node = free_node_table[aligned_index]; + if (free_node && free_node->list_addr == &frame_free_lists[size]) { + remove_from_list(&frame_free_lists[size], aligned_index); + debug_printf("[DEBUG][reserve_page] allocate memory, index: %ld, size: %dK\n", aligned_index, 4 << size); + } + else { + aligned_index = reserve_page(size + 1, addr); + int end = aligned_index + (2 << size) - 1; + int mid = (aligned_index + end) / 2; + for (int i = aligned_index + 1; i <= end; ++i) + frame_array[i] = 0xBB; + if (index <= mid) { + frame_array[mid + 1] = size; + add_to_list(&frame_free_lists[size], mid + 1); + debug_printf("[DEBUG][reserve_page] release redundant memory, index: %ld, size: %ldK\n", mid + 1, 4 * (1 << size)); + } + else { + frame_array[aligned_index] = size; + add_to_list(&frame_free_lists[size], aligned_index); + debug_printf("[DEBUG][reserve_page] release redundant memory, index: %ld, size: %ldK\n", aligned_index, 4 * (1 << size)); + } + debug_printf("[DEBUG][reserve_page] allocate memory, index: %ld, size: %dK\n", index, 4 << size); + } + for (int i = 0; i < (1 << size); ++i) + frame_array[index + i] = 0xAA; + + return aligned_index; +} + +void page_free(uint64_t addr, int size) { + uint64_t index = getIndex(addr, size); + if (index >= FRAME_ARRAY_SIZE || frame_array[index] != 0xAA) + uart_printf("[ERROR][page_free] page_free: illegal index!\n"); + + debug_printf("[DEBUG][page_free] free %ldK page, index: %ld\n", 4 << size, index); + frame_array[index] = size; + for (int i = 1; i < (1 << size); ++i) + frame_array[index + i] = 0xBB; + add_to_list(&frame_free_lists[size], index); + merge_page(index, size + 1); +} + +void merge_page(uint64_t index, int size) { + if (size > 3) + return; + + uint64_t mask = (1 << size) - 1; + uint64_t start = index & ~mask; + uint64_t end = index | mask; + int mergable = 1; + for (uint64_t i = start; i <= end; ++i) { + if (frame_array[i] == 0xAA) { + mergable = 0; + break; + } + } + + if (!mergable) + return; + + debug_printf("[DEBUG][merge_page] merge into %ldK page\n", 4 << size); + for (uint64_t i = start + 1; i <= end; ++i) + frame_array[i] = 0xBB; + frame_array[start] = size; + for (uint64_t i = start; i <= end; ++i) { + if (free_node_table[i]) + remove_from_list(&frame_free_lists[size - 1], i); + } + add_to_list(&frame_free_lists[size], start); + + merge_page(index, size + 1); +} + +/* remove the first free node from a list */ +void pop_front(frame_free_node **list) { + frame_free_node *free_node = *list; + *list = (*list)->next; + if (*list) + (*list)->prev = NULL; + return_free_node(free_node); +} + +/* remove the free node holding specify index from a list, if exits */ +void remove_from_list(frame_free_node **list, uint64_t index) { + frame_free_node *target = free_node_table[index]; + if (!target) + uart_printf("[ERROR][remove_from_list] illegal index!\n"); + free_node_table[index] = NULL; + if (target->list_addr != list) + uart_printf("[ERROR][remove_from_list] list address not matched!\n"); + target->list_addr = NULL; + if (target == *list) { + *list = (*list)->next; + (*list)->prev = NULL; + } + else { + if (target->next) + target->next->prev = target->prev; + if (!target->prev) + uart_printf("[ERROR][remove_from_list] should not reach here!\n"); + target->prev->next = target->next; + } + return_free_node(target); +} + +/* add a free node holding specify index to a list */ +void add_to_list(frame_free_node **list, uint64_t index) { + frame_free_node *new_node = get_free_node(); + free_node_table[index] = new_node; + new_node->list_addr = list; + new_node->index = index; + new_node->prev = NULL; + new_node->next = *list; + if (*list) + (*list)->prev = new_node; + (*list) = new_node; +} + +uint64_t getIndex(uint64_t addr, int size) { + uint64_t _addr = addr - MEMORY_BASE_ADDR; + int page_size = (1 << size) << 12; + if (_addr % page_size != 0) + uart_printf("[ERROR][getIndex] getIndex: illegal address: %x\n", _addr); + return _addr / PAGE_SIZE_4K; +} + +frame_free_node *get_free_node() { + frame_free_node *node = node_pool_head; + if (!node) + uart_printf("[ERROR][get_free_node] get_free_node: no more nodes!\n"); + node_pool_head = node_pool_head->next; + return node; +} + +void return_free_node(frame_free_node *node) { + if (!node) + uart_printf("[ERROR][return_free_node] null node!\n"); + node->next = node_pool_head; + node_pool_head = node; +} + +uint64_t get_allocated_num() { + uint64_t cnt = 0; + for (uint64_t i = 0; i < FRAME_ARRAY_SIZE; ++i) { + if (frame_array[i] == 0xAA) + ++cnt; + } + return cnt; +} + +uint64_t get_free_num() { + return (MEMORY_END_ADDR - MEMORY_BASE_ADDR) / 4096 - get_allocated_num(); +} + +/* clear first 64 bytes */ +void clear_4K_page(uint64_t index) { + uint64_t *addr = (uint64_t*)GET_PAGE_ADDR(index); + addr[0] = 0; +} + + +void print_frame_array() { + uart_printf("frame_array: "); + for (uint64_t i = 0; i < 8; ++i) { + uart_printf("(%ld, %x) ", i, frame_array[i]); + } + uart_printf("\n"); +} + +void print_frame_free_lists() { + uart_printf("frame_free_lists: "); + for (int i = 0; i < 4; ++i) { + if (frame_free_lists[i]) + uart_printf("(%d, %ld) ", i, frame_free_lists[i]->index); + else + uart_printf("(%d, NULL) ", i); + } + uart_printf("\n"); +} \ 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..9f4503ef4 --- /dev/null +++ b/Lab7/lib/mini_uart.c @@ -0,0 +1,196 @@ +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" +#include "utils.h" +#include "mini_uart.h" +#include "printf.h" +#include + + +// The AUX_MU_LSR_REG register (8 bits) shows the data status. +// The AUX_MU_IO_REG register (8 bits) is primary used to write data to and read data from the UART FIFOs. +void uart_send ( char c ) { + if (c == '\n') + uart_send('\r'); + while(!(*AUX_MU_LSR_REG & 0x20)) {} // Bit 5, if set to 1, tells us that the transmitter is empty. + *AUX_MU_IO_REG = c; +} + +char uart_recv ( void ) { + while(!(*AUX_MU_LSR_REG & 0x01)) {} // Bit 0, if set to 1, indicates that the data is ready. + char recv = *AUX_MU_IO_REG & 0xFF; + return recv != '\r' ? recv : '\n'; +} + +void uart_recv_string(char *buffer) { + int size = 0; + while(size < MAX_BUFFER_SIZE){ + buffer[size] = uart_recv(); + uart_send(buffer[size]); + if(buffer[size++] == '\n'){ + break; + } + } + buffer[--size] = '\0'; +} + +void uart_send_string(char* str) { + for (int i = 0; str[i] != '\0'; i ++) { + uart_send((char)str[i]); + } +} + +unsigned int uart_printf(char* fmt,...) { + char dst[100]; + //__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); + unsigned int ret=vsprintf(dst,fmt,args); + uart_send_string(dst); + return ret; +} + +void uart_hex(unsigned int d) { + unsigned int n; + int c; + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_send(n); + } +} + +unsigned char uart_getb(){ //for data transfer + unsigned char r; + do{ asm volatile("nop"); } while (!(*AUX_MU_LSR_REG & 0x01)); + r = (unsigned char)(*AUX_MU_IO_REG); + return r; +} + +void delay(unsigned int clock) { + while (clock--) { + asm volatile("nop"); + } +} + +// An alternative function is a number from 0 to 5 that can be set for each pin and configures which device is connected to the pin. +// GPFSEL1 register is used to control alternative functions for pins 10-19. +// pin 14 -> TXD1: set bits 14-12 to 5 +// pin 15 -> RXD1: set bits 17-15 to 5 +void uart_init ( void ) { + // connect Mini UART to the GPIO pins + unsigned int selector; + selector = *GPFSEL1; + selector &= ~(7u << 12); // Clean gpio14 + selector |= 2u << 12; // Set alt5 for gpio14 + selector &= ~(7u << 15); // Clean gpio15 + selector |= 2u << 15; // Set alt5 for gpio15 + *GPFSEL1 = selector; + + // Remove both the pull-up and pull-down states from a pin + *GPPUD = 0; + delay(150u); + *GPPUDCLK0 = (1u << 14) | (1u << 15); + delay(150u); + *GPPUDCLK0 = 0; + + // Initializing the Mini UART + *AUX_ENABLES = 1u; // Enable mini uart (this also enables access to its registers) + *AUX_MU_CNTL_REG = 0u; // Disable auto flow control and disable receiver and transmitter (for now) + *AUX_MU_IER_REG = 1u; // Disable receive and transmit interrupts + *AUX_MU_LCR_REG = 3u; // Enable 8 bit mode + *AUX_MU_MCR_REG = 0u; // Set RTS line to be always high + *AUX_MU_BAUD_REG = 270u; // Set baud rate to 115200 + *AUX_MU_CNTL_REG = 3u; // Finally, enable transmitter and receiver + + *AUX_MU_IIR_REG = 6u; + + read_buf_start = read_buf_end = 0; + write_buf_start = write_buf_end = 0; +} + + + +/* async mini uart */ +char read_buf[MAX_BUFFER_SIZE]; +char write_buf[MAX_BUFFER_SIZE]; +int read_buf_start, read_buf_end; +int write_buf_start, write_buf_end; + +void enable_uart_interrupt() { *ENB_IRQS1 = AUX_IRQ; } +void disable_uart_interrupt() { *DISABLE_IRQS1 = AUX_IRQ; } +void set_transmit_interrupt() { *AUX_MU_IER_REG |= 0x2; } +void clear_transmit_interrupt() { *AUX_MU_IER_REG &= ~(0x2); } + +void uart_handler() { + disable_uart_interrupt(); + int RX = (*AUX_MU_IIR_REG & 0x4); + int TX = (*AUX_MU_IIR_REG & 0x2); + if (RX) { + char c = (char)(*AUX_MU_IO_REG); + read_buf[read_buf_end++] = c; + if (read_buf_end == MAX_BUFFER_SIZE) + read_buf_end = 0; + } + else if (TX) { + while (*AUX_MU_LSR_REG & 0x20) { + if (write_buf_start == write_buf_end) { + clear_transmit_interrupt(); + break; + } + char c = write_buf[write_buf_start++]; + *AUX_MU_IO_REG = c; + if (write_buf_start == MAX_BUFFER_SIZE) + write_buf_start = 0; + } + } + else { + uart_send_string("[Error] uart_handler: should not reach here!\n"); + while (1) { } + } + enable_uart_interrupt(); +} + +char uart_async_recv() { + // wait until there are new data + while (read_buf_start == read_buf_end) + asm volatile("nop"); + char c = read_buf[read_buf_start++]; + if (read_buf_start == MAX_BUFFER_SIZE) + read_buf_start = 0; + return c == '\r' ? '\n' : c; +} + +void uart_async_send_string(char *str) { + + for (int i = 0; str[i]; i++) { + if (str[i] == '\n') { + write_buf[write_buf_end++] = '\r'; + write_buf[write_buf_end++] = '\n'; + continue; + } + write_buf[write_buf_end++] = str[i]; + if (write_buf_end == MAX_BUFFER_SIZE) + write_buf_end = 0; + } + set_transmit_interrupt(); +} + +void test_uart_async() { + uart_send_string("[Please type something]\n"); + enable_uart_interrupt(); + delay(15000); + char buffer[MAX_BUFFER_SIZE]; + size_t index = 0; + while (1) { + buffer[index] = uart_async_recv(); + if (buffer[index] == '\n') + break; + index++; + } + buffer[index + 1] = '\0'; + uart_async_send_string(buffer); + disable_uart_interrupt(); +} diff --git a/Lab7/lib/mm.S b/Lab7/lib/mm.S new file mode 100644 index 000000000..2e2d88c28 --- /dev/null +++ b/Lab7/lib/mm.S @@ -0,0 +1,6 @@ +.globl memzero +memzero: + str xzr, [x0], #8 // Post-index: store 0 to the unmodified address in x0 first, then update x0 (to x0 + #8) + subs x1, x1, #8 + b.gt memzero + ret \ No newline at end of file diff --git a/Lab7/lib/printf.c b/Lab7/lib/printf.c new file mode 100644 index 000000000..f54f6736f --- /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 "../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..bceb3922f --- /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 reboot(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_reboot() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/Lab7/lib/shell.c b/Lab7/lib/shell.c new file mode 100644 index 000000000..c1b52f9a9 --- /dev/null +++ b/Lab7/lib/shell.c @@ -0,0 +1,204 @@ +#include "mini_uart.h" +#include "shell.h" +#include "utils.h" +#include "reboot.h" +#include "peripherals/mail_box.h" +#include "mail_box.h" +#include "cpio.h" +#include "timer.h" +#include "memory.h" +#include "allocator.h" +#include "printf.h" +#include "task.h" +#include "exception.h" +#include "vfs.h" + + +int debug_mode = 0; +char buffer[MAX_BUFFER_SIZE]; + +void get_command(); +void parse_command(); + +void get_board_revision(); + +void shell(void) { + while (1) { + uart_send_string("> "); + get_command(); + parse_command(); + } +} + +void get_command() { + unsigned int index = 0; + char recv; + while (1) { + recv = uart_recv(); + if (recv == '\r') + continue; + uart_send(recv); + buffer[index++] = recv; + index = index < MAX_BUFFER_SIZE ? index : MAX_BUFFER_SIZE - 1; + if (recv == '\n') { + buffer[index - 1] = '\0'; + break; + } + } +} + +unsigned int debug_printf(char* fmt,...) { + if (debug_mode) { + char dst[100]; + __builtin_va_list args; + __builtin_va_start(args,fmt); + unsigned int ret=vsprintf(dst,fmt,args); + uart_send_string(dst); + return ret; + } + return 0; +} + +void parse_command() { + if (compare_string(buffer, "\0") == 0) {} + else if (compare_string(buffer, "hello") == 0) + uart_send_string("Hello World!\n"); + else if (compare_string(buffer, "reboot") == 0) { + uart_send_string("rebooting ...\n"); + reboot(100); + while (1) {} + } + else if (compare_string(buffer, "info") == 0) { + get_board_revision(); + get_arm_memory(); + get_serial_number(); + } + else if (compare_string(buffer, "ls") == 0) { + cpio_list(); + } + else if (compare_string(buffer, "cat") == 0) { + uart_send_string("Filename: \n"); + get_command(); + cpio_cat(buffer); + } + else if (compare_string(buffer, "async_uart") == 0) { + test_uart_async(); + } + else if (compare_string(buffer, "test_timer_lab3") == 0) { + test_timer(); + } + else if (compare_string(buffer, "test_page") == 0) { + debug_mode = 1; + const int test_size = 3; + const uint64_t test_address[] = {0x2001, 0x3010, 0x6100}; // covered index 2(4K), 3(4K), 6(8K) + const int page_size[] = {0, 0, 1}; + const uint64_t mask[] = {0xFFF, 0xFFF, 0x1FFF}; + for (int i = 0; i < test_size; ++i) { + reserve_page(page_size[i], test_address[i]); + print_frame_array(); + uart_printf("\n"); + } + for (int i = 0; i < test_size; ++i) { + page_free(test_address[i] & ~mask[i], page_size[i]); + print_frame_array(); + uart_printf("\n"); + } + debug_mode = 0; + } + else if (compare_string(buffer, "test_dyn") == 0) { + debug_mode = 1; + const int test_size = 10; + const int test_cases[] = {31, 2, 32, 63, 120, 256, 129, 155, 240, 250}; + void *addrs[test_size]; + for (int i = 0; i < test_size; ++i) { + addrs[i] = kmalloc(test_cases[i]); + print_slot_record(find_page(addrs[i])); + uart_printf("\n"); + } + for (int i = 0; i < test_size; ++i) { + kfree(addrs[i]); + print_slot_record(find_page(addrs[i])); + uart_printf("\n"); + } + debug_mode = 0; + } + else if (compare_string(buffer, "test_fork") == 0) { + run_user_program("fork_test.img", NULL); + } + else if (compare_string(buffer, "test_exec") == 0) { + run_user_program("exec_test.img", NULL); + } + else if (compare_string(buffer, "test_timer") == 0) { + run_user_program("timer_test.img", NULL); + } + else if (compare_string(buffer, "test_mbox") == 0) { + run_user_program("mbox_test.img", NULL); + } + else if (compare_string(buffer, "test_dummy") == 0) { + run_user_program("dummy_test.img", NULL); + } + else if (compare_string(buffer, "test_vm") == 0) { + run_user_program("vm.img", NULL); + } + else if (compare_string(buffer, "test_fs") == 0) { + run_user_program("initramfs/vfs1.img", NULL); + + // run_user_program("fs_test.img", NULL); + + // file* f; + // /* basic 1 */ + // char buffer1[17] = "This is fs_test!\n"; + // char buffer2[30]; + // vfs_open("/dir1/dummy1.txt", O_CREAT, &f); + // vfs_read(f, buffer2, 30); + // uart_printf("%s", buffer2); + // vfs_close(f); + // vfs_open("/dir1/dummy1.txt", O_CREAT, &f); + // vfs_write(f, buffer1, 17); + // vfs_close(f); + // vfs_open("/dir1/dummy1.txt", O_CREAT, &f); + // vfs_read(f, buffer2, 30); + // buffer2[17] = '\0'; + // uart_printf("%s", buffer2); + // vfs_close(f); + + // char buffer_n[16] = "test new file!\n"; + // vfs_open("/new_file.txt", O_CREAT, &f); + // vfs_write(f, buffer_n, 16); + // vfs_close(f); + // vfs_open("/new_file.txt", O_CREAT, &f); + // vfs_read(f, buffer2, 30); + // buffer2[16] = '\0'; + // uart_printf("%s", buffer2); + // vfs_close(f); + + // /* basic 2 */ + // char buffer_mkdir[13] = "test mkdir!\n"; + // vfs_mkdir("/dir3-1/dir3-2"); + // if (vfs_mount("/dir3-1/dir3-2", "tmpfs") == SUCCESS) + // uart_printf("--- vfs_mount success ---\n"); + // vfs_open("/dir3-1/dir3-2/test.txt", O_CREAT, &f); + // vfs_write(f, buffer_mkdir, 13); + // vfs_close(f); + // vfs_open("/dir3-1/dir3-2/test.txt", O_CREAT, &f); + // vfs_read(f, buffer2, 13); + // buffer2[17] = '\0'; + // vfs_close(f); + // uart_printf("%s\n", buffer2); + } + else if (compare_string(buffer, "help") == 0) { + uart_send_string("help : print this help menu\n"); + uart_send_string("hello : print Hello World!\n"); + uart_send_string("reboot : reboot the device\n"); + uart_send_string("info : print device info\n"); + uart_send_string("ls : print files in rootfs\n"); + uart_send_string("cat : print file content\n"); + uart_send_string("async_uart : test async uart\n"); + uart_send_string("test_timer_lab3 : test timer multiplexing\n"); + uart_send_string("test_page : test buddy system\n"); + uart_send_string("test_dyn : test dynamic allocator\n"); + uart_send_string("test_fork : test user program\n"); + } + else + uart_send_string("\rcommand not found!\r\n"); +} diff --git a/Lab7/lib/switch.S b/Lab7/lib/switch.S new file mode 100644 index 000000000..6033b5501 --- /dev/null +++ b/Lab7/lib/switch.S @@ -0,0 +1,28 @@ +.section ".text" + +.global switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + msr tpidr_el1, x1 + ret + +.global get_current +get_current: + mrs x0, tpidr_el1 + ret \ No newline at end of file diff --git a/Lab7/lib/task.c b/Lab7/lib/task.c new file mode 100644 index 000000000..93cddef2b --- /dev/null +++ b/Lab7/lib/task.c @@ -0,0 +1,175 @@ +#include "task.h" +#include "allocator.h" +#include "switch.h" +#include "shell.h" +#include "utils.h" +#include "mini_uart.h" +#include "sysreg.h" +#include "cpio.h" +#include "timer.h" +#include "vm.h" +#include "vfs.h" + + +task_queue run_queue = {"run", NULL, NULL}; +task_queue wait_queue = {"wait", NULL, NULL}; +task_queue terminated_queue = {"terminated", NULL, NULL}; +int run_queue_sz = 0; +char **_argv = NULL; +static int task_cnt = 0; + +unsigned long user_addr; +unsigned long user_sp; +unsigned long user_page_table; + + +void run_user_program(const char* name, char *const argv[]) { + task_struct *task = thread_create(switch_to_user_space); + load_program((char*)name, task->page_table); + _argv = (char**)argv; + user_addr = USER_PROGRAM_VA; + for (int i = 0; i < 4; ++i) + map_pages(task->page_table, 0xffffffffb000 + i * 0x1000, 1, VA2PA(page_malloc(0))); + user_sp = task->user_fp; + user_page_table = (unsigned long)(task->page_table); + add_timer(read_sysreg(cntfrq_el0) >> 5, normal_timer, NULL); // < 0.1s + core_timer_enable(); + debug_mode = 0; + idle(); +} + +void switch_to_user_space() { + asm volatile("mov x0, 0x340 \n"::); + asm volatile("msr spsr_el1, x0 \n"::); + asm volatile("msr elr_el1, %0 \n"::"r"(user_addr)); + asm volatile("msr sp_el0, %0 \n"::"r"(user_sp)); + debug_printf("[DEBUG][switch_to_user_space]\n"); + asm volatile("eret \n"::); +} + +void create_root_thread() { + task_struct* root_task = thread_create(idle); + write_sysreg(tpidr_el1, root_task); +} + +task_struct* thread_create(void *func) { + task_struct* new_task = (task_struct*)page_malloc(0); + initPT(&(new_task->page_table)); + new_task->context.fp = (unsigned long)new_task + PAGE_SIZE_4K - 16; + new_task->context.lr = (unsigned long)func; + new_task->context.sp = (unsigned long)new_task + PAGE_SIZE_4K - 16; // kernel stack pointer for the thread + new_task->user_fp = 0xfffffffff000 - 16; + new_task->state = RUNNING; + new_task->id = task_cnt++; + new_task->handler = NULL; + new_task->cur_dir = rootfs->root; + for (int i = 0; i < FD_TABLE_SIZE; ++i) + new_task->fd_table[i] = 0; + + debug_printf("[DEBUG][thread_create] id: %d\n", new_task->id); + + push_task_to_queue(&run_queue, new_task); + return new_task; +} + +void thread_schedule() { + task_struct *next_task = run_queue.begin; + if (!next_task->id && !next_task->next) // escapes idle(), but the call stack will grow forever + shell(); + + pop_task_from_queue(&run_queue, next_task); + push_task_to_queue(&run_queue, next_task); + + asm volatile("mov x0, %0 \n"::"r"(next_task->page_table)); + asm volatile("dsb ish \n"); //ensure write has completed + asm volatile("msr ttbr0_el1, x0 \n"); //switch translation based address. + asm volatile("tlbi vmalle1is \n"); //invalidates cached copies of translation table entries from L1 TLBs + asm volatile("dsb ish \n"); //ensure completion of TLB invalidatation + asm volatile("isb \n"); //clear pipeline + + task_struct *cur = get_current(); + debug_printf("[DEBUG][thread_schedule] switch from thread %d to %d\n", cur->id, next_task->id); + + asm volatile("\ + mov x0, %0\n\ + mov x1, %1\n\ + bl switch_to\n\ + "::"r"(cur), "r"(next_task)); +} + +void idle() { + while(1) { + kill_zombies(); + thread_schedule(); + } +} + +void kill_zombies() { + +} + +void push_task_to_queue(task_queue *queue, task_struct *task) { + if (queue->begin) { + queue->end->next = task; + task->prev = queue->end; + task->next = NULL; + queue->end = task; + } + else { + queue->begin = queue->end = task; + task->prev = task->next = NULL; + } + run_queue_sz += 1; + debug_printf("[DEBUG][push_task_to_queue] push thread %d into %s queue\n", task->id, queue->name); +} + +void pop_task_from_queue(task_queue *queue, task_struct *task) { + task_struct *prev = task->prev; + task_struct *next = task->next; + if (prev && next) { + prev->next = next; + next->prev = prev; + } + else if (!prev && next) { + next->prev = NULL; + queue->begin = next; + } + else if (prev && !next) { + prev->next = NULL; + queue->end = prev; + } + else + queue->begin = queue->end = NULL; + run_queue_sz -= 1; + debug_printf("[DEBUG][pop_task_from_queue] pop thread %d from %s queue\n", task->id, queue->name); +} + +void dump_queue(task_queue *queue) { + task_struct *task = queue->begin; + uart_printf("%s queue: ", queue->name); + while (task) { + uart_printf("%d ", task->id, task); + task = task->next; + } + uart_printf("\n"); +} + +/* Helper functions */ +void put_args(char *const argv[]) { + if (!argv) + return; + + char **iter = (char**) argv; + for (int i = 0; iter[i]; ++i) + asm volatile("mov %0, %1 \n"::"r"(i), "r"(iter[i])); +} + +task_struct *find_task_by_id(task_queue *queue, int pid) { + task_struct *task = queue->begin; + while (task) { + if (task->id == pid) + break; + task = task->next; + } + return task; +} \ No newline at end of file diff --git a/Lab7/lib/timer.c b/Lab7/lib/timer.c new file mode 100644 index 000000000..119188355 --- /dev/null +++ b/Lab7/lib/timer.c @@ -0,0 +1,109 @@ +#include "timer.h" +#include "mini_uart.h" +#include "sysreg.h" +#include "allocator.h" +#include "exception.h" +#include "shell.h" + + +static struct Timer *timer_list = NULL; + + +void init_timer() { + uint64_t tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); +} + +void core_timer_enable() { + write_sysreg(cntp_ctl_el0, 1); // enable + *CORE0_TIMER_IRQ_CTRL = 2; // unmask timer interrupt +} + +void core_timer_disable() { + write_sysreg(cntp_ctl_el0, 0); // disable + *CORE0_TIMER_IRQ_CTRL = 0; // mask timer interrupt +} + +void add_timer(unsigned int time, timer_call_back call_back, void *args) { + struct Timer *timer = (struct Timer*)kmalloc(sizeof(struct Timer)); + timer->expire_time = read_sysreg(cntpct_el0) + time; + timer->call_back = call_back; + timer->args = args; + timer->next = NULL; + int need_update = 0; + //core_timer_disable(); + if (!timer_list) { + timer_list = timer; + need_update = 1; + } + else if (timer_list->expire_time > timer->expire_time) { + timer->next = timer_list; + timer_list = timer; + need_update = 1; + } + else { + struct Timer *pre = timer_list, *next = timer_list->next; + while (next && pre->expire_time < timer->expire_time) { + pre = next; + next = next->next; + } + pre->next = timer; + timer->next = next; + } + if (need_update) + write_sysreg(cntp_tval_el0, time); + //core_timer_enable(); +} + +void pop_timer() { + //core_timer_disable(); + struct Timer *timer = timer_list; + timer_list = timer_list->next; + //core_timer_enable(); + timer->call_back(timer->args); + kfree((void*)timer); + if (!timer_list) + core_timer_disable(); + else + write_sysreg(cntp_tval_el0, timer_list->expire_time - read_sysreg(cntpct_el0)); +} + +void test_timer() { + char* msg1 = (char *)kmalloc(20); + char* msg2 = (char *)kmalloc(20); + char* msg3 = (char *)kmalloc(20); + msg1 = "\nThis is timer 1!\n"; + msg2 = "This is timer 2!\n"; + msg3 = "This is timer 3!\n"; + add_timer(3 * read_sysreg(cntfrq_el0), print_timer, msg3); + add_timer(2 * read_sysreg(cntfrq_el0), print_timer, msg2); + add_timer(1 * read_sysreg(cntfrq_el0), print_timer, msg1); + core_timer_enable(); +} + +/* callbacks */ +void show_time_elapsed(void *args) { + unsigned long cntpct = read_sysreg(cntpct_el0); + unsigned long cntfrq = read_sysreg(cntfrq_el0); + unsigned long tmp = cntpct * 10 / cntfrq; + uart_printf("--------------------\n"); + uart_printf("Time Elapsed: %d.%ds\n", tmp/10, tmp%10); + uart_printf("--------------------\n"); + add_timer(cntfrq << 1, show_time_elapsed, NULL); +} + +void print_timer(void *args) { + char *msg = (char *)args; + uart_send_string(msg); +} + +void normal_timer() { + unsigned long cntpct = read_sysreg(cntpct_el0); + unsigned long cntfrq = read_sysreg(cntfrq_el0); + unsigned long tmp = cntpct * 10 / cntfrq; + debug_printf("[DEBUG][normal_timer] time elapsed: %d.%ds\n", tmp/10, tmp%10); + add_timer(cntfrq >> 5, normal_timer, NULL); + thread_schedule(); +} \ No newline at end of file diff --git a/Lab7/lib/tmpfs.c b/Lab7/lib/tmpfs.c new file mode 100644 index 000000000..b69144180 --- /dev/null +++ b/Lab7/lib/tmpfs.c @@ -0,0 +1,268 @@ +#include "tmpfs.h" +#include "allocator.h" +#include "mini_uart.h" +#include "cpio.h" +#include "utils.h" + + +struct mount* rootfs = 0; + +int tmpfs_nodeInit(vnode* root) { + void* f = fbase_get(); + unsigned long size; + while (1) { //build tree + const char* fname = fname_get(f, &size); + char* fdata = fdata_get(f, &size); + int fmode = fmode_get(f); + if (compare_string(fname, "TRAILER!!!") == 0) + break; + + vnode* dir_node = root; //insert file from root + Content* content = (Content*)(dir_node->internal); + vnode** target = (vnode**)(content->data); + while (1) { //iterative search for a path name + char prefix[PREFIX_LEN]; + fname = slashIgnore(fname, prefix, PREFIX_LEN); + int idx = tmpfs_lookup(dir_node, 0, prefix); + if (idx >= 0) { // next level + dir_node = target[idx]; + content = (Content*)(dir_node->internal); + target = (vnode**)(content->data); + } else { //final level + if (fname != 0) { + uart_printf("tmpfs_nodeInit error!!\n"); + uart_printf("%s\n%s\n", prefix, fname); + while(1) {} + } + idx = tmpfs_creat(dir_node, 0, prefix); + vnode* new_node = target[idx]; + new_node->parent = dir_node; + new_node->mnt = dir_node->mnt; + content = (Content*)(new_node->internal); + if (fmode == 1) { + content->type = DIR_TYPE; + content->capacity = DIR_CAP; + content->size = 0; + content->data = (void*)kmalloc(DIR_CAP * 8); + } else if (fmode == 2) { + content->type = FILE_TYPE; + content->capacity = size; + content->size = size; + content->data = fdata; + content->cache = 0; + } else { + uart_printf("unknown file type!!\n"); + while (1) {} + } + content = (Content*)(root->internal); + target = (vnode**)(content->data); + break; + } + } + f = next_fget(f); + } + return 0; +} + +int tmpfs_setup(filesystem* fs, mount* mnt) { + vnode* root = mnt->root; + root->v_ops = (vnode_operations*)kmalloc(sizeof(vnode_operations)); + root->v_ops->lookup = tmpfs_lookup; + root->v_ops->create = tmpfs_creat; + root->v_ops->mkdir = tmpfs_mkdir; + root->f_ops=(file_operations*)kmalloc(sizeof(file_operations)); + root->f_ops->write = tmpfs_write; + root->f_ops->read = tmpfs_read; + root->f_ops->open = tmpfs_open; + root->f_ops->close = tmpfs_close; + char* name = 0; + if (root->internal) + name = ((Content*)(root->internal))->name; + root->internal = (void*)kmalloc(sizeof(Content)); + + Content* content = (Content*)(root->internal); + content->name = name; + content->type = DIR_TYPE; + content->capacity = DIR_CAP; + content->size = 0; + content->data = (void*)kmalloc(DIR_CAP * 8); + + return 0; +} + +void cache_init(Content* content) { + if (content->cache) + uart_printf("[ERROR][cache_init] cache already exist!\n"); + content->cache = (void*)page_malloc(0); + char* src = (char*)(content->data); + char* dst = (char*)(content->cache); + for (int i = 0; i < content->size; ++i) + dst[i] = src[i]; +} + +void tmpfs_dump(vnode* cur, int level){ + Content* content = (Content*)(cur->internal); + for (int i = 0; i < level; ++i) + uart_printf("\t"); + if (content->type == DIR_TYPE) { + uart_printf("%s\n", content->name); + vnode** childs = (vnode**)(content->data); + for (int i=0; i < content->size; ++i) + tmpfs_dump(childs[i], level + 1); + } else if (content->type == FILE_TYPE) + uart_printf("%s (%d bytes)\n", content->name, content->size); +} + +/* vops */ +int tmpfs_lookup(vnode* dir_node, vnode** target, const char* component_name) { + Content* content = (Content*)(dir_node->internal); + if (content->type != DIR_TYPE){ + uart_printf("[ERROR][tmpfs_lookup] %s should be a directory!\n", content->name); + while (1) {} + } + vnode** childs = (vnode**)(content->data); + + for (int i = 0; i < content->size; ++i) { + vnode* child = childs[i]; + Content* child_content = (Content*)(child->internal); + if (compare_string(child_content->name, component_name) == 0) { + if (target) + *target = child; + return i; + } + } + return -1; +} + +int tmpfs_creat(vnode* dir_node, vnode** target, const char* component_name) { + Content* content = (Content*)(dir_node->internal); + if (content->type != DIR_TYPE) { + uart_printf("[ERROR][tmpfs_creat] Parent should be a directory!\n"); + while (1) {} + } + vnode** childs = (vnode**)content->data; + + int idx =- 1; + if (content->capacity > content->size) + idx = content->size++; + else { + uart_printf("[ERROR][tmpfs_creat] Not enough space!\n"); + while (1) {} + } + + vnode* new_node = (vnode*)kmalloc(sizeof(vnode)); + new_node->mnt = dir_node->mnt; + new_node->v_ops = dir_node->v_ops; + new_node->f_ops = dir_node->f_ops; + new_node->internal = (Content*)kmalloc(sizeof(Content)); + + content = (Content*)new_node->internal; + content->name = (char*)kmalloc(PREFIX_LEN); + slashIgnore(component_name, content->name, PREFIX_LEN); + content->type = FILE_TYPE; + content->capacity = 0; + content->size = 0; + content->data = 0; + content->cache = 0; + new_node->parent = dir_node; + childs[idx] = new_node; + if (target) + *target = new_node; + return idx; +} + +int tmpfs_mkdir(vnode* dir_node, vnode** target, const char* component_name) { + Content* content = (Content*)(dir_node->internal); + if (content->type != DIR_TYPE) { + uart_printf("[ERROR][tmpfs_mkdir] Parent should be a directory!\n"); + while (1) {} + } + vnode** childs = (vnode**)content->data; + + int idx = -1; + if (content->capacity > content->size) + idx = content->size++; + else { + uart_printf("[ERROR][tmpfs_mkdir] Not enough space!\n"); + while (1) {} + } + + vnode* new_node = (vnode*)kmalloc(sizeof(vnode)); + new_node->mnt = dir_node->mnt; + new_node->v_ops = dir_node->v_ops; + new_node->f_ops = dir_node->f_ops; + new_node->internal = (Content*)kmalloc(sizeof(Content)); + + content = (Content*)new_node->internal; + content->name = (char*)kmalloc(PREFIX_LEN); + slashIgnore(component_name, content->name, PREFIX_LEN); + content->type = DIR_TYPE; + content->capacity = DIR_CAP; + content->size = 0; + content->data = (void*)kmalloc(DIR_CAP * 8); + childs[idx] = new_node; + if (target) + *target = new_node; + return idx; +} + +/* fops */ +int tmpfs_read(file* f, void* buf, size_t len) { + vnode* node = f->node; + Content* content = (Content*)(node->internal); + int size = content->size; + if (content->type == FILE_TYPE) { + if (!content->cache) + cache_init(content); + char* cache = (char*)(content->cache); + char* buffer = (char*)buf; + int ret = 0; + for (int i = f->f_pos; i < size; ++i) { + if (ret < len) + buffer[ret++] = cache[i]; + else + break; + } + f->f_pos += ret; + return ret; + } else if (content->type == DIR_TYPE) { + uart_printf("[ERROR][tmpfs_read] This is a directory!\n"); + return 0; + } else + return 0; +} + +int tmpfs_write(file* f, const void* buf, size_t len) { + vnode* node = f->node; + Content* content = (Content*)(node->internal); + if (content->type == FILE_TYPE) { + if (!content->cache) + cache_init(content); + char* cache = (char*)(content->cache); + if (f->f_pos + len > 4096) + uart_printf("[ERROR][tmpfs_write] Exceed max size of a file!\n"); + const char* buffer = (const char*)buf; + for (int i = 0; i < len; ++i) { + cache[f->f_pos] = buffer[i]; + f->f_pos += 1; + } + if (content->size < f->f_pos) + content->size = f->f_pos; + return len; + } else { + uart_printf("[ERROR][tmpfs_write] This is a directory!\n"); + return 0; + } +} + +int tmpfs_open(vnode* file_node, file** target) { + return SUCCESS; +} + +int tmpfs_close(file* file) { + if (!file) { + uart_printf("[ERROR][tmpfs_close] Already freed!\n"); + return FAIL; + } + return SUCCESS; +} diff --git a/Lab7/lib/utils.c b/Lab7/lib/utils.c new file mode 100644 index 000000000..7b180a3e9 --- /dev/null +++ b/Lab7/lib/utils.c @@ -0,0 +1,125 @@ +#include "utils.h" +#include "mini_uart.h" + +int compare_string(const char *s1, const char *s2) { + 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; +} + +void uintoa(char *out, unsigned int i) +{ + unsigned int index = 0; + char tmp[20]; + do { + unsigned char m = i % 16; + i >>= 4; + + char c = m + '0'; + if (m == 10) + c = 'A'; + else if (m == 11) + c = 'B'; + else if (m == 12) + c = 'C'; + else if (m == 13) + c = 'D'; + else if (m == 14) + c = 'E'; + else if (m == 15) + c = 'F'; + + tmp[index++] = c; + + } while (i); + + index--; + for (unsigned int i = 0; i <= index; ++i) + out[i] = tmp[index - i]; + out[index + 1] = '\0'; +} + +unsigned int getIntegerFromString(const char *str) { + unsigned int value = 0u; + + while (*str) { + if(*str >= '0' && *str<= '9'){ + value = value * 10u + (*str - '0'); + } + ++str; + } + return value; +} + +unsigned long getHexFromString(const char *str) { + unsigned long value = 0u; + + while (*str) { + if(*str >= '0' && *str <= '9'){ + value = value*16 + *str - '0'; + }else if(*str >= 'a' && *str <= 'z'){ + value = value*16 + *str - 'a' + 10u; + }else if(*str >= 'A' && *str <= 'Z'){ + value = value*16 + *str - 'A' + 10u; + } + ++str; + } + return value; +} + +unsigned long getHexFromString8(const char *str) { + unsigned long ret = 0; + for (int i = 0; i < 8; ++i) { + if (str[i] >= '0' && str[i] <= '9') + ret = ret * 16 + str[i] - '0'; + else if (str[i] >= 'a' && str[i] <= 'f') + ret = ret * 16 + str[i] - 'a' + 10; + else if (str[i] >= 'A' && str[i] <= 'F') + ret = ret * 16 + str[i] - 'A' + 10; + } + return ret; +} + +// convert hexadecimal string into decimal +unsigned long hexToDec(char *s) { + unsigned long r = 0; + for(int i = 0; i < 8; ++i) { + if(s[i] >= '0' && s[i] <= '9') + r = r * 16 + s[i] -'0'; + else + r = r * 16 + s[i] - 'A' + 10; + } + return r; +} + +/* align to multiple of 4 */ +void align_4(void* size) { + unsigned long* x =(unsigned long*) size; + if((*x)&3){ + (*x) += 4-((*x)&3); + } +} + +/* extract the substring starts from the beginning of the src + and ends with the first '/' and put it into dst */ +const char* slashIgnore(const char* src, char* dst, int size) { + for (int i = 0; i < size; ++i) { + if (src[i] == 0) { + dst[i] = 0; + return 0; + } else if (src[i] == '/') { + dst[i] = 0; + return src + i + 1; + } else + dst[i] = src[i]; + } + return 0; +} \ No newline at end of file diff --git a/Lab7/lib/vfs.c b/Lab7/lib/vfs.c new file mode 100644 index 000000000..976e27d4b --- /dev/null +++ b/Lab7/lib/vfs.c @@ -0,0 +1,190 @@ +#include "vfs.h" +#include "tmpfs.h" +#include "utils.h" +#include "mini_uart.h" +#include "allocator.h" + +char buffer[16]; +struct mount* initramfs = 0; + +int register_filesystem(filesystem* fs, const char* fs_name) { + if (compare_string(fs_name, "tmpfs") == 0) { + char* name = (char*)kmalloc(PREFIX_LEN); + for (int i = 0; i < 6; ++i) + name[i] = fs_name[i]; + fs->name = name; + fs->setup_mount = tmpfs_setup; + } + else { + uart_printf("[ERROR][register_filesystem] fs not supported!\n"); + while(1) {} + } + return 0; +} + +int vfs_open(const char* pathname, int flags, file** target, vnode* root) { + *target = kmalloc(sizeof(file)); + vnode* dir = root; + vnode* file_node; + char prefix[PREFIX_LEN]; + pathname = slashIgnore(pathname, prefix, PREFIX_LEN); // rip off the leading '/' + pathname = slashIgnore(pathname, prefix, PREFIX_LEN); + while (1) { + int idx = dir->v_ops->lookup(dir, &file_node, prefix); + if (!pathname) { // file + if (idx == -1) { + if (!(flags & O_CREAT)) + return FAIL; + dir->v_ops->create(dir, &file_node, prefix); + } + break; + } + else { // dir + if (idx == -1) + dir->v_ops->mkdir(dir, &file_node, prefix); + } + dir = file_node; + pathname = slashIgnore(pathname, prefix, PREFIX_LEN); + } + (*target)->node = file_node; + (*target)->f_pos = 0; + (*target)->flags = flags; + (*target)->f_ops = dir->f_ops; + return (*target)->f_ops->open(file_node, target); +} + +int vfs_close(file* f) { + if (!f) { + uart_printf("[ERROR][tmpfs_close] Null pointer!\n"); + return f->f_ops->close(f); + } + kfree(f); + return SUCCESS; +} + +int vfs_read(file* f, void* buf, size_t len) { + return f->f_ops->read(f, buf, len); +} + +int vfs_write(file* f, const void* buf, size_t len) { + if (isReadOnly(f->node)) { + return 0; + } + return f->f_ops->write(f, buf, len); +} + +int vfs_create(vnode* dir_node, vnode** target, const char* component_name) { + if (isReadOnly(dir_node)) + return FAIL; + (*target)->parent = dir_node; + return dir_node->v_ops->create(dir_node, target, component_name); +} + +int vfs_mkdir(const char* pathname, vnode* root) { + if (isReadOnly(root)) + return FAIL; + vnode* dir = root; + vnode* target; + int flag = 0; + char prefix[PREFIX_LEN]; + pathname = slashIgnore(pathname, prefix, PREFIX_LEN); // rip off the leading '/' + pathname = slashIgnore(pathname, prefix, PREFIX_LEN); + while (1) { + int idx = dir->v_ops->lookup(dir, &target, prefix); + if (idx == -1) { // dir not exists + flag = 1; + dir->v_ops->mkdir(dir, &target, prefix); + target->parent = dir; + } + dir = target; + pathname = slashIgnore(pathname, prefix, PREFIX_LEN); + if (compare_string(pathname, prefix) == 0) + break; + } + if (!flag) { + uart_printf("[ERROR][vfs_mkdir] Dir already exists!\n"); + return FAIL; + } + return SUCCESS; +} + +int vfs_mount(const char* target, const char* file_system, vnode* root) { + if (compare_string(file_system, "tmpfs") == 0) { + vnode* node; + int ret = vfs_lookup(target, &node, root); + if (ret != SUCCESS) + return ret; + mount* mnt = kmalloc(sizeof(mount)); + mnt->root = node; + node->mnt = mnt; + mnt->fs = kmalloc(sizeof(filesystem)); + register_filesystem(mnt->fs, "tmpfs"); + mnt->fs->setup_mount(mnt->fs, mnt); + } + else { + uart_printf("[ERROR][vfs_mount] Unsupported filesystem!\n"); + return FAIL; + } + return SUCCESS; +} + +int vfs_lookup(const char* pathname, vnode** target, vnode* root) { + vnode* dir = root; + char prefix[PREFIX_LEN]; + pathname = slashIgnore(pathname, prefix, PREFIX_LEN); + while (1) { + pathname = slashIgnore(pathname, prefix, PREFIX_LEN); + int idx = dir->v_ops->lookup(dir, target, prefix); + if (pathname) { + if (idx >= 0) + dir = *target; + else { + uart_printf("[ERROR][vfs_lookup] Something went wrong!\n"); + return FAIL; + } + } else { + if (idx >= 0) + return SUCCESS; // already exist + else { + for (int i = 0; i < PREFIX_LEN; ++i) + buffer[i] = prefix[i]; + return FILE_NOT_EXIST; + } + } + } + uart_printf("[ERROR][vfs_lookup] Should not reach here!\n"); + return FAIL; +} + +vnode* find_root(const char* pathname, vnode* cur_dir, char** new_pathname) { + int idx_src = 0; + vnode* ret; + if (pathname[0] == '/') { + ret = rootfs->root; + idx_src = 1; + } + else if (pathname[0] == '.') { + if (pathname[1] == '.') { + ret = cur_dir->parent; + idx_src = 3; + } + else { + ret = cur_dir; + idx_src = 2; + } + } + + *new_pathname = kmalloc(PREFIX_LEN); + (*new_pathname)[0] = '/'; + int idx_dst = 1; + while (idx_src < PREFIX_LEN && idx_dst < PREFIX_LEN) + (*new_pathname)[idx_dst++] = pathname[idx_src++]; + + return ret; +} + +int isReadOnly(vnode* node) { + if (node->mnt == initramfs) + return 1; + return 0; +} \ No newline at end of file diff --git a/Lab7/lib/vm.c b/Lab7/lib/vm.c new file mode 100644 index 000000000..08a65b8fc --- /dev/null +++ b/Lab7/lib/vm.c @@ -0,0 +1,159 @@ +#include "vm.h" +#include "memory.h" +#include "mini_uart.h" + + +/* map va for pa */ +void map_pages(void* page_table, uint64_t va, int page_num, uint64_t pa) { + if (!page_table) + uart_printf("[ERROR][map_pages] null page table!\n"); + + for (int n = 0; n < page_num; ++n) { + unsigned long _va = (unsigned long)(va + n * 4096); + int index[4]; //index of each table + _va >>= 12; + index[3] = _va & 0x1ff; + _va >>= 9; + index[2] = _va & 0x1ff; + _va >>= 9; + index[1] = _va & 0x1ff; + _va >>= 9; + index[0] = _va & 0x1ff; + unsigned long* table = (unsigned long*)PA2VA(page_table); + for (int i = 0; i <= 2; ++i) { + if (!table[index[i]]) { + initPT((void**)&table[index[i]]); + table[index[i]] |= PD_TABLE; + } + unsigned long entry = table[index[i]]; + entry = entry - (entry & 0xfff); + table = (unsigned long*)PA2VA(entry); //address of the first entry of next level table + } + if (table[index[3]]) + uart_printf("[ERROR][map_pages] the VA: %x has already been mapped!\n", va); + //MAIR_IDX_NORMAL_NOCACHE << 2: index to MAIR (8 * 8bytes register) + table[index[3]] = (pa + n * 4096) | (1<<10) | (1<<6) | MAIR_IDX_NORMAL_NOCACHE << 2 | PD_TABLE; + } +} + +void dupPT(void* page_table_src, void* page_table_dst, int level) { + if (page_table_src == 0 || page_table_dst == 0) + uart_printf("[ERROR][dupPT] invalid table!"); + + //frame + if (level == 4) { + char* src = (char*)PA2VA(page_table_src); + char* dst = (char*)PA2VA(page_table_dst); + for (int i = 0; i < 4096; ++i) + dst[i] = src[i]; + return; + } + + //table + unsigned long* table_src = (unsigned long*)PA2VA(page_table_src); + unsigned long* table_dst = (unsigned long*)PA2VA(page_table_dst); + for (int i = 0; i < 512; ++i) { + if (table_src[i] != 0) { + // if () { + + // } + initPT((void**)&table_dst[i]); + dupPT((void*)(table_src[i] & 0xfffffffff000), (void*)(table_dst[i]), level + 1); + unsigned long tmp = table_src[i] & 0xfff; + table_dst[i] |= tmp; + } + } +} + +void initPT(void** page_table) { + char* table = (char*)page_malloc(0); + for (int i = 0; i < 4096; ++i) + table[i] = 0; + *page_table = (void*)VA2PA(table); +} + +void freePT(void** page_table) {} + +void mmu_init() { + //setup tcr & mair + asm volatile("msr tcr_el1, %0\n"::"r"(TCR_CONFIG_DEFAULT)); + /* + 1000 0000 0001 0000 0000 0000 0001 0000 + [5:0] the number of the most significant bits that must be all 0s + [21:16] the number of the most significant bits that must be all 1s + [15:14] granule size for user space (00=4KB, 01=16KB, 11=64KB) + [31:30] granule size for kernel space + */ + asm volatile("msr mair_el1, %0\n"::"r"(MAIR_CONFIG_DEFAULT)); + /* + 0100 0100 0000 0000 + [7:0] device memory nGnRnE + [15:8] normal memory without cache + */ + + //L1 table init + asm volatile("str %0, [%1]\n"::"r"(0x1000|BOOT_PGD_ATTR),"r"(0)); + //L2 table init + asm volatile("str %0, [%1]\n"::"r"(0x2000|BOOT_PGD_ATTR),"r"(0x1000)); //finer granularity for different memory type + asm volatile("str %0, [%1]\n"::"r"(0x40000000|BOOT_PUD_ATTR),"r"(0x1000+8)); // 1G block for ARM peripherals + //L3 table for 0~1G + asm volatile("\ + mov x10, %0\n\ + mov x11, %1\n\ + mov x0, #0x2000\n\ + mov x1, #512\n\ + mov x2, #0\n\ +beg1:\n\ + cbz x1, end1\n\ + ldr x3, =0x3F000000\n\ + cmp x2, x3\n\ + blt normalmem\n\ +peripheralsmem:\n\ + orr x3, x2, x10\n\ + b end2\n\ +normalmem:\n\ + orr x3, x2, x11\n\ + b end2\n\ +end2:\n\ + str x3, [x0]\n\ + add x0, x0, #8\n\ + sub x1, x1, #1\n\ + add x2, x2, #0x200000\n\ + b beg1\n\ +end1:\n\ + "::"r"(BOOT_L2D_ATTR),"r"(BOOT_L2N_ATTR)); + + //setting L1 table for lower VA region (0000) + asm volatile("msr ttbr0_el1, %0\n"::"r"(0)); //ensure to read correct inst when mmu opened + //setting L1 table for higher VA region (ffff) + asm volatile("msr ttbr1_el1, %0\n"::"r"(0)); + asm volatile("isb \n"); //forces the changes to be seen before the MMU is enabled + + asm volatile("mrs x0, sctlr_el1 \n"); + asm volatile("orr x0 , x0, 1 \n"); //enalble mmu for EL1&0 (bit 0 of sctlr_el1) + asm volatile("msr sctlr_el1, x0 \n"); + asm volatile("isb \n"); //forces the change to be seen by the next instruction + + //no longer running on 0x80000 + asm volatile("\ + ldr x0, =0xffff000000000000\n\ + add x30, x30, x0\n\ + "::); +} + +/* for video program */ +// void vc_identity_mapping(void* page_table) { +// if (!page_table) +// uart_printf("[ERROR][vc_identity_mapping] null page table!\n"); + +// /* +// index for 0x3c000000 & 0x3f000000 (1G frame) +// 0011 1100 0000 0000 00 +// 0011 1111 0000 0000 00 +// */ +// for (uint64_t i = 0b001111000000000000; i < 0b001111110000000000; ++i) { +// uart_printf("%d\n", i); +// uint64_t* table = (uint64_t*)PA2VA(page_table); +// *(table + i * 8) = ((uint64_t)0x3c0000000000 + i * (uint64_t)0x40000000) | BOOT_PUD_ATTR; +// } +// } \ No newline at end of file diff --git a/Lab7/load_kernel.py b/Lab7/load_kernel.py new file mode 100755 index 000000000..13d229249 --- /dev/null +++ b/Lab7/load_kernel.py @@ -0,0 +1,45 @@ +#!/usr/bin/python3 +import os +import time +import serial#pyserial + +def waitFor(target,dev,display=True):#avoid loss data + msgs='' + while True: + cnt=dev.inWaiting() + if cnt>0: + msg=dev.read(cnt).decode() + msgs=msgs+msg + if display: + print(msg,end='') + if target == '.': + if msgs.find(target)!=-1: + return + else: + return + +def dumpImg(dev,k_addr='0x80000',kernel='kernel8.img'): + dev.write(str.encode("[Load Kernel]\n")) + + k_size=os.stat(kernel).st_size + + time.sleep(1) + waitFor('',dev) + dev.write(str.encode(k_addr + '\n')) + + time.sleep(1) + waitFor('',dev) + dev.write(str.encode(str(k_size) + '\n')) + + with open(kernel,"rb") as f: + time.sleep(1) + waitFor('',dev) + for i in range(k_size): + dev.write(f.read(1)) + waitFor('.',dev,False) + +if __name__=='__main__': + br=115200 + #dev=serial.Serial("/dev/ttyUSB0",br) + dev=serial.Serial("/dev/pts/2",br) + dumpImg(dev) diff --git a/Lab7/user/dummy_test.c b/Lab7/user/dummy_test.c new file mode 100644 index 000000000..a3bc71460 --- /dev/null +++ b/Lab7/user/dummy_test.c @@ -0,0 +1,6 @@ +#include "system_call.h" + +void dummy_test() { + printf("\nDummy test!\n"); + exit(); +} \ No newline at end of file diff --git a/Lab7/user/exec_test.c b/Lab7/user/exec_test.c new file mode 100644 index 000000000..72e407abc --- /dev/null +++ b/Lab7/user/exec_test.c @@ -0,0 +1,6 @@ +#include "system_call.h" + +void exec_test() { + printf("\nExec Test, pid %d\n", get_pid()); + exec("dummy_test.img", NULL); +} \ No newline at end of file diff --git a/Lab7/user/fork_test.c b/Lab7/user/fork_test.c new file mode 100644 index 000000000..c2cef3dfb --- /dev/null +++ b/Lab7/user/fork_test.c @@ -0,0 +1,31 @@ +#include "system_call.h" + +void fork_test(){ + printf("\nFork Test, pid %d\n", get_pid()); + int cnt = 1; + int ret = 0; + if ((ret = fork()) == 0) { // child + long long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + ++cnt; + + if ((ret = fork()) != 0){ + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + } + else{ + while (cnt < 5) { + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf("second child pid: %d, cnt: %d, ptr: %x, sp : %x\n", get_pid(), cnt, &cnt, cur_sp); + delay(1000000); + ++cnt; + } + } + exit(); + } + else { + printf("parent here, pid %d, child %d\n", get_pid(), ret); + exit(); + } +} \ No newline at end of file diff --git a/Lab7/user/fs_test.c b/Lab7/user/fs_test.c new file mode 100644 index 000000000..6a8b4de2b --- /dev/null +++ b/Lab7/user/fs_test.c @@ -0,0 +1,23 @@ +#include "system_call.h" + +void fs_test() { + char buffer_mkdir[10] = "test fs!\n"; + mkdir("../home/d"); + if (mount(0, "d", "tmpfs", 0, 0) == -1) { + printf("[ERROR] mount fail\n"); + while (1) {} + } + int fd = open("/home/d/t.txt", O_CREAT); + write(fd, buffer_mkdir, 10); + close(fd); + fd = open("./d/t.txt", O_CREAT); + read(fd, buffer_mkdir, 10); + close(fd); + printf("%s\n", buffer_mkdir); + + fd = open("/initramfs/t.txt", O_CREAT); + if (write(fd, buffer_mkdir, 10) != -1) + printf("[ERROR] Should fail!\n"); + + exit(); +} \ No newline at end of file diff --git a/Lab7/user/include/mail_box.h b/Lab7/user/include/mail_box.h new file mode 100644 index 000000000..6370ebb4f --- /dev/null +++ b/Lab7/user/include/mail_box.h @@ -0,0 +1,23 @@ +#ifndef _MAIL_BOX_H +#define _MAIL_BOX_H + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_GETSERIAL 0x10004 +#define MBOX_TAG_LAST 0 +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_EMEORY 0x00010005 + +#endif \ No newline at end of file diff --git a/Lab7/user/include/system_call.h b/Lab7/user/include/system_call.h new file mode 100644 index 000000000..778487142 --- /dev/null +++ b/Lab7/user/include/system_call.h @@ -0,0 +1,31 @@ +#ifndef _SYSTEM_CALL_H +#define _SYSTEM_CALL_H + +#include + +#define O_CREAT 2 + +/* helper functions for user programs, not the real system calls */ +int get_pid(); +size_t uart_read(char buf[], size_t size); +size_t uart_write(const char buf[], size_t size); +int exec(const char *name, char *const argv[]); +int fork(); +void exit(); +int mbox_call(unsigned char ch, unsigned int *mbox); +void kill(int pid); + +int open(const char *pathname, int flags); +int close(int fd); +int write(int fd, const void *buf, int count); +int read(int fd, void *buf, int count); +int mkdir(const char *pathname); +// you can ignore arguments other than target and filesystem +int mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data); + +/* utility functions */ +unsigned int printf(char* fmt,...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); +void delay(unsigned int clock); + +#endif \ No newline at end of file diff --git a/Lab7/user/lib/system_call.c b/Lab7/user/lib/system_call.c new file mode 100644 index 000000000..46aeda863 --- /dev/null +++ b/Lab7/user/lib/system_call.c @@ -0,0 +1,236 @@ +#include "system_call.h" + + +/* helper functions for user programs, not the real system calls */ +int get_pid() { + unsigned long ret; + asm volatile("mov x8, 0\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +size_t uart_read(char buf[], size_t size) { + unsigned long ret; + asm volatile("mov x8, 1\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +size_t uart_write(const char buf[], size_t size) { + unsigned long ret; + asm volatile("mov x8, 2\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +int exec(const char *name, char *const argv[]) { + unsigned long ret; + asm volatile("mov x8, 3\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +int fork() { + unsigned long ret; + asm volatile("mov x8, 4\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +void exit() { + asm volatile("mov x8, 5\n"); + asm volatile("svc 0\n"); +} + +int mbox_call(unsigned char ch, unsigned int *mbox) { + unsigned long ret; + asm volatile("mov x8, 6\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +void kill(int pid) { + asm volatile("mov x8, 7\n"); + asm volatile("svc 0\n"); +} + +int open(const char *pathname, int flags) { + unsigned long ret; + asm volatile("mov x8, 11\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +int close(int fd) { + unsigned long ret; + asm volatile("mov x8, 12\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +int write(int fd, const void *buf, int count) { + unsigned long ret; + asm volatile("mov x8, 13\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +int read(int fd, void *buf, int count) { + unsigned long ret; + asm volatile("mov x8, 14\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +int mkdir(const char *pathname) { + unsigned long ret; + asm volatile("mov x8, 15\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +// you can ignore arguments other than target and filesystem +int mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data) { + unsigned long ret; + asm volatile("mov x8, 16\n"); + asm volatile("svc 0\n"); + asm volatile("mov %0, x0\n":"=r"(ret):); + return ret; +} + +/* utility functions */ +unsigned int printf(char* fmt,...) { + char dst[100]; + __builtin_va_list args; + __builtin_va_start(args,fmt); + unsigned int ret = vsprintf(dst,fmt,args); + uart_write(dst, 100); + return ret; +} + +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; +} + +void delay(unsigned int clock) { + while (clock--) { + asm volatile("nop"); + } +} \ No newline at end of file diff --git a/Lab7/user/linker.ld b/Lab7/user/linker.ld new file mode 100644 index 000000000..7bb1dde69 --- /dev/null +++ b/Lab7/user/linker.ld @@ -0,0 +1,12 @@ +SECTIONS +{ + . = 0x80000; + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + . = ALIGN(0x10); + bss_begin = .; + .bss : { *(.bss*) } + bss_end = .; +} \ No newline at end of file diff --git a/Lab7/user/mbox_test.c b/Lab7/user/mbox_test.c new file mode 100644 index 000000000..efc50acc1 --- /dev/null +++ b/Lab7/user/mbox_test.c @@ -0,0 +1,58 @@ +#include "system_call.h" +#include "mail_box.h" + + +void mbox_test() { + /* test mbox_call */ + printf("\nTest mbox\n"); + // my_mailbox[0] = 7 * 4; + // my_mailbox[1] = REQUEST_CODE; + // my_mailbox[2] = GET_BOARD_REVISION; + // my_mailbox[3] = 4; + // my_mailbox[4] = TAG_REQUEST_CODE; + // my_mailbox[5] = 0; + // my_mailbox[6] = END_TAG; + // int status = mbox_call(8, my_mailbox); + // printf("\rboard revision: 0x"); + // printf("%x\n", my_mailbox[5]); // it should be 0xa020d3 for rpi3 b+ + // if (status) + // printf("success\n"); + // else + // printf("fail\n"); + + volatile unsigned int __attribute__((aligned(16))) my_mailbox[36]; + my_mailbox[0] = 7 * 4; // buffer size in bytes + my_mailbox[1] = MBOX_REQUEST; + // tags begin + my_mailbox[2] = GET_BOARD_REVISION; // tag identifier + my_mailbox[3] = 4; // maximum of request and response value buffer's length. + my_mailbox[4] = 8; + my_mailbox[5] = 0; // value buffer + // tags end + my_mailbox[6] = MBOX_TAG_LAST; + if (mbox_call(MBOX_CH_PROP, (unsigned int*)my_mailbox)) + printf("board revision number: 0x%x\n", my_mailbox[5]); + else + printf("can not get board revision number!\n"); + + + /* test kill */ + // int child_id[3]; + // int parent_id = 0; + // for (int i = 0; i < 3; ++i) { + // int id = fork(); + // if (!id) // child + // break; + // child_id[i] = id; + // parent_id = get_pid(); + // } + // if (get_pid() == parent_id) { + // for (int i = 0; i < 1000000; ++i) {} + // } + // else { + // printf("Thread %d before kill\n", get_pid()); + // while (1) {} + // } + + exit(); +} diff --git a/Lab7/user/timer_test.c b/Lab7/user/timer_test.c new file mode 100644 index 000000000..f0ca93a5c --- /dev/null +++ b/Lab7/user/timer_test.c @@ -0,0 +1,12 @@ +#include "system_call.h" + +void timer_test() { + fork(); + + for (int i = 1; i <= 10000000; ++i) { + for (int j = 0; j < 1000000; ++j) {} + printf("Thread: %d, counts to %dM\n", get_pid(), i); + } + + exit(); +} \ No newline at end of file diff --git a/ssd_fuse_lab/.vscode/configurationCache.log b/ssd_fuse_lab/.vscode/configurationCache.log new file mode 100644 index 000000000..57699e11e --- /dev/null +++ b/ssd_fuse_lab/.vscode/configurationCache.log @@ -0,0 +1 @@ +{"buildTargets":["all","clean","test"],"launchTargets":["/home/littlelagi/OSC2022/ssd_fuse_lab>ssd_fuse()","/home/littlelagi/OSC2022/ssd_fuse_lab>ssd_fuse(-d,/tmp/ssd)","/home/littlelagi/OSC2022/ssd_fuse_lab>ssd_fuse_dut()"],"customConfigurationProvider":{"workspaceBrowse":{"browsePath":["/home/littlelagi/OSC2022/ssd_fuse_lab"],"compilerArgs":["-Wall","ssd_fuse_dut.c","-o","ssd_fuse_dut"],"compilerPath":"/usr/bin/gcc","standard":"c11","windowsSdkVersion":""},"fileIndex":[["/home/littlelagi/OSC2022/ssd_fuse_lab/ssd_fuse.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/ssd_fuse_lab/ssd_fuse.c","path":"/home/littlelagi/OSC2022/ssd_fuse_lab/ssd_fuse.c","scheme":"file"},"configuration":{"defines":["_FILE_OFFSET_BITS=64"],"standard":"c11","includePath":[],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/gcc","compilerArgs":["-Wall","ssd_fuse.c","-I/usr/include/fuse3","-lfuse3","-lpthread","-o","ssd_fuse"],"windowsSdkVersion":""},"compileCommand":{"command":"gcc -Wall ssd_fuse.c `pkg-config fuse3 --cflags --libs` -D_FILE_OFFSET_BITS=64 -o ssd_fuse","directory":"/home/littlelagi/OSC2022/ssd_fuse_lab","file":"/home/littlelagi/OSC2022/ssd_fuse_lab/ssd_fuse.c"}}],["/home/littlelagi/OSC2022/ssd_fuse_lab/ssd_fuse_dut.c",{"uri":{"$mid":1,"fsPath":"/home/littlelagi/OSC2022/ssd_fuse_lab/ssd_fuse_dut.c","path":"/home/littlelagi/OSC2022/ssd_fuse_lab/ssd_fuse_dut.c","scheme":"file"},"configuration":{"defines":[],"standard":"c11","includePath":[],"forcedInclude":[],"intelliSenseMode":"gcc-x64","compilerPath":"/usr/bin/gcc","compilerArgs":["-Wall","ssd_fuse_dut.c","-o","ssd_fuse_dut"],"windowsSdkVersion":""},"compileCommand":{"command":"gcc -Wall ssd_fuse_dut.c -o ssd_fuse_dut","directory":"/home/littlelagi/OSC2022/ssd_fuse_lab","file":"/home/littlelagi/OSC2022/ssd_fuse_lab/ssd_fuse_dut.c"}}]]}} \ No newline at end of file diff --git a/ssd_fuse_lab/.vscode/dryrun.log b/ssd_fuse_lab/.vscode/dryrun.log new file mode 100644 index 000000000..787e9e949 --- /dev/null +++ b/ssd_fuse_lab/.vscode/dryrun.log @@ -0,0 +1,8 @@ +make --dry-run --always-make --keep-going --print-directory +make: Entering directory '/home/littlelagi/OSC2022/ssd_fuse_lab' +gcc -Wall ssd_fuse.c `pkg-config fuse3 --cflags --libs` -D_FILE_OFFSET_BITS=64 -o ssd_fuse +gcc -Wall ssd_fuse_dut.c -o ssd_fuse_dut +mkdir /tmp/ssd +./ssd_fuse -d /tmp/ssd +make: Leaving directory '/home/littlelagi/OSC2022/ssd_fuse_lab' + diff --git a/ssd_fuse_lab/.vscode/settings.json b/ssd_fuse_lab/.vscode/settings.json new file mode 100644 index 000000000..65e1ec078 --- /dev/null +++ b/ssd_fuse_lab/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "makefile.extensionOutputFolder": "./.vscode" +} \ No newline at end of file diff --git a/ssd_fuse_lab/.vscode/targets.log b/ssd_fuse_lab/.vscode/targets.log new file mode 100644 index 000000000..eb83400c6 --- /dev/null +++ b/ssd_fuse_lab/.vscode/targets.log @@ -0,0 +1,273 @@ +make all --print-data-base --no-builtin-variables --no-builtin-rules --question +# GNU Make 4.2.1 +# Built for x86_64-pc-linux-gnu +# Copyright (C) 1988-2016 Free Software Foundation, Inc. +# License GPLv3+: GNU GPL version 3 or later +# This is free software: you are free to change and redistribute it. +# There is NO WARRANTY, to the extent permitted by law. + +# Make data base, printed on Sat Jun 18 14:26:28 2022 + +# Variables + +# automatic + /tmp/ssd/ssd_file diff --git a/ssd_fuse_lab/make_ioctl b/ssd_fuse_lab/make_ioctl new file mode 100644 index 000000000..210920a96 --- /dev/null +++ b/ssd_fuse_lab/make_ioctl @@ -0,0 +1,2 @@ +gcc -Wall ssd_fuse.c `pkg-config fuse3 --cflags --libs` -D_FILE_OFFSET_BITS=64 -o ssd_fuse + diff --git a/ssd_fuse_lab/make_ssd b/ssd_fuse_lab/make_ssd new file mode 100644 index 000000000..9cc4f4399 --- /dev/null +++ b/ssd_fuse_lab/make_ssd @@ -0,0 +1,3 @@ +gcc -Wall ssd_fuse.c `pkg-config fuse3 --cflags --libs` -D_FILE_OFFSET_BITS=64 -o ssd_fuse +gcc -Wall ssd_fuse_dut.c -o ssd_fuse_dut + diff --git a/ssd_fuse_lab/nand_0 b/ssd_fuse_lab/nand_0 new file mode 100644 index 000000000..3321fe7a2 --- /dev/null +++ b/ssd_fuse_lab/nand_0 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/ssd_fuse_lab/nand_1 b/ssd_fuse_lab/nand_1 new file mode 100644 index 000000000..0abc9fde3 --- /dev/null +++ b/ssd_fuse_lab/nand_1 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/ssd_fuse_lab/nand_10 b/ssd_fuse_lab/nand_10 new file mode 100644 index 000000000..e69de29bb diff --git a/ssd_fuse_lab/nand_11 b/ssd_fuse_lab/nand_11 new file mode 100644 index 000000000..e69de29bb diff --git a/ssd_fuse_lab/nand_12 b/ssd_fuse_lab/nand_12 new file mode 100644 index 000000000..e69de29bb diff --git a/ssd_fuse_lab/nand_2 b/ssd_fuse_lab/nand_2 new file mode 100644 index 000000000..5d9d03e07 --- /dev/null +++ b/ssd_fuse_lab/nand_2 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/ssd_fuse_lab/nand_3 b/ssd_fuse_lab/nand_3 new file mode 100644 index 000000000..7a9331e77 --- /dev/null +++ b/ssd_fuse_lab/nand_3 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/ssd_fuse_lab/nand_4 b/ssd_fuse_lab/nand_4 new file mode 100644 index 000000000..39d20d1cd --- /dev/null +++ b/ssd_fuse_lab/nand_4 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/ssd_fuse_lab/nand_5 b/ssd_fuse_lab/nand_5 new file mode 100644 index 000000000..a381df91d --- /dev/null +++ b/ssd_fuse_lab/nand_5 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/ssd_fuse_lab/nand_6 b/ssd_fuse_lab/nand_6 new file mode 100644 index 000000000..09f43ad24 --- /dev/null +++ b/ssd_fuse_lab/nand_6 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/ssd_fuse_lab/nand_7 b/ssd_fuse_lab/nand_7 new file mode 100644 index 000000000..ccfd0aa62 --- /dev/null +++ b/ssd_fuse_lab/nand_7 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/ssd_fuse_lab/nand_8 b/ssd_fuse_lab/nand_8 new file mode 100644 index 000000000..df316e06a --- /dev/null +++ b/ssd_fuse_lab/nand_8 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/ssd_fuse_lab/nand_9 b/ssd_fuse_lab/nand_9 new file mode 100644 index 000000000..85b2bb647 --- /dev/null +++ b/ssd_fuse_lab/nand_9 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/ssd_fuse_lab/ssd_fuse.c b/ssd_fuse_lab/ssd_fuse.c new file mode 100644 index 000000000..11054ac44 --- /dev/null +++ b/ssd_fuse_lab/ssd_fuse.c @@ -0,0 +1,492 @@ +/* + FUSE ssd: FUSE ioctl example + Copyright (C) 2008 SUSE Linux Products GmbH + Copyright (C) 2008 Tejun Heo + This program can be distributed under the terms of the GNU GPLv2. + See the file COPYING. +*/ +#define FUSE_USE_VERSION 35 +#include +#include +#include +#include +#include +#include +#include +#include +#include "ssd_fuse_header.h" +#define SSD_NAME "ssd_file" +enum +{ + SSD_NONE, + SSD_ROOT, + SSD_FILE, +}; + + +static size_t physic_size; +static size_t logic_size; +static size_t host_write_size; +static size_t nand_write_size; + +typedef union pca_rule PCA_RULE; +union pca_rule +{ + unsigned int pca; + struct + { + unsigned int lba : 16; + unsigned int nand: 16; // the physical block this pca reside in + } fields; +}; + +PCA_RULE curr_pca; +static unsigned int get_next_pca(); +void GC(); + +unsigned int* L2P,* P2L,* valid_count, free_block_number,* pca_status; +/* + L2P: logic page number to physical page number + P2L: physical page number to logic page number + valid_count: records number of programmed pages in each block +*/ + +static int ssd_resize(size_t new_size) +{ + //set logic size to new_size + if (new_size > NAND_SIZE_KB * 1024) + { + return -ENOMEM; + } + else + { + logic_size = new_size; + return 0; + } + +} + +static int ssd_expand(size_t new_size) +{ + //logic must less logic limit + + if (new_size > logic_size) + { + return ssd_resize(new_size); + } + + return 0; +} + +static int nand_read(char* buf, int pca) +{ + char nand_name[100]; + FILE* fptr; + + PCA_RULE my_pca; + my_pca.pca = pca; + snprintf(nand_name, 100, "%s/nand_%d", NAND_LOCATION, my_pca.fields.nand); + + //read + if ( (fptr = fopen(nand_name, "r") )) + { + fseek( fptr, my_pca.fields.lba * 512, SEEK_SET ); + fread(buf, 1, 512, fptr); + fclose(fptr); + } + else + { + printf("open file fail at nand read pca = %d\n", pca); + return -EINVAL; + } + return 512; +} +static int nand_write(const char* buf, int pca) +{ + char nand_name[100]; + FILE* fptr; + + PCA_RULE my_pca; + my_pca.pca = pca; + snprintf(nand_name, 100, "%s/nand_%d", NAND_LOCATION, my_pca.fields.nand); + + //write + if ( (fptr = fopen(nand_name, "r+"))) + { + fseek( fptr, my_pca.fields.lba * 512, SEEK_SET ); + fwrite(buf, 1, 512, fptr); + fclose(fptr); + physic_size ++; + valid_count[my_pca.fields.nand]++; + } + else + { + printf("open file fail at nand (%s) write pca = %d, return %d\n", nand_name, pca, -EINVAL); + return -EINVAL; + } + + nand_write_size += 512; + return 512; +} + +static int nand_erase(int block_index) +{ + char nand_name[100]; + FILE* fptr; + snprintf(nand_name, 100, "%s/nand_%d", NAND_LOCATION, block_index); + fptr = fopen(nand_name, "w"); + if (fptr == NULL) + { + printf("erase nand_%d fail", block_index); + return 0; + } + fclose(fptr); + valid_count[block_index] = FREE_BLOCK; + free_block_number += 1; + return 1; +} + +static unsigned int get_next_block() +{ + for (int i = 0; i < PHYSICAL_NAND_NUM; i++) // iterate through all nand(block) from current nand + { + if (valid_count[(curr_pca.fields.nand + i) % PHYSICAL_NAND_NUM] == FREE_BLOCK) + { + curr_pca.fields.nand = (curr_pca.fields.nand + i) % PHYSICAL_NAND_NUM; // get a free nand(block) + curr_pca.fields.lba = 0; + free_block_number--; + valid_count[curr_pca.fields.nand] = 0; + return curr_pca.pca; + } + } + return OUT_OF_BLOCK; +} +static unsigned int get_next_pca() +{ + if (curr_pca.pca == INVALID_PCA) + { + //init + curr_pca.pca = 0; + valid_count[0] = 0; + free_block_number--; + return curr_pca.pca; + } + + if(curr_pca.fields.lba == 9) // current physical block is full + { + int temp = get_next_block(); + if (free_block_number == 0) { + GC(); + return curr_pca.pca; + } + if (temp == OUT_OF_BLOCK) + { + return OUT_OF_BLOCK; + } + else if(temp == -EINVAL) + { + return -EINVAL; + } + else + { + return temp; + } + } + else + { + curr_pca.fields.lba += 1; + } + return curr_pca.pca; + +} + + +static int ftl_read( char* buf, size_t lba) +{ + return nand_read(buf, L2P[lba]); +} + +static int ftl_write(const char* buf, size_t lba_rnage, size_t lba) +{ + unsigned int pca = get_next_pca(); + int ret = nand_write(buf, pca); + if (L2P[lba] != INVALID_PCA) { + PCA_RULE old_pca; + old_pca.pca = L2P[lba]; + unsigned int old_pca_idx = old_pca.fields.nand * PAGE_PER_BLOCK + old_pca.fields.lba; + pca_status[old_pca_idx] = STALE_PCA; + P2L[old_pca_idx] = INVALID_LBA; + valid_count[old_pca.fields.nand] -= 1; + } + PCA_RULE new_pca; + new_pca.pca = pca; + unsigned int new_pca_idx = new_pca.fields.nand * PAGE_PER_BLOCK + new_pca.fields.lba; + P2L[new_pca_idx] = lba; + L2P[lba] = pca; + pca_status[new_pca_idx] = VALID_PCA; + return ret; +} + + + +static int ssd_file_type(const char* path) +{ + if (strcmp(path, "/") == 0) + { + return SSD_ROOT; + } + if (strcmp(path, "/" SSD_NAME) == 0) + { + return SSD_FILE; + } + return SSD_NONE; +} +static int ssd_getattr(const char* path, struct stat* stbuf, + struct fuse_file_info* fi) +{ + (void) fi; + stbuf->st_uid = getuid(); + stbuf->st_gid = getgid(); + stbuf->st_atime = stbuf->st_mtime = time(NULL); + switch (ssd_file_type(path)) + { + case SSD_ROOT: + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + break; + case SSD_FILE: + stbuf->st_mode = S_IFREG | 0644; + stbuf->st_nlink = 1; + stbuf->st_size = logic_size; + break; + case SSD_NONE: + return -ENOENT; + } + return 0; +} +static int ssd_open(const char* path, struct fuse_file_info* fi) +{ + (void) fi; + if (ssd_file_type(path) != SSD_NONE) + { + return 0; + } + return -ENOENT; +} +static int ssd_do_read(char* buf, size_t size, off_t offset) +{ + int tmp_lba, tmp_lba_range; + char* tmp_buf; + + //off limit + if ((offset ) >= logic_size) + { + return 0; + } + if ( size > logic_size - offset) + { + //is valid data section + size = logic_size - offset; + } + tmp_lba = offset / 512; // start from which page + tmp_lba_range = (offset + size - 1) / 512 - (tmp_lba) + 1; // total page count + tmp_buf = calloc(tmp_lba_range * 512, sizeof(char)); // read data into this buffer + + for (int i = 0; i < tmp_lba_range; i++) { // read full pages + ftl_read(tmp_buf + i * 512, tmp_lba + i); + } + + memcpy(buf, tmp_buf + offset % 512, size); + + + free(tmp_buf); + return size; +} +static int ssd_read(const char* path, char* buf, size_t size, + off_t offset, struct fuse_file_info* fi) +{ + (void) fi; + if (ssd_file_type(path) != SSD_FILE) + { + return -EINVAL; + } + return ssd_do_read(buf, size, offset); +} +static int ssd_do_write(const char* buf, size_t size, off_t offset) +{ + int tmp_lba, tmp_lba_range; + int idx; + char* tmp_buf; + + host_write_size += size; + if (ssd_expand(offset + size) != 0) + { + return -ENOMEM; + } + + tmp_lba = offset / 512; + tmp_lba_range = (offset + size - 1) / 512 - (tmp_lba) + 1; + + size_t buf_idx = 0; + tmp_buf = calloc(512, sizeof(char)); + for (idx = 0; idx < tmp_lba_range; ++idx) { + if (idx == 0 || idx == tmp_lba_range - 1) { + nand_read(tmp_buf, L2P[tmp_lba + idx]); + size_t begin = 0, end = 512; + if (idx == 0) + begin = offset % 512; + if (idx == tmp_lba_range - 1) + end = (offset + size) % 512; + if (end == 0) + end = 512; + for (int i = begin; i < end; ++i) + tmp_buf[i] = buf[buf_idx++]; + ftl_write(tmp_buf, tmp_lba_range, tmp_lba + idx); + } + else { + ftl_write(buf + buf_idx, tmp_lba_range, tmp_lba + idx); + buf_idx += 512; + } + } + free(tmp_buf); + return size; +} +static int ssd_write(const char* path, const char* buf, size_t size, + off_t offset, struct fuse_file_info* fi) +{ + + (void) fi; + if (ssd_file_type(path) != SSD_FILE) + { + return -EINVAL; + } + return ssd_do_write(buf, size, offset); +} +static int ssd_truncate(const char* path, off_t size, + struct fuse_file_info* fi) +{ + (void) fi; + memset(L2P, INVALID_PCA, sizeof(int) * LOGICAL_NAND_NUM * PAGE_PER_BLOCK); + memset(P2L, INVALID_LBA, sizeof(int) * PHYSICAL_NAND_NUM * PAGE_PER_BLOCK); + memset(valid_count, FREE_BLOCK, sizeof(int) * PHYSICAL_NAND_NUM); + curr_pca.pca = INVALID_PCA; + free_block_number = PHYSICAL_NAND_NUM; + if (ssd_file_type(path) != SSD_FILE) + { + return -EINVAL; + } + + return ssd_resize(size); +} +static int ssd_readdir(const char* path, void* buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info* fi, + enum fuse_readdir_flags flags) +{ + (void) fi; + (void) offset; + (void) flags; + if (ssd_file_type(path) != SSD_ROOT) + { + return -ENOENT; + } + filler(buf, ".", NULL, 0, 0); + filler(buf, "..", NULL, 0, 0); + filler(buf, SSD_NAME, NULL, 0, 0); + return 0; +} +static int ssd_ioctl(const char* path, unsigned int cmd, void* arg, + struct fuse_file_info* fi, unsigned int flags, void* data) +{ + + if (ssd_file_type(path) != SSD_FILE) + { + return -EINVAL; + } + if (flags & FUSE_IOCTL_COMPAT) + { + return -ENOSYS; + } + switch (cmd) + { + case SSD_GET_LOGIC_SIZE: + *(size_t*)data = logic_size; + return 0; + case SSD_GET_PHYSIC_SIZE: + *(size_t*)data = physic_size; + return 0; + case SSD_GET_WA: + *(double*)data = (double)nand_write_size / (double)host_write_size; + return 0; + } + return -EINVAL; +} + +void GC() { + unsigned int min_valid_count = PAGE_PER_BLOCK + 1, victim = 0; + for (int i = 1; i < PHYSICAL_NAND_NUM; ++i) { + int idx = (curr_pca.fields.nand + i) % PHYSICAL_NAND_NUM; + if (valid_count[idx] < min_valid_count && valid_count[idx] != FREE_BLOCK) { + min_valid_count = valid_count[idx]; + victim = idx; + } + } + if (valid_count[victim] != 0) { + for (int j = victim * PAGE_PER_BLOCK; j < (victim + 1) * PAGE_PER_BLOCK; ++j) { + if (pca_status[j] == VALID_PCA) { + char buffer[512]; + ftl_read(buffer, P2L[j]); + nand_write(buffer, curr_pca.pca); + L2P[P2L[j]] = curr_pca.pca; + P2L[curr_pca.fields.nand * PAGE_PER_BLOCK + curr_pca.fields.lba] = P2L[j]; + P2L[j] = INVALID_LBA; + pca_status[j] = STALE_PCA; + pca_status[curr_pca.fields.nand * PAGE_PER_BLOCK + curr_pca.fields.lba] = VALID_PCA; + curr_pca.fields.lba += 1; + } + } + } + nand_erase(victim); +} + +static const struct fuse_operations ssd_oper = +{ + .getattr = ssd_getattr, + .readdir = ssd_readdir, + .truncate = ssd_truncate, + .open = ssd_open, + .read = ssd_read, + .write = ssd_write, + .ioctl = ssd_ioctl, +}; +int main(int argc, char* argv[]) +{ + int idx; + char nand_name[100]; + physic_size = 0; + logic_size = 0; + curr_pca.pca = INVALID_PCA; + free_block_number = PHYSICAL_NAND_NUM; + + L2P = malloc(LOGICAL_NAND_NUM * PAGE_PER_BLOCK * sizeof(int)); + memset(L2P, INVALID_PCA, sizeof(int) * LOGICAL_NAND_NUM * PAGE_PER_BLOCK); + P2L = malloc(PHYSICAL_NAND_NUM * PAGE_PER_BLOCK * sizeof(int)); + memset(P2L, INVALID_LBA, sizeof(int) * PHYSICAL_NAND_NUM * PAGE_PER_BLOCK); + valid_count = malloc(PHYSICAL_NAND_NUM * sizeof(int)); + memset(valid_count, FREE_BLOCK, sizeof(int) * PHYSICAL_NAND_NUM); + pca_status = malloc(PHYSICAL_NAND_NUM * PAGE_PER_BLOCK * sizeof(int)); + memset(pca_status, INVALID_PCA, sizeof(int) * PHYSICAL_NAND_NUM * PAGE_PER_BLOCK); + + //create nand file + for (idx = 0; idx < PHYSICAL_NAND_NUM; idx++) + { + FILE* fptr; + snprintf(nand_name, 100, "%s/nand_%d", NAND_LOCATION, idx); + fptr = fopen(nand_name, "w"); + if (fptr == NULL) + { + printf("open fail"); + } + fclose(fptr); + } + return fuse_main(argc, argv, &ssd_oper, NULL); +} diff --git a/ssd_fuse_lab/ssd_fuse_dut.c b/ssd_fuse_lab/ssd_fuse_dut.c new file mode 100644 index 000000000..28e61b23f --- /dev/null +++ b/ssd_fuse_lab/ssd_fuse_dut.c @@ -0,0 +1,171 @@ +/* + FUSE ssdlient: FUSE ioctl example client + Copyright (C) 2008 SUSE Linux Products GmbH + Copyright (C) 2008 Tejun Heo + This program can be distributed under the terms of the GNU GPLv2. + See the file COPYING. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ssd_fuse_header.h" +#include +const char* usage = + "Usage: ssd_fuse SSD_FILE COMMAND\n" + "\n" + "COMMANDS\n" + " l : get logic size \n" + " p : get physical size \n" + " r SIZE [OFF] : read SIZE bytes @ OFF (dfl 0) and output to stdout\n" + " w SIZE [OFF] : write SIZE bytes @ OFF (dfl 0) from random\n" + " W : write amplification factor\n" + "\n"; +static int do_rw(FILE* fd, int is_read, size_t size, off_t offset) +{ + char* buf; + int idx; + ssize_t ret; + buf = calloc(1, size); + + if (!buf) + { + fprintf(stderr, "failed to allocated %zu bytes\n", size); + return -1; + } + if (is_read) + { + printf("dut do read size %ld, off %d\n", size, (int)offset); + fseek( fd, offset, SEEK_SET ); + ret = fread( buf, 1, size, fd); + if (ret >= 0) + { + fwrite(buf, 1, ret, stdout); + } + } + else + { + for ( idx = 0; idx < size; idx++) + { + buf[idx] = '%'; + } + printf("\n"); + printf("dut do write size %ld, off %d\n", size, (int)offset); + fseek( fd, offset, SEEK_SET ); + printf("fseek \n"); + ret = fwrite(buf, 1, size, fd); + //arg.size = fread(arg.buf, 1, size, stdin); + fprintf(stderr, "Writing %zu bytes\n", size); + } + if (ret < 0) + { + perror("ioctl"); + } + + free(buf); + return ret; +} +int main(int argc, char** argv) +{ + size_t param[2] = { }; + size_t size; + char cmd; + char* path; + FILE* fptr; + int fd, i, rc; + + if (argc < 3) + { + goto usage; + } + path = argv[1]; + cmd = tolower(argv[2][0]); + cmd = argv[2][0]; + argc -= 3; + argv += 3; + for (i = 0; i < argc; i++) + { + char* endp; + param[i] = strtoul(argv[i], &endp, 0); + if (endp == argv[i] || *endp != '\0') + { + goto usage; + } + } + switch (cmd) + { + case 'l': + fd = open(path, O_RDWR); + if (fd < 0) + { + perror("open"); + return 1; + } + if (ioctl(fd, SSD_GET_LOGIC_SIZE, &size)) + { + perror("ioctl"); + goto error; + } + printf("%zu\n", size); + close(fd); + return 0; + case 'p': + fd = open(path, O_RDWR); + if (fd < 0) + { + perror("open"); + return 1; + } + if (ioctl(fd, SSD_GET_PHYSIC_SIZE, &size)) + { + perror("ioctl"); + goto error; + } + printf("%zu\n", size); + close(fd); + return 0; + case 'r': + case 'w': + if ( !(fptr = fopen(path, "r+"))) + { + perror("open"); + return 1; + } + rc = do_rw(fptr, cmd == 'r', param[0], param[1]); + if (rc < 0) + { + goto error; + } + fprintf(stderr, "transferred %d bytes \n", rc); + + fclose(fptr); + return 0; + case 'W': + fd = open(path, O_RDWR); + if (fd < 0) + { + perror("open"); + return 1; + } + double wa; + if (ioctl(fd, SSD_GET_WA, &wa)) + { + perror("ioctl"); + goto error; + } + printf("%f\n", wa); + close(fd); + return 0; + } +usage: + fprintf(stderr, "%s", usage); + return 1; +error: + + return 1; +} \ No newline at end of file diff --git a/ssd_fuse_lab/ssd_fuse_header.h b/ssd_fuse_lab/ssd_fuse_header.h new file mode 100644 index 000000000..3634df011 --- /dev/null +++ b/ssd_fuse_lab/ssd_fuse_header.h @@ -0,0 +1,29 @@ +/* + FUSE-ioctl: ioctl support for FUSE + Copyright (C) 2008 SUSE Linux Products GmbH + Copyright (C) 2008 Tejun Heo + This program can be distributed under the terms of the GNU GPLv2. + See the file COPYING. +*/ +#include +#include +#include +#define PHYSICAL_NAND_NUM (13) +#define LOGICAL_NAND_NUM (10) +#define NAND_SIZE_KB (50) // LOGICAL_NAND_NUM * PAGE_PER_BLOCK * 512(page size) +#define INVALID_PCA (0xFFFFFFFF) +#define VALID_PCA (0xFFFFFFF0) +#define STALE_PCA (0xFFFFFF00) +#define INVALID_LBA (0xFFFFFFFF) +#define FREE_BLOCK (0xFFFFFFFF) +#define OUT_OF_BLOCK (0xFFFF) +#define FULL_PCA (0xFFFFFFFE) +#define PAGE_PER_BLOCK (10) +#define NAND_LOCATION "/home/littlelagi/ssd_fuse_lab" + +enum +{ + SSD_GET_LOGIC_SIZE = _IOR('E', 0, size_t), + SSD_GET_PHYSIC_SIZE = _IOR('E', 1, size_t), + SSD_GET_WA = _IOR('E', 2, size_t), +}; diff --git a/ssd_fuse_lab/ssd_fuse_lab.docx b/ssd_fuse_lab/ssd_fuse_lab.docx new file mode 100644 index 000000000..852071cbf Binary files /dev/null and b/ssd_fuse_lab/ssd_fuse_lab.docx differ diff --git a/ssd_fuse_lab/test.sh b/ssd_fuse_lab/test.sh new file mode 100755 index 000000000..a27bb6440 --- /dev/null +++ b/ssd_fuse_lab/test.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +SSD_FILE="/tmp/ssd/ssd_file" +GOLDEN="/tmp/ssd_file_golden" +TEMP="/tmp/temp" +touch ${GOLDEN} +truncate -s 0 ${SSD_FILE} +truncate -s 0 ${GOLDEN} + +rand(){ + min=$1 + max=$(($2-$min)) + num=$(cat /dev/urandom | head -n 10 | cksum | awk -F ' ' '{print $1}') + echo $(($num%$max)) +} + +case "$1" in + "test1") + cat /dev/urandom | tr -dc '[:alpha:][:digit:]' | head -c 51200 | tee ${SSD_FILE} > ${GOLDEN} 2> /dev/null + ;; + "test2") + cat /dev/urandom | tr -dc '[:alpha:][:digit:]' | head -c 51200 | tee ${SSD_FILE} > ${GOLDEN} 2> /dev/null + cat /dev/urandom | tr -dc '[:alpha:][:digit:]' | head -c 11264 > ${TEMP} + for i in $(seq 0 9) + do + dd if=${TEMP} skip=$(($i*1024)) of=${GOLDEN} iflag=skip_bytes oflag=seek_bytes seek=$(($i*5120)) bs=1024 count=1 conv=notrunc 2> /dev/null + dd if=${TEMP} skip=$(($i*1024)) of=${SSD_FILE} iflag=skip_bytes oflag=seek_bytes seek=$(($i*5120)) bs=1024 count=1 conv=notrunc 2> /dev/null + done + dd if=${TEMP} skip=10240 of=${GOLDEN} iflag=skip_bytes oflag=seek_bytes seek=0 bs=1024 count=1 conv=notrunc 2> /dev/null + dd if=${TEMP} skip=10240 of=${SSD_FILE} iflag=skip_bytes oflag=seek_bytes seek=0 bs=1024 count=1 conv=notrunc 2> /dev/null + ;; + *) + printf "Usage: sh test.sh test_pattern\n" + printf "\n" + printf "test_pattern\n" + printf "test1: Sequential write whole SSD size(51200bytes)\n" + printf " test basic SSD read & write\n" + printf "test2:\n" + printf " 1: Sequential write whole SSD size(51200bytes)\n" + printf " 2: Override 0, 1, 10, 11, 20, 21, 30, 31, 40, 41, 50, 51, 60, 61, 70, 71, 80, 81, 90, 91 page \n" + printf " 2: Override 0, 1 page \n" + printf " test GC's result\n" + return + ;; +esac + +# check +diff ${GOLDEN} ${SSD_FILE} +if [ $? -eq 0 ] +then + echo "success!" +else + echo "fail!" +fi + +echo "WA:" +./ssd_fuse_dut /tmp/ssd/ssd_file W +rm -rf ${TEMP} ${GOLDEN} \ No newline at end of file diff --git a/ssd_fuse_lab/test_case b/ssd_fuse_lab/test_case new file mode 100755 index 000000000..805b28133 Binary files /dev/null and b/ssd_fuse_lab/test_case differ diff --git a/ssd_fuse_lab/test_case_x86_64 b/ssd_fuse_lab/test_case_x86_64 new file mode 100755 index 000000000..d622742e9 Binary files /dev/null and b/ssd_fuse_lab/test_case_x86_64 differ