diff --git a/Makefile b/Makefile index 7685c1662..f4067da16 100644 --- a/Makefile +++ b/Makefile @@ -101,6 +101,7 @@ define _run_qemu_base $(QEMU) -M raspi3 \ -drive if=sd,file=./res/sdcard/sfn_nctuos.img,format=raw \ -initrd $(INIT_RAM_FS) \ + -d int\ -display none endef diff --git a/impl-c/dev/mbr.c b/impl-c/dev/mbr.c index 1ae726ead..21488f55c 100644 --- a/impl-c/dev/mbr.c +++ b/impl-c/dev/mbr.c @@ -1,7 +1,7 @@ #include "dev/mbr.h" #include "dev/sd.h" -#include "mm.h" +#include "memory.h" #include "stdint.h" #include "uart.h" diff --git a/impl-c/dev/uart.c b/impl-c/dev/uart.c index eb2253812..08e30b899 100644 --- a/impl-c/dev/uart.c +++ b/impl-c/dev/uart.c @@ -141,6 +141,7 @@ void uart_println(char *fmt, ...) { int64_t i; char *s; char c; + uint64_t ui; va_list arg; va_start(arg, fmt); @@ -163,9 +164,9 @@ void uart_println(char *fmt, ...) { uart_puts(itoa(i, 10)); break; case 'x': - i = va_arg(arg, int); + ui = va_arg(arg, uint64_t); uart_puts("0x"); - uart_puts(itoa((int64_t)i, 16)); + uart_puts(itoa((uint64_t)ui, 16)); break; case 'c': c = va_arg(arg, int); @@ -187,6 +188,8 @@ void uart_println(char *fmt, ...) { // same as println, but without a newline at the end void uart_printf(char *fmt, ...) { int64_t i; + uint64_t ui; + char *s; char c; @@ -211,9 +214,9 @@ void uart_printf(char *fmt, ...) { uart_puts(itoa(i, 10)); break; case 'x': - i = va_arg(arg, int); + ui = va_arg(arg, uint64_t); uart_puts("0x"); - uart_puts(itoa((int64_t)i, 16)); + uart_puts(itoa(ui, 16)); break; case 'c': c = va_arg(arg, int); diff --git a/impl-c/fs/fat.c b/impl-c/fs/fat.c index 389b85fe7..7137b0394 100644 --- a/impl-c/fs/fat.c +++ b/impl-c/fs/fat.c @@ -5,8 +5,8 @@ #include "dev/sd.h" #include "fatal.h" +#include "memory.h" #include "minmax.h" -#include "mm.h" #include "stdint.h" #include "string.h" #include "uart.h" diff --git a/impl-c/fs/tmpfs.c b/impl-c/fs/tmpfs.c index 1926388f2..641e02835 100644 --- a/impl-c/fs/tmpfs.c +++ b/impl-c/fs/tmpfs.c @@ -2,8 +2,8 @@ #include "fs/vfs.h" #include "dev/cpio.h" +#include "memory.h" #include "minmax.h" -#include "mm.h" #include "stdint.h" #include "string.h" #include "uart.h" diff --git a/impl-c/fs/vfs.c b/impl-c/fs/vfs.c index e2dab8d3a..f25ddb2a4 100644 --- a/impl-c/fs/vfs.c +++ b/impl-c/fs/vfs.c @@ -1,6 +1,6 @@ #include "fs/vfs.h" -#include "mm.h" +#include "memory.h" #include "string.h" #include "uart.h" diff --git a/impl-c/gdbinit b/impl-c/gdbinit index 0f87d963d..96d7bd788 100644 --- a/impl-c/gdbinit +++ b/impl-c/gdbinit @@ -2,5 +2,6 @@ file impl-c/kernel8.elf dir impl-c target remote :1234 + tui enable -si \ No newline at end of file +si diff --git a/impl-c/include/config.h b/impl-c/include/config.h index d4d42a781..f380b5641 100644 --- a/impl-c/include/config.h +++ b/impl-c/include/config.h @@ -11,19 +11,20 @@ // #define CFG_LOG_SHELL_CMD // #define CFG_LOG_SHELL_BUFFER // #define CFG_LOG_MEM_STARTUP -// #define CFG_LOG_MEM_KALLOC -// #define CFG_LOG_MEM_BUDDY -// #define CFG_LOG_MEM_SLAB -// #define CFG_LOG_PROC_TASK -// #define CFG_LOG_PROC_SCHED -// #define CFG_LOG_PROC_ARGV -// #define CFG_LOG_PROC_EXEC +#define CFG_LOG_MEM_KALLOC +#define CFG_LOG_MEM_BUDDY +#define CFG_LOG_MEM_SLAB +#define CFG_LOG_PROC_TASK +#define CFG_LOG_PROC_SCHED +#define CFG_LOG_PROC_ARGV +#define CFG_LOG_PROC_EXEC #define CFG_LOG_VFS // #define CFG_LOG_TMPFS #define CFG_LOG_TMPFS_LOOKUP #define CFG_LOG_TMPFS_DUMP_TREE #define CFG_LOG_DEV_MBR #define CFG_LOG_FAT +#define CFG_LOG_VM /** * TEST @@ -34,14 +35,14 @@ #define CFG_RUN_LIB_STRING_TEST // Shell -// #define CFG_RUN_SHELL_BUFFER_TEST -// #define CFG_RUN_SHELL_CMD_TEST +#define CFG_RUN_SHELL_BUFFER_TEST +#define CFG_RUN_SHELL_CMD_TEST // Memory management -// #define CFG_RUN_STATUP_ALLOC_TEST +#define CFG_RUN_STATUP_ALLOC_TEST // PROC -// #define CFG_RUN_PROC_ARGV_TEST +#define CFG_RUN_PROC_ARGV_TEST // DEV #define CFG_RUN_DEV_MBR_TEST diff --git a/impl-c/include/dev/mmio.h b/impl-c/include/dev/mmio.h index 8229a68e2..fe5976b61 100644 --- a/impl-c/include/dev/mmio.h +++ b/impl-c/include/dev/mmio.h @@ -1,3 +1,3 @@ #pragma once - -#define MMIO_BASE 0x3F000000 +#include "mm/vm.h" +#define MMIO_BASE (KVA_START + 0x3F000000) diff --git a/impl-c/include/libs/const.h b/impl-c/include/libs/const.h new file mode 100644 index 000000000..8ef04cea0 --- /dev/null +++ b/impl-c/include/libs/const.h @@ -0,0 +1,9 @@ +#pragma once + +#define CONST_1K 1024 +#define CONST_4K (4 * CONST_1K) + +#define CONST_1M (CONST_1K * CONST_1K) +#define CONST_2M (2 * CONST_1M) + +#define CONST_1G (CONST_1K * CONST_1M) \ No newline at end of file diff --git a/impl-c/include/libs/string.h b/impl-c/include/libs/string.h index 17c0d88f1..6adfc100e 100644 --- a/impl-c/include/libs/string.h +++ b/impl-c/include/libs/string.h @@ -9,7 +9,7 @@ char *strcpy(char *dst, const char *src); void memcpy(char *dst, const char *src, size_t n); const char *strchr(const char *s, const char c); -char *itoa(int64_t val, int base); +char *itoa(uint64_t val, int base); // Return the fitst char in `s` not being `c` const char *ignore_leading(const char *s, const char c); diff --git a/impl-c/include/memory.h b/impl-c/include/memory.h new file mode 100644 index 000000000..7d9bd2d86 --- /dev/null +++ b/impl-c/include/memory.h @@ -0,0 +1,19 @@ +#pragma once + +/** + * Memory.h + * Provide interface for dynamic memory allocation + */ + +// Allocate a block of memory to use in kernel space (KVA) +void *kalloc(int size); + +// Free a memory block (KVA) +void kfree(void *addr); + +// Initialize dynamic memory allocator +void KAllocManager_init(); +void KAllocManager_show_status(); + +// Run several allocation/free as an example +void KAllocManager_run_example(); \ No newline at end of file diff --git a/impl-c/include/mm/alloc.h b/impl-c/include/mm/alloc.h index 6d0de3854..45880280f 100644 --- a/impl-c/include/mm/alloc.h +++ b/impl-c/include/mm/alloc.h @@ -1,11 +1,38 @@ #pragma once +/** + * Buddy & slab allocators + */ -#include "list.h" -#include "mm/const.h" #include "mm/frame.h" #include "mm/startup.h" +#include "mm/vm.h" + +#include "list.h" #include +#define SLAB_NUM_SLAB_SIZES 6 + +#define BUDDY_MAX_EXPONENT 18 // 1GB +// #define BUDDY_MAX_EXPONENT 10 +// #define BUDDY_MAX_EXPONENT 5 + +#define BUDDY_NUM_FREE_LISTS (BUDDY_MAX_EXPONENT + 1) +#define MEMORY_START KVA_START + +// SlabAllocator +// manage slabs with the same allocation size, +// A slab is a frame allocated with small objects with same size +// + @SLAB_MAX_SLOTS: The number of pages available for a single slab +// -> Frame is 4kb by architecture. +// CortexA53 is 16 bytes aligned, so the here 16 bytes is set to be +// the minimum size available for objects in slab. +// -> Therefore, the maximum slots in slab is 4096/16 = 256 +#define SLAB_MAX_SLOTS 256 + +// The size of slab range from 16(2^4) to 512(2^9) bytes +#define SLAB_OBJ_MIN_SIZE_EXP 4 +#define SLAB_OBJ_MAX_SIZE_EXP 9 + typedef struct Frame { // inherit a list type, so we could cast FrameNode into list_head struct list_head list_base; diff --git a/impl-c/include/mm/const.h b/impl-c/include/mm/const.h deleted file mode 100644 index 81409bc75..000000000 --- a/impl-c/include/mm/const.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#define SLAB_NUM_SLAB_SIZES 6 - -#define BUDDY_MAX_EXPONENT 18 // 1GB -// #define BUDDY_MAX_EXPONENT 10 -// #define BUDDY_MAX_EXPONENT 5 - -#define BUDDY_NUM_FREE_LISTS (BUDDY_MAX_EXPONENT + 1) - -// #define MEMORY_START 0x90000 -#define MEMORY_START 0x0 - -// SlabAllocator -// manage slabs with the same allocation size, -// A slab is a frame allocated with small objects with same size -// + @SLAB_MAX_SLOTS: The number of pages available for a single slab -// -> Frame is 4kb by architecture. -// CortexA53 is 16 bytes aligned, so the here 16 bytes is set to be -// the minimum size available for objects in slab. -// -> Therefore, the maximum slots in slab is 4096/16 = 256 -#define SLAB_MAX_SLOTS 256 - -// The size of slab range from 16(2^4) to 512(2^9) bytes -#define SLAB_OBJ_MIN_SIZE_EXP 4 -#define SLAB_OBJ_MAX_SIZE_EXP 9 \ No newline at end of file diff --git a/impl-c/include/mm/frame.h b/impl-c/include/mm/frame.h index 1f3305010..efb1c7e13 100644 --- a/impl-c/include/mm/frame.h +++ b/impl-c/include/mm/frame.h @@ -1,4 +1,8 @@ #pragma once +/** + * frame.h + * Prvide constants about physical memory frames + */ #define FRAME_SHIFT 12 // 4Kb #define FRAME_ADDR_BASE (1 << FRAME_SHIFT) diff --git a/impl-c/include/mm.h b/impl-c/include/mm/kalloc_manager.h similarity index 64% rename from impl-c/include/mm.h rename to impl-c/include/mm/kalloc_manager.h index be590719b..1e2954e6e 100644 --- a/impl-c/include/mm.h +++ b/impl-c/include/mm/kalloc_manager.h @@ -1,10 +1,10 @@ #pragma once -#include "list.h" #include "mm/alloc.h" -#include "mm/const.h" #include "mm/frame.h" #include "mm/startup.h" + +#include "list.h" #include /** @@ -24,18 +24,4 @@ typedef struct AllocationManager { // Statically linked to the heap space // because their lifetimes is equal to the system itself -extern struct Frame Frames[1 << BUDDY_MAX_EXPONENT]; - -// Allocate a memory space to use in kernel space -void *kalloc(int size); - -// Free a memory space -void kfree(void *addr); - -// Initialize dynamic memory allocator -void KAllocManager_init(); - -void KAllocManager_show_status(); - -// Run several allocation/free as an example -void KAllocManager_run_example(); \ No newline at end of file +extern struct Frame Frames[1 << BUDDY_MAX_EXPONENT]; \ No newline at end of file diff --git a/impl-c/include/mm/mmu.h b/impl-c/include/mm/mmu.h new file mode 100644 index 000000000..efc8dc04a --- /dev/null +++ b/impl-c/include/mm/mmu.h @@ -0,0 +1,124 @@ +#pragma once + +/** + * TCR: Translation Control Register, which controls + * 1. (IPS) Intermediate Physical Address Size (32/36/40/42/44/48 bits) + * 2. (TG) Translation Granule: The page size manage by MMU (4/64K) + * 3. (SZ) Number of the most significant bits that must be either all 0s or + * all 1s, or.. THe size offset of the memory region address by TTBRx_ELx + */ +#define TCR_OFFSET_T1SZ 16 +#define TCR_OFFSET_T0SZ 0 +#define TCR_TxSZ_ADDRESS_48bit (64 - 48) +#define TCR_CONFIG_REGION_48bit \ + ((TCR_TxSZ_ADDRESS_48bit << TCR_OFFSET_T0SZ) | \ + (TCR_TxSZ_ADDRESS_48bit << TCR_OFFSET_T1SZ)) + +// With a 4K granule, we expect at most 4-level page table +#define TCR_TG0_4KB (0b00 << 14) +#define TCR_TG1_4KB (0b10 << 30) +#define TCR_CONFIG_4KB (TCR_TG0_4KB | TCR_TG1_4KB) +#define TCR_CONFIG_DEFAULT (TCR_CONFIG_REGION_48bit | TCR_CONFIG_4KB) + +/** + * MAIR: Memory Attribute Indirection Register (Cache policies) + * Provide memory attribute encodings + * Device attributes: + * 1. Gathering(G/nG): Merge multiple accesses into a bus transaction + * 2. Reording(R/nR): Reorder the accesses to the same device + * 3. Early Write Ack (E/nE): Ack response could come from buffer + */ +#define MAIR_IDX_DEVICE_nGnRnE 0 +#define MAIR_IDX_NORMAL_NOCACHE 1 +// Peripheral access +#define MAIR_DEVICE_nGnRnE 0b00000000 +// Normal RAM access +#define MAIR_NORMAL_NOCACHE 0b01000100 + +#define MAIR_CONFIG_DEFAULT \ + ((MAIR_DEVICE_nGnRnE << (MAIR_IDX_DEVICE_nGnRnE * 8)) | \ + (MAIR_NORMAL_NOCACHE << (MAIR_IDX_NORMAL_NOCACHE * 8))) + +#define STCLR_OFFSET_ELx_MMU 0 +#define STCLR_MMU_ENABLE 1 +#define STCLR_CONFIG_MMU_ENABLE (STCLR_MMU_ENABLE << STCLR_OFFSET_ELx_MMU) + +/** + * Page descriptor: entries in the page table + * (Referring to the VMSAv8-32 Long-descriptor format) + * may be marked as: + * 1. Block descriptor: gives the base addr of + * a block of memory, also mark this entry as an + * end of translatoin lookup + * 2. Table descriptor: gives the base addr of the + * next level of translation table + * 3. Invalid + * + * Descriptor Format (Long-descriptor format) + * Block/Table entries: (upper_attr, output_addr, lower_attr, pd_type) + */ +// PD type +#define PD_TYPE_TABLE 0b11 +#define PD_TYPE_BLOCK 0b01 +#define PD_TYPE_INVALID 0b00 +#define PD_TYPE_PAGE 0b11 + +#define MASK_PD_TYPE 0b11 + +// PD_ATTR +#define PD_ATTR_ACCESS (1 << 10) +#define PD_ATTR_MAIR(MAIR_IDX) (MAIR_IDX << 2) +#define PD_ATTR_RO (1 << 7) +#define PD_ATTR_RW (0 << 7) +#define PD_ATTR_KERNEL (0 << 6) +#define PD_ATTR_USER (1 << 6) + +// Base schema for page descriptors + +// Table descriptor +#define BOOT_PD_TABLE (PD_TYPE_TABLE) +// Block descriptor for device memory +#define BOOT_PD_BLOCK_DEV \ + (PD_ATTR_ACCESS | PD_ATTR_MAIR(MAIR_IDX_DEVICE_nGnRnE) | PD_TYPE_BLOCK) +// Block descriptor for normal memory +#define BOOT_PD_BLOCK_NORMAL \ + (PD_ATTR_ACCESS | PD_ATTR_MAIR(MAIR_NORMAL_NOCACHE) | PD_TYPE_BLOCK) + +#define MAP_TYPE_USER_CODE 1 +#define MAP_TYPE_USER_MEM 2 +#define USER_ATTR_CODE \ + (PD_ATTR_ACCESS | PD_ATTR_MAIR(MAIR_NORMAL_NOCACHE) | PD_ATTR_RO | \ + PD_ATTR_USER | PD_TYPE_PAGE) +#define USER_ATTR_STACK \ + (PD_ATTR_ACCESS | PD_ATTR_MAIR(MAIR_NORMAL_NOCACHE) | PD_ATTR_RW | \ + PD_ATTR_USER | PD_TYPE_PAGE) + +/** + * Boot Page table config + * Identity paging for bare metal system + */ + +// Each entry is 8 Bytes (64bit), so we need 0x1000 Bytes for each table +#define BOOT_ADDR_L0_TABLE 0x0 +#define BOOT_ADDR_L1_TABLE 0x1000 +#define BOOT_ADDR_L2_TABLE 0x2000 + +#define L0_ENTRY (BOOT_ADDR_L1_TABLE | BOOT_PD_TABLE) + +// Each entry in L1 control the mapping with size=1G +// Because we only use the first 2G address, so we only need to setup +// identity paging for the first 2G. +// entry0 (0-1G): Forward to BOOT_L2_TABLE +// note: address from 0 - 1G [0x0 - 0x4000_0000) +#define L1_ENTRY_SUB_TABLE (BOOT_ADDR_L2_TABLE | BOOT_PD_TABLE) +// entry1 (1-2G): to represent a block of device memory (ARM Pheripherals) +// note: address from 1 - 2G [0x4000_0000 - 0x8000_0000] +#define L1_ENTRY_ARM_PERIF (0x40000000 | BOOT_PD_BLOCK_DEV) + +// Addrees from 3F00_0000 to 3FFF_FFFF is used for Pheripherals +#define LOWER_1G_PERIF_START 0x3F000000 + +#ifndef __ASSEMBLER__ +// Only inlcude for C files + +#endif \ No newline at end of file diff --git a/impl-c/include/mm/vm.h b/impl-c/include/mm/vm.h new file mode 100644 index 000000000..cdf33535a --- /dev/null +++ b/impl-c/include/mm/vm.h @@ -0,0 +1,32 @@ +#pragma once +/** + * Linear mapping + * We our kernel is linked to higher memory area(KVA), which is only a offset + * of actual phisical address. + */ + +// VA: virutal address +// PA: physical address + +#define kva_to_pa(addr) (0x0000ffffffffffff & (uint64_t)addr) +#define pa_to_kva(addr) (0xffff000000000000 | (uint64_t)addr) + +#define KVA_START 0xffff000000000000 + +#ifndef __ASSEMBLER__ +// Only inlcude for C files +#include +void *new_empty_page_table(); + +/** + * @brief Allocate a new page in givin va and map it to user's page table + * @param pgd_addr address of the page global directory(pgd) + * @param va virtual address in the address space mapped by pgd + * @retval Address of the newly allocated page (in KVA) + */ +void *map_new_addr(void *pgd_addr, uintptr_t va, int map_type); + +// Set page table for low mem area +void set_pgd_low(uint64_t next_pgd); + +#endif \ No newline at end of file diff --git a/impl-c/include/proc/exec.h b/impl-c/include/proc/exec.h index 771046888..6148e82bf 100644 --- a/impl-c/include/proc/exec.h +++ b/impl-c/include/proc/exec.h @@ -1,6 +1,5 @@ #pragma once #include -void *load_program(const char *name, /*OUT*/ size_t *target_size); int exec(const char *name, char *const argv[]); // Create and bind a user thread to current running task. diff --git a/impl-c/include/proc/task.h b/impl-c/include/proc/task.h index 65e7900b6..954d259e0 100644 --- a/impl-c/include/proc/task.h +++ b/impl-c/include/proc/task.h @@ -1,4 +1,5 @@ #pragma once +#include "const.h" #include "fs/vfs.h" #include #include @@ -7,6 +8,9 @@ #define TASK_STATUS_ALIVE 1 #define TASK_MX_NUM_FD 10 +#define DEFAULT_USPACE_LOAD_ADDR 0x80000 +#define USPACE_MEM_TOP CONST_1G + struct cpu_context { uint64_t x19; uint64_t x20; @@ -31,13 +35,14 @@ struct task_struct { int fd_size; struct file *fd[TASK_MX_NUM_FD]; + void *page_table; uintptr_t kernel_stack; uintptr_t user_stack; uintptr_t user_sp; // value of sp in el0 // address of the program code allocaed in memory - void *code; - size_t code_size; + // void *code; + // size_t code_size; }; struct task_struct *task_create(void *func); @@ -49,7 +54,7 @@ void cur_task_exit(); extern uint32_t new_tid; static inline void _wait() { - for (uint64_t j = 0; j < (1 << 27); j++) { + for (uint64_t j = 0; j < (1 << 23); j++) { ; } } diff --git a/impl-c/kernel/entry.S b/impl-c/kernel/entry.S index 332cc8510..0650a8159 100644 --- a/impl-c/kernel/entry.S +++ b/impl-c/kernel/entry.S @@ -81,6 +81,9 @@ _start: ldr x0, =exception_vector_table msr vbar_el1, x0 + //MMU init (vm/mmu_init.S) + bl mmu_init + // Initialize stack pointer: set to __stack_top ldr x0, = __stack_top mov sp, x0 diff --git a/impl-c/kernel/linker.ld b/impl-c/kernel/linker.ld index e0f912770..c07768dea 100644 --- a/impl-c/kernel/linker.ld +++ b/impl-c/kernel/linker.ld @@ -1,16 +1,18 @@ SECTIONS { /* + 0xffff000000000000 is the Start of our kernel virtual address after enabling MMU. 0x80000 is the default address where the kernel image would be loaded into memory (for 64bit machine), this address could be modified by varaible `kernel_address` in config.txt see: https://www.raspberrypi.org/documentation/configuration/config-txt/boot.md for more information */ - . = 0x80000; + . = 0xffff000000000000; + . += 0x80000; __kernel_start = .; .text : { - KEEP(*(.text.boot)) *(.text) + KEEP(*(.text.boot)) KEEP(*(.text.mmu_init)) *(.text) } .rodata : { diff --git a/impl-c/kernel/main.c b/impl-c/kernel/main.c index 887aae6d8..3af01568a 100644 --- a/impl-c/kernel/main.c +++ b/impl-c/kernel/main.c @@ -4,8 +4,9 @@ #include "fs/fat.h" #include "fs/tmpfs.h" #include "fs/vfs.h" -#include "mm.h" +#include "memory.h" #include "mm/startup.h" +#include "mm/vm.h" #include "proc.h" #include "shell/shell.h" #include "test.h" @@ -16,7 +17,7 @@ #define ANSI_GREEN(s) ("\033[0;32m" s "\033[0m") #define MX_CMD_BFRSIZE 64 -extern unsigned char __kernel_start, __kernel_end; +extern char __kernel_start, __kernel_end; static void init_sys(char *name, void (*func)(void)); static inline void run_shell(); @@ -98,6 +99,7 @@ void main() { #ifdef CFG_RUN_TEST run_tests(); #endif + // FATAL("TEST FINISHED"); vfs_init(); register_filesystem(&tmpfs); @@ -105,15 +107,17 @@ void main() { mount_root_fs("tmpfs"); // mount SD card to our filesystem tree - struct vnode *sdcard_root = NULL; - vfs_find_vnode("/dev", true); - sdcard_root = vfs_find_vnode("/dev/sdcard", true); - if (0 != mount(sdcard_root, "fat32")) { - FATAL("Could not mount sd card"); - } + // struct vnode *sdcard_root = NULL; + // vfs_find_vnode("/dev", true); + // sdcard_root = vfs_find_vnode("/dev/sdcard", true); + // if (0 != mount(sdcard_root, "fat32")) { + // FATAL("Could not mount sd card"); + // } + + // tmpfs_lab7_demo(); + // FATAL("STOP HERE"); - tmpfs_lab7_demo(); - fat_lab8_demo(); + // fat_lab8_demo(); // FATAL("Done"); test_tasks(); @@ -129,13 +133,14 @@ void init_sys(char *name, void (*func)(void)) { void reserve_startup_area() { // Kernel - startup_reserve((void *)0x0, 0x1000); // spin table - startup_reserve((void *)0x60000, 0x20000); // stack - startup_reserve((void *)(&__kernel_start), - (&__kernel_end - &__kernel_start)); // kernel - // startup_reserve((void *)(&kn_end), mem_size / PAGE_SIZE); // buddy - // System - startup_reserve((void *)0x3f000000, 0x1000000); // MMIO + // startup_reserve((void *)pa_to_kva(0x0), 0x1000); // spin table + startup_reserve((void *)pa_to_kva(0x0), + 0x3000); // Kernel page table (identity map) + startup_reserve((void *)pa_to_kva(0x60000), 0x20000); // stack + + startup_reserve((void *)&__kernel_start, + (&__kernel_end - &__kernel_start)); // kernel + startup_reserve((void *)pa_to_kva(0x3f000000), 0x1000000); // MMIO } void run_shell() { diff --git a/impl-c/libs/string.c b/impl-c/libs/string.c index 3ff7c6841..7118a05e2 100644 --- a/impl-c/libs/string.c +++ b/impl-c/libs/string.c @@ -73,7 +73,7 @@ const char *ignore_leading(const char *s, const char c) { // Caution: // 1. Copy the string returned if you need to store result // 2. Only pass in positive values -char *itoa(int64_t val, int base) { +char *itoa(uint64_t val, int base) { static char buf[64] = {0}; int i = 62; if (val == 0) { diff --git a/impl-c/mm/buddy.c b/impl-c/mm/buddy.c index 7f23f7d94..365895661 100644 --- a/impl-c/mm/buddy.c +++ b/impl-c/mm/buddy.c @@ -1,10 +1,10 @@ +#include "mm/alloc.h" +#include "mm/startup.h" + #include "bool.h" #include "config.h" #include "list.h" #include "log.h" -#include "mm.h" -#include "mm/alloc.h" -#include "mm/startup.h" #include "uart.h" #include @@ -191,7 +191,7 @@ void buddy_init_reserved(BuddyAllocater *alloc, StartupAllocator_t *sa) { for (int i = 0; i < sa->num_reserved; i++) { reg.addr = sa->_reserved[i].addr; reg.size = sa->_reserved[i].size; - uart_println("reserved: %d, %d", reg.addr, reg.size); + uart_println("reserved: %x, %x", reg.addr, reg.size); } #endif @@ -238,7 +238,8 @@ void buddy_init(BuddyAllocater *alloc, StartupAllocator_t *sa, for (int i = 0; i < (1 << BUDDY_MAX_EXPONENT); i++) { alloc->frames[i].arr_index = i; alloc->frames[i].exp = -1; - alloc->frames[i].addr = (void *)(((long)i << FRAME_SHIFT) + MEMORY_START); + alloc->frames[i].addr = + (void *)(((uintptr_t)i << FRAME_SHIFT) + MEMORY_START); alloc->frames[i].list_base.next = NULL; alloc->frames[i].list_base.prev = NULL; } diff --git a/impl-c/mm/kalloc.c b/impl-c/mm/kalloc.c index 08c7027ef..21bc384e4 100644 --- a/impl-c/mm/kalloc.c +++ b/impl-c/mm/kalloc.c @@ -1,8 +1,11 @@ +#include "memory.h" +#include "mm/alloc.h" +#include "mm/kalloc_manager.h" +#include "mm/startup.h" + #include "bool.h" #include "list.h" #include "log.h" -#include "mm.h" -#include "mm/startup.h" #include "uart.h" #include diff --git a/impl-c/mm/mmu_init.S b/impl-c/mm/mmu_init.S new file mode 100644 index 000000000..a1abb97e4 --- /dev/null +++ b/impl-c/mm/mmu_init.S @@ -0,0 +1,84 @@ +#include "mm/mmu.h" +#include "mm/vm.h" + +// Define a section near the kernel entrypoint makes it +// easier to debug.. +.section ".text.mmu_init" + +.global mmu_init +// We haven't setup stack, so be careful with stack memory +mmu_init: + // Setup TCR: Translation Control Register for base config + ldr x0, =TCR_CONFIG_DEFAULT + msr tcr_el1, x0 + + // Setup MAIR: Memory Attribute Indirection Register for accessibility & cache + // policies + ldr x0, =MAIR_CONFIG_DEFAULT + msr mair_el1, x0 + + /** + * Init Page Table, requires at least two table for enabling MMU + * Here we hard coded the table content + */ + // L0 table with only one entry to the L1 table + ldr x0, =BOOT_ADDR_L0_TABLE + ldr x1, =L0_ENTRY + str x1, [x0] + + // L1 table with two entries + ldr x0, =BOOT_ADDR_L1_TABLE + ldr x1, =L1_ENTRY_SUB_TABLE + str x1, [x0] + ldr x2, =L1_ENTRY_ARM_PERIF + str x2, [x0, 8] + + // L2 table +fill_first_1G_table: + ldr x5, =BOOT_PD_BLOCK_DEV + ldr x6, =BOOT_PD_BLOCK_NORMAL + ldr x10,=LOWER_1G_PERIF_START + ldr x0, =BOOT_ADDR_L2_TABLE + mov x1, #0 // address of mapped memory + mov x2, #512 // number of entries remains + + set_entry: + cbz x2, fill_table_end + cmp x1, x10 + blt set_entry_normal + set_entry_device: + orr x3, x1, x5 + b set_entry_end + set_entry_normal: + orr x3, x1, x6 + b set_entry_end + set_entry_end: + str x3,[x0] + add x0, x0, #8 // each entry take 8 bytes space + sub x2, x2, #1 + add x1, x1, #0x200000 //each entry specify 2M addres + b set_entry +fill_table_end: + + // Point to our page table + // Use the same page table for both lower/higher VA region + ldr x0, =BOOT_ADDR_L0_TABLE + msr ttbr0_el1, x0 + msr ttbr1_el1, x0 + isb + + // Enable MMU + ldr x0, =STCLR_CONFIG_MMU_ENABLE + mrs x2, sctlr_el1 + orr x2, x2, x0 + msr sctlr_el1, x2 + isb + + // The entire kernel code is linked to the higher memory region + // However, the bootloader would load our kernel at 0x80000 + // After enabling the MMU, we're officially running in the + // Address that are supposed to be linked to + // mmu_init_finished: defined in entry.S + ldr x0 ,=KVA_START + add x30, x30, x0 + ret diff --git a/impl-c/mm/slab.c b/impl-c/mm/slab.c index 252a9283d..c80c7f6a2 100644 --- a/impl-c/mm/slab.c +++ b/impl-c/mm/slab.c @@ -1,7 +1,10 @@ +#include "memory.h" +#include "mm/alloc.h" +#include "mm/kalloc_manager.h" + #include "bool.h" #include "list.h" #include "log.h" -#include "mm.h" #include "uart.h" #include diff --git a/impl-c/mm/vm.c b/impl-c/mm/vm.c new file mode 100644 index 000000000..8b0cebde7 --- /dev/null +++ b/impl-c/mm/vm.c @@ -0,0 +1,112 @@ +#include "mm/vm.h" +#include "mm/mmu.h" + +#include "fatal.h" +#include "memory.h" +#include +#include + +#include "config.h" +#include "log.h" + +#ifdef CFG_LOG_VM +static const int _DO_LOG = 1; +#else +static const int _DO_LOG = 0; +#endif + +#define PAGE_TABLE_SIZE (8 * 512) + +#define MASK_9Bits 0x1ff + +#define PGD_IDX(addr) (((addr) >> 39) & MASK_9Bits) +#define PUD_IDX(addr) (((addr) >> 30) & MASK_9Bits) +#define PMD_IDX(addr) (((addr) >> 21) & MASK_9Bits) +#define PTE_IDX(addr) (((addr) >> 12) & MASK_9Bits) + +// addr: dp[39:12] +#define DP_ADDR_MASK 0xFFFFFFF000 +#define DP_ADDR(dp) (dp & DP_ADDR_MASK) + +// Page descriptor for table entry +#define make_descriptor(addr, attr) ((addr) | (attr)) + +// Return the kva of a newly allocate page table +void *new_empty_page_table() { + // allocator directly output physical address + int64_t *table = (int64_t *)kalloc(PAGE_TABLE_SIZE); + for (int i = 0; i < 512; i++) { + table[i] = PD_TYPE_INVALID; + } + return (void *)table; +} + +// Return the index of each table +void get_page_idx(uintptr_t va, int *pgd_idx, int *pud_idx, int *pmd_idx, + int *pte_idx) { + if (pgd_idx != NULL) { + *pgd_idx = PGD_IDX(va); + } + if (pud_idx != NULL) { + *pud_idx = PUD_IDX(va); + } + if (pmd_idx != NULL) { + *pmd_idx = PMD_IDX(va); + } + if (pte_idx != NULL) { + *pte_idx = PTE_IDX(va); + } + return; +} + +void set_pgd_low(uint64_t next_pgd) { + asm volatile("\ + mov x0, %0\n\ + dsb ish\n\ + msr ttbr0_el1, x0\n\ + tlbi vmalle1is\n\ + dsb ish\n\ + isb" ::"r"(next_pgd)); +} + +void *map_new_addr(void *pgd_addr, uintptr_t va, int map_type) { + int entry_idx[4]; + get_page_idx(va, &entry_idx[0], &entry_idx[1], &entry_idx[2], &entry_idx[3]); + log_println("[VM] map new page to pgd:%x with va:%x", pgd_addr, va); + + // Create descriptor tables along page walk + // we can't use pa directly becuase using this low addrees area + // would result in using client virtual address + int64_t *cur_table = (int64_t *)pa_to_kva(pgd_addr); + int idx; + for (int i = 0; i < 3; i++) { + uintptr_t new_pt; + int64_t *next_table; + idx = entry_idx[i]; + + // required entry not exists + if (PD_TYPE_INVALID == (cur_table[idx] & MASK_PD_TYPE)) { + new_pt = (uintptr_t)new_empty_page_table(); + cur_table[idx] = make_descriptor(kva_to_pa(new_pt), PD_TYPE_TABLE); + next_table = (int64_t *)new_pt; + } else { + next_table = (int64_t *)pa_to_kva(DP_ADDR(cur_table[idx])); + } + cur_table = next_table; + } + int64_t *pte = cur_table; + // alloc a new page + uintptr_t page_addr = (uintptr_t)kalloc(PAGE_TABLE_SIZE); + uint64_t page_attr; + + if (map_type == MAP_TYPE_USER_CODE) { + page_attr = USER_ATTR_CODE; + } else if (map_type == MAP_TYPE_USER_MEM) { + page_attr = USER_ATTR_STACK; + } else { + uart_println("unknown map type: %d", map_type); + FATAL("Kernel bug"); + } + pte[entry_idx[3]] = make_descriptor(kva_to_pa(page_addr), page_attr); + return (void *)page_addr; +} \ No newline at end of file diff --git a/impl-c/proc/argv.c b/impl-c/proc/argv.c index 3bf9b7f30..03754fd56 100644 --- a/impl-c/proc/argv.c +++ b/impl-c/proc/argv.c @@ -1,8 +1,9 @@ -#include "mm.h" +#include "memory.h" #include "string.h" #include "uart.h" #include "config.h" +#include "fatal.h" #include "log.h" #include "test.h" @@ -25,17 +26,22 @@ static inline uintptr_t align_up(uintptr_t n, unsigned long align) { * @brief Place argv into user stack * @param src_sp the original user sp value * @param src_argv argv to copy from - * @param ret_argc (total argc count) - * @param ret_argv (alt) + * @param ret_argc address of the argc + * @param ret_argv0 address of the argv0 * @param ret_sp new sp value */ void place_args(/*IN*/ uintptr_t src_sp, /*IN*/ const char **src_argv, - /*OUT*/ int *ret_argc, - /*OUT*/ char ***ret_argv, + /*OUT*/ uintptr_t *ret_argc, + /*OUT*/ uintptr_t *ret_argv0, /*OUT*/ uintptr_t *ret_sp) { log_println("[place_arg] src_sp:%x", src_sp); + if ((src_sp % SP_ALIGN) != 0) { + uart_println("[place arg] src_sp must be %d bytes aligned, get:%x", + SP_ALIGN, src_sp); + FATAL("Check sp before calling this function"); + } int nm_args = 0; while (src_argv[nm_args] != NULL) { @@ -44,10 +50,6 @@ void place_args(/*IN*/ uintptr_t src_sp, nm_args++; } - if (ret_argc != NULL) { - *ret_argc = nm_args; - } - // Save Arguments into kernel memory. // We need to backup argv since they are stored in the user stack, // which would be overwritten by following operations. @@ -64,82 +66,72 @@ void place_args(/*IN*/ uintptr_t src_sp, * Save argv into user stack. * * High - * | "str2" | <- `args_offset[2]` / old stack top - * | "str1" | <- `args_offset[1]` - * | "str0" | <- `args_offset[0]` + * | | / old stack top (16 bytes aligned ) + * | "str2" | <- `args_offset[2]` (16 bytes aligned ) + * | | + * | "str1" | <- `args_offset[1]` (16 bytes aligned ) + * | | + * | "str0" | <- `args_offset[0]` (16 bytes aligned ) * | argv[2] | * | argv[1] | * | argv[0] | - * |stack_top| <- new user stack + * | argc | <- new stack top (16 bytes aligned ) * Low */ - // Calculate total size to store in user stack - // size is calculated in byte - size_t *args_offset = kalloc(sizeof(size_t) * nm_args); - size_t size_byte = 0, _size = 0; - - // Size for **argv array - _size = sizeof(char **) * nm_args; - _size = align_up(_size, SP_ALIGN); - size_byte += _size; - args_offset[0] = size_byte; - log_println("[place_arg] size for argv array: %d(byte)", _size); + uintptr_t sp = src_sp; + size_t _size = 0; + uintptr_t *addrs = kalloc(sizeof(char *) * nm_args); + log_println("[place_arg] start copy, sp: %x", sp); - // Size for each argv string - for (int i = 0; i < nm_args; i++) { - _size = strlen(saved_args[i]) + 1; + // copy args + for (int i = nm_args - 1; i >= 0; i--) { + _size = (sizeof(char) * strlen(saved_args[i])) + 1; _size = align_up(_size, SP_ALIGN); - size_byte += _size; - args_offset[i + 1] = size_byte; - log_println("[place_arg] size for src_argv[%d]: %d(byte)", i, _size); + sp -= _size; + log_println("[place_arg] size for src_argv[%d]: %d(byte), sp after:%x", i, + _size, sp); + addrs[i] = sp; + strcpy((char *)(sp), saved_args[i]); } - for (int i = 0; i < nm_args; i++) { - log_println(" args_offset[%d] -> %d", i, args_offset[i]); + // Start of the argv array is 16 byte aligned + // we put the argv from back + int size_argv = ((sizeof(char **)) * nm_args); + int size_argc = sizeof(size_t); + int total_size = size_argv + size_argc; + if (total_size < align_up(total_size, 16)) { + int back_indent = align_up(total_size, 16) - total_size; + sp -= back_indent; } - log_println("total bytes -> %d", size_byte); - - // The new user sp value (byte-addressable) - { - size_t aligned = align_up(size_byte, SP_ALIGN); - log_println("[place arg] total bytes:%d, after alignment:%d", size_byte, - aligned); - size_byte = aligned; + // fillup argv array + for (int i = nm_args - 1; i >= 0; i--) { + _size = (sizeof(char **)); + sp -= _size; + log_println("[place_arg] store pointer to argv[%d]: %d(byte), sp after:%x", + i, _size, sp); + // argv: pointer to char* + *(char **)sp = (char *)addrs[i]; } - - // 1. sp grow from HIGH->LOW - // 2. sp point to an empty memory space - int base = SP_ALIGN; - - uintptr_t sp = src_sp; - sp -= size_byte; - log_println("[place arg] move sp(%x) -> sp(%x)", src_sp, sp); - - // Calculate directly in byte address - char **user_argv = (char **)(sp + base); - for (int i = 0; i < nm_args; i++) { - user_argv[i] = (char *)(sp + base + args_offset[i]); + if (ret_argv0 != NULL) { + *ret_argv0 = sp; } + kfree(addrs); - // Copy args to user stack (would overwrite existing data) - for (int i = 0; i < nm_args; i++) { - strcpy((char *)(sp + base + args_offset[i]), saved_args[i]); - log_println("[place arg] argv[%d](%x) written -> %s", i, - sp + base + args_offset[i], sp + base + args_offset[i]); - // log_println("src_argv[%d] => %x", i, saved_args[i]); + // place argc + _size = (sizeof(size_t)); + sp -= _size; + log_println("[place_arg] store argc: %d(byte), sp after:%x", _size, sp); + *((size_t *)sp) = nm_args; + if (ret_argc != NULL) { + *ret_argc = sp; } - if (ret_argv != NULL) { - *ret_argv = (char **)(sp + base); - } if (ret_sp != NULL) { *ret_sp = sp; } - // Caution: need to be freed. - kfree(args_offset); for (int i = 0; i < nm_args; i++) { kfree(saved_args[i]); } @@ -152,19 +144,45 @@ bool test_good() { char stack[400]; uintptr_t src_sp = align_up((uintptr_t)&stack[350], SP_ALIGN); - uintptr_t new_sp; - char **new_argv; - int argc; + uintptr_t new_sp; + uintptr_t addr_argv0; + uintptr_t addr_argc; + + place_args(src_sp, (const char **)src_argv, &addr_argc, &addr_argv0, &new_sp); + + char **new_argv = (char **)addr_argv0; + int argc = *(int *)addr_argc; + + // uart_println("returned sp: %x", new_sp); + // uart_println("returned argc: %d(%x)", argc, addr_argc); + // for (int i = 0; i < argc; i++) { + // uart_println("returned argv[%d]: (%x)", i, &new_argv[i]); + // } + if ((new_sp % SP_ALIGN) != 0) { + uart_println("Returned sp is not 16 byte aligned: %d", new_sp); + return false; + } + if (new_sp >= src_sp) { + uart_println("returned sp higher than given"); + return false; + } + if (argc != 3) { + uart_println("Wrong argc :%d, expect:%d", argc, 3); + return false; + } - place_args(src_sp, (const char **)src_argv, &argc, &new_argv, &new_sp); - assert((new_sp % SP_ALIGN) == 0); - assert(new_sp < src_sp); - assert(argc == 3); for (size_t i = 0; i < argc; i++) { - assert((new_sp < (uintptr_t)new_argv[i])); - // sp point to an empty memory space - assert(((uintptr_t)new_argv[i] < (src_sp + SP_ALIGN))); + if (new_sp >= (uintptr_t)new_argv[i]) { + uart_println("argv[%d] (%x) is higher than new_sp:%x", i, &new_argv[i], + new_sp); + return false; + } + if (0 != strcmp(new_argv[i], src_argv[i])) { + uart_println("wrong argv[%d]: %s, expect:%s", i, new_argv[i], + src_argv[i]); + return false; + } } return true; } diff --git a/impl-c/proc/exec.c b/impl-c/proc/exec.c index fba02880c..c8f61ca3b 100644 --- a/impl-c/proc/exec.c +++ b/impl-c/proc/exec.c @@ -2,9 +2,13 @@ #include "proc/argv.h" #include "proc/task.h" -#include "dev/cpio.h" -#include "mm.h" +// #include "dev/cpio.h" +#include "fatal.h" +#include "fs/vfs.h" +#include "memory.h" #include "mm/frame.h" +#include "mm/mmu.h" +#include "mm/vm.h" #include "stddef.h" #include "stdint.h" #include "timer.h" @@ -19,80 +23,78 @@ static const int _DO_LOG = 1; static const int _DO_LOG = 0; #endif -// load program into a seperate memory space -void *load_program(const char *name, /*ret*/ size_t *target_size) { - unsigned long size; - uint8_t *file = (uint8_t *)cpioGetFile((void *)RAMFS_ADDR, name, &size); - if (file == NULL) { - uart_println("[Loader]Cannot found `%s` under rootfs", name); - return NULL; - } - if (target_size != NULL) { - *target_size = size; - } - unsigned char *load_addr = (unsigned char *)kalloc(FRAME_SIZE); - for (unsigned long i = 0; i < size; i++) { - load_addr[i] = file[i]; - } - return load_addr; -} - void exec_user(const char *name, char *const argv[]) { struct task_struct *task = get_current(); log_println("[exec] name:%s cur_task: %d(%x)", name, task->id, task); + // TODO: may need to free old page table + task->page_table = new_empty_page_table(); + log_println("[exec] new pgd allocated: %x", task->page_table); + + // load new program into memory, also setup page table + struct file *f = vfs_open(name, 0); + if (f == NULL) { + uart_println("[Loader]Cannot found `%s` in vfs", name); + FATAL("Should check file exists before running loader"); + } + uintptr_t page_kva = (uintptr_t)map_new_addr( + task->page_table, DEFAULT_USPACE_LOAD_ADDR, MAP_TYPE_USER_CODE); + int total_pages = 1; + for (;; page_kva += FRAME_SIZE, total_pages += 1) { + // TODO: support code larger than 1 frame + int cnt = vfs_read(f, (void *)page_kva, FRAME_SIZE); + uart_println("num bytes load... :%d", cnt); + if (cnt < FRAME_SIZE) { + break; + } + } + vfs_close(f); + log_println("[exec] load new program, total pages: %d", total_pages); - // load new program into memory - size_t code_size; - void *entry_point = load_program(name, &code_size); - log_println("[exec] load new program code at: %x", entry_point); + // allocate a new user stack to use. Initialy it's 4K - // allocate a new user stack to use - uintptr_t user_stack = (uintptr_t)kalloc(FRAME_SIZE); - uintptr_t user_sp = user_stack + FRAME_SIZE; + uintptr_t page_start = (uintptr_t)map_new_addr( + task->page_table, USPACE_MEM_TOP - FRAME_SIZE, MAP_TYPE_USER_MEM); + uintptr_t page_end = page_start + FRAME_SIZE; // place args onto the newly allocated user stack - int argc; - char **user_argv; uintptr_t new_sp; - place_args(user_sp, argv, &argc, &user_argv, &new_sp); + place_args(page_end, argv, NULL, NULL, &new_sp); + uintptr_t page_offset = page_end - new_sp; + uintptr_t user_sp = USPACE_MEM_TOP - page_offset; + + // Access to low memory area equals to access user space now + set_pgd_low((uintptr_t)task->page_table); + + uart_println("access user argc"); + int argc = *(int *)user_sp; + char **argv0 = (char **)(user_sp + 8); + + uart_println("get-> %d(%x)", argc, user_sp); + uart_println("argv0: %s", argv0[0]); + // FATAL("STOP here"); + + // TODO: handle sys_exec, may need to free up old code frame // Caller of this function is either // 1. a kernel thread with a user thread called sys_exec // or // 2. a kernel thread spawning a new user thread - // In the first case, we might have load a existing user_program into memory - // and allocated a user stack, so here we could safely free these memory - // (because argv might exists in the previous user stack) - { - // assign the new user_stack - if (task->user_stack != (uintptr_t)NULL) { - kfree((void *)task->user_stack); - } - // unload previous task code - if (task->code != NULL) { - log_println("[exec] free code from previous process: %x", task->code); - kfree((void *)task->code); - } - } - task->user_stack = user_stack; - task->user_sp = new_sp; - task->code = entry_point; - task->code_size = code_size; + // task->user_stack = user_stack; + // task->user_sp = new_sp; // context under kernel mode task->cpu_context.fp = task->kernel_stack + FRAME_SIZE; - task->cpu_context.lr = (uint64_t)entry_point; task->cpu_context.sp = task->kernel_stack + FRAME_SIZE; // Jump into user mode asm volatile("mov x0, 0x340 \n"); // enable core timer interrupt asm volatile("msr spsr_el1, x0 \n"); - asm volatile("msr sp_el0, %0 \n" ::"r"(task->user_sp)); - asm volatile("msr elr_el1, %0 \n" ::"r"(task->cpu_context.lr)); + asm volatile("msr sp_el0, %0 \n" ::"r"(user_sp)); + asm volatile("msr elr_el1, %0 \n" ::"r"(DEFAULT_USPACE_LOAD_ADDR)); - asm volatile("mov x0, %0 \n\ + asm volatile("mov x0, %0\n\ mov x1, %1 \n\ - eret" ::"r"(argc), - "r"(user_argv)); + eret" ::"r"(user_sp), + "r"(argv0)); } \ No newline at end of file diff --git a/impl-c/proc/fork.c b/impl-c/proc/fork.c index db290f4f5..15070b0ab 100644 --- a/impl-c/proc/fork.c +++ b/impl-c/proc/fork.c @@ -3,7 +3,7 @@ #include "bool.h" #include "fs/vfs.h" -#include "mm.h" +#include "memory.h" #include "mm/frame.h" #include "string.h" #include "syscall.h" @@ -47,7 +47,7 @@ int sys_fork(const struct trap_frame *tf) { // TODO: fix this (memory leak) // parent should free memory // parent should be collected after child - child->code = NULL; + // child->code = NULL; // Child return // direct to the exception return point diff --git a/impl-c/proc/sched.c b/impl-c/proc/sched.c index 43fe9f186..cfeb63965 100644 --- a/impl-c/proc/sched.c +++ b/impl-c/proc/sched.c @@ -1,8 +1,10 @@ #include "proc/sched.h" #include "proc/task.h" +#include "fatal.h" #include "list.h" -#include "mm.h" +#include "memory.h" +#include "mm/vm.h" #include "uart.h" #include "config.h" @@ -14,7 +16,6 @@ static const int _DO_LOG = 1; static const int _DO_LOG = 0; #endif -// proc/sched.S void switch_to(struct task_struct *prev, struct task_struct *next); static void kill_zombies(); @@ -48,6 +49,7 @@ void task_schedule() { } } log_println("[schedule] switch thread %d->%d", cur->id, next->id); + set_pgd_low((uint64_t)next->page_table); switch_to(cur, next); } } @@ -55,7 +57,7 @@ void task_schedule() { void idle() { while (1) { uart_println("idle scheduling..."); - _wait(); + // _wait(); task_schedule(); kill_zombies(); } diff --git a/impl-c/proc/task.c b/impl-c/proc/task.c index 3379136ea..ee0d00f8a 100644 --- a/impl-c/proc/task.c +++ b/impl-c/proc/task.c @@ -5,10 +5,12 @@ #include "proc/sched.h" #include "bool.h" +#include "fatal.h" #include "fs/vfs.h" #include "list.h" -#include "mm.h" +#include "memory.h" #include "mm/frame.h" +#include "mm/vm.h" #include "string.h" #include "syscall.h" #include "timer.h" @@ -43,8 +45,6 @@ struct task_struct *task_create(void *func) { t->kernel_stack = (uintptr_t)kalloc(FRAME_SIZE); // Normal task is a kernel function, which has already been loaded to memory - t->code = NULL; - t->code_size = 0; t->cpu_context.fp = t->kernel_stack + FRAME_SIZE; t->cpu_context.lr = (uint64_t)func; t->cpu_context.sp = t->kernel_stack + FRAME_SIZE; @@ -59,6 +59,9 @@ struct task_struct *task_create(void *func) { // A task would only bind to a user thread if called with exec_user t->user_stack = (uintptr_t)(NULL); t->user_sp = (uintptr_t)(NULL); + uint64_t pgd; + asm volatile("mrs %0, ttbr0_el1" : "=r"(pgd)); + t->page_table = (void *)pgd; struct task_entry *entry = (struct task_entry *)kalloc(sizeof(struct task_entry)); @@ -76,9 +79,12 @@ void task_free(struct task_struct *task) { // if (task->code) { // kfree(task->code); // } - if (task->user_stack) { - kfree((void *)task->user_stack); - } + + // TODO: Free page table + // if (task->user_stack) { + // kfree((void *)task->user_stack); + // } + kfree((void *)task->kernel_stack); // Close all file descriptors @@ -168,7 +174,8 @@ int sys_read(int fd, void *buf, int count) { void sys_exit() { cur_task_exit(); } void cur_task_exit() { - // Mark current thread as exited, which would be picked up by the idle thread + // Mark current thread as exited, which would be picked up by the idle + // thread struct task_struct *task = get_current(); task->status = TASK_STATUS_DEAD; log_println("[task] exit called: %d", task->id); @@ -179,7 +186,7 @@ void foo() { struct task_struct *task = get_current(); for (int i = 0; i < 2; ++i) { uart_println("Thread id: %d -> loop:%d", task->id, i); - _wait(); + // _wait(); task_schedule(); } cur_task_exit(); @@ -199,6 +206,20 @@ void task_start_user() { exec_user(name, args); } +// This function should be runned as a kernel task +void task_get_pid() { + uart_println("enter user startup"); + char *name = "./get_pid.out"; + char *args[] = {"./get_pid.out", NULL}; + + // Launch a user program thread (in el0) with this kernel thread + // + // Eversince this point, exceptions under el0 would be trap + // to the context of this kernel thread + // (Since we would call `eret` under this kernel thread) + exec_user(name, args); +} + void test_user_io() { char *name = "./file.out"; char *args[4] = {"./file.out", NULL}; @@ -214,7 +235,8 @@ void test_tasks() { // create a task to bootup the very first user program // task_create(task_start_user); - task_create(test_user_io); + // task_create(test_user_io); + task_create(task_get_pid); task_create(foo); // task_create(foo); diff --git a/impl-c/shell/sh_cmd.c b/impl-c/shell/sh_cmd.c index 975005a4d..69c563740 100644 --- a/impl-c/shell/sh_cmd.c +++ b/impl-c/shell/sh_cmd.c @@ -4,6 +4,7 @@ #include "bool.h" #include "config.h" #include "dev/cpio.h" +#include "dev/mmio.h" #include "log.h" #include "string.h" #include "test.h" @@ -20,8 +21,8 @@ // #endif #define PM_PASSWORD 0x5a000000 -#define PM_RSTC ((volatile unsigned int *)0x3F10001c) -#define PM_WDOG ((volatile unsigned int *)0x3F100024) +#define PM_RSTC ((volatile unsigned int *)(MMIO_BASE + 0x10001c)) +#define PM_WDOG ((volatile unsigned int *)(MMIO_BASE + 0x100024)) static void cmdHello(); static void cmdLs(); diff --git a/user_programs/get_pid.c b/user_programs/get_pid.c index 0dab7bd34..631cf7bca 100644 --- a/user_programs/get_pid.c +++ b/user_programs/get_pid.c @@ -1,8 +1,6 @@ #include "lib.h" int main() { - getpid(); - for (int j = 0; j < 5; j++) { - asm volatile("svc 0\n" :); - } + int pid = getpid(); + printf("hello\n"); return 0; } \ No newline at end of file diff --git a/user_programs/stdio.c b/user_programs/stdio.c index 83288a84d..8819894e5 100644 --- a/user_programs/stdio.c +++ b/user_programs/stdio.c @@ -4,8 +4,8 @@ #include "lib.h" #define MX_BUF_SIZE 100 -static char *itoa(int64_t val, int base); -static size_t sputs(char *output, const char *input); +char *itoa(int64_t val, int base); +int sputs(char *output, const char *input); char *itoa(int64_t val, int base) { static char buf[64] = {0}; @@ -20,8 +20,8 @@ char *itoa(int64_t val, int base) { return &buf[i + 1]; } -size_t sputs(char *output, const char *input) { - size_t size = 0; +int sputs(char *output, const char *input) { + int size = 0; while (*input) { *(output++) = *(input++); size++; @@ -34,7 +34,7 @@ size_t sputs(char *output, const char *input) { void printf(char *fmt, ...) { int64_t i; char *s; - size_t size = 0; + int size = 0; char buf[MX_BUF_SIZE] = {}; va_list arg;