diff --git a/.gitignore b/.gitignore index e5613c6ba..3e7376c80 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,6 @@ *.img *.d *.elf +initramfs.cpio.test **yuchang** \ No newline at end of file diff --git a/lab05/README.md b/lab05/README.md index 56e82e60f..1360ac749 100644 --- a/lab05/README.md +++ b/lab05/README.md @@ -1,4 +1,4 @@ -# OSC2023-Lab04 +# OSC2023-Lab05 | Github Account | Student ID | Name | |----------------|------------|---------------| diff --git a/lab05/initramfs.cpio.1 b/lab05/initramfs.cpio.1 new file mode 100644 index 000000000..35e0f5d18 Binary files /dev/null and b/lab05/initramfs.cpio.1 differ diff --git a/lab05/kernel/src/entry.S b/lab05/kernel/src/entry.S index 70635565d..8d7d4fd22 100644 --- a/lab05/kernel/src/entry.S +++ b/lab05/kernel/src/entry.S @@ -203,7 +203,7 @@ ret_from_fork: bl schedule_tail // preemptive enable cbz x19, ret_to_user mov x0, x20 - blr x19 //should never return + blr x19 //should never return, except for kp_to_user ret_to_user: bl disable_irq diff --git a/lab05/kernel/src/sys.c b/lab05/kernel/src/sys.c index 5c1f84b3d..de7614d8d 100644 --- a/lab05/kernel/src/sys.c +++ b/lab05/kernel/src/sys.c @@ -90,7 +90,7 @@ int sys_fork() // [TODO] { unsigned long stack = (unsigned long)balloc(THREAD_SIZE); if((void*)stack == NULL) return -1; - memzero_asm(stack, 4*THREAD_SIZE); + memzero_asm(stack, THREAD_SIZE); return copy_process(0, 0, 0, stack); } diff --git a/lab07/bootloader/Makefile b/lab07/bootloader/Makefile new file mode 100644 index 000000000..3a9d087ed --- /dev/null +++ b/lab07/bootloader/Makefile @@ -0,0 +1,49 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -ffreestanding -nostdinc -nostdlib -nostartfiles -fno-stack-protector -g -Iinclude +ASMOPS = + +BUILD_DIR = build +SRC_DIR = src + + +all: clean bootloader.img + +.PHONY: clean +clean: + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.s + $(ARMGNU)-gcc $(ASMOPS) -c $< -o $@ + + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +# DEP_FILES = $(OBJ_FILES:%.o=%.d) +# -include $(DEP_FILES) + +bootloader.img: $(OBJ_FILES) $(SRC_DIR)/linker.ld + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/bootloader.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/bootloader.elf -O binary bootloader.img + +.PHONY: run debug test +run: bootloader.img + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -display none -serial null -serial pty \ + -initrd ../initramfs.cpio \ + -dtb ../bcm2710-rpi-3-b-plus.dtb + +test: bootloader.img + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -display none -serial null -serial stdio + +dump: bootloader.img + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -display none -d in_asm + +debug: all + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -display none -serial null -serial stdio -S -s diff --git a/lab07/bootloader/include/base.h b/lab07/bootloader/include/base.h new file mode 100644 index 000000000..fb8886d5b --- /dev/null +++ b/lab07/bootloader/include/base.h @@ -0,0 +1,6 @@ +#ifndef _BASE_H +#define _BASE_H + +#define MMIO_BASE 0x3F000000 + +#endif \ No newline at end of file diff --git a/lab07/bootloader/include/bootload.h b/lab07/bootloader/include/bootload.h new file mode 100644 index 000000000..3dda28e56 --- /dev/null +++ b/lab07/bootloader/include/bootload.h @@ -0,0 +1,16 @@ +#ifndef __BOOTLOAD_H__ +#define __BOOTLOAD_H__ + +#define KernelAddr 0x80000 +#define BootAddr 0x60000 + +#include "mini_uart.h" +#include "io.h" +#include "type.h" + +extern uint32_t __bss_end; + +void reallocate(); +void load_kernel(); + +#endif diff --git a/lab07/bootloader/include/gpio.h b/lab07/bootloader/include/gpio.h new file mode 100644 index 000000000..9fc10379b --- /dev/null +++ b/lab07/bootloader/include/gpio.h @@ -0,0 +1,12 @@ +#ifndef _GPIO_H +#define _GPIO_H + +#include "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 diff --git a/lab07/bootloader/include/io.h b/lab07/bootloader/include/io.h new file mode 100644 index 000000000..64b657fb0 --- /dev/null +++ b/lab07/bootloader/include/io.h @@ -0,0 +1,11 @@ +#ifndef __IO_H__ +#define __IO_H__ + +#include "mini_uart.h" + +void printf(char* str); +void printfc(char c); +void printf_hex(unsigned int d); +char read_char(); + +#endif \ No newline at end of file diff --git a/lab07/bootloader/include/mini_uart.h b/lab07/bootloader/include/mini_uart.h new file mode 100644 index 000000000..659dd83c0 --- /dev/null +++ b/lab07/bootloader/include/mini_uart.h @@ -0,0 +1,26 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +#include "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)) + + +void uart_init(); +char uart_recv(); +char uart_recv_io(); +void uart_send(char c); +void uart_send_string(const char* str); + +#endif \ No newline at end of file diff --git a/lab07/bootloader/include/type.h b/lab07/bootloader/include/type.h new file mode 100644 index 000000000..90b369a00 --- /dev/null +++ b/lab07/bootloader/include/type.h @@ -0,0 +1,9 @@ +#ifndef __TYPE_H__ +#define __TYPE_H__ + +typedef unsigned char uint8_t; +typedef unsigned int uint16_t; +typedef unsigned long int uint32_t; +typedef unsigned long long int uint64_t; + +#endif diff --git a/lab07/bootloader/src/boot.S b/lab07/bootloader/src/boot.S new file mode 100644 index 000000000..4579e1f8c --- /dev/null +++ b/lab07/bootloader/src/boot.S @@ -0,0 +1,35 @@ +.section ".text.boot" + +.global _start +_prologue: + mov x20, x0 + mov x1, #0x0000 + movk x1, #5, lsl #16 // 0x50000 + str x20, [x1] + +_start: + mrs x0, mpidr_el1 + and x0, x0,#0xFF // Check processor id + cbz x0, master // if cpu_id == 0, then booting + b proc_hang // Otherwise, hang + +proc_hang: + b proc_hang + +master: + adr x0, __bss_start + adr x1, __bss_size + bl memzero + + adr x1, _start + mov sp, x1 + bl main // jump to kernel_main c code + b proc_hang // should never come here + +memzero: + str xzr, [x0], #8 // xzr: a register holds zero + subs x1, x1, #8 + b.gt memzero + ret + +// adr: Load a label's relative address into the target register. \ No newline at end of file diff --git a/lab07/bootloader/src/bootload.c b/lab07/bootloader/src/bootload.c new file mode 100644 index 000000000..8f6febcce --- /dev/null +++ b/lab07/bootloader/src/bootload.c @@ -0,0 +1,41 @@ +#include "bootload.h" + +// uint64_t* BootHead = (uint64_t*)KernelAddr; +// uint64_t* CopyHead = (uint64_t*)BootAddr; +// uint64_t* bss_end = (uint64_t*)(&__bss_end); + +void reallocate() +{ + uint64_t* BootHead = (uint64_t*)KernelAddr; + uint64_t* CopyHead = (uint64_t*)BootAddr; + uint64_t* bss_end = (uint64_t*)(&__bss_end); + int i = 0; + while(BootHead != bss_end){ + printf("\n"); + printf_hex(i); + i++; + *CopyHead = *BootHead; + CopyHead++; + BootHead++; + } + printf("\nCopy done."); +} + +void load_kernel() +{ + unsigned int kernel_size = 0; + for(int i=0; i<4; i++){ + kernel_size <<= 8; + kernel_size |= (uart_recv() & 0xff); + } + + printf("\nKernel Size: "); + printf_hex(kernel_size); + printf("\n"); + + unsigned char* kernel = (unsigned char*)(0x80000); + unsigned char* kernel_ptr = kernel; + for(unsigned int i=0; i 0x????? - 0x20000 +***** need to branch hereh ***** -> 0x????? - 0x20000 + 4 + + . + . + . + +0x80000: kernel start address + +0x?????: load_kernel() +*/ + +void readcmd(char*); + +void *dtb_addr = 0; // Due to the variable is used in the assembly code, must be declared as global variable + + +void main() +{ + uart_init(); + + while(1) + { + printf("\nType load for bootloading: "); + char cmd[10]; + readcmd(cmd); + if(cmd[0] == 'l' && cmd[1] == 'o' && cmd[2] == 'a' && cmd[3] == 'd') + { + break; + } + } + + reallocate(); + asm volatile("b -131068"); // jump to same place in bootloader + // 0x20000 = 131072 + // 0x20000 - 4 = 131068 + printf("\nListening New Kernel"); + load_kernel(); + printf("\nFinished Loading"); + + asm volatile("mov %0, x20" : "=r" (dtb_addr)); + printf("\nDTB Address (Bootloader): "); + printf_hex(dtb_addr); + + // asm volatile ( + // "mov x30, 0x80000;" + // "ret" + // ); + asm volatile("blr %0" + : + : "r" (0x80000)); +} + +void readcmd(char *x) +{ + char input_char; + int input_index = 0; + x[0] = 0; + while( ((input_char = read_char()) != '\n')) + { + x[input_index] = input_char; + ++input_index; + printfc(input_char); + } + + x[input_index]=0; // null char +} diff --git a/lab07/bootloader/src/io.c b/lab07/bootloader/src/io.c new file mode 100644 index 000000000..63d0aa432 --- /dev/null +++ b/lab07/bootloader/src/io.c @@ -0,0 +1,32 @@ +#include "io.h" + +void printf(char* str) +{ + uart_send_string(str); +} + +void printfc(char c) +{ + uart_send(c); +} + +void printf_hex(unsigned int d) +{ + printf("0x"); + unsigned int td = d; + for(int i=28; i>=0; i-=4){ + int tmp = (td >> i) & 0xf; + if(tmp < 10){ + printfc('0'+tmp); + } + else{ + printfc('a'+tmp-10); + } + } +} + +char read_char() +{ + char c = uart_recv_io(); + return c; +} diff --git a/lab07/bootloader/src/linker.ld b/lab07/bootloader/src/linker.ld new file mode 100644 index 000000000..6b2ee8a0e --- /dev/null +++ b/lab07/bootloader/src/linker.ld @@ -0,0 +1,22 @@ +SECTIONS +{ + . = 0x80000; + .text : + { + KEEP(*(.text.boot)) + *(.text) + } + .rodata :{ *(.rodata) } + .data : { *(.data) } + .bss : + { + . = ALIGN(0x8); + __bss_start = .; + *(.bss) + . = ALIGN(0x8); + __bss_end = .; + } + . = ALIGN(0x8); + _end = .; +} +__bss_size = (__bss_end - __bss_start)>>3; \ No newline at end of file diff --git a/lab07/bootloader/src/mini_uart.c b/lab07/bootloader/src/mini_uart.c new file mode 100644 index 000000000..2c4d3c00f --- /dev/null +++ b/lab07/bootloader/src/mini_uart.c @@ -0,0 +1,69 @@ +#include "gpio.h" +#include "mini_uart.h" + +void uart_init() +{ + // set the alternate function for GPIO14 and GPIO15 + unsigned int selector; + selector = *GPFSEL1; + selector &= ~(7<<12); // size gpio14 to 0 for gpio14 is bits 12-14 + selector |= 2<<12; // set to alt5 for gpio14 + selector &= ~(7<<15); // size gpio15 to 0 for gpio15 is bits 15-17 + selector |= 2<<15; // set to alt5 for gpio15 + *GPFSEL1 = selector; + + // GPIO initilaization + *GPPUD = 0; // disable pull up/down for all GPIO pins + unsigned int i = 150; + while(i--) asm volatile("nop"); + *GPPUDCLK0 = (1<<14) | (1<<15); // enable clock for gpio14 and gpio15 + i = 150; + while(i--) asm volatile("nop"); + *GPPUDCLK0 = 0; // disable clock for gpio14 and gpio15 + + // initialize mini uart + *AUX_ENABLES = 1; //Enable mini uart (this also enables access to its registers) + *AUX_MU_CNTL_REG = 0; //Disable auto flow control and disable receiver and transmitter (for now) + *AUX_MU_IER_REG = 0; //Disable receive and transmit interrupts + *AUX_MU_LCR_REG = 3; //Enable 8 bit mode + *AUX_MU_MCR_REG = 0; //Set RTS line to be always high + *AUX_MU_BAUD_REG = 270; // 115200 baud + *AUX_MU_CNTL_REG = 3; //Finally, enable transmitter and receiver +} + +char uart_recv() +{ + char r; + // bit 0 == 1, if receiver holds valid byte + do{asm volatile("nop");}while(!(*AUX_MU_LSR_REG & 0x01)); + return *AUX_MU_IO_REG; + // return r == '\r'?'\n':r; + +} + +char uart_recv_io() +{ + char r; + do{asm volatile("nop");}while(!(*AUX_MU_LSR_REG & 0x01)); + r = *AUX_MU_IO_REG; + return r == '\r'?'\n':r; +} + +void uart_send(char c) +{ + // bit 6 == 1, if transmitter is empty + while (1) { + if ((*AUX_MU_LSR_REG)&0x20) break; + } + *AUX_MU_IO_REG = c; + +} + +void uart_send_string(const char* str) +{ + while(*str){ + if(*str == '\n') + uart_send('\r'); + uart_send(*str++); + } +} \ No newline at end of file diff --git a/lab07/bootloader/src/type.c b/lab07/bootloader/src/type.c new file mode 100644 index 000000000..a521f5fdd --- /dev/null +++ b/lab07/bootloader/src/type.c @@ -0,0 +1 @@ +#include "type.h" diff --git a/lab07/create_fs.sh b/lab07/create_fs.sh new file mode 100755 index 000000000..88b71b68e --- /dev/null +++ b/lab07/create_fs.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +(cd initramfs && find . | cpio -o -H newc > ../initramfs.cpio) + diff --git a/lab07/initramfs.cpio b/lab07/initramfs.cpio new file mode 100644 index 000000000..3014be52b Binary files /dev/null and b/lab07/initramfs.cpio differ diff --git a/lab07/initramfs/dir1/f3 b/lab07/initramfs/dir1/f3 new file mode 100644 index 000000000..93ca8fc0c --- /dev/null +++ b/lab07/initramfs/dir1/f3 @@ -0,0 +1 @@ +This is f3 diff --git a/lab07/initramfs/dir1/f4 b/lab07/initramfs/dir1/f4 new file mode 100644 index 000000000..397683db2 --- /dev/null +++ b/lab07/initramfs/dir1/f4 @@ -0,0 +1 @@ +This is f4 diff --git a/lab07/initramfs/f1 b/lab07/initramfs/f1 new file mode 100644 index 000000000..5d12ba17a --- /dev/null +++ b/lab07/initramfs/f1 @@ -0,0 +1 @@ +This is f1 diff --git a/lab07/initramfs/f2 b/lab07/initramfs/f2 new file mode 100644 index 000000000..688c067f3 --- /dev/null +++ b/lab07/initramfs/f2 @@ -0,0 +1 @@ +This is f2 diff --git a/lab07/kernel/Makefile b/lab07/kernel/Makefile new file mode 100644 index 000000000..d78176373 --- /dev/null +++ b/lab07/kernel/Makefile @@ -0,0 +1,64 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -ffreestanding -nostartfiles -nostdlib -g -Iinclude +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all: clean makedir kernel8.img + + +ifdef DEBUG +COPS += -DDEBUG +endif + +ifdef BUDDY_SYSTEM_DEBUG +COPS += -BUDDY_SYSTEM_DEBUG +endif + +ifdef DYNAMIC_ALLOC_DEBUG +COPS += -DYNAMIC_ALLOC_DEBUG +endif + +ifdef SYSCALL_DEBUG +COPS += -DSYSCALL_DEBUG +endif + +.PHONY: clean +clean: + rm -rf $(BUILD_DIR) *.img + +makedir: + mkdir -p $(BUILD_DIR) +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: $(OBJ_FILES) $(SRC_DIR)/linker.ld + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img + +.PHONY: run debug QEMU +run: clean makedir kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -serial null -serial stdio -initrd ../initramfs.cpio + +dump: kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -d in_asm + +gdb: clean makedir kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -serial null -serial stdio -S -s -initrd ../initramfs.cpio + +QEMU: COPS += -DQEMU +QEMU: run \ No newline at end of file diff --git a/lab07/kernel/include/alloc.h b/lab07/kernel/include/alloc.h new file mode 100644 index 000000000..ffbcbebf6 --- /dev/null +++ b/lab07/kernel/include/alloc.h @@ -0,0 +1,25 @@ +#ifndef __ALLOC_H__ +#define __ALLOC_H__ + +#include "type.h" + +void mem_init(); +void* simple_malloc(uint32_t size); + +struct frame_t; +struct free_t; +struct memory_pool_t; +struct chunk_t; + +void frame_init_with_reserve(); + +void* balloc(uint64_t size); +int bfree(void* ptr); + +void memory_pool_init(); +void* dynamic_alloc(uint64_t size); +int dfree(void* ptr); + +void memory_reserve(uint64_t start, uint64_t end, char* msg); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/bootload.h b/lab07/kernel/include/bootload.h new file mode 100644 index 000000000..a15f9b56a --- /dev/null +++ b/lab07/kernel/include/bootload.h @@ -0,0 +1,15 @@ +#ifndef __BOOTLOAD_H__ +#define __BOOTLOAD_H__ + +#define KernelAddr 0x80000 +#define BootAddr 0x60000 + +#include "type.h" + +extern uint32_t __bss_end; +extern uint32_t __bss_size; + +void reallocate(); +void load_kernel(); + +#endif diff --git a/lab07/kernel/include/cpio.h b/lab07/kernel/include/cpio.h new file mode 100644 index 000000000..4d6102060 --- /dev/null +++ b/lab07/kernel/include/cpio.h @@ -0,0 +1,42 @@ +#ifndef __CPIO_H__ +#define __CPIO_H__ + +#include "devicetree.h" + +#ifdef QEMU + #define CPIO_ADDR 0x8000000 +#else + #define CPIO_ADDR 0x20000000 +#endif + +typedef struct cpio_newc_header { + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +} cpio_newc_header; + +void cpio_list(int argc, char **argv); +void cpio_cat(int argc, char **argv); +void cpio_exec(int argc, char **argv); + +#ifndef QEMU +void initramfs_callback(char* node_name, char* property_name, fdt_prop* prop); + +extern uint64_t CPIO_START_ADDR_FROM_DT; +extern uint64_t CPIO_END_ADDR_FROM_DT; +#endif + +int cpio_newc_parser(cpio_newc_header** head, char** filename, char** filedata); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/dev_framebuffer.h b/lab07/kernel/include/dev_framebuffer.h new file mode 100644 index 000000000..3ba45a40a --- /dev/null +++ b/lab07/kernel/include/dev_framebuffer.h @@ -0,0 +1,23 @@ +#ifndef _DEV_FRAMEBUFFER_H__ +#define _DEV_FRAMEBUFFER_H__ + +#include "vfs.h" + +struct framebuffer_info +{ + unsigned int width; + unsigned int height; + unsigned int pitch; + unsigned int isrgb; +}; + +#define SEEK_SET 0 + +int dev_framebuffer_register(); +int dev_framebuffer_write(struct file *file, const void *buf, size_t len); +int dev_framebuffer_read(struct file *file, void *buf, size_t len); +int dev_framebuffer_open(struct vnode *file_node, struct file **target); +int dev_framebuffer_close(struct file *file); +long dev_framebuffer_lseek64(struct file *file, long offset, int whence); + +#endif diff --git a/lab07/kernel/include/dev_uart.h b/lab07/kernel/include/dev_uart.h new file mode 100644 index 000000000..5f07be050 --- /dev/null +++ b/lab07/kernel/include/dev_uart.h @@ -0,0 +1,12 @@ +#ifndef __DEV_UART_H__ +#define __DEV_UART_H__ + +#include "vfs.h" + +int dev_uart_register(); +int dev_uart_write(struct file *file, const void *buf, size_t len); +int dev_uart_read(struct file *file, void *buf, size_t len); +int dev_uart_open(struct vnode *file_node, struct file **target); +int dev_uart_close(struct file *file); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/devicetree.h b/lab07/kernel/include/devicetree.h new file mode 100644 index 000000000..f89d11aee --- /dev/null +++ b/lab07/kernel/include/devicetree.h @@ -0,0 +1,94 @@ +#ifndef __DEVICETREE_H__ +#define __DEVICETREE_H__ + +#include "type.h" + + +/* +0x50000: devicetree blob address +*/ + +#define DTB_ADDR ((volatile uint64_t *)0x50000) + +#define FDT_BEGIN_NODE 0x01 +#define FDT_END_NODE 0x02 +#define FDT_PROP 0x03 +#define FDT_NOP 0x04 +#define FDT_END 0x09 + +/* + |-------------------| + | struct fdt_header | + |-------------------| + | free space | + |-------------------| + | memory reservation| -> list of areas in physical memory which are reserved + |-------------------| + | free space | + |-------------------| + | structure block | + |-------------------| + | free space | + |-------------------| + | strings block | + |-------------------| + | free space | + |-------------------| +*/ + +/* All the header fields are 32-bit integers, stored in big-endian format. */ +typedef struct fdt_header { + uint32_t magic; + uint32_t totalsize; // total size of DT block + uint32_t off_dt_struct; // offset to the structure block + uint32_t off_dt_strings; // offset to the strings block + uint32_t off_mem_rsvmap; // offset to the memory reservation block + uint32_t version; + uint32_t last_comp_version; + uint32_t boot_cpuid_phys; // physical address of the boot CPU + uint32_t size_dt_strings; // size of the strings block + uint32_t size_dt_struct; // size of the structure block +} fdt_header; + + +/* + Memory reservation block + Composed of sequence of tokens with data shown below. + Each token in the structure block, and thus the structure block itself, + shall be loacted at a 4-byte aligned offset from the beginning of the devicetree blob. + + Five tokens types: (32-bit big-endian integers) + 1. FDT_BEGIN_NODE (0x00000001) be followed by the node's uint name as extra data + 2. FDT_END_NODE (0x00000002) + 3. FDT_PROP (0x00000003) + 4. FDT_NOP (0x00000004) + 5. FDT_END (0x00000009) + + FDT_BEGIN_NODE -> ... -> FDT_END_NODE + + - (Optional) Any number of FDT_NOP tokens + - FDT_BEGIN_NODE + - The node’s name as a null-terminated string + - [zeroed padding bytes to align to a 4-byte boundary] + - For each property of the node + - (Optional) Any number of FDT_NOP tokens + - FDT_PROP token + * property infomation + * aligned to a 4-byte boundary +*/ + +/* + The strings block contains strings representing all the property names used in the tree. +*/ + + +/* 32-bit big-endian integers */ +typedef struct fdt_prop { + uint32_t len; // length of the property value + uint32_t nameoff; // offset into the strings block for the property name +} fdt_prop; + +void fdt_traverse(void(*callback_func)(char*, char*, fdt_prop*)); +uint32_t endian_swap(uint32_t value); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/entry.h b/lab07/kernel/include/entry.h new file mode 100644 index 000000000..872bec449 --- /dev/null +++ b/lab07/kernel/include/entry.h @@ -0,0 +1,30 @@ +#ifndef _ENTRY_H__ +#define _ENTRY_H__ + + +#define SYNC_INVALID_EL1t 0 +#define IRQ_INVALID_EL1t 1 +#define FIQ_INVALID_EL1t 2 +#define ERROR_INVALID_EL1t 3 + +#define SYNC_INVALID_EL1h 4 +#define IRQ_INVALID_EL1h 5 +#define FIQ_INVALID_EL1h 6 +#define ERROR_INVALID_EL1h 7 + +#define SYNC_INVALID_EL0_64 8 +#define IRQ_INVALID_EL0_64 9 +#define FIQ_INVALID_EL0_64 10 +#define ERROR_INVALID_EL0_64 11 + +#define SYNC_INVALID_EL0_32 12 +#define IRQ_INVALID_EL0_32 13 +#define FIQ_INVALID_EL0_32 14 +#define ERROR_INVALID_EL0_32 15 + +#define SYNC_ERROR 16 +#define SYSCALL_ERROR 17 + +#define S_X0 0 + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/errno.h b/lab07/kernel/include/errno.h new file mode 100644 index 000000000..8f4fbd285 --- /dev/null +++ b/lab07/kernel/include/errno.h @@ -0,0 +1,9 @@ +#ifndef __ERRNO_H__ +#define __ERRNO_H__ + +#define RERROR -1 +#define WERROR -1 +#define CERROR -1 +#define LERROR -1 + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/fork.h b/lab07/kernel/include/fork.h new file mode 100644 index 000000000..c85fc4cb1 --- /dev/null +++ b/lab07/kernel/include/fork.h @@ -0,0 +1,26 @@ +#ifndef __FORK_H__ +#define __FORK_H__ + +// int copy_process(unsigned long fn, unsigned long arg); +#include "schedule.h" + +int copy_process( + unsigned long flags, + unsigned long fn, + unsigned long arg, + unsigned long stack); +int move_to_user_mode(unsigned long pc); + +struct pt_regs { + unsigned long regs[31]; + unsigned long sp; + unsigned long pc; + unsigned long pstate; +}; + +struct pt_regs * task_pt_regs(struct task_struct *tsk); +void kp_user_mode(unsigned long func); + +#define PSR_MODE_EL0t 0x00000000; + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/initramfs.h b/lab07/kernel/include/initramfs.h new file mode 100644 index 000000000..276f6720e --- /dev/null +++ b/lab07/kernel/include/initramfs.h @@ -0,0 +1,35 @@ +#ifndef __INITRAMFS_H__ +#define __INITRAMFS_H__ + +#define COMPONENT_SIZE 15 +#define ENTRIES_PER_DIR 16 +#define INITRAMFS_MAX_FILE 4096*128 + +#include "vfs.h" +#include "cpio.h" + +struct initramfs_internal { + char* name; // file name or directory name + unsigned long size; // child count for directory + char* data; + unsigned long filesize; + int type; // DIR_NODE or FILE_NODE + // struct vnode* parent; + struct vnode* children[ENTRIES_PER_DIR]; + // struct vnode* next; +}; + +int initramfs_list(struct vnode* dir_node); +int initramfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name); +int initramfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name); +int initramfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name); +int initramfs_close(struct file* file); +int initramfs_open(struct vnode* file_node, struct file** target); +int initramfs_read(struct file* file, void* buf, size_t len); +int initramfs_write(struct file* file, const void* buf, size_t len); +int initramfs_getsize(struct vnode* vnode); +int initramfs_setup_mount(struct filesystem* fs, struct mount** mount); +int initramfs_register(); +// int parse_initramfs(); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/io.h b/lab07/kernel/include/io.h new file mode 100644 index 000000000..d1e5333e5 --- /dev/null +++ b/lab07/kernel/include/io.h @@ -0,0 +1,14 @@ +#ifndef __IO_H__ +#define __IO_H__ + +#include "mini_uart.h" + +void printf(const char* str); +void printfc(const char c); +void printf_hex(const unsigned int d); +void printf_int(const int d); +char read_char(); + +#define debug() printf("\r\n [DEBUG] : "); printf(__FILE__); printf(" : "); printf_int(__LINE__) + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/irq.h b/lab07/kernel/include/irq.h new file mode 100644 index 000000000..21f2fd7f1 --- /dev/null +++ b/lab07/kernel/include/irq.h @@ -0,0 +1,12 @@ +#ifndef __IRQ_H__ +#define __IRQ_H__ + +#define EL1_IRQ_TIMER_PRIORITY 0x1 +#define EL1_IRQ_UART_PRIORITY 0x2 + +struct irq_task_struct; + +void task_head_init(); +void test_func(); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/lib.h b/lab07/kernel/include/lib.h new file mode 100644 index 000000000..cb370038c --- /dev/null +++ b/lab07/kernel/include/lib.h @@ -0,0 +1,12 @@ +#ifndef __LIB_H__ +#define __LIB_H__ + +#include "type.h" + +uint32_t strtol(const char *sptr, uint32_t base, int size); +uint64_t atoi(const char *str); +uint64_t atoi_hex(const char *str); +uint64_t pow(int base, int exp); +void assert(int condition, char* message); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/mailbox.h b/lab07/kernel/include/mailbox.h new file mode 100644 index 000000000..46f26015f --- /dev/null +++ b/lab07/kernel/include/mailbox.h @@ -0,0 +1,9 @@ +#ifndef __MAIULBOX_H__ +#define __MAILBOX_H__ + +void get_board_revision(); +void get_memory_info(); +void mailbox_call(unsigned int *mailbox); +int mailbox_call_s(unsigned char ch, unsigned int *mbox); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/mem.h b/lab07/kernel/include/mem.h new file mode 100644 index 000000000..f355738b4 --- /dev/null +++ b/lab07/kernel/include/mem.h @@ -0,0 +1,31 @@ +#ifndef __MEM_H__ +#define __MEM_H__ + +#include "type.h" + +extern uint64_t _heap_start; + +#define HEAP_END (uint64_t)(&_heap_start + 0x100000) + +#define USER_PROCESS_SP 0x200000 +#define USER_START_ADDR 0x100000 + + +// malloc +#define FRAME_SIZE 4096 // 4KB +// #define MAX_LEVEL 16 +#define MAX_LEVEL 18 // log_2(FRAME_NUM) about 17.~ + +// #define MALLOC_START_ADDR 0x10000000 +// #define MALLOC_END_ADDR 0x20000000 +#define MALLOC_START_ADDR 0x00000000 +#define MALLOC_END_ADDR 0x3C000000 +#define MALLOC_TOTAL_SIZE (MALLOC_END_ADDR - MALLOC_START_ADDR) +#define FRAME_NUM MALLOC_TOTAL_SIZE / FRAME_SIZE + +#define MAX_BUDDY_SYSTEM_LIST 10 + +#define MEMORY_POOL_SIZE 4 +#define MEMORY_POOL_DEPTH 4 + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/mini_uart.h b/lab07/kernel/include/mini_uart.h new file mode 100644 index 000000000..eed952d7b --- /dev/null +++ b/lab07/kernel/include/mini_uart.h @@ -0,0 +1,26 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +#define BUFF_SIZE 256 + +void uart_init(); +char uart_recv(); +void uart_send(const char c); +void uart_send_string(const char* str); + +void enable_uart_interrupt(); +void disable_uart_interrupt(); +void enable_uart_recv_interrupt(); +void disable_uart_recv_interrupt(); +void enable_uart_trans_interrupt(); +void disable_uart_trans_interrupt(); + +void uart_buff_init(); + +void async_uart_puts(char* buff); +int async_uart_gets(char* buff, int size); + +void async_uart_read_handler(); +void async_uart_write_handler(); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/mm.h b/lab07/kernel/include/mm.h new file mode 100644 index 000000000..d97596341 --- /dev/null +++ b/lab07/kernel/include/mm.h @@ -0,0 +1,6 @@ +#ifndef __MM_H__ +#define __MM_H__ + +void memzero_asm(unsigned long src, unsigned long n); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/peripherals/base.h b/lab07/kernel/include/peripherals/base.h new file mode 100644 index 000000000..1d3265580 --- /dev/null +++ b/lab07/kernel/include/peripherals/base.h @@ -0,0 +1,6 @@ +#ifndef __PERIPHERALS_BASE_H__ +#define __PERIPHERALS_BASE_H__ + +#define MMIO_BASE 0x3F000000 + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/peripherals/gpio.h b/lab07/kernel/include/peripherals/gpio.h new file mode 100644 index 000000000..b6a104ab3 --- /dev/null +++ b/lab07/kernel/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _GPIO_H +#define _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 \ No newline at end of file diff --git a/lab07/kernel/include/peripherals/irq.h b/lab07/kernel/include/peripherals/irq.h new file mode 100644 index 000000000..54672e0f5 --- /dev/null +++ b/lab07/kernel/include/peripherals/irq.h @@ -0,0 +1,29 @@ +#ifndef __PERIPHERALS_IRQ_H__ +#define __PERIPHERALS_IRQ_H__ + +#include "peripherals/base.h" + +// BCM2835 page. 112-116 +#define IRQ_BASIC_PENDING ((volatile unsigned int*)(MMIO_BASE+0x0000B200)) +#define IRQ_PENDING_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B204)) // Holds All interrupts 0...31 from the GPU side. +#define IRQ_PENDING_2 ((volatile unsigned int*)(MMIO_BASE+0x0000B208)) // 32...63 +#define FIQ_CONTROL ((volatile unsigned int*)(MMIO_BASE+0x0000B20C)) +#define ENABLE_IRQS_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B210)) // Writing a 1 to a bit will set the corresponding IRQ enable bit. (0-31) +#define ENABLE_IRQS_2 ((volatile unsigned int*)(MMIO_BASE+0x0000B214)) // (32-63) +#define ENABLE_BASIC_IRQS ((volatile unsigned int*)(MMIO_BASE+0x0000B218)) +#define DISABLE_IRQS_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B21C)) +#define DISABLE_IRQS_2 ((volatile unsigned int*)(MMIO_BASE+0x0000B220)) +#define DISABLE_BASIC_IRQS ((volatile unsigned int*)(MMIO_BASE+0x0000B224)) // AUX interrupt. 29 + +#define AUX_INT (1 << 29) + +// QA7 page. 16 +#define CORE0_IRQ_SOURCE ((volatile unsigned int*)(0x40000060)) // Get the IRQ source for the core 0. + +#define SYSTEM_TIMER_IRQ_1 (1 << 1) +#define GPU_IRQ (1 << 8) + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/peripherals/mailbox.h b/lab07/kernel/include/peripherals/mailbox.h new file mode 100644 index 000000000..454eb13a3 --- /dev/null +++ b/lab07/kernel/include/peripherals/mailbox.h @@ -0,0 +1,26 @@ +#ifndef __PERIPHERALS_MAILBOX_H__ +#define __PERIPHERALS_MAILBOX_H__ + +#include "peripherals/base.h" + +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#define MAILBOX_READ ((volatile unsigned int*)(MAILBOX_BASE )) // M0: CPU read from GPU +#define MAILBOX_STATUS ((volatile unsigned int*)(MAILBOX_BASE + 0x18)) // M0: Check GPU statue +#define MAILBOX_WRITE ((volatile unsigned int*)(MAILBOX_BASE + 0x20)) // M1: CPU write to GPU + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +#define MBOX_CH_PROP 8 +#define MBOX_TAG_LAST 0 + +#endif diff --git a/lab07/kernel/include/peripherals/mini_uart.h b/lab07/kernel/include/peripherals/mini_uart.h new file mode 100644 index 000000000..bb55ba2fe --- /dev/null +++ b/lab07/kernel/include/peripherals/mini_uart.h @@ -0,0 +1,26 @@ +#ifndef __PERIPHERALS_MINI_UART_H__ +#define __PERIPHERALS_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)) // Interrupt Enable Register (BCM2835 page. 12) +#define AUX_MU_IIR_REG ((volatile unsigned int*)(MMIO_BASE+0x00215048)) // Shows the interrupt status. (BCM2835 page. 13) +#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 ENABLE_RCV_IRQ (1 << 0) +#define ENABLE_TRANS_IRQ (1 << 1) + +#define AUX_MU_IIR_REG_READ (1 << 2) +#define AUX_MU_IIR_REG_WRITE (1 << 1) + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/reboot.h b/lab07/kernel/include/reboot.h new file mode 100644 index 000000000..e47678792 --- /dev/null +++ b/lab07/kernel/include/reboot.h @@ -0,0 +1,8 @@ +#ifndef __REBOOT_H__ +#define __REBOOT_H__ + +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/schedule.h b/lab07/kernel/include/schedule.h new file mode 100644 index 000000000..5392a441d --- /dev/null +++ b/lab07/kernel/include/schedule.h @@ -0,0 +1,79 @@ +#ifndef __SCHEDULE_H__ +#define __SCHEDULE_H__ + +#define THREAD_CPU_CONTEXT 0 // offset of cpu_context in task_struct + + +#ifndef __ASSEMBLER__ + +#define THREAD_SIZE 4096 + +#define NR_TASKS 64 + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#define TASK_RUNNING 0 +#define TASK_ZOMBIE 1 +#define TASK_STOPPED 2 + +#define PF_KTHREAD 2 + +// #define MAX_PATH_LEN 256 + +extern struct task_struct *current; +extern struct task_struct * task[NR_TASKS]; +extern int nr_tasks; + +#include "vfs.h" + +struct cpu_context { + unsigned long long x19; + unsigned long long x20; + unsigned long long x21; + unsigned long long x22; + unsigned long long x23; + unsigned long long x24; + unsigned long long x25; + unsigned long long x26; + unsigned long long x27; + unsigned long long x28; + unsigned long long fp; // x29 + unsigned long long sp; + unsigned long long pc; // x30 +}; + +struct task_struct { + struct cpu_context cpu_context; + long state; + long counter; + long priority; + long preempt_count; + unsigned long stack; + unsigned long flags; + int pid; + char cwd[MAX_PATH_LEN]; + struct file_descriptor_table fd_table; +}; + +extern void sched_init(void); +extern void schedule(void); +extern void timer_tick(void); +extern void preempt_disable(void); +extern void preempt_enable(void); +extern void switch_to(struct task_struct* next); +extern void cpu_switch_to(struct task_struct* prev, struct task_struct* next); +extern void enable_irq(void); +extern void disable_irq(void); +extern void kill_zombies(void); +extern void exit_process(void); + +#define INIT_TASK \ +/*cpu_context*/ { {0,0,0,0,0,0,0,0,0,0,0,0,0}, \ +/* state etc */ 0,0,1, 0, 0, PF_KTHREAD, 0, \ +/* cwd */ "/", \ +/*fd table*/ {0, {0}} \ +} + +#endif +#endif \ No newline at end of file diff --git a/lab07/kernel/include/shell.h b/lab07/kernel/include/shell.h new file mode 100644 index 000000000..cf6dd6e14 --- /dev/null +++ b/lab07/kernel/include/shell.h @@ -0,0 +1,12 @@ +#ifndef __SHELL_H__ +#define __SHELL_H__ + +typedef struct cmd { + char *name; + void (*func)(int argc, char *argv[]); + char help_msg[100]; +} cmd; + +void readcmd(char [256]); +void shell_loop(); +#endif \ No newline at end of file diff --git a/lab07/kernel/include/string.h b/lab07/kernel/include/string.h new file mode 100644 index 000000000..edf5814b4 --- /dev/null +++ b/lab07/kernel/include/string.h @@ -0,0 +1,12 @@ +#ifndef __STRING_H__ +#define __STRING_H__ + +#include "type.h" + +int strcmp(const char *str1, const char *str2); +char* strcpy(char* dest, const char* src); +char* strncpy(char* dest, const char* src, int n); +uint32_t strlen(const char* str); +char *strtok(char* str, const char* delim); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/sys.h b/lab07/kernel/include/sys.h new file mode 100644 index 000000000..ae3f6528f --- /dev/null +++ b/lab07/kernel/include/sys.h @@ -0,0 +1,57 @@ +#ifndef __SYS_H__ +#define __SYS_H__ + +#define __NR_syscalls 20 + +#define SYS_GETPID_NUM 0 // syscall number +#define SYS_UARTREAD_NUM 1 +#define SYS_UARTWRITE_NUM 2 +#define SYS_EXEC_NUM 3 +#define SYS_FORK_NUM 4 +#define SYS_EXIT_NUM 5 +#define SYS_MBOX_CALL_NUM 6 +#define SYS_KILL_NUM 7 + + +#define SYS_OPEN_NUM 11 +#define SYS_CLOSE_NUM 12 +#define SYS_WRITE_NUM 13 +#define SYS_READ_NUM 14 +#define SYS_MKDIR_NUM 15 +#define SYS_MOUNT_NUM 16 +#define SYS_CHDIR_NUM 17 +#define SYS_LSEEK64_NUM 18 +#define SYS_IOCTL_NUM 19 + +#ifndef __ASSEMBLER__ + +#include "type.h" + +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(const char *name, char *const argv[]); +int sys_fork(); +void sys_exit(int status); +int sys_mbox_call(unsigned char ch, unsigned int *mbox); +void sys_kill(int pid); + +// lab7 +int sys_open(const char *pathname, int flags); +int sys_close(int fd); +long sys_write(int fd, const void *buf, unsigned long count); +long sys_read(int fd, void *buf, unsigned long count); + +// you can ignore mode, since there is no access control +int sys_mkdir(const char *pathname, unsigned mode); + +// you can ignore arguments other than target (where to mount) and filesystem (fs name) +int sys_mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data); +int sys_chdir(const char *path); + +long sys_lseek64(int fd, long offset, int whence); +long sys_ioctl(int fd, unsigned long request, unsigned long arg); + +#endif + +#endif diff --git a/lab07/kernel/include/timer.h b/lab07/kernel/include/timer.h new file mode 100644 index 000000000..7591b62d0 --- /dev/null +++ b/lab07/kernel/include/timer.h @@ -0,0 +1,14 @@ +#ifndef __TIMER_H__ +#define __TIMER_H__ + +extern void core_timer_enable(); +extern void core_timer_disable(); +extern unsigned long long get_cpu_cycles(); +extern unsigned int get_cpu_freq(); +extern void set_timer_asm(unsigned int sec); + +void timer_init(); +void irq_timer_handler(); +void set_timer(unsigned int sec); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/tmpfs.h b/lab07/kernel/include/tmpfs.h new file mode 100644 index 000000000..1c2beee77 --- /dev/null +++ b/lab07/kernel/include/tmpfs.h @@ -0,0 +1,33 @@ +#ifndef __TMPFS_H__ +#define __TMPFS_H__ + +#define COMPONENT_SIZE 15 +#define ENTRIES_PER_DIR 16 +#define TMPFS_MAX_FILE 4096 + +#include "vfs.h" + +struct tmpfs_internal { + char* name; // file name or directory name + unsigned long size; + char* data; + unsigned long filesize; + int type; // DIR_NODE or FILE_NODE + // struct vnode* parent; + struct vnode* children[ENTRIES_PER_DIR]; + // struct vnode* next; +}; + +int tmpfs_list(struct vnode* dir_node); +int tmpfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name); +int tmpfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name); +int tmpfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name); +int tmpfs_close(struct file* file); +int tmpfs_open(struct vnode* file_node, struct file** target); +int tmpfs_read(struct file* file, void* buf, size_t len); +int tmpfs_write(struct file* file, const void* buf, size_t len); +int tmpfs_getsize(struct vnode* vnode); +int tmpfs_setup_mount(struct filesystem* fs, struct mount** mount); +int tmpfs_register(); + +#endif \ No newline at end of file diff --git a/lab07/kernel/include/type.h b/lab07/kernel/include/type.h new file mode 100644 index 000000000..91acd4bd5 --- /dev/null +++ b/lab07/kernel/include/type.h @@ -0,0 +1,13 @@ +#ifndef __TYPE_H__ +#define __TYPE_H__ + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef unsigned long long size_t; + +#define NULL (void*)0 + +#endif diff --git a/lab07/kernel/include/user_demo.h b/lab07/kernel/include/user_demo.h new file mode 100644 index 000000000..7ebabd664 --- /dev/null +++ b/lab07/kernel/include/user_demo.h @@ -0,0 +1,14 @@ +#ifndef __USER_DEMO_H__ +#define __USER_DEMO_H__ + +#define delay(x) for(int i=0; i (void*)HEAP_END){ + + return (char*)0; + } + char* ret = HEAP_REAR; + HEAP_REAR += size; + return ret; +} + +// ========================================== + +static uint64_t pow_2(uint32_t n); + +extern uint64_t _kernel_end; +static uint64_t* _kernel_end_ptr = &_kernel_end; +static uint64_t* _heap_start_ptr = &_heap_start; + +#ifndef QEMU +extern uint64_t CPIO_START_ADDR_FROM_DT; +extern uint64_t CPIO_END_ADDR_FROM_DT; +#endif + +struct frame_t{ + struct frame_t* next; + struct frame_t* prev; // [TODO] maintain prev pointer + uint32_t index; + uint8_t level; + uint8_t status; +}; + +struct flist_t{ + struct frame_t* head; +}; + +struct buddy_system_list_t{ + void* base_addr; + uint32_t index; + uint8_t max_level; +}; + +struct memory_pool_t{ + uint8_t frame_used; + uint8_t chunk_used; + uint32_t size; + uint32_t chunk_per_frame; + uint32_t chunk_offset; // use to get the offset of chunk in a frame + struct chunk_t* free_chunk; + void *frame_base_addrs[MEMORY_POOL_DEPTH]; +}; + +struct chunk_t{ + struct chunk_t* next; + struct chunk_t* prev; +}; + +static struct frame_t frame_arr[FRAME_NUM]; +static struct flist_t flist_arr[MAX_LEVEL + 1]; +static struct memory_pool_t memory_pools[MEMORY_POOL_SIZE]; +static struct buddy_system_list_t buddy_system_list[MAX_BUDDY_SYSTEM_LIST]; + +#define FREE 0 +#define ALLOCATED 1 +#define LARGE_CONTIGUOUS 2 +#define RESERVED 3 + + +static void add_to_flist(struct flist_t* flist, struct frame_t* frame) +{ + struct frame_t *curr = flist->head; + while(curr) + { + if(curr->next)curr = curr->next; + else break; + } + if(curr) curr->next = frame; + else + { + // printf("\r\n[SYSTEM INFO] Add Frame: "); printf_int(frame->index); printf(" to Level: "); printf_int(frame->level); + flist->head = frame; + // printf("\r\n[SYSTEM INFO] Frame status: "); printf_int(frame->status); + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Leave add_to_flist"); +#endif +} + +static void remove_from_flist(struct flist_t* flist, struct frame_t* frame) +{ + struct frame_t *curr = flist->head; + struct frame_t *prev = NULL; + int next_index = frame_arr[frame->index + pow_2(frame->level) - 1].next == NULL \ + ? -1 : frame_arr[frame->index + pow_2(frame->level) - 1].next->index; + frame_arr[frame->index + pow_2(frame->level) - 1].next = NULL; + while(curr) + { + if(curr == frame) + { + if(prev) prev->next = next_index == -1 ? NULL : &frame_arr[next_index]; + else flist->head = next_index == -1 ? NULL : &frame_arr[next_index]; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Remove Frame: "); printf_int(frame->index); printf(" from flist Level: "); printf_int(frame->level); +#endif + // curr->next = NULL; + return; + } + prev = curr; + curr = curr->next; + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG ERROR] Frame Not Found in flist!"); +#endif + return; +} + +static uint64_t pow_2(uint32_t n) +{ + return 1 << n; +} + +void memory_reserve(uint64_t start, uint64_t end, char* msg) +{ +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Reserve Memory from: "); printf_hex(start); printf(" to: "); printf_hex(end); +#endif + uint32_t start_index = (start - 0) >> 12; + uint32_t end_index = (end - 0) >> 12; + +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Reserve Memory from Frame: "); printf_int(start_index); printf(" to Frame: "); printf_int(end_index); + printf(" for "); printf(msg); +#endif + if(start_index == end_index) + frame_arr[start_index].status = RESERVED; + else + for(int i=start_index; i= (uint64_t)buddy_system_list[i].base_addr) + { + return i; + } + else{ + if( addr >= (uint64_t)buddy_system_list[i].base_addr + && addr < (uint64_t)buddy_system_list[i+1].base_addr ) + { + return i; + } + } + } + return -1; +} + +void print_bslist(int argc, char* argv[]) +{ + printf("\r\n========== buddy system list =========="); + for(int i=0; ilevel = get_lower_bound_level(free_cnt); +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Free Start Frame: "); printf_int(free_start->index); + printf(", Level: "); printf_int(free_start->level); +#endif + buddy_system_list[bid].index = free_start->index; + buddy_system_list[bid].base_addr = (void*)(uint64_t)(MALLOC_START_ADDR + free_start->index * FRAME_SIZE); + buddy_system_list[bid++].max_level = free_start->level; + frame_arr[free_start->index + pow_2(free_start->level) - 1].next = NULL; + add_to_flist(&flist_arr[free_start->level], free_start); + is_free_start = 1; + free_cnt = 0; + free_start = NULL; + } + } + else{ + if(is_free_start){ + buddy_system_list[bid].base_addr = &frame_arr[i]; + frame_arr[i].status = FREE; + free_start = &frame_arr[i]; + is_free_start = 0; + free_cnt = 1; + } + else{ + frame_arr[i].status = LARGE_CONTIGUOUS; + frame_arr[i].level = 0; + free_cnt++; + } + } + if(i== FRAME_NUM-1 && is_free_start==0 && free_start != NULL){ + free_start->level = get_lower_bound_level(free_cnt); +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Free Start Frame: "); printf_int(free_start->index); + printf(", Level: "); printf_int(free_start->level); printf(" "); printf_int(free_cnt); +#endif + buddy_system_list[bid].index = free_start->index; + buddy_system_list[bid].base_addr = (void*)(uint64_t)(MALLOC_START_ADDR + free_start->index * FRAME_SIZE); + buddy_system_list[bid++].max_level = free_start->level; + frame_arr[free_start->index + pow_2(free_start->level) - 1].next = NULL; + add_to_flist(&flist_arr[free_start->level], free_start); + is_free_start = 1; + free_cnt = 0; + free_start = NULL; + } + } + +#ifdef BUDDY_SYSTEM_DEBUG + int tag = 0; + printf("\r\n[SYSTEM INFO] Buddy System List (Start Frame, base_addr, max_level): \n"); +#endif + for(int i=0; i "); +#endif + if(buddy_system_list[i].base_addr == NULL) break; +#ifdef BUDDY_SYSTEM_DEBUG + printf("( "); printf_int(buddy_system_list[i].index); printf(", "); + printf_hex((uint64_t)buddy_system_list[i].base_addr); printf(", "); + printf_int(buddy_system_list[i].max_level); printf(" )"); + tag = 1; +#endif + } +} + +void print_flist(int argc, char* argv[]) +{ + printf("\r\n========== free list =========="); + for(int i=0; i<=MAX_LEVEL; i++) + { +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Level: ");printf_int(i); +#endif + struct frame_t* frame = flist_arr[i].head; + int sign = 0; + while(frame != NULL) + { + if(frame->status == FREE) + { + if(sign == 0) { printf("\r\n[SYSTEM INFO] Level: "); printf_int(i); printf(", Frame: "); } + if(sign) printf("-> "); + printf_int(frame->index); + sign = 1; + // frame = frame->next; + frame = frame_arr[frame->index + pow_2(frame->level) - 1].next; +#ifdef BUDDY_SYSTEM_DEBUG + if(frame != NULL) {printf(" (expected next: "); printf_int(frame->index); printf(")");} +#endif + } + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Leave Level: ");printf_int(i); +#endif + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Leave print_flist"); +#endif +} + +void print_allocated(int argc, char* argv[]) +{ + printf("\r\n=========== allocated ==========="); + for(int i=0; inext; + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Allocated Frame Count: "); printf_int(cnt); printf(", Expected Count: "); printf_int(expected_cnt); + printf(" , level: "); printf_int(level); +#endif + assert(cnt == expected_cnt, "Allocated Frame Count Error!"); + i--; + } + } + printf("\n==============================="); +} + +static uint64_t round_size(uint64_t size) // return size to the nearest power of 2 +{ + uint64_t ret = 1; + while(ret < size) ret <<= 1; + return ret; +} + +static uint8_t get_level(uint32_t size) +{ + uint8_t level = 0; + for(int i=FRAME_SIZE; iindex; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] From Level: "); printf_int(from_level); + printf("\r\n[DEBUG] Start Index: "); printf_int(start_index); +#endif + remove_from_flist(&flist_arr[from_level], frame); + + while(from_level > level) // e.g. get level 4 frame, but only have level 6 frame + { + from_level--; + uint64_t level_size = pow_2(from_level); + uint32_t split_index = start_index + level_size; + + frame_arr[split_index].level = from_level; + frame_arr[split_index + level_size - 1].next = NULL; + + frame_arr[split_index].status = FREE; + // printf("\r\n[SYSTEM INFO] Split Frame: "); printf_int(split_index); printf(", Level: "); printf_int(from_level); + add_to_flist(&flist_arr[from_level], &frame_arr[split_index]); + } + frame->status = ALLOCATED; + frame->level = level; + frame_arr[start_index + pow_2(level) - 1].next = NULL; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Allocate Frame: "); printf_int(frame->index); +#endif + ret = (void*)(uint64_t)(MALLOC_START_ADDR + start_index * FRAME_SIZE); + break; + } + } + if(ret == NULL) + { + printf("\r\n[SYSTEM ERROR] No Enough Memory!"); + } +#ifdef BUDDY_SYSTEM_DEBUG + print_flist(0, NULL); + print_allocated(0, NULL); +#endif + return ret; +} + +static void* get_buddy_address(void* ptr, uint8_t level) +{ + return (void*)((uint64_t)ptr ^ (pow_2(level) * FRAME_SIZE)); +} + +static uint32_t get_buddy_index(void* ptr, uint8_t level) +{ + return ((uint64_t)get_buddy_address(ptr, level) - MALLOC_START_ADDR) >> 12; +} + +int bfree(void* ptr) +{ + uint8_t max_level = buddy_system_list[get_bid((uint64_t)ptr)].max_level; + uint32_t offset = buddy_system_list[get_bid((uint64_t)ptr)].index; + + struct frame_t* curr_frame = &frame_arr[((uint64_t)ptr - MALLOC_START_ADDR) >> 12]; + + switch(curr_frame->status) + { + case FREE: +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM ERROR] Frame Already Free!"); +#endif + return 1; + case LARGE_CONTIGUOUS: +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM ERROR] Frame is belong to Large Contiguous Frame!"); +#endif + return 1; + case RESERVED: +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM ERROR] Frame is Reserved!"); +#endif + return 1; + default: + break; + } + + // printf("\r\n[SYSTEM INFO] Free Frame Address: "); printf_hex((uint64_t)ptr); + // buddy address = curr address ^ (block size) + struct frame_t* buddy_frame = &frame_arr[get_buddy_index((ptr-offset*FRAME_SIZE), curr_frame->level)+offset]; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Free Frame: "); printf_int(curr_frame->index); printf(", Level: "); printf_int(curr_frame->level); + printf("\r\n[SYSTEM INFO] Buddy Frame: "); printf_int(buddy_frame->index); printf(", Level: "); printf_int(buddy_frame->level); +#endif + if(buddy_frame->status != FREE) + { +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Buddy Frame is not FREE!"); +#endif + curr_frame->status = FREE; + } + else + { +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Buddy Frame is Free!"); +#endif + } + while(buddy_frame->status == FREE && curr_frame->level < max_level) + { + curr_frame->status = FREE; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Merge Frame:"); printf_int(curr_frame->index); printf(" and Frame: "); printf_int(buddy_frame->index); + printf(" to Level: "); printf_int(curr_frame->level + 1); +#endif + +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] remove_from_flist: level: "); printf_int(buddy_frame->level); printf(" index: "); printf_int(buddy_frame->index); +#endif + remove_from_flist(&flist_arr[buddy_frame->level], buddy_frame); + + uint32_t merge_index; + if(buddy_frame->index < curr_frame->index) + { + merge_index = buddy_frame->index; + frame_arr[buddy_frame->index + pow_2(buddy_frame->level) - 1].next = curr_frame; + curr_frame->status = LARGE_CONTIGUOUS; + } + else + { + merge_index = curr_frame->index; + frame_arr[curr_frame->index + pow_2(curr_frame->level) - 1].next = buddy_frame; + buddy_frame->status = LARGE_CONTIGUOUS; + } + +#ifdef BUDDY_SYSTEM_DEBUG + printf(" with head frame: "); printf_int(merge_index); +#endif + + curr_frame = &frame_arr[merge_index]; + curr_frame->level++; + if(curr_frame->level == max_level) + { + break; + } + buddy_frame = &frame_arr[get_buddy_index((void*)(uint64_t)(MALLOC_START_ADDR + (merge_index-offset) * FRAME_SIZE), curr_frame->level) + offset]; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] New Frame: "); printf_int(curr_frame->index); printf(", Level: "); printf_int(curr_frame->level); + printf("\r\n[SYSTEM INFO] New Buddy Frame: "); printf_int(buddy_frame->index); printf(", Level: "); printf_int(buddy_frame->level); +#endif + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Add Frame:"); printf_int(curr_frame->index); printf(" to Level: "); printf_int(curr_frame->level); +#endif + add_to_flist(&flist_arr[curr_frame->level], curr_frame); + return 0; +} + +void bfree_wrapper(int argc, char *argv[]) +{ + if(argc != 2){ + printf("\nUsage: test_bfree "); + return; + } + uint64_t index = atoi(argv[1]); + if(index >= FRAME_NUM){ + printf("\nIndex out of range"); + return; + } + if(!bfree((void*)(MALLOC_START_ADDR + index * FRAME_SIZE))) + { + print_flist(0, NULL); + print_allocated(0, NULL); + } +} + +void memory_pool_init() +{ + for(int i=0; isize = size; + memory_pool->chunk_per_frame = FRAME_SIZE / size; +} + +static int get_memory_pool_id(uint64_t size) +{ + uint64_t r_size = round_size(size); + + if(r_size >= FRAME_SIZE) return -1; // larger than frame size, use general balloc + + for(int i=0; i= r_size) + { + return i; + } + else if(memory_pools[i].size == 0) + { +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Init New Memory Pool with chunk size: "); printf_int(r_size); +#endif + init_memory_pool_with_size(&memory_pools[i], r_size); + return i; + } + } + return -2; +} + +void* dynamic_alloc(uint64_t size) +{ + + int ret = get_memory_pool_id(size); + switch(ret) + { + case -1: + printf("\r\n[SYSTEM ERROR] Larger than Frame Size! Please use General balloc!"); + return 0; + case -2: + printf("\r\n[SYSTEM ERROR] No Enough Memory Pool! Please use General balloc!"); + return 0; + default: + break; + } + + struct memory_pool_t* memory_pool = &memory_pools[ret]; + + void* res = NULL; + + if(memory_pool->free_chunk != NULL) + { + res = memory_pool->free_chunk; + memzero_asm((uint64_t)res, memory_pool->size); + memory_pool->free_chunk = memory_pool->free_chunk->next; // point to the next free chunk +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] Allocate Chunk at address: "); printf_hex((uint64_t)res); printf(", in Frame: "); printf_int(((uint64_t)res - MALLOC_START_ADDR) >> 12); +#endif + return res; + } + + if(memory_pool->frame_used >= MEMORY_POOL_DEPTH * memory_pool->chunk_per_frame) + { + printf("\r\n[SYSTEM ERROR] No Enough Memory Pool Frame!"); + return res; + } + + if(memory_pool->chunk_used >= memory_pool->frame_used * memory_pool->chunk_per_frame) + { + if(memory_pool->frame_used == 0) + { +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] Create First Frame for Memory Pool with size: ");printf_int(memory_pool->size); +#endif + } + else + { +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] The Frame of Memory Pool with size: ");printf_int(memory_pool->size);printf(" is Full! "); + printf("Create a New Frame!"); +#endif + } + + void* new_frame = balloc(FRAME_SIZE); + memory_pool->frame_base_addrs[memory_pool->frame_used] = new_frame; + memory_pool->frame_used++; + memory_pool->chunk_offset = 0; + } + + // printf("\r\n[SYSTEM INFO] Allocate Chunk in Memory Pool with size: "); printf_int(memory_pool->size); + // printf(" in Frame: "); printf_int(((struct frame_t*)memory_pool->frame_base_addrs[memory_pool->frame_used - 1])->index); + + res = memory_pool->frame_base_addrs[memory_pool->frame_used - 1] + memory_pool->chunk_offset * memory_pool->size; +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] Allocate Chunk at address: "); printf_hex((uint64_t)res); printf(", in Frame: "); printf_int(((uint64_t)res - MALLOC_START_ADDR) >> 12); +#endif + memory_pool->chunk_offset++; + memory_pool->chunk_used++; + memzero_asm((uint64_t)res, memory_pool->size); + return res; +} + +int dfree(void* ptr) +{ + int memory_pool_index = -1; + for(int i=0; i>12; // 2^12 = 4096 = FRAME_SIZE + struct memory_pool_t* memory_pool = &memory_pools[memory_pool_index]; + + // check whether the chunk is already in the free chunk list + struct chunk_t* head_free_chunk = memory_pool->free_chunk; + while(head_free_chunk) + { + if(head_free_chunk == ptr) + { + printf("\r\n[SYSTEM ERROR] Chunk Already Free!"); + return 1; + } + head_free_chunk = head_free_chunk->next; + } +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] Free Chunk in Frame: "); printf_int(((uint64_t)ptr - MALLOC_START_ADDR) >>12); +#endif + memory_pool->chunk_used--; + struct chunk_t* last_free_chunk = memory_pool->free_chunk; + memory_pool->free_chunk = (struct chunk_t*)ptr; + memory_pool->free_chunk->next = last_free_chunk; +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] Free Chunk at address: "); printf_hex((uint64_t)ptr); +#endif + return 0; +} \ No newline at end of file diff --git a/lab07/kernel/src/boot.S b/lab07/kernel/src/boot.S new file mode 100644 index 000000000..30d694fb6 --- /dev/null +++ b/lab07/kernel/src/boot.S @@ -0,0 +1,48 @@ +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 + and x0, x0,#0xFF // Check processor id + cbz x0, master // if cpu_id == 0, then booting + b proc_hang // Otherwise, hang + +proc_hang: + b proc_hang + +master: + bl from_el2_to_el1 + +exception_table: + bl set_exception_vector_table + +bss_init: + adr x0, __bss_start + adr x1, __bss_size + bl memzero + + adr x1, _start + mov sp, x1 + bl main // jump to kernel_main c code + b proc_hang // should never come here + +memzero: + str xzr, [x0], #8 // xzr: a register holds zero + subs x1, x1, #8 + b.gt memzero + ret + +// adr: Load a label's relative address into the target register. + +set_exception_vector_table: + adr x0, exception_vector_table // get the base address of the exception vector table + msr vbar_el1, x0 // set the base address of the exception vector table + ret + +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x0 // msr: Status Register <-- Register (page 1924) + mov x0, 0x3c5 // EL1h (SPSel = 1) with interrupt disabled (D = 1, A = 1, I = 1, F = 1, M[3:0] = 5) + msr spsr_el2, x0 // Save the current processor's state + msr elr_el2, lr // Save the exception return address + eret // return to EL1 (use eret to return from the exception) \ No newline at end of file diff --git a/lab07/kernel/src/bootload.c b/lab07/kernel/src/bootload.c new file mode 100644 index 000000000..9c0e0ae2f --- /dev/null +++ b/lab07/kernel/src/bootload.c @@ -0,0 +1,43 @@ +#include "bootload.h" +#include "mini_uart.h" +#include "io.h" + +// uint64_t* BootHead = (uint64_t*)KernelAddr; +// uint64_t* CopyHead = (uint64_t*)BootAddr; +// uint64_t* bss_end = (uint64_t*)(&__bss_end); + +void reallocate() +{ + uint64_t* BootHead = (uint64_t*)KernelAddr; + uint64_t* CopyHead = (uint64_t*)BootAddr; + uint64_t* bss_end = (uint64_t*)(&__bss_end); + // int i = 0; + while(BootHead != bss_end){ + // printf("\n"); + // printf_hex(i); + // i++; + *CopyHead = *BootHead; + CopyHead++; + BootHead++; + } + printf("\nCopy done."); +} + +void load_kernel() +{ + unsigned int kernel_size = 0; + for(int i=0; i<4; i++){ + kernel_size <<= 8; + kernel_size |= (uart_recv() & 0xff); + } + + printf("\nKernel Size: "); + printf_hex(kernel_size); + printf("\n"); + + unsigned char* kernel = (unsigned char*)(0x80000); + unsigned char* kernel_ptr = kernel; + for(unsigned int i=0; ic_namesize, 16, 8); + int filesize = strtol(head->c_filesize, 16, 8); + + // char *filename = (void*)head + head_size; + char filename[256]; + strncpy(filename, (void*)head + head_size, namesize); + /* The above statement equal to the following: + char filename[256]; + strncpy(filename, (void*)head + head_size, namesize); + + In New ASCII format, the filename is followed by the header + */ + + if(strcmp(filename, "TRAILER!!!") == 0) break; + + printf("\r\n"); + printf(filename); + + uint32_t offset = head_size + namesize; + if(offset % 4 != 0) offset = ((offset/4 +1)*4); + if(filesize % 4 != 0) filesize = (filesize/4 +1)*4; + /* New ASCII format + header size + filename size must be multiple of 4 + filesize must be multiple of 4 + */ + + head = (void*)head + offset + filesize; + /* + Why (void*)head instead of head? + In C, when you add an integer to a pointer, + in this case, + head = head + (offset + filesize)*sizeof(cpio_newc_header) in practical. + But (offset + filesize) is the byte size, not the number of cpio_newc_header. + So, we need to cast head to void* to make it byte size. + */ + } +} + +void cpio_cat(int argc, char **argv) +{ + // printf("\nFilename: "); + // char input_filename[256]; + // readcmd(input_filename); + if(argc < 2){ + printf("\nUsage: cat "); + return; + } + char *input_filename = argv[1]; + +#ifndef QEMU + cpio_newc_header* head = (void*)(uint64_t)CPIO_START_ADDR_FROM_DT; +#else + cpio_newc_header* head = (void*)(uint64_t)CPIO_ADDR; +#endif + + uint32_t head_size = sizeof(cpio_newc_header); + + while(1) + { + int namesize = strtol(head->c_namesize, 16, 8); + int filesize = strtol(head->c_filesize, 16, 8); + + char *filename = (void*)head + head_size; + + uint32_t offset = head_size + namesize; + if(offset % 4 != 0) offset = ((offset/4 +1)*4); + + if(strcmp(filename, "TRAILER!!!") == 0){ + printf("\nFile not found"); + break; + } + else if(strcmp(filename, input_filename) == 0){ + /* The filedata is appended after filename */ + char *filedata = (void*)head + offset; + printf("\n"); + for(int i=0; i"); + return; + } + + char *input_filename = argv[1]; + +#ifndef QEMU + cpio_newc_header* head = (void*)(uint64_t)CPIO_START_ADDR_FROM_DT; +#else + cpio_newc_header* head = (void*)(uint64_t)CPIO_ADDR; +#endif + + uint32_t head_size = sizeof(cpio_newc_header); + while(1) + { + int namesize = strtol(head->c_namesize, 16, 8); + int filesize = strtol(head->c_filesize, 16, 8); + + char *filename = (void*)head + head_size; + + uint32_t offset = head_size + namesize; + if(offset % 4 != 0) offset = ((offset/4 +1)*4); + + if(strcmp(filename, "TRAILER!!!") == 0){ + printf("\nFile not found"); + break; + } + else if(strcmp(filename, input_filename) == 0){ + /* The filedata is appended after filename */ + char *filedata = (void*)head + offset; + char *user_program_addr = (void*)(uint64_t)USER_START_ADDR; + for(int i=0; ic_namesize, 16, 8); + int filesize = strtol((*head)->c_filesize, 16, 8); + // *c_mode = (*head)->c_mode; + + uint32_t head_size = sizeof(cpio_newc_header); + + char *filename = (void*)(*head) + head_size; + *pathname = filename; + + uint32_t offset = head_size + namesize; + if(offset % 4 != 0) offset = ((offset/4 +1)*4); + + if(strcmp(filename, "TRAILER!!!") == 0){ + // do nothing + } + else{ + /* The filedata is appended after filename */ + *filedata = (void*)(*head) + offset; + ret = 0; + } + + if(filesize % 4 != 0) filesize = (filesize/4 +1)*4; + *head = (void*)(*head) + offset + filesize; + return ret; +} + +#ifndef QEMU +void initramfs_callback(char* node_name, char* property_name, fdt_prop* prop) +{ + // reference: https://stackoverflow.com/questions/73974443/how-does-the-linux-kernel-know-about-the-initrd-when-booting-with-a-device-tree + if((strcmp(node_name, "chosen") == 0) && (strcmp(property_name, "linux,initrd-start") == 0)){ + void *data = (void*)prop + sizeof(fdt_prop); + CPIO_START_ADDR_FROM_DT = endian_swap(*(uint32_t*)data); + printf("\nInitramfs Start Address from DT: "); + printf_hex(CPIO_START_ADDR_FROM_DT); + } + if((strcmp(node_name, "chosen") == 0) && (strcmp(property_name, "linux,initrd-end") == 0)){ + void *data = (void*)prop + sizeof(fdt_prop); + CPIO_END_ADDR_FROM_DT = endian_swap(*(uint32_t*)data); + printf("\nInitramfs End Address from DT: "); + printf_hex(CPIO_END_ADDR_FROM_DT); + } +} +#endif \ No newline at end of file diff --git a/lab07/kernel/src/dev_framebuffer.c b/lab07/kernel/src/dev_framebuffer.c new file mode 100644 index 000000000..ba0745f86 --- /dev/null +++ b/lab07/kernel/src/dev_framebuffer.c @@ -0,0 +1,134 @@ +#include "vfs.h" +#include "dev_framebuffer.h" +#include "io.h" +#include "alloc.h" +#include "mailbox.h" +#include "peripherals/mailbox.h" +#include "string.h" + + +extern void disable_irq(); +extern void enable_irq(); + +//The following code is for mailbox initialize used in lab7. +unsigned int width, height, pitch, isrgb; /* dimensions and channel order */ +unsigned char *lfb; /* raw frame buffer address */ + +struct file_operations dev_framebuffer_operations = { + dev_framebuffer_write, + 0, // read + dev_framebuffer_open, + dev_framebuffer_close, + 0, // getsize + dev_framebuffer_lseek64 +}; + +unsigned int __attribute__((aligned(16))) mbox_s[36]; + +int dev_framebuffer_register() +{ + printf("Registering framebuffer device..."); + //The following code is for mailbox initialize used in lab7. + mbox_s[0] = 35 * 4; + mbox_s[1] = TAG_REQUEST_CODE; + + mbox_s[2] = 0x48003; // set phy wh + mbox_s[3] = 8; + mbox_s[4] = 8; + mbox_s[5] = 1024; // FrameBufferInfo.width + mbox_s[6] = 768; // FrameBufferInfo.height + + mbox_s[7] = 0x48004; // set virt wh + mbox_s[8] = 8; + mbox_s[9] = 8; + mbox_s[10] = 1024; // FrameBufferInfo.virtual_width + mbox_s[11] = 768; // FrameBufferInfo.virtual_height + + mbox_s[12] = 0x48009; // set virt offset + mbox_s[13] = 8; + mbox_s[14] = 8; + mbox_s[15] = 0; // FrameBufferInfo.x_offset + mbox_s[16] = 0; // FrameBufferInfo.y.offset + + mbox_s[17] = 0x48005; // set dembox_sh + mbox_s[18] = 4; + mbox_s[19] = 4; + mbox_s[20] = 32; // FrameBufferInfo.dembox_sh + + mbox_s[21] = 0x48006; // set pixel order + mbox_s[22] = 4; + mbox_s[23] = 4; + mbox_s[24] = 1; // RGB, not BGR preferably + + mbox_s[25] = 0x40001; // get framebuffer, gets alignment on request + mbox_s[26] = 8; + mbox_s[27] = 8; + mbox_s[28] = 4096; // FrameBufferInfo.pointer + mbox_s[29] = 0; // FrameBufferInfo.size + + mbox_s[30] = 0x40008; // get pitch + mbox_s[31] = 4; + mbox_s[32] = 4; + mbox_s[33] = 0; // FrameBufferInfo.pitch + + mbox_s[34] = MBOX_TAG_LAST; + + // this might not return exactly what we asked for, could be + // the closest supported resolution instead + if (mailbox_call_s(MBOX_CH_PROP, mbox_s) && mbox_s[20] == 32 && mbox_s[28] != 0) + { + mbox_s[28] &= 0x3FFFFFFF; // convert GPU address to ARM address + width = mbox_s[5]; // get actual physical width + height = mbox_s[6]; // get actual physical height + pitch = mbox_s[33]; // get number of bytes per line + isrgb = mbox_s[24]; // get the actual channel order + lfb = ((void *)((unsigned long)mbox_s[28])); // raw frame buffer address + } + else + { + printf("Unable to set screen resolution to 1024x768x32\n"); + } + + return register_dev(&dev_framebuffer_operations); +} + +int dev_framebuffer_write(struct file *file, const void *buf, size_t len) +{ + enable_irq(); + if (len + file->f_pos > pitch * height) + { + printf("\r\n[ERROR] Invlaid Write framebuffer!"); + len = pitch * height - file->f_pos; + } + for(int i=0; if_pos))[i] = ((char*)buf)[i]; + } + file->f_pos += len; + disable_irq(); + return len; +} + +int dev_framebuffer_open(struct vnode *file_node, struct file **target) +{ + printf("\r\n[INFO] Opening framebuffer device..."); + (*target)->f_pos = 0; + (*target)->vnode = file_node; + (*target)->f_ops = &dev_framebuffer_operations; + return 0; +} + +int dev_framebuffer_close(struct file *file) +{ + dfree(file); + return 0; +} + +long dev_framebuffer_lseek64(struct file *file, long offset, int whence) +{ + if (whence == SEEK_SET) + { + file->f_pos = offset; + return file->f_pos; + } + return -1; +} diff --git a/lab07/kernel/src/dev_uart.c b/lab07/kernel/src/dev_uart.c new file mode 100644 index 000000000..d0eddfab8 --- /dev/null +++ b/lab07/kernel/src/dev_uart.c @@ -0,0 +1,58 @@ +#include "dev_uart.h" +#include "mini_uart.h" +#include "alloc.h" + +struct file_operations dev_file_operations = { + dev_uart_write, + dev_uart_read, + dev_uart_open, + dev_uart_close, + 0 // getsizeq +}; + + +int dev_uart_register() +{ + uart_send_string("\r\n[INFO] Registering uart device..."); + return register_dev(&dev_file_operations); +} + +int dev_uart_write(struct file *file, const void *buf, size_t len) +{ + uart_send_string("\r\n[INFO] Writing to console..."); + const char *cbuf = buf; + for (int i = 0; i < len;i++) + { + uart_send(cbuf[i]); + } + return len; +} + +int dev_uart_read(struct file *file, void *buf, size_t len) +{ + uart_send_string("\r\n[INFO] Reading from uart..."); + for (int i = 0; i < len; i++) + { + ((char*)buf)[i] = uart_recv(); + } + return len; +} + +int dev_uart_open(struct vnode *file_node, struct file **target) +{ + uart_send_string("\r\n[INFO] Opening uart device..."); + (*target)->vnode = file_node; + (*target)->f_ops = &dev_file_operations; + return 0; +} + +int dev_uart_close(struct file *file) +{ + dfree(file); + return 0; +} + +int dev_uart_op_deny() +{ + return -1; +} diff --git a/lab07/kernel/src/devicetree.c b/lab07/kernel/src/devicetree.c new file mode 100644 index 000000000..cfb61bfe8 --- /dev/null +++ b/lab07/kernel/src/devicetree.c @@ -0,0 +1,94 @@ +#include "devicetree.h" +#include "string.h" +#include "io.h" +#include "type.h" + +void fdt_traverse(void(*callback_func)(char*, char*, fdt_prop*)) +{ + fdt_header *dt_header = (fdt_header*)(*DTB_ADDR); + printf("\nDTB Address (Function): "); + printf_hex((uint64_t)(void*)(dt_header)); + + uint32_t dt_struct_off = endian_swap(dt_header->off_dt_struct); + uint32_t dt_string_off = endian_swap(dt_header->off_dt_strings); + + void* dt_struct_addr = (void*)*DTB_ADDR + dt_struct_off; + char* dt_string_addr = (void*)*DTB_ADDR + dt_string_off; + + + printf("\nDT String Address: "); + printf_hex((uint64_t)(void*)dt_string_addr); + printf("\nDT Struct Address: "); + printf_hex((uint64_t)(void*)dt_struct_addr); + + printf("\nMagic: "); + printf_hex(endian_swap(dt_header->magic)); + if(dt_header->magic == (uint32_t)0xd00dfeed) + { + printf("Magic Failed\n"); + return; + } + + + char* node_name; + char* prop_name; + + while(1) + { + uint32_t token = endian_swap((*(uint32_t*)dt_struct_addr)); + + switch (token) + { + case FDT_BEGIN_NODE: // It shall be followed by the node’s unit name as extra data. + { + node_name = (char*)dt_struct_addr + 4; // tage size is 32bits = 4bytes + uint32_t size = strlen(node_name); // size of node name + uint32_t offset = 4 + size + 1; + + if(offset % 4 !=0) offset = ((offset/4 + 1)*4); // align to 4bytes (32bits) + dt_struct_addr = dt_struct_addr + offset; + + break; + } + case FDT_END_NODE: //This token has no extra data; so it is followed immediately by the next token + { + dt_struct_addr = dt_struct_addr + 4; break; + } + case FDT_PROP: + { + fdt_prop* prop_ptr = (fdt_prop*)(dt_struct_addr + 4); + uint32_t offset = 4 + sizeof(fdt_prop) + endian_swap(prop_ptr->len); + + if(offset % 4 != 0) offset = ((offset/4 + 1)*4); + dt_struct_addr = dt_struct_addr + offset; + + prop_name = (void*)dt_string_addr + endian_swap(prop_ptr->nameoff); + + callback_func(node_name, prop_name, prop_ptr); + + break; + } + case FDT_NOP: + { + dt_struct_addr = dt_struct_addr + 4; break; + } + case FDT_END: + { + dt_struct_addr = dt_struct_addr + 4; break; + } + default: + return; + } + } + +} + +// big endian to little endian +uint32_t endian_swap(uint32_t value) +{ + uint32_t ret = 0; + uint8_t* ptr = (void*)&value; + ret = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]; + return ret; +} + diff --git a/lab07/kernel/src/entry.S b/lab07/kernel/src/entry.S new file mode 100644 index 000000000..8d7d4fd22 --- /dev/null +++ b/lab07/kernel/src/entry.S @@ -0,0 +1,235 @@ +#include "entry.h" +#include "sys.h" +#include "peripherals/irq.h" + +.section ".text" + +.global set_exception_vector_table + + +// save general registers to stack +.macro save_all el + //bl save_all_debug + sub sp, sp, 16*17 + stp x0, x1, [sp ,16 * 0] // storing the contents of x0 and x1 to the address pointed by the stack pointer sp with an offset of 16 bytes + stp x2, x3, [sp ,16 * 1] // stp: Store Pair and it's used to store a pair of 64-bit (8-byte) registers to memory + stp x4, x5, [sp ,16 * 2] + stp x6, x7, [sp ,16 * 3] + stp x8, x9, [sp ,16 * 4] + stp x10, x11, [sp ,16 * 5] + stp x12, x13, [sp ,16 * 6] + stp x14, x15, [sp ,16 * 7] + stp x16, x17, [sp ,16 * 8] + stp x18, x19, [sp ,16 * 9] + stp x20, x21, [sp ,16 * 10] + stp x22, x23, [sp ,16 * 11] + stp x24, x25, [sp ,16 * 12] + stp x26, x27, [sp ,16 * 13] + stp x28, x29, [sp ,16 * 14] + + .if \el == 0 // using two distinct stack pointers for EL0 and EL1 + mrs x21, sp_el0 + .else + add x21, sp, 16*17 // using the same stack pointer for EL1 & sp will be switched by the cpu_switch_to function + .endif + + mrs x22, elr_el1 + mrs x23, spsr_el1 + + stp x30, x21, [sp ,16 * 15] + stp x22, x23, [sp ,16 * 16] +.endm + +// load general registers from stack +.macro load_all el + //bl load_all_debug + ldp x22, x23, [sp ,16 * 16] + ldp x30, x21, [sp ,16 * 15] + + .if \el == 0 + msr sp_el0, x21 + .endif + + msr elr_el1, x22 + msr spsr_el1, x23 + + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + ldr x30, [sp, 16 * 15] + add sp, sp, 16*17 +.endm + +.macro ventry label + b \label // branch to a handler function. + .align 7 // entry size is 0x80, .align will pad 0 +.endm + + +.global exception_vector_table +.align 11 // vector table should be aligned to 0x800 (2^11 = 0x1000_0000_0000 = 0x800) +exception_vector_table: + + //========================================================== + // Exception from the current EL while using SP_EL0 (exception level not changed) + + ventry SYNC_EL1T /* Synchronous EL1t */ + ventry IRQ_EL1T /* IRQ or vIRQ EL1t */ + ventry FIQ_EL1T /* FIQ or vFIQ EL1t */ + ventry SERROR_EL1T /* SError or vSError EL1t */ + + + //========================================================== + // Exception from the current EL while using SP_ELx (exception level not changed) + + ventry SYNC_EL1H /* Synchronous EL1h */ + ventry EL1_IRQ /* IRQ or vIRQ EL1h */ + ventry FIQ_EL1H /* FIQ or vFIQ EL1h */ + ventry SERROR_EL1H /* SError or vSError EL1h */ + + //========================================================== + // Exception from a lower EL and all lower ELs are AArch64 (Moves to higher exception level) + + ventry EL0_SYNC /* Synchronous EL0t */ + ventry EL0_IRQ /* IRQ or vIRQ EL0t */ + ventry FIQ_64_EL0T /* FIQ or vFIQ EL0t */ + ventry SERROR_64_EL0T /* SError or vSError EL0t */ + //========================================================== + // Exception from a lower EL and all lower ELs are AArch32 Moves to higher exception level + + ventry SYNC_32_EL0T /* Synchronous 32-bit EL0t */ + ventry IRQ_32_EL0T /* IRQ or vIRQ 32-bit EL0t */ + ventry FIQ_32_EL0T /* FIQ or vFIQ 32-bit EL0t */ + ventry SERROR_32_EL0T /* SError or vSError 32-bit EL0t */ + + +.macro handle_invalid_entry el, type + save_all \el + mov x0, #\type + mrs x1, spsr_el1 + mrs x2, elr_el1 + mrs x3, esr_el1 + bl invalid_exception_entry + b error_hang +.endm + +SYNC_EL1T: + handle_invalid_entry 1, SYNC_INVALID_EL1t + +IRQ_EL1T: + handle_invalid_entry 1, IRQ_INVALID_EL1t + +FIQ_EL1T: + handle_invalid_entry 1, FIQ_INVALID_EL1t + +SERROR_EL1T: + handle_invalid_entry 1, ERROR_INVALID_EL1t + +SYNC_EL1H: + handle_invalid_entry 1, SYNC_INVALID_EL1h + +EL1_IRQ: + save_all 1 + bl irq_handler + load_all 1 + eret + +FIQ_EL1H: + handle_invalid_entry 1, FIQ_INVALID_EL1h + +SERROR_EL1H: + handle_invalid_entry 1, ERROR_INVALID_EL1h + +EL0_SYNC: //[TODO] + save_all 0 + mrs x25, esr_el1 + lsr x24, x25, #ESR_ELx_EC_SHIFT + cmp x24, #ESR_ELx_EC_SVC64 // check if the exception is a system call + b.eq el0_svc + handle_invalid_entry 0, SYNC_ERROR // if not a system call, handle the exception + +EL0_IRQ: + save_all 0 + bl irq_handler + load_all 0 + eret + +FIQ_64_EL0T: + handle_invalid_entry 0, FIQ_INVALID_EL0_64 + +SERROR_64_EL0T: + handle_invalid_entry 0, ERROR_INVALID_EL0_64 + +SYNC_32_EL0T: + handle_invalid_entry 0, SYNC_INVALID_EL0_32 + +IRQ_32_EL0T: + handle_invalid_entry 0, IRQ_INVALID_EL0_32 + +FIQ_32_EL0T: + handle_invalid_entry 0, FIQ_INVALID_EL0_32 + +SERROR_32_EL0T: + handle_invalid_entry 0, ERROR_INVALID_EL0_32 + + +// creates alias +sc_nr .req x25 // number of system calls +scno .req x26 // syscall number +stbl .req x27 // syscall table pointer + +.global from_el1_to_el0 +from_el1_to_el0: + mov x2, 0x3c0 + msr spsr_el1, x2 + msr sp_el0, x1 // pass the stack pointer address from arg + msr elr_el1, x0 // pass the program's start address from arg + eret + +.global ret_from_fork // entry point for executing the process +ret_from_fork: + bl schedule_tail // preemptive enable + cbz x19, ret_to_user + mov x0, x20 + blr x19 //should never return, except for kp_to_user + +ret_to_user: + bl disable_irq + load_all 0 + eret + +el0_svc: + adr stbl, sys_call_table // load syscall table pointer + uxtw scno, w8 // syscall number in w8, uxtw: Unsigned Extend Word + mov sc_nr, #__NR_syscalls + bl enable_irq + cmp scno, sc_nr // check upper syscall limit + b.hs ni_sys // hs: higher or same + + ldr x16, [stbl, scno, lsl #3] // address in the syscall table, x16 = stbl[scno] + blr x16 // call sys_* routine + b ret_from_syscall + +ret_from_syscall: + bl disable_irq + str x0, [sp, #S_X0] // returned x0 (overwritten the original x0 value on the stack) + load_all 0 + eret + +ni_sys: + handle_invalid_entry 0, SYSCALL_ERROR + +error_hang: + b error_hang \ No newline at end of file diff --git a/lab07/kernel/src/fork.c b/lab07/kernel/src/fork.c new file mode 100644 index 000000000..7fb5c823f --- /dev/null +++ b/lab07/kernel/src/fork.c @@ -0,0 +1,148 @@ +#include "fork.h" +#include "alloc.h" +#include "schedule.h" +#include "io.h" +#include "mm.h" +#include "vfs.h" +#include "string.h" + +extern void ret_from_fork(void); +extern int nr_tasks; +extern struct task_struct * task[NR_TASKS]; +extern void memzero(unsigned long begin, unsigned long len); + +int copy_process( + unsigned long flags, + unsigned long fn, + unsigned long arg, + unsigned long stack) +{ + preempt_disable(); + struct task_struct *p; + + int pid = -1; + for(pid = 0; pid< NR_TASKS; pid++) + if(task[pid] == NULL) break; + if(pid == -1) + { + printf("\r\n[ERROR] Thread limit exceeded"); + goto finish; + } + // p = (struct task_struct *) balloc(sizeof(struct task_struct)); + p = (struct task_struct *) balloc(THREAD_SIZE); + printf("\r\n[INFO] Process allocated at "); printf_hex((unsigned long)p); + if (!p) + return -1; + + struct pt_regs *childregs = task_pt_regs(p); + memzero_asm((unsigned long)childregs, sizeof(struct pt_regs)); + memzero_asm((unsigned long)&p->cpu_context, sizeof(struct cpu_context)); + + // clear the file descriptor table + p->fd_table.count = 0; + for(int i=0; ifd_table.fds[i] = NULL; + + // create stdin, stdout, stderr + // p->fd_table.fds[0] = (struct file*)dynamic_alloc(sizeof(struct file)); + // p->fd_table.fds[1] = (struct file*)dynamic_alloc(sizeof(struct file)); + // p->fd_table.fds[2] = (struct file*)dynamic_alloc(sizeof(struct file)); + vfs_open("/dev/uart", O_RW, &p->fd_table.fds[0]); + vfs_open("/dev/uart", O_RW, &p->fd_table.fds[1]); + vfs_open("/dev/uart", O_RW, &p->fd_table.fds[2]); + // printf("\r\n[INFO] File descriptor table created"); + // printf("\r\n[INFO] File descriptor 0: "); printf_hex((unsigned long)p->fd_table.fds[0]); + // printf("\r\n[INFO] File descriptor 1: "); printf_hex((unsigned long)p->fd_table.fds[1]); + // printf("\r\n[INFO] File descriptor 2: "); printf_hex((unsigned long)p->fd_table.fds[2]); + + if(flags & PF_KTHREAD) // is a kernel thread + { + p->cpu_context.x19 = fn; + p->cpu_context.x20 = arg; + } + else + { + struct pt_regs *cur_regs = task_pt_regs(current); + + // copy the current process state to the new process + for(int i=0; iregs[0] = 0; // child process return value + // next sp for the new task is set to the top of the new user stack + // save the stack pointer to cleanup the stack when task finishes + unsigned long stack_used = current->stack + THREAD_SIZE - cur_regs->sp; + + // copy the stack to the new process + childregs->sp = stack + THREAD_SIZE - stack_used; + for(int i=0; isp)[i] = ((char*)cur_regs->sp)[i]; + + p->stack = stack; + + // copy the file descriptor table + p->fd_table.count = current->fd_table.count; + for(int i=0; ifd_table.fds[i] != NULL){ + p->fd_table.fds[i] = (struct file *)dynamic_alloc(sizeof(struct file)); + p->fd_table.fds[i] = current->fd_table.fds[i]; + } + } + } + p->flags = flags; + p->priority = current->priority; + p->state = TASK_RUNNING; + p->counter = p->priority; + p->preempt_count = 1; //disable preemtion until schedule_tail + strcpy(p->cwd, current->cwd); + + + p->cpu_context.pc = (unsigned long)ret_from_fork; // for the first time, pc is set to ret_from_fork + p->cpu_context.sp = (unsigned long)childregs; + + task[pid] = p; + p->pid = pid; + printf("\r\n[INFO] Process created with pid: "); printf_int(pid); +finish: + preempt_enable(); + return pid; +} + +int move_to_user_mode(unsigned long pc) +{ + struct pt_regs *regs = task_pt_regs(current); // get current process state + // memzero_asm((unsigned long)regs, sizeof(struct pt_regs)); + + regs->pc = pc; // point to the function that need to be executed in user mode + regs->pstate = PSR_MODE_EL0t; // EL0t is user state + + unsigned long stack = (unsigned long)balloc(THREAD_SIZE); //allocate new user stack + memzero_asm(stack, THREAD_SIZE); + + if (!stack) { // if stack allocation failed + return -1; + } + + // allocate stack for user process + // set sp to the top of the stack + regs->sp = stack + THREAD_SIZE; + current->stack = stack; + return 0; +} + + +// calculate the location of pt_regs in the task_struct +// task_struct is allocated at the end of the stack +// pt_regs is allocated at the top of the task_struct +struct pt_regs * task_pt_regs(struct task_struct *tsk){ + unsigned long p = (unsigned long)tsk + THREAD_SIZE - sizeof(struct pt_regs); + return (struct pt_regs *)p; +} + +void kp_user_mode(unsigned long func){ // Kernel process(func pass by argu) to user mode + printf("\r\nKernel process started. Switching to user mode..."); + int err = move_to_user_mode(func); + if (err < 0){ + printf("Error while moving process to user mode\n\r"); + } +} diff --git a/lab07/kernel/src/initramfs.c b/lab07/kernel/src/initramfs.c new file mode 100644 index 000000000..3e05dd72a --- /dev/null +++ b/lab07/kernel/src/initramfs.c @@ -0,0 +1,256 @@ +#include "initramfs.h" +#include "alloc.h" +#include "errno.h" +#include "io.h" +#include "string.h" +#include "lib.h" +#include "cpio.h" + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +struct vnode_operations *initramfs_v_ops; +struct file_operations *initramfs_f_ops; + + +static struct vnode* initramfs_create_vnode(const char *name, int type, struct vnode *parent); +static int isFileInSubDir(const char* pathname); + +int initramfs_setup_mount(struct filesystem* fs, struct mount **mount) // mount the filesystem to the mount point +{ + (*mount)->fs = fs; + (*mount)->root = initramfs_create_vnode("/", DIR_NODE, NULL); + +#ifndef QEMU + cpio_newc_header* head = (void*)(uint64_t)CPIO_START_ADDR_FROM_DT; +#else + cpio_newc_header* head = (void*)(uint64_t)CPIO_ADDR; +#endif + // vfs_chdir("/initramfs"); + while(1) + { + char* pathname; + char* filedata; + int filesize = strtol(head->c_filesize, 16, 8); + char c_mode[5]; + strncpy(c_mode, head->c_mode, 5); + int ret = cpio_newc_parser(&head, &pathname, &filedata); + if(ret == 1)break; + if(filesize > INITRAMFS_MAX_FILE){ + printf("\r\n[SYSTEM INFO] File: "); printf(pathname); printf(" is too large to fit in initramfs"); + continue; + } + // printf("\r\n[INITRAMFS INFO] Mount Archive: "); printf(pathname); printf("\t, cmode: "); printf(c_mode); + struct initramfs_internal *root_internal = (struct initramfs_internal*)(*mount)->root->internal; + + if(!strcmp(c_mode, "00008")){ // file + if(!strcmp(pathname, ".") || !strcmp(pathname, "..") || isFileInSubDir(pathname))continue; + struct vnode *filevnode = initramfs_create_vnode(pathname, FILE_NODE, (*mount)->root); + struct initramfs_internal *fileinode = (struct initramfs_internal*)filevnode->internal; + strncpy(fileinode->data, filedata, filesize); + fileinode->size = 0; + fileinode->filesize = filesize; + root_internal->children[root_internal->size++] = filevnode; + printf("\r\n[INITRAMFS INFO] Mount Archive: "); printf(pathname); + for(int i=0; i<10-strlen(pathname); i++) printf(" "); + printf("\t, cmode: "); printf(c_mode); + printf("\t, size: "); printf_hex(filesize); + } + else if(!strcmp(c_mode, "00004")){ // directory + // cannot create directory in initramfs + } + else{ + printf("\r\n[ERROR] Unsupported file type"); + return -1; + } + } + printf("\r\n[INITRAMFS INFO] Mounting complete"); + + return 0; +} + +static struct vnode* initramfs_create_vnode(const char *name, int type, struct vnode *parent) +{ + struct initramfs_internal *internal = (struct initramfs_internal*)dynamic_alloc(sizeof(struct initramfs_internal)); + + if(sizeof(name) > COMPONENT_SIZE){ + printf("\r\n[ERROR] File name too long"); + return NULL; + } + internal->name = (char*)dynamic_alloc(COMPONENT_SIZE); + strcpy(internal->name, name); + internal->size = 0; + if(type == FILE_NODE){ + internal->data = (char*)balloc(INITRAMFS_MAX_FILE); + } + else{ + internal->data = NULL; + } + internal->type = type; + // internal->parent = parent; + // internal->next = NULL; + for(int i=0; ichildren[i] = NULL; + } + struct vnode *vnode = (struct vnode*)dynamic_alloc(sizeof(struct vnode)); + vnode->parent = parent; + vnode->mount = NULL; + vnode->v_ops = initramfs_v_ops; + vnode->f_ops = initramfs_f_ops; + vnode->internal = internal; + return vnode; +} + +int initramfs_register() +{ + // check if tmpfs already registered + int i=0; + for(; ilookup = initramfs_lookup; + initramfs_v_ops->list = initramfs_list; + initramfs_v_ops->create = initramfs_create; + initramfs_v_ops->mkdir = initramfs_mkdir; + + initramfs_f_ops->open = initramfs_open; + initramfs_f_ops->read = initramfs_read; + initramfs_f_ops->write = initramfs_write; + initramfs_f_ops->close = initramfs_close; + initramfs_f_ops->getsize = initramfs_getsize; + initramfs_f_ops->lseek64 = NULL; + + return 0; +} + +int initramfs_list(struct vnode* dir_node) +{ + // 1. List all the files in the directory + // 2. Return error code if fails + + printf("\r\n[INITRAMFS LIST]"); + struct initramfs_internal *internal = (struct initramfs_internal*)dir_node->internal; + + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot list in a file"); + return LERROR; + } + + printf("\r\nName \tType"); + printf("\r\n-----------------------"); + for(int i=0; isize; i++){ + struct initramfs_internal *child_internal = (struct initramfs_internal*)internal->children[i]->internal; + printf("\r\n"); printf(child_internal->name); for(int j=0; j<15-strlen(child_internal->name); j++) printf(" "); + printf("\t"); printf(child_internal->type == FILE_NODE ? "FILE" : "DIR"); + } + return 0; +} + +int initramfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // 1. Lookup the vnode in the directory + // 2. Return error code if fails + struct initramfs_internal *internal = (struct initramfs_internal*)dir_node->internal; + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot lookup in a file"); + return LERROR; + } + + for(int i=0; ichildren[i]->internal; + if(internal->children[i] != NULL && !strcmp(child_internal->name, component_name)){ + *target = internal->children[i]; + return 0; + } + } + // printf("[ERROR] File not found\n"); + return LERROR; +} + +int initramfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // Alawys return -1 because we are not implementing mkdir in initramfs + return -1; +} + +int initramfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // Alawys return -1 because we are not implementing create in initramfs + return -1; +} + +int initramfs_close(struct file* file) +{ + // 1. release the file handle + // 2. Return error code if fails + if(file == NULL){ + printf("\r\n[ERROR] File pointer cannot be NULL"); + return CERROR; + } + return 0; // vfs_close will free the file pointer +} + +int initramfs_open(struct vnode* file_node, struct file** target) +{ + // 1. Allocate file handle + // 2. Return error code if fails + struct file *file = (struct file*)dynamic_alloc(sizeof(struct file)); + file->vnode = file_node; + file->f_pos = 0; + *target = file; + return 0; +} + +int initramfs_read(struct file* file, void* buf, size_t len) +{ + struct vnode *vnode = file->vnode; + struct initramfs_internal *internal = (struct initramfs_internal*)vnode->internal; + if(internal->type == DIR_NODE){ + printf("\r\n[ERROR] Cannot read a directory"); + return RERROR; + } + + size_t readable_size = min(len, internal->filesize - file->f_pos); + + // memory copy + for(int i=0; idata[file->f_pos + i]; + } + file->f_pos += readable_size; + return readable_size; +} + +int initramfs_write(struct file* file, const void* buf, size_t len) +{ + //cannot write on initframfs + return -1; +} + + +int initramfs_getsize(struct vnode* vnode) +{ + struct initramfs_internal *internal = (struct initramfs_internal*)vnode->internal; + return internal->filesize; +} + +static int isFileInSubDir(const char* pathname) +{ + for(int i=0; i=0; i-=4){ + int tmp = (td >> i) & 0xf; + if(tmp < 10){ + printfc('0'+tmp); + } + else{ + printfc('a'+tmp-10); + } + } +} + +void printf_int(const int d) +{ + int td = d; + if(td < 0){ + printf("-"); + td = -td; + } + if(td == 0){ + printf("0"); + return; + } + int digits[10]; + int cnt = 0; + while(td > 0){ + digits[cnt++] = td % 10; + td /= 10; + } + for(int i=cnt-1; i>=0; i--){ + printfc('0'+digits[i]); + } +} + +char read_char() +{ + char c = uart_recv(); + return c; +} diff --git a/lab07/kernel/src/irq.S b/lab07/kernel/src/irq.S new file mode 100644 index 000000000..ee0531406 --- /dev/null +++ b/lab07/kernel/src/irq.S @@ -0,0 +1,11 @@ +.section ".text" + +.global enable_irq +enable_irq: + msr daifclr, 0xf + ret + +.global disable_irq +disable_irq: + msr daifset, 0xf + ret \ No newline at end of file diff --git a/lab07/kernel/src/irq.c b/lab07/kernel/src/irq.c new file mode 100644 index 000000000..21d7686f1 --- /dev/null +++ b/lab07/kernel/src/irq.c @@ -0,0 +1,84 @@ +#include "peripherals/irq.h" +#include "peripherals/mini_uart.h" + +#include "irq.h" +#include "io.h" + +extern void enable_irq(); +extern void disable_irq(); +extern void irq_timer_handler(); + +static char *entry_error_messages[] = { + "SYNC_INVALID_EL1t", + "IRQ_INVALID_EL1t", + "FIQ_INVALID_EL1t", + "ERROR_INVALID_EL1T", + + "SYNC_INVALID_EL1h", + "IRQ_INVALID_EL1h", + "FIQ_INVALID_EL1h", + "ERROR_INVALID_EL1h", + + "SYNC_INVALID_EL0_64", + "IRQ_INVALID_EL0_64", + "FIQ_INVALID_EL0_64", + "ERROR_INVALID_EL0_64", + + "SYNC_INVALID_EL0_32", + "IRQ_INVALID_EL0_32", + "FIQ_INVALID_EL0_32", + "ERROR_INVALID_EL0_32", + + "SYNC_ERROR", + "SYSCALL_ERROR" +}; + +static void show_debug_msg(int type, unsigned long spsr, unsigned long elr, unsigned long esr) +{ + printf("\r\n"); + printf(entry_error_messages[type]); + printf(", SPSR: "); + printf_hex(spsr); + printf(", ELR: "); + printf_hex(elr); + printf(", ESR: "); + printf_hex(esr); +} + +void irq_handler(int type, unsigned long spsr, unsigned long elr, unsigned long esr) +{ + disable_irq(); + + unsigned int irq = *CORE0_IRQ_SOURCE; + switch(irq) + { + case SYSTEM_TIMER_IRQ_1: + irq_timer_handler(); + break; + default: + printf("\r\nUnknown irq: "); + printf_hex(irq); + break; + } + enable_irq(); +} + +void invalid_exception_entry(int type, unsigned long spsr, unsigned long elr, unsigned long esr) +{ + + show_debug_msg(type, spsr, elr, esr); +} + +// void el0_irq_entry(int type, unsigned long spsr, unsigned long elr, unsigned long esr) +// { +// disable_irq(); +// show_debug_msg(type, spsr, elr, esr); +// enable_irq(); +// } + +void svc_exception_entry(int type, unsigned long spsr, unsigned long elr, unsigned long esr) +{ + disable_irq(); + show_debug_msg(type, spsr, elr, esr); + enable_irq(); +} diff --git a/lab07/kernel/src/kernel_main.c b/lab07/kernel/src/kernel_main.c new file mode 100644 index 000000000..fa338c83a --- /dev/null +++ b/lab07/kernel/src/kernel_main.c @@ -0,0 +1,54 @@ +#include "io.h" +#include "fork.h" +#include "schedule.h" + +extern void shell_loop(); +extern void frame_init_with_reserve(); +extern void memory_pool_init(); +extern void mem_init(); +extern void uart_init(); +extern void timer_init(); +extern void enable_irq(); +extern void initramfs_callback(void*); +extern void rootfs_init(); + +#ifndef QEMU +extern void fdt_traverse(void (*callback)(void*)); +#endif + +static void multiple_init(); + +extern struct task_struct *current; + +int main() +{ + multiple_init(); + enable_irq(); + +#ifndef QEMU + fdt_traverse(initramfs_callback); +#endif + frame_init_with_reserve(); + + rootfs_init(); + + printf("\nWelcome to Yuchang's Raspberry Pi 3!\n"); + + // copy_process((unsigned long)(void*)&shell_loop, 0); + copy_process(PF_KTHREAD, (unsigned long)(void*)&shell_loop, 0, 0); + + while(1){ + kill_zombies(); + schedule(); + } + return 0; +} + +static void multiple_init() +{ + mem_init(); + uart_init(); + memory_pool_init(); + timer_init(); + // rootfs_init(); +} \ No newline at end of file diff --git a/lab07/kernel/src/lib.c b/lab07/kernel/src/lib.c new file mode 100644 index 000000000..82bff2bfa --- /dev/null +++ b/lab07/kernel/src/lib.c @@ -0,0 +1,87 @@ +#include "lib.h" +#include "io.h" + +uint32_t strtol(const char *sptr, uint32_t base, int size) +{ + uint32_t ret = 0; + int i=0; + + while((sptr[i] != '\0') && (i= '0' && sptr[i] <= '9'){ + ret = ret * 16 + (sptr[i] - '0'); + } + else if(sptr[i] >= 'a' && sptr[i] <= 'f'){ + ret = ret * 16 + (sptr[i] - 'a' + 10); + } + else if(sptr[i] >= 'A' && sptr[i] <= 'F'){ + ret = ret * 16 + (sptr[i] - 'A' + 10); + } + else{ + break; + } + } + else if(base == 8 || base == 2){ + if(sptr[i] >= '0' && sptr[i] <= '9'){ + ret = ret * base + (sptr[i] - '0'); + } + else{ + break; + } + } + i++; + } + return ret; +} + +uint64_t atoi(const char *str) +{ + uint64_t ret = 0; + int i=0; + while(str[i] != '\0' && (str[i] >= '0' && str[i] <= '9')){ + ret = ret * 10 + (str[i] - '0'); + i++; + } + return ret; +} + +uint64_t atoi_hex(const char *str) +{ + uint64_t ret = 0; + int i=0; + while(str[i] != '\0'){ + 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); + } + else{ + break; + } + i++; + } + return ret; +} + +uint64_t pow(int base, int exp) +{ + uint64_t ret = 1; + while(exp-- > 0){ + ret *= base; + } + return ret; +} + +void assert(int condition, char* message) +{ + if(!condition){ + printf("\nAssertion failed: "); + printf(message); + printf("\n"); + while(1); + } +} \ No newline at end of file diff --git a/lab07/kernel/src/linker.ld b/lab07/kernel/src/linker.ld new file mode 100644 index 000000000..4eb74d510 --- /dev/null +++ b/lab07/kernel/src/linker.ld @@ -0,0 +1,24 @@ +SECTIONS +{ + . = 0x80000; + .text : + { + KEEP(*(.text.boot)) + *(.text) + } + .rodata :{ *(.rodata) } + .data : { *(.data) } + .bss : + { + . = ALIGN(0x8); + __bss_start = .; + *(.bss) + . = ALIGN(0x8); + __bss_end = .; + } + . = ALIGN(0x8); + _kernel_end = .; + . = ALIGN(0x8); + _heap_start = .; +} +__bss_size = (__bss_end - __bss_start)>>3; \ No newline at end of file diff --git a/lab07/kernel/src/mailbox.c b/lab07/kernel/src/mailbox.c new file mode 100644 index 000000000..c3ef7dc13 --- /dev/null +++ b/lab07/kernel/src/mailbox.c @@ -0,0 +1,88 @@ +#include "peripherals/mailbox.h" + +#include "mailbox.h" +#include "io.h" + +void get_board_revision() +{ + unsigned int mailbox[7]; + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + mailbox_call(mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + + // printf("0x%x\n", mailbox[5]); // it should be 0xa020d3 for rpi3 b+ + printf("\nBoard revision: "); + printf_hex(mailbox[5]); +} + +void get_memory_info() +{ + unsigned int mailbox[8]; + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_ARM_MEMORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; + // tags end + mailbox[7] = END_TAG; + + mailbox_call(mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + + printf("\nARM base memory address: "); + printf_hex(mailbox[5]); + printf("\nARM memory size: "); + printf_hex(mailbox[6]); + +} + +void mailbox_call(unsigned int* mailbox) +{ + unsigned int mesg = (((unsigned long)mailbox) & ~0xf) | 8; + + while(*MAILBOX_STATUS & MAILBOX_FULL){ // // Check if Mailbox 0 status register’s full flag is set. if MAILBOX_STATUS == 0x80000001, then error parsing request buffer + asm volatile("nop"); + } + + *MAILBOX_WRITE = mesg; + + while(1){ + while(*MAILBOX_STATUS & MAILBOX_EMPTY){ + asm volatile("nop"); + } + if(mesg == *MAILBOX_READ){ + break; + } + } +} + +int mailbox_call_s(unsigned char ch, unsigned int *mbox) +{ + + unsigned int mesg = (((unsigned int)(unsigned long)mbox) & ~0xf) | (ch & 0xf); + while(*MAILBOX_STATUS & MAILBOX_FULL){ // // Check if Mailbox 0 status register’s full flag is set. if MAILBOX_STATUS == 0x80000001, then error parsing request buffer + asm volatile("nop"); + } + + *MAILBOX_WRITE = mesg; + + while(1){ + while(*MAILBOX_STATUS & MAILBOX_EMPTY){ + asm volatile("nop"); + } + if(mesg == *MAILBOX_READ){ + return mbox[1] == REQUEST_SUCCEED; + } + } + return 0; +} \ No newline at end of file diff --git a/lab07/kernel/src/mini_uart.c b/lab07/kernel/src/mini_uart.c new file mode 100644 index 000000000..f43431f60 --- /dev/null +++ b/lab07/kernel/src/mini_uart.c @@ -0,0 +1,65 @@ +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" + +#include "mini_uart.h" +#include "string.h" + +void uart_init() +{ + // set the alternate function for GPIO14 and GPIO15 + unsigned int selector; + selector = *GPFSEL1; + selector &= ~(7<<12); // size gpio14 to 0 for gpio14 is bits 12-14 + selector |= 2<<12; // set to alt5 for gpio14 + selector &= ~(7<<15); // size gpio15 to 0 for gpio15 is bits 15-17 + selector |= 2<<15; // set to alt5 for gpio15 + *GPFSEL1 = selector; + + // GPIO initilaization + *GPPUD = 0; // disable pull up/down for all GPIO pins + unsigned int i = 150; + while(i--) asm volatile("nop"); + *GPPUDCLK0 = (1<<14) | (1<<15); // enable clock for gpio14 and gpio15 + i = 150; + while(i--) asm volatile("nop"); + *GPPUDCLK0 = 0; // disable clock for gpio14 and gpio15 + + // initialize mini uart + *AUX_ENABLES = 1; //Enable mini uart (this also enables access to its registers) + *AUX_MU_CNTL_REG = 0; //Disable auto flow control and disable receiver and transmitter (for now) + *AUX_MU_IER_REG = 0; //Disable receive and transmit interrupts + *AUX_MU_LCR_REG = 3; //Enable 8 bit mode + *AUX_MU_MCR_REG = 0; //Set RTS line to be always high + *AUX_MU_BAUD_REG = 270; // 115200 baud + *AUX_MU_CNTL_REG = 3; //Finally, enable transmitter and receiver +} + +char uart_recv() +{ + + char r; + // bit 0 == 1, if receiver holds valid byte + do{asm volatile("nop");}while(!(*AUX_MU_LSR_REG & 0x01)); + r = (char)(*AUX_MU_IO_REG); + return r == '\r'?'\n':r; + +} + +void uart_send(const char c) +{ + // bit 6 == 1, if transmitter is empty + while (1) { + if ((*AUX_MU_LSR_REG)&0x20) break; + } + *AUX_MU_IO_REG = c; + +} + +void uart_send_string(const char* str) +{ + while(*str){ + if(*str == '\n') + uart_send('\r'); + uart_send(*str++); + } +} \ No newline at end of file diff --git a/lab07/kernel/src/mm.S b/lab07/kernel/src/mm.S new file mode 100644 index 000000000..3998c53d5 --- /dev/null +++ b/lab07/kernel/src/mm.S @@ -0,0 +1,6 @@ +.globl memzero_asm +memzero_asm: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero_asm + ret \ No newline at end of file diff --git a/lab07/kernel/src/reboot.c b/lab07/kernel/src/reboot.c new file mode 100644 index 000000000..9d8153f62 --- /dev/null +++ b/lab07/kernel/src/reboot.c @@ -0,0 +1,18 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/lab07/kernel/src/schedule.S b/lab07/kernel/src/schedule.S new file mode 100644 index 000000000..4dd8af0d4 --- /dev/null +++ b/lab07/kernel/src/schedule.S @@ -0,0 +1,24 @@ +#include "schedule.h" + +.globl cpu_switch_to +cpu_switch_to: + mov x10, #THREAD_CPU_CONTEXT + add x8, x0, x10 // x8 = the pointer points to current thread's cpu_context + mov x9, sp + stp x19, x20, [x8], #16 // store callee-saved registers + stp x21, x22, [x8], #16 + stp x23, x24, [x8], #16 + stp x25, x26, [x8], #16 + stp x27, x28, [x8], #16 + stp x29, x9, [x8], #16 + str x30, [x8] + add x8, x1, x10 // x8 = the pointer points to next thread's cpu_context + ldp x19, x20, [x8], #16 // restore callee-saved registers + ldp x21, x22, [x8], #16 + ldp x23, x24, [x8], #16 + ldp x25, x26, [x8], #16 + ldp x27, x28, [x8], #16 + ldp x29, x9, [x8], #16 + ldr x30, [x8] // restore pc + mov sp, x9 + ret \ No newline at end of file diff --git a/lab07/kernel/src/schedule.c b/lab07/kernel/src/schedule.c new file mode 100644 index 000000000..d61fe437b --- /dev/null +++ b/lab07/kernel/src/schedule.c @@ -0,0 +1,103 @@ +#include "schedule.h" +#include "irq.h" +#include "alloc.h" +#include "io.h" + +static struct task_struct init_task = INIT_TASK; +struct task_struct *current = &(init_task); +struct task_struct * task[NR_TASKS] = {&(init_task), }; +int nr_tasks = 1; + +void preempt_disable(void) +{ + current->preempt_count++; +} + +void preempt_enable(void) +{ + current->preempt_count--; +} + + +void _schedule(void) +{ + preempt_disable(); + int next,c; + struct task_struct * p; + while (1) { + c = -1; + next = 0; + for (int i = 0; i < NR_TASKS; i++){ // find the task with the maximum counter + p = task[i]; + if (p && p->state == TASK_RUNNING && p->counter > c) { + c = p->counter; + next = i; + } + } + if (c) { // found & break for switch to the task + break; + } + // if no task is found, increase the counter of all tasks + for (int i = 0; i < NR_TASKS; i++) { + p = task[i]; + if (p) { + p->counter = (p->counter >> 1) + p->priority; + } + } + } + switch_to(task[next]); + preempt_enable(); +} + +void schedule(void) +{ + current->counter = 0; + _schedule(); +} + +void switch_to(struct task_struct * next) +{ + if (current == next) + return; + struct task_struct * prev = current; + current = next; + cpu_switch_to(prev, next); +} + +void schedule_tail(void) { + preempt_enable(); +} + + +void timer_tick() +{ + --current->counter; + if (current->counter>0 || current->preempt_count >0) { + return; + } + current->counter=0; + enable_irq(); + _schedule(); + disable_irq(); +} + +void kill_zombies() +{ + for (int i = 0; i < NR_TASKS; i++) { + if (task[i] && task[i]->state == TASK_ZOMBIE) { + struct task_struct * p = task[i]; + task[i] = 0; + printf("\r\n[KILL] zombies, pid: "); printf_int(p->pid); + bfree(p); + } + } +} + +void exit_process() +{ + preempt_disable(); + current->state = TASK_ZOMBIE; + bfree((void*)current->stack); + preempt_enable(); + schedule(); +} \ No newline at end of file diff --git a/lab07/kernel/src/shell.c b/lab07/kernel/src/shell.c new file mode 100644 index 000000000..1d64b1dc0 --- /dev/null +++ b/lab07/kernel/src/shell.c @@ -0,0 +1,271 @@ +#include "shell.h" +#include "mini_uart.h" +#include "mailbox.h" +#include "reboot.h" +#include "io.h" +#include "string.h" +#include "alloc.h" +#include "lib.h" +#include "timer.h" +#include "irq.h" +#include "fork.h" +#include "schedule.h" +#include "vfs.h" + +#define delay(x) for(int i=0; icwd); + } + else if(argc == 2){ + vfs_list(argv[1]); + } + else{ + printf("\nUsage: ls [path]"); + return; + } +} + + +static void rootfs_mkdir(int argc, char *argv[]) +{ + if(argc == 2){ + vfs_mkdir(argv[1]); + } + else{ + printf("\nUsage: mkdir [path]"); + return; + } +} + +static void rootfs_touch(int argc, char *argv[]) +{ + if(argc == 2){ + // vfs_create(argv[1]); + } + else{ + printf("\nUsage: touch [path]"); + return; + } +} + +static void rootfs_exec(int argc, char *argv[]) +{ + if(argc == 2){ + vfs_exec(argv[1], 0); + } + else{ + printf("\nUsage: exec [path]"); + return; + } +} + + +static void print_cwd(int argc, char *argv[]) +{ + printf("\nCurrent Working Directory: "); + printf(current->cwd); +} + + + +static void change_dir(int argc, char *argv[]) +{ + if(argc == 2){ + vfs_chdir(argv[1]); + } + else{ + printf("\nUsage: cd [path]"); + return; + } +} + +void readcmd(char x[256]) +{ + char input_char; + int input_index = 0; + x[0] = 0; + while( ((input_char = read_char()) != '\n')) + { + if(input_char == 127){ + if(input_index > 0){ + input_index--; + printf("\b \b"); + } + continue; + } + x[input_index] = input_char; + ++input_index; + printfc(input_char); + } + + x[input_index]=0; // null char +} + +int split_command(char* command, char *argv[]) +{ + int argc = 0; + + char *token = strtok(command, " "); + while(token != NULL) + { + argv[argc] = token; + argc++; + token = strtok(0, " "); + } + return argc; +} \ No newline at end of file diff --git a/lab07/kernel/src/string.c b/lab07/kernel/src/string.c new file mode 100644 index 000000000..dd7d84e6c --- /dev/null +++ b/lab07/kernel/src/string.c @@ -0,0 +1,69 @@ +#include "string.h" +#include "io.h" + +int strcmp(const char* a, const char* b) +{ + while(*a == *b){ + if(*a == '\0') + return 0; + a++; + b++; + } + return *a - *b; +} + +char* strcpy(char* dest, const char* src) +{ + char* ret = dest; + while(*src){ + *dest = *src; + dest++; + src++; + } + *dest = '\0'; + return ret; +} + +char* strncpy(char* dest, const char* src, int n) +{ + char* ret = dest; + while(n--){ + *dest = *src; + dest++; + src++; + } + *dest = '\0'; + return ret; +} + +uint32_t strlen(const char* str) +{ + uint32_t len = 0; + while(*str){ + len++; + str++; + } + return len; +} + +char *strtok(char* str, const char* delim) +{ + // printf("\r\nstr: "); printf(str); + static char* p = 0; + if(str != 0) p = str; + if(p == 0) return 0; + char* ret = p; + while(*p){ + if(*p == *delim){ + *p = '\0'; + p++; + if(ret[0] == 0) return NULL; + return ret; + } + p++; + // printf("\r\np++"); + } + // printf("\r\nret: "); printf(ret); printf(", "); printfc(ret[0]); printf(", "); printf_int(ret[0] == NULL); + if(ret[0] == 0) return NULL; + return ret; +} \ No newline at end of file diff --git a/lab07/kernel/src/sys.S b/lab07/kernel/src/sys.S new file mode 100644 index 000000000..9aa5adaef --- /dev/null +++ b/lab07/kernel/src/sys.S @@ -0,0 +1,110 @@ +#include "sys.h" + +// reason for using w8 is that x0-x7 are used for passing arguments +// the such warpper functions are not inlcuded in the real linux kernel +// they often are packed in the different language's standard library, such as glibc + +// svc #0 is used to generate synchronous exception + +.global getpid +getpid: + mov w8, #SYS_GETPID_NUM + svc #0 // using svc to generate synchronous exception + ret + +.global uartread +uartread: + mov w8, #SYS_UARTREAD_NUM + svc #0 + ret + +.global uartwrite +uartwrite: + mov w8, #SYS_UARTWRITE_NUM + svc #0 + ret + +.global exec +exec: + mov w8, #SYS_EXEC_NUM + svc #0 + ret + +.global fork +fork: + mov w8, #SYS_FORK_NUM + svc #0 + ret + +.global exit +exit: + mov w8, #SYS_EXIT_NUM + svc #0 + ret + +.global mbox_call +mbox_call: + mov w8, #SYS_MBOX_CALL_NUM + svc #0 + ret + +.global kill +kill: + mov w8, #SYS_KILL_NUM + svc #0 + ret + +.global open +open: + mov w8, #SYS_OPEN_NUM + svc #0 + ret + +.global close +close: + mov w8, #SYS_CLOSE_NUM + svc #0 + ret + +.global write +write: + mov w8, #SYS_WRITE_NUM + svc #0 + ret + +.global read +read: + mov w8, #SYS_READ_NUM + svc #0 + ret + +.global mkdir +mkdir: + mov w8, #SYS_MKDIR_NUM + svc #0 + ret + +.global mount +mount: + mov w8, #SYS_MOUNT_NUM + svc #0 + ret + +.global chdir +chdir: + mov w8, #SYS_CHDIR_NUM + svc #0 + ret + +.global lseek64 +lseek64: + mov w8, #SYS_LSEEK64_NUM + svc #0 + ret + + +.global ioctl +ioctl: + mov w8, #SYS_IOCTL_NUM + svc #0 + ret \ No newline at end of file diff --git a/lab07/kernel/src/sys.c b/lab07/kernel/src/sys.c new file mode 100644 index 000000000..23dd3bb32 --- /dev/null +++ b/lab07/kernel/src/sys.c @@ -0,0 +1,242 @@ +#include "sys.h" +#include "schedule.h" +#include "fork.h" +#include "mini_uart.h" +#include "io.h" +#include "alloc.h" +#include "cpio.h" +#include "lib.h" +#include "type.h" +#include "string.h" +#include "peripherals/mailbox.h" +#include "dev_framebuffer.h" + +extern struct task_struct *current; +extern void memzero_asm(unsigned long src, unsigned long n); +// #ifndef QEMU +// extern unsigned long CPIO_START_ADDR_FROM_DT; +// #endif + +void foo(){}; + +int sys_getpid() +{ + return current->pid; +} + +size_t sys_uartread(char buf[], size_t size) +{ + for(size_t i=0; ivnode->f_ops->getsize(file->vnode); + void* user_program_addr = balloc(filesize+THREAD_SIZE); + + if(user_program_addr == NULL){ + printf("\r\n[ERROR] Cannot allocate memory for file: "); printf(name); + return -1; + } + + vfs_read(file, user_program_addr, filesize); + vfs_close(file); + + preempt_disable(); // leads to get the correct current task + + struct pt_regs *cur_regs = task_pt_regs(current); + cur_regs->pc = (unsigned long)user_program_addr; + cur_regs->sp = current->stack + THREAD_SIZE; + + preempt_enable(); + return 0; +} + +int sys_fork() // [TODO] +{ + unsigned long stack = (unsigned long)balloc(THREAD_SIZE); + if((void*)stack == NULL) return -1; + memzero_asm(stack, THREAD_SIZE); + return copy_process(0, 0, 0, stack); +} + +void sys_exit(int status) // [TODO] +{ + exit_process(); +} + +int sys_mbox_call(unsigned char ch, unsigned int *mbox) // [TODO] +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] mbox_call: "); printf_int(ch); +#endif + unsigned int mesg = (((unsigned int)(unsigned long)mbox) & ~0xf) | (ch & 0xf); + while(*MAILBOX_STATUS & MAILBOX_FULL){ // // Check if Mailbox 0 status register’s full flag is set. if MAILBOX_STATUS == 0x80000001, then error parsing request buffer + asm volatile("nop"); + } + + *MAILBOX_WRITE = mesg; + + while(1){ + while(*MAILBOX_STATUS & MAILBOX_EMPTY){ + asm volatile("nop"); + } + if(mesg == *MAILBOX_READ){ + return mbox[1] == REQUEST_SUCCEED; + } + } + return 0; +} + +void sys_kill(int pid) // [TODO] +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] kill: "); printf_int(pid); +#endif + if(task[pid] == NULL){ + printf("\r\nProcess not found: "); printf_int(pid); + return; + } + task[pid]->state = TASK_ZOMBIE; +} + +int sys_open(const char *pathname, int flags) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] open: "); printf(pathname); printf(", flags: "); printf_int(flags); +#endif + for(int i=0; ifd_table.fds[i] == NULL){ + int ret = vfs_open(pathname, flags, ¤t->fd_table.fds[i]); + if(ret == 0){ + printf("\r\n[SYSCALL] open: File descriptor: "); printf_int(i + OFFSET_FD); printf(" , File: "); printf(pathname); + return i + OFFSET_FD; + } + break; + } + } + return -1; +} + +int sys_close(int fd) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] close: "); printf_int(fd); +#endif + if(fd < OFFSET_FD || fd >= MAX_OPEN_FILE + OFFSET_FD) return -1; + int ret = vfs_close(current->fd_table.fds[fd - OFFSET_FD]); + current->fd_table.fds[fd - OFFSET_FD] = NULL; + return ret; +} + +long sys_write(int fd, const void *buf, unsigned long count) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] write: fd: "); printf_int(fd); printf(", count: "); printf_int(count); +#endif + if(fd < OFFSET_FD || fd >= MAX_OPEN_FILE + OFFSET_FD) return -1; + return vfs_write(current->fd_table.fds[fd - OFFSET_FD], buf, count); +} +long sys_read(int fd, void *buf, unsigned long count) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] read: fd: "); printf_int(fd); printf(", count: "); printf_int(count); +#endif + if(fd < OFFSET_FD || fd >= MAX_OPEN_FILE + OFFSET_FD) return -1; + return vfs_read(current->fd_table.fds[fd - OFFSET_FD], buf, count); +} + +// you can ignore mode, since there is no access control +int sys_mkdir(const char *pathname, unsigned mode) +{ + return vfs_mkdir(pathname); +} + +// you can ignore arguments other than target (where to mount) and filesystem (fs name) +int sys_mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] mount:"); printf(src); printf(" to "); printf(target); printf(" with filesystem: "); printf(filesystem); +#endif + return vfs_mount(target, filesystem); +} + +int sys_chdir(const char *path) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] chdir: "); printf(path); +#endif + return vfs_chdir(path); +} + + +long sys_lseek64(int fd, long offset, int whence) +{ + long ret; + if(whence == SEEK_SET) // used for dev_framebuffer + { + current->fd_table.fds[fd - OFFSET_FD]->f_pos = offset; + ret = offset; + } + else // other is not supported + { + ret = -1; + } + + return ret; +} + +// ioctl 0 will be use to get info +// there will be default value in info +// if it works with default value, you can ignore this syscall +long sys_ioctl(int fd, unsigned long request, unsigned long arg) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] ioctl: fd: "); printf_int(fd); printf(" , request: "); printf_hex(request); +#endif + return 0; +} + + +void * const sys_call_table[] = { + sys_getpid, + sys_uartread, + sys_uartwrite, + sys_exec, + sys_fork, + sys_exit, + sys_mbox_call, + sys_kill, + // lab5 advanced + foo, + foo, + foo, + // lab7 + sys_open, + sys_close, + sys_write, + sys_read, + sys_mkdir, + sys_mount, + sys_chdir, + sys_lseek64, + sys_ioctl + }; diff --git a/lab07/kernel/src/timer.S b/lab07/kernel/src/timer.S new file mode 100644 index 000000000..1d3a466b2 --- /dev/null +++ b/lab07/kernel/src/timer.S @@ -0,0 +1,32 @@ +.section ".text" + +.global core_timer_enable +core_timer_enable: + mov x0, 1 + msr cntp_ctl_el0, x0 // enable + mov x0, 2 + // mrs x0, cntfrq_el0 + ldr x1, =0x40000040 // timer interrupt control register for core 0 + str w0, [x1] // unmask timer interrupt + ret + +.global core_timer_disable +core_timer_disable: + mov x0, 0 + msr cntp_ctl_el0, x0 // disable + ret + +.global get_cpu_cycles +get_cpu_cycles: + mrs x0, cntpct_el0 + ret + +.global get_cpu_freq +get_cpu_freq: + mrs x0, cntfrq_el0 + ret + +.global set_timer_asm +set_timer_asm: + msr cntp_tval_el0, x0 + ret \ No newline at end of file diff --git a/lab07/kernel/src/timer.c b/lab07/kernel/src/timer.c new file mode 100644 index 000000000..0dcd61513 --- /dev/null +++ b/lab07/kernel/src/timer.c @@ -0,0 +1,25 @@ +#include "timer.h" +#include "alloc.h" +#include "string.h" +#include "type.h" +#include "io.h" + +extern void timer_tick(); + +void timer_init() +{ + core_timer_enable(); + set_timer(1); +} + +void irq_timer_handler() +{ + set_timer_asm(get_cpu_freq()>>5); + timer_tick(); +} + +void set_timer(uint32_t sec) +{ + uint64_t cycles = get_cpu_freq() * sec; + set_timer_asm(cycles); +} diff --git a/lab07/kernel/src/tmpfs.c b/lab07/kernel/src/tmpfs.c new file mode 100644 index 000000000..13487a034 --- /dev/null +++ b/lab07/kernel/src/tmpfs.c @@ -0,0 +1,282 @@ +#include "tmpfs.h" +#include "alloc.h" +#include "errno.h" +#include "io.h" +#include "string.h" + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +struct file_operations *tmpfs_f_ops; +struct vnode_operations *tmpfs_v_ops; + +static struct vnode* tmpfs_create_vnode(const char *name, int type, struct vnode *parent); + +int tmpfs_setup_mount(struct filesystem* fs, struct mount **mount) // mount the filesystem to the mount point +{ + (*mount)->fs = fs; + (*mount)->root = tmpfs_create_vnode("/", DIR_NODE, NULL); + return 0; +} + +static struct vnode* tmpfs_create_vnode(const char *name, int type, struct vnode *parent) +{ + struct tmpfs_internal *internal = (struct tmpfs_internal*)dynamic_alloc(sizeof(struct tmpfs_internal)); + + if(sizeof(name) > COMPONENT_SIZE){ + printf("\r\n[ERROR] File name too long"); + return NULL; + } + internal->name = (char*)dynamic_alloc(COMPONENT_SIZE); + strcpy(internal->name, name); + internal->size = 0; + if(type == FILE_NODE){ + internal->data = (char*)balloc(TMPFS_MAX_FILE); + } + else{ + internal->data = NULL; + } + internal->type = type; + internal->filesize = 0; + // internal->parent = parent; + // internal->next = NULL; + for(int i=0; ichildren[i] = NULL; + } + struct vnode *vnode = (struct vnode*)dynamic_alloc(sizeof(struct vnode)); + vnode->parent = parent; + vnode->mount = NULL; + vnode->v_ops = tmpfs_v_ops; + vnode->f_ops = tmpfs_f_ops; + vnode->internal = internal; + return vnode; +} + +int tmpfs_register() +{ + // check if tmpfs already registered + int i=0; + for(; iwrite = tmpfs_write; + tmpfs_f_ops->read = tmpfs_read; + tmpfs_f_ops->open = tmpfs_open; + tmpfs_f_ops->close = tmpfs_close; + tmpfs_f_ops->getsize = tmpfs_getsize; + tmpfs_f_ops->lseek64 = NULL; + + tmpfs_v_ops->lookup = tmpfs_lookup; + tmpfs_v_ops->create = tmpfs_create; + tmpfs_v_ops->mkdir = tmpfs_mkdir; + tmpfs_v_ops->list = tmpfs_list; + + return 0; +} + +int tmpfs_write(struct file* file, const void* buf, size_t len) +{ + // Given the file handle, VFS calls the corresponding write + // method to write the file starting from f_pos, then updates + // f_pos and size after write. (or not if it’s a special file) + // Returns size written or error code on error. + + // 1. write len byte from buf to the opened file. + // 2. return written size or error code if an error occurs. + struct vnode *vnode = file->vnode; + struct tmpfs_internal *internal = (struct tmpfs_internal*)vnode->internal; + if(internal->type == DIR_NODE){ + printf("\r\n[ERROR] Cannot write to a directory"); + return WERROR; + } + + if(file->f_pos + len > TMPFS_MAX_FILE){ + printf("\r\n[ERROR] File size exceeded"); + return WERROR; + } + + // memory copy + int written_size = min(len, TMPFS_MAX_FILE - file->f_pos); + for(int i=0; idata[file->f_pos + i] = ((char*)buf)[i]; + } + file->f_pos += written_size; + internal->filesize += written_size; + return len; +} + +int tmpfs_read(struct file* file, void* buf, size_t len) +{ + // Given the file handle, VFS calls the corresponding read method + // to read the file starting from f_pos, then updates f_pos after read. + // (or not if it’s a special file) + + // 1. read min(len, readable size) byte to buf from the opened file. + // 2. block if nothing to read for FIFO type + // 2. return read size or error code if an error occurs. + + struct vnode *vnode = file->vnode; + struct tmpfs_internal *internal = (struct tmpfs_internal*)vnode->internal; + if(internal->type == DIR_NODE){ + printf("\r\n[ERROR] Cannot read a directory"); + return RERROR; + } + + size_t readable_size = min(len, internal->filesize - file->f_pos); + + // memory copy + for(int i=0; idata[file->f_pos + i]; + } + file->f_pos += readable_size; + return readable_size; +} + +int tmpfs_open(struct vnode* file_node, struct file** target) +{ + return 0; // the steps for checking the file is implemented in vfs_open +} + +int tmpfs_close(struct file* file) +{ + // 1. release the file handle + // 2. Return error code if fails + if(file == NULL){ + printf("\r\n[ERROR] File pointer cannot be NULL"); + return CERROR; + } + return 0; // vfs_close will free the file pointer +} + +int tmpfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // create an regular file on underlying file system, + // should fail if file exist. Then passes the file’s vnode back to VFS. + + // 1. Create a new file in the directory + // 2. Return error code if fails + struct tmpfs_internal *internal = (struct tmpfs_internal*)dir_node->internal; + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot create file in a file"); + return CERROR; + } + + if(strlen(component_name) > COMPONENT_SIZE){ + printf("\r\n[ERROR] File name too long"); + return CERROR; + } + + // for(int i=0; ichildren[i] == NULL){ + // internal->children[i] = tmpfs_create_vnode(component_name, FILE_NODE, dir_node); + // *target = internal->children[i]; + // return 0; + // } + // } + if(internal->size + 1 > ENTRIES_PER_DIR){ + printf("\r\n[ERROR] No space for new file"); + return CERROR; + } + internal->children[internal->size] = tmpfs_create_vnode(component_name, FILE_NODE, dir_node); + *target = internal->children[internal->size]; + internal->size++; + return 0; +} + +int tmpfs_getsize(struct vnode* vnode) +{ + struct tmpfs_internal *internal = (struct tmpfs_internal*)vnode->internal; + return internal->filesize; +} + +int tmpfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // 1. Create a new directory in the directory + // 2. Return error code if fails + + struct tmpfs_internal *internal = (struct tmpfs_internal*)dir_node->internal; + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot create directory in a file"); + return CERROR; + } + + if(strlen(component_name) > COMPONENT_SIZE){ + printf("\r\n[ERROR] Directory name too long"); + return CERROR; + } + + // for(int i=0; ichildren[i] == NULL){ + // internal->children[i] = tmpfs_create_vnode(component_name, DIR_NODE, dir_node); + // *target = internal->children[i]; + // return 0; + // } + // } + if(internal->size + 1 > ENTRIES_PER_DIR){ + printf("\r\n[ERROR] No space for new directory"); + return CERROR; + } + internal->children[internal->size] = tmpfs_create_vnode(component_name, DIR_NODE, dir_node); + *target = internal->children[internal->size]; + internal->size++; + return 0; +} + +int tmpfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // 1. Lookup the vnode in the directory + // 2. Return error code if fails + struct tmpfs_internal *internal = (struct tmpfs_internal*)dir_node->internal; + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot lookup in a file"); + return LERROR; + } + + for(int i=0; ichildren[i]->internal; + if(internal->children[i] != NULL && !strcmp(child_internal->name, component_name)){ + *target = internal->children[i]; + return 0; + } + } + // printf("[ERROR] File not found\n"); + return LERROR; +} + +int tmpfs_list(struct vnode* dir_node) +{ + // 1. List all the files in the directory + // 2. Return error code if fails + printf("\r\n[TMPFS LIST]"); + struct tmpfs_internal *internal = (struct tmpfs_internal*)dir_node->internal; + + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot list in a file"); + return LERROR; + } + + printf("\r\nName \tType"); + printf("\r\n-----------------------"); + for(int i=0; isize; i++){ + struct tmpfs_internal *child_internal = (struct tmpfs_internal*)internal->children[i]->internal; + printf("\r\n"); printf(child_internal->name); for(int j=0; j<15-strlen(child_internal->name); j++) printf(" "); + printf("\t"); printf(child_internal->type == FILE_NODE ? "FILE" : "DIR"); + } + return 0; +} diff --git a/lab07/kernel/src/user_demo.c b/lab07/kernel/src/user_demo.c new file mode 100644 index 000000000..2088f2418 --- /dev/null +++ b/lab07/kernel/src/user_demo.c @@ -0,0 +1,261 @@ +#include "user_demo.h" +#include "fork.h" +#include "schedule.h" +#include "io.h" +#include "sys.h" + +// system call +extern int getpid(); +extern int fork(); +extern void exit(); +extern int open(const char *pathname, int flags); +extern int close(int fd); +extern int read(int fd, void *buf, unsigned long count); +extern int write(int fd, const void *buf, unsigned long count); + +static void user_multiple_thread_test_foo(); +static void user_fork_test_foo(); +static void user_open_test_foo(); +static void user_open_test_initramfs_foo(); +static void user_read_test_foo(); +static void user_write_test_foo(); +static void user_write_test_initramfs_foo(); +static void user_stdout_test_foo(); +static void user_stdin_test_foo(); + +// lab5 +void multiple_thread_test(int argc, char *argv[]) +{ + for(int i = 0; i < 5; ++i) { + copy_process(PF_KTHREAD, (unsigned long)&user_multiple_thread_test_foo, 0, 0); + } +} + +void user_fork_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_fork_test_foo, 0); +} + +// lab7 + +void user_open_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_open_test_foo, 0); +} + +void user_open_test_initramfs(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_open_test_initramfs_foo, 0); +} + +void user_read_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_read_test_foo, 0); +} + +void user_write_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_write_test_foo, 0); +} + +void user_write_test_initramfs(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_write_test_initramfs_foo, 0); +} + +void user_stdout_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_stdout_test_foo, 0); +} + +void user_stdin_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_stdin_test_foo, 0); +} + +// ------------------------------------------------------------------ + +static void user_multiple_thread_test_foo() +{ + for(int i = 0; i < 10; ++i) { + printf("\r\nThread id: "); printf_int(current->pid); printf("\t,loop: "); printf_int(i); + delay(1000000); + schedule(); + } + current->state = TASK_ZOMBIE; + while(1); +} + +static void user_fork_test_foo() +{ + // printf("Fork Test , pid : %d\n",getpid()); + printf("\r\nFork Test, pid: "); printf_int(getpid()); + uint32_t cnt = 1,ret=0; + + if((ret=fork()) == 0){ //pid == 0 => child + printf("\r\n===== Child Process ====="); + unsigned long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + // printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + printf("\r\nfirst child pid: "); printf_int(getpid()); printf(", cnt: "); printf_int(cnt); + printf(", ptr: "); printf_hex((unsigned long)&cnt); printf(", sp: "); printf_hex(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", getpid(), cnt, &cnt, cur_sp); + printf("\r\nfirst child pid: "); printf_int(getpid()); printf(", cnt: "); printf_int(cnt); + printf(", ptr: "); printf_hex((unsigned long)&cnt); printf(", sp: "); printf_hex(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", getpid(), cnt, &cnt, cur_sp); + printf("\r\nsecond child pid: "); printf_int(getpid()); printf(", cnt: "); printf_int(cnt); + printf(", ptr: "); printf_hex((unsigned long)&cnt); printf(", sp: "); printf_hex(cur_sp); + delay(1000000); + ++cnt; + } + } + exit(); + } + else{ //pid > 0 => parent + printf("\r\n===== Parent Process ====="); + printf("\r\nParent Process, pid: "); printf_int(getpid()); + printf(" child pid: "); printf_int(ret); + unsigned long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf(" cnt: "); printf_int(cnt); printf(" , ptr: "); printf_hex((unsigned long)&cnt); + printf(" , sp: "); printf_hex(cur_sp); + exit(); + } +} + +static void user_open_test_foo() +{ + printf("\r\nUser Open Test pid: "); printf_int(getpid()); + // char buff[] = "Hello, World!"; + int fd = open("test.txt", O_CREAT); + if(fd == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd); + // write(fd, buff, sizeof(buff)); + close(fd); + exit(); +} + +static void user_open_test_initramfs_foo() +{ + printf("\r\nUser Open Test Initramfs pid: "); printf_int(getpid()); + // char buff[] = "Hello, World!"; + int fd = open("/initramfs/test.txt", O_CREAT); + if(fd == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd); + // write(fd, buff, sizeof(buff)); + close(fd); + exit(); +} + +static void user_read_test_foo() +{ + printf("\r\nUser Read Test pid: "); printf_int(getpid()); + char buff1[100]; + int fd1 = open("/initramfs/f1", 0); + if(fd1 == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd1); + read(fd1, buff1, sizeof(buff1)); + printf("\r\nRead content f1: "); printf(buff1); + + char buff2[4]; + int fd2 = open("/initramfs/f2", 0); + if(fd2 == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd2); + read(fd2, buff2, sizeof(buff2)); + printf("\r\nRead content f2: "); printf(buff2); + read(fd2, buff2, sizeof(buff2)); + printf("\r\nRead content f2: "); printf(buff2); + close(fd1); + close(fd2); + exit(); +} + +static void user_write_test_foo() +{ + printf("\r\nUser Write Test pid: "); printf_int(getpid()); + char buff[] = "Hello, World!"; + int fd = open("/write.txt", O_CREAT); + if(fd == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd); + write(fd, buff, sizeof(buff)); + close(fd); + + int fd2 = open("/write.txt", 0); + if(fd2 == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd2); + char buff2[100]; + read(fd2, buff2, sizeof(buff2)); + printf("\r\nRead content write.txt: "); printf(buff2); + close(fd2); + exit(); +} + +static void user_write_test_initramfs_foo() +{ + printf("\r\nUser Write Test Initramfs pid: "); printf_int(getpid()); + char buff[] = "Hello, World!"; + int fd = open("/initramfs/f1", 0); + if(fd == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd); + int size = write(fd, buff, sizeof(buff)); + if(size < 0) { + printf("\r\nWrite file failed!"); + exit(); + } + close(fd); + + int fd2 = open("/initramfs/f1", 0); + if(fd2 == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd2); + char buff2[100]; + read(fd2, buff2, sizeof(buff2)); + printf("\r\nRead content f1: "); printf(buff2); + close(fd2); + exit(); +} + +static void user_stdout_test_foo() +{ + write(1, "\nhello\n", 6); + exit(); +} + +static void user_stdin_test_foo() +{ + char buf[100]; + read(0, buf, 20); + write(1, buf, 20); + exit(); +} \ No newline at end of file diff --git a/lab07/kernel/src/vfs.c b/lab07/kernel/src/vfs.c new file mode 100644 index 000000000..774f7e943 --- /dev/null +++ b/lab07/kernel/src/vfs.c @@ -0,0 +1,538 @@ +#include "vfs.h" +#include "alloc.h" +#include "string.h" +#include "tmpfs.h" +#include "errno.h" +#include "tmpfs.h" +#include "initramfs.h" +#include "io.h" +#include "schedule.h" +#include "fork.h" +#include "dev_uart.h" +#include "dev_framebuffer.h" + +extern struct task_struct* current; + +struct mount* rootfs; +struct filesystem global_fs[MAX_FILESYSTEM]; +struct file_operations global_dev[MAX_DEV_REG]; + +extern struct file_operations *initramfs_f_ops; + + +static struct vnode* next_step(struct vnode* start_node, const char* pathname, struct vnode** target_dir); +static struct file* create_file(struct vnode* vnode, int flags); +static char* get_file_name(const char* pathname); +static void simplify_path(char* pathname); + +void rootfs_init() +{ + // pre init + // global_fd_table_init(); + // 1. create a tmpfs filesystem + // 2. create a rootfs mount + // 3. setup rootfs mount + for(int i=0; iname = (char*)dynamic_alloc(16); + strcpy(tmpfs->name, "tmpfs"); + + tmpfs->setup_mount = tmpfs_setup_mount; + register_filesystem(tmpfs); + + rootfs = (struct mount*)dynamic_alloc(sizeof(struct mount)); + tmpfs->setup_mount(tmpfs, &rootfs); + + // initramfs + vfs_mount("/initramfs", "initramfs"); + + // devfs + vfs_mkdir("/dev"); + int uart_id = dev_uart_register(); + printf("\r\nUART ID: "); printf_int(uart_id); + vfs_mknod("/dev/uart", uart_id); + int framebuffer_id = dev_framebuffer_register(); + vfs_mknod("/dev/framebuffer", framebuffer_id); +} + + +int register_filesystem(struct filesystem* fs) { // ensure there is sufficient memory for the filesystem + // register the file system to the kernel. + // you can also initialize memory pool of the file system here. + if(!strcmp(fs->name, "tmpfs")) + { + //initialize memory pool of the file system + return tmpfs_register(); + } + else if(!strcmp(fs->name, "initramfs")) + { + return initramfs_register(); + } + return -1; +} + +int register_dev(struct file_operations* f_ops) +{ + for(int i=0; iwrite; + global_dev[i].read = f_ops->read; + global_dev[i].open = f_ops->open; + global_dev[i].close = f_ops->close; + return i; + } + } + return -1; +} + +int vfs_open(const char* pathname, int flags, struct file** target) { + // 1. Lookup pathname + // 2. Create a new file handle for this vnode if found. + // 3. Create a new file if O_CREAT is specified in flags and vnode not found + // lookup error code shows if file exist or not or other error occurs + // 4. Return error code if fails + struct vnode* vnode; + int ret = vfs_lookup(pathname, &vnode); + if(ret != 0 && flags != O_CREAT){ + printf("\r\n[ERROR] Cannot find the file"); + return -1; + } + else if(ret == 0 && flags == O_CREAT){ + printf("\r\n[ERROR] File already exists"); + return -1; + } + else if(flags == O_CREAT){ + struct vnode* target_dir; + vfs_get_node(pathname, &target_dir); + if(target_dir == NULL){ + printf("\r\n[ERROR] Cannot find the parent directory"); + return -1; + } + + char* file_name = get_file_name(pathname); + + if(target_dir->mount != NULL) + ret = target_dir->mount->root->v_ops->create(target_dir->mount->root, &vnode, file_name); + else + ret = target_dir->v_ops->create(target_dir, &vnode, file_name); + + if(ret != 0){ + printf("\r\n[ERROR] Cannot create the file"); + return -1; + } + *target = create_file(vnode, flags); + return ret; + } + + struct file* file = create_file(vnode, flags); + *target = file; + if(vnode->f_ops->open(vnode, &file) != 0){ + printf("\r\n[ERROR] Cannot open the file"); + return -1; + } + + return 0; +} + +int vfs_close(struct file* file) { + // 1. release the file handle + // 2. Return error code if fails + int ret = file->f_ops->close(file); + dfree(file); + return ret; +} + +int vfs_write(struct file* file, const void* buf, size_t len) { + // 1. write len byte from buf to the opened file. + // 2. return written size or error code if an error occurs. + int ret; + if(file->vnode->mount != NULL) + ret = file->vnode->mount->root->f_ops->write(file, buf, len); + else + ret = file->f_ops->write(file, buf, len); + return ret; +} + +int vfs_read(struct file* file, void* buf, size_t len) { + // 1. read min(len, readable size) byte to buf from the opened file. + // 2. block if nothing to read for FIFO type + // 2. return read size or error code if an error occurs. + int ret = file->f_ops->read(file, buf, len); + return ret; +} + +int vfs_mkdir(const char* pathname) +{ + + struct vnode* target_dir; + struct vnode* vnode = vfs_get_node(pathname, &target_dir); + if(vnode != NULL) + { + printf("\r\n[ERROR] Directory already exists"); + return CERROR; + } + + if(target_dir == NULL) + { + printf("\r\n[ERROR] Cannot find the parent directory"); + return CERROR; + } + struct vnode* new_dir; + char* file_name = get_file_name(pathname); + printf("\r\n[MKDIR] pathname: "); printf(pathname); printf(" , filename: "); printf(file_name); + + + int ret; + if(target_dir->mount != NULL){ // check if it is a mount point + ret = target_dir->mount->root->v_ops->mkdir(target_dir->mount->root, &new_dir, file_name); + } + else { + ret = target_dir->v_ops->mkdir(target_dir, &new_dir, file_name); + } + + if(ret != 0) + { + printf("\r\n[ERROR] Cannot create directory"); + dfree(file_name); + return CERROR; + } + dfree(file_name); + return 0; +} + +int vfs_mknod(const char* pathname, int id) +{ + + struct file* file = (struct file*)dynamic_alloc(sizeof(struct file)); + + vfs_open(pathname, O_CREAT, &file); + file->vnode->f_ops = &global_dev[id]; // set the file operations + vfs_close(file); + return 0; +} + +int vfs_mount(const char* target, const char* filesystem) // mount the filesystem to the target +{ + // struct mount* mount_point = (struct mount*)dynamic_alloc(sizeof(struct mount)); + struct filesystem* fs = (struct filesystem*)dynamic_alloc(sizeof(struct filesystem)); + + struct vnode* vnode = vfs_get_node(target, 0); + if(vnode == NULL) + { + vfs_mkdir(target); + vnode = vfs_get_node(target, 0); + } + + vnode->mount = (struct mount*)dynamic_alloc(sizeof(struct mount)); + + fs->name = (char*)dynamic_alloc(16); + if(!strcmp(filesystem, "tmpfs")) + { + + strcpy(fs->name, "tmpfs"); + + fs->setup_mount = tmpfs_setup_mount; + + } + else if(!strcmp(filesystem, "initramfs")) + { + strcpy(fs->name, "initramfs"); + + fs->setup_mount = initramfs_setup_mount; + } + else + { + printf("\r\n[ERROR] Filesystem not found"); + return CERROR; + } + + register_filesystem(fs); + fs->setup_mount(fs, &vnode->mount); + + vnode->mount->root->parent = vnode->parent; + + return 0; +} +int vfs_lookup(const char* pathname, struct vnode** target) +{ + struct vnode* vnode = vfs_get_node(pathname, NULL); + if(vnode == NULL) + { + return -1; + } + *target = vnode; + return 0; +} + +int vfs_list(const char* pathname) +{ + struct vnode* vnode; + int ret = vfs_lookup(pathname, &vnode); + + if(ret != 0) + { + printf("\r\n[ERROR] Cannot find the directory"); + return -1; + } + if(vnode->mount != NULL){ // check if it is a mount point + ret = vnode->mount->root->v_ops->list(vnode->mount->root); + } + else { + ret = vnode->v_ops->list(vnode); + } + if(ret != 0) + { + printf("\r\n[ERROR] Cannot list the directory"); + return CERROR; + } + return 0; +} + + +int vfs_chdir(const char* relative_path) +{ + char* current_abs_path = current->cwd; + char* new_abs_path = (char*)dynamic_alloc(strlen(current_abs_path) + strlen(relative_path) + 4); + strcpy(new_abs_path, current_abs_path); + if(relative_path[0] == '/'){ // absolute path + strcpy(new_abs_path, relative_path); + } + else{ // relative path + strcpy(new_abs_path, current_abs_path); + strcpy(new_abs_path + strlen(current_abs_path), relative_path); + } + + if(new_abs_path[strlen(new_abs_path)-1] != '/'){ // add '/' at the end + new_abs_path[strlen(new_abs_path)] = '/'; + new_abs_path[strlen(new_abs_path)+1] = '\0'; + } + + // printf("\r\n[CHDIR] new_abs_path: "); printf(new_abs_path); + struct vnode* vnode = vfs_get_node(new_abs_path, NULL); + + if(vnode == NULL) + { + printf("\r\n[ERROR] Cannot find the directory"); + return CERROR; + } + + // printf("\r\n[INFO] File descriptor 0: "); printf_hex((unsigned long)current->fd_table.fds[0]); + // printf("\r\n[INFO] File descriptor 1: "); printf_hex((unsigned long)current->fd_table.fds[1]); + // printf("\r\n[INFO] File descriptor 2: "); printf_hex((unsigned long)current->fd_table.fds[2]); + + // simplify_path(new_abs_path); + // printf("\r\n[CHDIR] new_abs_path(simplified): "); printf(new_abs_path); + // printf("\r\n[INFO] File descriptor 0: "); printf_hex((unsigned long)current->fd_table.fds[0]); + // printf("\r\n[INFO] File descriptor 1: "); printf_hex((unsigned long)current->fd_table.fds[1]); + // printf("\r\n[INFO] File descriptor 2: "); printf_hex((unsigned long)current->fd_table.fds[2]); + preempt_enable(); + strcpy(current->cwd, new_abs_path); + preempt_disable(); + + return 0; +} + + +int vfs_exec(const char* pathname, char* const argv[]) +{ + struct file* file; + int ret = vfs_open(pathname, O_RW, &file); + + if(ret != 0) + { + printf("\r\n[ERROR] Cannot open the file"); + return CERROR; + } + + int filesize = file->vnode->f_ops->getsize(file->vnode); + void* user_program_addr = balloc(filesize+THREAD_SIZE); + + vfs_read(file, user_program_addr, filesize); + + printf("\r\n[EXEC] File: "); printf(pathname); printf(" , size: "); printf_hex(filesize); + + preempt_disable(); // leads to get the correct current task + + current->state = TASK_STOPPED; + + unsigned long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)user_program_addr, 0); + + preempt_enable(); + + return 0; +} + + +struct vnode* vfs_get_node(const char* pathname, struct vnode** target_dir) +{ + struct vnode* start_node; + + if(pathname[0] == '/'){ + start_node = rootfs->root; + return next_step(start_node, pathname+1, target_dir); + } + else{ + start_node = vfs_get_node(current->cwd, NULL); + return next_step(start_node, pathname, target_dir); + } + return NULL; +} + +static struct vnode* next_step(struct vnode* start_node, const char* pathname, struct vnode** target_dir) +{ + char* tmp_path = (char*)dynamic_alloc(strlen(pathname)+1); + strcpy(tmp_path, pathname); + char* token = strtok(tmp_path, "/"); + // if(strlen(token) == 0) { token = NULL; } + struct vnode* current_node = start_node; + + while(token != NULL){ + *target_dir = current_node; + if(!strcmp(token, "..")){ // [TODO] might have bugs when the path contains mount points + if(current_node->parent == NULL){ + current_node = NULL; + goto next_step_end; + } + current_node = current_node->parent; + } + else if(!strcmp(token, ".")){ + // do nothing + } + else{ + struct vnode* next_node; + if(current_node->mount != NULL){ + if(current_node->mount->root->v_ops->lookup(current_node->mount->root, &next_node, token) == 0){ + current_node = next_node; + } + else{ + current_node = NULL; + goto next_step_end; + } + } + else if(current_node->v_ops->lookup(current_node, &next_node, token) == 0){ + current_node = next_node; + } + else{ + current_node = NULL; + goto next_step_end; + } + } + token = strtok(NULL, "/"); + } +next_step_end: + dfree(tmp_path); + return current_node; +} + +static struct file* create_file(struct vnode* vnode, int flags) +{ + struct file* file = (struct file*)dynamic_alloc(sizeof(struct file)); + file->vnode = vnode; + file->f_pos = 0; + file->f_ops = vnode->f_ops; + file->flags = flags; + return file; +} + + +static char* get_file_name(const char* pathname) +{ + char* file_name = (char*)dynamic_alloc(16); + int i; + for(i = strlen(pathname)-1; i >= 0; i--){ + if(pathname[i] == '/'){ + break; + } + } + if(i == -1){ + strcpy(file_name, pathname); + } + else{ + strcpy(file_name, pathname+i+1); + } + return file_name; +} + +static void simplify_path(char* pathname) +{ + + // printf("\r\n"); printf(__func__); + #define MAX_SEGMENTS 256 + + char* tmp_path = (char*)dynamic_alloc(strlen(pathname)+1); + char* new_path = (char*)dynamic_alloc(strlen(pathname)+1); + + strcpy(tmp_path, pathname); + + char* segments[MAX_SEGMENTS]; + int n_segments = 0; + + char* token = strtok(tmp_path, "/"); + int isFirst = 1; // avoid the first NULL token + while(token != NULL || isFirst == 1){ + isFirst = 0; + if(token != NULL){ + segments[n_segments] = (char*)dynamic_alloc(strlen(token)+1); + strcpy(segments[n_segments++], token); + } + token = strtok(NULL, "/"); + } + + int need_segment[MAX_SEGMENTS]; + int need_idx = 0; + for(int i=0; i 0){ + need_idx--; + } + } + else{ + need_segment[need_idx++] = i; + } + } + + // printf("\r\n[DEBUG] need_idx: "); printf_int(need_idx); + + for(int i=0; ic_namesize, 16, 8); + int filesize = strtol(head->c_filesize, 16, 8); + + char *filename = (void*)head + head_size; + + uint32_t offset = head_size + namesize; + if(offset % 4 != 0) offset = ((offset/4 +1)*4); + + if(strcmp(filename, "TRAILER!!!") == 0){ + printf("\nFile not found"); + break; + } + else if(strcmp(filename, target_name) == 0){ + /* The filedata is appended after filename */ + char *filedata = (void*)head + offset; + + printf("\r\n[INFO] File found: "); printf(target_name); printf(" in CPIO at "); printf_hex((unsigned long)filedata); + printf("\r\n[INFO] File Size: "); printf_hex(filesize); + + void* user_program_addr = balloc(filesize+THREAD_SIZE); // extra page in case + if(user_program_addr == NULL) return; + memzero_asm((unsigned long)user_program_addr, filesize+THREAD_SIZE); + for(int i=0; istate = TASK_STOPPED; + + unsigned long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)user_program_addr, 0); + + preempt_enable(); + break; + } + + if(filesize % 4 != 0) filesize = (filesize/4 +1)*4; + head = (void*)head + offset + filesize; + } + return; +} \ No newline at end of file diff --git a/lab08/create_fs.sh b/lab08/create_fs.sh new file mode 100755 index 000000000..88b71b68e --- /dev/null +++ b/lab08/create_fs.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +(cd initramfs && find . | cpio -o -H newc > ../initramfs.cpio) + diff --git a/lab08/initramfs.cpio b/lab08/initramfs.cpio new file mode 100644 index 000000000..3014be52b Binary files /dev/null and b/lab08/initramfs.cpio differ diff --git a/lab08/initramfs/dir1/f3 b/lab08/initramfs/dir1/f3 new file mode 100644 index 000000000..93ca8fc0c --- /dev/null +++ b/lab08/initramfs/dir1/f3 @@ -0,0 +1 @@ +This is f3 diff --git a/lab08/initramfs/dir1/f4 b/lab08/initramfs/dir1/f4 new file mode 100644 index 000000000..397683db2 --- /dev/null +++ b/lab08/initramfs/dir1/f4 @@ -0,0 +1 @@ +This is f4 diff --git a/lab08/initramfs/f1 b/lab08/initramfs/f1 new file mode 100644 index 000000000..5d12ba17a --- /dev/null +++ b/lab08/initramfs/f1 @@ -0,0 +1 @@ +This is f1 diff --git a/lab08/initramfs/f2 b/lab08/initramfs/f2 new file mode 100644 index 000000000..688c067f3 --- /dev/null +++ b/lab08/initramfs/f2 @@ -0,0 +1 @@ +This is f2 diff --git a/lab08/kernel/Makefile b/lab08/kernel/Makefile new file mode 100644 index 000000000..bf4e55536 --- /dev/null +++ b/lab08/kernel/Makefile @@ -0,0 +1,60 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -ffreestanding -nostartfiles -nostdlib -g -Iinclude +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all: clean makedir kernel8.img + + +ifdef DEBUG +COPS += -DDEBUG +endif + +ifdef BUDDY_SYSTEM_DEBUG +COPS += -BUDDY_SYSTEM_DEBUG +endif + +ifdef DYNAMIC_ALLOC_DEBUG +COPS += -DYNAMIC_ALLOC_DEBUG +endif + +.PHONY: clean +clean: + rm -rf $(BUILD_DIR) *.img + +makedir: + mkdir -p $(BUILD_DIR) +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: $(OBJ_FILES) $(SRC_DIR)/linker.ld + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img + +.PHONY: run debug QEMU +run: clean makedir kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -serial null -serial stdio -initrd ../initramfs.cpio + +dump: kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -d in_asm + +gdb: clean makedir kernel8.img + qemu-system-aarch64 -M raspi3b -kernel kernel8.img -display none -serial null -serial stdio -S -s -initrd ../initramfs.cpio + +QEMU: COPS += -DQEMU +QEMU: run \ No newline at end of file diff --git a/lab08/kernel/include/alloc.h b/lab08/kernel/include/alloc.h new file mode 100644 index 000000000..ffbcbebf6 --- /dev/null +++ b/lab08/kernel/include/alloc.h @@ -0,0 +1,25 @@ +#ifndef __ALLOC_H__ +#define __ALLOC_H__ + +#include "type.h" + +void mem_init(); +void* simple_malloc(uint32_t size); + +struct frame_t; +struct free_t; +struct memory_pool_t; +struct chunk_t; + +void frame_init_with_reserve(); + +void* balloc(uint64_t size); +int bfree(void* ptr); + +void memory_pool_init(); +void* dynamic_alloc(uint64_t size); +int dfree(void* ptr); + +void memory_reserve(uint64_t start, uint64_t end, char* msg); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/bootload.h b/lab08/kernel/include/bootload.h new file mode 100644 index 000000000..a15f9b56a --- /dev/null +++ b/lab08/kernel/include/bootload.h @@ -0,0 +1,15 @@ +#ifndef __BOOTLOAD_H__ +#define __BOOTLOAD_H__ + +#define KernelAddr 0x80000 +#define BootAddr 0x60000 + +#include "type.h" + +extern uint32_t __bss_end; +extern uint32_t __bss_size; + +void reallocate(); +void load_kernel(); + +#endif diff --git a/lab08/kernel/include/cpio.h b/lab08/kernel/include/cpio.h new file mode 100644 index 000000000..4d6102060 --- /dev/null +++ b/lab08/kernel/include/cpio.h @@ -0,0 +1,42 @@ +#ifndef __CPIO_H__ +#define __CPIO_H__ + +#include "devicetree.h" + +#ifdef QEMU + #define CPIO_ADDR 0x8000000 +#else + #define CPIO_ADDR 0x20000000 +#endif + +typedef struct cpio_newc_header { + char c_magic[6]; + char c_ino[8]; + char c_mode[8]; + char c_uid[8]; + char c_gid[8]; + char c_nlink[8]; + char c_mtime[8]; + char c_filesize[8]; + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; + char c_check[8]; +} cpio_newc_header; + +void cpio_list(int argc, char **argv); +void cpio_cat(int argc, char **argv); +void cpio_exec(int argc, char **argv); + +#ifndef QEMU +void initramfs_callback(char* node_name, char* property_name, fdt_prop* prop); + +extern uint64_t CPIO_START_ADDR_FROM_DT; +extern uint64_t CPIO_END_ADDR_FROM_DT; +#endif + +int cpio_newc_parser(cpio_newc_header** head, char** filename, char** filedata); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/dev_framebuffer.h b/lab08/kernel/include/dev_framebuffer.h new file mode 100644 index 000000000..3ba45a40a --- /dev/null +++ b/lab08/kernel/include/dev_framebuffer.h @@ -0,0 +1,23 @@ +#ifndef _DEV_FRAMEBUFFER_H__ +#define _DEV_FRAMEBUFFER_H__ + +#include "vfs.h" + +struct framebuffer_info +{ + unsigned int width; + unsigned int height; + unsigned int pitch; + unsigned int isrgb; +}; + +#define SEEK_SET 0 + +int dev_framebuffer_register(); +int dev_framebuffer_write(struct file *file, const void *buf, size_t len); +int dev_framebuffer_read(struct file *file, void *buf, size_t len); +int dev_framebuffer_open(struct vnode *file_node, struct file **target); +int dev_framebuffer_close(struct file *file); +long dev_framebuffer_lseek64(struct file *file, long offset, int whence); + +#endif diff --git a/lab08/kernel/include/dev_uart.h b/lab08/kernel/include/dev_uart.h new file mode 100644 index 000000000..5f07be050 --- /dev/null +++ b/lab08/kernel/include/dev_uart.h @@ -0,0 +1,12 @@ +#ifndef __DEV_UART_H__ +#define __DEV_UART_H__ + +#include "vfs.h" + +int dev_uart_register(); +int dev_uart_write(struct file *file, const void *buf, size_t len); +int dev_uart_read(struct file *file, void *buf, size_t len); +int dev_uart_open(struct vnode *file_node, struct file **target); +int dev_uart_close(struct file *file); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/devicetree.h b/lab08/kernel/include/devicetree.h new file mode 100644 index 000000000..f89d11aee --- /dev/null +++ b/lab08/kernel/include/devicetree.h @@ -0,0 +1,94 @@ +#ifndef __DEVICETREE_H__ +#define __DEVICETREE_H__ + +#include "type.h" + + +/* +0x50000: devicetree blob address +*/ + +#define DTB_ADDR ((volatile uint64_t *)0x50000) + +#define FDT_BEGIN_NODE 0x01 +#define FDT_END_NODE 0x02 +#define FDT_PROP 0x03 +#define FDT_NOP 0x04 +#define FDT_END 0x09 + +/* + |-------------------| + | struct fdt_header | + |-------------------| + | free space | + |-------------------| + | memory reservation| -> list of areas in physical memory which are reserved + |-------------------| + | free space | + |-------------------| + | structure block | + |-------------------| + | free space | + |-------------------| + | strings block | + |-------------------| + | free space | + |-------------------| +*/ + +/* All the header fields are 32-bit integers, stored in big-endian format. */ +typedef struct fdt_header { + uint32_t magic; + uint32_t totalsize; // total size of DT block + uint32_t off_dt_struct; // offset to the structure block + uint32_t off_dt_strings; // offset to the strings block + uint32_t off_mem_rsvmap; // offset to the memory reservation block + uint32_t version; + uint32_t last_comp_version; + uint32_t boot_cpuid_phys; // physical address of the boot CPU + uint32_t size_dt_strings; // size of the strings block + uint32_t size_dt_struct; // size of the structure block +} fdt_header; + + +/* + Memory reservation block + Composed of sequence of tokens with data shown below. + Each token in the structure block, and thus the structure block itself, + shall be loacted at a 4-byte aligned offset from the beginning of the devicetree blob. + + Five tokens types: (32-bit big-endian integers) + 1. FDT_BEGIN_NODE (0x00000001) be followed by the node's uint name as extra data + 2. FDT_END_NODE (0x00000002) + 3. FDT_PROP (0x00000003) + 4. FDT_NOP (0x00000004) + 5. FDT_END (0x00000009) + + FDT_BEGIN_NODE -> ... -> FDT_END_NODE + + - (Optional) Any number of FDT_NOP tokens + - FDT_BEGIN_NODE + - The node’s name as a null-terminated string + - [zeroed padding bytes to align to a 4-byte boundary] + - For each property of the node + - (Optional) Any number of FDT_NOP tokens + - FDT_PROP token + * property infomation + * aligned to a 4-byte boundary +*/ + +/* + The strings block contains strings representing all the property names used in the tree. +*/ + + +/* 32-bit big-endian integers */ +typedef struct fdt_prop { + uint32_t len; // length of the property value + uint32_t nameoff; // offset into the strings block for the property name +} fdt_prop; + +void fdt_traverse(void(*callback_func)(char*, char*, fdt_prop*)); +uint32_t endian_swap(uint32_t value); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/entry.h b/lab08/kernel/include/entry.h new file mode 100644 index 000000000..872bec449 --- /dev/null +++ b/lab08/kernel/include/entry.h @@ -0,0 +1,30 @@ +#ifndef _ENTRY_H__ +#define _ENTRY_H__ + + +#define SYNC_INVALID_EL1t 0 +#define IRQ_INVALID_EL1t 1 +#define FIQ_INVALID_EL1t 2 +#define ERROR_INVALID_EL1t 3 + +#define SYNC_INVALID_EL1h 4 +#define IRQ_INVALID_EL1h 5 +#define FIQ_INVALID_EL1h 6 +#define ERROR_INVALID_EL1h 7 + +#define SYNC_INVALID_EL0_64 8 +#define IRQ_INVALID_EL0_64 9 +#define FIQ_INVALID_EL0_64 10 +#define ERROR_INVALID_EL0_64 11 + +#define SYNC_INVALID_EL0_32 12 +#define IRQ_INVALID_EL0_32 13 +#define FIQ_INVALID_EL0_32 14 +#define ERROR_INVALID_EL0_32 15 + +#define SYNC_ERROR 16 +#define SYSCALL_ERROR 17 + +#define S_X0 0 + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/errno.h b/lab08/kernel/include/errno.h new file mode 100644 index 000000000..8f4fbd285 --- /dev/null +++ b/lab08/kernel/include/errno.h @@ -0,0 +1,9 @@ +#ifndef __ERRNO_H__ +#define __ERRNO_H__ + +#define RERROR -1 +#define WERROR -1 +#define CERROR -1 +#define LERROR -1 + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/fork.h b/lab08/kernel/include/fork.h new file mode 100644 index 000000000..c85fc4cb1 --- /dev/null +++ b/lab08/kernel/include/fork.h @@ -0,0 +1,26 @@ +#ifndef __FORK_H__ +#define __FORK_H__ + +// int copy_process(unsigned long fn, unsigned long arg); +#include "schedule.h" + +int copy_process( + unsigned long flags, + unsigned long fn, + unsigned long arg, + unsigned long stack); +int move_to_user_mode(unsigned long pc); + +struct pt_regs { + unsigned long regs[31]; + unsigned long sp; + unsigned long pc; + unsigned long pstate; +}; + +struct pt_regs * task_pt_regs(struct task_struct *tsk); +void kp_user_mode(unsigned long func); + +#define PSR_MODE_EL0t 0x00000000; + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/initramfs.h b/lab08/kernel/include/initramfs.h new file mode 100644 index 000000000..276f6720e --- /dev/null +++ b/lab08/kernel/include/initramfs.h @@ -0,0 +1,35 @@ +#ifndef __INITRAMFS_H__ +#define __INITRAMFS_H__ + +#define COMPONENT_SIZE 15 +#define ENTRIES_PER_DIR 16 +#define INITRAMFS_MAX_FILE 4096*128 + +#include "vfs.h" +#include "cpio.h" + +struct initramfs_internal { + char* name; // file name or directory name + unsigned long size; // child count for directory + char* data; + unsigned long filesize; + int type; // DIR_NODE or FILE_NODE + // struct vnode* parent; + struct vnode* children[ENTRIES_PER_DIR]; + // struct vnode* next; +}; + +int initramfs_list(struct vnode* dir_node); +int initramfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name); +int initramfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name); +int initramfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name); +int initramfs_close(struct file* file); +int initramfs_open(struct vnode* file_node, struct file** target); +int initramfs_read(struct file* file, void* buf, size_t len); +int initramfs_write(struct file* file, const void* buf, size_t len); +int initramfs_getsize(struct vnode* vnode); +int initramfs_setup_mount(struct filesystem* fs, struct mount** mount); +int initramfs_register(); +// int parse_initramfs(); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/io.h b/lab08/kernel/include/io.h new file mode 100644 index 000000000..d1e5333e5 --- /dev/null +++ b/lab08/kernel/include/io.h @@ -0,0 +1,14 @@ +#ifndef __IO_H__ +#define __IO_H__ + +#include "mini_uart.h" + +void printf(const char* str); +void printfc(const char c); +void printf_hex(const unsigned int d); +void printf_int(const int d); +char read_char(); + +#define debug() printf("\r\n [DEBUG] : "); printf(__FILE__); printf(" : "); printf_int(__LINE__) + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/irq.h b/lab08/kernel/include/irq.h new file mode 100644 index 000000000..21f2fd7f1 --- /dev/null +++ b/lab08/kernel/include/irq.h @@ -0,0 +1,12 @@ +#ifndef __IRQ_H__ +#define __IRQ_H__ + +#define EL1_IRQ_TIMER_PRIORITY 0x1 +#define EL1_IRQ_UART_PRIORITY 0x2 + +struct irq_task_struct; + +void task_head_init(); +void test_func(); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/lib.h b/lab08/kernel/include/lib.h new file mode 100644 index 000000000..cb370038c --- /dev/null +++ b/lab08/kernel/include/lib.h @@ -0,0 +1,12 @@ +#ifndef __LIB_H__ +#define __LIB_H__ + +#include "type.h" + +uint32_t strtol(const char *sptr, uint32_t base, int size); +uint64_t atoi(const char *str); +uint64_t atoi_hex(const char *str); +uint64_t pow(int base, int exp); +void assert(int condition, char* message); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/mailbox.h b/lab08/kernel/include/mailbox.h new file mode 100644 index 000000000..46f26015f --- /dev/null +++ b/lab08/kernel/include/mailbox.h @@ -0,0 +1,9 @@ +#ifndef __MAIULBOX_H__ +#define __MAILBOX_H__ + +void get_board_revision(); +void get_memory_info(); +void mailbox_call(unsigned int *mailbox); +int mailbox_call_s(unsigned char ch, unsigned int *mbox); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/mem.h b/lab08/kernel/include/mem.h new file mode 100644 index 000000000..f355738b4 --- /dev/null +++ b/lab08/kernel/include/mem.h @@ -0,0 +1,31 @@ +#ifndef __MEM_H__ +#define __MEM_H__ + +#include "type.h" + +extern uint64_t _heap_start; + +#define HEAP_END (uint64_t)(&_heap_start + 0x100000) + +#define USER_PROCESS_SP 0x200000 +#define USER_START_ADDR 0x100000 + + +// malloc +#define FRAME_SIZE 4096 // 4KB +// #define MAX_LEVEL 16 +#define MAX_LEVEL 18 // log_2(FRAME_NUM) about 17.~ + +// #define MALLOC_START_ADDR 0x10000000 +// #define MALLOC_END_ADDR 0x20000000 +#define MALLOC_START_ADDR 0x00000000 +#define MALLOC_END_ADDR 0x3C000000 +#define MALLOC_TOTAL_SIZE (MALLOC_END_ADDR - MALLOC_START_ADDR) +#define FRAME_NUM MALLOC_TOTAL_SIZE / FRAME_SIZE + +#define MAX_BUDDY_SYSTEM_LIST 10 + +#define MEMORY_POOL_SIZE 4 +#define MEMORY_POOL_DEPTH 4 + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/mini_uart.h b/lab08/kernel/include/mini_uart.h new file mode 100644 index 000000000..eed952d7b --- /dev/null +++ b/lab08/kernel/include/mini_uart.h @@ -0,0 +1,26 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +#define BUFF_SIZE 256 + +void uart_init(); +char uart_recv(); +void uart_send(const char c); +void uart_send_string(const char* str); + +void enable_uart_interrupt(); +void disable_uart_interrupt(); +void enable_uart_recv_interrupt(); +void disable_uart_recv_interrupt(); +void enable_uart_trans_interrupt(); +void disable_uart_trans_interrupt(); + +void uart_buff_init(); + +void async_uart_puts(char* buff); +int async_uart_gets(char* buff, int size); + +void async_uart_read_handler(); +void async_uart_write_handler(); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/mm.h b/lab08/kernel/include/mm.h new file mode 100644 index 000000000..d97596341 --- /dev/null +++ b/lab08/kernel/include/mm.h @@ -0,0 +1,6 @@ +#ifndef __MM_H__ +#define __MM_H__ + +void memzero_asm(unsigned long src, unsigned long n); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/peripherals/base.h b/lab08/kernel/include/peripherals/base.h new file mode 100644 index 000000000..1d3265580 --- /dev/null +++ b/lab08/kernel/include/peripherals/base.h @@ -0,0 +1,6 @@ +#ifndef __PERIPHERALS_BASE_H__ +#define __PERIPHERALS_BASE_H__ + +#define MMIO_BASE 0x3F000000 + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/peripherals/gpio.h b/lab08/kernel/include/peripherals/gpio.h new file mode 100644 index 000000000..b6a104ab3 --- /dev/null +++ b/lab08/kernel/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _GPIO_H +#define _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 \ No newline at end of file diff --git a/lab08/kernel/include/peripherals/irq.h b/lab08/kernel/include/peripherals/irq.h new file mode 100644 index 000000000..54672e0f5 --- /dev/null +++ b/lab08/kernel/include/peripherals/irq.h @@ -0,0 +1,29 @@ +#ifndef __PERIPHERALS_IRQ_H__ +#define __PERIPHERALS_IRQ_H__ + +#include "peripherals/base.h" + +// BCM2835 page. 112-116 +#define IRQ_BASIC_PENDING ((volatile unsigned int*)(MMIO_BASE+0x0000B200)) +#define IRQ_PENDING_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B204)) // Holds All interrupts 0...31 from the GPU side. +#define IRQ_PENDING_2 ((volatile unsigned int*)(MMIO_BASE+0x0000B208)) // 32...63 +#define FIQ_CONTROL ((volatile unsigned int*)(MMIO_BASE+0x0000B20C)) +#define ENABLE_IRQS_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B210)) // Writing a 1 to a bit will set the corresponding IRQ enable bit. (0-31) +#define ENABLE_IRQS_2 ((volatile unsigned int*)(MMIO_BASE+0x0000B214)) // (32-63) +#define ENABLE_BASIC_IRQS ((volatile unsigned int*)(MMIO_BASE+0x0000B218)) +#define DISABLE_IRQS_1 ((volatile unsigned int*)(MMIO_BASE+0x0000B21C)) +#define DISABLE_IRQS_2 ((volatile unsigned int*)(MMIO_BASE+0x0000B220)) +#define DISABLE_BASIC_IRQS ((volatile unsigned int*)(MMIO_BASE+0x0000B224)) // AUX interrupt. 29 + +#define AUX_INT (1 << 29) + +// QA7 page. 16 +#define CORE0_IRQ_SOURCE ((volatile unsigned int*)(0x40000060)) // Get the IRQ source for the core 0. + +#define SYSTEM_TIMER_IRQ_1 (1 << 1) +#define GPU_IRQ (1 << 8) + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/peripherals/mailbox.h b/lab08/kernel/include/peripherals/mailbox.h new file mode 100644 index 000000000..454eb13a3 --- /dev/null +++ b/lab08/kernel/include/peripherals/mailbox.h @@ -0,0 +1,26 @@ +#ifndef __PERIPHERALS_MAILBOX_H__ +#define __PERIPHERALS_MAILBOX_H__ + +#include "peripherals/base.h" + +#define MAILBOX_BASE MMIO_BASE + 0xb880 + +#define MAILBOX_READ ((volatile unsigned int*)(MAILBOX_BASE )) // M0: CPU read from GPU +#define MAILBOX_STATUS ((volatile unsigned int*)(MAILBOX_BASE + 0x18)) // M0: Check GPU statue +#define MAILBOX_WRITE ((volatile unsigned int*)(MAILBOX_BASE + 0x20)) // M1: CPU write to GPU + +#define MAILBOX_EMPTY 0x40000000 +#define MAILBOX_FULL 0x80000000 + +#define GET_BOARD_REVISION 0x00010002 +#define GET_ARM_MEMORY 0x00010005 +#define REQUEST_CODE 0x00000000 +#define REQUEST_SUCCEED 0x80000000 +#define REQUEST_FAILED 0x80000001 +#define TAG_REQUEST_CODE 0x00000000 +#define END_TAG 0x00000000 + +#define MBOX_CH_PROP 8 +#define MBOX_TAG_LAST 0 + +#endif diff --git a/lab08/kernel/include/peripherals/mini_uart.h b/lab08/kernel/include/peripherals/mini_uart.h new file mode 100644 index 000000000..bb55ba2fe --- /dev/null +++ b/lab08/kernel/include/peripherals/mini_uart.h @@ -0,0 +1,26 @@ +#ifndef __PERIPHERALS_MINI_UART_H__ +#define __PERIPHERALS_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)) // Interrupt Enable Register (BCM2835 page. 12) +#define AUX_MU_IIR_REG ((volatile unsigned int*)(MMIO_BASE+0x00215048)) // Shows the interrupt status. (BCM2835 page. 13) +#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 ENABLE_RCV_IRQ (1 << 0) +#define ENABLE_TRANS_IRQ (1 << 1) + +#define AUX_MU_IIR_REG_READ (1 << 2) +#define AUX_MU_IIR_REG_WRITE (1 << 1) + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/reboot.h b/lab08/kernel/include/reboot.h new file mode 100644 index 000000000..e47678792 --- /dev/null +++ b/lab08/kernel/include/reboot.h @@ -0,0 +1,8 @@ +#ifndef __REBOOT_H__ +#define __REBOOT_H__ + +void set(long addr, unsigned int value); +void reset(int tick); +void cancel_reset(); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/schedule.h b/lab08/kernel/include/schedule.h new file mode 100644 index 000000000..5392a441d --- /dev/null +++ b/lab08/kernel/include/schedule.h @@ -0,0 +1,79 @@ +#ifndef __SCHEDULE_H__ +#define __SCHEDULE_H__ + +#define THREAD_CPU_CONTEXT 0 // offset of cpu_context in task_struct + + +#ifndef __ASSEMBLER__ + +#define THREAD_SIZE 4096 + +#define NR_TASKS 64 + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#define TASK_RUNNING 0 +#define TASK_ZOMBIE 1 +#define TASK_STOPPED 2 + +#define PF_KTHREAD 2 + +// #define MAX_PATH_LEN 256 + +extern struct task_struct *current; +extern struct task_struct * task[NR_TASKS]; +extern int nr_tasks; + +#include "vfs.h" + +struct cpu_context { + unsigned long long x19; + unsigned long long x20; + unsigned long long x21; + unsigned long long x22; + unsigned long long x23; + unsigned long long x24; + unsigned long long x25; + unsigned long long x26; + unsigned long long x27; + unsigned long long x28; + unsigned long long fp; // x29 + unsigned long long sp; + unsigned long long pc; // x30 +}; + +struct task_struct { + struct cpu_context cpu_context; + long state; + long counter; + long priority; + long preempt_count; + unsigned long stack; + unsigned long flags; + int pid; + char cwd[MAX_PATH_LEN]; + struct file_descriptor_table fd_table; +}; + +extern void sched_init(void); +extern void schedule(void); +extern void timer_tick(void); +extern void preempt_disable(void); +extern void preempt_enable(void); +extern void switch_to(struct task_struct* next); +extern void cpu_switch_to(struct task_struct* prev, struct task_struct* next); +extern void enable_irq(void); +extern void disable_irq(void); +extern void kill_zombies(void); +extern void exit_process(void); + +#define INIT_TASK \ +/*cpu_context*/ { {0,0,0,0,0,0,0,0,0,0,0,0,0}, \ +/* state etc */ 0,0,1, 0, 0, PF_KTHREAD, 0, \ +/* cwd */ "/", \ +/*fd table*/ {0, {0}} \ +} + +#endif +#endif \ No newline at end of file diff --git a/lab08/kernel/include/shell.h b/lab08/kernel/include/shell.h new file mode 100644 index 000000000..cf6dd6e14 --- /dev/null +++ b/lab08/kernel/include/shell.h @@ -0,0 +1,12 @@ +#ifndef __SHELL_H__ +#define __SHELL_H__ + +typedef struct cmd { + char *name; + void (*func)(int argc, char *argv[]); + char help_msg[100]; +} cmd; + +void readcmd(char [256]); +void shell_loop(); +#endif \ No newline at end of file diff --git a/lab08/kernel/include/string.h b/lab08/kernel/include/string.h new file mode 100644 index 000000000..edf5814b4 --- /dev/null +++ b/lab08/kernel/include/string.h @@ -0,0 +1,12 @@ +#ifndef __STRING_H__ +#define __STRING_H__ + +#include "type.h" + +int strcmp(const char *str1, const char *str2); +char* strcpy(char* dest, const char* src); +char* strncpy(char* dest, const char* src, int n); +uint32_t strlen(const char* str); +char *strtok(char* str, const char* delim); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/sys.h b/lab08/kernel/include/sys.h new file mode 100644 index 000000000..ae3f6528f --- /dev/null +++ b/lab08/kernel/include/sys.h @@ -0,0 +1,57 @@ +#ifndef __SYS_H__ +#define __SYS_H__ + +#define __NR_syscalls 20 + +#define SYS_GETPID_NUM 0 // syscall number +#define SYS_UARTREAD_NUM 1 +#define SYS_UARTWRITE_NUM 2 +#define SYS_EXEC_NUM 3 +#define SYS_FORK_NUM 4 +#define SYS_EXIT_NUM 5 +#define SYS_MBOX_CALL_NUM 6 +#define SYS_KILL_NUM 7 + + +#define SYS_OPEN_NUM 11 +#define SYS_CLOSE_NUM 12 +#define SYS_WRITE_NUM 13 +#define SYS_READ_NUM 14 +#define SYS_MKDIR_NUM 15 +#define SYS_MOUNT_NUM 16 +#define SYS_CHDIR_NUM 17 +#define SYS_LSEEK64_NUM 18 +#define SYS_IOCTL_NUM 19 + +#ifndef __ASSEMBLER__ + +#include "type.h" + +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(const char *name, char *const argv[]); +int sys_fork(); +void sys_exit(int status); +int sys_mbox_call(unsigned char ch, unsigned int *mbox); +void sys_kill(int pid); + +// lab7 +int sys_open(const char *pathname, int flags); +int sys_close(int fd); +long sys_write(int fd, const void *buf, unsigned long count); +long sys_read(int fd, void *buf, unsigned long count); + +// you can ignore mode, since there is no access control +int sys_mkdir(const char *pathname, unsigned mode); + +// you can ignore arguments other than target (where to mount) and filesystem (fs name) +int sys_mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data); +int sys_chdir(const char *path); + +long sys_lseek64(int fd, long offset, int whence); +long sys_ioctl(int fd, unsigned long request, unsigned long arg); + +#endif + +#endif diff --git a/lab08/kernel/include/timer.h b/lab08/kernel/include/timer.h new file mode 100644 index 000000000..7591b62d0 --- /dev/null +++ b/lab08/kernel/include/timer.h @@ -0,0 +1,14 @@ +#ifndef __TIMER_H__ +#define __TIMER_H__ + +extern void core_timer_enable(); +extern void core_timer_disable(); +extern unsigned long long get_cpu_cycles(); +extern unsigned int get_cpu_freq(); +extern void set_timer_asm(unsigned int sec); + +void timer_init(); +void irq_timer_handler(); +void set_timer(unsigned int sec); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/tmpfs.h b/lab08/kernel/include/tmpfs.h new file mode 100644 index 000000000..1c2beee77 --- /dev/null +++ b/lab08/kernel/include/tmpfs.h @@ -0,0 +1,33 @@ +#ifndef __TMPFS_H__ +#define __TMPFS_H__ + +#define COMPONENT_SIZE 15 +#define ENTRIES_PER_DIR 16 +#define TMPFS_MAX_FILE 4096 + +#include "vfs.h" + +struct tmpfs_internal { + char* name; // file name or directory name + unsigned long size; + char* data; + unsigned long filesize; + int type; // DIR_NODE or FILE_NODE + // struct vnode* parent; + struct vnode* children[ENTRIES_PER_DIR]; + // struct vnode* next; +}; + +int tmpfs_list(struct vnode* dir_node); +int tmpfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name); +int tmpfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name); +int tmpfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name); +int tmpfs_close(struct file* file); +int tmpfs_open(struct vnode* file_node, struct file** target); +int tmpfs_read(struct file* file, void* buf, size_t len); +int tmpfs_write(struct file* file, const void* buf, size_t len); +int tmpfs_getsize(struct vnode* vnode); +int tmpfs_setup_mount(struct filesystem* fs, struct mount** mount); +int tmpfs_register(); + +#endif \ No newline at end of file diff --git a/lab08/kernel/include/type.h b/lab08/kernel/include/type.h new file mode 100644 index 000000000..91acd4bd5 --- /dev/null +++ b/lab08/kernel/include/type.h @@ -0,0 +1,13 @@ +#ifndef __TYPE_H__ +#define __TYPE_H__ + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef unsigned long long size_t; + +#define NULL (void*)0 + +#endif diff --git a/lab08/kernel/include/user_demo.h b/lab08/kernel/include/user_demo.h new file mode 100644 index 000000000..7ebabd664 --- /dev/null +++ b/lab08/kernel/include/user_demo.h @@ -0,0 +1,14 @@ +#ifndef __USER_DEMO_H__ +#define __USER_DEMO_H__ + +#define delay(x) for(int i=0; i (void*)HEAP_END){ + + return (char*)0; + } + char* ret = HEAP_REAR; + HEAP_REAR += size; + return ret; +} + +// ========================================== + +static uint64_t pow_2(uint32_t n); + +extern uint64_t _kernel_end; +static uint64_t* _kernel_end_ptr = &_kernel_end; +static uint64_t* _heap_start_ptr = &_heap_start; + +#ifndef QEMU +extern uint64_t CPIO_START_ADDR_FROM_DT; +extern uint64_t CPIO_END_ADDR_FROM_DT; +#endif + +struct frame_t{ + struct frame_t* next; + struct frame_t* prev; // [TODO] maintain prev pointer + uint32_t index; + uint8_t level; + uint8_t status; +}; + +struct flist_t{ + struct frame_t* head; +}; + +struct buddy_system_list_t{ + void* base_addr; + uint32_t index; + uint8_t max_level; +}; + +struct memory_pool_t{ + uint8_t frame_used; + uint8_t chunk_used; + uint32_t size; + uint32_t chunk_per_frame; + uint32_t chunk_offset; // use to get the offset of chunk in a frame + struct chunk_t* free_chunk; + void *frame_base_addrs[MEMORY_POOL_DEPTH]; +}; + +struct chunk_t{ + struct chunk_t* next; + struct chunk_t* prev; +}; + +static struct frame_t frame_arr[FRAME_NUM]; +static struct flist_t flist_arr[MAX_LEVEL + 1]; +static struct memory_pool_t memory_pools[MEMORY_POOL_SIZE]; +static struct buddy_system_list_t buddy_system_list[MAX_BUDDY_SYSTEM_LIST]; + +#define FREE 0 +#define ALLOCATED 1 +#define LARGE_CONTIGUOUS 2 +#define RESERVED 3 + + +static void add_to_flist(struct flist_t* flist, struct frame_t* frame) +{ + struct frame_t *curr = flist->head; + while(curr) + { + if(curr->next)curr = curr->next; + else break; + } + if(curr) curr->next = frame; + else + { + // printf("\r\n[SYSTEM INFO] Add Frame: "); printf_int(frame->index); printf(" to Level: "); printf_int(frame->level); + flist->head = frame; + // printf("\r\n[SYSTEM INFO] Frame status: "); printf_int(frame->status); + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Leave add_to_flist"); +#endif +} + +static void remove_from_flist(struct flist_t* flist, struct frame_t* frame) +{ + struct frame_t *curr = flist->head; + struct frame_t *prev = NULL; + int next_index = frame_arr[frame->index + pow_2(frame->level) - 1].next == NULL \ + ? -1 : frame_arr[frame->index + pow_2(frame->level) - 1].next->index; + frame_arr[frame->index + pow_2(frame->level) - 1].next = NULL; + while(curr) + { + if(curr == frame) + { + if(prev) prev->next = next_index == -1 ? NULL : &frame_arr[next_index]; + else flist->head = next_index == -1 ? NULL : &frame_arr[next_index]; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Remove Frame: "); printf_int(frame->index); printf(" from flist Level: "); printf_int(frame->level); +#endif + // curr->next = NULL; + return; + } + prev = curr; + curr = curr->next; + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG ERROR] Frame Not Found in flist!"); +#endif + return; +} + +static uint64_t pow_2(uint32_t n) +{ + return 1 << n; +} + +void memory_reserve(uint64_t start, uint64_t end, char* msg) +{ +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Reserve Memory from: "); printf_hex(start); printf(" to: "); printf_hex(end); +#endif + uint32_t start_index = (start - 0) >> 12; + uint32_t end_index = (end - 0) >> 12; + +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Reserve Memory from Frame: "); printf_int(start_index); printf(" to Frame: "); printf_int(end_index); + printf(" for "); printf(msg); +#endif + if(start_index == end_index) + frame_arr[start_index].status = RESERVED; + else + for(int i=start_index; i= (uint64_t)buddy_system_list[i].base_addr) + { + return i; + } + else{ + if( addr >= (uint64_t)buddy_system_list[i].base_addr + && addr < (uint64_t)buddy_system_list[i+1].base_addr ) + { + return i; + } + } + } + return -1; +} + +void print_bslist(int argc, char* argv[]) +{ + printf("\r\n========== buddy system list =========="); + for(int i=0; ilevel = get_lower_bound_level(free_cnt); +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Free Start Frame: "); printf_int(free_start->index); + printf(", Level: "); printf_int(free_start->level); +#endif + buddy_system_list[bid].index = free_start->index; + buddy_system_list[bid].base_addr = (void*)(uint64_t)(MALLOC_START_ADDR + free_start->index * FRAME_SIZE); + buddy_system_list[bid++].max_level = free_start->level; + frame_arr[free_start->index + pow_2(free_start->level) - 1].next = NULL; + add_to_flist(&flist_arr[free_start->level], free_start); + is_free_start = 1; + free_cnt = 0; + free_start = NULL; + } + } + else{ + if(is_free_start){ + buddy_system_list[bid].base_addr = &frame_arr[i]; + frame_arr[i].status = FREE; + free_start = &frame_arr[i]; + is_free_start = 0; + free_cnt = 1; + } + else{ + frame_arr[i].status = LARGE_CONTIGUOUS; + frame_arr[i].level = 0; + free_cnt++; + } + } + if(i== FRAME_NUM-1 && is_free_start==0 && free_start != NULL){ + free_start->level = get_lower_bound_level(free_cnt); +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Free Start Frame: "); printf_int(free_start->index); + printf(", Level: "); printf_int(free_start->level); printf(" "); printf_int(free_cnt); +#endif + buddy_system_list[bid].index = free_start->index; + buddy_system_list[bid].base_addr = (void*)(uint64_t)(MALLOC_START_ADDR + free_start->index * FRAME_SIZE); + buddy_system_list[bid++].max_level = free_start->level; + frame_arr[free_start->index + pow_2(free_start->level) - 1].next = NULL; + add_to_flist(&flist_arr[free_start->level], free_start); + is_free_start = 1; + free_cnt = 0; + free_start = NULL; + } + } + +#ifdef BUDDY_SYSTEM_DEBUG + int tag = 0; + printf("\r\n[SYSTEM INFO] Buddy System List (Start Frame, base_addr, max_level): \n"); +#endif + for(int i=0; i "); +#endif + if(buddy_system_list[i].base_addr == NULL) break; +#ifdef BUDDY_SYSTEM_DEBUG + printf("( "); printf_int(buddy_system_list[i].index); printf(", "); + printf_hex((uint64_t)buddy_system_list[i].base_addr); printf(", "); + printf_int(buddy_system_list[i].max_level); printf(" )"); + tag = 1; +#endif + } +} + +void print_flist(int argc, char* argv[]) +{ + printf("\r\n========== free list =========="); + for(int i=0; i<=MAX_LEVEL; i++) + { +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Level: ");printf_int(i); +#endif + struct frame_t* frame = flist_arr[i].head; + int sign = 0; + while(frame != NULL) + { + if(frame->status == FREE) + { + if(sign == 0) { printf("\r\n[SYSTEM INFO] Level: "); printf_int(i); printf(", Frame: "); } + if(sign) printf("-> "); + printf_int(frame->index); + sign = 1; + // frame = frame->next; + frame = frame_arr[frame->index + pow_2(frame->level) - 1].next; +#ifdef BUDDY_SYSTEM_DEBUG + if(frame != NULL) {printf(" (expected next: "); printf_int(frame->index); printf(")");} +#endif + } + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Leave Level: ");printf_int(i); +#endif + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Leave print_flist"); +#endif +} + +void print_allocated(int argc, char* argv[]) +{ + printf("\r\n=========== allocated ==========="); + for(int i=0; inext; + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Allocated Frame Count: "); printf_int(cnt); printf(", Expected Count: "); printf_int(expected_cnt); + printf(" , level: "); printf_int(level); +#endif + assert(cnt == expected_cnt, "Allocated Frame Count Error!"); + i--; + } + } + printf("\n==============================="); +} + +static uint64_t round_size(uint64_t size) // return size to the nearest power of 2 +{ + uint64_t ret = 1; + while(ret < size) ret <<= 1; + return ret; +} + +static uint8_t get_level(uint32_t size) +{ + uint8_t level = 0; + for(int i=FRAME_SIZE; iindex; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] From Level: "); printf_int(from_level); + printf("\r\n[DEBUG] Start Index: "); printf_int(start_index); +#endif + remove_from_flist(&flist_arr[from_level], frame); + + while(from_level > level) // e.g. get level 4 frame, but only have level 6 frame + { + from_level--; + uint64_t level_size = pow_2(from_level); + uint32_t split_index = start_index + level_size; + + frame_arr[split_index].level = from_level; + frame_arr[split_index + level_size - 1].next = NULL; + + frame_arr[split_index].status = FREE; + // printf("\r\n[SYSTEM INFO] Split Frame: "); printf_int(split_index); printf(", Level: "); printf_int(from_level); + add_to_flist(&flist_arr[from_level], &frame_arr[split_index]); + } + frame->status = ALLOCATED; + frame->level = level; + frame_arr[start_index + pow_2(level) - 1].next = NULL; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Allocate Frame: "); printf_int(frame->index); +#endif + ret = (void*)(uint64_t)(MALLOC_START_ADDR + start_index * FRAME_SIZE); + break; + } + } + if(ret == NULL) + { + printf("\r\n[SYSTEM ERROR] No Enough Memory!"); + } +#ifdef BUDDY_SYSTEM_DEBUG + print_flist(0, NULL); + print_allocated(0, NULL); +#endif + return ret; +} + +static void* get_buddy_address(void* ptr, uint8_t level) +{ + return (void*)((uint64_t)ptr ^ (pow_2(level) * FRAME_SIZE)); +} + +static uint32_t get_buddy_index(void* ptr, uint8_t level) +{ + return ((uint64_t)get_buddy_address(ptr, level) - MALLOC_START_ADDR) >> 12; +} + +int bfree(void* ptr) +{ + uint8_t max_level = buddy_system_list[get_bid((uint64_t)ptr)].max_level; + uint32_t offset = buddy_system_list[get_bid((uint64_t)ptr)].index; + + struct frame_t* curr_frame = &frame_arr[((uint64_t)ptr - MALLOC_START_ADDR) >> 12]; + + switch(curr_frame->status) + { + case FREE: +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM ERROR] Frame Already Free!"); +#endif + return 1; + case LARGE_CONTIGUOUS: +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM ERROR] Frame is belong to Large Contiguous Frame!"); +#endif + return 1; + case RESERVED: +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM ERROR] Frame is Reserved!"); +#endif + return 1; + default: + break; + } + + // printf("\r\n[SYSTEM INFO] Free Frame Address: "); printf_hex((uint64_t)ptr); + // buddy address = curr address ^ (block size) + struct frame_t* buddy_frame = &frame_arr[get_buddy_index((ptr-offset*FRAME_SIZE), curr_frame->level)+offset]; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Free Frame: "); printf_int(curr_frame->index); printf(", Level: "); printf_int(curr_frame->level); + printf("\r\n[SYSTEM INFO] Buddy Frame: "); printf_int(buddy_frame->index); printf(", Level: "); printf_int(buddy_frame->level); +#endif + if(buddy_frame->status != FREE) + { +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Buddy Frame is not FREE!"); +#endif + curr_frame->status = FREE; + } + else + { +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Buddy Frame is Free!"); +#endif + } + while(buddy_frame->status == FREE && curr_frame->level < max_level) + { + curr_frame->status = FREE; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Merge Frame:"); printf_int(curr_frame->index); printf(" and Frame: "); printf_int(buddy_frame->index); + printf(" to Level: "); printf_int(curr_frame->level + 1); +#endif + +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] remove_from_flist: level: "); printf_int(buddy_frame->level); printf(" index: "); printf_int(buddy_frame->index); +#endif + remove_from_flist(&flist_arr[buddy_frame->level], buddy_frame); + + uint32_t merge_index; + if(buddy_frame->index < curr_frame->index) + { + merge_index = buddy_frame->index; + frame_arr[buddy_frame->index + pow_2(buddy_frame->level) - 1].next = curr_frame; + curr_frame->status = LARGE_CONTIGUOUS; + } + else + { + merge_index = curr_frame->index; + frame_arr[curr_frame->index + pow_2(curr_frame->level) - 1].next = buddy_frame; + buddy_frame->status = LARGE_CONTIGUOUS; + } + +#ifdef BUDDY_SYSTEM_DEBUG + printf(" with head frame: "); printf_int(merge_index); +#endif + + curr_frame = &frame_arr[merge_index]; + curr_frame->level++; + if(curr_frame->level == max_level) + { + break; + } + buddy_frame = &frame_arr[get_buddy_index((void*)(uint64_t)(MALLOC_START_ADDR + (merge_index-offset) * FRAME_SIZE), curr_frame->level) + offset]; +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] New Frame: "); printf_int(curr_frame->index); printf(", Level: "); printf_int(curr_frame->level); + printf("\r\n[SYSTEM INFO] New Buddy Frame: "); printf_int(buddy_frame->index); printf(", Level: "); printf_int(buddy_frame->level); +#endif + } +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[SYSTEM INFO] Add Frame:"); printf_int(curr_frame->index); printf(" to Level: "); printf_int(curr_frame->level); +#endif + add_to_flist(&flist_arr[curr_frame->level], curr_frame); + return 0; +} + +void bfree_wrapper(int argc, char *argv[]) +{ + if(argc != 2){ + printf("\nUsage: test_bfree "); + return; + } + uint64_t index = atoi(argv[1]); + if(index >= FRAME_NUM){ + printf("\nIndex out of range"); + return; + } + if(!bfree((void*)(MALLOC_START_ADDR + index * FRAME_SIZE))) + { + print_flist(0, NULL); + print_allocated(0, NULL); + } +} + +void memory_pool_init() +{ + for(int i=0; isize = size; + memory_pool->chunk_per_frame = FRAME_SIZE / size; +} + +static int get_memory_pool_id(uint64_t size) +{ + uint64_t r_size = round_size(size); + + if(r_size >= FRAME_SIZE) return -1; // larger than frame size, use general balloc + + for(int i=0; i= r_size) + { + return i; + } + else if(memory_pools[i].size == 0) + { +#ifdef BUDDY_SYSTEM_DEBUG + printf("\r\n[DEBUG] Init New Memory Pool with chunk size: "); printf_int(r_size); +#endif + init_memory_pool_with_size(&memory_pools[i], r_size); + return i; + } + } + return -2; +} + +void* dynamic_alloc(uint64_t size) +{ + + int ret = get_memory_pool_id(size); + switch(ret) + { + case -1: + printf("\r\n[SYSTEM ERROR] Larger than Frame Size! Please use General balloc!"); + return 0; + case -2: + printf("\r\n[SYSTEM ERROR] No Enough Memory Pool! Please use General balloc!"); + return 0; + default: + break; + } + + struct memory_pool_t* memory_pool = &memory_pools[ret]; + + void* res = NULL; + + if(memory_pool->free_chunk != NULL) + { + res = memory_pool->free_chunk; + memzero_asm((uint64_t)res, memory_pool->size); + memory_pool->free_chunk = memory_pool->free_chunk->next; // point to the next free chunk +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] Allocate Chunk at address: "); printf_hex((uint64_t)res); printf(", in Frame: "); printf_int(((uint64_t)res - MALLOC_START_ADDR) >> 12); +#endif + return res; + } + + if(memory_pool->frame_used >= MEMORY_POOL_DEPTH * memory_pool->chunk_per_frame) + { + printf("\r\n[SYSTEM ERROR] No Enough Memory Pool Frame!"); + return res; + } + + if(memory_pool->chunk_used >= memory_pool->frame_used * memory_pool->chunk_per_frame) + { + if(memory_pool->frame_used == 0) + { +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] Create First Frame for Memory Pool with size: ");printf_int(memory_pool->size); +#endif + } + else + { +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] The Frame of Memory Pool with size: ");printf_int(memory_pool->size);printf(" is Full! "); + printf("Create a New Frame!"); +#endif + } + + void* new_frame = balloc(FRAME_SIZE); + memory_pool->frame_base_addrs[memory_pool->frame_used] = new_frame; + memory_pool->frame_used++; + memory_pool->chunk_offset = 0; + } + + // printf("\r\n[SYSTEM INFO] Allocate Chunk in Memory Pool with size: "); printf_int(memory_pool->size); + // printf(" in Frame: "); printf_int(((struct frame_t*)memory_pool->frame_base_addrs[memory_pool->frame_used - 1])->index); + + res = memory_pool->frame_base_addrs[memory_pool->frame_used - 1] + memory_pool->chunk_offset * memory_pool->size; +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] Allocate Chunk at address: "); printf_hex((uint64_t)res); printf(", in Frame: "); printf_int(((uint64_t)res - MALLOC_START_ADDR) >> 12); +#endif + memory_pool->chunk_offset++; + memory_pool->chunk_used++; + memzero_asm((uint64_t)res, memory_pool->size); + return res; +} + +int dfree(void* ptr) +{ + int memory_pool_index = -1; + for(int i=0; i>12; // 2^12 = 4096 = FRAME_SIZE + struct memory_pool_t* memory_pool = &memory_pools[memory_pool_index]; + + // check whether the chunk is already in the free chunk list + struct chunk_t* head_free_chunk = memory_pool->free_chunk; + while(head_free_chunk) + { + if(head_free_chunk == ptr) + { + printf("\r\n[SYSTEM ERROR] Chunk Already Free!"); + return 1; + } + head_free_chunk = head_free_chunk->next; + } +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] Free Chunk in Frame: "); printf_int(((uint64_t)ptr - MALLOC_START_ADDR) >>12); +#endif + memory_pool->chunk_used--; + struct chunk_t* last_free_chunk = memory_pool->free_chunk; + memory_pool->free_chunk = (struct chunk_t*)ptr; + memory_pool->free_chunk->next = last_free_chunk; +#ifdef DYNAMIC_ALLOC_DEBUG + printf("\r\n[SYSTEM INFO] Free Chunk at address: "); printf_hex((uint64_t)ptr); +#endif + return 0; +} \ No newline at end of file diff --git a/lab08/kernel/src/boot.S b/lab08/kernel/src/boot.S new file mode 100644 index 000000000..30d694fb6 --- /dev/null +++ b/lab08/kernel/src/boot.S @@ -0,0 +1,48 @@ +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 + and x0, x0,#0xFF // Check processor id + cbz x0, master // if cpu_id == 0, then booting + b proc_hang // Otherwise, hang + +proc_hang: + b proc_hang + +master: + bl from_el2_to_el1 + +exception_table: + bl set_exception_vector_table + +bss_init: + adr x0, __bss_start + adr x1, __bss_size + bl memzero + + adr x1, _start + mov sp, x1 + bl main // jump to kernel_main c code + b proc_hang // should never come here + +memzero: + str xzr, [x0], #8 // xzr: a register holds zero + subs x1, x1, #8 + b.gt memzero + ret + +// adr: Load a label's relative address into the target register. + +set_exception_vector_table: + adr x0, exception_vector_table // get the base address of the exception vector table + msr vbar_el1, x0 // set the base address of the exception vector table + ret + +from_el2_to_el1: + mov x0, (1 << 31) // EL1 uses aarch64 + msr hcr_el2, x0 // msr: Status Register <-- Register (page 1924) + mov x0, 0x3c5 // EL1h (SPSel = 1) with interrupt disabled (D = 1, A = 1, I = 1, F = 1, M[3:0] = 5) + msr spsr_el2, x0 // Save the current processor's state + msr elr_el2, lr // Save the exception return address + eret // return to EL1 (use eret to return from the exception) \ No newline at end of file diff --git a/lab08/kernel/src/bootload.c b/lab08/kernel/src/bootload.c new file mode 100644 index 000000000..9c0e0ae2f --- /dev/null +++ b/lab08/kernel/src/bootload.c @@ -0,0 +1,43 @@ +#include "bootload.h" +#include "mini_uart.h" +#include "io.h" + +// uint64_t* BootHead = (uint64_t*)KernelAddr; +// uint64_t* CopyHead = (uint64_t*)BootAddr; +// uint64_t* bss_end = (uint64_t*)(&__bss_end); + +void reallocate() +{ + uint64_t* BootHead = (uint64_t*)KernelAddr; + uint64_t* CopyHead = (uint64_t*)BootAddr; + uint64_t* bss_end = (uint64_t*)(&__bss_end); + // int i = 0; + while(BootHead != bss_end){ + // printf("\n"); + // printf_hex(i); + // i++; + *CopyHead = *BootHead; + CopyHead++; + BootHead++; + } + printf("\nCopy done."); +} + +void load_kernel() +{ + unsigned int kernel_size = 0; + for(int i=0; i<4; i++){ + kernel_size <<= 8; + kernel_size |= (uart_recv() & 0xff); + } + + printf("\nKernel Size: "); + printf_hex(kernel_size); + printf("\n"); + + unsigned char* kernel = (unsigned char*)(0x80000); + unsigned char* kernel_ptr = kernel; + for(unsigned int i=0; ic_namesize, 16, 8); + int filesize = strtol(head->c_filesize, 16, 8); + + // char *filename = (void*)head + head_size; + char filename[256]; + strncpy(filename, (void*)head + head_size, namesize); + /* The above statement equal to the following: + char filename[256]; + strncpy(filename, (void*)head + head_size, namesize); + + In New ASCII format, the filename is followed by the header + */ + + if(strcmp(filename, "TRAILER!!!") == 0) break; + + printf("\r\n"); + printf(filename); + + uint32_t offset = head_size + namesize; + if(offset % 4 != 0) offset = ((offset/4 +1)*4); + if(filesize % 4 != 0) filesize = (filesize/4 +1)*4; + /* New ASCII format + header size + filename size must be multiple of 4 + filesize must be multiple of 4 + */ + + head = (void*)head + offset + filesize; + /* + Why (void*)head instead of head? + In C, when you add an integer to a pointer, + in this case, + head = head + (offset + filesize)*sizeof(cpio_newc_header) in practical. + But (offset + filesize) is the byte size, not the number of cpio_newc_header. + So, we need to cast head to void* to make it byte size. + */ + } +} + +void cpio_cat(int argc, char **argv) +{ + // printf("\nFilename: "); + // char input_filename[256]; + // readcmd(input_filename); + if(argc < 2){ + printf("\nUsage: cat "); + return; + } + char *input_filename = argv[1]; + +#ifndef QEMU + cpio_newc_header* head = (void*)(uint64_t)CPIO_START_ADDR_FROM_DT; +#else + cpio_newc_header* head = (void*)(uint64_t)CPIO_ADDR; +#endif + + uint32_t head_size = sizeof(cpio_newc_header); + + while(1) + { + int namesize = strtol(head->c_namesize, 16, 8); + int filesize = strtol(head->c_filesize, 16, 8); + + char *filename = (void*)head + head_size; + + uint32_t offset = head_size + namesize; + if(offset % 4 != 0) offset = ((offset/4 +1)*4); + + if(strcmp(filename, "TRAILER!!!") == 0){ + printf("\nFile not found"); + break; + } + else if(strcmp(filename, input_filename) == 0){ + /* The filedata is appended after filename */ + char *filedata = (void*)head + offset; + printf("\n"); + for(int i=0; i"); + return; + } + + char *input_filename = argv[1]; + +#ifndef QEMU + cpio_newc_header* head = (void*)(uint64_t)CPIO_START_ADDR_FROM_DT; +#else + cpio_newc_header* head = (void*)(uint64_t)CPIO_ADDR; +#endif + + uint32_t head_size = sizeof(cpio_newc_header); + while(1) + { + int namesize = strtol(head->c_namesize, 16, 8); + int filesize = strtol(head->c_filesize, 16, 8); + + char *filename = (void*)head + head_size; + + uint32_t offset = head_size + namesize; + if(offset % 4 != 0) offset = ((offset/4 +1)*4); + + if(strcmp(filename, "TRAILER!!!") == 0){ + printf("\nFile not found"); + break; + } + else if(strcmp(filename, input_filename) == 0){ + /* The filedata is appended after filename */ + char *filedata = (void*)head + offset; + char *user_program_addr = (void*)(uint64_t)USER_START_ADDR; + for(int i=0; ic_namesize, 16, 8); + int filesize = strtol((*head)->c_filesize, 16, 8); + // *c_mode = (*head)->c_mode; + + uint32_t head_size = sizeof(cpio_newc_header); + + char *filename = (void*)(*head) + head_size; + *pathname = filename; + + uint32_t offset = head_size + namesize; + if(offset % 4 != 0) offset = ((offset/4 +1)*4); + + if(strcmp(filename, "TRAILER!!!") == 0){ + // do nothing + } + else{ + /* The filedata is appended after filename */ + *filedata = (void*)(*head) + offset; + ret = 0; + } + + if(filesize % 4 != 0) filesize = (filesize/4 +1)*4; + *head = (void*)(*head) + offset + filesize; + return ret; +} + +#ifndef QEMU +void initramfs_callback(char* node_name, char* property_name, fdt_prop* prop) +{ + // reference: https://stackoverflow.com/questions/73974443/how-does-the-linux-kernel-know-about-the-initrd-when-booting-with-a-device-tree + if((strcmp(node_name, "chosen") == 0) && (strcmp(property_name, "linux,initrd-start") == 0)){ + void *data = (void*)prop + sizeof(fdt_prop); + CPIO_START_ADDR_FROM_DT = endian_swap(*(uint32_t*)data); + printf("\nInitramfs Start Address from DT: "); + printf_hex(CPIO_START_ADDR_FROM_DT); + } + if((strcmp(node_name, "chosen") == 0) && (strcmp(property_name, "linux,initrd-end") == 0)){ + void *data = (void*)prop + sizeof(fdt_prop); + CPIO_END_ADDR_FROM_DT = endian_swap(*(uint32_t*)data); + printf("\nInitramfs End Address from DT: "); + printf_hex(CPIO_END_ADDR_FROM_DT); + } +} +#endif \ No newline at end of file diff --git a/lab08/kernel/src/dev_framebuffer.c b/lab08/kernel/src/dev_framebuffer.c new file mode 100644 index 000000000..ba0745f86 --- /dev/null +++ b/lab08/kernel/src/dev_framebuffer.c @@ -0,0 +1,134 @@ +#include "vfs.h" +#include "dev_framebuffer.h" +#include "io.h" +#include "alloc.h" +#include "mailbox.h" +#include "peripherals/mailbox.h" +#include "string.h" + + +extern void disable_irq(); +extern void enable_irq(); + +//The following code is for mailbox initialize used in lab7. +unsigned int width, height, pitch, isrgb; /* dimensions and channel order */ +unsigned char *lfb; /* raw frame buffer address */ + +struct file_operations dev_framebuffer_operations = { + dev_framebuffer_write, + 0, // read + dev_framebuffer_open, + dev_framebuffer_close, + 0, // getsize + dev_framebuffer_lseek64 +}; + +unsigned int __attribute__((aligned(16))) mbox_s[36]; + +int dev_framebuffer_register() +{ + printf("Registering framebuffer device..."); + //The following code is for mailbox initialize used in lab7. + mbox_s[0] = 35 * 4; + mbox_s[1] = TAG_REQUEST_CODE; + + mbox_s[2] = 0x48003; // set phy wh + mbox_s[3] = 8; + mbox_s[4] = 8; + mbox_s[5] = 1024; // FrameBufferInfo.width + mbox_s[6] = 768; // FrameBufferInfo.height + + mbox_s[7] = 0x48004; // set virt wh + mbox_s[8] = 8; + mbox_s[9] = 8; + mbox_s[10] = 1024; // FrameBufferInfo.virtual_width + mbox_s[11] = 768; // FrameBufferInfo.virtual_height + + mbox_s[12] = 0x48009; // set virt offset + mbox_s[13] = 8; + mbox_s[14] = 8; + mbox_s[15] = 0; // FrameBufferInfo.x_offset + mbox_s[16] = 0; // FrameBufferInfo.y.offset + + mbox_s[17] = 0x48005; // set dembox_sh + mbox_s[18] = 4; + mbox_s[19] = 4; + mbox_s[20] = 32; // FrameBufferInfo.dembox_sh + + mbox_s[21] = 0x48006; // set pixel order + mbox_s[22] = 4; + mbox_s[23] = 4; + mbox_s[24] = 1; // RGB, not BGR preferably + + mbox_s[25] = 0x40001; // get framebuffer, gets alignment on request + mbox_s[26] = 8; + mbox_s[27] = 8; + mbox_s[28] = 4096; // FrameBufferInfo.pointer + mbox_s[29] = 0; // FrameBufferInfo.size + + mbox_s[30] = 0x40008; // get pitch + mbox_s[31] = 4; + mbox_s[32] = 4; + mbox_s[33] = 0; // FrameBufferInfo.pitch + + mbox_s[34] = MBOX_TAG_LAST; + + // this might not return exactly what we asked for, could be + // the closest supported resolution instead + if (mailbox_call_s(MBOX_CH_PROP, mbox_s) && mbox_s[20] == 32 && mbox_s[28] != 0) + { + mbox_s[28] &= 0x3FFFFFFF; // convert GPU address to ARM address + width = mbox_s[5]; // get actual physical width + height = mbox_s[6]; // get actual physical height + pitch = mbox_s[33]; // get number of bytes per line + isrgb = mbox_s[24]; // get the actual channel order + lfb = ((void *)((unsigned long)mbox_s[28])); // raw frame buffer address + } + else + { + printf("Unable to set screen resolution to 1024x768x32\n"); + } + + return register_dev(&dev_framebuffer_operations); +} + +int dev_framebuffer_write(struct file *file, const void *buf, size_t len) +{ + enable_irq(); + if (len + file->f_pos > pitch * height) + { + printf("\r\n[ERROR] Invlaid Write framebuffer!"); + len = pitch * height - file->f_pos; + } + for(int i=0; if_pos))[i] = ((char*)buf)[i]; + } + file->f_pos += len; + disable_irq(); + return len; +} + +int dev_framebuffer_open(struct vnode *file_node, struct file **target) +{ + printf("\r\n[INFO] Opening framebuffer device..."); + (*target)->f_pos = 0; + (*target)->vnode = file_node; + (*target)->f_ops = &dev_framebuffer_operations; + return 0; +} + +int dev_framebuffer_close(struct file *file) +{ + dfree(file); + return 0; +} + +long dev_framebuffer_lseek64(struct file *file, long offset, int whence) +{ + if (whence == SEEK_SET) + { + file->f_pos = offset; + return file->f_pos; + } + return -1; +} diff --git a/lab08/kernel/src/dev_uart.c b/lab08/kernel/src/dev_uart.c new file mode 100644 index 000000000..d0eddfab8 --- /dev/null +++ b/lab08/kernel/src/dev_uart.c @@ -0,0 +1,58 @@ +#include "dev_uart.h" +#include "mini_uart.h" +#include "alloc.h" + +struct file_operations dev_file_operations = { + dev_uart_write, + dev_uart_read, + dev_uart_open, + dev_uart_close, + 0 // getsizeq +}; + + +int dev_uart_register() +{ + uart_send_string("\r\n[INFO] Registering uart device..."); + return register_dev(&dev_file_operations); +} + +int dev_uart_write(struct file *file, const void *buf, size_t len) +{ + uart_send_string("\r\n[INFO] Writing to console..."); + const char *cbuf = buf; + for (int i = 0; i < len;i++) + { + uart_send(cbuf[i]); + } + return len; +} + +int dev_uart_read(struct file *file, void *buf, size_t len) +{ + uart_send_string("\r\n[INFO] Reading from uart..."); + for (int i = 0; i < len; i++) + { + ((char*)buf)[i] = uart_recv(); + } + return len; +} + +int dev_uart_open(struct vnode *file_node, struct file **target) +{ + uart_send_string("\r\n[INFO] Opening uart device..."); + (*target)->vnode = file_node; + (*target)->f_ops = &dev_file_operations; + return 0; +} + +int dev_uart_close(struct file *file) +{ + dfree(file); + return 0; +} + +int dev_uart_op_deny() +{ + return -1; +} diff --git a/lab08/kernel/src/devicetree.c b/lab08/kernel/src/devicetree.c new file mode 100644 index 000000000..cfb61bfe8 --- /dev/null +++ b/lab08/kernel/src/devicetree.c @@ -0,0 +1,94 @@ +#include "devicetree.h" +#include "string.h" +#include "io.h" +#include "type.h" + +void fdt_traverse(void(*callback_func)(char*, char*, fdt_prop*)) +{ + fdt_header *dt_header = (fdt_header*)(*DTB_ADDR); + printf("\nDTB Address (Function): "); + printf_hex((uint64_t)(void*)(dt_header)); + + uint32_t dt_struct_off = endian_swap(dt_header->off_dt_struct); + uint32_t dt_string_off = endian_swap(dt_header->off_dt_strings); + + void* dt_struct_addr = (void*)*DTB_ADDR + dt_struct_off; + char* dt_string_addr = (void*)*DTB_ADDR + dt_string_off; + + + printf("\nDT String Address: "); + printf_hex((uint64_t)(void*)dt_string_addr); + printf("\nDT Struct Address: "); + printf_hex((uint64_t)(void*)dt_struct_addr); + + printf("\nMagic: "); + printf_hex(endian_swap(dt_header->magic)); + if(dt_header->magic == (uint32_t)0xd00dfeed) + { + printf("Magic Failed\n"); + return; + } + + + char* node_name; + char* prop_name; + + while(1) + { + uint32_t token = endian_swap((*(uint32_t*)dt_struct_addr)); + + switch (token) + { + case FDT_BEGIN_NODE: // It shall be followed by the node’s unit name as extra data. + { + node_name = (char*)dt_struct_addr + 4; // tage size is 32bits = 4bytes + uint32_t size = strlen(node_name); // size of node name + uint32_t offset = 4 + size + 1; + + if(offset % 4 !=0) offset = ((offset/4 + 1)*4); // align to 4bytes (32bits) + dt_struct_addr = dt_struct_addr + offset; + + break; + } + case FDT_END_NODE: //This token has no extra data; so it is followed immediately by the next token + { + dt_struct_addr = dt_struct_addr + 4; break; + } + case FDT_PROP: + { + fdt_prop* prop_ptr = (fdt_prop*)(dt_struct_addr + 4); + uint32_t offset = 4 + sizeof(fdt_prop) + endian_swap(prop_ptr->len); + + if(offset % 4 != 0) offset = ((offset/4 + 1)*4); + dt_struct_addr = dt_struct_addr + offset; + + prop_name = (void*)dt_string_addr + endian_swap(prop_ptr->nameoff); + + callback_func(node_name, prop_name, prop_ptr); + + break; + } + case FDT_NOP: + { + dt_struct_addr = dt_struct_addr + 4; break; + } + case FDT_END: + { + dt_struct_addr = dt_struct_addr + 4; break; + } + default: + return; + } + } + +} + +// big endian to little endian +uint32_t endian_swap(uint32_t value) +{ + uint32_t ret = 0; + uint8_t* ptr = (void*)&value; + ret = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]; + return ret; +} + diff --git a/lab08/kernel/src/entry.S b/lab08/kernel/src/entry.S new file mode 100644 index 000000000..8d7d4fd22 --- /dev/null +++ b/lab08/kernel/src/entry.S @@ -0,0 +1,235 @@ +#include "entry.h" +#include "sys.h" +#include "peripherals/irq.h" + +.section ".text" + +.global set_exception_vector_table + + +// save general registers to stack +.macro save_all el + //bl save_all_debug + sub sp, sp, 16*17 + stp x0, x1, [sp ,16 * 0] // storing the contents of x0 and x1 to the address pointed by the stack pointer sp with an offset of 16 bytes + stp x2, x3, [sp ,16 * 1] // stp: Store Pair and it's used to store a pair of 64-bit (8-byte) registers to memory + stp x4, x5, [sp ,16 * 2] + stp x6, x7, [sp ,16 * 3] + stp x8, x9, [sp ,16 * 4] + stp x10, x11, [sp ,16 * 5] + stp x12, x13, [sp ,16 * 6] + stp x14, x15, [sp ,16 * 7] + stp x16, x17, [sp ,16 * 8] + stp x18, x19, [sp ,16 * 9] + stp x20, x21, [sp ,16 * 10] + stp x22, x23, [sp ,16 * 11] + stp x24, x25, [sp ,16 * 12] + stp x26, x27, [sp ,16 * 13] + stp x28, x29, [sp ,16 * 14] + + .if \el == 0 // using two distinct stack pointers for EL0 and EL1 + mrs x21, sp_el0 + .else + add x21, sp, 16*17 // using the same stack pointer for EL1 & sp will be switched by the cpu_switch_to function + .endif + + mrs x22, elr_el1 + mrs x23, spsr_el1 + + stp x30, x21, [sp ,16 * 15] + stp x22, x23, [sp ,16 * 16] +.endm + +// load general registers from stack +.macro load_all el + //bl load_all_debug + ldp x22, x23, [sp ,16 * 16] + ldp x30, x21, [sp ,16 * 15] + + .if \el == 0 + msr sp_el0, x21 + .endif + + msr elr_el1, x22 + msr spsr_el1, x23 + + ldp x0, x1, [sp ,16 * 0] + ldp x2, x3, [sp ,16 * 1] + ldp x4, x5, [sp ,16 * 2] + ldp x6, x7, [sp ,16 * 3] + ldp x8, x9, [sp ,16 * 4] + ldp x10, x11, [sp ,16 * 5] + ldp x12, x13, [sp ,16 * 6] + ldp x14, x15, [sp ,16 * 7] + ldp x16, x17, [sp ,16 * 8] + ldp x18, x19, [sp ,16 * 9] + ldp x20, x21, [sp ,16 * 10] + ldp x22, x23, [sp ,16 * 11] + ldp x24, x25, [sp ,16 * 12] + ldp x26, x27, [sp ,16 * 13] + ldp x28, x29, [sp ,16 * 14] + ldr x30, [sp, 16 * 15] + add sp, sp, 16*17 +.endm + +.macro ventry label + b \label // branch to a handler function. + .align 7 // entry size is 0x80, .align will pad 0 +.endm + + +.global exception_vector_table +.align 11 // vector table should be aligned to 0x800 (2^11 = 0x1000_0000_0000 = 0x800) +exception_vector_table: + + //========================================================== + // Exception from the current EL while using SP_EL0 (exception level not changed) + + ventry SYNC_EL1T /* Synchronous EL1t */ + ventry IRQ_EL1T /* IRQ or vIRQ EL1t */ + ventry FIQ_EL1T /* FIQ or vFIQ EL1t */ + ventry SERROR_EL1T /* SError or vSError EL1t */ + + + //========================================================== + // Exception from the current EL while using SP_ELx (exception level not changed) + + ventry SYNC_EL1H /* Synchronous EL1h */ + ventry EL1_IRQ /* IRQ or vIRQ EL1h */ + ventry FIQ_EL1H /* FIQ or vFIQ EL1h */ + ventry SERROR_EL1H /* SError or vSError EL1h */ + + //========================================================== + // Exception from a lower EL and all lower ELs are AArch64 (Moves to higher exception level) + + ventry EL0_SYNC /* Synchronous EL0t */ + ventry EL0_IRQ /* IRQ or vIRQ EL0t */ + ventry FIQ_64_EL0T /* FIQ or vFIQ EL0t */ + ventry SERROR_64_EL0T /* SError or vSError EL0t */ + //========================================================== + // Exception from a lower EL and all lower ELs are AArch32 Moves to higher exception level + + ventry SYNC_32_EL0T /* Synchronous 32-bit EL0t */ + ventry IRQ_32_EL0T /* IRQ or vIRQ 32-bit EL0t */ + ventry FIQ_32_EL0T /* FIQ or vFIQ 32-bit EL0t */ + ventry SERROR_32_EL0T /* SError or vSError 32-bit EL0t */ + + +.macro handle_invalid_entry el, type + save_all \el + mov x0, #\type + mrs x1, spsr_el1 + mrs x2, elr_el1 + mrs x3, esr_el1 + bl invalid_exception_entry + b error_hang +.endm + +SYNC_EL1T: + handle_invalid_entry 1, SYNC_INVALID_EL1t + +IRQ_EL1T: + handle_invalid_entry 1, IRQ_INVALID_EL1t + +FIQ_EL1T: + handle_invalid_entry 1, FIQ_INVALID_EL1t + +SERROR_EL1T: + handle_invalid_entry 1, ERROR_INVALID_EL1t + +SYNC_EL1H: + handle_invalid_entry 1, SYNC_INVALID_EL1h + +EL1_IRQ: + save_all 1 + bl irq_handler + load_all 1 + eret + +FIQ_EL1H: + handle_invalid_entry 1, FIQ_INVALID_EL1h + +SERROR_EL1H: + handle_invalid_entry 1, ERROR_INVALID_EL1h + +EL0_SYNC: //[TODO] + save_all 0 + mrs x25, esr_el1 + lsr x24, x25, #ESR_ELx_EC_SHIFT + cmp x24, #ESR_ELx_EC_SVC64 // check if the exception is a system call + b.eq el0_svc + handle_invalid_entry 0, SYNC_ERROR // if not a system call, handle the exception + +EL0_IRQ: + save_all 0 + bl irq_handler + load_all 0 + eret + +FIQ_64_EL0T: + handle_invalid_entry 0, FIQ_INVALID_EL0_64 + +SERROR_64_EL0T: + handle_invalid_entry 0, ERROR_INVALID_EL0_64 + +SYNC_32_EL0T: + handle_invalid_entry 0, SYNC_INVALID_EL0_32 + +IRQ_32_EL0T: + handle_invalid_entry 0, IRQ_INVALID_EL0_32 + +FIQ_32_EL0T: + handle_invalid_entry 0, FIQ_INVALID_EL0_32 + +SERROR_32_EL0T: + handle_invalid_entry 0, ERROR_INVALID_EL0_32 + + +// creates alias +sc_nr .req x25 // number of system calls +scno .req x26 // syscall number +stbl .req x27 // syscall table pointer + +.global from_el1_to_el0 +from_el1_to_el0: + mov x2, 0x3c0 + msr spsr_el1, x2 + msr sp_el0, x1 // pass the stack pointer address from arg + msr elr_el1, x0 // pass the program's start address from arg + eret + +.global ret_from_fork // entry point for executing the process +ret_from_fork: + bl schedule_tail // preemptive enable + cbz x19, ret_to_user + mov x0, x20 + blr x19 //should never return, except for kp_to_user + +ret_to_user: + bl disable_irq + load_all 0 + eret + +el0_svc: + adr stbl, sys_call_table // load syscall table pointer + uxtw scno, w8 // syscall number in w8, uxtw: Unsigned Extend Word + mov sc_nr, #__NR_syscalls + bl enable_irq + cmp scno, sc_nr // check upper syscall limit + b.hs ni_sys // hs: higher or same + + ldr x16, [stbl, scno, lsl #3] // address in the syscall table, x16 = stbl[scno] + blr x16 // call sys_* routine + b ret_from_syscall + +ret_from_syscall: + bl disable_irq + str x0, [sp, #S_X0] // returned x0 (overwritten the original x0 value on the stack) + load_all 0 + eret + +ni_sys: + handle_invalid_entry 0, SYSCALL_ERROR + +error_hang: + b error_hang \ No newline at end of file diff --git a/lab08/kernel/src/fork.c b/lab08/kernel/src/fork.c new file mode 100644 index 000000000..7fb5c823f --- /dev/null +++ b/lab08/kernel/src/fork.c @@ -0,0 +1,148 @@ +#include "fork.h" +#include "alloc.h" +#include "schedule.h" +#include "io.h" +#include "mm.h" +#include "vfs.h" +#include "string.h" + +extern void ret_from_fork(void); +extern int nr_tasks; +extern struct task_struct * task[NR_TASKS]; +extern void memzero(unsigned long begin, unsigned long len); + +int copy_process( + unsigned long flags, + unsigned long fn, + unsigned long arg, + unsigned long stack) +{ + preempt_disable(); + struct task_struct *p; + + int pid = -1; + for(pid = 0; pid< NR_TASKS; pid++) + if(task[pid] == NULL) break; + if(pid == -1) + { + printf("\r\n[ERROR] Thread limit exceeded"); + goto finish; + } + // p = (struct task_struct *) balloc(sizeof(struct task_struct)); + p = (struct task_struct *) balloc(THREAD_SIZE); + printf("\r\n[INFO] Process allocated at "); printf_hex((unsigned long)p); + if (!p) + return -1; + + struct pt_regs *childregs = task_pt_regs(p); + memzero_asm((unsigned long)childregs, sizeof(struct pt_regs)); + memzero_asm((unsigned long)&p->cpu_context, sizeof(struct cpu_context)); + + // clear the file descriptor table + p->fd_table.count = 0; + for(int i=0; ifd_table.fds[i] = NULL; + + // create stdin, stdout, stderr + // p->fd_table.fds[0] = (struct file*)dynamic_alloc(sizeof(struct file)); + // p->fd_table.fds[1] = (struct file*)dynamic_alloc(sizeof(struct file)); + // p->fd_table.fds[2] = (struct file*)dynamic_alloc(sizeof(struct file)); + vfs_open("/dev/uart", O_RW, &p->fd_table.fds[0]); + vfs_open("/dev/uart", O_RW, &p->fd_table.fds[1]); + vfs_open("/dev/uart", O_RW, &p->fd_table.fds[2]); + // printf("\r\n[INFO] File descriptor table created"); + // printf("\r\n[INFO] File descriptor 0: "); printf_hex((unsigned long)p->fd_table.fds[0]); + // printf("\r\n[INFO] File descriptor 1: "); printf_hex((unsigned long)p->fd_table.fds[1]); + // printf("\r\n[INFO] File descriptor 2: "); printf_hex((unsigned long)p->fd_table.fds[2]); + + if(flags & PF_KTHREAD) // is a kernel thread + { + p->cpu_context.x19 = fn; + p->cpu_context.x20 = arg; + } + else + { + struct pt_regs *cur_regs = task_pt_regs(current); + + // copy the current process state to the new process + for(int i=0; iregs[0] = 0; // child process return value + // next sp for the new task is set to the top of the new user stack + // save the stack pointer to cleanup the stack when task finishes + unsigned long stack_used = current->stack + THREAD_SIZE - cur_regs->sp; + + // copy the stack to the new process + childregs->sp = stack + THREAD_SIZE - stack_used; + for(int i=0; isp)[i] = ((char*)cur_regs->sp)[i]; + + p->stack = stack; + + // copy the file descriptor table + p->fd_table.count = current->fd_table.count; + for(int i=0; ifd_table.fds[i] != NULL){ + p->fd_table.fds[i] = (struct file *)dynamic_alloc(sizeof(struct file)); + p->fd_table.fds[i] = current->fd_table.fds[i]; + } + } + } + p->flags = flags; + p->priority = current->priority; + p->state = TASK_RUNNING; + p->counter = p->priority; + p->preempt_count = 1; //disable preemtion until schedule_tail + strcpy(p->cwd, current->cwd); + + + p->cpu_context.pc = (unsigned long)ret_from_fork; // for the first time, pc is set to ret_from_fork + p->cpu_context.sp = (unsigned long)childregs; + + task[pid] = p; + p->pid = pid; + printf("\r\n[INFO] Process created with pid: "); printf_int(pid); +finish: + preempt_enable(); + return pid; +} + +int move_to_user_mode(unsigned long pc) +{ + struct pt_regs *regs = task_pt_regs(current); // get current process state + // memzero_asm((unsigned long)regs, sizeof(struct pt_regs)); + + regs->pc = pc; // point to the function that need to be executed in user mode + regs->pstate = PSR_MODE_EL0t; // EL0t is user state + + unsigned long stack = (unsigned long)balloc(THREAD_SIZE); //allocate new user stack + memzero_asm(stack, THREAD_SIZE); + + if (!stack) { // if stack allocation failed + return -1; + } + + // allocate stack for user process + // set sp to the top of the stack + regs->sp = stack + THREAD_SIZE; + current->stack = stack; + return 0; +} + + +// calculate the location of pt_regs in the task_struct +// task_struct is allocated at the end of the stack +// pt_regs is allocated at the top of the task_struct +struct pt_regs * task_pt_regs(struct task_struct *tsk){ + unsigned long p = (unsigned long)tsk + THREAD_SIZE - sizeof(struct pt_regs); + return (struct pt_regs *)p; +} + +void kp_user_mode(unsigned long func){ // Kernel process(func pass by argu) to user mode + printf("\r\nKernel process started. Switching to user mode..."); + int err = move_to_user_mode(func); + if (err < 0){ + printf("Error while moving process to user mode\n\r"); + } +} diff --git a/lab08/kernel/src/initramfs.c b/lab08/kernel/src/initramfs.c new file mode 100644 index 000000000..3e05dd72a --- /dev/null +++ b/lab08/kernel/src/initramfs.c @@ -0,0 +1,256 @@ +#include "initramfs.h" +#include "alloc.h" +#include "errno.h" +#include "io.h" +#include "string.h" +#include "lib.h" +#include "cpio.h" + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +struct vnode_operations *initramfs_v_ops; +struct file_operations *initramfs_f_ops; + + +static struct vnode* initramfs_create_vnode(const char *name, int type, struct vnode *parent); +static int isFileInSubDir(const char* pathname); + +int initramfs_setup_mount(struct filesystem* fs, struct mount **mount) // mount the filesystem to the mount point +{ + (*mount)->fs = fs; + (*mount)->root = initramfs_create_vnode("/", DIR_NODE, NULL); + +#ifndef QEMU + cpio_newc_header* head = (void*)(uint64_t)CPIO_START_ADDR_FROM_DT; +#else + cpio_newc_header* head = (void*)(uint64_t)CPIO_ADDR; +#endif + // vfs_chdir("/initramfs"); + while(1) + { + char* pathname; + char* filedata; + int filesize = strtol(head->c_filesize, 16, 8); + char c_mode[5]; + strncpy(c_mode, head->c_mode, 5); + int ret = cpio_newc_parser(&head, &pathname, &filedata); + if(ret == 1)break; + if(filesize > INITRAMFS_MAX_FILE){ + printf("\r\n[SYSTEM INFO] File: "); printf(pathname); printf(" is too large to fit in initramfs"); + continue; + } + // printf("\r\n[INITRAMFS INFO] Mount Archive: "); printf(pathname); printf("\t, cmode: "); printf(c_mode); + struct initramfs_internal *root_internal = (struct initramfs_internal*)(*mount)->root->internal; + + if(!strcmp(c_mode, "00008")){ // file + if(!strcmp(pathname, ".") || !strcmp(pathname, "..") || isFileInSubDir(pathname))continue; + struct vnode *filevnode = initramfs_create_vnode(pathname, FILE_NODE, (*mount)->root); + struct initramfs_internal *fileinode = (struct initramfs_internal*)filevnode->internal; + strncpy(fileinode->data, filedata, filesize); + fileinode->size = 0; + fileinode->filesize = filesize; + root_internal->children[root_internal->size++] = filevnode; + printf("\r\n[INITRAMFS INFO] Mount Archive: "); printf(pathname); + for(int i=0; i<10-strlen(pathname); i++) printf(" "); + printf("\t, cmode: "); printf(c_mode); + printf("\t, size: "); printf_hex(filesize); + } + else if(!strcmp(c_mode, "00004")){ // directory + // cannot create directory in initramfs + } + else{ + printf("\r\n[ERROR] Unsupported file type"); + return -1; + } + } + printf("\r\n[INITRAMFS INFO] Mounting complete"); + + return 0; +} + +static struct vnode* initramfs_create_vnode(const char *name, int type, struct vnode *parent) +{ + struct initramfs_internal *internal = (struct initramfs_internal*)dynamic_alloc(sizeof(struct initramfs_internal)); + + if(sizeof(name) > COMPONENT_SIZE){ + printf("\r\n[ERROR] File name too long"); + return NULL; + } + internal->name = (char*)dynamic_alloc(COMPONENT_SIZE); + strcpy(internal->name, name); + internal->size = 0; + if(type == FILE_NODE){ + internal->data = (char*)balloc(INITRAMFS_MAX_FILE); + } + else{ + internal->data = NULL; + } + internal->type = type; + // internal->parent = parent; + // internal->next = NULL; + for(int i=0; ichildren[i] = NULL; + } + struct vnode *vnode = (struct vnode*)dynamic_alloc(sizeof(struct vnode)); + vnode->parent = parent; + vnode->mount = NULL; + vnode->v_ops = initramfs_v_ops; + vnode->f_ops = initramfs_f_ops; + vnode->internal = internal; + return vnode; +} + +int initramfs_register() +{ + // check if tmpfs already registered + int i=0; + for(; ilookup = initramfs_lookup; + initramfs_v_ops->list = initramfs_list; + initramfs_v_ops->create = initramfs_create; + initramfs_v_ops->mkdir = initramfs_mkdir; + + initramfs_f_ops->open = initramfs_open; + initramfs_f_ops->read = initramfs_read; + initramfs_f_ops->write = initramfs_write; + initramfs_f_ops->close = initramfs_close; + initramfs_f_ops->getsize = initramfs_getsize; + initramfs_f_ops->lseek64 = NULL; + + return 0; +} + +int initramfs_list(struct vnode* dir_node) +{ + // 1. List all the files in the directory + // 2. Return error code if fails + + printf("\r\n[INITRAMFS LIST]"); + struct initramfs_internal *internal = (struct initramfs_internal*)dir_node->internal; + + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot list in a file"); + return LERROR; + } + + printf("\r\nName \tType"); + printf("\r\n-----------------------"); + for(int i=0; isize; i++){ + struct initramfs_internal *child_internal = (struct initramfs_internal*)internal->children[i]->internal; + printf("\r\n"); printf(child_internal->name); for(int j=0; j<15-strlen(child_internal->name); j++) printf(" "); + printf("\t"); printf(child_internal->type == FILE_NODE ? "FILE" : "DIR"); + } + return 0; +} + +int initramfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // 1. Lookup the vnode in the directory + // 2. Return error code if fails + struct initramfs_internal *internal = (struct initramfs_internal*)dir_node->internal; + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot lookup in a file"); + return LERROR; + } + + for(int i=0; ichildren[i]->internal; + if(internal->children[i] != NULL && !strcmp(child_internal->name, component_name)){ + *target = internal->children[i]; + return 0; + } + } + // printf("[ERROR] File not found\n"); + return LERROR; +} + +int initramfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // Alawys return -1 because we are not implementing mkdir in initramfs + return -1; +} + +int initramfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // Alawys return -1 because we are not implementing create in initramfs + return -1; +} + +int initramfs_close(struct file* file) +{ + // 1. release the file handle + // 2. Return error code if fails + if(file == NULL){ + printf("\r\n[ERROR] File pointer cannot be NULL"); + return CERROR; + } + return 0; // vfs_close will free the file pointer +} + +int initramfs_open(struct vnode* file_node, struct file** target) +{ + // 1. Allocate file handle + // 2. Return error code if fails + struct file *file = (struct file*)dynamic_alloc(sizeof(struct file)); + file->vnode = file_node; + file->f_pos = 0; + *target = file; + return 0; +} + +int initramfs_read(struct file* file, void* buf, size_t len) +{ + struct vnode *vnode = file->vnode; + struct initramfs_internal *internal = (struct initramfs_internal*)vnode->internal; + if(internal->type == DIR_NODE){ + printf("\r\n[ERROR] Cannot read a directory"); + return RERROR; + } + + size_t readable_size = min(len, internal->filesize - file->f_pos); + + // memory copy + for(int i=0; idata[file->f_pos + i]; + } + file->f_pos += readable_size; + return readable_size; +} + +int initramfs_write(struct file* file, const void* buf, size_t len) +{ + //cannot write on initframfs + return -1; +} + + +int initramfs_getsize(struct vnode* vnode) +{ + struct initramfs_internal *internal = (struct initramfs_internal*)vnode->internal; + return internal->filesize; +} + +static int isFileInSubDir(const char* pathname) +{ + for(int i=0; i=0; i-=4){ + int tmp = (td >> i) & 0xf; + if(tmp < 10){ + printfc('0'+tmp); + } + else{ + printfc('a'+tmp-10); + } + } +} + +void printf_int(const int d) +{ + int td = d; + if(td < 0){ + printf("-"); + td = -td; + } + if(td == 0){ + printf("0"); + return; + } + int digits[10]; + int cnt = 0; + while(td > 0){ + digits[cnt++] = td % 10; + td /= 10; + } + for(int i=cnt-1; i>=0; i--){ + printfc('0'+digits[i]); + } +} + +char read_char() +{ + char c = uart_recv(); + return c; +} diff --git a/lab08/kernel/src/irq.S b/lab08/kernel/src/irq.S new file mode 100644 index 000000000..ee0531406 --- /dev/null +++ b/lab08/kernel/src/irq.S @@ -0,0 +1,11 @@ +.section ".text" + +.global enable_irq +enable_irq: + msr daifclr, 0xf + ret + +.global disable_irq +disable_irq: + msr daifset, 0xf + ret \ No newline at end of file diff --git a/lab08/kernel/src/irq.c b/lab08/kernel/src/irq.c new file mode 100644 index 000000000..21d7686f1 --- /dev/null +++ b/lab08/kernel/src/irq.c @@ -0,0 +1,84 @@ +#include "peripherals/irq.h" +#include "peripherals/mini_uart.h" + +#include "irq.h" +#include "io.h" + +extern void enable_irq(); +extern void disable_irq(); +extern void irq_timer_handler(); + +static char *entry_error_messages[] = { + "SYNC_INVALID_EL1t", + "IRQ_INVALID_EL1t", + "FIQ_INVALID_EL1t", + "ERROR_INVALID_EL1T", + + "SYNC_INVALID_EL1h", + "IRQ_INVALID_EL1h", + "FIQ_INVALID_EL1h", + "ERROR_INVALID_EL1h", + + "SYNC_INVALID_EL0_64", + "IRQ_INVALID_EL0_64", + "FIQ_INVALID_EL0_64", + "ERROR_INVALID_EL0_64", + + "SYNC_INVALID_EL0_32", + "IRQ_INVALID_EL0_32", + "FIQ_INVALID_EL0_32", + "ERROR_INVALID_EL0_32", + + "SYNC_ERROR", + "SYSCALL_ERROR" +}; + +static void show_debug_msg(int type, unsigned long spsr, unsigned long elr, unsigned long esr) +{ + printf("\r\n"); + printf(entry_error_messages[type]); + printf(", SPSR: "); + printf_hex(spsr); + printf(", ELR: "); + printf_hex(elr); + printf(", ESR: "); + printf_hex(esr); +} + +void irq_handler(int type, unsigned long spsr, unsigned long elr, unsigned long esr) +{ + disable_irq(); + + unsigned int irq = *CORE0_IRQ_SOURCE; + switch(irq) + { + case SYSTEM_TIMER_IRQ_1: + irq_timer_handler(); + break; + default: + printf("\r\nUnknown irq: "); + printf_hex(irq); + break; + } + enable_irq(); +} + +void invalid_exception_entry(int type, unsigned long spsr, unsigned long elr, unsigned long esr) +{ + + show_debug_msg(type, spsr, elr, esr); +} + +// void el0_irq_entry(int type, unsigned long spsr, unsigned long elr, unsigned long esr) +// { +// disable_irq(); +// show_debug_msg(type, spsr, elr, esr); +// enable_irq(); +// } + +void svc_exception_entry(int type, unsigned long spsr, unsigned long elr, unsigned long esr) +{ + disable_irq(); + show_debug_msg(type, spsr, elr, esr); + enable_irq(); +} diff --git a/lab08/kernel/src/kernel_main.c b/lab08/kernel/src/kernel_main.c new file mode 100644 index 000000000..fa338c83a --- /dev/null +++ b/lab08/kernel/src/kernel_main.c @@ -0,0 +1,54 @@ +#include "io.h" +#include "fork.h" +#include "schedule.h" + +extern void shell_loop(); +extern void frame_init_with_reserve(); +extern void memory_pool_init(); +extern void mem_init(); +extern void uart_init(); +extern void timer_init(); +extern void enable_irq(); +extern void initramfs_callback(void*); +extern void rootfs_init(); + +#ifndef QEMU +extern void fdt_traverse(void (*callback)(void*)); +#endif + +static void multiple_init(); + +extern struct task_struct *current; + +int main() +{ + multiple_init(); + enable_irq(); + +#ifndef QEMU + fdt_traverse(initramfs_callback); +#endif + frame_init_with_reserve(); + + rootfs_init(); + + printf("\nWelcome to Yuchang's Raspberry Pi 3!\n"); + + // copy_process((unsigned long)(void*)&shell_loop, 0); + copy_process(PF_KTHREAD, (unsigned long)(void*)&shell_loop, 0, 0); + + while(1){ + kill_zombies(); + schedule(); + } + return 0; +} + +static void multiple_init() +{ + mem_init(); + uart_init(); + memory_pool_init(); + timer_init(); + // rootfs_init(); +} \ No newline at end of file diff --git a/lab08/kernel/src/lib.c b/lab08/kernel/src/lib.c new file mode 100644 index 000000000..82bff2bfa --- /dev/null +++ b/lab08/kernel/src/lib.c @@ -0,0 +1,87 @@ +#include "lib.h" +#include "io.h" + +uint32_t strtol(const char *sptr, uint32_t base, int size) +{ + uint32_t ret = 0; + int i=0; + + while((sptr[i] != '\0') && (i= '0' && sptr[i] <= '9'){ + ret = ret * 16 + (sptr[i] - '0'); + } + else if(sptr[i] >= 'a' && sptr[i] <= 'f'){ + ret = ret * 16 + (sptr[i] - 'a' + 10); + } + else if(sptr[i] >= 'A' && sptr[i] <= 'F'){ + ret = ret * 16 + (sptr[i] - 'A' + 10); + } + else{ + break; + } + } + else if(base == 8 || base == 2){ + if(sptr[i] >= '0' && sptr[i] <= '9'){ + ret = ret * base + (sptr[i] - '0'); + } + else{ + break; + } + } + i++; + } + return ret; +} + +uint64_t atoi(const char *str) +{ + uint64_t ret = 0; + int i=0; + while(str[i] != '\0' && (str[i] >= '0' && str[i] <= '9')){ + ret = ret * 10 + (str[i] - '0'); + i++; + } + return ret; +} + +uint64_t atoi_hex(const char *str) +{ + uint64_t ret = 0; + int i=0; + while(str[i] != '\0'){ + 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); + } + else{ + break; + } + i++; + } + return ret; +} + +uint64_t pow(int base, int exp) +{ + uint64_t ret = 1; + while(exp-- > 0){ + ret *= base; + } + return ret; +} + +void assert(int condition, char* message) +{ + if(!condition){ + printf("\nAssertion failed: "); + printf(message); + printf("\n"); + while(1); + } +} \ No newline at end of file diff --git a/lab08/kernel/src/linker.ld b/lab08/kernel/src/linker.ld new file mode 100644 index 000000000..4eb74d510 --- /dev/null +++ b/lab08/kernel/src/linker.ld @@ -0,0 +1,24 @@ +SECTIONS +{ + . = 0x80000; + .text : + { + KEEP(*(.text.boot)) + *(.text) + } + .rodata :{ *(.rodata) } + .data : { *(.data) } + .bss : + { + . = ALIGN(0x8); + __bss_start = .; + *(.bss) + . = ALIGN(0x8); + __bss_end = .; + } + . = ALIGN(0x8); + _kernel_end = .; + . = ALIGN(0x8); + _heap_start = .; +} +__bss_size = (__bss_end - __bss_start)>>3; \ No newline at end of file diff --git a/lab08/kernel/src/mailbox.c b/lab08/kernel/src/mailbox.c new file mode 100644 index 000000000..c3ef7dc13 --- /dev/null +++ b/lab08/kernel/src/mailbox.c @@ -0,0 +1,88 @@ +#include "peripherals/mailbox.h" + +#include "mailbox.h" +#include "io.h" + +void get_board_revision() +{ + unsigned int mailbox[7]; + mailbox[0] = 7 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_BOARD_REVISION; // tag identifier + mailbox[3] = 4; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + // tags end + mailbox[6] = END_TAG; + + mailbox_call(mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + + // printf("0x%x\n", mailbox[5]); // it should be 0xa020d3 for rpi3 b+ + printf("\nBoard revision: "); + printf_hex(mailbox[5]); +} + +void get_memory_info() +{ + unsigned int mailbox[8]; + mailbox[0] = 8 * 4; // buffer size in bytes + mailbox[1] = REQUEST_CODE; + // tags begin + mailbox[2] = GET_ARM_MEMORY; // tag identifier + mailbox[3] = 8; // maximum of request and response value buffer's length. + mailbox[4] = TAG_REQUEST_CODE; + mailbox[5] = 0; // value buffer + mailbox[6] = 0; + // tags end + mailbox[7] = END_TAG; + + mailbox_call(mailbox); // message passing procedure call, you should implement it following the 6 steps provided above. + + printf("\nARM base memory address: "); + printf_hex(mailbox[5]); + printf("\nARM memory size: "); + printf_hex(mailbox[6]); + +} + +void mailbox_call(unsigned int* mailbox) +{ + unsigned int mesg = (((unsigned long)mailbox) & ~0xf) | 8; + + while(*MAILBOX_STATUS & MAILBOX_FULL){ // // Check if Mailbox 0 status register’s full flag is set. if MAILBOX_STATUS == 0x80000001, then error parsing request buffer + asm volatile("nop"); + } + + *MAILBOX_WRITE = mesg; + + while(1){ + while(*MAILBOX_STATUS & MAILBOX_EMPTY){ + asm volatile("nop"); + } + if(mesg == *MAILBOX_READ){ + break; + } + } +} + +int mailbox_call_s(unsigned char ch, unsigned int *mbox) +{ + + unsigned int mesg = (((unsigned int)(unsigned long)mbox) & ~0xf) | (ch & 0xf); + while(*MAILBOX_STATUS & MAILBOX_FULL){ // // Check if Mailbox 0 status register’s full flag is set. if MAILBOX_STATUS == 0x80000001, then error parsing request buffer + asm volatile("nop"); + } + + *MAILBOX_WRITE = mesg; + + while(1){ + while(*MAILBOX_STATUS & MAILBOX_EMPTY){ + asm volatile("nop"); + } + if(mesg == *MAILBOX_READ){ + return mbox[1] == REQUEST_SUCCEED; + } + } + return 0; +} \ No newline at end of file diff --git a/lab08/kernel/src/mini_uart.c b/lab08/kernel/src/mini_uart.c new file mode 100644 index 000000000..f43431f60 --- /dev/null +++ b/lab08/kernel/src/mini_uart.c @@ -0,0 +1,65 @@ +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" + +#include "mini_uart.h" +#include "string.h" + +void uart_init() +{ + // set the alternate function for GPIO14 and GPIO15 + unsigned int selector; + selector = *GPFSEL1; + selector &= ~(7<<12); // size gpio14 to 0 for gpio14 is bits 12-14 + selector |= 2<<12; // set to alt5 for gpio14 + selector &= ~(7<<15); // size gpio15 to 0 for gpio15 is bits 15-17 + selector |= 2<<15; // set to alt5 for gpio15 + *GPFSEL1 = selector; + + // GPIO initilaization + *GPPUD = 0; // disable pull up/down for all GPIO pins + unsigned int i = 150; + while(i--) asm volatile("nop"); + *GPPUDCLK0 = (1<<14) | (1<<15); // enable clock for gpio14 and gpio15 + i = 150; + while(i--) asm volatile("nop"); + *GPPUDCLK0 = 0; // disable clock for gpio14 and gpio15 + + // initialize mini uart + *AUX_ENABLES = 1; //Enable mini uart (this also enables access to its registers) + *AUX_MU_CNTL_REG = 0; //Disable auto flow control and disable receiver and transmitter (for now) + *AUX_MU_IER_REG = 0; //Disable receive and transmit interrupts + *AUX_MU_LCR_REG = 3; //Enable 8 bit mode + *AUX_MU_MCR_REG = 0; //Set RTS line to be always high + *AUX_MU_BAUD_REG = 270; // 115200 baud + *AUX_MU_CNTL_REG = 3; //Finally, enable transmitter and receiver +} + +char uart_recv() +{ + + char r; + // bit 0 == 1, if receiver holds valid byte + do{asm volatile("nop");}while(!(*AUX_MU_LSR_REG & 0x01)); + r = (char)(*AUX_MU_IO_REG); + return r == '\r'?'\n':r; + +} + +void uart_send(const char c) +{ + // bit 6 == 1, if transmitter is empty + while (1) { + if ((*AUX_MU_LSR_REG)&0x20) break; + } + *AUX_MU_IO_REG = c; + +} + +void uart_send_string(const char* str) +{ + while(*str){ + if(*str == '\n') + uart_send('\r'); + uart_send(*str++); + } +} \ No newline at end of file diff --git a/lab08/kernel/src/mm.S b/lab08/kernel/src/mm.S new file mode 100644 index 000000000..3998c53d5 --- /dev/null +++ b/lab08/kernel/src/mm.S @@ -0,0 +1,6 @@ +.globl memzero_asm +memzero_asm: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero_asm + ret \ No newline at end of file diff --git a/lab08/kernel/src/reboot.c b/lab08/kernel/src/reboot.c new file mode 100644 index 000000000..9d8153f62 --- /dev/null +++ b/lab08/kernel/src/reboot.c @@ -0,0 +1,18 @@ +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value) { + volatile unsigned int* point = (unsigned int*)addr; + *point = value; +} + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} \ No newline at end of file diff --git a/lab08/kernel/src/schedule.S b/lab08/kernel/src/schedule.S new file mode 100644 index 000000000..4dd8af0d4 --- /dev/null +++ b/lab08/kernel/src/schedule.S @@ -0,0 +1,24 @@ +#include "schedule.h" + +.globl cpu_switch_to +cpu_switch_to: + mov x10, #THREAD_CPU_CONTEXT + add x8, x0, x10 // x8 = the pointer points to current thread's cpu_context + mov x9, sp + stp x19, x20, [x8], #16 // store callee-saved registers + stp x21, x22, [x8], #16 + stp x23, x24, [x8], #16 + stp x25, x26, [x8], #16 + stp x27, x28, [x8], #16 + stp x29, x9, [x8], #16 + str x30, [x8] + add x8, x1, x10 // x8 = the pointer points to next thread's cpu_context + ldp x19, x20, [x8], #16 // restore callee-saved registers + ldp x21, x22, [x8], #16 + ldp x23, x24, [x8], #16 + ldp x25, x26, [x8], #16 + ldp x27, x28, [x8], #16 + ldp x29, x9, [x8], #16 + ldr x30, [x8] // restore pc + mov sp, x9 + ret \ No newline at end of file diff --git a/lab08/kernel/src/schedule.c b/lab08/kernel/src/schedule.c new file mode 100644 index 000000000..d61fe437b --- /dev/null +++ b/lab08/kernel/src/schedule.c @@ -0,0 +1,103 @@ +#include "schedule.h" +#include "irq.h" +#include "alloc.h" +#include "io.h" + +static struct task_struct init_task = INIT_TASK; +struct task_struct *current = &(init_task); +struct task_struct * task[NR_TASKS] = {&(init_task), }; +int nr_tasks = 1; + +void preempt_disable(void) +{ + current->preempt_count++; +} + +void preempt_enable(void) +{ + current->preempt_count--; +} + + +void _schedule(void) +{ + preempt_disable(); + int next,c; + struct task_struct * p; + while (1) { + c = -1; + next = 0; + for (int i = 0; i < NR_TASKS; i++){ // find the task with the maximum counter + p = task[i]; + if (p && p->state == TASK_RUNNING && p->counter > c) { + c = p->counter; + next = i; + } + } + if (c) { // found & break for switch to the task + break; + } + // if no task is found, increase the counter of all tasks + for (int i = 0; i < NR_TASKS; i++) { + p = task[i]; + if (p) { + p->counter = (p->counter >> 1) + p->priority; + } + } + } + switch_to(task[next]); + preempt_enable(); +} + +void schedule(void) +{ + current->counter = 0; + _schedule(); +} + +void switch_to(struct task_struct * next) +{ + if (current == next) + return; + struct task_struct * prev = current; + current = next; + cpu_switch_to(prev, next); +} + +void schedule_tail(void) { + preempt_enable(); +} + + +void timer_tick() +{ + --current->counter; + if (current->counter>0 || current->preempt_count >0) { + return; + } + current->counter=0; + enable_irq(); + _schedule(); + disable_irq(); +} + +void kill_zombies() +{ + for (int i = 0; i < NR_TASKS; i++) { + if (task[i] && task[i]->state == TASK_ZOMBIE) { + struct task_struct * p = task[i]; + task[i] = 0; + printf("\r\n[KILL] zombies, pid: "); printf_int(p->pid); + bfree(p); + } + } +} + +void exit_process() +{ + preempt_disable(); + current->state = TASK_ZOMBIE; + bfree((void*)current->stack); + preempt_enable(); + schedule(); +} \ No newline at end of file diff --git a/lab08/kernel/src/shell.c b/lab08/kernel/src/shell.c new file mode 100644 index 000000000..1d64b1dc0 --- /dev/null +++ b/lab08/kernel/src/shell.c @@ -0,0 +1,271 @@ +#include "shell.h" +#include "mini_uart.h" +#include "mailbox.h" +#include "reboot.h" +#include "io.h" +#include "string.h" +#include "alloc.h" +#include "lib.h" +#include "timer.h" +#include "irq.h" +#include "fork.h" +#include "schedule.h" +#include "vfs.h" + +#define delay(x) for(int i=0; icwd); + } + else if(argc == 2){ + vfs_list(argv[1]); + } + else{ + printf("\nUsage: ls [path]"); + return; + } +} + + +static void rootfs_mkdir(int argc, char *argv[]) +{ + if(argc == 2){ + vfs_mkdir(argv[1]); + } + else{ + printf("\nUsage: mkdir [path]"); + return; + } +} + +static void rootfs_touch(int argc, char *argv[]) +{ + if(argc == 2){ + // vfs_create(argv[1]); + } + else{ + printf("\nUsage: touch [path]"); + return; + } +} + +static void rootfs_exec(int argc, char *argv[]) +{ + if(argc == 2){ + vfs_exec(argv[1], 0); + } + else{ + printf("\nUsage: exec [path]"); + return; + } +} + + +static void print_cwd(int argc, char *argv[]) +{ + printf("\nCurrent Working Directory: "); + printf(current->cwd); +} + + + +static void change_dir(int argc, char *argv[]) +{ + if(argc == 2){ + vfs_chdir(argv[1]); + } + else{ + printf("\nUsage: cd [path]"); + return; + } +} + +void readcmd(char x[256]) +{ + char input_char; + int input_index = 0; + x[0] = 0; + while( ((input_char = read_char()) != '\n')) + { + if(input_char == 127){ + if(input_index > 0){ + input_index--; + printf("\b \b"); + } + continue; + } + x[input_index] = input_char; + ++input_index; + printfc(input_char); + } + + x[input_index]=0; // null char +} + +int split_command(char* command, char *argv[]) +{ + int argc = 0; + + char *token = strtok(command, " "); + while(token != NULL) + { + argv[argc] = token; + argc++; + token = strtok(0, " "); + } + return argc; +} \ No newline at end of file diff --git a/lab08/kernel/src/string.c b/lab08/kernel/src/string.c new file mode 100644 index 000000000..dd7d84e6c --- /dev/null +++ b/lab08/kernel/src/string.c @@ -0,0 +1,69 @@ +#include "string.h" +#include "io.h" + +int strcmp(const char* a, const char* b) +{ + while(*a == *b){ + if(*a == '\0') + return 0; + a++; + b++; + } + return *a - *b; +} + +char* strcpy(char* dest, const char* src) +{ + char* ret = dest; + while(*src){ + *dest = *src; + dest++; + src++; + } + *dest = '\0'; + return ret; +} + +char* strncpy(char* dest, const char* src, int n) +{ + char* ret = dest; + while(n--){ + *dest = *src; + dest++; + src++; + } + *dest = '\0'; + return ret; +} + +uint32_t strlen(const char* str) +{ + uint32_t len = 0; + while(*str){ + len++; + str++; + } + return len; +} + +char *strtok(char* str, const char* delim) +{ + // printf("\r\nstr: "); printf(str); + static char* p = 0; + if(str != 0) p = str; + if(p == 0) return 0; + char* ret = p; + while(*p){ + if(*p == *delim){ + *p = '\0'; + p++; + if(ret[0] == 0) return NULL; + return ret; + } + p++; + // printf("\r\np++"); + } + // printf("\r\nret: "); printf(ret); printf(", "); printfc(ret[0]); printf(", "); printf_int(ret[0] == NULL); + if(ret[0] == 0) return NULL; + return ret; +} \ No newline at end of file diff --git a/lab08/kernel/src/sys.S b/lab08/kernel/src/sys.S new file mode 100644 index 000000000..9fecd659f --- /dev/null +++ b/lab08/kernel/src/sys.S @@ -0,0 +1,110 @@ +#include "sys.h" + +// reason for using w8 is that x0-x7 are used for passing arguments +// the such warpper functions are not inlcuded in the real linux kernel +// they often are packed in the different language's standard library, such as glibc + +// svc #0 is used to generate synchronous exception + +.global getpid +getpid: + mov w8, #SYS_GETPID_NUM + svc #0 // using svc to generate synchronous exception + ret + +.global uartread +uartread: + mov w8, #SYS_UARTREAD_NUM + svc #0 + ret + +.global uartwrite +uartwrite: + mov w8, #SYS_UARTWRITE_NUM + svc #0 + ret + +.global exec +exec: + mov w8, #SYS_EXEC_NUM + svc #0 + ret + +.global fork +fork: + mov w8, #SYS_FORK_NUM + svc #0 + ret + +.global exit +exit: + mov w8, #SYS_EXIT_NUM + svc #0 + ret + +.global mbox_call +mbox_call: + mov w8, #SYS_MBOX_CALL_NUM + svc #0 + ret + +.global kill +kill: + mov w8, #SYS_KILL_NUM + svc #0 + ret + +.global open +open: + mov w8, #SYS_OPEN_NUM + svc #0 + ret + +.global close +close: + mov w8, #SYS_CLOSE_NUM + svc #0 + ret + +.global write +write: + mov w8, #SYS_WRITE_NUM + svc #0 + ret + +.global read +read: + mov w8, #SYS_READ_NUM + svc #0 + ret + +.global mkdir +mkdir: + mov w8, #SYS_MKDIR_NUM + svc #0 + ret + +.global mount +mount: + mov w8, #SYS_MOUNT_NUM + svc #0 + ret + +.global chdir +chdir: + mov w8, #SYS_CHDIR_NUM + svc #0 + ret + +.global lseek64 +lseek64: + mov w8, #SYS_LSEEK64_NUM + svc #0 + ret + + +//.global ioctl +//ioctl: +// mov w8, #SYS_IOCTL_NUM +// svc #0 +// ret \ No newline at end of file diff --git a/lab08/kernel/src/sys.c b/lab08/kernel/src/sys.c new file mode 100644 index 000000000..23dd3bb32 --- /dev/null +++ b/lab08/kernel/src/sys.c @@ -0,0 +1,242 @@ +#include "sys.h" +#include "schedule.h" +#include "fork.h" +#include "mini_uart.h" +#include "io.h" +#include "alloc.h" +#include "cpio.h" +#include "lib.h" +#include "type.h" +#include "string.h" +#include "peripherals/mailbox.h" +#include "dev_framebuffer.h" + +extern struct task_struct *current; +extern void memzero_asm(unsigned long src, unsigned long n); +// #ifndef QEMU +// extern unsigned long CPIO_START_ADDR_FROM_DT; +// #endif + +void foo(){}; + +int sys_getpid() +{ + return current->pid; +} + +size_t sys_uartread(char buf[], size_t size) +{ + for(size_t i=0; ivnode->f_ops->getsize(file->vnode); + void* user_program_addr = balloc(filesize+THREAD_SIZE); + + if(user_program_addr == NULL){ + printf("\r\n[ERROR] Cannot allocate memory for file: "); printf(name); + return -1; + } + + vfs_read(file, user_program_addr, filesize); + vfs_close(file); + + preempt_disable(); // leads to get the correct current task + + struct pt_regs *cur_regs = task_pt_regs(current); + cur_regs->pc = (unsigned long)user_program_addr; + cur_regs->sp = current->stack + THREAD_SIZE; + + preempt_enable(); + return 0; +} + +int sys_fork() // [TODO] +{ + unsigned long stack = (unsigned long)balloc(THREAD_SIZE); + if((void*)stack == NULL) return -1; + memzero_asm(stack, THREAD_SIZE); + return copy_process(0, 0, 0, stack); +} + +void sys_exit(int status) // [TODO] +{ + exit_process(); +} + +int sys_mbox_call(unsigned char ch, unsigned int *mbox) // [TODO] +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] mbox_call: "); printf_int(ch); +#endif + unsigned int mesg = (((unsigned int)(unsigned long)mbox) & ~0xf) | (ch & 0xf); + while(*MAILBOX_STATUS & MAILBOX_FULL){ // // Check if Mailbox 0 status register’s full flag is set. if MAILBOX_STATUS == 0x80000001, then error parsing request buffer + asm volatile("nop"); + } + + *MAILBOX_WRITE = mesg; + + while(1){ + while(*MAILBOX_STATUS & MAILBOX_EMPTY){ + asm volatile("nop"); + } + if(mesg == *MAILBOX_READ){ + return mbox[1] == REQUEST_SUCCEED; + } + } + return 0; +} + +void sys_kill(int pid) // [TODO] +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] kill: "); printf_int(pid); +#endif + if(task[pid] == NULL){ + printf("\r\nProcess not found: "); printf_int(pid); + return; + } + task[pid]->state = TASK_ZOMBIE; +} + +int sys_open(const char *pathname, int flags) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] open: "); printf(pathname); printf(", flags: "); printf_int(flags); +#endif + for(int i=0; ifd_table.fds[i] == NULL){ + int ret = vfs_open(pathname, flags, ¤t->fd_table.fds[i]); + if(ret == 0){ + printf("\r\n[SYSCALL] open: File descriptor: "); printf_int(i + OFFSET_FD); printf(" , File: "); printf(pathname); + return i + OFFSET_FD; + } + break; + } + } + return -1; +} + +int sys_close(int fd) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] close: "); printf_int(fd); +#endif + if(fd < OFFSET_FD || fd >= MAX_OPEN_FILE + OFFSET_FD) return -1; + int ret = vfs_close(current->fd_table.fds[fd - OFFSET_FD]); + current->fd_table.fds[fd - OFFSET_FD] = NULL; + return ret; +} + +long sys_write(int fd, const void *buf, unsigned long count) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] write: fd: "); printf_int(fd); printf(", count: "); printf_int(count); +#endif + if(fd < OFFSET_FD || fd >= MAX_OPEN_FILE + OFFSET_FD) return -1; + return vfs_write(current->fd_table.fds[fd - OFFSET_FD], buf, count); +} +long sys_read(int fd, void *buf, unsigned long count) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] read: fd: "); printf_int(fd); printf(", count: "); printf_int(count); +#endif + if(fd < OFFSET_FD || fd >= MAX_OPEN_FILE + OFFSET_FD) return -1; + return vfs_read(current->fd_table.fds[fd - OFFSET_FD], buf, count); +} + +// you can ignore mode, since there is no access control +int sys_mkdir(const char *pathname, unsigned mode) +{ + return vfs_mkdir(pathname); +} + +// you can ignore arguments other than target (where to mount) and filesystem (fs name) +int sys_mount(const char *src, const char *target, const char *filesystem, unsigned long flags, const void *data) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] mount:"); printf(src); printf(" to "); printf(target); printf(" with filesystem: "); printf(filesystem); +#endif + return vfs_mount(target, filesystem); +} + +int sys_chdir(const char *path) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] chdir: "); printf(path); +#endif + return vfs_chdir(path); +} + + +long sys_lseek64(int fd, long offset, int whence) +{ + long ret; + if(whence == SEEK_SET) // used for dev_framebuffer + { + current->fd_table.fds[fd - OFFSET_FD]->f_pos = offset; + ret = offset; + } + else // other is not supported + { + ret = -1; + } + + return ret; +} + +// ioctl 0 will be use to get info +// there will be default value in info +// if it works with default value, you can ignore this syscall +long sys_ioctl(int fd, unsigned long request, unsigned long arg) +{ +#ifdef SYSCALL_DEBUG + printf("\r\n[SYSCALL] ioctl: fd: "); printf_int(fd); printf(" , request: "); printf_hex(request); +#endif + return 0; +} + + +void * const sys_call_table[] = { + sys_getpid, + sys_uartread, + sys_uartwrite, + sys_exec, + sys_fork, + sys_exit, + sys_mbox_call, + sys_kill, + // lab5 advanced + foo, + foo, + foo, + // lab7 + sys_open, + sys_close, + sys_write, + sys_read, + sys_mkdir, + sys_mount, + sys_chdir, + sys_lseek64, + sys_ioctl + }; diff --git a/lab08/kernel/src/timer.S b/lab08/kernel/src/timer.S new file mode 100644 index 000000000..1d3a466b2 --- /dev/null +++ b/lab08/kernel/src/timer.S @@ -0,0 +1,32 @@ +.section ".text" + +.global core_timer_enable +core_timer_enable: + mov x0, 1 + msr cntp_ctl_el0, x0 // enable + mov x0, 2 + // mrs x0, cntfrq_el0 + ldr x1, =0x40000040 // timer interrupt control register for core 0 + str w0, [x1] // unmask timer interrupt + ret + +.global core_timer_disable +core_timer_disable: + mov x0, 0 + msr cntp_ctl_el0, x0 // disable + ret + +.global get_cpu_cycles +get_cpu_cycles: + mrs x0, cntpct_el0 + ret + +.global get_cpu_freq +get_cpu_freq: + mrs x0, cntfrq_el0 + ret + +.global set_timer_asm +set_timer_asm: + msr cntp_tval_el0, x0 + ret \ No newline at end of file diff --git a/lab08/kernel/src/timer.c b/lab08/kernel/src/timer.c new file mode 100644 index 000000000..0dcd61513 --- /dev/null +++ b/lab08/kernel/src/timer.c @@ -0,0 +1,25 @@ +#include "timer.h" +#include "alloc.h" +#include "string.h" +#include "type.h" +#include "io.h" + +extern void timer_tick(); + +void timer_init() +{ + core_timer_enable(); + set_timer(1); +} + +void irq_timer_handler() +{ + set_timer_asm(get_cpu_freq()>>5); + timer_tick(); +} + +void set_timer(uint32_t sec) +{ + uint64_t cycles = get_cpu_freq() * sec; + set_timer_asm(cycles); +} diff --git a/lab08/kernel/src/tmpfs.c b/lab08/kernel/src/tmpfs.c new file mode 100644 index 000000000..13487a034 --- /dev/null +++ b/lab08/kernel/src/tmpfs.c @@ -0,0 +1,282 @@ +#include "tmpfs.h" +#include "alloc.h" +#include "errno.h" +#include "io.h" +#include "string.h" + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +struct file_operations *tmpfs_f_ops; +struct vnode_operations *tmpfs_v_ops; + +static struct vnode* tmpfs_create_vnode(const char *name, int type, struct vnode *parent); + +int tmpfs_setup_mount(struct filesystem* fs, struct mount **mount) // mount the filesystem to the mount point +{ + (*mount)->fs = fs; + (*mount)->root = tmpfs_create_vnode("/", DIR_NODE, NULL); + return 0; +} + +static struct vnode* tmpfs_create_vnode(const char *name, int type, struct vnode *parent) +{ + struct tmpfs_internal *internal = (struct tmpfs_internal*)dynamic_alloc(sizeof(struct tmpfs_internal)); + + if(sizeof(name) > COMPONENT_SIZE){ + printf("\r\n[ERROR] File name too long"); + return NULL; + } + internal->name = (char*)dynamic_alloc(COMPONENT_SIZE); + strcpy(internal->name, name); + internal->size = 0; + if(type == FILE_NODE){ + internal->data = (char*)balloc(TMPFS_MAX_FILE); + } + else{ + internal->data = NULL; + } + internal->type = type; + internal->filesize = 0; + // internal->parent = parent; + // internal->next = NULL; + for(int i=0; ichildren[i] = NULL; + } + struct vnode *vnode = (struct vnode*)dynamic_alloc(sizeof(struct vnode)); + vnode->parent = parent; + vnode->mount = NULL; + vnode->v_ops = tmpfs_v_ops; + vnode->f_ops = tmpfs_f_ops; + vnode->internal = internal; + return vnode; +} + +int tmpfs_register() +{ + // check if tmpfs already registered + int i=0; + for(; iwrite = tmpfs_write; + tmpfs_f_ops->read = tmpfs_read; + tmpfs_f_ops->open = tmpfs_open; + tmpfs_f_ops->close = tmpfs_close; + tmpfs_f_ops->getsize = tmpfs_getsize; + tmpfs_f_ops->lseek64 = NULL; + + tmpfs_v_ops->lookup = tmpfs_lookup; + tmpfs_v_ops->create = tmpfs_create; + tmpfs_v_ops->mkdir = tmpfs_mkdir; + tmpfs_v_ops->list = tmpfs_list; + + return 0; +} + +int tmpfs_write(struct file* file, const void* buf, size_t len) +{ + // Given the file handle, VFS calls the corresponding write + // method to write the file starting from f_pos, then updates + // f_pos and size after write. (or not if it’s a special file) + // Returns size written or error code on error. + + // 1. write len byte from buf to the opened file. + // 2. return written size or error code if an error occurs. + struct vnode *vnode = file->vnode; + struct tmpfs_internal *internal = (struct tmpfs_internal*)vnode->internal; + if(internal->type == DIR_NODE){ + printf("\r\n[ERROR] Cannot write to a directory"); + return WERROR; + } + + if(file->f_pos + len > TMPFS_MAX_FILE){ + printf("\r\n[ERROR] File size exceeded"); + return WERROR; + } + + // memory copy + int written_size = min(len, TMPFS_MAX_FILE - file->f_pos); + for(int i=0; idata[file->f_pos + i] = ((char*)buf)[i]; + } + file->f_pos += written_size; + internal->filesize += written_size; + return len; +} + +int tmpfs_read(struct file* file, void* buf, size_t len) +{ + // Given the file handle, VFS calls the corresponding read method + // to read the file starting from f_pos, then updates f_pos after read. + // (or not if it’s a special file) + + // 1. read min(len, readable size) byte to buf from the opened file. + // 2. block if nothing to read for FIFO type + // 2. return read size or error code if an error occurs. + + struct vnode *vnode = file->vnode; + struct tmpfs_internal *internal = (struct tmpfs_internal*)vnode->internal; + if(internal->type == DIR_NODE){ + printf("\r\n[ERROR] Cannot read a directory"); + return RERROR; + } + + size_t readable_size = min(len, internal->filesize - file->f_pos); + + // memory copy + for(int i=0; idata[file->f_pos + i]; + } + file->f_pos += readable_size; + return readable_size; +} + +int tmpfs_open(struct vnode* file_node, struct file** target) +{ + return 0; // the steps for checking the file is implemented in vfs_open +} + +int tmpfs_close(struct file* file) +{ + // 1. release the file handle + // 2. Return error code if fails + if(file == NULL){ + printf("\r\n[ERROR] File pointer cannot be NULL"); + return CERROR; + } + return 0; // vfs_close will free the file pointer +} + +int tmpfs_create(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // create an regular file on underlying file system, + // should fail if file exist. Then passes the file’s vnode back to VFS. + + // 1. Create a new file in the directory + // 2. Return error code if fails + struct tmpfs_internal *internal = (struct tmpfs_internal*)dir_node->internal; + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot create file in a file"); + return CERROR; + } + + if(strlen(component_name) > COMPONENT_SIZE){ + printf("\r\n[ERROR] File name too long"); + return CERROR; + } + + // for(int i=0; ichildren[i] == NULL){ + // internal->children[i] = tmpfs_create_vnode(component_name, FILE_NODE, dir_node); + // *target = internal->children[i]; + // return 0; + // } + // } + if(internal->size + 1 > ENTRIES_PER_DIR){ + printf("\r\n[ERROR] No space for new file"); + return CERROR; + } + internal->children[internal->size] = tmpfs_create_vnode(component_name, FILE_NODE, dir_node); + *target = internal->children[internal->size]; + internal->size++; + return 0; +} + +int tmpfs_getsize(struct vnode* vnode) +{ + struct tmpfs_internal *internal = (struct tmpfs_internal*)vnode->internal; + return internal->filesize; +} + +int tmpfs_mkdir(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // 1. Create a new directory in the directory + // 2. Return error code if fails + + struct tmpfs_internal *internal = (struct tmpfs_internal*)dir_node->internal; + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot create directory in a file"); + return CERROR; + } + + if(strlen(component_name) > COMPONENT_SIZE){ + printf("\r\n[ERROR] Directory name too long"); + return CERROR; + } + + // for(int i=0; ichildren[i] == NULL){ + // internal->children[i] = tmpfs_create_vnode(component_name, DIR_NODE, dir_node); + // *target = internal->children[i]; + // return 0; + // } + // } + if(internal->size + 1 > ENTRIES_PER_DIR){ + printf("\r\n[ERROR] No space for new directory"); + return CERROR; + } + internal->children[internal->size] = tmpfs_create_vnode(component_name, DIR_NODE, dir_node); + *target = internal->children[internal->size]; + internal->size++; + return 0; +} + +int tmpfs_lookup(struct vnode* dir_node, struct vnode** target, const char* component_name) +{ + // 1. Lookup the vnode in the directory + // 2. Return error code if fails + struct tmpfs_internal *internal = (struct tmpfs_internal*)dir_node->internal; + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot lookup in a file"); + return LERROR; + } + + for(int i=0; ichildren[i]->internal; + if(internal->children[i] != NULL && !strcmp(child_internal->name, component_name)){ + *target = internal->children[i]; + return 0; + } + } + // printf("[ERROR] File not found\n"); + return LERROR; +} + +int tmpfs_list(struct vnode* dir_node) +{ + // 1. List all the files in the directory + // 2. Return error code if fails + printf("\r\n[TMPFS LIST]"); + struct tmpfs_internal *internal = (struct tmpfs_internal*)dir_node->internal; + + if(internal->type == FILE_NODE){ + printf("\r\n[ERROR] Cannot list in a file"); + return LERROR; + } + + printf("\r\nName \tType"); + printf("\r\n-----------------------"); + for(int i=0; isize; i++){ + struct tmpfs_internal *child_internal = (struct tmpfs_internal*)internal->children[i]->internal; + printf("\r\n"); printf(child_internal->name); for(int j=0; j<15-strlen(child_internal->name); j++) printf(" "); + printf("\t"); printf(child_internal->type == FILE_NODE ? "FILE" : "DIR"); + } + return 0; +} diff --git a/lab08/kernel/src/user_demo.c b/lab08/kernel/src/user_demo.c new file mode 100644 index 000000000..2088f2418 --- /dev/null +++ b/lab08/kernel/src/user_demo.c @@ -0,0 +1,261 @@ +#include "user_demo.h" +#include "fork.h" +#include "schedule.h" +#include "io.h" +#include "sys.h" + +// system call +extern int getpid(); +extern int fork(); +extern void exit(); +extern int open(const char *pathname, int flags); +extern int close(int fd); +extern int read(int fd, void *buf, unsigned long count); +extern int write(int fd, const void *buf, unsigned long count); + +static void user_multiple_thread_test_foo(); +static void user_fork_test_foo(); +static void user_open_test_foo(); +static void user_open_test_initramfs_foo(); +static void user_read_test_foo(); +static void user_write_test_foo(); +static void user_write_test_initramfs_foo(); +static void user_stdout_test_foo(); +static void user_stdin_test_foo(); + +// lab5 +void multiple_thread_test(int argc, char *argv[]) +{ + for(int i = 0; i < 5; ++i) { + copy_process(PF_KTHREAD, (unsigned long)&user_multiple_thread_test_foo, 0, 0); + } +} + +void user_fork_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_fork_test_foo, 0); +} + +// lab7 + +void user_open_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_open_test_foo, 0); +} + +void user_open_test_initramfs(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_open_test_initramfs_foo, 0); +} + +void user_read_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_read_test_foo, 0); +} + +void user_write_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_write_test_foo, 0); +} + +void user_write_test_initramfs(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_write_test_initramfs_foo, 0); +} + +void user_stdout_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_stdout_test_foo, 0); +} + +void user_stdin_test(int argc, char *argv[]) +{ + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)&user_stdin_test_foo, 0); +} + +// ------------------------------------------------------------------ + +static void user_multiple_thread_test_foo() +{ + for(int i = 0; i < 10; ++i) { + printf("\r\nThread id: "); printf_int(current->pid); printf("\t,loop: "); printf_int(i); + delay(1000000); + schedule(); + } + current->state = TASK_ZOMBIE; + while(1); +} + +static void user_fork_test_foo() +{ + // printf("Fork Test , pid : %d\n",getpid()); + printf("\r\nFork Test, pid: "); printf_int(getpid()); + uint32_t cnt = 1,ret=0; + + if((ret=fork()) == 0){ //pid == 0 => child + printf("\r\n===== Child Process ====="); + unsigned long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + // printf("first child pid: %d, cnt: %d, ptr: %x, sp : %x\n", getpid(), cnt, &cnt, cur_sp); + printf("\r\nfirst child pid: "); printf_int(getpid()); printf(", cnt: "); printf_int(cnt); + printf(", ptr: "); printf_hex((unsigned long)&cnt); printf(", sp: "); printf_hex(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", getpid(), cnt, &cnt, cur_sp); + printf("\r\nfirst child pid: "); printf_int(getpid()); printf(", cnt: "); printf_int(cnt); + printf(", ptr: "); printf_hex((unsigned long)&cnt); printf(", sp: "); printf_hex(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", getpid(), cnt, &cnt, cur_sp); + printf("\r\nsecond child pid: "); printf_int(getpid()); printf(", cnt: "); printf_int(cnt); + printf(", ptr: "); printf_hex((unsigned long)&cnt); printf(", sp: "); printf_hex(cur_sp); + delay(1000000); + ++cnt; + } + } + exit(); + } + else{ //pid > 0 => parent + printf("\r\n===== Parent Process ====="); + printf("\r\nParent Process, pid: "); printf_int(getpid()); + printf(" child pid: "); printf_int(ret); + unsigned long cur_sp; + asm volatile("mov %0, sp" : "=r"(cur_sp)); + printf(" cnt: "); printf_int(cnt); printf(" , ptr: "); printf_hex((unsigned long)&cnt); + printf(" , sp: "); printf_hex(cur_sp); + exit(); + } +} + +static void user_open_test_foo() +{ + printf("\r\nUser Open Test pid: "); printf_int(getpid()); + // char buff[] = "Hello, World!"; + int fd = open("test.txt", O_CREAT); + if(fd == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd); + // write(fd, buff, sizeof(buff)); + close(fd); + exit(); +} + +static void user_open_test_initramfs_foo() +{ + printf("\r\nUser Open Test Initramfs pid: "); printf_int(getpid()); + // char buff[] = "Hello, World!"; + int fd = open("/initramfs/test.txt", O_CREAT); + if(fd == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd); + // write(fd, buff, sizeof(buff)); + close(fd); + exit(); +} + +static void user_read_test_foo() +{ + printf("\r\nUser Read Test pid: "); printf_int(getpid()); + char buff1[100]; + int fd1 = open("/initramfs/f1", 0); + if(fd1 == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd1); + read(fd1, buff1, sizeof(buff1)); + printf("\r\nRead content f1: "); printf(buff1); + + char buff2[4]; + int fd2 = open("/initramfs/f2", 0); + if(fd2 == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd2); + read(fd2, buff2, sizeof(buff2)); + printf("\r\nRead content f2: "); printf(buff2); + read(fd2, buff2, sizeof(buff2)); + printf("\r\nRead content f2: "); printf(buff2); + close(fd1); + close(fd2); + exit(); +} + +static void user_write_test_foo() +{ + printf("\r\nUser Write Test pid: "); printf_int(getpid()); + char buff[] = "Hello, World!"; + int fd = open("/write.txt", O_CREAT); + if(fd == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd); + write(fd, buff, sizeof(buff)); + close(fd); + + int fd2 = open("/write.txt", 0); + if(fd2 == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd2); + char buff2[100]; + read(fd2, buff2, sizeof(buff2)); + printf("\r\nRead content write.txt: "); printf(buff2); + close(fd2); + exit(); +} + +static void user_write_test_initramfs_foo() +{ + printf("\r\nUser Write Test Initramfs pid: "); printf_int(getpid()); + char buff[] = "Hello, World!"; + int fd = open("/initramfs/f1", 0); + if(fd == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd); + int size = write(fd, buff, sizeof(buff)); + if(size < 0) { + printf("\r\nWrite file failed!"); + exit(); + } + close(fd); + + int fd2 = open("/initramfs/f1", 0); + if(fd2 == -1){ + printf("\r\nOpen file failed!"); + exit(); + } + printf("\r\nOpen file success, fd: "); printf_int(fd2); + char buff2[100]; + read(fd2, buff2, sizeof(buff2)); + printf("\r\nRead content f1: "); printf(buff2); + close(fd2); + exit(); +} + +static void user_stdout_test_foo() +{ + write(1, "\nhello\n", 6); + exit(); +} + +static void user_stdin_test_foo() +{ + char buf[100]; + read(0, buf, 20); + write(1, buf, 20); + exit(); +} \ No newline at end of file diff --git a/lab08/kernel/src/vfs.c b/lab08/kernel/src/vfs.c new file mode 100644 index 000000000..774f7e943 --- /dev/null +++ b/lab08/kernel/src/vfs.c @@ -0,0 +1,538 @@ +#include "vfs.h" +#include "alloc.h" +#include "string.h" +#include "tmpfs.h" +#include "errno.h" +#include "tmpfs.h" +#include "initramfs.h" +#include "io.h" +#include "schedule.h" +#include "fork.h" +#include "dev_uart.h" +#include "dev_framebuffer.h" + +extern struct task_struct* current; + +struct mount* rootfs; +struct filesystem global_fs[MAX_FILESYSTEM]; +struct file_operations global_dev[MAX_DEV_REG]; + +extern struct file_operations *initramfs_f_ops; + + +static struct vnode* next_step(struct vnode* start_node, const char* pathname, struct vnode** target_dir); +static struct file* create_file(struct vnode* vnode, int flags); +static char* get_file_name(const char* pathname); +static void simplify_path(char* pathname); + +void rootfs_init() +{ + // pre init + // global_fd_table_init(); + // 1. create a tmpfs filesystem + // 2. create a rootfs mount + // 3. setup rootfs mount + for(int i=0; iname = (char*)dynamic_alloc(16); + strcpy(tmpfs->name, "tmpfs"); + + tmpfs->setup_mount = tmpfs_setup_mount; + register_filesystem(tmpfs); + + rootfs = (struct mount*)dynamic_alloc(sizeof(struct mount)); + tmpfs->setup_mount(tmpfs, &rootfs); + + // initramfs + vfs_mount("/initramfs", "initramfs"); + + // devfs + vfs_mkdir("/dev"); + int uart_id = dev_uart_register(); + printf("\r\nUART ID: "); printf_int(uart_id); + vfs_mknod("/dev/uart", uart_id); + int framebuffer_id = dev_framebuffer_register(); + vfs_mknod("/dev/framebuffer", framebuffer_id); +} + + +int register_filesystem(struct filesystem* fs) { // ensure there is sufficient memory for the filesystem + // register the file system to the kernel. + // you can also initialize memory pool of the file system here. + if(!strcmp(fs->name, "tmpfs")) + { + //initialize memory pool of the file system + return tmpfs_register(); + } + else if(!strcmp(fs->name, "initramfs")) + { + return initramfs_register(); + } + return -1; +} + +int register_dev(struct file_operations* f_ops) +{ + for(int i=0; iwrite; + global_dev[i].read = f_ops->read; + global_dev[i].open = f_ops->open; + global_dev[i].close = f_ops->close; + return i; + } + } + return -1; +} + +int vfs_open(const char* pathname, int flags, struct file** target) { + // 1. Lookup pathname + // 2. Create a new file handle for this vnode if found. + // 3. Create a new file if O_CREAT is specified in flags and vnode not found + // lookup error code shows if file exist or not or other error occurs + // 4. Return error code if fails + struct vnode* vnode; + int ret = vfs_lookup(pathname, &vnode); + if(ret != 0 && flags != O_CREAT){ + printf("\r\n[ERROR] Cannot find the file"); + return -1; + } + else if(ret == 0 && flags == O_CREAT){ + printf("\r\n[ERROR] File already exists"); + return -1; + } + else if(flags == O_CREAT){ + struct vnode* target_dir; + vfs_get_node(pathname, &target_dir); + if(target_dir == NULL){ + printf("\r\n[ERROR] Cannot find the parent directory"); + return -1; + } + + char* file_name = get_file_name(pathname); + + if(target_dir->mount != NULL) + ret = target_dir->mount->root->v_ops->create(target_dir->mount->root, &vnode, file_name); + else + ret = target_dir->v_ops->create(target_dir, &vnode, file_name); + + if(ret != 0){ + printf("\r\n[ERROR] Cannot create the file"); + return -1; + } + *target = create_file(vnode, flags); + return ret; + } + + struct file* file = create_file(vnode, flags); + *target = file; + if(vnode->f_ops->open(vnode, &file) != 0){ + printf("\r\n[ERROR] Cannot open the file"); + return -1; + } + + return 0; +} + +int vfs_close(struct file* file) { + // 1. release the file handle + // 2. Return error code if fails + int ret = file->f_ops->close(file); + dfree(file); + return ret; +} + +int vfs_write(struct file* file, const void* buf, size_t len) { + // 1. write len byte from buf to the opened file. + // 2. return written size or error code if an error occurs. + int ret; + if(file->vnode->mount != NULL) + ret = file->vnode->mount->root->f_ops->write(file, buf, len); + else + ret = file->f_ops->write(file, buf, len); + return ret; +} + +int vfs_read(struct file* file, void* buf, size_t len) { + // 1. read min(len, readable size) byte to buf from the opened file. + // 2. block if nothing to read for FIFO type + // 2. return read size or error code if an error occurs. + int ret = file->f_ops->read(file, buf, len); + return ret; +} + +int vfs_mkdir(const char* pathname) +{ + + struct vnode* target_dir; + struct vnode* vnode = vfs_get_node(pathname, &target_dir); + if(vnode != NULL) + { + printf("\r\n[ERROR] Directory already exists"); + return CERROR; + } + + if(target_dir == NULL) + { + printf("\r\n[ERROR] Cannot find the parent directory"); + return CERROR; + } + struct vnode* new_dir; + char* file_name = get_file_name(pathname); + printf("\r\n[MKDIR] pathname: "); printf(pathname); printf(" , filename: "); printf(file_name); + + + int ret; + if(target_dir->mount != NULL){ // check if it is a mount point + ret = target_dir->mount->root->v_ops->mkdir(target_dir->mount->root, &new_dir, file_name); + } + else { + ret = target_dir->v_ops->mkdir(target_dir, &new_dir, file_name); + } + + if(ret != 0) + { + printf("\r\n[ERROR] Cannot create directory"); + dfree(file_name); + return CERROR; + } + dfree(file_name); + return 0; +} + +int vfs_mknod(const char* pathname, int id) +{ + + struct file* file = (struct file*)dynamic_alloc(sizeof(struct file)); + + vfs_open(pathname, O_CREAT, &file); + file->vnode->f_ops = &global_dev[id]; // set the file operations + vfs_close(file); + return 0; +} + +int vfs_mount(const char* target, const char* filesystem) // mount the filesystem to the target +{ + // struct mount* mount_point = (struct mount*)dynamic_alloc(sizeof(struct mount)); + struct filesystem* fs = (struct filesystem*)dynamic_alloc(sizeof(struct filesystem)); + + struct vnode* vnode = vfs_get_node(target, 0); + if(vnode == NULL) + { + vfs_mkdir(target); + vnode = vfs_get_node(target, 0); + } + + vnode->mount = (struct mount*)dynamic_alloc(sizeof(struct mount)); + + fs->name = (char*)dynamic_alloc(16); + if(!strcmp(filesystem, "tmpfs")) + { + + strcpy(fs->name, "tmpfs"); + + fs->setup_mount = tmpfs_setup_mount; + + } + else if(!strcmp(filesystem, "initramfs")) + { + strcpy(fs->name, "initramfs"); + + fs->setup_mount = initramfs_setup_mount; + } + else + { + printf("\r\n[ERROR] Filesystem not found"); + return CERROR; + } + + register_filesystem(fs); + fs->setup_mount(fs, &vnode->mount); + + vnode->mount->root->parent = vnode->parent; + + return 0; +} +int vfs_lookup(const char* pathname, struct vnode** target) +{ + struct vnode* vnode = vfs_get_node(pathname, NULL); + if(vnode == NULL) + { + return -1; + } + *target = vnode; + return 0; +} + +int vfs_list(const char* pathname) +{ + struct vnode* vnode; + int ret = vfs_lookup(pathname, &vnode); + + if(ret != 0) + { + printf("\r\n[ERROR] Cannot find the directory"); + return -1; + } + if(vnode->mount != NULL){ // check if it is a mount point + ret = vnode->mount->root->v_ops->list(vnode->mount->root); + } + else { + ret = vnode->v_ops->list(vnode); + } + if(ret != 0) + { + printf("\r\n[ERROR] Cannot list the directory"); + return CERROR; + } + return 0; +} + + +int vfs_chdir(const char* relative_path) +{ + char* current_abs_path = current->cwd; + char* new_abs_path = (char*)dynamic_alloc(strlen(current_abs_path) + strlen(relative_path) + 4); + strcpy(new_abs_path, current_abs_path); + if(relative_path[0] == '/'){ // absolute path + strcpy(new_abs_path, relative_path); + } + else{ // relative path + strcpy(new_abs_path, current_abs_path); + strcpy(new_abs_path + strlen(current_abs_path), relative_path); + } + + if(new_abs_path[strlen(new_abs_path)-1] != '/'){ // add '/' at the end + new_abs_path[strlen(new_abs_path)] = '/'; + new_abs_path[strlen(new_abs_path)+1] = '\0'; + } + + // printf("\r\n[CHDIR] new_abs_path: "); printf(new_abs_path); + struct vnode* vnode = vfs_get_node(new_abs_path, NULL); + + if(vnode == NULL) + { + printf("\r\n[ERROR] Cannot find the directory"); + return CERROR; + } + + // printf("\r\n[INFO] File descriptor 0: "); printf_hex((unsigned long)current->fd_table.fds[0]); + // printf("\r\n[INFO] File descriptor 1: "); printf_hex((unsigned long)current->fd_table.fds[1]); + // printf("\r\n[INFO] File descriptor 2: "); printf_hex((unsigned long)current->fd_table.fds[2]); + + // simplify_path(new_abs_path); + // printf("\r\n[CHDIR] new_abs_path(simplified): "); printf(new_abs_path); + // printf("\r\n[INFO] File descriptor 0: "); printf_hex((unsigned long)current->fd_table.fds[0]); + // printf("\r\n[INFO] File descriptor 1: "); printf_hex((unsigned long)current->fd_table.fds[1]); + // printf("\r\n[INFO] File descriptor 2: "); printf_hex((unsigned long)current->fd_table.fds[2]); + preempt_enable(); + strcpy(current->cwd, new_abs_path); + preempt_disable(); + + return 0; +} + + +int vfs_exec(const char* pathname, char* const argv[]) +{ + struct file* file; + int ret = vfs_open(pathname, O_RW, &file); + + if(ret != 0) + { + printf("\r\n[ERROR] Cannot open the file"); + return CERROR; + } + + int filesize = file->vnode->f_ops->getsize(file->vnode); + void* user_program_addr = balloc(filesize+THREAD_SIZE); + + vfs_read(file, user_program_addr, filesize); + + printf("\r\n[EXEC] File: "); printf(pathname); printf(" , size: "); printf_hex(filesize); + + preempt_disable(); // leads to get the correct current task + + current->state = TASK_STOPPED; + + unsigned long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)user_program_addr, 0); + + preempt_enable(); + + return 0; +} + + +struct vnode* vfs_get_node(const char* pathname, struct vnode** target_dir) +{ + struct vnode* start_node; + + if(pathname[0] == '/'){ + start_node = rootfs->root; + return next_step(start_node, pathname+1, target_dir); + } + else{ + start_node = vfs_get_node(current->cwd, NULL); + return next_step(start_node, pathname, target_dir); + } + return NULL; +} + +static struct vnode* next_step(struct vnode* start_node, const char* pathname, struct vnode** target_dir) +{ + char* tmp_path = (char*)dynamic_alloc(strlen(pathname)+1); + strcpy(tmp_path, pathname); + char* token = strtok(tmp_path, "/"); + // if(strlen(token) == 0) { token = NULL; } + struct vnode* current_node = start_node; + + while(token != NULL){ + *target_dir = current_node; + if(!strcmp(token, "..")){ // [TODO] might have bugs when the path contains mount points + if(current_node->parent == NULL){ + current_node = NULL; + goto next_step_end; + } + current_node = current_node->parent; + } + else if(!strcmp(token, ".")){ + // do nothing + } + else{ + struct vnode* next_node; + if(current_node->mount != NULL){ + if(current_node->mount->root->v_ops->lookup(current_node->mount->root, &next_node, token) == 0){ + current_node = next_node; + } + else{ + current_node = NULL; + goto next_step_end; + } + } + else if(current_node->v_ops->lookup(current_node, &next_node, token) == 0){ + current_node = next_node; + } + else{ + current_node = NULL; + goto next_step_end; + } + } + token = strtok(NULL, "/"); + } +next_step_end: + dfree(tmp_path); + return current_node; +} + +static struct file* create_file(struct vnode* vnode, int flags) +{ + struct file* file = (struct file*)dynamic_alloc(sizeof(struct file)); + file->vnode = vnode; + file->f_pos = 0; + file->f_ops = vnode->f_ops; + file->flags = flags; + return file; +} + + +static char* get_file_name(const char* pathname) +{ + char* file_name = (char*)dynamic_alloc(16); + int i; + for(i = strlen(pathname)-1; i >= 0; i--){ + if(pathname[i] == '/'){ + break; + } + } + if(i == -1){ + strcpy(file_name, pathname); + } + else{ + strcpy(file_name, pathname+i+1); + } + return file_name; +} + +static void simplify_path(char* pathname) +{ + + // printf("\r\n"); printf(__func__); + #define MAX_SEGMENTS 256 + + char* tmp_path = (char*)dynamic_alloc(strlen(pathname)+1); + char* new_path = (char*)dynamic_alloc(strlen(pathname)+1); + + strcpy(tmp_path, pathname); + + char* segments[MAX_SEGMENTS]; + int n_segments = 0; + + char* token = strtok(tmp_path, "/"); + int isFirst = 1; // avoid the first NULL token + while(token != NULL || isFirst == 1){ + isFirst = 0; + if(token != NULL){ + segments[n_segments] = (char*)dynamic_alloc(strlen(token)+1); + strcpy(segments[n_segments++], token); + } + token = strtok(NULL, "/"); + } + + int need_segment[MAX_SEGMENTS]; + int need_idx = 0; + for(int i=0; i 0){ + need_idx--; + } + } + else{ + need_segment[need_idx++] = i; + } + } + + // printf("\r\n[DEBUG] need_idx: "); printf_int(need_idx); + + for(int i=0; ic_namesize, 16, 8); + int filesize = strtol(head->c_filesize, 16, 8); + + char *filename = (void*)head + head_size; + + uint32_t offset = head_size + namesize; + if(offset % 4 != 0) offset = ((offset/4 +1)*4); + + if(strcmp(filename, "TRAILER!!!") == 0){ + printf("\nFile not found"); + break; + } + else if(strcmp(filename, target_name) == 0){ + /* The filedata is appended after filename */ + char *filedata = (void*)head + offset; + + printf("\r\n[INFO] File found: "); printf(target_name); printf(" in CPIO at "); printf_hex((unsigned long)filedata); + printf("\r\n[INFO] File Size: "); printf_hex(filesize); + + void* user_program_addr = balloc(filesize+THREAD_SIZE); // extra page in case + if(user_program_addr == NULL) return; + memzero_asm((unsigned long)user_program_addr, filesize+THREAD_SIZE); + for(int i=0; istate = TASK_STOPPED; + + unsigned long tmp; + asm volatile("mrs %0, cntkctl_el1" : "=r"(tmp)); + tmp |= 1; + asm volatile("msr cntkctl_el1, %0" : : "r"(tmp)); + + copy_process(PF_KTHREAD, (unsigned long)&kp_user_mode, (unsigned long)user_program_addr, 0); + + preempt_enable(); + break; + } + + if(filesize % 4 != 0) filesize = (filesize/4 +1)*4; + head = (void*)head + offset + filesize; + } + return; +} \ No newline at end of file diff --git a/lab8/bootloader/FAT_R.txt b/lab8/bootloader/FAT_R.txt new file mode 100644 index 000000000..5d2252cd1 --- /dev/null +++ b/lab8/bootloader/FAT_R.txt @@ -0,0 +1 @@ +fat_r test \ No newline at end of file diff --git a/lab8/bootloader/bcm2710-rpi-3-b-plus.dtb b/lab8/bootloader/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 000000000..38395a23f Binary files /dev/null and b/lab8/bootloader/bcm2710-rpi-3-b-plus.dtb differ diff --git a/lab8/bootloader/config.txt b/lab8/bootloader/config.txt new file mode 100644 index 000000000..15654a481 --- /dev/null +++ b/lab8/bootloader/config.txt @@ -0,0 +1,3 @@ +kernel=bootloader.img +arm_64bit=1 +initramfs initramfs.cpio 0x8000000 diff --git a/lab8/bootloader/include/bcm2837/rpi_base.h b/lab8/bootloader/include/bcm2837/rpi_base.h new file mode 100644 index 000000000..e3259e8de --- /dev/null +++ b/lab8/bootloader/include/bcm2837/rpi_base.h @@ -0,0 +1,6 @@ +#ifndef _RPI_BASE_H_ +#define _RPI_BASE_H_ + +#define PERIPHERAL_BASE 0x3F000000 + +#endif /*_RPI_BASE_H_ */ diff --git a/lab8/bootloader/include/bcm2837/rpi_gpio.h b/lab8/bootloader/include/bcm2837/rpi_gpio.h new file mode 100644 index 000000000..e5133708a --- /dev/null +++ b/lab8/bootloader/include/bcm2837/rpi_gpio.h @@ -0,0 +1,25 @@ +#ifndef _RPI_GPIO_H_ +#define _RPI_GPIO_H_ + +#include "bcm2837/rpi_base.h" + +#define GPFSEL0 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200000)) +#define GPFSEL1 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200004)) +#define GPFSEL2 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200008)) +#define GPFSEL3 ((volatile unsigned int*)(PERIPHERAL_BASE+0x0020000C)) +#define GPFSEL4 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200010)) +#define GPFSEL5 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200014)) +#define GPSET0 ((volatile unsigned int*)(PERIPHERAL_BASE+0x0020001C)) +#define GPSET1 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200020)) +#define GPCLR0 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200028)) +#define GPLEV0 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200034)) +#define GPLEV1 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200038)) +#define GPEDS0 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200040)) +#define GPEDS1 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200044)) +#define GPHEN0 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200064)) +#define GPHEN1 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200068)) +#define GPPUD ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int*)(PERIPHERAL_BASE+0x00200098)) +#define GPPUDCLK1 ((volatile unsigned int*)(PERIPHERAL_BASE+0x0020009C)) + +#endif /*_RPI_GPIO_H_*/ diff --git a/lab8/bootloader/include/bcm2837/rpi_uart1.h b/lab8/bootloader/include/bcm2837/rpi_uart1.h new file mode 100644 index 000000000..959130656 --- /dev/null +++ b/lab8/bootloader/include/bcm2837/rpi_uart1.h @@ -0,0 +1,19 @@ +#ifndef _RPI_UART1_H_ +#define _RPI_UART1_H_ + +#include "bcm2837/rpi_base.h" + +#define AUX_ENABLES ((volatile unsigned int*)(PERIPHERAL_BASE+0x00215004)) +#define AUX_MU_IO_REG ((volatile unsigned int*)(PERIPHERAL_BASE+0x00215040)) +#define AUX_MU_IER_REG ((volatile unsigned int*)(PERIPHERAL_BASE+0x00215044)) +#define AUX_MU_IIR_REG ((volatile unsigned int*)(PERIPHERAL_BASE+0x00215048)) +#define AUX_MU_LCR_REG ((volatile unsigned int*)(PERIPHERAL_BASE+0x0021504C)) +#define AUX_MU_MCR_REG ((volatile unsigned int*)(PERIPHERAL_BASE+0x00215050)) +#define AUX_MU_LSR_REG ((volatile unsigned int*)(PERIPHERAL_BASE+0x00215054)) +#define AUX_MU_MSR_REG ((volatile unsigned int*)(PERIPHERAL_BASE+0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int*)(PERIPHERAL_BASE+0x0021505C)) +#define AUX_MU_CNTL_REG ((volatile unsigned int*)(PERIPHERAL_BASE+0x00215060)) +#define AUX_MU_STAT_REG ((volatile unsigned int*)(PERIPHERAL_BASE+0x00215064)) +#define AUX_MU_BAUD_REG ((volatile unsigned int*)(PERIPHERAL_BASE+0x00215068)) + +#endif /*_RPI_UART1_H_ */ diff --git a/lab8/bootloader/include/power.h b/lab8/bootloader/include/power.h new file mode 100644 index 000000000..baf990974 --- /dev/null +++ b/lab8/bootloader/include/power.h @@ -0,0 +1,8 @@ +#ifndef _POWER_H_ +#define _POWER_H_ + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +#endif /*_POWER_H_*/ diff --git a/lab8/bootloader/include/shell.h b/lab8/bootloader/include/shell.h new file mode 100644 index 000000000..702f5eb14 --- /dev/null +++ b/lab8/bootloader/include/shell.h @@ -0,0 +1,23 @@ +#ifndef _SHELL_H_ +#define _SHELL_H_ + +#define CLI_MAX_CMD 3 +#define CMD_MAX_LEN 32 +#define MSG_MAX_LEN 128 + +typedef struct CLI_CMDS +{ + char command[CMD_MAX_LEN]; + char help[MSG_MAX_LEN]; +} CLI_CMDS; + +void cli_cmd_clear(char*, int); +void cli_cmd_read(char*); +void cli_cmd_exec(char*); +void cli_print_banner(); + +void do_cmd_help(); +void do_cmd_loadimg(); +void do_cmd_reboot(); + +#endif /* _SHELL_H_ */ diff --git a/lab8/bootloader/include/uart1.h b/lab8/bootloader/include/uart1.h new file mode 100644 index 000000000..329d25c81 --- /dev/null +++ b/lab8/bootloader/include/uart1.h @@ -0,0 +1,11 @@ +#ifndef _UART1_H_ +#define _UART1_H_ + +void uart_init(); +char uart_getc(); +char uart_recv(); +void uart_send(unsigned int c); +int uart_puts(char* fmt, ...); +void uart_2hex(unsigned int d); + +#endif /*_UART1_H_*/ diff --git a/lab8/bootloader/include/utils.h b/lab8/bootloader/include/utils.h new file mode 100644 index 000000000..e65ece675 --- /dev/null +++ b/lab8/bootloader/include/utils.h @@ -0,0 +1,11 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#define VSPRINT_MAX_BUF_SIZE 128 + +unsigned int sprintf(char *dst, char* fmt, ...); +unsigned int vsprintf(char *dst,char* fmt, __builtin_va_list args); + +int strcmp(const char*, const char*); + +#endif /* _UTILS_H_ */ diff --git a/lab8/bootloader/makefile b/lab8/bootloader/makefile new file mode 100644 index 000000000..b81bad692 --- /dev/null +++ b/lab8/bootloader/makefile @@ -0,0 +1,42 @@ +ARMGNU ?= aarch64-linux-gnu + +CFLAGS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only +ASMFLAGS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src +#--------------------------------------------------------------------------------------- + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + @mkdir -p $(@D) + $(ARMGNU)-gcc $(CFLAGS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMFLAGS) -MMD -c $< -o $@ + +bootloader.img: $(SRC_DIR)/link.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/link.ld -o $(BUILD_DIR)/bootloader.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/bootloader.elf -O binary bootloader.img + +all: bootloader.img + +clean: + rm -rf $(BUILD_DIR) *.img + +run_std: + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -serial null -serial stdio -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +run_pty: + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -serial null -serial pty -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb + +debug: + qemu-system-aarch64 -M raspi3b -kernel bootloader.img -display none -S -s + diff --git a/lab8/bootloader/src/boot.S b/lab8/bootloader/src/boot.S new file mode 100644 index 000000000..c872f56a7 --- /dev/null +++ b/lab8/bootloader/src/boot.S @@ -0,0 +1,52 @@ +/* ARMv8 Assembly Instruction */ +/** + +mov x0, x1 + sets: x0 = x1 +ldr x0, + load 32bits from to x0 +ldr w0, + load 64bits from to w0 +cbz x0,