From c11ed2722efe065ea4b449c8ab43d5d8e57c3d14 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Thu, 27 Jun 2024 17:31:23 +0800 Subject: [PATCH] finish lab7 --- lab7/.clang-format | 9 + lab7/.clangd | 7 + lab7/Makefile | 24 ++ lab7/README.md | 22 ++ lab7/bcm2710-rpi-3-b-plus.dtb | Bin 0 -> 34228 bytes lab7/bsp/entry.S | 114 +++++++++ lab7/bsp/entry.h | 39 +++ lab7/bsp/fbdev.c | 90 +++++++ lab7/bsp/fbdev.h | 16 ++ lab7/bsp/gpio.h | 25 ++ lab7/bsp/gpu.c | 29 +++ lab7/bsp/irq.h | 58 +++++ lab7/bsp/linker.ld | 26 ++ lab7/bsp/mailbox.c | 75 ++++++ lab7/bsp/mailbox.h | 31 +++ lab7/bsp/ramfs.c | 96 ++++++++ lab7/bsp/ramfs.h | 41 ++++ lab7/bsp/reboot.c | 20 ++ lab7/bsp/reboot.h | 8 + lab7/bsp/sched.S | 26 ++ lab7/bsp/start.S | 63 +++++ lab7/bsp/sysregs.h | 11 + lab7/bsp/timer.c | 47 ++++ lab7/bsp/traps.h | 41 ++++ lab7/bsp/uart.c | 171 ++++++++++++++ lab7/bsp/uart.h | 20 ++ lab7/bsp/utils.c | 57 +++++ lab7/config.txt | 1 + lab7/file_sender.py | 25 ++ lab7/initramfs.cpio | Bin 0 -> 903168 bytes lab7/kernel/Makefile | 48 ++++ lab7/kernel/buddy.c | 269 +++++++++++++++++++++ lab7/kernel/commands.h | 31 +++ lab7/kernel/commands/async_io.c | 39 +++ lab7/kernel/commands/exec.c | 57 +++++ lab7/kernel/commands/hello.c | 8 + lab7/kernel/commands/mailbox.c | 23 ++ lab7/kernel/commands/memory.c | 73 ++++++ lab7/kernel/commands/multi_thread.c | 29 +++ lab7/kernel/commands/ramfs.c | 49 ++++ lab7/kernel/commands/reboot.c | 12 + lab7/kernel/commands/rootfs.c.old | 43 ++++ lab7/kernel/commands/set_timeout.c | 27 +++ lab7/kernel/console.c | 109 +++++++++ lab7/kernel/console.h | 13 + lab7/kernel/device_tree.c | 91 +++++++ lab7/kernel/device_tree.h | 31 +++ lab7/kernel/fs/dev_uart.c | 51 ++++ lab7/kernel/fs/dev_uart.h | 15 ++ lab7/kernel/fs/fdtable.h | 21 ++ lab7/kernel/fs/initramfs.h | 36 +++ lab7/kernel/fs/tmpfs.c | 185 +++++++++++++++ lab7/kernel/fs/tmpfs.h | 31 +++ lab7/kernel/fs/vfs.c | 266 +++++++++++++++++++++ lab7/kernel/fs/vfs.h | 80 +++++++ lab7/kernel/initramfs.c | 135 +++++++++++ lab7/kernel/io.c | 51 ++++ lab7/kernel/io.h | 12 + lab7/kernel/irq_entry.c | 140 +++++++++++ lab7/kernel/irq_entry.h | 17 ++ lab7/kernel/kmalloc.c | 137 +++++++++++ lab7/kernel/lock.c | 16 ++ lab7/kernel/lock.h | 7 + lab7/kernel/main.c | 49 ++++ lab7/kernel/memory.h | 20 ++ lab7/kernel/mm.h | 31 +++ lab7/kernel/sched.h | 70 ++++++ lab7/kernel/signal.c | 49 ++++ lab7/kernel/signal.h | 13 + lab7/kernel/simple.c | 30 +++ lab7/kernel/syscall.c | 313 +++++++++++++++++++++++++ lab7/kernel/syscall.h | 32 +++ lab7/kernel/task.c | 151 ++++++++++++ lab7/kernel/timer.c | 73 ++++++ lab7/kernel/timer.h | 11 + lab7/lib/limits.h | 7 + lab7/lib/sprintf.c | 147 ++++++++++++ lab7/lib/stddef.h | 13 + lab7/lib/stdlib.c | 41 ++++ lab7/lib/stdlib.h | 7 + lab7/lib/string.c | 107 +++++++++ lab7/lib/string.h | 15 ++ lab7/lib/utils.c | 3 + lab7/lib/utils.h | 9 + lab7/rootfs/file1 | 1 + lab7/rootfs/file2.txt | 1 + lab7/user_program/Makefile | 18 ++ lab7/user_program/linker.ld | 0 lab7/user_program/test_svc_exception.S | 11 + 89 files changed, 4566 insertions(+) create mode 100644 lab7/.clang-format create mode 100644 lab7/.clangd create mode 100644 lab7/Makefile create mode 100644 lab7/README.md create mode 100644 lab7/bcm2710-rpi-3-b-plus.dtb create mode 100644 lab7/bsp/entry.S create mode 100644 lab7/bsp/entry.h create mode 100644 lab7/bsp/fbdev.c create mode 100644 lab7/bsp/fbdev.h create mode 100644 lab7/bsp/gpio.h create mode 100644 lab7/bsp/gpu.c create mode 100644 lab7/bsp/irq.h create mode 100644 lab7/bsp/linker.ld create mode 100644 lab7/bsp/mailbox.c create mode 100644 lab7/bsp/mailbox.h create mode 100644 lab7/bsp/ramfs.c create mode 100644 lab7/bsp/ramfs.h create mode 100644 lab7/bsp/reboot.c create mode 100644 lab7/bsp/reboot.h create mode 100644 lab7/bsp/sched.S create mode 100644 lab7/bsp/start.S create mode 100644 lab7/bsp/sysregs.h create mode 100644 lab7/bsp/timer.c create mode 100644 lab7/bsp/traps.h create mode 100644 lab7/bsp/uart.c create mode 100644 lab7/bsp/uart.h create mode 100644 lab7/bsp/utils.c create mode 100644 lab7/config.txt create mode 100644 lab7/file_sender.py create mode 100644 lab7/initramfs.cpio create mode 100644 lab7/kernel/Makefile create mode 100644 lab7/kernel/buddy.c create mode 100644 lab7/kernel/commands.h create mode 100644 lab7/kernel/commands/async_io.c create mode 100644 lab7/kernel/commands/exec.c create mode 100644 lab7/kernel/commands/hello.c create mode 100644 lab7/kernel/commands/mailbox.c create mode 100644 lab7/kernel/commands/memory.c create mode 100644 lab7/kernel/commands/multi_thread.c create mode 100644 lab7/kernel/commands/ramfs.c create mode 100644 lab7/kernel/commands/reboot.c create mode 100644 lab7/kernel/commands/rootfs.c.old create mode 100644 lab7/kernel/commands/set_timeout.c create mode 100644 lab7/kernel/console.c create mode 100644 lab7/kernel/console.h create mode 100644 lab7/kernel/device_tree.c create mode 100644 lab7/kernel/device_tree.h create mode 100644 lab7/kernel/fs/dev_uart.c create mode 100644 lab7/kernel/fs/dev_uart.h create mode 100644 lab7/kernel/fs/fdtable.h create mode 100644 lab7/kernel/fs/initramfs.h create mode 100644 lab7/kernel/fs/tmpfs.c create mode 100644 lab7/kernel/fs/tmpfs.h create mode 100644 lab7/kernel/fs/vfs.c create mode 100644 lab7/kernel/fs/vfs.h create mode 100644 lab7/kernel/initramfs.c create mode 100644 lab7/kernel/io.c create mode 100644 lab7/kernel/io.h create mode 100644 lab7/kernel/irq_entry.c create mode 100644 lab7/kernel/irq_entry.h create mode 100644 lab7/kernel/kmalloc.c create mode 100644 lab7/kernel/lock.c create mode 100644 lab7/kernel/lock.h create mode 100644 lab7/kernel/main.c create mode 100644 lab7/kernel/memory.h create mode 100644 lab7/kernel/mm.h create mode 100644 lab7/kernel/sched.h create mode 100644 lab7/kernel/signal.c create mode 100644 lab7/kernel/signal.h create mode 100644 lab7/kernel/simple.c create mode 100644 lab7/kernel/syscall.c create mode 100644 lab7/kernel/syscall.h create mode 100644 lab7/kernel/task.c create mode 100644 lab7/kernel/timer.c create mode 100644 lab7/kernel/timer.h create mode 100644 lab7/lib/limits.h create mode 100644 lab7/lib/sprintf.c create mode 100644 lab7/lib/stddef.h create mode 100644 lab7/lib/stdlib.c create mode 100644 lab7/lib/stdlib.h create mode 100644 lab7/lib/string.c create mode 100644 lab7/lib/string.h create mode 100644 lab7/lib/utils.c create mode 100644 lab7/lib/utils.h create mode 100644 lab7/rootfs/file1 create mode 100644 lab7/rootfs/file2.txt create mode 100644 lab7/user_program/Makefile create mode 100644 lab7/user_program/linker.ld create mode 100644 lab7/user_program/test_svc_exception.S diff --git a/lab7/.clang-format b/lab7/.clang-format new file mode 100644 index 000000000..4113d14a2 --- /dev/null +++ b/lab7/.clang-format @@ -0,0 +1,9 @@ +UseTab: Never +TabWidth: 4 +IndentWidth: 4 +AccessModifierOffset: -4 + +BasedOnStyle: Google +IncludeBlocks: Regroup +SortIncludes: true + diff --git a/lab7/.clangd b/lab7/.clangd new file mode 100644 index 000000000..656204ef0 --- /dev/null +++ b/lab7/.clangd @@ -0,0 +1,7 @@ +CompileFlags: + Compiler: /usr/homebrew/bin/aarch64-linux-gnu-gcc + Add: [ + "-Wall", "-ffreestanding", "-nostdinc", "-nostdlib", "-nostartfiles", "-fno-stack-protector", "-g", "-mgeneral-regs-only", + "-I/Users/yjack/GitHub/osc2024/lab7/include", + ] + diff --git a/lab7/Makefile b/lab7/Makefile new file mode 100644 index 000000000..408f09705 --- /dev/null +++ b/lab7/Makefile @@ -0,0 +1,24 @@ +QEMU_OPTS = -initrd initramfs.cpio -dtb bcm2710-rpi-3-b-plus.dtb +BUILD_DIR := $(CURDIR)/build + +.PHONY: all bootloader kernel run clean + +all: clean kernel run + +clean: + rm -rf $(BUILD_DIR) + +bootloader: clean + $(MAKE) -C bootloader BUILD_DIR=$(BUILD_DIR) LIB_PATH=$(CURDIR)/lib BSP_PATH=$(CURDIR)/bsp + +kernel: clean + $(MAKE) -C kernel BUILD_DIR=$(BUILD_DIR) LIB_PATH=$(CURDIR)/lib BSP_PATH=$(CURDIR)/bsp + +run: + qemu-system-aarch64 -M raspi3b -kernel $(BUILD_DIR)/kernel8.img -display none -serial null -serial stdio $(QEMU_OPTS) + +run-bootloader: + qemu-system-aarch64 -M raspi3b -kernel $(BUILD_DIR)/kernel8.img -display none -serial null -serial pty $(QEMU_OPTS) + +debug: clean kernel + qemu-system-aarch64 -M raspi3b -kernel $(BUILD_DIR)/kernel8.img -display none -serial null -serial stdio -s -S $(QEMU_OPTS) diff --git a/lab7/README.md b/lab7/README.md new file mode 100644 index 000000000..e575fa0f3 --- /dev/null +++ b/lab7/README.md @@ -0,0 +1,22 @@ +# OSC2023-Lab01 + +| Github Account | Student ID | +| -------------- | ---------- | +| visitorckw | 312551071 | + +## Requirements + +- a cross-compiler for aarch64 +- (optional) qemu-system-aarch64 + +## Build + +``` +make +``` + +## Test With QEMU + +``` +make run +``` diff --git a/lab7/bcm2710-rpi-3-b-plus.dtb b/lab7/bcm2710-rpi-3-b-plus.dtb new file mode 100644 index 0000000000000000000000000000000000000000..c83b0817e2eb5295a3dfe6aafe3aa55d93e9785d GIT binary patch literal 34228 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 EL1 while using SP_EL0 + ventry invalid_exc_handler + ventry invalid_exc_handler + ventry invalid_exc_handler + ventry invalid_exc_handler + // EL1 -> EL1 while using SP_EL1 + ventry invalid_exc_handler + ventry irq_handler + ventry invalid_exc_handler + ventry invalid_exc_handler + // EL0 (AArch64) -> EL1 + ventry exception_handler + ventry irq_handler + ventry invalid_exc_handler + ventry invalid_exc_handler + // EL0 (AArch32) -> EL1 + ventry invalid_exc_handler + ventry invalid_exc_handler + ventry invalid_exc_handler + ventry invalid_exc_handler diff --git a/lab7/bsp/entry.h b/lab7/bsp/entry.h new file mode 100644 index 000000000..014f23be5 --- /dev/null +++ b/lab7/bsp/entry.h @@ -0,0 +1,39 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#define S_FRAME_SIZE 272 // size of all saved registers, which is 16*17 from pt_regs +#define S_X0 0 // offset of x0 register in saved stack frame + +#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 + +#endif + +#ifndef __ASSEMBLER__ +#include + +void ret_from_fork(void); + +void from_el1_to_el0(uint64_t, uint64_t); + +#endif diff --git a/lab7/bsp/fbdev.c b/lab7/bsp/fbdev.c new file mode 100644 index 000000000..44b6963e5 --- /dev/null +++ b/lab7/bsp/fbdev.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + +unsigned int __attribute__((aligned(16))) mbox[36]; + +unsigned int width, height, pitch, isrgb; /* dimensions and channel order */ +unsigned char *lfb; + +// This function is responsible for setting up the framebuffer +int fb_init() { + mbox[0] = 35 * 4; // Total size of the message + mbox[1] = MBOX_REQUEST; + + // Set physical width-height + mbox[2] = 0x48003; + mbox[3] = 8; + mbox[4] = 8; + mbox[5] = 1024; // width + mbox[6] = 768; // height + + // Set virtual width-height + mbox[7] = 0x48004; + mbox[8] = 8; + mbox[9] = 8; + mbox[10] = 1024; // virtual width + mbox[11] = 768; // virtual height + + // Set virtual offset + mbox[12] = 0x48009; + mbox[13] = 8; + mbox[14] = 8; + mbox[15] = 0; // x offset + mbox[16] = 0; // y offset + + // Set depth + mbox[17] = 0x48005; + mbox[18] = 4; + mbox[19] = 4; + mbox[20] = 32; // depth + + // Set pixel order + mbox[21] = 0x48006; + mbox[22] = 4; + mbox[23] = 4; + mbox[24] = 1; // RGB, not BGR + + // Get framebuffer + mbox[25] = 0x40001; + mbox[26] = 8; + mbox[27] = 8; + mbox[28] = 4096; // pointer to framebuffer + mbox[29] = 0; // size + + // Get pitch + mbox[30] = 0x40008; + mbox[31] = 4; + mbox[32] = 4; + mbox[33] = 0; // pitch + + mbox[34] = MBOX_TAG_LAST; + + // Call the mailbox + if (mailbox_call(MBOX_CH_PROP, mbox) && mbox[20] == 32 && mbox[28] != 0) { + mbox[28] &= 0x3FFFFFFF; // Convert GPU address to ARM address + + width = mbox[5]; // get actual physical width + height = mbox[6]; // get actual physical height + pitch = mbox[33]; // get number of bytes per line + isrgb = mbox[24]; // get the actual channel order + lfb = (void *)((unsigned long)mbox[28]); + + // Use the framebuffer (width, height, pitch, isrgb, lfb) + return 0; // Success + } + + return -1; // Failure +} + +int fb_write(size_t pos, const void *buf, size_t len) { + if (len + pos > pitch * height) { + uart_puts("[ERROR] Attempted write out of bounds\r\n"); + return -1; + } + + memcpy(lfb + pos, buf, len); + return 0; +} diff --git a/lab7/bsp/fbdev.h b/lab7/bsp/fbdev.h new file mode 100644 index 000000000..6abf3e873 --- /dev/null +++ b/lab7/bsp/fbdev.h @@ -0,0 +1,16 @@ +#ifndef _FBDEV_H_ +#define _FBDEV_H_ + +#include + +struct framebuffer_info { + unsigned int width; + unsigned int height; + unsigned int pitch; + unsigned int isrgb; +}; + +int fb_init(); +int fb_write(size_t pos, const void *buf, size_t len); + +#endif diff --git a/lab7/bsp/gpio.h b/lab7/bsp/gpio.h new file mode 100644 index 000000000..6c1c10e63 --- /dev/null +++ b/lab7/bsp/gpio.h @@ -0,0 +1,25 @@ +#ifndef _GPIO_H +#define _GPIO_H + +#define MMIO_BASE 0x3F000000 // BCM2837 ARM Peripherals Page 6 + +#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE + 0x00200000)) +#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE + 0x00200004)) +#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE + 0x00200008)) +#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE + 0x0020000C)) +#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE + 0x00200010)) +#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE + 0x00200014)) +#define GPSET0 ((volatile unsigned int*)(MMIO_BASE + 0x0020001C)) +#define GPSET1 ((volatile unsigned int*)(MMIO_BASE + 0x00200020)) +#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE + 0x00200028)) +#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE + 0x00200034)) +#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE + 0x00200038)) +#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE + 0x00200040)) +#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE + 0x00200044)) +#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE + 0x00200064)) +#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE + 0x00200068)) +#define GPPUD ((volatile unsigned int*)(MMIO_BASE + 0x00200094)) +#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE + 0x00200098)) +#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE + 0x0020009C)) + +#endif diff --git a/lab7/bsp/gpu.c b/lab7/bsp/gpu.c new file mode 100644 index 000000000..e0643a273 --- /dev/null +++ b/lab7/bsp/gpu.c @@ -0,0 +1,29 @@ +#include +/* Auxilary mini UART registers */ +#define AUX_ENABLE ((volatile unsigned int *)(MMIO_BASE + 0x00215004)) +#define AUX_MU_IO ((volatile unsigned int *)(MMIO_BASE + 0x00215040)) +#define AUX_MU_IER ((volatile unsigned int *)(MMIO_BASE + 0x00215044)) +#define AUX_MU_IIR ((volatile unsigned int *)(MMIO_BASE + 0x00215048)) +#define AUX_MU_LCR ((volatile unsigned int *)(MMIO_BASE + 0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int *)(MMIO_BASE + 0x00215050)) +#define AUX_MU_LSR ((volatile unsigned int *)(MMIO_BASE + 0x00215054)) +#define AUX_MU_MSR ((volatile unsigned int *)(MMIO_BASE + 0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int *)(MMIO_BASE + 0x0021505C)) +#define AUX_MU_CNTL ((volatile unsigned int *)(MMIO_BASE + 0x00215060)) +#define AUX_MU_STAT ((volatile unsigned int *)(MMIO_BASE + 0x00215064)) +#define AUX_MU_BAUD ((volatile unsigned int *)(MMIO_BASE + 0x00215068)) + +#include +#include +#include + +uint32_t is_aux_irq() { + // uart_puts("\nIRQ_PENDING_1: "); + // uart_hex((unsigned long)*IRQ_PENDING_1); + // uart_puts("\n"); + return (*IRQ_PENDING_1 & (1 << 29)); +} + +uint32_t is_uart_rx_irq() { return (*AUX_MU_IIR & 0x6) == (1 << 2); } + +uint32_t is_uart_tx_irq() { return (*AUX_MU_IIR & 0x6) == (1 << 1); } diff --git a/lab7/bsp/irq.h b/lab7/bsp/irq.h new file mode 100644 index 000000000..5ccd3f84c --- /dev/null +++ b/lab7/bsp/irq.h @@ -0,0 +1,58 @@ +// BCM2837 ARM Peripherals Page 6 +#define MMIO_BASE \ + 0x3F000000 +// 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 + +// QA7 page. 16 +#define CORE0_IRQ_SOURCE \ + ((volatile unsigned int*)(0x40000060)) // Get the IRQ source for the core 0. + +#ifndef __IRQ_H__ +#define __IRQ_H__ + +#include + +// el1 IRQ can be disable to protect the critical sections +void enable_irq(); +void disable_irq(); + +// GPU IRQ handle is used to handle the GPU IRQ such as UART IRQ +void gpu_irq_handler(); + +// Core timer IRQ handle is used to handle the core timer IRQ +void core_timer_enable(); +void core_timer_disable(); +void core_timer_irq_handler(); +uint64_t timer_get_uptime(); + +// IRQ utils +uint32_t is_core_timer_irq(); +uint32_t is_gpu_irq(); + +uint32_t is_aux_irq(); +uint32_t is_uart_rx_irq(); +uint32_t is_uart_tx_irq(); + +const char *get_exception_message(unsigned long type); + +#endif diff --git a/lab7/bsp/linker.ld b/lab7/bsp/linker.ld new file mode 100644 index 000000000..54b6e7698 --- /dev/null +++ b/lab7/bsp/linker.ld @@ -0,0 +1,26 @@ + +SECTIONS +{ + . = 0x60000; + __loader_start = .; + . = 0x80000; + .text : + { + KEEP(*(.text.boot)) + *(.text) + } + .rodata :{ *(.rodata) } + .data : { *(.data) } + .bss : + { + __bss_start = .; + *(.bss) + *(COMMON) + __bss_end = .; + } + . = ALIGN(8); + __heap_start = .; + __loader_end = .; +} +__bss_size = (__bss_end - __bss_start) >> 3; +__loader_size = (__loader_end - __loader_start) >> 3; diff --git a/lab7/bsp/mailbox.c b/lab7/bsp/mailbox.c new file mode 100644 index 000000000..76826d874 --- /dev/null +++ b/lab7/bsp/mailbox.c @@ -0,0 +1,75 @@ +#include +#include + +int mailbox_call(unsigned char ch, unsigned int *mailbox) { + // Write the data (shifted into the upper 28 bits) combined with + // the channel (in the lower four bits) to the write register. + unsigned int r = + (((unsigned long)mailbox) & ~0xf) | (ch & 0xf); // mail_ch_prop + // & ~0xf => only "and" upper 28 bit can be saved + // |8 => if upper 28 is 1 => save and ensure last 4 bit is 1 + + // Check if Mailbox 0 status register’s full flag is set. + while (*MAILBOX_STATUS & MAILBOX_FULL) { + asm volatile("nop"); + }; + + // If not, then you can write to Mailbox 1 Read/Write register. + *MAILBOX_WRITE = r; + + while (1) { + // Check if Mailbox 0 status register’s empty flag is set. + while (*MAILBOX_STATUS & MAILBOX_EMPTY) { + asm volatile("nop"); + }; + + // If not, then you can read from Mailbox 0 Read/Write register. + // Check if the value is the same as you wrote in step 1. + if (r == *MAILBOX_READ) { + return mailbox[1] == REQUEST_SUCCEED; + } + } + + return 0; +} + +unsigned int 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; + + // message passing procedure call, you should implement + // it following the 6 steps provided above. + mailbox_call(8, mailbox); + + return mailbox[5]; +} + +void get_memory_info(unsigned int *base_addr, unsigned int *size) { + 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; // tag code + mailbox[5] = 0; // base address + mailbox[6] = 0; // size in bytes + mailbox[7] = END_TAG; // end tag + + // message passing procedure call, you should implement + // it following the 6 steps provided above. + mailbox_call(8, mailbox); + + // ARM memory base address + *base_addr = mailbox[5]; + // ARM memory size + *size = mailbox[6]; +} diff --git a/lab7/bsp/mailbox.h b/lab7/bsp/mailbox.h new file mode 100644 index 000000000..2eebf7fbe --- /dev/null +++ b/lab7/bsp/mailbox.h @@ -0,0 +1,31 @@ +#ifndef __PERIPHERALS_MAILBOX_H__ +#define __PERIPHERALS_MAILBOX_H__ + +#define MMIO_BASE 0x3F000000 // BCM2837 ARM Peripherals Page 6 +#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 + +// lab7 +#define MBOX_REQUEST 0 +#define MBOX_CH_PROP 8 +#define MBOX_TAG_LAST 0 + +int mailbox_call(unsigned char ch, unsigned int *mailbox); +unsigned int get_board_revision(); +void get_memory_info(unsigned int *base, unsigned int *size); + +#endif diff --git a/lab7/bsp/ramfs.c b/lab7/bsp/ramfs.c new file mode 100644 index 000000000..f66202bfe --- /dev/null +++ b/lab7/bsp/ramfs.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include + +// #define CPIO_BASE_QEMU (0x8000000) +#define CPIO_BASE_RPI (0x20000000) +static void *ramfs_base = (void *)CPIO_BASE_RPI; // DEFAULT for RPI + +static int hextoi(char *s, int n); + +void init_ramfs_callback(void *addr) { + uart_puts("[INFO] Initrd is mounted at "); + uart_hex((uint64_t)addr); + uart_send('\n'); + ramfs_base = addr; +} + +static file_list_t file_list; + +file_list_t *ramfs_get_file_list() { + uint8_t *fptr = (uint8_t *)ramfs_base; // for 8 byte alignment + file_list.file_count = 0; // 重置檔案數量 + + while (strcmp((void *)fptr + sizeof(cpio_t), "TRAILER!!!") && + file_list.file_count < MAX_FILES) { + char *file_name = (void *)fptr + sizeof(cpio_t); + + cpio_t *header = (cpio_t *)fptr; + uint32_t namesize = hextoi(header->c_namesize, 8); + uint32_t filesize = hextoi(header->c_filesize, 8); + uint32_t copy_length = + namesize < MAX_FILENAME_LENGTH ? namesize : MAX_FILENAME_LENGTH - 1; + + memcpy(file_list.file_names[file_list.file_count], file_name, + copy_length); + file_list.file_names[file_list.file_count][copy_length] = '\0'; + file_list.file_sizes[file_list.file_count] = filesize; + + uint32_t headsize = align4(sizeof(cpio_t) + namesize); + uint32_t datasize = align4(filesize); + file_list.file_data[file_list.file_count] = (void *)fptr + headsize; + file_list.file_count++; + + fptr += headsize + datasize; + } + + return &file_list; +} + +void ramfs_get_file_contents(const char *file_name, char *file_buf) { + uint8_t *fptr = (uint8_t *)ramfs_base; // for 8 byte alignment + while (strcmp((void *)fptr + sizeof(cpio_t), "TRAILER!!!")) { + cpio_t *header = (cpio_t *)fptr; + uint32_t namesize = hextoi(header->c_namesize, 8); + uint32_t filesize = hextoi(header->c_filesize, 8); + + uint32_t headsize = align4(sizeof(cpio_t) + namesize); + uint32_t datasize = align4(filesize); + + if (strcmp((void *)fptr + sizeof(cpio_t), file_name) == 0) { + memcpy(file_buf, (void *)fptr + headsize, filesize); + } + + fptr += headsize + datasize; + } +} + +unsigned long ramfs_get_file_size(const char *file_name) { + uint8_t *fptr = (uint8_t *)ramfs_base; // for 8 byte alignment + while (strcmp((void *)fptr + sizeof(cpio_t), "TRAILER!!!")) { + cpio_t *header = (cpio_t *)fptr; + uint32_t namesize = hextoi(header->c_namesize, 8); + uint32_t filesize = hextoi(header->c_filesize, 8); + uint32_t headsize = align4(sizeof(cpio_t) + namesize); + uint32_t datasize = align4(filesize); + if (strcmp((void *)fptr + sizeof(cpio_t), file_name) == 0) { + return filesize; + } + fptr += headsize + datasize; + } + return 0; +} + +static int hextoi(char *s, int n) { + int r = 0; + while (n-- > 0) { + r = r << 4; + if (*s >= 'A') + r += *s++ - 'A' + 10; + else if (*s >= '0') + r += *s++ - '0'; + } + return r; +} diff --git a/lab7/bsp/ramfs.h b/lab7/bsp/ramfs.h new file mode 100644 index 000000000..95ba748d8 --- /dev/null +++ b/lab7/bsp/ramfs.h @@ -0,0 +1,41 @@ +#ifndef _RAMFS_H +#define _RAMFS_H + +#include +#include + +typedef struct cpio_newc_header { + char c_magic[6]; // The string 070701 for new ASCII + 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]; // must be 0 for FIFOs and directories + char c_devmajor[8]; + char c_devminor[8]; + char c_rdevmajor[8]; + char c_rdevminor[8]; + char c_namesize[8]; // count includes terminating NUL in pathname + char c_check[8]; // 0 for "new" portable format; for CRC format the sum of + // all the bytes in the file +} cpio_t; + +#define MAX_FILES 100 // 預設的最大檔案數量 +#define MAX_FILENAME_LENGTH 256 // 每個檔案名稱的最大長度 + +typedef struct { + char file_names[MAX_FILES][MAX_FILENAME_LENGTH]; + unsigned long file_sizes[MAX_FILES]; + int file_count; + char* file_data[MAX_FILES]; +} file_list_t; + +void init_ramfs_callback(void *base_addr); +file_list_t *ramfs_get_file_list(); +unsigned long ramfs_get_file_size(const char *file_name); +void ramfs_get_file_contents(const char *file_name, char *buffer); +void ramfs_execute_file(const char *file_name); + +#endif diff --git a/lab7/bsp/reboot.c b/lab7/bsp/reboot.c new file mode 100644 index 000000000..43b575bec --- /dev/null +++ b/lab7/bsp/reboot.c @@ -0,0 +1,20 @@ +#include + +#define PM_PASSWORD 0x5a000000 +#define PM_RSTC 0x3F10001c +#define PM_WDOG 0x3F100024 + +void set(long addr, unsigned int value) { + volatile unsigned int *point = (unsigned int *)addr; + *point = value; +} + +void reset(int tick) { // reboot after watchdog timer expire + set(PM_RSTC, PM_PASSWORD | 0x20); // full reset + set(PM_WDOG, PM_PASSWORD | tick); // number of watchdog tick +} + +void cancel_reset() { + set(PM_RSTC, PM_PASSWORD | 0); // full reset + set(PM_WDOG, PM_PASSWORD | 0); // number of watchdog tick +} diff --git a/lab7/bsp/reboot.h b/lab7/bsp/reboot.h new file mode 100644 index 000000000..8522085c8 --- /dev/null +++ b/lab7/bsp/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 diff --git a/lab7/bsp/sched.S b/lab7/bsp/sched.S new file mode 100644 index 000000000..323fe3998 --- /dev/null +++ b/lab7/bsp/sched.S @@ -0,0 +1,26 @@ +.global switch_to +switch_to: + stp x19, x20, [x0, 16 * 0] + stp x21, x22, [x0, 16 * 1] + stp x23, x24, [x0, 16 * 2] + stp x25, x26, [x0, 16 * 3] + stp x27, x28, [x0, 16 * 4] + stp fp, lr, [x0, 16 * 5] + mov x9, sp + str x9, [x0, 16 * 6] + + ldp x19, x20, [x1, 16 * 0] + ldp x21, x22, [x1, 16 * 1] + ldp x23, x24, [x1, 16 * 2] + ldp x25, x26, [x1, 16 * 3] + ldp x27, x28, [x1, 16 * 4] + ldp fp, lr, [x1, 16 * 5] + ldr x9, [x1, 16 * 6] + mov sp, x9 + msr tpidr_el1, x1 + ret + +.global get_current +get_current: + mrs x0, tpidr_el1 + ret diff --git a/lab7/bsp/start.S b/lab7/bsp/start.S new file mode 100644 index 000000000..8ea5717eb --- /dev/null +++ b/lab7/bsp/start.S @@ -0,0 +1,63 @@ +.section ".data" +.global dtb_base +dtb_base: .word 0 + +.section ".text.boot" + +.global _start + +_start: + // store dtb base address from x0 to dtb_base + ldr x1, =dtb_base + str x0, [x1] + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, boot + // cpu id > 0, stop + +proc_hang: + wfe + b proc_hang + +boot: + // set exception levels to EL1, where the kernel will run + bl from_el2_to_el1 // from exception.S + // set exception vector table + bl set_exception_vector_table // from exception.S + +bss_init: + // cpu id == 0 + // set top of stack just before our code (stack grows to a lower address per AAPCS64) + ldr x1, =_start + mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size + +bss_clear: + cbz w2, jump_main + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, bss_clear + + // jump to C code, should not return +jump_main: + bl main + // for failsafe, halt this core too + b proc_hang + + +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) diff --git a/lab7/bsp/sysregs.h b/lab7/bsp/sysregs.h new file mode 100644 index 000000000..2e691f2c1 --- /dev/null +++ b/lab7/bsp/sysregs.h @@ -0,0 +1,11 @@ +#ifndef _SYSREGS_H +#define _SYSREGS_H + +// *************************************** +// ESR_EL1, Exception Syndrome Register (EL1). Page 2431 of AArch64-Reference-Manual. +// *************************************** + +#define ESR_ELx_EC_SHIFT 26 +#define ESR_ELx_EC_SVC64 0x15 + +#endif diff --git a/lab7/bsp/timer.c b/lab7/bsp/timer.c new file mode 100644 index 000000000..811b30d18 --- /dev/null +++ b/lab7/bsp/timer.c @@ -0,0 +1,47 @@ +#include +#include + +void core_timer_enable() { +#ifdef TIMER_DEBUG + puts("\n[core_timer_enable] "); +#endif + asm volatile( + "mov x0, 1;" + "msr cntp_ctl_el0, x0;" // Enable + "mrs x0, cntfrq_el0;" + // "lsr x0, x0, #5;" + "msr cntp_tval_el0, x0;" // Set expired time + "mov x0, 2;" + "ldr x1, =0x40000040;" // timer interrupt control register for core 0 + "str w0, [x1];"); // Unmask timer interrupt + + asm volatile( + "mrs x0, cntkctl_el1;" + "orr x0, x0, 1;" + "msr cntkctl_el1, x0;"); +} + +void core_timer_disable() { +#ifdef TIMER_DEBUG + puts("\n[core_timer_disable] "); +#endif + asm volatile( + "mov x0, 0;" + "msr cntp_ctl_el0, x0;" // disable + ); +} + +uint64_t timer_get_uptime() { + uint64_t cntpct_el0 = 0; + uint64_t cntfrq_el0 = 0; + asm volatile("mrs %0, cntpct_el0" : "=r"(cntpct_el0)); + asm volatile("mrs %0, cntfrq_el0" : "=r"(cntfrq_el0)); + return cntpct_el0 / cntfrq_el0; +} + +void enable_user_to_physical_timer() { + asm volatile( + "mrs x0, cntkctl_el1;" + "orr x0, x0, 1;" + "msr cntkctl_el1, x0;"); +} diff --git a/lab7/bsp/traps.h b/lab7/bsp/traps.h new file mode 100644 index 000000000..0b6650e75 --- /dev/null +++ b/lab7/bsp/traps.h @@ -0,0 +1,41 @@ +#ifndef TRAPS_H +#define TRAPS_H + +typedef struct trap_frame { + unsigned long x0; + unsigned long x1; + unsigned long x2; + unsigned long x3; + unsigned long x4; + unsigned long x5; + unsigned long x6; + unsigned long x7; + unsigned long x8; + unsigned long x9; + unsigned long x10; + unsigned long x11; + unsigned long x12; + unsigned long x13; + unsigned long x14; + unsigned long x15; + unsigned long x16; + unsigned long x17; + unsigned long x18; + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long x29; + unsigned long x30; + unsigned long spsr_el1; + unsigned long elr_el1; + unsigned long sp_el0; +} trap_frame; + +#endif diff --git a/lab7/bsp/uart.c b/lab7/bsp/uart.c new file mode 100644 index 000000000..b8ddbb28c --- /dev/null +++ b/lab7/bsp/uart.c @@ -0,0 +1,171 @@ +#include +#include + +#include // for enable uart irq +#include + +#define AUX_ENABLE ((volatile unsigned int *)(MMIO_BASE + 0x00215004)) +#define AUX_MU_IO ((volatile unsigned int *)(MMIO_BASE + 0x00215040)) +#define AUX_MU_IER ((volatile unsigned int *)(MMIO_BASE + 0x00215044)) +#define AUX_MU_IIR ((volatile unsigned int *)(MMIO_BASE + 0x00215048)) +#define AUX_MU_LCR ((volatile unsigned int *)(MMIO_BASE + 0x0021504C)) +#define AUX_MU_MCR ((volatile unsigned int *)(MMIO_BASE + 0x00215050)) +#define AUX_MU_LSR ((volatile unsigned int *)(MMIO_BASE + 0x00215054)) +#define AUX_MU_MSR ((volatile unsigned int *)(MMIO_BASE + 0x00215058)) +#define AUX_MU_SCRATCH ((volatile unsigned int *)(MMIO_BASE + 0x0021505C)) +#define AUX_MU_CNTL ((volatile unsigned int *)(MMIO_BASE + 0x00215060)) +#define AUX_MU_STAT ((volatile unsigned int *)(MMIO_BASE + 0x00215064)) +#define AUX_MU_BAUD ((volatile unsigned int *)(MMIO_BASE + 0x00215068)) + +void uart_init() { + register unsigned int r; + + /* initialize UART */ + *AUX_ENABLE |= 1; // Enable mini UART0x01 + *AUX_MU_CNTL = 0; // Disable TX, RX during configuration + *AUX_MU_IER = 0; // Disable interrupt + *AUX_MU_LCR = 3; // Set the data size to 8 bit + *AUX_MU_MCR = 0; // Don't need auto flow control + *AUX_MU_BAUD = 270; // Set baud rate to 115200 + *AUX_MU_IIR = 6; // No FIFO + + /* map UART1 to GPIO pins */ + r = *GPFSEL1; + r &= ~((7 << 12) | (7 << 15)); // gpio14, gpio15 innitial + r |= (2 << 12) | (2 << 15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 + r = 150; + while (r--) { + asm volatile("nop"); + } + *GPPUDCLK0 = (1 << 14) | (1 << 15); + r = 150; + while (r--) { + asm volatile("nop"); + } + *GPPUDCLK0 = 0; // flush GPIO setup + *AUX_MU_CNTL = 3; // enable Tx, Rx // bit1:transmitter bit0:receiver + + // *ENABLE_IRQS_1 |= (1 << 29); +} + +void uart_send(unsigned int c) { + do { + asm volatile("nop"); + } while (!(*AUX_MU_LSR & 0x20)); // This bit is set if the transmit FIFO + // can accept at least one byte. + /* write the character to the buffer */ + *AUX_MU_IO = c; +} + +char uart_recv() { + do { + asm volatile("nop"); + } while (!(*AUX_MU_LSR & 0x01)); // This bit is set if the receive FIFO + // holds at least 1 symbol. + return (char)(*AUX_MU_IO); +} + +char uart_getc() { + char r; + do { + asm volatile("nop"); + } while (!( + *AUX_MU_LSR & + 0x01)); // This bit is set if the receive FIFO holds at least 1 symbol. + + r = (char)(*AUX_MU_IO); + // convert carrige return to newline + return r == '\r' ? '\n' : r; +} + +void uart_puts(const char *s) { + while (*s) { + /* convert newline to carrige return + newline */ + if (*s == '\n') uart_send('\r'); + uart_send(*s++); + } +} + +void uart_hex(unsigned long long int d) { + uart_puts("0x"); + unsigned int n; + int c; + for (c = 28; c >= 0; c -= 4) { + // get highest tetrad + n = (d >> c) & 0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n += n > 9 ? 0x37 : 0x30; + uart_send(n); + } +} + +void uart_enable_tx_interrupt() { +#ifdef IRQ_DEBUG + uart_puts("[INFO] enable tx interrupt\n"); +#endif /* ifdef IRQ_DEBUG */ + + *AUX_MU_IER |= (1 << 1); +} + +void uart_disable_tx_interrupt() { +#ifdef IRQ_DEBUG + uart_puts("[INFO] disable tx interrupt\n"); +#endif /* ifdef IRQ_DEBUG */ + *AUX_MU_IER &= ~(1 << 1); +} + +void uart_enable_rx_interrupt() { +#ifdef IRQ_DEBUG + uart_puts("[INFO] enable rx interrupt\n"); +#endif /* ifdef IRQ_DEBUG */ + *AUX_MU_IER |= (1 << 0); +} + +void uart_disable_rx_interrupt() { +#ifdef IRQ_DEBUG + uart_puts("[INFO] disable rx interrupt\n"); +#endif /* ifdef IRQ_DEBUG */ + *AUX_MU_IER &= ~(1 << 0); +} + +#define UART_BUF_SIZE 2048 +static char write_buffer[UART_BUF_SIZE]; +static char read_buffer[UART_BUF_SIZE]; +static int write_idx = 0, write_end = 0; +static int read_idx = 0; + +void uart_rx_irq_handler() { + char c = (char)(*AUX_MU_IO); + read_buffer[read_idx++] = c == '\r' ? '\n' : c; + read_buffer[read_idx] = '\0'; + if (read_idx >= UART_BUF_SIZE) read_idx = 0; + uart_enable_rx_interrupt(); +} + +void uart_tx_irq_handler() { + uart_disable_tx_interrupt(); + if (write_idx != write_end && write_buffer[write_idx] != '\0') { + *AUX_MU_IO = write_buffer[write_idx]; + write_idx = (write_idx + 1) % UART_BUF_SIZE; + uart_enable_tx_interrupt(); + } +} + +void uart_async_read(char *buf) { + uart_disable_rx_interrupt(); + strncpy(buf, read_buffer, read_idx); + buf[read_idx] = '\0'; + read_idx = 0; +} + +void uart_async_write(const char *s) { + // append string to write buffer + while (*s) { + write_buffer[write_end] = *s++; + write_end = (write_end + 1) % UART_BUF_SIZE; + } + write_buffer[write_end] = '\0'; + uart_enable_tx_interrupt(); +} diff --git a/lab7/bsp/uart.h b/lab7/bsp/uart.h new file mode 100644 index 000000000..4e7813532 --- /dev/null +++ b/lab7/bsp/uart.h @@ -0,0 +1,20 @@ +#ifndef _UART_H +#define _UART_H + +void uart_init(); +void uart_send(unsigned int c); +char uart_getc(); +char uart_recv(); +void uart_puts(const char *s); +void uart_hex(unsigned long long d); + +void uart_enable_tx_interrupt(); +void uart_disable_tx_interrupt(); +void uart_enable_rx_interrupt(); +void uart_disable_rx_interrupt(); +void uart_tx_irq_handler(); +void uart_rx_irq_handler(); +void uart_async_read(char *buf); +void uart_async_write(const char *s); + +#endif diff --git a/lab7/bsp/utils.c b/lab7/bsp/utils.c new file mode 100644 index 000000000..373780081 --- /dev/null +++ b/lab7/bsp/utils.c @@ -0,0 +1,57 @@ +#include +#include + +#include + +uint32_t get_irq() { return *CORE0_IRQ_SOURCE; } + +uint32_t is_core_timer_irq() { + // uart_puts("\nCORE0_IRQ_SOURCE: "); + // uart_hex((unsigned long)*CORE0_IRQ_SOURCE); + // uart_puts("\n"); + // uart_puts("Timer IRQ: "); + // uart_hex((unsigned long)(1 << 1)); + // uart_puts("\n"); + return *CORE0_IRQ_SOURCE == (1 << 1); +} + +uint32_t is_gpu_irq() { + // uart_puts("\nCORE0_IRQ_SOURCE: "); + // uart_hex((unsigned long)*CORE0_IRQ_SOURCE); + // uart_puts("\n"); + // uart_puts("GPU IRQ: "); + // uart_hex((unsigned long)(1 << 8)); + // uart_puts("\n"); + return *CORE0_IRQ_SOURCE == (1 << 8); +} + +static const char *entry_error_messages[] = { + "SYNC_INVALID_EL1t", "IRQ_INVALID_EL1t", "FIQ_INVALID_EL1t", + "ERROR_INVALID_EL1T", + + "SYNC_INVALID_EL1h", "IRQ_INVALID_EL1h", "FIQ_INVALID_EL1h", + "ERROR_INVALID_EL1h", + + "SYNC_INVALID_EL0_64", "IRQ_INVALID_EL0_64", "FIQ_INVALID_EL0_64", + "ERROR_INVALID_EL0_64", + + "SYNC_INVALID_EL0_32", "IRQ_INVALID_EL0_32", "FIQ_INVALID_EL0_32", + "ERROR_INVALID_EL0_32", "SYNC_ERROR", "SYSCALL_ERROR"}; + +const char *get_exception_message(unsigned long type) { + return entry_error_messages[type]; +} + +void enable_irq() { + // Clear the D, A, I, F bits in the DAIF register + // to enable interrupts + // uart_puts("\n[enable_irq]\n"); + asm volatile("msr daifclr, 0xf;"); +} + +void disable_irq() { + // Set 1 to the D, A, I, F bits in the DAIF register + // to disable interrupts + // uart_puts("\n[disable_irq]\n"); + asm volatile("msr daifset, 0xf;"); +} diff --git a/lab7/config.txt b/lab7/config.txt new file mode 100644 index 000000000..80c90a4ec --- /dev/null +++ b/lab7/config.txt @@ -0,0 +1 @@ +initramfs initramfs.cpio 0x20000000 diff --git a/lab7/file_sender.py b/lab7/file_sender.py new file mode 100644 index 000000000..39d7e57bc --- /dev/null +++ b/lab7/file_sender.py @@ -0,0 +1,25 @@ +import serial +import time +import sys + +kernel_image_path = "build/kernel8.img" + +dev_name = sys.argv[1] +ser = serial.Serial(dev_name, 115200, timeout=1) + +input("Press any button to continue...") + +with open(kernel_image_path, "rb") as f: + kernel_image = f.read() + +kernel_size = len(kernel_image) +print(f"Sending kernel size: {kernel_size} bytes") +ser.write(f"{kernel_size}\n".encode()) + +time.sleep(1) + +print("Sending kernel image...") +ser.write(kernel_image) + +ser.close() +print("Kernel image sent.") diff --git a/lab7/initramfs.cpio b/lab7/initramfs.cpio new file mode 100644 index 0000000000000000000000000000000000000000..68a0ab3c75f8c1480f3da9d546a4c26abc4256eb GIT binary patch literal 903168 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 z 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≧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 CWQ~{r literal 0 HcmV?d00001 diff --git a/lab7/kernel/Makefile b/lab7/kernel/Makefile new file mode 100644 index 000000000..0fe7df059 --- /dev/null +++ b/lab7/kernel/Makefile @@ -0,0 +1,48 @@ +CFLAGS = -Wall -ffreestanding -nostdinc -nostdlib -nostartfiles -fno-stack-protector -g -mgeneral-regs-only +C = aarch64-linux-gnu + +INCLUDE_PATH ?= ../ +BUILD_DIR ?= build +CFLAGS += -I$(INCLUDE_PATH) + +LIB_PATH ?= ../lib +BSP_PATH ?= ../bsp +LIB_SRCS = $(shell find $(LIB_PATH) -type f -name '*.c') +BSP_SRCS = $(shell find $(BSP_PATH) -type f -name '*.c') +BSP_ASM_SRCS = $(shell find $(BSP_PATH) -type f -name '*.S') + +LOCAL_SRCS = $(shell find . -type f -name '*.c') +SRCS = $(LOCAL_SRCS) $(LIB_SRCS) $(BSP_SRCS) +OBJS = $(patsubst ./%.c,$(BUILD_DIR)/obj/%.o,$(LOCAL_SRCS)) \ + $(patsubst $(LIB_PATH)/%.c,$(BUILD_DIR)/obj/lib/%.o,$(LIB_SRCS)) \ + $(patsubst $(BSP_PATH)/%.c,$(BUILD_DIR)/obj/bsp/%.o,$(BSP_SRCS)) \ + $(patsubst $(BSP_PATH)/%.S,$(BUILD_DIR)/obj/bsp/%_s.o,$(BSP_ASM_SRCS)) + +QEMU_OPTS ?= + +ifeq ($(DEBUG), 1) +CFLAGS += -DDEBUG +endif + +all: kernel8.img + +$(BUILD_DIR)/obj/%.o: %.c + mkdir -p $(dir $@) + $(C)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/obj/lib/%.o: $(LIB_PATH)/%.c + mkdir -p $(dir $@) + $(C)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/obj/bsp/%.o: $(BSP_PATH)/%.c + mkdir -p $(dir $@) + $(C)-gcc $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/obj/bsp/%_s.o: $(BSP_PATH)/%.S + mkdir -p $(dir $@) + $(C)-gcc $(CFLAGS) -c $< -o $@ + +kernel8.img: $(OBJS) + $(C)-ld -nostdlib $^ -T $(BSP_PATH)/linker.ld -o $(BUILD_DIR)/kernel8.elf + $(C)-objcopy -O binary $(BUILD_DIR)/kernel8.elf $(BUILD_DIR)/kernel8.img + diff --git a/lab7/kernel/buddy.c b/lab7/kernel/buddy.c new file mode 100644 index 000000000..57a101185 --- /dev/null +++ b/lab7/kernel/buddy.c @@ -0,0 +1,269 @@ +#include "io.h" +#include "memory.h" + +#include "mm.h" + +static page_t *mem_map; +static page_t *free_areas[MAX_ORDER + 1]; + +static inline void __push_page(page_t **head, page_t *page) { + if (*head == NULL) { + *head = page; + return; + } + + page->next = *head; + (*head)->prev = page; + *head = page; +} + +static inline page_t *__pop_page(page_t **head) { + if (*head == NULL) { + return NULL; + } + page_t *page = *head; + + *head = page->next; + page->next = NULL; + + if (*head) { // unlink the head + (*head)->prev = NULL; + } + return page; +} + +static inline void __remove_page(page_t **head, page_t *page) { + if (page->prev) { + page->prev->next = page->next; + } else { + *head = page->next; + } + + if (page->next) { + page->next->prev = page->prev; + } +} + +void buddy_init(phys_addr_t start, phys_addr_t end) { + uintptr_t buddy_size = (uintptr_t)end - (uintptr_t)start; + +#ifdef MEM_DEBUG + puts("Buddy size: "); + print_d(buddy_size); + puts("\nFrom "); + print_h((uint64_t)start); + puts(" to "); + print_h((uint64_t)end); + puts("\n"); +#endif + + // split the memory into max order pages and add them to free areas + for (int i = 0; i <= MAX_ORDER; i++) { + free_areas[i] = NULL; + } + + int num_of_pages = buddy_size / PAGE_SIZE; + +#ifdef MEM_DEBUG + puts("Number of pages: "); + print_d(num_of_pages); + puts("\n"); +#endif + + mem_map = simple_malloc(num_of_pages * sizeof(page_t)); + + if (mem_map == NULL) { + puts("Failed to allocate memory for mem_map\n"); + return; + } + + for (int i = num_of_pages - 1; i >= 0; i--) { + mem_map[i].order = MAX_ORDER; + mem_map[i].status = PAGE_FREE; + mem_map[i].prev = NULL; + mem_map[i].next = NULL; + + if (i % (1 << MAX_ORDER) == + 0) { // push the chunk of page to the free area + __push_page(&free_areas[MAX_ORDER], &mem_map[i]); + } + } + +#ifdef MEM_DEBUG + print_free_areas(); +#endif +} + +page_t *alloc_pages(unsigned long order) { + unsigned long cur_order; + for (cur_order = order; cur_order <= MAX_ORDER; cur_order++) { + if (free_areas[cur_order]) { + page_t *page = __pop_page(&free_areas[cur_order]); + + // split the page into smaller pages + while (cur_order > order) { + cur_order--; + uint32_t buddy_pfn = (page - mem_map) ^ (1 << cur_order); + page_t *buddy = &mem_map[buddy_pfn]; + buddy->order = cur_order; + __push_page(&free_areas[cur_order], buddy); + } + + page->order = order; + page->status = PAGE_ALLOCATED; + return page; + } + } + return NULL; // 沒有可用記憶體 +} + +void free_pages(page_t *page, unsigned long order) { + int cur_order = order; + for (; cur_order < MAX_ORDER; cur_order++) { + uint32_t buddy_pfn = (page - mem_map) ^ (1 << cur_order); + page_t *buddy = &mem_map[buddy_pfn]; + + // puts("\ni: "); + // print_d(cur_order); + // puts("----------\n"); + // puts("Page: "); + // print_h((uint64_t)get_addr_by_page(page)); + // puts("\nBuddy: "); + // print_h((uint64_t)get_addr_by_page(buddy)); + // puts("\nbuddy_order: "); + // print_d(buddy->order); + // puts("\nbuddy_status: "); + // print_d(buddy->status); + + if (buddy->order != cur_order || buddy->status != PAGE_FREE) { + break; + } + + __remove_page(&free_areas[cur_order], buddy); + page = (page < buddy) + ? page + : buddy; // update the page pointer to the lower address + } + + page->status = PAGE_FREE; + page->order = cur_order; + // puts("\nPush page: "); + // print_h((uint64_t)get_addr_by_page(page)); + // puts("\nTo order "); + // print_d(cur_order); + // puts("\n"); + __push_page(&free_areas[cur_order], page); +} + +void print_free_areas() { + for (int i = 0; i <= MAX_ORDER; i++) { + page_t *page = free_areas[i]; + puts("Order "); + print_d(i); + puts(": "); + while (page) { + print_h((uint64_t)get_addr_by_page(page)); + puts(" -> "); + page = page->next; + } + puts("NULL\n"); + } +} + +phys_addr_t get_addr_by_page(page_t *page) { + // puts("Get addr by page: "); + // print_h((uint64_t)(((page - mem_map) << PAGE_SHIFT) + (void *)start)); + // puts("\n"); + return (phys_addr_t)((page - mem_map) << PAGE_SHIFT); +} + +page_t *get_page_by_addr(phys_addr_t addr) { + // puts("Get page by addr: "); + // print_h((uint64_t)&mem_map[(addr - start) >> PAGE_SHIFT]); + return &mem_map[(uint64_t)(void *)addr >> PAGE_SHIFT]; +} + +void memory_reserve(phys_addr_t start, phys_addr_t end) { + puts("Reserve memory: "); + print_h((uint64_t)start); + puts(" - "); + print_h((uint64_t)end); + puts("\n"); + + for (int cur_order = MAX_ORDER; cur_order >= 0; cur_order--) { + page_t *page = free_areas[cur_order]; + while (page != NULL) { + page_t *next_page = page->next; + + phys_addr_t page_addr = get_addr_by_page(page); + phys_addr_t page_end = + page_addr + (1 << (cur_order + PAGE_SHIFT)) - 1; + + if (cur_order == 0) { + if (!(page_end < start || page_addr > end)) { +#ifdef MEM_DEBUG + puts("\nPage partially reserved\n"); +#endif + page->status = PAGE_RESERVED; + __remove_page(&free_areas[cur_order], page); + } + } else if (page_addr >= start && page_end <= end) { +#ifdef MEM_DEBUG + puts("\nPage fully reserved\n"); + print_h((uint64_t)page_addr); + puts(" - "); + print_h((uint64_t)page_end); + puts("\n"); +#endif + + page->status = PAGE_RESERVED; + __remove_page(&free_areas[cur_order], page); + } else if (start > page_end || + end < page_addr) { // page out of range + // puts("\nPage out of range\n"); + } else { // split the overlapping page using buddy + // puts("\nFind buddy\n"); + // puts("\nPage: "); + // print_h((uint64_t)page_addr); + // puts("\n"); + // puts("\nCur order: "); + // print_d(cur_order); + // puts("\n"); + + uint32_t buddy_pfn = (page - mem_map) ^ (1 << (cur_order - 1)); + page_t *buddy = &mem_map[buddy_pfn]; + +#ifdef MEM_DEBUG + puts("Split page: "); + print_h((uint64_t)page_addr); + puts(", "); + print_h((uint64_t)get_addr_by_page(buddy)); + puts(", "); + print_h((uint64_t)buddy_pfn); + puts("\n"); +#endif + +// remove the original page from the free area +#ifdef MEM_DEBUG + puts("\nRemove page "); + print_h((uint64_t)get_addr_by_page(page)); + puts(" from order "); + print_d(cur_order); + puts("\n"); +#endif + __remove_page(&free_areas[cur_order], page); + buddy->order = cur_order - 1; + page->order = cur_order - 1; + page->prev = NULL; + // push split page to the free area + __push_page(&free_areas[cur_order - 1], buddy); + __push_page(&free_areas[cur_order - 1], page); + } + + // puts("\nNext page\n"); + // print_h((uint64_t)get_addr_by_page(next_page)); + + page = next_page; + } + } +} diff --git a/lab7/kernel/commands.h b/lab7/kernel/commands.h new file mode 100644 index 000000000..bd49b9491 --- /dev/null +++ b/lab7/kernel/commands.h @@ -0,0 +1,31 @@ +#ifndef _COMMAND_H_ +#define _COMMAND_H_ + +typedef struct command { + char name[16]; + char description[64]; + void (*function)(int argc, char **argv); +} command_t; + +extern command_t hello_command; +extern command_t mailbox_command; +extern command_t reboot_command; +extern command_t ls_command; +extern command_t cat_command; +extern command_t test_malloc_command; +extern command_t async_io_demo_command; +extern command_t exec_command; +extern command_t set_timeout_command; +extern command_t test_kmalloc_command; +extern command_t test_kfree_command; +extern command_t test_multi_thread_command; +extern command_t test_thread_command; + +extern command_t rootfs_ls_command; +extern command_t rootfs_cat_command; +extern command_t rootfs_mkdir_command; +extern command_t rootfs_cd_command; +extern command_t rootfs_cwd_command; +extern command_t rootfs_touch_command; + +#endif diff --git a/lab7/kernel/commands/async_io.c b/lab7/kernel/commands/async_io.c new file mode 100644 index 000000000..fb1bdb593 --- /dev/null +++ b/lab7/kernel/commands/async_io.c @@ -0,0 +1,39 @@ + +#include +#include +#include + +void _async_io_demo(int argc, char **argv) { + uart_enable_rx_interrupt(); + char command[256]; + + while (1) { + uart_async_write("\r\n(async) > "); + + while (command[strlen(command) - 1] != + '\n') { // wait for enter and keep reading from buffer + for (int i = 0; i < 2000000; i++) { + // delay + } + int current_len = strlen(command); + uart_async_read(command + current_len); + uart_async_write(command + current_len); + uart_enable_rx_interrupt(); + } + command[strlen(command) - 1] = '\0'; // delete last \n + if (strcmp(command, "exit") == 0) { + break; + } + command[0] = '\0'; + } + + uart_disable_tx_interrupt(); + + // TODO: find out why I should clear the buffer... + uart_async_read(command); +} + +command_t async_io_demo_command = { + .name = "async_io", + .description = "demo async IO functions", + .function = &_async_io_demo}; diff --git a/lab7/kernel/commands/exec.c b/lab7/kernel/commands/exec.c new file mode 100644 index 000000000..cb28d25c4 --- /dev/null +++ b/lab7/kernel/commands/exec.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +void _exec_command(int argc, char **argv) { + if (argc < 2) { + puts("\nUsage: exec "); + return; + } + + char *file_name = argv[1]; + unsigned long file_size = ramfs_get_file_size(file_name); + char *file_contents = kmalloc(file_size); + ramfs_get_file_contents(file_name, file_contents); + + if (file_contents == NULL) { + puts("[ERROR] File not found: "); + puts(file_name); + puts("\n"); + return; + } + puts("\n[INFO] Executing file: "); + puts(file_name); + puts("\n"); + + char *user_program = kmalloc(file_size); + memcpy(user_program, file_contents, file_size); + enable_user_to_physical_timer(); + struct task_struct *task = kthread_create((void *)user_program); + asm volatile("msr tpidr_el1, %0;" ::"r"(task)); + asm volatile("msr spsr_el1, %0" ::"r"(0x0)); + asm volatile("msr elr_el1, %0" ::"r"(task->context.lr)); + asm volatile("msr sp_el0, %0" ::"r"(task->user_stack + STACK_SIZE)); + asm volatile("mov sp, %0" ::"r"(task->stack + STACK_SIZE)); + asm volatile("eret"); + + // char buf[100]; + // sprintf(buf, "User program pointer: %x\n", user_program); + // puts(buf); + + // preempt_disable(); + // get_current()->state = TASK_STOPPED; + // puts("Enabling user to physical timer\n"); + // enable_user_to_physical_timer(); + // puts("Copying process\n"); + // copy_process(PF_KTHREAD, (unsigned long)&move_to_user_mode, (unsigned + // long)user_program, 0); preempt_enable(); +} + +command_t exec_command = {.name = "exec", + .description = "execute a user program", + .function = &_exec_command}; diff --git a/lab7/kernel/commands/hello.c b/lab7/kernel/commands/hello.c new file mode 100644 index 000000000..4e698c1ab --- /dev/null +++ b/lab7/kernel/commands/hello.c @@ -0,0 +1,8 @@ +#include +#include + +void _hello_command(int argc, char **argv) { puts("\nHello World!"); } + +command_t hello_command = {.name = "hello", + .description = "print Hello World!", + .function = &_hello_command}; diff --git a/lab7/kernel/commands/mailbox.c b/lab7/kernel/commands/mailbox.c new file mode 100644 index 000000000..8c1564887 --- /dev/null +++ b/lab7/kernel/commands/mailbox.c @@ -0,0 +1,23 @@ +#include +#include +#include + +void _mailbox_command(int argc, char **argv) { + puts("\nMailbox info :\n"); + unsigned int r = get_board_revision(); + puts("board revision : "); + print_h(r); + puts("\r\n"); + unsigned int base_addr, size; + get_memory_info(&base_addr, &size); + puts("ARM memory base address : "); + print_h(base_addr); + puts("\r\n"); + puts("ARM memory size : "); + print_h(size); + puts("\r\n"); +} + +command_t mailbox_command = {.name = "mailbox", + .description = "print hardware info", + .function = &_mailbox_command}; diff --git a/lab7/kernel/commands/memory.c b/lab7/kernel/commands/memory.c new file mode 100644 index 000000000..2fae34175 --- /dev/null +++ b/lab7/kernel/commands/memory.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include + +void _test_malloc_command(int argc, char **argv) { + puts("\nMalloc size: "); + unsigned int size = 0; + while (1) { + char c = read_c(); + if (c == '\n') { + break; + } + size = size * 10 + (c - '0'); + print_char(c); + } + void *ptr = simple_malloc(size); + if (ptr == 0) { + puts("\nMalloc failed! "); + } + + puts("\nMalloc address: "); + print_h((uintptr_t)ptr); + puts("\n"); +} + +command_t test_malloc_command = {.name = "test_malloc", + .description = "test malloc", + .function = &_test_malloc_command}; + +void _test_kmalloc_comand(int argc, char **argv) { + if (argc != 2) { + puts("\nUsage: test_kmalloc \n"); + return; + } + + int size = atoi(argv[1]); + puts("\nMalloc size: "); + puts(argv[1]); + void *ptr = kmalloc(size); + if (ptr == 0) { + puts("\nMalloc failed! "); + } + puts("\nMalloc address: "); + print_h((uint64_t)ptr); + puts(", "); + print_d((uint64_t)ptr); + puts("\n"); + + // print_kmalloc_caches(); + // print_free_areas(); +} + +command_t test_kmalloc_command = {.name = "test_kmalloc", + .description = "test kmalloc", + .function = &_test_kmalloc_comand}; + +void _test_kfree_command(int argc, char **argv) { + if (argc != 2) { + puts("\nUsage: test_kfree
\n"); + return; + } + uintptr_t addr = atoi(argv[1]); + kfree((void *)addr); + puts("\nFree address: "); + print_h(addr); + puts("\n"); + print_free_areas(); +} + +command_t test_kfree_command = {.name = "test_kfree", + .description = "test kfree", + .function = &_test_kfree_command}; diff --git a/lab7/kernel/commands/multi_thread.c b/lab7/kernel/commands/multi_thread.c new file mode 100644 index 000000000..5ab926e9a --- /dev/null +++ b/lab7/kernel/commands/multi_thread.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include +#include + +void tt() { + for (int i = 0; i < 3; i++) + kthread_create(thread_test); + idle(); +} + +command_t test_thread_command = { + .name = "thread", + .description = "demo thread user program", + .function = &tt, +}; + +void entry() { + kthread_create(run_fork_test); + idle(); +} + +command_t test_multi_thread_command = { + .name = "multi_thread", + .description = "demo multi-thread user program", + .function = &entry, +}; diff --git a/lab7/kernel/commands/ramfs.c b/lab7/kernel/commands/ramfs.c new file mode 100644 index 000000000..0b9a3499a --- /dev/null +++ b/lab7/kernel/commands/ramfs.c @@ -0,0 +1,49 @@ + +#include +#include +#include +#include +#include +#include +#include + +void _ls_command(int argc, char **argv) { + file_list_t *file_list = ramfs_get_file_list(); + for (int i = 0; i < file_list->file_count; i++) { + puts("\n"); + puts(file_list->file_names[i]); + puts(" "); + print_d(file_list->file_sizes[i]); + puts(" bytes"); + } + puts("\n"); +} + +command_t ls_command = {.name = "ls", + .description = "list the files in ramfs", + .function = &_ls_command}; + +void _cat_command(int argc, char **argv) { + if (argc < 2) { + puts("\nUsage: cat \n"); + return; + } + char *file_name = argv[1]; + + unsigned long file_size = ramfs_get_file_size(file_name); + char *file_contents = kmalloc(file_size); + ramfs_get_file_contents(file_name, file_contents); + + if (file_contents) { + puts("\n"); + for (int i = 0; i < file_size - 1; i++) { + print_char(file_contents[i]); + } + } else { + puts("\nFile not found\n"); + } +} + +command_t cat_command = {.name = "cat", + .description = "print the contents of a file", + .function = &_cat_command}; diff --git a/lab7/kernel/commands/reboot.c b/lab7/kernel/commands/reboot.c new file mode 100644 index 000000000..9894b0a82 --- /dev/null +++ b/lab7/kernel/commands/reboot.c @@ -0,0 +1,12 @@ +#include +#include +#include + +void _reboot_command(int argc, char **argv) { + puts("\nRebooting ...\n"); + reset(200); +} + +command_t reboot_command = {.name = "reboot", + .description = "reboot the device", + .function = &_reboot_command}; diff --git a/lab7/kernel/commands/rootfs.c.old b/lab7/kernel/commands/rootfs.c.old new file mode 100644 index 000000000..671f06091 --- /dev/null +++ b/lab7/kernel/commands/rootfs.c.old @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +static void rootfs_ls(int argc, char** argv) { + char *pathname; + if (argc == 1) { + pathname = get_current()->cwd; + } else if (argc == 2) { + pathname = argv[1]; + } else { + puts("\nUsage: ls [path]"); + return; + } + + struct vnode* vnode; + int ret = vfs_lookup(pathname, &vnode); + + if (ret != 0) { + puts("\r\n[ERROR] Cannot find the directory"); + return; + } + 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) { + puts("\r\n[ERROR] Cannot list the directory"); + return; + } +} + +command_t rootfs_ls_command = { + .name = "ls", + .function = rootfs_ls, + .description = "List files in the root filesystem", +} command_t rootfs_cat_command; +command_t rootfs_mkdir_command; +command_t rootfs_cd_command; +command_t rootfs_cwd_command; +command_t rootfs_touch_command; diff --git a/lab7/kernel/commands/set_timeout.c b/lab7/kernel/commands/set_timeout.c new file mode 100644 index 000000000..557d9b25e --- /dev/null +++ b/lab7/kernel/commands/set_timeout.c @@ -0,0 +1,27 @@ +#include +#include +#include + +void print_timeout(int delay) { + puts("\nTimeout: "); + print_d((const int)delay); + puts("s\n"); +} + +void _set_timeout(int argc, char **argv) { + if (argc < 2) { + puts("\nUsage: set_timeout \n"); + return; + } + + puts("\nSetting timeout: "); + print_d(atoi(argv[1])); + puts("s\n"); + + unsigned long timeout = atoi(argv[1]); + set_timeout((void *)print_timeout, (void *)timeout, atoi(argv[1])); +} + +command_t set_timeout_command = {.name = "set_timeout", + .description = "set a timeout", + .function = &_set_timeout}; diff --git a/lab7/kernel/console.c b/lab7/kernel/console.c new file mode 100644 index 000000000..bacf231b0 --- /dev/null +++ b/lab7/kernel/console.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include + +static command_t commands[64]; +static int num_commands; + +static void read_command(char *); +static int parse_command(char *, char **); +void _print_help(); + +void init_console() { + num_commands = 0; + register_all_commands(); +} + +void run_console() { + char input[256]; + + while (1) { + puts("\n$ "); + + read_command(input); + int argc = 0; + char *argv[16]; + argc = parse_command(input, argv); + + if (argc == 0) { + continue; + } + if (strcmp(argv[0], "help") == 0) { + _print_help(); + continue; + } + int i = 0; + for (i = 0; i < num_commands; i++) { + if (strcmp(argv[0], commands[i].name) == 0) { + commands[i].function(argc, argv); + break; + } + } + if (i == num_commands) { + puts("\ncommand not found\n"); + } + } +} + +void register_command(command_t *command) { + commands[num_commands] = *command; + num_commands++; +} + +void register_all_commands() { + register_command(&hello_command); + register_command(&mailbox_command); + register_command(&reboot_command); + register_command(&ls_command); + register_command(&cat_command); + register_command(&exec_command); + register_command(&test_malloc_command); + register_command(&async_io_demo_command); + register_command(&set_timeout_command); + register_command(&test_kmalloc_command); + register_command(&test_kfree_command); + register_command(&test_multi_thread_command); + register_command(&test_thread_command); +} + +static void read_command(char *x) { + char input_char; + x[0] = 0; + int input_index = 0; + while ((input_char = read_c()) != '\n') { + x[input_index] = input_char; + input_index += 1; + print_char(input_char); + } + if (x[input_index - 1] == '\n') { + x[input_index - 1] = '\0'; + } else { + x[input_index] = '\0'; + } +} + +static int parse_command(char *command, char **argv) { + int argc = 0; + + char *token = strtok(command, " "); + while (token != NULL) { + argv[argc] = token; + argc++; + token = strtok(NULL, " "); + } + return argc; +} + +void _print_help() { + puts("\n"); + + puts("help : print this help menu\n"); + for (int i = 0; i < num_commands; i++) { + puts(commands[i].name); + puts(" : "); + puts(commands[i].description); + puts("\n"); + } +} diff --git a/lab7/kernel/console.h b/lab7/kernel/console.h new file mode 100644 index 000000000..bf6df2a85 --- /dev/null +++ b/lab7/kernel/console.h @@ -0,0 +1,13 @@ +#ifndef CONSOLE_H +#define CONSOLE_H + +#include + + +void init_console(); +void run_console(); +void register_command(command_t *command); +void register_all_commands(); +void destroy_console(); + +#endif diff --git a/lab7/kernel/device_tree.c b/lab7/kernel/device_tree.c new file mode 100644 index 000000000..6a621b28f --- /dev/null +++ b/lab7/kernel/device_tree.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include + +// get this value from start.S +extern void *dtb_base; + +static uint64_t initrd_start, initrd_end; +static uint32_t be2le(const void *s); + +void fdt_traverse(void (*callback)(void *)) { + struct fdt_header *header = (struct fdt_header *)(dtb_base); + puts("[INFO] Dtb loaded address: "); + uart_hex((uintptr_t)header); + puts("\n"); + + // get the offset of the structure block and string block by adding the base + // address of the header to the offset + uint8_t *structure = (uint8_t *)header + be2le(&header->off_dt_struct); + uint8_t *strings = (uint8_t *)header + be2le(&header->off_dt_strings); + + uint32_t totalsize = be2le(&header->totalsize); + + // Parse the structure block + uint8_t *ptr = structure; // Point to the beginning of structure block + while (ptr < strings + totalsize) { + uint32_t token = be2le((char *)ptr); +#ifdef FDT_DEBUG + puts("\n[fdt_traverse] "); + puts("\nptr / strings + totalsize: "); + print_h((uint32_t)ptr); + puts(" / "); + print_h((uint32_t)(strings + totalsize)); + puts(" / "); + print_h(token); +#endif + ptr += 4; // Token takes 4 bytes + + switch (token) { + case FDT_BEGIN_NODE: + // puts((char *)ptr); + ptr += align4(strlen((char *)ptr)); + break; + case FDT_END_NODE: + break; + case FDT_PROP:; // for C23 warning + uint32_t len = be2le((char *)ptr); + ptr += 4; + uint32_t nameoff = be2le((char *)ptr); + ptr += 4; +#if FDT_DEBUG + puts("\n[fdt_traverse] "); + puts((char *)strings + nameoff); +#endif + + // TODO: 這個寫法很怪應為很大程度限制了只能傳 ramfs 的 callback + if (strcmp((char *)(strings + nameoff), "linux,initrd-start") == + 0) { + initrd_start = be2le((void *)ptr); + callback((void *)initrd_start); + } else if (strcmp((char *)(strings + nameoff), + "linux,initrd-end") == 0) { + initrd_end = be2le((void *)ptr); + } + + ptr += align4(len); + break; + case FDT_NOP: + break; + case FDT_END: + break; + } + } +} + +uint64_t fdt_get_initrd_start() { return initrd_start; } +uint64_t fdt_get_initrd_end() { return initrd_end; } + +/** + * @brief Convert a 4-byte big-endian sequence to little-endian. + * + * @param s: big-endian sequence + * @return little-endian sequence + */ +static uint32_t be2le(const void *s) { + const uint8_t *bytes = (const uint8_t *)s; + return (uint32_t)bytes[0] << 24 | (uint32_t)bytes[1] << 16 | + (uint32_t)bytes[2] << 8 | (uint32_t)bytes[3]; +} diff --git a/lab7/kernel/device_tree.h b/lab7/kernel/device_tree.h new file mode 100644 index 000000000..8def99cd5 --- /dev/null +++ b/lab7/kernel/device_tree.h @@ -0,0 +1,31 @@ +#ifndef _DEVTREE_H +#define _DEVTREE_H + +#include +#include + +struct fdt_header { + uint32_t magic; + uint32_t totalsize; + uint32_t off_dt_struct; + uint32_t off_dt_strings; + uint32_t off_mem_rsvmap; + uint32_t version; + uint32_t last_comp_version; + uint32_t boot_cpuid_phys; + uint32_t size_dt_strings; + uint32_t size_dt_struct; +}; + +#define FDT_BEGIN_NODE 0x00000001 +#define FDT_END_NODE 0x00000002 +#define FDT_PROP 0x00000003 +#define FDT_NOP 0x00000004 +#define FDT_END 0x00000009 + +void fdt_traverse(void (*callback)(void *)); +uint64_t fdt_get_initrd_start(); +uint64_t fdt_get_initrd_end(); + + +#endif diff --git a/lab7/kernel/fs/dev_uart.c b/lab7/kernel/fs/dev_uart.c new file mode 100644 index 000000000..bb980c9bc --- /dev/null +++ b/lab7/kernel/fs/dev_uart.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include + +struct file_operations dev_uart_operations = {dev_uart_write, dev_uart_read, dev_uart_open, dev_uart_close, (void *)dev_uart_deny, (void *)dev_uart_deny}; + +int init_dev_uart() +{ + return register_dev(&dev_uart_operations); +} + +int dev_uart_write(struct file *file, const void *buf, size_t len) +{ + /*printf("dev_uart_write\n");*/ + 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) +{ + char *cbuf = buf; + for (int i = 0; i < len; i++) + { + cbuf[i] = uart_recv(); + } + return len; +} + +int dev_uart_open(struct vnode *file_node, struct file **target) +{ + (*target)->vnode = file_node; + (*target)->f_ops = &dev_uart_operations; + return 0; +} + +int dev_uart_close(struct file *file) +{ + kfree(file); + return 0; +} + +int dev_uart_deny() +{ + return -1; +} diff --git a/lab7/kernel/fs/dev_uart.h b/lab7/kernel/fs/dev_uart.h new file mode 100644 index 000000000..6af5096b9 --- /dev/null +++ b/lab7/kernel/fs/dev_uart.h @@ -0,0 +1,15 @@ +#ifndef _DEV_UART_H_ +#define _DEV_UART_H_ + +#include +#include + +int init_dev_uart(); + +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); +int dev_uart_deny(); + +#endif diff --git a/lab7/kernel/fs/fdtable.h b/lab7/kernel/fs/fdtable.h new file mode 100644 index 000000000..9046ced26 --- /dev/null +++ b/lab7/kernel/fs/fdtable.h @@ -0,0 +1,21 @@ +#ifndef _FDTABLE_H_ +#define _FDTABLE_H_ + +# define MAX_FD 32 + +#include + +struct file +{ + struct vnode *vnode; + size_t f_pos; // RW position of this file handle + struct file_operations *f_ops; + int flags; +}; + +struct fdtable { + int count; + struct file* fds[MAX_FD]; +}; + +#endif diff --git a/lab7/kernel/fs/initramfs.h b/lab7/kernel/fs/initramfs.h new file mode 100644 index 000000000..68a68e0f3 --- /dev/null +++ b/lab7/kernel/fs/initramfs.h @@ -0,0 +1,36 @@ +#ifndef _INITRAMFS_H_ +#define _INITRAMFS_H_ + +#include +#include + +#define INITRAMFS_MAX_DIR_ENTRY 100 + +// initramfs basically is same as tmpfs, but it is read-only + +struct initramfs_inode +{ + enum fsnode_type type; + char name[64]; + struct vnode *entry[INITRAMFS_MAX_DIR_ENTRY]; + char *data; + size_t datasize; +}; + +int register_initramfs(); +int initramfs_setup_mount(struct filesystem *fs, struct mount *_mount); + +int initramfs_write(struct file *file, const void *buf, size_t len); +int initramfs_read(struct file *file, void *buf, size_t len); +int initramfs_open(struct vnode *file_node, struct file **target); +int initramfs_close(struct file *file); +long initramfs_lseek64(struct file *file, long offset, int whence); +long initramfs_getsize(struct vnode *vd); + +int initramfs_lookup(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_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); + +struct vnode *initramfs_create_vnode(struct mount *_mount, enum fsnode_type type); + +#endif /* _INITRAMFS_H_ */ diff --git a/lab7/kernel/fs/tmpfs.c b/lab7/kernel/fs/tmpfs.c new file mode 100644 index 000000000..a9a086b50 --- /dev/null +++ b/lab7/kernel/fs/tmpfs.c @@ -0,0 +1,185 @@ +#include +#include +#include +#include +#include + +struct file_operations tmpfs_file_operations = {tmpfs_write, tmpfs_read, + tmpfs_open, tmpfs_close, + tmpfs_lseek64, tmpfs_getsize}; +struct vnode_operations tmpfs_vnode_operations = {tmpfs_lookup, tmpfs_create, + tmpfs_mkdir}; + + +int register_tmpfs() { + struct filesystem fs; + fs.name = "tmpfs"; + fs.setup_mount = tmpfs_setup_mount; + return register_filesystem(&fs); +} + +int tmpfs_setup_mount(struct filesystem *fs, struct mount *_mount) { + _mount->fs = fs; + _mount->root = tmpfs_create_vnode(0, DIR); + return 0; +} + +struct vnode *tmpfs_create_vnode(struct mount *_mount, enum fsnode_type type) { + struct vnode *v = kmalloc(sizeof(struct vnode)); + v->f_ops = &tmpfs_file_operations; + v->v_ops = &tmpfs_vnode_operations; + v->mount = 0; + struct tmpfs_inode *inode = kmalloc(sizeof(struct tmpfs_inode)); + memset(inode, 0, sizeof(struct tmpfs_inode)); + inode->type = type; + inode->data = kmalloc(0x1000); + v->internal = inode; + return v; +} + +// file operations +int tmpfs_write(struct file *file, const void *buf, size_t len) { + struct tmpfs_inode *inode = file->vnode->internal; + // write from f_pos + memcpy(inode->data + file->f_pos, buf, len); + // update f_pos and size + file->f_pos += len; + if (inode->datasize < file->f_pos) inode->datasize = file->f_pos; + return len; +} + +int tmpfs_read(struct file *file, void *buf, size_t len) { + struct tmpfs_inode *inode = file->vnode->internal; + // if buffer overflow, shrink the request read length + // read from f_pos + if (len + file->f_pos > inode->datasize) { + len = inode->datasize - file->f_pos; + memcpy(buf, inode->data + file->f_pos, len); + file->f_pos += inode->datasize - file->f_pos; + return len; + } else { + memcpy(buf, inode->data + file->f_pos, len); + file->f_pos += len; + return len; + } + return -1; +} + +int tmpfs_open(struct vnode *file_node, struct file **target) { + (*target)->vnode = file_node; + (*target)->f_ops = file_node->f_ops; + (*target)->f_pos = 0; + return 0; +} + +int tmpfs_close(struct file *file) { + kfree(file); + return 0; +} + +long tmpfs_lseek64(struct file *file, long offset, int whence) { + if (whence == SEEK_SET) { + file->f_pos = offset; + return file->f_pos; + } + return -1; +} + +// vnode operations +int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name) { + struct tmpfs_inode *dir_inode = dir_node->internal; + int child_idx = 0; + // BFS search tree + for (; child_idx <= MAX_DIR_ENTRY; child_idx++) { + struct vnode *vnode = dir_inode->entry[child_idx]; + if (!vnode) break; + struct tmpfs_inode *inode = vnode->internal; + if (strcmp(component_name, inode->name) == 0) { + *target = vnode; + return 0; + } + } + return -1; +} + +// file ops +int tmpfs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name) { + struct tmpfs_inode *inode = dir_node->internal; + if (inode->type != DIR) { + puts("[ERROR] tmpfs create not DIR\r\n"); + return -1; + } + + int child_idx = 0; + for (; child_idx <= MAX_DIR_ENTRY; child_idx++) { + if (!inode->entry[child_idx]) break; + struct tmpfs_inode *child_inode = inode->entry[child_idx]->internal; + if (strcmp(child_inode->name, component_name) == 0) { + puts("[ERROR] tmpfs create file exists\r\n"); + return -1; + } + } + + if (child_idx > MAX_DIR_ENTRY) { + puts("DIR ENTRY FULL\r\n"); + return -1; + } + + if (strlen(component_name) > MAX_FILE_NAME) { + puts("FILE NAME TOO LONG\r\n"); + return -1; + } + + struct vnode *_vnode = tmpfs_create_vnode(0, FILE); + inode->entry[child_idx] = _vnode; + + struct tmpfs_inode *newinode = _vnode->internal; + strcpy(newinode->name, component_name); + + *target = _vnode; + return 0; +} + +// dir ops +int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name) { + struct tmpfs_inode *inode = dir_node->internal; + + if (inode->type != DIR) { + puts("[ERROR] tmpfs mkdir not DIR\r\n"); + return -1; + } + + int child_idx = 0; + for (; child_idx <= MAX_DIR_ENTRY; child_idx++) { + if (!inode->entry[child_idx]) { + break; + } + } + + if (child_idx > MAX_DIR_ENTRY) { + puts("[ERROR] DIR ENTRY FULL\r\n"); + return -1; + } + + if (strlen(component_name) > MAX_FILE_NAME) { + puts("[ERROR] FILE NAME TOO LONG\r\n"); + return -1; + } + + struct vnode *_vnode = tmpfs_create_vnode(0, DIR); + inode->entry[child_idx] = _vnode; + + struct tmpfs_inode *newinode = _vnode->internal; + strcpy(newinode->name, component_name); + + *target = _vnode; + return 0; +} + +long tmpfs_getsize(struct vnode *vd) { + struct tmpfs_inode *inode = vd->internal; + return inode->datasize; +} diff --git a/lab7/kernel/fs/tmpfs.h b/lab7/kernel/fs/tmpfs.h new file mode 100644 index 000000000..c34ed6c56 --- /dev/null +++ b/lab7/kernel/fs/tmpfs.h @@ -0,0 +1,31 @@ +#ifndef _TMPFS_H_ +#define _TMPFS_H_ + +#include + +struct tmpfs_inode +{ + enum fsnode_type type; + char name[MAX_FILE_NAME]; + struct vnode *entry[MAX_DIR_ENTRY]; + char *data; + size_t datasize; +}; + +int register_tmpfs(); +int tmpfs_setup_mount(struct filesystem *fs, struct mount *_mount); + +int tmpfs_write(struct file *file, const void *buf, size_t len); +int tmpfs_read(struct file *file, void *buf, size_t len); +int tmpfs_open(struct vnode *file_node, struct file **target); +int tmpfs_close(struct file *file); +long tmpfs_lseek64(struct file *file, long offset, int whence); +long tmpfs_getsize(struct vnode *vd); + +int tmpfs_lookup(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_create(struct vnode *dir_node, struct vnode **target, const char *component_name); +int tmpfs_mkdir(struct vnode *dir_node, struct vnode **target, const char *component_name); + +struct vnode *tmpfs_create_vnode(struct mount *_mount, enum fsnode_type type); + +#endif /* _TMPFS_H_ */ diff --git a/lab7/kernel/fs/vfs.c b/lab7/kernel/fs/vfs.c new file mode 100644 index 000000000..927154595 --- /dev/null +++ b/lab7/kernel/fs/vfs.c @@ -0,0 +1,266 @@ + +#include +#include +#include +#include +#include +#include +#include + +struct mount *rootfs; +struct filesystem reg_fs[MAX_FS_REG]; +struct file_operations reg_dev[MAX_DEV_REG]; + +void init_rootfs() { + // cannot use vfs_mount because starting point is vfs_root, and it has + // nothing yet will mount at rootfs -> mount -> root instead of rootfs -> + // root + int idx = register_tmpfs(); + rootfs = kmalloc(sizeof(struct mount)); + reg_fs[idx].setup_mount(®_fs[idx], rootfs); + + vfs_mkdir("/initramfs"); + register_initramfs(); + vfs_mount("/initramfs", "initramfs"); + + vfs_mkdir("/dev"); + + int uart_id = init_dev_uart(); + vfs_mknod("/dev/uart", uart_id); + printf("[INFO] uart_id: %d\n", uart_id); +} + +int register_filesystem(struct filesystem *fs) { + for (int i = 0; i < MAX_FS_REG; i++) { + if (!reg_fs[i].name) { + reg_fs[i].name = fs->name; + reg_fs[i].setup_mount = fs->setup_mount; + return i; + } + } + return -1; +} + +int register_dev(struct file_operations *fo) { + for (int i = 0; i < MAX_FS_REG; i++) { + if (!reg_dev[i].open) { + // return unique id for the assigned device + reg_dev[i].open = fo->open; + reg_dev[i].read = fo->read; + reg_dev[i].write = fo->write; + reg_dev[i].close = fo->close; + + return i; + } + } + return -1; +} + +struct filesystem *find_filesystem(const char *fs_name) { + for (int i = 0; i < MAX_FS_REG; i++) { + if (strcmp(reg_fs[i].name, fs_name) == 0) { + return ®_fs[i]; + } + } + return 0; +} + +// file ops +int vfs_open(const char *pathname, int flags, struct file **target) { + // 1. Lookup pathname + // 2. Create a new file if O_CREAT is specified in flags and vnode not found + struct vnode *node; + if (vfs_lookup(pathname, &node) != 0 && (flags & O_CREAT)) { + // grep all of the directory path + int last_slash_idx = 0; + for (int i = 0; i < strlen(pathname); i++) { + if (pathname[i] == '/') { + last_slash_idx = i; + } + } + + char dirname[MAX_PATH_NAME + 1]; + strcpy(dirname, pathname); + dirname[last_slash_idx] = 0; + // update dirname to node + if (vfs_lookup(dirname, &node) != 0) { + puts("[ERROR] cannot create no dirname\r\n"); + return -1; + } + // create a new file node on node, &node is new file, 3rd arg is + // filename + node->v_ops->create(node, &node, pathname + last_slash_idx + 1); + *target = kmalloc(sizeof(struct file)); + // attach opened file on the new node + node->f_ops->open(node, target); + (*target)->flags = flags; + return 0; + } + + // 2. Create a new file handle for this vnode if found. + // attach opened file on the node + *target = kmalloc(sizeof(struct file)); + node->f_ops->open(node, target); + (*target)->flags = flags; + return 0; +} + +// file ops +int vfs_close(struct file *file) { + // 1. release the file handle + // 2. Return error code if fails + file->f_ops->close(file); + return 0; +} + +// file ops +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. + return file->f_ops->write(file, buf, len); +} + +// file ops +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. + return file->f_ops->read(file, buf, len); +} + +// file ops +int vfs_mkdir(const char *pathname) { + char dirname[MAX_PATH_NAME] = {}; // before add folder + char newdirname[MAX_PATH_NAME] = {}; // after add folder + + // search for last directory + int last_slash_idx = 0; + for (int i = 0; i < strlen(pathname); i++) { + if (pathname[i] == '/') { + last_slash_idx = i; + } + } + + memcpy(dirname, pathname, last_slash_idx); + strcpy(newdirname, pathname + last_slash_idx + 1); + + // create new directory if upper directory is found + struct vnode *node; + if (vfs_lookup(dirname, &node) == 0) { + // node is the old dir, &node is new dir + node->v_ops->mkdir(node, &node, newdirname); + return 0; + } + + puts("[ERROR] vfs_MAX_OPEN_FILEmkdir cannot find pathname"); + return -1; +} + +int vfs_mount(const char *target, const char *filesystem) { + struct vnode *dirnode; + // search for the target filesystem + struct filesystem *fs = find_filesystem(filesystem); + if (!fs) { + printf("[ERROR] vfs_mount cannot find filesystem\r\n"); + return -1; + } + + if (vfs_lookup(target, &dirnode) == -1) { + printf("[ERROR] vfs_mount cannot find dir\r\n"); + return -1; + } else { + // mount fs on dirnode + dirnode->mount = kmalloc(sizeof(struct mount)); + fs->setup_mount(fs, dirnode->mount); + } + return 0; +} + +int vfs_lookup(const char *pathname, struct vnode **target) { + // if no path input, return root + if (strlen(pathname) == 0) { + *target = rootfs->root; + return 0; + } + + struct vnode *dirnode = rootfs->root; + char component_name[MAX_FILE_NAME + 1] = {}; + int c_idx = 0; + // deal with directory + for (int i = 1; i < strlen(pathname); i++) { + if (pathname[i] == '/') { + component_name[c_idx++] = 0; + // if fs's v_ops error, return -1 + if (dirnode->v_ops->lookup(dirnode, &dirnode, component_name) != 0) + return -1; + // redirect to mounted filesystem + while (dirnode->mount) { + dirnode = dirnode->mount->root; + } + c_idx = 0; + } else { + component_name[c_idx++] = pathname[i]; + } + } + + // deal with file + component_name[c_idx++] = 0; + // if fs's v_ops error, return -1 + if (dirnode->v_ops->lookup(dirnode, &dirnode, component_name) != 0) + return -1; + // redirect to mounted filesystem + while (dirnode->mount) { + dirnode = dirnode->mount->root; + } + // return file's vnode + *target = dirnode; + + return 0; +} + +int vfs_mknod(char *pathname, int id) { + struct file *f = kmalloc(sizeof(struct file)); + // create leaf and its file operations + vfs_open(pathname, O_CREAT, &f); + f->vnode->f_ops = ®_dev[id]; + vfs_close(f); + return 0; +} + +char *get_absolute_path(char *path, char *cwd) { + // if relative path -> add root path + if (path[0] != '/') { + char tmp[MAX_PATH_NAME]; + strcpy(tmp, cwd); + if (strcmp(cwd, "/") != 0) strcat(tmp, "/"); + strcat(tmp, path); + strcpy(path, tmp); + } + + char absolute_path[MAX_PATH_NAME + 1] = {}; + int idx = 0; + for (int i = 0; i < strlen(path); i++) { + // handle .. + if (path[i] == '/' && path[i + 1] == '.' && path[i + 2] == '.') { + for (int j = idx; j >= 0; j--) { + if (absolute_path[j] == '/') { + absolute_path[j] = 0; + idx = j; + } + } + i += 2; + continue; + } + + // handle . + if (path[i] == '/' && path[i + 1] == '.') { + i++; + continue; + } + + absolute_path[idx++] = path[i]; + } + absolute_path[idx] = 0; + + return strcpy(path, absolute_path); +} diff --git a/lab7/kernel/fs/vfs.h b/lab7/kernel/fs/vfs.h new file mode 100644 index 000000000..462cbee68 --- /dev/null +++ b/lab7/kernel/fs/vfs.h @@ -0,0 +1,80 @@ +#ifndef _VFS_H_ +#define _VFS_H_ + +#include +#include + +#define MAX_PATH_NAME 255 +#define O_CREAT 100 +#define O_RDWR 000 +#define SEEK_SET 0 +#define MAX_FS_REG 0x50 +#define MAX_DEV_REG 0x10 +#define MAX_FILE_NAME 15 +#define MAX_DIR_ENTRY 16 +#define MAX_FILE_SIZE 4096 + +enum fsnode_type +{ + DIR, + FILE +}; + + +struct vnode +{ + struct mount *mount; // Superblock : represents mounted fs + struct vnode_operations *v_ops; // inode & dentry Ops: represents kernel methods for vnode + struct file_operations *f_ops; // file Ops : represents process methods for opened file + void *internal; // vnode itself : directly point to fs's vnode +}; + +struct mount +{ + struct vnode *root; + struct filesystem *fs; +}; + +struct filesystem +{ + const char *name; + int (*setup_mount)(struct filesystem *fs, struct mount *mount); +}; + +struct file_operations +{ + int (*write)(struct file *file, const void *buf, size_t len); + int (*read)(struct file *file, void *buf, size_t len); + int (*open)(struct vnode *file_node, struct file **target); + int (*close)(struct file *file); + long (*lseek64)(struct file *file, long offset, int whence); + long (*getsize)(struct vnode *vd); +}; + +struct vnode_operations +{ + int (*lookup)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*create)(struct vnode *dir_node, struct vnode **target, + const char *component_name); + int (*mkdir)(struct vnode *dir_node, struct vnode **target, + const char *component_name); +}; + +int register_filesystem(struct filesystem *fs); +int register_dev(struct file_operations* fo); +struct filesystem *find_filesystem(const char *fs_name); +int vfs_open(const char *pathname, int flags, struct file **target); +int vfs_close(struct file *file); +int vfs_write(struct file *file, const void *buf, size_t len); +int vfs_read(struct file *file, void *buf, size_t len); +int vfs_mkdir(const char *pathname); +int vfs_mount(const char *target, const char *filesystem); +int vfs_lookup(const char *pathname, struct vnode **target); +int vfs_mknod(char* pathname, int id); + +void init_rootfs(); +void vfs_test(); +char* get_absolute_path(char* path,char* xwd); + +#endif /* _VFS_H_ */ diff --git a/lab7/kernel/initramfs.c b/lab7/kernel/initramfs.c new file mode 100644 index 000000000..8a973d7bd --- /dev/null +++ b/lab7/kernel/initramfs.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include + +struct file_operations initramfs_file_operations = { + initramfs_write, initramfs_read, initramfs_open, + initramfs_close, initramfs_lseek64, initramfs_getsize}; +struct vnode_operations initramfs_vnode_operations = { + initramfs_lookup, initramfs_create, initramfs_mkdir}; + +int register_initramfs() { + struct filesystem fs; + fs.name = "initramfs"; + fs.setup_mount = initramfs_setup_mount; + return register_filesystem(&fs); +} + +int initramfs_setup_mount(struct filesystem *fs, struct mount *_mount) { + _mount->fs = fs; + _mount->root = initramfs_create_vnode(0, DIR); + // create entry under _mount, cpio files should be attached on it + struct initramfs_inode *ramdir_inode = _mount->root->internal; + + int idx = 0; + + file_list_t *files = ramfs_get_file_list(); + + for (int i = 0; i < files->file_count; i++) { + // only support file (no dir) + struct vnode *filevnode = initramfs_create_vnode(0, FILE); + struct initramfs_inode *fileinode = filevnode->internal; + /*printf("initramfs: create file %s\n", files->file_names[i]);*/ + /*printf("initramfs: size %d\n", files->file_sizes[i]);*/ + strcpy(fileinode->name, files->file_names[i]); + fileinode->data = files->file_data[i]; + fileinode->datasize = files->file_sizes[i]; + /*printf("inode - name %s\n", fileinode->name);*/ + /*printf("inode - size %d\n", fileinode->datasize);*/ + ramdir_inode->entry[idx++] = filevnode; + } + + return 0; +} + +struct vnode *initramfs_create_vnode(struct mount *_mount, + enum fsnode_type type) { + struct vnode *v = kmalloc(sizeof(struct vnode)); + v->f_ops = &initramfs_file_operations; + v->v_ops = &initramfs_vnode_operations; + v->mount = _mount; + struct initramfs_inode *inode = kmalloc(sizeof(struct initramfs_inode)); + memset(inode, 0, sizeof(struct initramfs_inode)); + inode->type = type; + inode->data = NULL; + v->internal = inode; + return v; +} + +// file operations +int initramfs_write(struct file *file, const void *buf, size_t len) { + // read-only + return -1; +} + +int initramfs_read(struct file *file, void *buf, size_t len) { + struct initramfs_inode *inode = file->vnode->internal; + // overflow, shrink size + if (len + file->f_pos > inode->datasize) { + memcpy(buf, inode->data + file->f_pos, inode->datasize - file->f_pos); + file->f_pos += inode->datasize - file->f_pos; + return inode->datasize - file->f_pos; + } else { + memcpy(buf, inode->data + file->f_pos, len); + file->f_pos += len; + return len; + } + return -1; +} + +int initramfs_open(struct vnode *file_node, struct file **target) { + (*target)->vnode = file_node; + (*target)->f_ops = file_node->f_ops; + (*target)->f_pos = 0; + return 0; +} + +int initramfs_close(struct file *file) { + kfree(file); + return 0; +} + +long initramfs_lseek64(struct file *file, long offset, int whence) { + if (whence == SEEK_SET) { + file->f_pos = offset; + return file->f_pos; + } + return -1; +} + +// vnode operations +int initramfs_lookup(struct vnode *dir_node, struct vnode **target, + const char *component_name) { + struct initramfs_inode *dir_inode = dir_node->internal; + int child_idx = 0; + for (; child_idx < INITRAMFS_MAX_DIR_ENTRY; child_idx++) { + struct vnode *vnode = dir_inode->entry[child_idx]; + if (!vnode) break; + struct initramfs_inode *inode = vnode->internal; + if (strcmp(component_name, inode->name) == 0) { + *target = vnode; + return 0; + } + } + return -1; +} + +int initramfs_create(struct vnode *dir_node, struct vnode **target, + const char *component_name) { + // read-only + return -1; +} + +int initramfs_mkdir(struct vnode *dir_node, struct vnode **target, + const char *component_name) { + // read-only + return -1; +} + +long initramfs_getsize(struct vnode *vd) { + struct initramfs_inode *inode = vd->internal; + return inode->datasize; +} diff --git a/lab7/kernel/io.c b/lab7/kernel/io.c new file mode 100644 index 000000000..444d94c9b --- /dev/null +++ b/lab7/kernel/io.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +char read_c() { return uart_getc(); } +void read_s(char *s) { + char input_char; + s[0] = 0; + int input_index = 0; + while ((input_char = read_c()) != '\n') { + if (input_char == '\b' || input_char == 127) { // 處理退格鍵 + if (input_index > 0) { // 確保有字元可以刪除 + input_index -= 1; // 刪除最後一個字元 + puts("\b \b"); // 在控制台上刪除這個字元,\b + // 是回退一格,空格刪除字元,再一個 \b + // 是將光標回退一格。 + continue; + } + } + s[input_index] = input_char; + input_index += 1; + print_char(input_char); + } + + s[input_index] = 0; +} + +/** + * printf implementation using sprintf + */ +void printf(const char* fmt, ...) +{ + char buffer[1024]; + __builtin_va_list args; + __builtin_va_start(args, fmt); + vsprintf(buffer, fmt, args); + __builtin_va_end(args); + puts(buffer); // Assuming puts writes the string to the standard output and returns the number of characters written +} + +void print_char(const char c) { return uart_send(c); } +void puts(const char *s) { return uart_puts(s); } +void print_h(const unsigned long long x) { uart_hex(x); } + +void print_d(const int x) { + char buffer[10]; + + itoa(x, buffer); + puts(buffer); +} diff --git a/lab7/kernel/io.h b/lab7/kernel/io.h new file mode 100644 index 000000000..671732d73 --- /dev/null +++ b/lab7/kernel/io.h @@ -0,0 +1,12 @@ +#ifndef IO_H +#define IO_H + +char read_c(); +void read_s(char *s); +void printf(const char* fmt, ...); +void print_char(const char); +void puts(const char *); +void print_h(const unsigned long long x); +void print_d(const int x); + +#endif diff --git a/lab7/kernel/irq_entry.c b/lab7/kernel/irq_entry.c new file mode 100644 index 000000000..c904b3af5 --- /dev/null +++ b/lab7/kernel/irq_entry.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include + +void print_registers(uint64_t elr, uint64_t esr, uint64_t spsr) { + puts("spsr_el1: "); + print_h(spsr); + puts("\n elr_el1: "); + print_h(elr); + puts("\n esr_el1: "); + print_h(esr); + puts("\n\n"); +} + +void exception_entry(trap_frame *tf) { + unsigned long elr, esr, spsr; + asm volatile("mrs %0, elr_el1" : "=r"(elr)); + asm volatile("mrs %0, esr_el1" : "=r"(esr)); + asm volatile("mrs %0, spsr_el1" : "=r"(spsr)); + if (esr != 0x56000000) { + print_registers(elr, esr, spsr); + while (1); + } + + enable_irq(); + switch (tf->x8) { + case 0: + tf->x0 = sys_getpid(); + break; + case 1: + tf->x0 = sys_uart_read((char *)tf->x0, tf->x1); + break; + case 2: + tf->x0 = sys_uart_write((const char *)tf->x0, tf->x1); + break; + case 3: + tf->x0 = sys_exec((const char *)tf->x0, (char *const *)tf->x1); + tf->elr_el1 = get_current()->context.lr; + tf->sp_el0 = (unsigned long)get_current()->user_stack + STACK_SIZE; + break; + case 4: + tf->x0 = sys_fork(tf); + break; + case 5: + sys_exit(); + break; + case 6: + tf->x0 = sys_mbox_call(tf->x0, (unsigned int *)tf->x1); + break; + case 7: + sys_kill(tf->x0); + break; + case 8: + sys_signal(tf->x0, (void (*)())tf->x1); + break; + case 9: + sys_sigkill(tf->x0, tf->x1); + break; + case 11: + sys_open(tf, (char*)tf->x0, tf->x1); + break; + case 12: + sys_close(tf, tf->x0); + break; + case 13: + sys_write(tf, tf->x0, (char *)tf->x1, tf->x2); + break; + case 14: + sys_read(tf, tf->x0, (char *)tf->x1, tf->x2); + break; + case 15: + sys_mkdir(tf, (char *)tf->x0, tf->x1); + break; + case 16: + sys_mount(tf, (char *)tf->x0, (char *)tf->x1, (char *)tf->x2, tf->x3, (void*)tf->x4); + break; + case 17: + sys_chdir(tf, (char *)tf->x0); + break; + case 18: + sys_lseek64(tf, tf->x0, tf->x1, tf->x2); + break; + case 19: + sys_ioctl(tf, tf->x0, tf->x1, (void*)tf->x2); + break; + case 139: + sys_sigreturn(tf); + break; + default: + printf("[ERROR] Invalid system call\n"); + } +} + +void invalid_entry(uint64_t elr, uint64_t esr, uint64_t spsr) { + puts("[ERROR] The exception handler is not implemented\n"); + print_registers(elr, esr, spsr); + while (1); +} + +void irq_entry(trap_frame *tf) { +#ifdef IRQ_DEBUG + uart_puts("IRQ count: "); + uart_hex(count); + uart_puts("\n"); + uart_puts("IRQ CORE0_IRQ_SOURCE: "); + uart_hex(get_irq()); + uart_puts("\n"); + puts("\n[el1_irq_entry] "); + show_irq_debug_msg(type, spsr, elr, esr); +#endif + + disable_irq(); + + if (is_core_timer_irq()) { + // Schedule processes + if (get_current() != get_current()->next) { + schedule(); + } + core_timer_disable(); + timer_irq_handler(); + } else if (is_gpu_irq()) { + if (is_aux_irq()) { + if (is_uart_rx_irq()) { + uart_disable_rx_interrupt(); + uart_rx_irq_handler(); + } else if (is_uart_tx_irq()) { + uart_disable_tx_interrupt(); + uart_tx_irq_handler(); + } + } + } else { + puts("\r\nUnknown irq"); + } + + do_signal(tf); +} diff --git a/lab7/kernel/irq_entry.h b/lab7/kernel/irq_entry.h new file mode 100644 index 000000000..16b0ccf92 --- /dev/null +++ b/lab7/kernel/irq_entry.h @@ -0,0 +1,17 @@ +#ifndef __IRQ_ENTRY_H__ +#define __IRQ_ENTRY_H__ + +#define EL1_IRQ_TIMER_PRIORITY 0x1 +#define EL1_IRQ_UART_PRIORITY 0x2 + +// exception entrypoint for exception.S +void el1_irq_entry(int type, unsigned long spsr, unsigned long elr, + unsigned long esr); + +void default_exception_entry(int type, unsigned long spsr, unsigned long elr, + unsigned long esr); + +void el0_irq_entry(int type, unsigned long spsr, unsigned long elr, + unsigned long esr); + +#endif diff --git a/lab7/kernel/kmalloc.c b/lab7/kernel/kmalloc.c new file mode 100644 index 000000000..64130a8ae --- /dev/null +++ b/lab7/kernel/kmalloc.c @@ -0,0 +1,137 @@ +#include +#include +#include + +#include "mm.h" + +#define KMEM_CACHE_MIN_ORDER 4 // 16 +#define KMEM_CACHE_MAX_ORDER 8 // 256 + +typedef struct kmem_cache { + struct kmem_cache *next; + unsigned long order; +} kmem_cache_t; + +static kmem_cache_t + *kmalloc_caches[KMEM_CACHE_MAX_ORDER - KMEM_CACHE_MIN_ORDER + 1]; + +uint32_t get_page_order_by_size(uint32_t size) { + uint32_t order = 0; + while (size > (1 << (PAGE_SHIFT + order))) { + order++; + } + return order; +} + +uint32_t get_cache_order_by_size(uint32_t size) { + uint32_t order = 0; + while (size > (1 << (order + KMEM_CACHE_MIN_ORDER))) { + order++; + } + return order; +} + +extern uint64_t __heap_start; +void init_kmalloc() { + // buddy_init((phys_addr_t)0x10000000, (phys_addr_t)0x20000000); + buddy_init((phys_addr_t)0x0, (phys_addr_t)0x3C000000); + memory_reserve(0x0, (phys_addr_t)0x1000); // Spin tables for multicore boot + // (0x0000 - 0x1000) + memory_reserve((phys_addr_t)0x80000, + (phys_addr_t)&__heap_start); // Kernel code and data + + memory_reserve( + (phys_addr_t)&__heap_start, + (phys_addr_t)((void *)&__heap_start + 0x100000)); // Startup allocator + + memory_reserve((phys_addr_t)fdt_get_initrd_start(), + (phys_addr_t)fdt_get_initrd_end()); // Initramfs + +// #ifdef MEM_DEBUG + print_free_areas(); +// #endif +} + +void print_kmalloc_caches() { + for (int i = 0; i < KMEM_CACHE_MAX_ORDER - KMEM_CACHE_MIN_ORDER; i++) { + kmem_cache_t *cache = kmalloc_caches[i]; + puts("Cache Order "); + print_d(i); + puts(": "); + while (cache != NULL) { + print_h((uint64_t)cache); + puts(" -> "); + cache = cache->next; + } + puts("NULL\n"); + } +} + +void *kmem_cache_alloc(uint32_t order) { + if (order > KMEM_CACHE_MAX_ORDER - KMEM_CACHE_MIN_ORDER) { + return NULL; + } + if (kmalloc_caches[order] == NULL) { + page_t *page = alloc_pages(0); + + if (page == NULL) { + return NULL; + } + + page->status = PAGE_CACHE; // mark as cache page + uint32_t cache_size = 1 << (order + KMEM_CACHE_MIN_ORDER); + for (int i = 0; i < PAGE_SIZE; i += cache_size) { + kmem_cache_t *cache = ((void *)get_addr_by_page(page) + i); + cache->order = order; + cache->next = kmalloc_caches[order]; + kmalloc_caches[order] = cache; + } + // print_d((uint64_t)page); + } + kmem_cache_t *cache = kmalloc_caches[order]; + kmalloc_caches[order] = cache->next; + + // print_kmalloc_caches(); + + return cache; +} + +void kmem_cache_free(void *ptr, uint32_t order) { + if (order > KMEM_CACHE_MAX_ORDER - KMEM_CACHE_MIN_ORDER) { + return; + } + // push cache back to the list + kmem_cache_t *cache = (kmem_cache_t *)ptr; + cache->next = kmalloc_caches[order]; + kmalloc_caches[order] = cache; + + // print_kmalloc_caches(); +} + +void *kmalloc(uint32_t size) { + uint32_t order = get_page_order_by_size(size); + if (order > MAX_ORDER) { + return NULL; + } + + // if (order == 0) { + // if (size >= (1 << KMEM_CACHE_MAX_ORDER)) { + // return (void *)get_addr_by_page(alloc_pages(order)); + // } + // + // uint32_t cache_order = get_cache_order_by_size(size); + // return kmem_cache_alloc(cache_order); + // } + + return (void *)get_addr_by_page(alloc_pages(order)); +} + +void kfree(void *ptr) { + if ((uintptr_t)ptr % PAGE_SIZE == 0) { + page_t *page = get_page_by_addr((phys_addr_t)ptr); + free_pages(page, page->order); + return; + } + kmem_cache_t *cache = (kmem_cache_t *)ptr; + kmem_cache_free(cache, cache->order); +} diff --git a/lab7/kernel/lock.c b/lab7/kernel/lock.c new file mode 100644 index 000000000..d1444ce8a --- /dev/null +++ b/lab7/kernel/lock.c @@ -0,0 +1,16 @@ +#include +#include + +static unsigned long long lock_count = 0; +void lock() +{ + disable_irq(); + lock_count++; +} + +void unlock() +{ + lock_count--; + if (lock_count == 0) + enable_irq(); +} diff --git a/lab7/kernel/lock.h b/lab7/kernel/lock.h new file mode 100644 index 000000000..5e44b27ac --- /dev/null +++ b/lab7/kernel/lock.h @@ -0,0 +1,7 @@ +#ifndef LOCK_H +#define LOCK_H + +void lock(); +void unlock(); + +#endif diff --git a/lab7/kernel/main.c b/lab7/kernel/main.c new file mode 100644 index 000000000..90efc12c1 --- /dev/null +++ b/lab7/kernel/main.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void print_boot_timeout(int delay) { + puts("\nBoot Timeout: "); + print_d((const int)delay); + puts("s\n"); +} + +int main() { + // lab1 + uart_init(); + init_console(); + + // lab2 + init_memory(); + fdt_traverse(init_ramfs_callback); + + // lab3 + enable_irq(); + // set_timeout((void *)print_boot_timeout, (void *)4, 4); + core_timer_enable(); + + // lab4 + init_kmalloc(); + + // lab7 + init_rootfs(); + + // lab5 + // sched_init(); + kthread_init(); + + + puts("\nWelcome to visitorckw's shell\n"); + + // set_timeout((void*)print_boot_timeout, 0, 1); + // kthread_create((void *)run_console); + run_console(); + + return 0; +} diff --git a/lab7/kernel/memory.h b/lab7/kernel/memory.h new file mode 100644 index 000000000..c51df8290 --- /dev/null +++ b/lab7/kernel/memory.h @@ -0,0 +1,20 @@ +#ifndef _MEMORY_H +#define _MEMORY_H + +#define USER_PROGRAM_BASE 0x100000 +#define USER_STACK_POINTER_BASE 0x200000 + +#include + +void init_memory(); +void *simple_malloc(unsigned int size); +char *get_heap_top(); + +void init_kmalloc(); +void *kmalloc(uint32_t size); +void kfree(void *ptr); + +void print_kmalloc_caches(); +void print_free_areas(); + +#endif diff --git a/lab7/kernel/mm.h b/lab7/kernel/mm.h new file mode 100644 index 000000000..fa6255b0f --- /dev/null +++ b/lab7/kernel/mm.h @@ -0,0 +1,31 @@ +#ifndef __MM_TYPE_H__ +#define __MM_TYPE_H__ + +#include + +#define MAX_ORDER 10 +#define PAGE_SIZE 4096 +#define PAGE_SHIFT 12 + +#define PAGE_FREE 0 +#define PAGE_ALLOCATED 1 +#define PAGE_CACHE 2 +#define PAGE_RESERVED 3 + +typedef uintptr_t phys_addr_t; // 節點結構,代表自由區塊 +typedef struct page { + struct page *prev, *next; // 指向同一 order 的下一個節點 + unsigned long order; + uint8_t status; // 0: free, 1: allocated +} page_t; + +void buddy_init(phys_addr_t start, phys_addr_t end); +page_t *alloc_pages(unsigned long order); +void free_pages(page_t *page, unsigned long order); + +phys_addr_t get_addr_by_page(page_t *page); +page_t *get_page_by_addr(phys_addr_t addr); + +void memory_reserve(phys_addr_t, phys_addr_t); + +#endif diff --git a/lab7/kernel/sched.h b/lab7/kernel/sched.h new file mode 100644 index 000000000..19ac3ca99 --- /dev/null +++ b/lab7/kernel/sched.h @@ -0,0 +1,70 @@ +#ifndef SCHED_H +#define SCHED_H + +#include +#include +#include + +#define STACK_SIZE 4096 + +struct thread_struct { + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + unsigned long fp; + unsigned long lr; + unsigned long sp; +}; + +enum task_state { + TASK_RUNNING, + TASK_STOPPED, + EXIT_ZOMBIE, +}; + +struct task_struct { + struct thread_struct context; + unsigned long pid; + // unsigned long parent_pid; + // unsigned long child_count; + enum task_state state; + void *stack; + void *user_stack; + void (*sighand[NSIG + 1])(); + int sigpending; + int sighandling; + trap_frame sigframe; + void *sig_stack; + struct task_struct *prev; + struct task_struct *next; + + char cwd[256]; + struct fdtable fdtable; +}; + +typedef struct task_queue_t { + struct task_struct *front; + struct task_struct *rear; +} task_queue_t; + +extern struct task_struct *get_current(); +struct task_struct *get_task(int pid); +void kthread_init(); +struct task_struct *kthread_create(void (*func)()); +void kthread_exit(); +void kthread_stop(int pid); +void schedule(); +void idle(); +void kill_zombies(); + +void display_run_queue(); +void thread_test(); + +#endif // SCHED_H diff --git a/lab7/kernel/signal.c b/lab7/kernel/signal.c new file mode 100644 index 000000000..980899fd4 --- /dev/null +++ b/lab7/kernel/signal.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +extern void sigreturn(); // Defined in entry.S + +void signal(int signum, void (*handler)()) +{ + get_current()->sighand[signum] = handler; +} + +void sigkill(int pid, int sig) +{ + struct task_struct *task = get_task(pid); + task->sigpending |= 1 << (sig - 1); // Set the signal pending bit +} + +void do_signal(trap_frame *regs) +{ + // Prevent nested signal handling + if (get_current()->sighandling) + return; + + int signum = 1; + while (get_current()->sigpending) { + if (get_current()->sigpending & 0x1) { + get_current()->sigpending &= ~(0x1); // make sure that we not handling the same signal again + get_current()->sighandling = 1; + + if (get_current()->sighand[signum] == 0) { + kthread_exit(); // Default handler (exit the process) + get_current()->sighandling = 0; + return; // Jump to the previous context (user program) after eret + } + + // Save the sigframe + memcpy(&get_current()->sigframe, regs, sizeof(trap_frame)); + get_current()->sig_stack = kmalloc(STACK_SIZE); + regs->x30 = (unsigned long)sigreturn; + regs->spsr_el1 = 0x0; + regs->elr_el1 = (unsigned long)get_current()->sighand[signum]; + regs->sp_el0 = (unsigned long)get_current()->sig_stack + STACK_SIZE; + return; // Jump to the signal handler after eret + } + signum++; + get_current()->sigpending >>= 1; + } +} diff --git a/lab7/kernel/signal.h b/lab7/kernel/signal.h new file mode 100644 index 000000000..913de9e3a --- /dev/null +++ b/lab7/kernel/signal.h @@ -0,0 +1,13 @@ + +#ifndef SIGNAL_H +#define SIGNAL_H + +#include + +#define NSIG 10 + +void signal(int signum, void (*handler)()); +void sigkill(int pid, int sig); +void do_signal(trap_frame *regs); + +#endif diff --git a/lab7/kernel/simple.c b/lab7/kernel/simple.c new file mode 100644 index 000000000..d22781d2b --- /dev/null +++ b/lab7/kernel/simple.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +extern uint64_t __heap_start; +#define HEAP_MAX (&__heap_start) + 0x100000 + +static char *heap_top; + +void init_memory() { + heap_top = (char *)(&__heap_start); + // heap_top++; +} + +void *simple_malloc(unsigned int size) { + if (size == 0) { + return NULL; + } + size = align4(size); + if (heap_top + size >= HEAP_MAX) { + puts("Out of memory\n"); + return NULL; + } + void *ret = heap_top; + heap_top += size; + return ret; +} + +char *get_heap_top() { return heap_top; } diff --git a/lab7/kernel/syscall.c b/lab7/kernel/syscall.c new file mode 100644 index 000000000..b80521efa --- /dev/null +++ b/lab7/kernel/syscall.c @@ -0,0 +1,313 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void child_ret_from_fork(); + +int sys_getpid() { return get_current()->pid; } + +size_t sys_uart_read(char *buf, size_t size) { + int i = 0; + while (i < size) buf[i++] = uart_getc(); + return i; +} + +size_t sys_uart_write(const char *buf, size_t size) { + int i = 0; + while (i < size) uart_send(buf[i++]); + return i; +} + +int sys_exec(const char *file_name, char *const argv[]) { + struct file *file; + int ret = vfs_open(file_name, O_RDWR, &file); + if (ret == -1) { + printf("\r\n[ERROR] Cannot open file: %s", file_name); + return -1; + } + + int filesize = file->vnode->f_ops->getsize(file->vnode); + void *user_program = kmalloc(filesize); + + if (user_program == NULL) { + printf("\r\n[ERROR] Cannot allocate memory for file: %s", file_name); + return -1; + } + + vfs_read(file, user_program, filesize); + vfs_close(file); + + get_current()->state = TASK_STOPPED; + vfs_read(file, user_program, filesize); + get_current()->sigpending = 0; + memset(get_current()->sighand, 0, sizeof(get_current()->sighand)); + get_current()->context.lr = (unsigned long)user_program; + return 0; +} + +int sys_fork(trap_frame *tf) { + /*lock();*/ + struct task_struct *parent = get_current(); + struct task_struct *child = kthread_create(0); + + // child->parent_pid = parent->pid; + // parent->child_count++; + // Copy the parent's memory + memcpy(child->stack, parent->stack, STACK_SIZE); + memcpy(child->user_stack, parent->user_stack, STACK_SIZE); + memcpy(child->sighand, parent->sighand, sizeof(parent->sighand)); + + unsigned long sp_off = (unsigned long)tf - (unsigned long)parent->stack; + trap_frame *child_trap_frame = (trap_frame *)(child->stack + sp_off); + + child->context.sp = (unsigned long)child_trap_frame; + child->context.lr = (unsigned long)child_ret_from_fork; + + unsigned long sp_el0_off = tf->sp_el0 - (unsigned long)parent->user_stack; + child_trap_frame->sp_el0 = (unsigned long)child->user_stack + sp_el0_off; + child_trap_frame->x0 = 0; + + strcpy(child->cwd, parent->cwd); + for (int i = 0; i < MAX_FD; i++) { + if (parent->fdtable.fds[i]) { + child->fdtable.fds[i] = kmalloc(sizeof(struct file)); + *child->fdtable.fds[i] = *parent->fdtable.fds[i]; + } + } + + /*unlock();*/ + return child->pid; +} + +void sys_exit() { kthread_exit(); } + +int sys_mbox_call(unsigned char ch, unsigned int *mbox) { + return mailbox_call(ch, mbox); +} + +void sys_kill(int pid) { kthread_stop(pid); } + +void sys_signal(int signum, void (*handler)()) { signal(signum, handler); } + +void sys_sigkill(int pid, int sig) { sigkill(pid, sig); } + +void sys_sigreturn(trap_frame *regs) { + // Restore the sigframe + memcpy(regs, &get_current()->sigframe, sizeof(trap_frame)); + kfree(get_current()->sig_stack); + get_current()->sighandling = 0; + return; // Jump to the previous context (user program) after eret +} + +// emit the syscall instruction +static int getpid() { + long pid = -1; + asm volatile("mov x8, 0"); + asm volatile("svc 0"); + asm volatile("mov %0, x0" : "=r"(pid)); + return pid; +} + +static int fork() { + long ret = -1; + asm volatile("mov x8, 4"); + asm volatile("svc 0"); + asm volatile("mov %0, x0" : "=r"(ret)); + return ret; +} + +static void exit() { + asm volatile("mov x8, 5"); + asm volatile("svc 0"); +} + +void fork_test() { + puts("Fork Test (pid = "); + print_d(getpid()); + puts(")\n"); + int cnt = 1; + int ret = 0; + + if ((ret = fork()) == 0) { + puts("first child pid: "); + print_d(getpid()); + puts(", cnt: "); + print_d(cnt); + puts(", ptr: "); + print_h((unsigned long long)&cnt); + puts("\n"); + cnt++; + if ((ret = fork()) != 0) { + puts("first child pid: "); + print_d(getpid()); + puts(", cnt: "); + print_d(cnt); + puts(", ptr: "); + print_h((unsigned long long)&cnt); + puts("\n"); + } else { + while (cnt < 5) { + puts("second child pid: "); + print_d(getpid()); + puts(", cnt: "); + print_d(cnt); + puts(", ptr: "); + print_h((unsigned long long)&cnt); + puts("\n"); + + for (int i = 0; i < 1000000; i++); + cnt++; + } + } + exit(); + } else { + puts("parent here, pid "); + print_d(getpid()); + puts(", child "); + print_d(ret); + puts("\n"); + } + exit(); +} + +void run_fork_test() { + asm volatile("msr spsr_el1, %0" ::"r"(0x0)); + asm volatile("msr elr_el1, %0" ::"r"(fork_test)); + asm volatile("msr sp_el0, %0" ::"r"(get_current()->context.sp)); + asm volatile("mov sp, %0" ::"r"(get_current()->stack + STACK_SIZE)); + asm volatile("eret"); +} + +int sys_open(trap_frame *tf, const char *pathname, int flags) { + /*printf("\r\n[SYSCALL] open - cwd: %s\r\n", get_current()->cwd);*/ + /*printf("\r\n[SYSCALL] open-1 - path: %s, flags: %x\r\n", pathname, flags);*/ + char abs_path[MAX_PATH_NAME]; + strcpy(abs_path, pathname); + // update abs_path + get_absolute_path(abs_path, get_current()->cwd); + /*printf("\r\n[SYSCALL] open-2 - path: %s, flags: %x\r\n", abs_path, + * flags);*/ + for (int i = 0; i < MAX_FD; i++) { + // find a usable fd + if (!get_current()->fdtable.fds[i]) { + /*printf("\r\n[SYSCALL] open-3 - fd index: %d\r\n", i);*/ + if (vfs_open(abs_path, flags, &get_current()->fdtable.fds[i]) != + 0) { + break; + } + + tf->x0 = i; + return i; + } + } + + tf->x0 = -1; + return -1; +} + +int sys_close(trap_frame *tf, int fd) { + /*printf("\r\n[SYSCALL] close - fd: %d\r\n", fd);*/ + // find an opened fd + if (get_current()->fdtable.fds[fd]) { + vfs_close(get_current()->fdtable.fds[fd]); + get_current()->fdtable.fds[fd] = 0; + tf->x0 = 0; + return 0; + } + + tf->x0 = -1; + return -1; +} + +long sys_write(trap_frame *tf, int fd, const void *buf, unsigned long count) { + /*printf("\r\n[SYSCALL] write - fd: %d, buf: %x, count: %d\r\n", fd, buf, + * count);*/ + // find an opened fd + if (get_current()->fdtable.fds[fd]) { + tf->x0 = vfs_write(get_current()->fdtable.fds[fd], buf, count); + return tf->x0; + } + + tf->x0 = -1; + return tf->x0; +} + +long sys_read(trap_frame *tf, int fd, void *buf, unsigned long count) { + /*printf("\r\n[SYSCALL] read - fd: %d, buf: %x, count: %d\r\n", fd, buf, + * count);*/ + // find an opened fd + if (get_current()->fdtable.fds[fd]) { + tf->x0 = vfs_read(get_current()->fdtable.fds[fd], buf, count); + return tf->x0; + } + + tf->x0 = -1; + return tf->x0; +} + +long sys_mkdir(trap_frame *tf, const char *pathname, unsigned mode) { + /*printf("\r\n[SYSCALL] mkdir - path: %s, mode: %x\r\n", pathname, mode);*/ + char abs_path[MAX_PATH_NAME]; + strcpy(abs_path, pathname); + get_absolute_path(abs_path, get_current()->cwd); + tf->x0 = vfs_mkdir(abs_path); + return tf->x0; +} + +long sys_mount(trap_frame *tf, const char *src, const char *target, + const char *filesystem, unsigned long flags, const void *data) { + /*printf(*/ + /* "\r\n[SYSCALL] mount - src: %s, target: %s, filesystem: %s, flags: %x\r\n",*/ + /* src, target, filesystem, flags);*/ + char abs_path[MAX_PATH_NAME]; + strcpy(abs_path, target); + /*printf("\r\n[SYSCALL] mount - abs_path: %s\r\n", abs_path);*/ + + tf->x0 = vfs_mount(abs_path, filesystem); + return tf->x0; +} + +long sys_chdir(trap_frame *tf, const char *path) { + /*printf("\r\n[SYSCALL] chdir - path: %s\r\n", path);*/ + char abs_path[MAX_PATH_NAME]; + strcpy(abs_path, path); + get_absolute_path(abs_path, get_current()->cwd); + strcpy(get_current()->cwd, abs_path); + + return 0; +} + +long sys_lseek64(trap_frame *tf, int fd, long offset, int whence) { + /*printf("\r\n[SYSCALL] lseek64 - fd: %d, offset: %d, whence: %d\r\n", fd, + * offset, whence);*/ + if (whence == SEEK_SET) // used for dev_framebuffer + { + get_current()->fdtable.fds[fd]->f_pos = offset; + tf->x0 = offset; + } else // other is not supported + { + tf->x0 = -1; + } + + return tf->x0; +} + +// 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(trap_frame *tf, int fb, unsigned long request, void *info) { + /*printf("\r\n[SYSCALL] ioctl - fb: %d, request: %x, info: %x\r\n", fb, + * request, info);*/ + tf->x0 = 0; + return tf->x0; +} diff --git a/lab7/kernel/syscall.h b/lab7/kernel/syscall.h new file mode 100644 index 000000000..1cdc088a3 --- /dev/null +++ b/lab7/kernel/syscall.h @@ -0,0 +1,32 @@ + +#ifndef syscall_h +#define syscall_h + +#include +#include + +int sys_getpid(); +size_t sys_uart_read(char *buf, size_t size); +size_t sys_uart_write(const char *buf, size_t size); +int sys_exec(const char *name, char *const argv[]); +int sys_fork(trap_frame *tf); +void sys_exit(); +int sys_mbox_call(unsigned char ch, unsigned int *mbox); +void sys_kill(int pid); +void sys_signal(int signum, void (*handler)()); +void sys_sigkill(int pid, int sig); +void sys_sigreturn(trap_frame *regs); +void run_fork_test(); + +int sys_open(trap_frame *tf, const char *pathname, int flags); +int sys_close(trap_frame *tf, int fd); +long sys_write(trap_frame *tf, int fd, const void *buf, unsigned long count); +long sys_read(trap_frame *tf, int fd, void *buf, unsigned long count); +long sys_mkdir(trap_frame *tf, const char *pathname, unsigned mode); +long sys_mount(trap_frame *tf, const char *src, const char *target, + const char *filesystem, unsigned long flags, const void *data); +long sys_chdir(trap_frame *tf, const char *path); +long sys_lseek64(trap_frame *tf, int fd, long offset, int whence); +long sys_ioctl(trap_frame *tf, int fb, unsigned long request, void *info); + +#endif diff --git a/lab7/kernel/task.c b/lab7/kernel/task.c new file mode 100644 index 000000000..00f4665d1 --- /dev/null +++ b/lab7/kernel/task.c @@ -0,0 +1,151 @@ +#include +#include +#include +#include +#include + +static int thread_count = 0; +static struct task_struct *run_queue; + +extern void switch_to(struct task_struct *prev, struct task_struct *next); + +static void enqueue(struct task_struct **queue, struct task_struct *task) { + if (*queue == 0) { + *queue = task; + task->next = task; + task->prev = task; + } else { + task->next = *queue; + task->prev = (*queue)->prev; + (*queue)->prev->next = task; + (*queue)->prev = task; + } +} + +static void remove(struct task_struct **queue, struct task_struct *task) { + if (*queue == task) *queue = (task->next == task) ? 0 : task->next; + task->next->prev = task->prev; + task->prev->next = task->next; +} + +void display_run_queue() { + struct task_struct *task = run_queue; + do { + puts("Task id: "); + print_d(task->pid); + puts(", state: "); + print_d(task->state); + puts(", next: "); + print_d(task->next->pid); + puts("\n"); + task = task->next; + } while (task != run_queue); +} + +void schedule() { + struct task_struct *current = get_current(); + struct task_struct *next = current->next; + + while (next->state != TASK_RUNNING) { + next = next->next; + } + + // display_run_queue(); + // puts("Scheduling from: "); + // print_d(current->pid); + // puts(" -> "); + // print_d(next->pid); + // puts("\n"); + + switch_to(current, current->next); +} + +void kill_zombies() { + // puts("Killing zombies\n"); + // display_run_queue(); + struct task_struct *next, *task = run_queue; + do { + next = task->next; + if (task->state == EXIT_ZOMBIE) { + remove(&run_queue, task); + kfree(task->stack); + kfree(task->user_stack); + } + task = next; + } while (task != run_queue); +} + +void idle() { + while (1) { + kill_zombies(); + schedule(); + } +} + +struct task_struct *get_task(int pid) { + struct task_struct *task = run_queue; + do { + if (task->pid == pid) return task; + task = task->next; + } while (task != run_queue); + return 0; +} + +void kthread_init() { + kthread_create(idle); + asm volatile("msr tpidr_el1, %0" ::"r"(run_queue)); + // display_run_queue(); +} + +struct task_struct *kthread_create(void (*func)()) { + /*lock();*/ + struct task_struct *task = kmalloc(sizeof(struct task_struct)); + task->pid = thread_count++; + task->state = TASK_RUNNING; + task->stack = kmalloc(STACK_SIZE); + task->user_stack = kmalloc(STACK_SIZE); + memset(task->sighand, 0, sizeof(task->sighand)); + task->sigpending = 0; + task->sighandling = 0; + task->context.lr = (unsigned long)func; + task->context.sp = (unsigned long)task->user_stack + STACK_SIZE; + task->context.fp = (unsigned long)task->user_stack + STACK_SIZE; + strcpy(task->cwd, "/"); + + task->fdtable.count = 0; + for (int i = 0; i < MAX_FD; i++) task->fdtable.fds[i] = NULL; + vfs_open("/dev/uart", O_RDWR, &task->fdtable.fds[0]); // stdin + vfs_open("/dev/uart", O_RDWR, &task->fdtable.fds[1]); // stdout + vfs_open("/dev/uart", O_RDWR, &task->fdtable.fds[2]); // stderr + + enqueue(&run_queue, task); + /*unlock();*/ + return task; +} + +void kthread_exit() { + get_current()->state = EXIT_ZOMBIE; + schedule(); +} + +void kthread_stop(int pid) { + struct task_struct *task = run_queue; + do { + if (task->pid == pid) task->state = EXIT_ZOMBIE; + task = task->next; + } while (task != run_queue); + schedule(); +} + +void thread_test() { + for (int i = 0; i < 5; ++i) { + puts("Thread id: "); + print_d(get_current()->pid); + puts(" "); + print_d(i); + puts("\n"); + for (int i = 0; i < 1000000; i++); + schedule(); + } + kthread_exit(); +} diff --git a/lab7/kernel/timer.c b/lab7/kernel/timer.c new file mode 100644 index 000000000..74bb771c7 --- /dev/null +++ b/lab7/kernel/timer.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include + +typedef struct timer_t { + void (*func)(void *); + void *arg; + int time; + struct timer_t *next; +} timer_t; + +static timer_t *head = (timer_t *)0; + +void set_timeout(void (*callback)(void *), void *arg, int delay) { + timer_t *timer = (timer_t *)kmalloc(sizeof(timer_t)); + // timer_t *timer = (timer_t *)kmalloc(STACK_SIZE); +#ifdef TIMER_DEBUG + puts("\n[set_timeout] timer_t allocated at "); + print_h((unsigned long)timer); + puts("\n"); + puts("[set_timeout] head: "); + print_h((unsigned long)head); + puts("\n"); +#endif /* ifdef TIMER_DEBUG */ + + timer->func = callback; + timer->arg = arg; + timer->time = timer_get_uptime() + delay; + timer->next = 0; + + if (head == 0 || timer->time < head->time) { + // Insert at the beginning of the list + timer->next = head; + head = timer; + core_timer_enable(); + return; + } + + timer_t *current = head; + while (current->next != 0 && current->next->time <= timer->time) + current = current->next; + timer->next = current->next; + current->next = timer; +} + +static void empty() {} + +void timer_irq_handler() { + // puts("\n[timer_irq_handler] \n"); + // puts("Current task: "); + // print_d(get_current()->pid); + // puts("\n"); +#ifdef SCHED_DEBUG + static int count = 0; + if (count++ % 1 == 0) { + puts("\n[timer_irq_handler] \n"); + print_task_list(); + } +#endif + + set_timeout(&empty, 0, 1); // 1s for task switch + + // Check the timer queue + while (head != 0 && timer_get_uptime() >= head->time) { + head->func(head->arg); + timer_t *temp = head; + head = head->next; + kfree(temp); // if free this multi_thread will crash + } + + if (head != 0) core_timer_enable(); +} diff --git a/lab7/kernel/timer.h b/lab7/kernel/timer.h new file mode 100644 index 000000000..41c3a05b3 --- /dev/null +++ b/lab7/kernel/timer.h @@ -0,0 +1,11 @@ +#ifndef __TIMER_H__ +#define __TIMER_H__ + +#include +#include + +void set_timeout(void (*callback)(void *), void *arg, int after); +void timer_irq_handler(); +void enable_user_to_physical_timer(); + +#endif diff --git a/lab7/lib/limits.h b/lab7/lib/limits.h new file mode 100644 index 000000000..36f8e3237 --- /dev/null +++ b/lab7/lib/limits.h @@ -0,0 +1,7 @@ +#ifndef _LIMITS_H +#define _LIMITS_H + +#define INT_MAX 2147483647 +#define INT_MIN -2147483648 + +#endif diff --git a/lab7/lib/sprintf.c b/lab7/lib/sprintf.c new file mode 100644 index 000000000..bcf48cbb0 --- /dev/null +++ b/lab7/lib/sprintf.c @@ -0,0 +1,147 @@ +#include + +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +/** + * minimal sprintf implementation + * Use the built-in va_list, va_start, va_arg, va_end macros to parse the parameters from `char* fmt`. + */ +unsigned int vsprintf(char *dst, const char *fmt, __builtin_va_list args) +{ + long int arg; + int len, sign, i; + char *p, *orig=dst, tmpstr[19]; + + /* failsafes */ + if (dst == (void *) 0 || fmt == (void *) 0) { + return 0; + } + + /* main loop */ + arg = 0; + while (*fmt) { + // argument access + if (*fmt == '%') { // %d, %x, %s, %c + fmt++; + // literal % + if(*fmt == '%') { + goto put; + } + len = 0; + // size modifier + while(*fmt >= '0' && *fmt <= '9') { + len *= 10; + len += *fmt - '0'; + fmt++; + } + // skip long modifier + if(*fmt == 'l') { + fmt++; + } + // character + if(*fmt == 'c') { + arg = __builtin_va_arg(args, int); // use int to get char + *dst++ = (char) arg; + fmt++; + continue; + } else + // decimal number + if(*fmt == 'd') { + arg = __builtin_va_arg(args, int); + // check input + sign = 0; + if((int) arg < 0) { + arg *= -1; + sign++; + } + if(arg > 99999999999999999L) { + arg = 99999999999999999L; + } + // convert to string + i = 18; + tmpstr[i] = 0; + do { + tmpstr[--i] = '0' + (arg % 10); + arg /= 10; + } while (arg != 0 && i > 0); + if (sign) { + tmpstr[--i] = '-'; + } + // padding, only space + if (len > 0 && len < 18) { + while (i > 18 - len) { + tmpstr[--i] = ' '; + } + } + p = &tmpstr[i]; + goto copystring; + } else if (*fmt == 'x') { // hex number + arg = __builtin_va_arg(args, long int); + // convert to string + i = 16; + tmpstr[i] = 0; + do { + char n = arg & 0xf; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + tmpstr[--i] = n + (n > 9 ? 0x37 : 0x30); + arg >>= 4; + } while (arg != 0 && i > 0); + // padding, only leading zeros + if (len > 0 && len <= 16) { + while (i > 16 - len) { + tmpstr[--i] = '0'; + } + } + p = &tmpstr[i]; + goto copystring; + } else if (*fmt == 's') { // string + p = __builtin_va_arg(args, char*); +copystring: if (p == (void *) 0) { + p = "(null)"; + } + while (*p) { + *dst++ = *p++; + } + } + } else { // without '%', just copy to *dst +put: *dst++ = *fmt; + } + fmt++; + } + *dst = 0; + // number of bytes written + return dst - orig; +} + +/** + * Variable length arguments + */ +unsigned int sprintf(char *dst, const char* fmt, ...) +{ + __builtin_va_list args; + __builtin_va_start(args, fmt); // generate the va_list from fmt. + return vsprintf(dst, fmt, args); +} diff --git a/lab7/lib/stddef.h b/lab7/lib/stddef.h new file mode 100644 index 000000000..79fc8e514 --- /dev/null +++ b/lab7/lib/stddef.h @@ -0,0 +1,13 @@ +#ifndef _STDDEF_H_ +#define _STDDEF_H_ + +#define NULL ((void *)0) + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef uint64_t uintptr_t; +typedef unsigned long long size_t; + +#endif diff --git a/lab7/lib/stdlib.c b/lab7/lib/stdlib.c new file mode 100644 index 000000000..d583af908 --- /dev/null +++ b/lab7/lib/stdlib.c @@ -0,0 +1,41 @@ +#include + +int atoi(const char *s) { + long long result = 0; // prevent overflow + int sign = 1; + int i = 0; + + while (s[i] == ' ') i++; + + if (s[i] == '-') { + sign = -1; + i++; + } else if (s[i] == '+') + i++; + + while (s[i] >= '0' && s[i] <= '9') { + result = result * 10 + (s[i] - '0'); + i++; + } + + return sign * (int)result; +} + +void itoa(int value, char *str) { + int i = 0; + int sign = value; + if (value < 0) value = -value; + do { + str[i++] = value % 10 + '0'; + } while ((value /= 10) > 0); + if (sign < 0) str[i++] = '-'; + str[i] = '\0'; + + // reverse + for (int j = 0; j < i / 2; j++) { + char temp = str[j]; + str[j] = str[i - j - 1]; + str[i - j - 1] = temp; + } +} + diff --git a/lab7/lib/stdlib.h b/lab7/lib/stdlib.h new file mode 100644 index 000000000..a3ce0b866 --- /dev/null +++ b/lab7/lib/stdlib.h @@ -0,0 +1,7 @@ +#ifndef _STDLIB_H +#define _STDLIB_H + +int atoi(const char *); +void itoa(int value, char *str); + +#endif diff --git a/lab7/lib/string.c b/lab7/lib/string.c new file mode 100644 index 000000000..da45afdee --- /dev/null +++ b/lab7/lib/string.c @@ -0,0 +1,107 @@ +#include +#include + +int strcmp(const char *a, const char *b) { + while (*a && (*a == *b)) { + a++, b++; + } + return *(const unsigned char *)a - *(const unsigned char *)b; +} + +char* strcat (char *dest, const char *src) +{ + strcpy (dest + strlen (dest), src); + return dest; +} + +char *strcpy(char *dest, const char *src) { + char *start = dest; + + while (*src != '\0') { + *dest = *src; + dest++; + src++; + } + + *dest = '\0'; + return start; +} + +char *strncpy(char *dest, const char *src, int n) { + char *start = dest; + while (*src != '\0' && n > 0) { + *dest = *src; + dest++; + src++; + n--; + } + *dest = '\0'; + return start; +} + +void *memcpy(void *dest, const void *src, int n) +{ + char *d = dest; + const char *s = src; + while (n--) + *d++ = *s++; + return dest; +} + +void *memset(void *s, int c, size_t n) { + unsigned char *p = (unsigned char *)s; + while (n--) { + *p++ = (unsigned char)c; + } + return s; +} + +int strlen(const char *str) { + int len = 0; + while (*str) { + str++; + len++; + } + return len; +} + +char *strtok(char *s, const char *delim) { + char *spanp; + int c, sc; + char *tok; + static char *last; + + if (s == NULL && (s = last) == NULL) { + return NULL; + } + + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++);) { + if (c == sc) { + c = *s++; + spanp = (char *)delim; + } + } + + if (c == 0) { + last = NULL; + return (NULL); + } + tok = s - 1; + + while (1) { + c = *s++; + spanp = (char *)delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) { + s = NULL; + } else { + s[-1] = 0; + } + last = s; + return (tok); + } + } while (sc != 0); + } +} diff --git a/lab7/lib/string.h b/lab7/lib/string.h new file mode 100644 index 000000000..5c9a946ba --- /dev/null +++ b/lab7/lib/string.h @@ -0,0 +1,15 @@ +#ifndef _STRING_H +#define _STRING_H + +#include + +int strcmp(const char *a, const char *b); +char *strcat(char *dest, const char *src); +char *strcpy(char *dst, const char *src); +char *strncpy(char *dst, const char *src, int n); +void *memcpy(void *dest, const void *src, int n); +void *memset(void *str, int c, size_t n); +int strlen(const char *s); +char* strtok(char* str, const char* delim); + +#endif diff --git a/lab7/lib/utils.c b/lab7/lib/utils.c new file mode 100644 index 000000000..ce920acff --- /dev/null +++ b/lab7/lib/utils.c @@ -0,0 +1,3 @@ +#include + +int align4(int n) { return n + (4 - n % 4) % 4; } diff --git a/lab7/lib/utils.h b/lab7/lib/utils.h new file mode 100644 index 000000000..aabe00f9d --- /dev/null +++ b/lab7/lib/utils.h @@ -0,0 +1,9 @@ +#ifndef _UTILS_H +#define _UTILS_H + +unsigned int sprintf(char *dst, const char *fmt, ...); +unsigned int vsprintf(char *dst, const char *fmt, __builtin_va_list args); + +int align4(int n); + +#endif diff --git a/lab7/rootfs/file1 b/lab7/rootfs/file1 new file mode 100644 index 000000000..9bc8d9ca0 --- /dev/null +++ b/lab7/rootfs/file1 @@ -0,0 +1 @@ +this is file1. diff --git a/lab7/rootfs/file2.txt b/lab7/rootfs/file2.txt new file mode 100644 index 000000000..f1adef63c --- /dev/null +++ b/lab7/rootfs/file2.txt @@ -0,0 +1 @@ +nothing here diff --git a/lab7/user_program/Makefile b/lab7/user_program/Makefile new file mode 100644 index 000000000..5e2780f44 --- /dev/null +++ b/lab7/user_program/Makefile @@ -0,0 +1,18 @@ +ARMGNU ?= aarch64-linux-gnu + +all: test_svc_exception.img + +test_svc_exception.img: test_svc_exception.o + $(ARMGNU)-ld -o test_svc_exception.elf test_svc_exception.o + $(ARMGNU)-objcopy test_svc_exception.elf -O binary test_svc_exception.img + cp ./test_svc_exception.img ../rootfs/ + (cd ../rootfs/ && find . | cpio -o -H newc > ../initramfs.cpio) + +test_svc_exception.o: test_svc_exception.S + $(ARMGNU)-gcc -MMD -c $< -o $@ + +clean: + rm -f *.o *.d *.elf *.img + +dump: test_svc_exception.img + qemu-aarch64 -M raspi3 -kernel test_svc_exception.img -display none -d in_asm diff --git a/lab7/user_program/linker.ld b/lab7/user_program/linker.ld new file mode 100644 index 000000000..e69de29bb diff --git a/lab7/user_program/test_svc_exception.S b/lab7/user_program/test_svc_exception.S new file mode 100644 index 000000000..ce7e53908 --- /dev/null +++ b/lab7/user_program/test_svc_exception.S @@ -0,0 +1,11 @@ +.section ".text" +.global _start +_start: + mov x0, 0 +1: + add x0, x0, 1 + svc 0 + cmp x0, 5 + blt 1b +1: + b 1b