From 7759eef8cdac79028dd5b468bd9ce0cf1c12b162 Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Tue, 30 Dec 2025 14:21:40 +0800 Subject: dev(spinlock): refactoring the implementation of locks --- include/kernel/proc.h | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'include/kernel/proc.h') diff --git a/include/kernel/proc.h b/include/kernel/proc.h index b557267..e77fdc9 100644 --- a/include/kernel/proc.h +++ b/include/kernel/proc.h @@ -3,11 +3,13 @@ #include "kernel/trap.h" #include "kernel/spinlock.h" +// Context structure, used for context switching struct Context { uint64 ra; uint64 sp; + // Callee-saved registers uint64 s0; uint64 s1; uint64 s2; @@ -22,7 +24,9 @@ struct Context uint64 s11; }; -enum ProcState{ +// Process State Enumeration +enum ProcState +{ UNUSED, USED, SLEEPING, @@ -31,6 +35,7 @@ enum ProcState{ ZOMBIE, }; +// Process Control Block (PCB) struct Proc { struct Context context; @@ -41,15 +46,25 @@ struct Proc enum ProcState state; int pid; - void* kstack; + void *kstack; char name[16]; uint64 sz; struct Proc *parent; void *chan; int xstate; + + // Implement later }; +// CPU status structure +struct cpu +{ + struct Proc *proc; // Processes currently running on this CPU + struct Context context; // Save the scheduler context here + int noff; // Depth of push_off() + int intena; // Interrupt enable status before closing +}; namespace ProcManager { @@ -62,7 +77,8 @@ namespace ProcManager void user_init(); void exit(int status); int wait(uint64 addr); - void sleep(void *chan, struct spinlock *lk); + + void sleep(void *chan, Spinlock *lk); void wakeup(void *chan); } -- cgit v1.2.3 From dbba25aa24f86c1f8c3a0589c82985840adc1b6b Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Wed, 31 Dec 2025 18:00:55 +0800 Subject: dev:Refactor Memory Management and Process Management --- Makefile | 2 +- build/kernel.elf | Bin 78448 -> 154536 bytes build/src/boot/entry.o | Bin 1864 -> 5464 bytes build/src/drivers/uart.o | Bin 4352 -> 57352 bytes build/src/kernel/config.o | Bin 1272 -> 4376 bytes build/src/kernel/fdt.o | Bin 4560 -> 40344 bytes build/src/kernel/initcode.o | Bin 1488 -> 2448 bytes build/src/kernel/main.o | Bin 7056 -> 17744 bytes build/src/kernel/mm/pmm.o | Bin 5128 -> 90424 bytes build/src/kernel/mm/slab.o | Bin 0 -> 67304 bytes build/src/kernel/mm/vm.o | Bin 135304 -> 213776 bytes build/src/kernel/proc/proc.o | Bin 118560 -> 205000 bytes build/src/kernel/proc/swtch.o | Bin 1072 -> 5024 bytes build/src/kernel/sbi.o | Bin 1832 -> 11584 bytes build/src/kernel/spinlock.o | Bin 6968 -> 99920 bytes build/src/kernel/syscall.o | Bin 81848 -> 47560 bytes build/src/kernel/timer.o | Bin 2368 -> 10992 bytes build/src/kernel/trap/handler.o | Bin 13992 -> 65848 bytes build/src/kernel/trap/trampoline.o | Bin 13408 -> 20960 bytes build/src/kernel/trap/trap.o | Bin 13440 -> 20904 bytes build/src/lib/string.o | Bin 4136 -> 27632 bytes build/user/init.o | Bin 11264 -> 45880 bytes build/user/initcode | Bin 464 -> 1424 bytes build/user/initcode.asm | 558 +++++++++++++++++++++++++++---------- build/user/initcode.out | Bin 9256 -> 14168 bytes include/drivers/uart.h | 11 +- include/kernel/cpu.h | 19 ++ include/kernel/mm.h | 28 +- include/kernel/pmm.h | 3 - include/kernel/proc.h | 65 +---- include/kernel/proc_def.h | 59 ++++ include/kernel/riscv.h | 1 + include/kernel/runqueue.h | 16 ++ include/kernel/slab.h | 10 + include/kernel/spinlock.h | 2 - include/kernel/sync.h | 38 +++ include/kernel/trap.h | 7 +- link.ld | 39 --- linker.ld | 45 +++ src/boot/entry.S | 26 +- src/drivers/uart.cc | 71 +++-- src/kernel/fdt.cc | 11 - src/kernel/main.cc | 92 +++--- src/kernel/mm/pmm.cc | 353 ++++++++++++++++++++--- src/kernel/mm/slab.cc | 246 ++++++++++++++++ src/kernel/mm/vm.cc | 394 +++++++++++++++----------- src/kernel/proc/proc.cc | 434 ++++++++++++++++++----------- src/kernel/spinlock.cc | 33 ++- src/kernel/syscall.cc | 93 ++++--- src/kernel/trap/handler.cc | 242 ++++++++-------- src/user/init.cc | 104 ++++++- src/user/user.ld | 12 +- 52 files changed, 2090 insertions(+), 924 deletions(-) create mode 100644 build/src/kernel/mm/slab.o create mode 100644 include/kernel/cpu.h create mode 100644 include/kernel/proc_def.h create mode 100644 include/kernel/runqueue.h create mode 100644 include/kernel/slab.h create mode 100644 include/kernel/sync.h delete mode 100644 link.ld create mode 100644 linker.ld create mode 100644 src/kernel/mm/slab.cc (limited to 'include/kernel/proc.h') diff --git a/Makefile b/Makefile index 3e06e89..7c3de2d 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ SRC_DIR := src CFLAGS := -Wall -Wextra -O2 -g -ffreestanding -nostdlib -mcmodel=medany -Iinclude CXXFLAGS := $(CFLAGS) -fno-exceptions -fno-rtti -fno-use-cxa-atexit -LINKER_SCRIPT := link.ld +LINKER_SCRIPT := linker.ld UPROGS_SRC := $(SRC_DIR)/user/init.cc UPROGS_OBJ := $(BUILD_DIR)/user/init.o diff --git a/build/kernel.elf b/build/kernel.elf index e13d2ff..679a7bb 100755 Binary files a/build/kernel.elf and b/build/kernel.elf differ diff --git a/build/src/boot/entry.o b/build/src/boot/entry.o index 2398fda..ca04d37 100644 Binary files a/build/src/boot/entry.o and b/build/src/boot/entry.o differ diff --git a/build/src/drivers/uart.o b/build/src/drivers/uart.o index bdbc317..34a0840 100644 Binary files a/build/src/drivers/uart.o and b/build/src/drivers/uart.o differ diff --git a/build/src/kernel/config.o b/build/src/kernel/config.o index eb2108d..a07739e 100644 Binary files a/build/src/kernel/config.o and b/build/src/kernel/config.o differ diff --git a/build/src/kernel/fdt.o b/build/src/kernel/fdt.o index 2dd29e3..c2e2fe3 100644 Binary files a/build/src/kernel/fdt.o and b/build/src/kernel/fdt.o differ diff --git a/build/src/kernel/initcode.o b/build/src/kernel/initcode.o index e53a8a5..e29dda3 100644 Binary files a/build/src/kernel/initcode.o and b/build/src/kernel/initcode.o differ diff --git a/build/src/kernel/main.o b/build/src/kernel/main.o index df2f4af..54ee210 100644 Binary files a/build/src/kernel/main.o and b/build/src/kernel/main.o differ diff --git a/build/src/kernel/mm/pmm.o b/build/src/kernel/mm/pmm.o index 7065343..c77cdc9 100644 Binary files a/build/src/kernel/mm/pmm.o and b/build/src/kernel/mm/pmm.o differ diff --git a/build/src/kernel/mm/slab.o b/build/src/kernel/mm/slab.o new file mode 100644 index 0000000..23305aa Binary files /dev/null and b/build/src/kernel/mm/slab.o differ diff --git a/build/src/kernel/mm/vm.o b/build/src/kernel/mm/vm.o index 22cbbe3..2e3c0de 100644 Binary files a/build/src/kernel/mm/vm.o and b/build/src/kernel/mm/vm.o differ diff --git a/build/src/kernel/proc/proc.o b/build/src/kernel/proc/proc.o index ef1e81e..63506e7 100644 Binary files a/build/src/kernel/proc/proc.o and b/build/src/kernel/proc/proc.o differ diff --git a/build/src/kernel/proc/swtch.o b/build/src/kernel/proc/swtch.o index f3443f3..8fee25b 100644 Binary files a/build/src/kernel/proc/swtch.o and b/build/src/kernel/proc/swtch.o differ diff --git a/build/src/kernel/sbi.o b/build/src/kernel/sbi.o index 20dd9de..24e5e36 100644 Binary files a/build/src/kernel/sbi.o and b/build/src/kernel/sbi.o differ diff --git a/build/src/kernel/spinlock.o b/build/src/kernel/spinlock.o index 96b62d9..f4a24bf 100644 Binary files a/build/src/kernel/spinlock.o and b/build/src/kernel/spinlock.o differ diff --git a/build/src/kernel/syscall.o b/build/src/kernel/syscall.o index 259a780..a3df126 100644 Binary files a/build/src/kernel/syscall.o and b/build/src/kernel/syscall.o differ diff --git a/build/src/kernel/timer.o b/build/src/kernel/timer.o index 4728b8b..5f93af4 100644 Binary files a/build/src/kernel/timer.o and b/build/src/kernel/timer.o differ diff --git a/build/src/kernel/trap/handler.o b/build/src/kernel/trap/handler.o index 88daa0e..570f268 100644 Binary files a/build/src/kernel/trap/handler.o and b/build/src/kernel/trap/handler.o differ diff --git a/build/src/kernel/trap/trampoline.o b/build/src/kernel/trap/trampoline.o index 4419278..ce16681 100644 Binary files a/build/src/kernel/trap/trampoline.o and b/build/src/kernel/trap/trampoline.o differ diff --git a/build/src/kernel/trap/trap.o b/build/src/kernel/trap/trap.o index feb0976..ebb1b8f 100644 Binary files a/build/src/kernel/trap/trap.o and b/build/src/kernel/trap/trap.o differ diff --git a/build/src/lib/string.o b/build/src/lib/string.o index bceb813..6d50c43 100644 Binary files a/build/src/lib/string.o and b/build/src/lib/string.o differ diff --git a/build/user/init.o b/build/user/init.o index d32ad08..13021f2 100644 Binary files a/build/user/init.o and b/build/user/init.o differ diff --git a/build/user/initcode b/build/user/initcode index 511a518..7d139ad 100755 Binary files a/build/user/initcode and b/build/user/initcode differ diff --git a/build/user/initcode.asm b/build/user/initcode.asm index e3a1185..c04fbab 100644 --- a/build/user/initcode.asm +++ b/build/user/initcode.asm @@ -4,212 +4,482 @@ build/user/initcode.out: file format elf64-littleriscv Disassembly of section .text: -0000000000000000 <_start>: +0000000000000000 <_Z6strlenPKc>: #include "user/user.h" -int main(); - -extern "C" void _start() +int strlen(const char *s) { - 0: 1141 addi sp,sp,-16 - 2: e406 sd ra,8(sp) - exit(main()); - 4: 004000ef jal 8
+ int n = 0; + while (s[n]) + 0: 00054783 lbu a5,0(a0) + 4: cf81 beqz a5,1c <_Z6strlenPKc+0x1c> + 6: 0505 addi a0,a0,1 + 8: 87aa mv a5,a0 + a: 0007c703 lbu a4,0(a5) + e: 86be mv a3,a5 + 10: 0785 addi a5,a5,1 + 12: ff65 bnez a4,a <_Z6strlenPKc+0xa> + n++; + 14: 40a6853b subw a0,a3,a0 + 18: 2505 addiw a0,a0,1 + 1a: 8082 ret + int n = 0; + 1c: 4501 li a0,0 + return n; +} + 1e: 8082 ret + +0000000000000020 <_Z5printPKc>: + while (s[n]) + 20: 00054783 lbu a5,0(a0) -0000000000000008
: +void print(const char *s) +{ + 24: 85aa mv a1,a0 + while (s[n]) + 26: cf89 beqz a5,40 <_Z5printPKc+0x20> + 28: 00150693 addi a3,a0,1 + 2c: 87b6 mv a5,a3 + 2e: 0007c703 lbu a4,0(a5) + 32: 863e mv a2,a5 + 34: 0785 addi a5,a5,1 + 36: ff65 bnez a4,2e <_Z5printPKc+0xe> + n++; + 38: 9e15 subw a2,a2,a3 + 3a: 2605 addiw a2,a2,1 + write(1, s, strlen(s)); + 3c: 4505 li a0,1 + 3e: a491 j 282 + int n = 0; + 40: 4601 li a2,0 + write(1, s, strlen(s)); + 42: 4505 li a0,1 + 44: ac3d j 282 + +0000000000000046 <_Z9print_inti>: + +void print_int(int val) +{ + char buf[16]; + int i = 0; + if (val == 0) + 46: c159 beqz a0,cc <_Z9print_inti+0x86> +{ + 48: 7139 addi sp,sp,-64 + 4a: f822 sd s0,48(sp) + 4c: fc06 sd ra,56(sp) + 4e: f426 sd s1,40(sp) + 50: f04a sd s2,32(sp) + 52: 842a mv s0,a0 + { + print("0"); + return; + } + if (val < 0) + 54: 06054163 bltz a0,b6 <_Z9print_inti+0x70> + 58: 081c addi a5,sp,16 +{ + 5a: 873e mv a4,a5 + print("-"); + val = -val; + } + while (val > 0) + { + buf[i++] = (val % 10) + '0'; + 5c: 4629 li a2,10 + 5e: 02c466bb remw a3,s0,a2 + 62: 85ba mv a1,a4 + while (val > 0) + 64: 0705 addi a4,a4,1 + val /= 10; + 66: 02c4443b divw s0,s0,a2 + buf[i++] = (val % 10) + '0'; + 6a: 0306869b addiw a3,a3,48 + 6e: fed70fa3 sb a3,-1(a4) + while (val > 0) + 72: f475 bnez s0,5e <_Z9print_inti+0x18> + 74: 9d9d subw a1,a1,a5 + 76: 0015871b addiw a4,a1,1 + 7a: fff7059b addiw a1,a4,-1 + 7e: fff78493 addi s1,a5,-1 + 82: 1582 slli a1,a1,0x20 + 84: 94ba add s1,s1,a4 + 86: 9181 srli a1,a1,0x20 + 88: 00e78433 add s0,a5,a4 + 8c: 8c8d sub s1,s1,a1 + 8e: 00f10913 addi s2,sp,15 + } + while (i > 0) + { + char c = buf[--i]; + 92: fff44783 lbu a5,-1(s0) + write(1, &c, 1); + 96: 4605 li a2,1 + 98: 85ca mv a1,s2 + 9a: 4505 li a0,1 + while (i > 0) + 9c: 147d addi s0,s0,-1 + char c = buf[--i]; + 9e: 00f107a3 sb a5,15(sp) + write(1, &c, 1); + a2: 1e0000ef jal 282 + while (i > 0) + a6: fe9416e3 bne s0,s1,92 <_Z9print_inti+0x4c> + } } + aa: 70e2 ld ra,56(sp) + ac: 7442 ld s0,48(sp) + ae: 74a2 ld s1,40(sp) + b0: 7902 ld s2,32(sp) + b2: 6121 addi sp,sp,64 + b4: 8082 ret + write(1, s, strlen(s)); + b6: 4605 li a2,1 + b8: 00000597 auipc a1,0x0 + bc: 26058593 addi a1,a1,608 # 318 + c0: 4505 li a0,1 + c2: 1c0000ef jal 282 + val = -val; + c6: 4080043b negw s0,s0 + while (val > 0) + ca: b779 j 58 <_Z9print_inti+0x12> + write(1, s, strlen(s)); + cc: 4605 li a2,1 + ce: 00000597 auipc a1,0x0 + d2: 24258593 addi a1,a1,578 # 310 + d6: 4505 li a0,1 + d8: a26d j 282 + +00000000000000da <_Z4passv>: + while (s[n]) + da: 00000697 auipc a3,0x0 + de: 24668693 addi a3,a3,582 # 320 + +void pass() { print(" -> [PASS]\n"); } + e2: 87b6 mv a5,a3 + while (s[n]) + e4: 0017c703 lbu a4,1(a5) + e8: 863e mv a2,a5 + ea: 0785 addi a5,a5,1 + ec: ff65 bnez a4,e4 <_Z4passv+0xa> + n++; + ee: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + f0: 2605 addiw a2,a2,1 + f2: 00000597 auipc a1,0x0 + f6: 22e58593 addi a1,a1,558 # 320 + fa: 4505 li a0,1 + fc: a259 j 282 + +00000000000000fe <_Z4failv>: +void fail() +{ + fe: 1141 addi sp,sp,-16 + 100: 00000697 auipc a3,0x0 + 104: 23068693 addi a3,a3,560 # 330 + 108: e406 sd ra,8(sp) + 10a: 87b6 mv a5,a3 + while (s[n]) + 10c: 0017c703 lbu a4,1(a5) + 110: 863e mv a2,a5 + 112: 0785 addi a5,a5,1 + 114: ff65 bnez a4,10c <_Z4failv+0xe> + n++; + 116: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 118: 2605 addiw a2,a2,1 + 11a: 00000597 auipc a1,0x0 + 11e: 21658593 addi a1,a1,534 # 330 + 122: 4505 li a0,1 + 124: 15e000ef jal 282 + print(" -> [FAIL]\n"); + exit(1); +} + 128: 60a2 ld ra,8(sp) + exit(1); + 12a: 4505 li a0,1 +} + 12c: 0141 addi sp,sp,16 + exit(1); + 12e: aa15 j 262 + +0000000000000130
: int main() { - 8: 1141 addi sp,sp,-16 - a: e406 sd ra,8(sp) + 130: 1141 addi sp,sp,-16 + print("\n=== Lume OS Full Validation ===\n"); + 132: 00000517 auipc a0,0x0 + 136: 20e50513 addi a0,a0,526 # 340 +{ + 13a: e406 sd ra,8(sp) + 13c: e022 sd s0,0(sp) + print("\n=== Lume OS Full Validation ===\n"); + 13e: ee3ff0ef jal 20 <_Z5printPKc> + + print("[TEST 1] Write\n"); + 142: 00000517 auipc a0,0x0 + 146: 22650513 addi a0,a0,550 # 368 + 14a: ed7ff0ef jal 20 <_Z5printPKc> + print(" System call write is working."); + 14e: 00000517 auipc a0,0x0 + 152: 22a50513 addi a0,a0,554 # 378 + 156: ecbff0ef jal 20 <_Z5printPKc> +void pass() { print(" -> [PASS]\n"); } + 15a: 00000517 auipc a0,0x0 + 15e: 1c650513 addi a0,a0,454 # 320 + 162: ebfff0ef jal 20 <_Z5printPKc> + pass(); + + print("[TEST 2] GetPID\n"); + 166: 00000517 auipc a0,0x0 + 16a: 23250513 addi a0,a0,562 # 398 + 16e: eb3ff0ef jal 20 <_Z5printPKc> + int parent_pid = getpid(); + 172: 170000ef jal 2e2 + 176: 842a mv s0,a0 + print(" Parent PID: "); + 178: 00000517 auipc a0,0x0 + 17c: 23850513 addi a0,a0,568 # 3b0 + 180: ea1ff0ef jal 20 <_Z5printPKc> + print_int(parent_pid); + 184: 8522 mv a0,s0 + 186: ec1ff0ef jal 46 <_Z9print_inti> + if (parent_pid > 0) + 18a: 0c805563 blez s0,254 +void pass() { print(" -> [PASS]\n"); } + 18e: 00000517 auipc a0,0x0 + 192: 19250513 addi a0,a0,402 # 320 + 196: e8bff0ef jal 20 <_Z5printPKc> + pass(); + else + fail(); + + print("[TEST 3] Fork, Wait & COW\n"); + 19a: 00000517 auipc a0,0x0 + 19e: 22650513 addi a0,a0,550 # 3c0 + 1a2: e7fff0ef jal 20 <_Z5printPKc> + int val = 100; int pid = fork(); - c: 060000ef jal 6c + 1a6: 0b4000ef jal 25a if (pid < 0) - 10: 00054f63 bltz a0,2e + 1aa: 04054363 bltz a0,1f0 { - write(1, "Fork failed\n", 12); - exit(1); + print(" Fork Failed\n"); + fail(); } if (pid == 0) - 14: e905 bnez a0,44 + 1ae: e929 bnez a0,200 { - write(1, "Hello from Child!\n", 18); - 16: 4649 li a2,18 - 18: 00000597 auipc a1,0x0 - 1c: 12058593 addi a1,a1,288 # 138 - 20: 4505 li a0,1 - 22: 072000ef jal 94 + print(" [Child] PID: "); + 1b0: 00000517 auipc a0,0x0 + 1b4: 24050513 addi a0,a0,576 # 3f0 + 1b8: e69ff0ef jal 20 <_Z5printPKc> + print_int(getpid()); + 1bc: 126000ef jal 2e2 + 1c0: e87ff0ef jal 46 <_Z9print_inti> + print("\n"); + 1c4: 00000517 auipc a0,0x0 + 1c8: 23c50513 addi a0,a0,572 # 400 + 1cc: e55ff0ef jal 20 <_Z5printPKc> + print(" [Child] Data corruption!\n"); + exit(1); + } + + val = 200; + print(" [Child] Modified val to 200. Exiting.\n"); + 1d0: 00000517 auipc a0,0x0 + 1d4: 23850513 addi a0,a0,568 # 408 + 1d8: e49ff0ef jal 20 <_Z5printPKc> exit(0); - 26: 4501 li a0,0 - 28: 04c000ef jal 74 - write(1, "Parent waiting...\n", 18); - wait(0); - write(1, "Parent: Child exited.\n", 22); + 1dc: 4501 li a0,0 + 1de: 084000ef jal 262 + print_int(val); + fail(); + } } - while (1); - 2c: a001 j 2c - write(1, "Fork failed\n", 12); - 2e: 4631 li a2,12 - 30: 00000597 auipc a1,0x0 - 34: 0f058593 addi a1,a1,240 # 120 - 38: 4505 li a0,1 - 3a: 05a000ef jal 94 - exit(1); - 3e: 4505 li a0,1 - 40: 034000ef jal 74 - write(1, "Parent waiting...\n", 18); - 44: 4649 li a2,18 - 46: 00000597 auipc a1,0x0 - 4a: 10a58593 addi a1,a1,266 # 150 - 4e: 4505 li a0,1 - 50: 044000ef jal 94 - wait(0); - 54: 4501 li a0,0 - 56: 026000ef jal 7c - write(1, "Parent: Child exited.\n", 22); - 5a: 4659 li a2,22 - 5c: 00000597 auipc a1,0x0 - 60: 10c58593 addi a1,a1,268 # 168 - 64: 4505 li a0,1 - 66: 02e000ef jal 94 - 6a: b7c9 j 2c - -000000000000006c : + print("\n=== All Tests Passed ===\n"); + 1e2: 00000517 auipc a0,0x0 + 1e6: 2ce50513 addi a0,a0,718 # 4b0 + 1ea: e37ff0ef jal 20 <_Z5printPKc> + while (1) + 1ee: a001 j 1ee + print(" Fork Failed\n"); + 1f0: 00000517 auipc a0,0x0 + 1f4: 1f050513 addi a0,a0,496 # 3e0 + 1f8: e29ff0ef jal 20 <_Z5printPKc> + fail(); + 1fc: f03ff0ef jal fe <_Z4failv> + print(" [Parent] Waiting for child...\n"); + 200: 00000517 auipc a0,0x0 + 204: 23850513 addi a0,a0,568 # 438 + 208: e19ff0ef jal 20 <_Z5printPKc> + int child_pid = wait(0); + 20c: 4501 li a0,0 + 20e: 05c000ef jal 26a + 212: 842a mv s0,a0 + print(" [Parent] Child "); + 214: 00000517 auipc a0,0x0 + 218: 24c50513 addi a0,a0,588 # 460 + 21c: e05ff0ef jal 20 <_Z5printPKc> + print_int(child_pid); + 220: 8522 mv a0,s0 + 222: e25ff0ef jal 46 <_Z9print_inti> + print(" exited.\n"); + 226: 00000517 auipc a0,0x0 + 22a: 25250513 addi a0,a0,594 # 478 + 22e: df3ff0ef jal 20 <_Z5printPKc> + print(" [Parent] Check val (Expect 100): "); + 232: 00000517 auipc a0,0x0 + 236: 25650513 addi a0,a0,598 # 488 + 23a: de7ff0ef jal 20 <_Z5printPKc> + print_int(val); + 23e: 06400513 li a0,100 + 242: e05ff0ef jal 46 <_Z9print_inti> +void pass() { print(" -> [PASS]\n"); } + 246: 00000517 auipc a0,0x0 + 24a: 0da50513 addi a0,a0,218 # 320 + 24e: dd3ff0ef jal 20 <_Z5printPKc> + 252: bf41 j 1e2 + fail(); + 254: eabff0ef jal fe <_Z4failv> + 258: b789 j 19a + +000000000000025a : name: \ li a7, SYS_ ## name; \ ecall; \ ret SYSCALL(fork) - 6c: 4889 li a7,2 - 6e: 00000073 ecall - 72: 8082 ret + 25a: 4889 li a7,2 + 25c: 00000073 ecall + 260: 8082 ret -0000000000000074 : +0000000000000262 : SYSCALL(exit) - 74: 488d li a7,3 - 76: 00000073 ecall - 7a: 8082 ret + 262: 488d li a7,3 + 264: 00000073 ecall + 268: 8082 ret -000000000000007c : +000000000000026a : SYSCALL(wait) - 7c: 4891 li a7,4 - 7e: 00000073 ecall - 82: 8082 ret + 26a: 4891 li a7,4 + 26c: 00000073 ecall + 270: 8082 ret -0000000000000084 : +0000000000000272 : SYSCALL(pipe) - 84: 4895 li a7,5 - 86: 00000073 ecall - 8a: 8082 ret + 272: 4895 li a7,5 + 274: 00000073 ecall + 278: 8082 ret -000000000000008c : +000000000000027a : SYSCALL(read) - 8c: 4899 li a7,6 - 8e: 00000073 ecall - 92: 8082 ret + 27a: 4899 li a7,6 + 27c: 00000073 ecall + 280: 8082 ret -0000000000000094 : +0000000000000282 : SYSCALL(write) - 94: 48c5 li a7,17 - 96: 00000073 ecall - 9a: 8082 ret + 282: 48c5 li a7,17 + 284: 00000073 ecall + 288: 8082 ret -000000000000009c : +000000000000028a : SYSCALL(close) - 9c: 48d9 li a7,22 - 9e: 00000073 ecall - a2: 8082 ret + 28a: 48d9 li a7,22 + 28c: 00000073 ecall + 290: 8082 ret -00000000000000a4 : +0000000000000292 : SYSCALL(kill) - a4: 489d li a7,7 - a6: 00000073 ecall - aa: 8082 ret + 292: 489d li a7,7 + 294: 00000073 ecall + 298: 8082 ret -00000000000000ac : +000000000000029a : SYSCALL(exec) - ac: 48a1 li a7,8 - ae: 00000073 ecall - b2: 8082 ret + 29a: 48a1 li a7,8 + 29c: 00000073 ecall + 2a0: 8082 ret -00000000000000b4 : +00000000000002a2 : SYSCALL(open) - b4: 48c1 li a7,16 - b6: 00000073 ecall - ba: 8082 ret + 2a2: 48c1 li a7,16 + 2a4: 00000073 ecall + 2a8: 8082 ret -00000000000000bc : +00000000000002aa : SYSCALL(mknod) - bc: 48c9 li a7,18 - be: 00000073 ecall - c2: 8082 ret + 2aa: 48c9 li a7,18 + 2ac: 00000073 ecall + 2b0: 8082 ret -00000000000000c4 : +00000000000002b2 : SYSCALL(unlink) - c4: 48cd li a7,19 - c6: 00000073 ecall - ca: 8082 ret + 2b2: 48cd li a7,19 + 2b4: 00000073 ecall + 2b8: 8082 ret -00000000000000cc : +00000000000002ba : SYSCALL(fstat) - cc: 48a5 li a7,9 - ce: 00000073 ecall - d2: 8082 ret + 2ba: 48a5 li a7,9 + 2bc: 00000073 ecall + 2c0: 8082 ret -00000000000000d4 : +00000000000002c2 : SYSCALL(link) - d4: 48d1 li a7,20 - d6: 00000073 ecall - da: 8082 ret + 2c2: 48d1 li a7,20 + 2c4: 00000073 ecall + 2c8: 8082 ret -00000000000000dc : +00000000000002ca : SYSCALL(mkdir) - dc: 48d5 li a7,21 - de: 00000073 ecall - e2: 8082 ret + 2ca: 48d5 li a7,21 + 2cc: 00000073 ecall + 2d0: 8082 ret -00000000000000e4 : +00000000000002d2 : SYSCALL(chdir) - e4: 48a9 li a7,10 - e6: 00000073 ecall - ea: 8082 ret + 2d2: 48a9 li a7,10 + 2d4: 00000073 ecall + 2d8: 8082 ret -00000000000000ec : +00000000000002da : SYSCALL(dup) - ec: 48ad li a7,11 - ee: 00000073 ecall - f2: 8082 ret + 2da: 48ad li a7,11 + 2dc: 00000073 ecall + 2e0: 8082 ret -00000000000000f4 : +00000000000002e2 : SYSCALL(getpid) - f4: 48b1 li a7,12 - f6: 00000073 ecall - fa: 8082 ret + 2e2: 48b1 li a7,12 + 2e4: 00000073 ecall + 2e8: 8082 ret -00000000000000fc : +00000000000002ea : SYSCALL(sbrk) - fc: 48b5 li a7,13 - fe: 00000073 ecall - 102: 8082 ret + 2ea: 48b5 li a7,13 + 2ec: 00000073 ecall + 2f0: 8082 ret -0000000000000104 : +00000000000002f2 : SYSCALL(sleep) - 104: 48b9 li a7,14 - 106: 00000073 ecall - 10a: 8082 ret + 2f2: 48b9 li a7,14 + 2f4: 00000073 ecall + 2f8: 8082 ret -000000000000010c : +00000000000002fa : SYSCALL(uptime) - 10c: 48bd li a7,15 - 10e: 00000073 ecall - 112: 8082 ret - -0000000000000114 : - 114: 4885 li a7,1 - 116: 00000073 ecall - 11a: 8082 ret + 2fa: 48bd li a7,15 + 2fc: 00000073 ecall + 300: 8082 ret + +0000000000000302 : + 302: 4885 li a7,1 + 304: 00000073 ecall + 308: 8082 ret diff --git a/build/user/initcode.out b/build/user/initcode.out index 0667728..af31998 100755 Binary files a/build/user/initcode.out and b/build/user/initcode.out differ diff --git a/include/drivers/uart.h b/include/drivers/uart.h index 4d00d94..cb84bde 100644 --- a/include/drivers/uart.h +++ b/include/drivers/uart.h @@ -1,9 +1,12 @@ #pragma once -typedef unsigned long long uint64_t; +#include "common/types.h" -namespace Drivers { +namespace Drivers +{ void uart_init(); void uart_putc(char c); - void uart_puts(const char* s); - void print_hex(uint64_t val); + + void uart_puts(const char *s); + void uart_put_int(int value); + void print_hex(uint64 value); } \ No newline at end of file diff --git a/include/kernel/cpu.h b/include/kernel/cpu.h new file mode 100644 index 0000000..92890b6 --- /dev/null +++ b/include/kernel/cpu.h @@ -0,0 +1,19 @@ +#pragma once +#include "common/types.h" +#include "kernel/proc_def.h" + +struct RunQueue; + +struct cpu +{ + struct Proc *proc; + struct Context context; + int noff; + int intena; + + struct RunQueue *runqueue; +}; + + +extern struct cpu cpus[]; +struct cpu *mycpu(); \ No newline at end of file diff --git a/include/kernel/mm.h b/include/kernel/mm.h index 07d675b..363ce74 100644 --- a/include/kernel/mm.h +++ b/include/kernel/mm.h @@ -3,20 +3,22 @@ namespace VM { - typedef uint64_t *pagetable_t; - typedef uint64_t pte_t; + extern uint64 *kernel_pagetable; - pte_t *walk(pagetable_t pagetable, uint64 va, int alloc); - int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm); - void kvmmap(uint64 va, uint64 pa, uint64 sz, int perm); void kvminit(); void kvminithart(); - pagetable_t uvmcreate(); - void uvminit(pagetable_t pagetable, uchar *src, uint sz); - void uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free); - void uvmfree(pagetable_t pagetable, uint64 sz); - int uvmcopy(pagetable_t oldpt, pagetable_t newpt, uint64 sz); - uint64 uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz); - uint64 uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz); - int copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len); + + uint64 *uvmcreate(); + void uvminit(uint64 *pagetable, uchar *src, uint64 sz); + uint64 uvmalloc(uint64 *pagetable, uint64 oldsz, uint64 newsz, int xperm); + uint64 uvmdealloc(uint64 *pagetable, uint64 oldsz, uint64 newsz); + void uvmfree(uint64 *pagetable, uint64 sz); + int uvmcopy(uint64 *oldpt, uint64 *newpt, uint64 sz); + void uvmunmap(uint64 *pagetable, uint64 va, uint64 npages, int do_free); + + int copyout(uint64 *pagetable, uint64 dstva, char *src, uint64 len); + int copyin(uint64 *pagetable, char *dst, uint64 srcva, uint64 len); + + int handle_cow_fault(uint64 *pagetable, uint64 va); + int mappages(uint64 *pagetable, uint64 va, uint64 size, uint64 pa, int perm); } \ No newline at end of file diff --git a/include/kernel/pmm.h b/include/kernel/pmm.h index 7156c76..d31473f 100644 --- a/include/kernel/pmm.h +++ b/include/kernel/pmm.h @@ -8,9 +8,6 @@ #define PHYSIZE (128 * 1024 * 1024) #define PHYSTOP (KERNBASE + PHYSIZE) -#define PGSIZE 4096 -#define PGSHIFT 12 - // Buddy System Max Order // Order 10 => 2^10 pages = 1024 * 4KB = 4MB contiguous block // Order 11 => 2^11 pages = 8MB diff --git a/include/kernel/proc.h b/include/kernel/proc.h index e77fdc9..d63ccf7 100644 --- a/include/kernel/proc.h +++ b/include/kernel/proc.h @@ -1,71 +1,8 @@ #pragma once #include "common/types.h" -#include "kernel/trap.h" +#include "kernel/proc_def.h" #include "kernel/spinlock.h" -// Context structure, used for context switching -struct Context -{ - uint64 ra; - uint64 sp; - - // Callee-saved registers - uint64 s0; - uint64 s1; - uint64 s2; - uint64 s3; - uint64 s4; - uint64 s5; - uint64 s6; - uint64 s7; - uint64 s8; - uint64 s9; - uint64 s10; - uint64 s11; -}; - -// Process State Enumeration -enum ProcState -{ - UNUSED, - USED, - SLEEPING, - RUNNABLE, - RUNNING, - ZOMBIE, -}; - -// Process Control Block (PCB) -struct Proc -{ - struct Context context; - struct Trapframe *tf; - - uint64 *pagetable; - - enum ProcState state; - int pid; - - void *kstack; - char name[16]; - uint64 sz; - - struct Proc *parent; - void *chan; - int xstate; - - // Implement later -}; - -// CPU status structure -struct cpu -{ - struct Proc *proc; // Processes currently running on this CPU - struct Context context; // Save the scheduler context here - int noff; // Depth of push_off() - int intena; // Interrupt enable status before closing -}; - namespace ProcManager { void init(); diff --git a/include/kernel/proc_def.h b/include/kernel/proc_def.h new file mode 100644 index 0000000..e5a2cbc --- /dev/null +++ b/include/kernel/proc_def.h @@ -0,0 +1,59 @@ +#pragma once +#include "common/types.h" + +struct cpu; +struct Trapframe; + +enum ProcState +{ + UNUSED, + USED, + SLEEPING, + RUNNABLE, + RUNNING, + ZOMBIE, +}; + +#define PRIO_MAX 0 +#define PRIO_MIN 3 +#define N_PRIO 4 + +// Context structure +struct Context +{ + uint64 ra; + uint64 sp; + uint64 s0; + uint64 s1; + uint64 s2; + uint64 s3; + uint64 s4; + uint64 s5; + uint64 s6; + uint64 s7; + uint64 s8; + uint64 s9; + uint64 s10; + uint64 s11; +}; + +struct Proc +{ + struct Context context; + struct Trapframe *tf; + uint64 *pagetable; + enum ProcState state; + int pid; + void *kstack; + char name[16]; + uint64 sz; + struct Proc *parent; + void *chan; + int xstate; + + struct Proc *next; + struct Proc *prev; + int priority; + int ticks; + struct cpu *cpu; +}; \ No newline at end of file diff --git a/include/kernel/riscv.h b/include/kernel/riscv.h index 4b3d323..e81976f 100644 --- a/include/kernel/riscv.h +++ b/include/kernel/riscv.h @@ -79,6 +79,7 @@ w_sip(uint64 x) // Supervisor Interrupt Enable #define SIE_SEIE (1L << 9) // external #define SIE_STIE (1L << 5) // timer +#define SIE_SSIE (1L << 1) // software static inline uint64 r_sie() { diff --git a/include/kernel/runqueue.h b/include/kernel/runqueue.h new file mode 100644 index 0000000..ea6e4cc --- /dev/null +++ b/include/kernel/runqueue.h @@ -0,0 +1,16 @@ +#pragma once +#include "kernel/spinlock.h" +#include "kernel/proc_def.h" + +struct RunQueue +{ + Spinlock lock; + struct Proc *heads[N_PRIO]; + struct Proc *tails[N_PRIO]; + uint64 count; + + void init(const char *name); + void enqueue(struct Proc *p); + struct Proc *dequeue(); + struct Proc *steal(); +}; \ No newline at end of file diff --git a/include/kernel/slab.h b/include/kernel/slab.h new file mode 100644 index 0000000..650f8a9 --- /dev/null +++ b/include/kernel/slab.h @@ -0,0 +1,10 @@ +#pragma once +#include "common/types.h" + +namespace Slab +{ + void init(); + + void *kmalloc(uint64 size); + void kfree(void *ptr); +} \ No newline at end of file diff --git a/include/kernel/spinlock.h b/include/kernel/spinlock.h index b3cc93e..3102e68 100644 --- a/include/kernel/spinlock.h +++ b/include/kernel/spinlock.h @@ -1,9 +1,7 @@ #pragma once - #include "common/types.h" struct cpu; -struct Proc; // Spinlock // Features: Non-interruptible, busy-wait loop, extremely short hold time. diff --git a/include/kernel/sync.h b/include/kernel/sync.h new file mode 100644 index 0000000..83d88c8 --- /dev/null +++ b/include/kernel/sync.h @@ -0,0 +1,38 @@ +#pragma once +#include "common/types.h" +#include "kernel/spinlock.h" +#include "kernel/proc_def.h" + + +struct WaitQueue +{ + Spinlock lock; + struct Proc *head; + struct Proc *tail; + + void init(const char *name); + void sleep(); + void wakeup(); + void wakeup_all(); +}; + +struct Semaphore +{ + int value; + WaitQueue wq; + Spinlock lock; + + void init(int val, const char *name); + void wait(); + void post(); +}; + +struct CondVar +{ + WaitQueue wq; + + void init(const char *name); + void wait(Spinlock *mutex_lock); + void signal(); + void broadcast(); +}; \ No newline at end of file diff --git a/include/kernel/trap.h b/include/kernel/trap.h index 79bb037..35b225c 100644 --- a/include/kernel/trap.h +++ b/include/kernel/trap.h @@ -45,7 +45,6 @@ struct Trapframe namespace Trap { void init(); - extern "C" void kernelvec(); - extern "C" void kerneltrap(struct Trapframe *tf); -} -extern "C" void usertrap(); \ No newline at end of file + void inithart(); + int devintr(); +} \ No newline at end of file diff --git a/link.ld b/link.ld deleted file mode 100644 index 2029e8c..0000000 --- a/link.ld +++ /dev/null @@ -1,39 +0,0 @@ -OUTPUT_ARCH( "riscv" ) -ENTRY(_start) - -SECTIONS -{ - . = 0x80200000; - - .text : { - PROVIDE(text_start = .); - *(.text.entry) - *(.text .text.*) - . = ALIGN(4096); - PROVIDE(text_end = .); - } - - .rodata : { - PROVIDE(rodata_start = .); - *(.rodata .rodata.*) - . = ALIGN(4096); - PROVIDE(rodata_end = .); - } - - .data : { - PROVIDE(data_start = .); - *(.data .data.*) - . = ALIGN(4096); - PROVIDE(data_end = .); - } - - .bss : { - PROVIDE(bss_start = .); - *(.bss .bss.*) - *(.sbss .sbss.*) - . = ALIGN(4096); - PROVIDE(bss_end = .); - } - - PROVIDE(kernel_end = .); -} \ No newline at end of file diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..63e3249 --- /dev/null +++ b/linker.ld @@ -0,0 +1,45 @@ +OUTPUT_ARCH( "riscv" ) +ENTRY( _start ) + +SECTIONS +{ + . = 0x80200000; + + /* Text Segment */ + .text : { + *(.text.entry) + *(.text .text.*) + . = ALIGN(0x1000); + PROVIDE(etext = .); + } + + /* Read Only Data Segment */ + .rodata : { + . = ALIGN(16); + *(.srodata .srodata.*) + . = ALIGN(16); + *(.rodata .rodata.*) + } + + /* Data Segment */ + .data : { + . = ALIGN(16); + *(.sdata .sdata.*) + . = ALIGN(16); + *(.data .data.*) + } + + /* BBS Segment */ + .bss : { + . = ALIGN(16); + PROVIDE(sbss = .); + *(.sbss .sbss.*) + . = ALIGN(16); + *(.bss .bss.*) + PROVIDE(ebss = .); + } + + . = ALIGN(0x1000); + PROVIDE(end = .); + PROVIDE(kernel_end = .); +} \ No newline at end of file diff --git a/src/boot/entry.S b/src/boot/entry.S index 924d7d6..6d75bcf 100644 --- a/src/boot/entry.S +++ b/src/boot/entry.S @@ -2,13 +2,29 @@ .global _start _start: - la t0, g_dtb_addr - sd a1, 0(t0) - mv tp, a0 - la sp, stack_top + la t0, stack_base + li t1, 4096 + addi t2, a0, 1 + mul t1, t1, t2 + add sp, t0, t1 + + bnez a0, .L_jump_main + + la t0, sbss + la t1, ebss +.L_clear_bss: + bge t0, t1, .L_save_dtb + sd zero, 0(t0) + addi t0, t0, 8 + j .L_clear_bss + +.L_save_dtb: + la t0, g_dtb_addr + sd a1, 0(t0) +.L_jump_main: call kernel_main .L_park: @@ -19,7 +35,7 @@ _start: .align 4 .global stack_top stack_base: - .space 4096 * 4 + .space 4096 * 8 stack_top: .align 8 diff --git a/src/drivers/uart.cc b/src/drivers/uart.cc index 367f442..fe051f8 100644 --- a/src/drivers/uart.cc +++ b/src/drivers/uart.cc @@ -14,7 +14,9 @@ #define UART_LSR_RX_READY 0x01 #define UART_LSR_TX_EMPTY 0x20 -namespace Drivers{ +namespace Drivers +{ + inline volatile uint8_t ®(uint32_t offset) { return *reinterpret_cast(g_uart_base + offset); @@ -22,36 +24,35 @@ namespace Drivers{ void uart_init() { - if (g_uart_base == 0) return; - reg(UART_IER) = 0x00; - - reg(UART_LCR) = 0x80; - reg(0x00) = 0x03; - reg(0x01) = 0x00; - - reg(UART_LCR) = 0x03; - + reg(UART_IER) = 0x00; // Disable interrupt + reg(UART_LCR) = 0x80; // Set baud rate (LATCH bit) + reg(0x00) = 0x03; // LSB + reg(0x01) = 0x00; // MSB + reg(UART_LCR) = 0x03; // 8 bits, no parity, one stop bit reg(UART_FCR) = 0x07; // Enable FIFO, clear TX/RX queues } void uart_putc(char c) { + if (g_uart_base == 0) + return; + if (c == '\n') { uart_putc('\r'); } + // Waiting for the send buffer to be empty while ((reg(UART_LSR) & UART_LSR_TX_EMPTY) == 0) - { - - } + ; reg(UART_THR) = c; } + void uart_puts(const char *s) { while (*s) @@ -60,18 +61,42 @@ namespace Drivers{ } } - void print_hex(uint64_t val) + void uart_put_int(int value) + { + if (value == 0) + { + uart_putc('0'); + return; + } + + if (value < 0) + { + uart_putc('-'); + value = -value; + } + + char buffer[16]; + int i = 0; + while (value > 0) + { + buffer[i++] = (value % 10) + '0'; + value /= 10; + } + + while (i > 0) + { + uart_putc(buffer[--i]); + } + } + + void print_hex(uint64 value) { - char buf[20]; - const char *digits = "0123456789ABCDEF"; - buf[0] = '0'; - buf[1] = 'x'; - for (int i = 0; i < 16; i++) + uart_puts("0x"); + char hex[] = "0123456789abcdef"; + for (int i = 15; i >= 0; i--) { - buf[17 - i] = digits[val & 0xF]; - val >>= 4; + int nibble = (value >> (i * 4)) & 0xF; + uart_putc(hex[nibble]); } - buf[18] = 0; - Drivers::uart_puts(buf); } } \ No newline at end of file diff --git a/src/kernel/fdt.cc b/src/kernel/fdt.cc index 1863086..5334845 100644 --- a/src/kernel/fdt.cc +++ b/src/kernel/fdt.cc @@ -96,17 +96,6 @@ void fdt_init(uint64 dtb) } } - // if (g_clint_base == 0) - // { - // for (uint32 i = 0; i < len; i++) - // { - // if (data[i] == 'c' && data[i + 1] == 'l' && data[i + 2] == 'i' && data[i + 3] == 'n') - // { - // g_clint_base = current_reg_addr; - // break; - // } - // } - // } } } } diff --git a/src/kernel/main.cc b/src/kernel/main.cc index c6d794d..081ab3e 100644 --- a/src/kernel/main.cc +++ b/src/kernel/main.cc @@ -1,75 +1,53 @@ +#include "common/types.h" +#include "kernel/riscv.h" #include "drivers/uart.h" #include "kernel/pmm.h" #include "kernel/mm.h" -#include "kernel/trap.h" #include "kernel/proc.h" +#include "kernel/trap.h" #include "kernel/timer.h" -#include "kernel/config.h" - -void fdt_init(uint64 dtb); +#include "kernel/cpu.h" -void delay() -{ - for(volatile int i = 0; i < 1000000; i++) - { +// 引用外部 FDT 初始化函数 +extern void fdt_init(uint64 dtb); +extern uint64 g_dtb_addr; - } -} - -void task_a() -{ - while(1) - { - Drivers::uart_putc('A'); - delay(); - // ProcManager::yield(); - } -} +volatile static int started = 0; -void task_b() +extern "C" void kernel_main(uint64 hartid, uint64 dtb) { - while (1) + if (hartid == 0) { - Drivers::uart_putc('B'); - delay(); - // ProcManager::yield(); - } - -} - -extern "C" void kernel_main() -{ - - fdt_init(g_dtb_addr); - Drivers::uart_init(); - Drivers::uart_puts("\n[Lume OS Kernel] Booted in S-Mode.\n"); - Drivers::uart_puts("2025 Richard Qin\n"); - Drivers::uart_puts("\n"); - Drivers::uart_puts("\n[Boot] Kernel started.\n"); + fdt_init(dtb); - PMM::init(); - Drivers::uart_puts("[Boot] PMM initialized.\n"); + Drivers::uart_init(); + Drivers::uart_puts("\n[Lume OS] Booting...\n"); - VM::kvminit(); - Drivers::uart_puts("[Boot] Kernel page table created.\n"); + Drivers::uart_puts("[Boot] PMP configured.\n"); - VM::kvminithart(); - Drivers::uart_puts("[Boot] MMU ENABLED! We are now using virtual addresses.\n"); + PMM::init(); // Physical Memory Management + VM::kvminit(); // Kernel Pagetable + VM::kvminithart(); // Enable MMU + Trap::init(); // Trap Management + Trap::inithart(); + Timer::init(); + ProcManager::init(); // Process Management + ProcManager::user_init(); // Initialize first user process - Trap::init(); - Drivers::uart_puts("[Boot] Trap Handler Installed.\n"); + __atomic_store_n(&started, 1, __ATOMIC_RELEASE); - Timer::init(); - Drivers::uart_puts("[Boot] Timer Interrupt Enabled.\n"); - - ProcManager::init(); - Drivers::uart_puts("[Boot] ProcManager Initialized.\n"); + Drivers::uart_puts("[Boot] System initialized. Entering scheduler...\n"); + } + else + { + while (__atomic_load_n(&started, __ATOMIC_ACQUIRE) == 0) + ; - void task_a(); - void task_b(); - // ProcManager::create_kernel_thread(task_a, "Task A"); - // ProcManager::create_kernel_thread(task_b, "Task B"); - ProcManager::user_init(); + VM::kvminithart(); + Trap::inithart(); + Timer::init(); + Drivers::uart_puts("[Boot] Hart started.\n"); + } - ProcManager::scheduler(); + ProcManager::scheduler(); // Enable Scheduler } \ No newline at end of file diff --git a/src/kernel/mm/pmm.cc b/src/kernel/mm/pmm.cc index 9b68fcd..09bd65b 100644 --- a/src/kernel/mm/pmm.cc +++ b/src/kernel/mm/pmm.cc @@ -1,71 +1,356 @@ +#include "common/types.h" +#include "kernel/riscv.h" #include "kernel/pmm.h" +#include "kernel/mm.h" +// #include "kernel/spinlock.h" #include "drivers/uart.h" +#include "lib/string.h" extern "C" char kernel_end[]; +extern uint64 g_dtb_addr; + +// namespace PMM +// { +// struct Run +// { +// struct Run *next; +// }; + +// struct +// { +// struct Run *freelist; +// } kmem; + +// inline uint64_t PGROUNDUP(uint64_t a) +// { +// return (a + PGSIZE - 1) & ~(PGSIZE - 1); +// } + +// void init() +// { +// uint64_t start = PGROUNDUP((uint64_t)kernel_end); + +// Drivers::uart_puts("PMM: Initializing from"); + +// for (uint64_t p = start; p + PGSIZE <= PHYSTOP; p += PGSIZE) +// { +// free_page((void *)p); +// } +// } + +// void free_page(void* pa) +// { +// struct Run *r; +// if (((uint64_t)pa % PGSIZE) != 0 || (uint64_t)pa < (uint64_t)kernel_end || (uint64_t)pa >= PHYSTOP) +// { +// Drivers::uart_puts("PMM: Error - Invalid free address\n"); +// return; +// } +// r = (struct Run*)pa; + +// r->next = kmem.freelist; +// kmem.freelist = r; + +// } + +// void* alloc_page() +// { +// struct Run* r; + +// r = kmem.freelist; +// if (r) +// { +// kmem.freelist = r->next; + +// uint64_t *p = (uint64_t *)r; +// for (int i = 0; i < PGSIZE / 8; i++) +// { +// p[i] = 0; +// } +// } +// else +// { +// Drivers::uart_puts("PMM: Out of memory!\n"); +// } +// return (void *)r; +// } +// } namespace PMM { - struct Run - { - struct Run *next; - }; + // Global metadata array pointer + struct Page *mem_map = nullptr; + // Total number of physical memory pages + uint64 total_pages = 0; + // Free list array (free_area[k] stores the head of the free block list of order=k) + struct Page *free_area[MAX_ORDER]; + // Protective lock + Spinlock pmm_lock; - struct + struct Page *pa_to_page(uint64 pa) { - struct Run *freelist; - } kmem; + if (pa < KERNBASE || pa >= PHYSTOP) + return nullptr; + uint64 pfn = (pa - KERNBASE) >> PGSHIFT; + if (pfn >= total_pages) + return nullptr; + return &mem_map[pfn]; + } - inline uint64_t PGROUNDUP(uint64_t a) + uint64 page_to_pa(struct Page *page) { - return (a + PGSIZE - 1) & ~(PGSIZE - 1); + uint64 pfn = page - mem_map; + return KERNBASE + (pfn << PGSHIFT); } - void init() + void list_add(struct Page *page, int order) { - uint64_t start = PGROUNDUP((uint64_t)kernel_end); + page->order = order; + page->flags = 0; // Mark as available + page->next = free_area[order]; + page->prev = nullptr; - Drivers::uart_puts("PMM: Initializing from"); + if (free_area[order]) + { + free_area[order]->prev = page; + } + free_area[order] = page; + } - for (uint64_t p = start; p + PGSIZE <= PHYSTOP; p += PGSIZE) + void list_del(struct Page* page, int order) + { + if (page->prev) + { + page->prev->next = page->next; + } + else + { + free_area[order] = page->next; + } + if (page->next) { - free_page((void *)p); + page->next->prev = page->prev; } + page->next = nullptr; + page->prev = nullptr; } - void free_page(void* pa) + void init() { - struct Run *r; - if (((uint64_t)pa % PGSIZE) != 0 || (uint64_t)pa < (uint64_t)kernel_end || (uint64_t)pa >= PHYSTOP) + pmm_lock.init("pmm"); + + uint64 kern_end_pa = PGROUNDUP((uint64)kernel_end); + total_pages = (PHYSTOP - KERNBASE) / PGSIZE; + + Drivers::uart_puts("PMM: Total RAM size: 128MB\n"); + // Place the mem_map array + // mem_map is located immediately after kernel_end + mem_map = (struct Page*)kern_end_pa; + + uint64 mem_map_size = total_pages * sizeof(struct Page); + uint64 free_mem_start = PGROUNDUP(kern_end_pa + mem_map_size); + + Drivers::uart_puts("PMM: MemMap placed at: "); + Drivers::print_hex((uint64)mem_map); + Drivers::uart_putc('\n'); + + Drivers::uart_puts("PMM: Free memory starts at: "); + Drivers::print_hex(free_mem_start); + Drivers::uart_puts("\n"); + + if (free_mem_start >= PHYSTOP) { - Drivers::uart_puts("PMM: Error - Invalid free address\n"); - return; + Drivers::uart_puts("PMM: Error - Kernel too large, no memory left!\n"); + while (1) + ; + } + + // Initialize all page states + for (uint64 i = 0; i < total_pages; i++) + { + mem_map[i].flags = PG_reserved; + mem_map[i].order = 0; + mem_map[i].refcnt = 0; + mem_map[i].next = nullptr; + mem_map[i].prev = nullptr; } - r = (struct Run*)pa; - r->next = kmem.freelist; - kmem.freelist = r; + for (int i = 0; i < MAX_ORDER; i++) + { + free_area[i] = nullptr; + } + + // Release actual free memory to the allocator + // Range: [free_mem_start, PHYSTOP) + // Note: need to avoid the page where the DTB is located + uint64 dtb_pa_start = PGROUNDDOWN(g_dtb_addr); + uint64 dtb_pa_end = PGROUNDUP(g_dtb_addr + 0x10000); + + uint64 p = free_mem_start; + while (p < PHYSTOP) + { + if (p >= dtb_pa_start && p < dtb_pa_end) + { + p += PGSIZE; + continue; + } + + // Mark the page as Used, then call free_pages to release it + // This allows free_pages to handle the merging logic automatically + struct Page *page = pa_to_page(p); + if (page) + { + page->flags = PG_used; + free_pages((void *)p, 0); // Release page by page, let Buddy merge automatically + } + p += PGSIZE; + + + } } - void* alloc_page() + void *alloc_pages(int order) { - struct Run* r; + if (order < 0 || order >= MAX_ORDER) + return nullptr; + + pmm_lock.acquire(); - r = kmem.freelist; - if (r) + int current_order = order; + while (current_order < MAX_ORDER) { - kmem.freelist = r->next; + if (free_area[current_order]) + { + // Find free block + struct Page *page = free_area[current_order]; + list_del(page, current_order); + + // If the block is too large, split it. + while (current_order > order) + { + current_order--; + // page is the left part (Buddy A) + // buddy is the right part (Buddy B) + // Pointer addition: Page* + n is equivalent to address offset n * sizeof(Page) + // Since mem_map is linearly mapped, mem_map[i + (1<flags = PG_used; + page->order = order; // Record the orders that have been assigned + page->refcnt = 1; - uint64_t *p = (uint64_t *)r; - for (int i = 0; i < PGSIZE / 8; i++) + pmm_lock.release(); + return (void *)page_to_pa(page); + } + current_order++; + } + pmm_lock.release(); + Drivers::uart_puts("PMM: OOM alloc_pages\n"); + return nullptr; + } + + void free_pages(void *pa, int order) + { + if (!pa) + return; + struct Page *page = pa_to_page((uint64)pa); + if (!page) + return; + pmm_lock.acquire(); + + if (!(page->flags & PG_used)) + { + Drivers::uart_puts("PMM: Double free warning\n"); + pmm_lock.release(); + return; + } + + // Mark as basic status + page->flags = 0; + page->refcnt = 0; + + // try merge + uint64 page_idx = page - mem_map; + + while (order < MAX_ORDER - 1) + { + // calculate Buddy index: index ^ (1 << order) + uint64 buddy_idx = page_idx ^ (1 << order); + struct Page *buddy = &mem_map[buddy_idx]; + + // Check if the Buddy can be merged: + // 1. Must be within the memory range + // 2. Must be free (flags == 0) + // 3. Must be at the current order (to prevent merging already split small blocks) + if (buddy_idx >= total_pages || (buddy->flags & PG_used) || (buddy->flags & PG_reserved) || buddy->order != order) { - p[i] = 0; + break; } + + // Can be merged! + // Remove Buddy from the free list + list_del(buddy, order); + + // Update the current block to the merged block + // The starting address of the merged block is the smaller one between index and buddy_index + if (buddy_idx < page_idx) + { + page = buddy; + page_idx = buddy_idx; + } + + order++; } - else + + // Insert into the final order linked list + list_add(page, order); + + pmm_lock.release(); + } + + void *alloc_page() + { + void *p = alloc_pages(0); + if (p) + { + memset(p, 0, PGSIZE); + } + return p; + } + + void free_page(void *pa) + { + free_pages(pa, 0); + } + + void print_free_lists() + { + // Debug print the number of free blocks at each level + Drivers::uart_puts("PMM Stats: [ "); + for (int i = 0; i < MAX_ORDER; i++) { - Drivers::uart_puts("PMM: Out of memory!\n"); + int count = 0; + struct Page *p = free_area[i]; + while (p) + { + count++; + p = p->next; + } + if (count > 0) + { + Drivers::uart_puts("Order"); + // Drivers::uart_put_int(i); + Drivers::uart_puts(":"); + // Drivers::uart_put_int(count); + Drivers::uart_puts(" "); + } } - return (void *)r; + Drivers::uart_puts("]\n"); } -} \ No newline at end of file +} // namespace PMM diff --git a/src/kernel/mm/slab.cc b/src/kernel/mm/slab.cc new file mode 100644 index 0000000..370074a --- /dev/null +++ b/src/kernel/mm/slab.cc @@ -0,0 +1,246 @@ +#include "kernel/slab.h" +#include "kernel/pmm.h" +#include "kernel/spinlock.h" +#include "kernel/riscv.h" +#include "drivers/uart.h" +#include "lib/string.h" + +#define PG_slab 0x04 + +// Supported object size (must be a multiple of 8 and <= 2048) +const uint64 kmalloc_sizes[] = { + 16, 32, 64, 128, 256, 512, 1024, 2048}; +const int NUM_CACHES = 8; + +struct SlabHeader +{ + struct SlabHeader *next; // Next slab in the linked list + uint16 free_idx; // Index of the head of the free list (0xFFFF means none) + uint16 used_count; // Number of allocated objects + // Followed immediately by object data... + // The free list of objects is embedded in the first 2 bytes of the object itself (stores the index of the next object) +}; + +struct KmemCache +{ + Spinlock lock; + uint64 obj_size; + uint64 obj_count_per_slab; + struct SlabHeader *slab_list; // Slab list with free objects + const char *name; +}; + +struct KmemCache caches[NUM_CACHES]; + +// Virtual address -> struct Page* +static struct Page *virt_to_page(void *ptr) +{ + uint64 pa = (uint64)ptr; + return PMM::pa_to_page(pa); +} + +// Slab Implementation + +namespace Slab +{ + + void init() + { + for (int i = 0; i < NUM_CACHES; i++) + { + caches[i].lock.init("slab_lock"); + caches[i].obj_size = kmalloc_sizes[i]; + caches[i].name = "kmalloc"; + + // Calculate how many objects can fit on a page + // Excluding the overhead of the SlabHeader + uint64 available = PGSIZE - sizeof(struct SlabHeader); + caches[i].obj_count_per_slab = available / caches[i].obj_size; + caches[i].slab_list = nullptr; + } + Drivers::uart_puts("[Slab] Initialized kmalloc caches.\n"); + } + + // Allocate a new slab page for the cache + // Must hold cache->lock + static struct SlabHeader *grow_cache(struct KmemCache *c) + { + void *p = PMM::alloc_page(); + if (!p) + return nullptr; + + // Mark this page as a Slab page + struct Page *page = virt_to_page(p); + if (page) + { + page->flags |= PG_slab; + int cache_idx = c - caches; + page->order = (uint8)cache_idx; + } + + struct SlabHeader *slab = (struct SlabHeader *)p; + slab->next = nullptr; + slab->used_count = 0; + slab->free_idx = 0; + + // Initialize the free list of objects + // The starting position of each object stores the index of the next object + // Starting position of the object data area + char *base = (char *)(slab + 1); + + for (uint i = 0; i < c->obj_count_per_slab - 1; i++) + { + // The content of the i-th object is i+1 + uint16 *ptr = (uint16 *)(base + i * c->obj_size); + *ptr = i + 1; + } + // The last object points to 0xFFFF + uint16 *ptr = (uint16 *)(base + (c->obj_count_per_slab - 1) * c->obj_size); + *ptr = 0xFFFF; + + return slab; + } + + void *kmalloc(uint64 size) + { + if (size == 0) + return nullptr; + + // Large objects go directly through PMM + if (size > 2048) + { + // calculate order + int order = 0; + uint64 req = size; + uint64 pages = (size + PGSIZE - 1) / PGSIZE; + (void)req; + + // calculate order: 2^order >= pages + while ((1UL << order) < pages) + { + order++; + } + if (order > MAX_ORDER) + return nullptr; + + void *p = PMM::alloc_pages(order); + // Here, page->flags defaults to PG_used, not PG_slab + // kfree needs to be able to recognize it + return p; + } + + int idx = 0; + while (idx < NUM_CACHES && kmalloc_sizes[idx] < size) + { + idx++; + } + + struct KmemCache *c = &caches[idx]; + c->lock.acquire(); + + if (!c->slab_list) + { + c->slab_list = grow_cache(c); + if (!c->slab_list) + { + c->lock.release(); + return nullptr; + } + } + + struct SlabHeader *slab = c->slab_list; + + int obj_idx = slab->free_idx; + char *base = (char *)(slab + 1); + void *ptr = base + obj_idx * c->obj_size; + + uint16 *link = (uint16 *)ptr; + slab->free_idx = *link; + slab->used_count++; + + if (slab->free_idx == 0xFFFF) + { + if (slab->next) + { + c->slab_list = slab->next; + slab->next = nullptr; + } + else + { + c->slab_list = nullptr; + } + } + + c->lock.release(); + + memset(ptr, 0, size); + return ptr; + } + + void kfree(void *ptr) + { + if (!ptr) + return; + + struct Page *page = virt_to_page(ptr); + if (!page) + return; + + if (!(page->flags & PG_slab)) + { + PMM::free_pages(ptr, page->order); + return; + } + + int cache_idx = page->order; + if (cache_idx >= NUM_CACHES) + { + Drivers::uart_puts("Slab: Corrupted page metadata\n"); + return; + } + + struct KmemCache *c = &caches[cache_idx]; + c->lock.acquire(); + + struct SlabHeader *slab = (struct SlabHeader *)PGROUNDDOWN((uint64)ptr); + + char *base = (char *)(slab + 1); + int obj_idx = ((uint64)ptr - (uint64)base) / c->obj_size; + + uint16 *link = (uint16 *)ptr; + *link = slab->free_idx; + slab->free_idx = (uint16)obj_idx; + + slab->used_count--; + + if (slab->used_count == 0) + { + struct SlabHeader **pp = &c->slab_list; + // bool found = false; + while (*pp) + { + if (*pp == slab) + { + *pp = slab->next; + // found = true; + break; + } + pp = &(*pp)->next; + } + + page->flags &= ~PG_slab; + PMM::free_page(slab); + } + else + { + + if (slab->used_count == c->obj_count_per_slab - 1) + { + slab->next = c->slab_list; + c->slab_list = slab; + } + } + + c->lock.release(); + } +} \ No newline at end of file diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc index 650fcf1..c3c5f01 100644 --- a/src/kernel/mm/vm.cc +++ b/src/kernel/mm/vm.cc @@ -1,75 +1,88 @@ #include "kernel/mm.h" #include "kernel/pmm.h" #include "kernel/riscv.h" -#include "drivers/uart.h" #include "common/types.h" -#include "kernel/config.h" #include "lib/string.h" +#include "drivers/uart.h" +// COW Flag (PTE bit 8) +#define PTE_COW (1L << 8) -extern char text_start[]; -extern char text_end[]; -extern char rodata_start[]; -extern char rodata_end[]; -extern char data_start[]; -extern char data_end[]; -extern char bss_start[]; -extern char bss_end[]; -extern char kernel_end[]; - -extern char uservec[]; -extern char userret[]; -extern char trampoline[]; - -VM::pagetable_t kernel_pagetable; +extern "C" +{ + extern char kernel_end[]; + extern char trampoline[]; +} namespace VM { - // pagetable_t kernel_pagetable; - pte_t *walk(pagetable_t pagetable, uint64 va, int alloc) + uint64 *kernel_pagetable; + + static void page_ref_inc(uint64 pa) + { + struct Page *p = PMM::pa_to_page(pa); + if (p) + { + __atomic_add_fetch(&p->refcnt, 1, __ATOMIC_RELAXED); + } + } + + static bool page_ref_dec(uint64 pa) + { + struct Page *p = PMM::pa_to_page(pa); + if (p) + { + if (__atomic_sub_fetch(&p->refcnt, 1, __ATOMIC_RELEASE) == 0) + { + return true; + } + } + return false; + } + + static uint64 *walk(uint64 *pagetable, uint64 va, int alloc) { if (va >= MAXVA) - return 0; - + return nullptr; + for (int level = 2; level > 0; level--) { - pte_t *pte = &pagetable[PX(level, va)]; - + uint64 *pte = &pagetable[PX(level, va)]; if (*pte & PTE_V) { - pagetable = (pagetable_t)PTE2PA(*pte); + pagetable = (uint64 *)PTE2PA(*pte); } else { - if (!alloc || (pagetable = (pagetable_t)PMM::alloc_page()) == 0) - return 0; + if (!alloc || (pagetable = (uint64 *)PMM::alloc_page()) == nullptr) + return nullptr; + memset(pagetable, 0, PGSIZE); - // pagetable = (pagetable_t)PMM::alloc_page(); *pte = PA2PTE(pagetable) | PTE_V; } } return &pagetable[PX(0, va)]; } - int mappages(pagetable_t pagetable, uint64 va, uint64 size, uint64 pa, int perm) + int mappages(uint64 *pagetable, uint64 va, uint64 size, uint64 pa, int perm) { uint64 a, last; - pte_t *pte; + uint64 *pte; + + if (size == 0) + return -1; a = PGROUNDDOWN(va); last = PGROUNDDOWN(va + size - 1); - for(;;) + for (;;) { - if((pte = walk(pagetable, a, 1)) == 0) + if ((pte = walk(pagetable, a, 1)) == nullptr) return -1; if (*pte & PTE_V) { - Drivers::uart_puts("Remap panic: "); - Drivers::print_hex(a); - Drivers::uart_puts("\n"); return -1; } @@ -83,228 +96,281 @@ namespace VM return 0; } - void kvmmap(uint64 va, uint64 pa, uint64 sz, int perm) + uint64 *uvmcreate() { - if (mappages(kernel_pagetable, va, sz, pa, perm) != 0) + uint64 *pagetable = (uint64 *)PMM::alloc_page(); + if (pagetable) { - Drivers::uart_puts("kvmmap: failed to map\n"); + memset(pagetable, 0, PGSIZE); + + if (mappages(pagetable, TRAMPOLINE, PGSIZE, (uint64)trampoline, PTE_R | PTE_X) < 0) + { + PMM::free_page(pagetable); + return nullptr; + } } + return pagetable; } - void kvminit() + void uvminit(uint64 *pagetable, uchar *src, uint64 sz) { - kernel_pagetable = (pagetable_t)PMM::alloc_page(); - memset(kernel_pagetable, 0, PGSIZE); - - kvmmap(g_uart_base, g_uart_base, PGSIZE, PTE_R | PTE_W); - - kvmmap(g_plic_base, g_plic_base, 0x400000, PTE_R | PTE_W); - - // kvmmap(g_clint_base, g_clint_base, 0x10000, PTE_R | PTE_W); - - kvmmap((uint64)text_start, (uint64)text_start, - (uint64)text_end - (uint64)text_start, PTE_R | PTE_X); - - kvmmap((uint64)rodata_start, (uint64)rodata_start, - (uint64)rodata_end - (uint64)rodata_start, PTE_R); + char *mem; - kvmmap((uint64)data_start, (uint64)data_start, - (uint64)kernel_end - (uint64)data_start, PTE_R | PTE_W); + if (sz >= PGSIZE) + { + Drivers::uart_puts("uvminit: initcode too big!\n"); + return; + } - kvmmap((uint64)kernel_end, (uint64)kernel_end, - (uint64)PHYSTOP - (uint64)kernel_end, PTE_R | PTE_W); + mem = (char *)PMM::alloc_page(); + memset(mem, 0, PGSIZE); - kvmmap(TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X); - } - void kvminithart() - { - w_satp(MAKE_SATP(kernel_pagetable)); - sfence_vma(); + mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W | PTE_R | PTE_X | PTE_U); + memmove(mem, src, sz); } - - pagetable_t uvmcreate() + uint64 uvmalloc(uint64 *pagetable, uint64 oldsz, uint64 newsz, int xperm) { - pagetable_t pagetable = (pagetable_t)PMM::alloc_page(); - if (pagetable == 0) - return 0; - memset(pagetable, 0, PGSIZE); + char *mem; + uint64 a; + + if (newsz < oldsz) + return oldsz; - if (mappages(pagetable, TRAMPOLINE, PGSIZE, (uint64)trampoline, PTE_R | PTE_X) < 0) + oldsz = PGROUNDUP(oldsz); + for (a = oldsz; a < newsz; a += PGSIZE) { - return 0; + mem = (char *)PMM::alloc_page(); + if (mem == nullptr) + { + uvmdealloc(pagetable, a, oldsz); + return 0; + } + memset(mem, 0, PGSIZE); + if (mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_R | PTE_U | xperm) != 0) + { + PMM::free_page(mem); + uvmdealloc(pagetable, a, oldsz); + return 0; + } } - - return pagetable; + return newsz; } - void uvminit(pagetable_t pagetable, uchar *src, uint sz) + uint64 uvmdealloc(uint64 *pagetable, uint64 oldsz, uint64 newsz) { - char *mem; + if (newsz >= oldsz) + return oldsz; - if (sz >= PGSIZE) + if (PGROUNDUP(newsz) < PGROUNDUP(oldsz)) { - Drivers::uart_puts("uvminit: initcode too big\n"); - return; + int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE; + uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1); } - mem = (char*)PMM::alloc_page(); - memset(mem, 0, PGSIZE); - - mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X|PTE_U); - - memmove(mem, src, sz); - - uint64 trap_pa = (uint64)uservec; - uint64 trap_page_start = PGROUNDDOWN(trap_pa); - - mappages(pagetable, trap_page_start, PGSIZE, trap_page_start, PTE_R | PTE_X); - - mappages(pagetable, trap_page_start + PGSIZE, PGSIZE, trap_page_start + PGSIZE, PTE_R | PTE_X); + return newsz; } - void uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free) + void uvmunmap(uint64 *pagetable, uint64 va, uint64 npages, int do_free) { uint64 a; - pte_t *pte; + uint64 *pte; if ((va % PGSIZE) != 0) - { - Drivers::uart_puts("uvmunmap: not aligned\n"); return; - } - for(a = va; a < va + npages * PGSIZE; a += PGSIZE) + for (a = va; a < va + npages * PGSIZE; a += PGSIZE) { - if ((pte = walk(pagetable, a, 0)) == 0) + if ((pte = walk(pagetable, a, 0)) == nullptr) continue; - if((*pte & PTE_V) == 0) + if ((*pte & PTE_V) == 0) continue; - if (PTE_FLAGS(*pte) == PTE_V) + if ((PTE_FLAGS(*pte) & (PTE_R | PTE_W | PTE_X)) == 0) { - Drivers::uart_puts("uvmunmap: not a leaf\n"); + continue; } if (do_free) { uint64 pa = PTE2PA(*pte); - PMM::free_page((void *)pa); + if (page_ref_dec(pa)) + { + PMM::free_page((void *)pa); + } } *pte = 0; } } - void uvmfree(pagetable_t pagetable, uint64 sz) + static void freewalk(uint64 *pagetable) { - if(sz > 0) - uvmunmap(pagetable, 0, PGROUNDDOWN(sz)/PGSIZE, 1); + for (int i = 0; i < 512; i++) + { + uint64 pte = pagetable[i]; + if ((pte & PTE_V) && (pte & (PTE_R | PTE_W | PTE_X)) == 0) + { + uint64 *child = (uint64 *)PTE2PA(pte); + freewalk(child); + pagetable[i] = 0; + } + } + PMM::free_page(pagetable); + } - PMM::free_page((void *)pagetable); + void uvmfree(uint64 *pagetable, uint64 sz) + { + if (sz > 0) + uvmunmap(pagetable, 0, PGROUNDUP(sz) / PGSIZE, 1); + freewalk(pagetable); } - int uvmcopy(pagetable_t oldpt, pagetable_t newpt, uint64 sz) + int uvmcopy(uint64 *oldpt, uint64 *newpt, uint64 sz) { - pte_t *pte; + uint64 *pte; uint64 pa, i; uint flags; - char *mem; - for(i = 0; i < sz; i += PGSIZE) + for (i = 0; i < sz; i += PGSIZE) { - if((pte = walk(oldpt, i, 0)) == 0) + if ((pte = walk(oldpt, i, 0)) == nullptr) continue; if ((*pte & PTE_V) == 0) continue; - + pa = PTE2PA(*pte); flags = PTE_FLAGS(*pte); - if ((mem = (char *)PMM::alloc_page()) == 0) - goto err; - - memmove(mem, (char *)pa, PGSIZE); + if (flags & PTE_W) + { + flags &= ~PTE_W; + flags |= PTE_COW; + *pte = PA2PTE(pa) | flags; + } - if (mappages(newpt, i, PGSIZE, (uint64)mem, flags) != 0) + if (mappages(newpt, i, PGSIZE, pa, flags) != 0) { - PMM::free_page(mem); - goto err; + return -1; } + + page_ref_inc(pa); } + + sfence_vma(); return 0; - err: - uvmunmap(newpt, 0, i / PGSIZE, 1); - return -1; } - uint64 uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) + int copyout(uint64 *pagetable, uint64 dstva, char *src, uint64 len) { - char *mem; - uint64 a; - - if (newsz < oldsz) - return oldsz; + uint64 n, va0, pa0; + uint64 *pte; - oldsz = PGROUNDUP(oldsz); - for (a = oldsz; a < newsz; a += PGSIZE) + while (len > 0) { - mem = (char *)PMM::alloc_page(); - if (mem == 0) - { - uvmdealloc(pagetable, a, oldsz); - return 0; - } - memset(mem, 0, PGSIZE); - if (mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W | PTE_X | PTE_R | PTE_U) != 0) - { - PMM::free_page(mem); - uvmdealloc(pagetable, a, oldsz); - return 0; - } - } - return newsz; - } + va0 = PGROUNDDOWN(dstva); + pte = walk(pagetable, va0, 0); + if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0) + return -1; - uint64 uvmdealloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz) - { - if (newsz >= oldsz) - return oldsz; + pa0 = PTE2PA(*pte); + n = PGSIZE - (dstva - va0); + if (n > len) + n = len; - if (PGROUNDUP(newsz) < PGROUNDUP(oldsz)) - { - int npages = (PGROUNDUP(oldsz) - PGROUNDUP(newsz)) / PGSIZE; - uvmunmap(pagetable, PGROUNDUP(newsz), npages, 1); - } + memmove((void *)(pa0 + (dstva - va0)), src, n); - return newsz; + len -= n; + src += n; + dstva = va0 + PGSIZE; + } + return 0; } - int copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len) + int copyin(uint64 *pagetable, char *dst, uint64 srcva, uint64 len) { uint64 n, va0, pa0; - pte_t *pte; + uint64 *pte; while (len > 0) { va0 = PGROUNDDOWN(srcva); pte = walk(pagetable, va0, 0); - if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0) - { + if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0) return -1; - } + pa0 = PTE2PA(*pte); n = PGSIZE - (srcva - va0); - if(n > len) + if (n > len) n = len; - - memmove(dst, (void*)(pa0 + (srcva - va0)), n); + + memmove(dst, (void *)(pa0 + (srcva - va0)), n); len -= n; dst += n; srcva = va0 + PGSIZE; } return 0; - + } + + int handle_cow_fault(uint64 *pagetable, uint64 va) + { + if (va >= MAXVA) + return -1; + + uint64 *pte = walk(pagetable, va, 0); + if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0) + return -1; + + if ((*pte & PTE_COW) == 0) + return -1; + + uint64 pa = PTE2PA(*pte); + uint64 flags = PTE_FLAGS(*pte); + + char *mem = (char *)PMM::alloc_page(); + if (mem == nullptr) + return -1; + + memmove(mem, (char *)pa, PGSIZE); + + uint64 new_flags = (flags | PTE_W) & ~PTE_COW; + *pte = PA2PTE((uint64)mem) | new_flags | PTE_V; + + if (page_ref_dec(pa)) + { + PMM::free_page((void *)pa); + } + + sfence_vma(); + return 0; + } + + static void kvmmap(uint64 va, uint64 pa, uint64 sz, int perm) + { + if (mappages(kernel_pagetable, va, sz, pa, perm) != 0) + { + Drivers::uart_puts("kvmmap: failed\n"); + while (1) + ; + } + } + + void kvminit() + { + kernel_pagetable = uvmcreate(); + + kvmmap(0x10000000, 0x10000000, PGSIZE, PTE_R | PTE_W); + kvmmap(0x0c000000, 0x0c000000, 0x400000, PTE_R | PTE_W); + kvmmap(0x02000000, 0x02000000, 0x10000, PTE_R | PTE_W); // CLINT + kvmmap(KERNBASE, KERNBASE, PHYSTOP - KERNBASE, PTE_R | PTE_W | PTE_X); + // kvmmap(TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X); + } + + void kvminithart() + { + w_satp(MAKE_SATP(kernel_pagetable)); + sfence_vma(); + Drivers::uart_puts("[Boot] MMU ENABLED! Using virtual addresses.\n"); } } \ No newline at end of file diff --git a/src/kernel/proc/proc.cc b/src/kernel/proc/proc.cc index 77a078e..e99b83d 100644 --- a/src/kernel/proc/proc.cc +++ b/src/kernel/proc/proc.cc @@ -1,120 +1,198 @@ #include "kernel/proc.h" +#include "kernel/proc_def.h" +#include "kernel/runqueue.h" +#include "kernel/cpu.h" +#include "kernel/spinlock.h" #include "kernel/pmm.h" #include "kernel/mm.h" -#include "drivers/uart.h" #include "kernel/trap.h" -#include "common/types.h" #include "kernel/riscv.h" -#include "kernel/config.h" -#include "kernel/spinlock.h" +#include "drivers/uart.h" #include "lib/string.h" -#define NPROC 10 +#define NPROC 64 #define NCPU 8 extern "C" void swtch(struct Context *old_ctx, struct Context *new_ctx); -extern char uservec[]; +extern char uservec[], trampoline[]; +extern "C" void usertrap(); extern "C" void userret(uint64, uint64); -extern char trampoline[]; +extern char initcode_start[], initcode_end[]; struct Proc procs[NPROC]; -struct Context main_context; // The main_context here should actually be one per CPU, but it's temporarily kept for compatibility with single-core logic -struct Proc *current_proc = nullptr; -struct Spinlock proc_lock; - +struct Spinlock proc_mem_lock; struct cpu cpus[NCPU]; +struct RunQueue runqueues[NCPU]; + + +static int nextpid = 1; + + +struct cpu *mycpu() +{ + int id = r_tp(); + return &cpus[id]; +} + -int nextpid = 1; +void RunQueue::init(const char *name) +{ + lock.init(name); + count = 0; + for (int i = 0; i < N_PRIO; i++) + { + heads[i] = nullptr; + tails[i] = nullptr; + } +} + +void RunQueue::enqueue(struct Proc *p) +{ + if (p->priority < 0 || p->priority >= N_PRIO) + p->priority = PRIO_MIN; + p->next = nullptr; + if (heads[p->priority] == nullptr) + { + heads[p->priority] = p; + tails[p->priority] = p; + } + else + { + tails[p->priority]->next = p; + tails[p->priority] = p; + } + count++; +} -extern char initcode_start[]; -extern char initcode_end[]; +struct Proc *RunQueue::dequeue() +{ + for (int i = 0; i < N_PRIO; i++) + { + if (heads[i]) + { + struct Proc *p = heads[i]; + heads[i] = p->next; + if (!heads[i]) + tails[i] = nullptr; + p->next = nullptr; + count--; + return p; + } + } + return nullptr; +} -struct Proc *myproc() +struct Proc *RunQueue::steal() { - // Keep a simple implementation for now, should be changed later to: - // push_off(); - // struct cpu *c = mycpu(); - // struct Proc *p = c->proc; - // pop_off(); - // return p; - return current_proc; + for (int i = N_PRIO - 1; i >= 0; i--) + { + if (heads[i]) + { + struct Proc *p = heads[i]; + heads[i] = p->next; + if (!heads[i]) + tails[i] = nullptr; + p->next = nullptr; + count--; + return p; + } + } + return nullptr; } +// Trap Return Functions + void usertrapret() { struct Proc *p = myproc(); intr_off(); + // Set stvec to point to uservec in the trampoline + // When an interrupt occurs in user mode, the CPU will jump here uint64 trampoline_uservec = TRAMPOLINE + (uservec - trampoline); w_stvec(trampoline_uservec); + // Fill in the Trapframe, used when uservec saves the kernel state p->tf->kernel_satp = r_satp(); p->tf->kernel_sp = (uint64)p->kstack + PGSIZE; p->tf->kernel_trap = (uint64)usertrap; p->tf->kernel_hartid = r_tp(); + // Set SSTATUS + // SPP = 0 (return to User Mode) + // SPIE = 1 (enable interrupts) unsigned long x = r_sstatus(); x &= ~SSTATUS_SPP; x |= SSTATUS_SPIE; w_sstatus(x); + // Set SEPC to the user program counter w_sepc(p->tf->epc); + // Prepare user page table SATP uint64 satp = MAKE_SATP(p->pagetable); + // Calculate the virtual address of userret in the trampoline uint64 fn = TRAMPOLINE + ((uint64)userret - (uint64)trampoline); + + // Jump to userret, with parameters being the TRAPFRAME address and the user page table SATP ((void (*)(uint64, uint64))fn)(TRAPFRAME, satp); } + void forkret() { - //.... - proc_lock.release(); + + struct cpu *c = mycpu(); + c->runqueue->lock.release(); Drivers::uart_puts("[Proc] forkret: jumping to user.\n"); + + // Enter user mode usertrapret(); } +// ProcManager Implementation + static Proc *allocproc() { - struct Proc* p; - proc_lock.acquire(); + struct Proc *p; + proc_mem_lock.acquire(); for (p = procs; p < &procs[NPROC]; p++) { if (p->state == UNUSED) - { goto found; - } } - - proc_lock.release(); + proc_mem_lock.release(); return 0; found: p->state = USED; p->pid = nextpid++; + p->priority = 0; + p->cpu = mycpu(); if ((p->tf = (struct Trapframe *)PMM::alloc_page()) == 0) { p->state = UNUSED; - proc_lock.release(); + proc_mem_lock.release(); return 0; } if ((p->kstack = PMM::alloc_page()) == 0) { PMM::free_page(p->tf); p->state = UNUSED; - proc_lock.release(); + proc_mem_lock.release(); return 0; } memset(p->kstack, 0, PGSIZE); memset(&p->context, 0, sizeof(p->context)); + + // Set the context so that the next time this process is scheduled, it starts executing directly from forkret p->context.ra = (uint64)forkret; p->context.sp = (uint64)p->kstack + PGSIZE; - - proc_lock.release(); return p; } @@ -123,15 +201,12 @@ static void freeproc(struct Proc *p) if (p->tf) PMM::free_page(p->tf); p->tf = 0; - if (p->kstack) PMM::free_page(p->kstack); p->kstack = 0; - if (p->pagetable) VM::uvmfree(p->pagetable, p->sz); p->pagetable = 0; - p->sz = 0; p->pid = 0; p->parent = 0; @@ -142,204 +217,225 @@ static void freeproc(struct Proc *p) int fork() { - int pid; struct Proc *np; struct Proc *p = myproc(); if ((np = allocproc()) == 0) - { return -1; - } np->pagetable = VM::uvmcreate(); - if (VM::uvmcopy(p->pagetable, np->pagetable, p->sz) < 0) { freeproc(np); - proc_lock.release(); // Maybe a bug + proc_mem_lock.release(); return -1; } np->sz = p->sz; - if (VM::mappages(np->pagetable, TRAPFRAME, PGSIZE, - (uint64)np->tf, PTE_R | PTE_W) < 0) + if (VM::mappages(np->pagetable, TRAPFRAME, PGSIZE, (uint64)np->tf, PTE_R | PTE_W) < 0) { freeproc(np); + proc_mem_lock.release(); return -1; } *(np->tf) = *(p->tf); - np->tf->a0 = 0; - strcpy(np->name, p->name); np->parent = p; + np->priority = p->priority; - proc_lock.acquire(); + proc_mem_lock.release(); + + struct cpu *c = mycpu(); + c->runqueue->lock.acquire(); np->state = RUNNABLE; - pid = np->pid; - proc_lock.release(); + c->runqueue->enqueue(np); + c->runqueue->lock.release(); - return pid; + return np->pid; } namespace ProcManager { + void init() { - proc_lock.init("proc"); - + proc_mem_lock.init("proc_mem"); for (int i = 0; i < NPROC; i++) - { procs[i].state = UNUSED; - procs[i].kstack = 0; + + for (int i = 0; i < NCPU; i++) + { + cpus[i].runqueue = &runqueues[i]; + cpus[i].runqueue->init("runqueue"); } } - void create_kernel_thread(void (*func)(), const char *name) + void scheduler() { - struct Proc *p = nullptr; - for(int i = 0; i < NPROC; i++) - { - if(procs[i].state == UNUSED) - { - p = &procs[i]; - p->pid = i + 1; - break; - } - } + struct Proc *p; + struct cpu *c = mycpu(); + c->proc = 0; + Drivers::uart_puts("[Proc] Scheduler started (Per-CPU).\n"); - if (!p) + for (;;) { - Drivers::uart_puts("Error: No free process slots!\n"); - return; - } + intr_on(); - p->kstack = PMM::alloc_page(); - if (!p->kstack) - { - Drivers::uart_puts("Error: Alloc kstack failed!\n"); - return; - } + // Get from the local queue + c->runqueue->lock.acquire(); + p = c->runqueue->dequeue(); + c->runqueue->lock.release(); - p->context.ra = (uint64)func; + // Work Stealing + if (!p) + { + for (int i = 0; i < NCPU; i++) + { + if ((uint64)i == r_tp()) + continue; + + struct cpu *victim = &cpus[i]; + victim->runqueue->lock.acquire(); + if (victim->runqueue->count > 0) + p = victim->runqueue->steal(); + victim->runqueue->lock.release(); + if (p) + break; + } + } - p->context.sp = (uint64)p->kstack + 4096; + if (p) + { + p->state = RUNNING; + c->proc = p; - p->state = RUNNABLE; - strcpy(p->name, name); + c->runqueue->lock.acquire(); + swtch(&c->context, &p->context); + c->runqueue->lock.release(); - Drivers::uart_puts("[Proc] Created thread: "); - Drivers::uart_puts(name); - Drivers::uart_puts("\n"); + c->proc = 0; + } + } } void yield() { struct Proc *p = myproc(); - proc_lock.acquire(); + struct cpu *c = mycpu(); + c->runqueue->lock.acquire(); if (p && p->state == RUNNING) { p->state = RUNNABLE; - swtch(&p->context, &main_context); + if (p->priority < PRIO_MIN) + p->priority++; + c->runqueue->enqueue(p); + swtch(&p->context, &c->context); } - proc_lock.release(); + c->runqueue->lock.release(); } - void scheduler() + void user_init() { - struct Proc *p = nullptr; - Drivers::uart_puts("[Proc] Scheduler started.\n"); + struct Proc *p = allocproc(); + if (!p) + return; - for (;;) + p->pagetable = VM::uvmcreate(); + + uint64 initcode_sz = initcode_end - initcode_start; + Drivers::uart_puts("[Proc] initcode size: "); + Drivers::uart_put_int(initcode_sz); + Drivers::uart_puts(" bytes\n"); + + uint64 code_pages = PGROUNDUP(initcode_sz) / PGSIZE; + + for (uint64 i = 0; i < code_pages; i++) { - intr_on(); + void *mem = PMM::alloc_page(); + if (!mem) + { + Drivers::uart_puts("user_init: out of memory for code\n"); + return; + } + memset(mem, 0, PGSIZE); - proc_lock.acquire(); + uint64 src_offset = i * PGSIZE; + uint64 copy_len = PGSIZE; + if (src_offset + copy_len > initcode_sz) + { + copy_len = initcode_sz - src_offset; + } + memmove(mem, (void *)(initcode_start + src_offset), copy_len); - for (p = procs; p < &procs[NPROC]; p++) + if (VM::mappages(p->pagetable, i * PGSIZE, PGSIZE, (uint64)mem, PTE_R | PTE_W | PTE_X | PTE_U) < 0) { - if (p->state == RUNNABLE) - { - p->state = RUNNING; - current_proc = p; - // Switch context: from scheduler to process - swtch(&main_context, &p->context); - // The process returns here after yielding the CPU - current_proc = nullptr; - } + Drivers::uart_puts("user_init: mappages code failed\n"); + return; } - proc_lock.release(); } - } - void user_init() - { - struct Proc *p; + uint64 stack_va = (code_pages + 1) * PGSIZE; - p = allocproc(); - if (!p) - { - Drivers::uart_puts("user_init: failed\n"); + void *stack = PMM::alloc_page(); + if (!stack) return; - } - - p->pagetable = VM::uvmcreate(); + memset(stack, 0, PGSIZE); - uint64 initcode_sz = initcode_end - initcode_start; - VM::uvminit(p->pagetable, (uchar *)initcode_start, initcode_sz); - p->sz = PGSIZE; + if (VM::mappages(p->pagetable, stack_va, PGSIZE, (uint64)stack, PTE_R | PTE_W | PTE_U) < 0) + return; - if (VM::mappages(p->pagetable, TRAPFRAME, PGSIZE, - (uint64)p->tf, PTE_R | PTE_W) < 0) - { - Drivers::uart_puts("user_init: map trapframe failed\n"); + if (VM::mappages(p->pagetable, TRAPFRAME, PGSIZE, (uint64)p->tf, PTE_R | PTE_W) < 0) return; - } - p->tf->epc = 0; - p->tf->sp = PGSIZE; - + p->tf->sp = stack_va + PGSIZE; + p->sz = stack_va + PGSIZE; strcpy(p->name, "initcode"); - - proc_lock.acquire(); + proc_mem_lock.release(); + + struct cpu *c = &cpus[0]; + c->runqueue->lock.acquire(); p->state = RUNNABLE; - proc_lock.release(); + c->runqueue->enqueue(p); + c->runqueue->lock.release(); Drivers::uart_puts("[Proc] user_init success. PID: 1\n"); + asm volatile("fence.i"); } - void sleep(void *chan, struct Spinlock *lk) + void sleep(void *chan, Spinlock *lk) { struct Proc *p = myproc(); - if(lk != &proc_lock) - { - proc_lock.acquire(); + struct cpu *c = mycpu(); + + if (lk && lk != &proc_mem_lock) lk->release(); - } + + c->runqueue->lock.acquire(); p->chan = chan; p->state = SLEEPING; - - swtch(&p->context, &main_context); - + swtch(&p->context, &c->context); p->chan = 0; + c->runqueue->lock.release(); - if (lk != &proc_lock) - { - proc_lock.release(); + if (lk && lk != &proc_mem_lock) lk->acquire(); - } } void wakeup(void *chan) { - for(struct Proc *p = procs; p < &procs[NPROC]; p++) + for (struct Proc *p = procs; p < &procs[NPROC]; p++) { if (p->state == SLEEPING && p->chan == chan) { + struct cpu *c = mycpu(); + c->runqueue->lock.acquire(); p->state = RUNNABLE; + c->runqueue->enqueue(p); + c->runqueue->lock.release(); } } } @@ -348,15 +444,10 @@ namespace ProcManager { struct Proc *p = myproc(); struct Proc *initproc = &procs[0]; - if (p == initproc) - { - Drivers::uart_puts("init exiting!\n"); while (1) ; - } - proc_lock.acquire(); wakeup(p->parent); for (struct Proc *pp = procs; pp < &procs[NPROC]; pp++) @@ -369,24 +460,27 @@ namespace ProcManager } p->xstate = status; - p->state = ZOMBIE; - - swtch(&p->context, &main_context); - while(1); + struct cpu *c = mycpu(); + c->runqueue->lock.acquire(); + p->state = ZOMBIE; + swtch(&p->context, &c->context); + while (1) + ; } int wait(uint64 addr) { - struct Proc* np; + (void)addr; + + struct Proc *np; int havekids, pid; struct Proc *p = myproc(); - - proc_lock.acquire(); - - for(;;) + for (;;) { havekids = 0; + proc_mem_lock.acquire(); + for (np = procs; np < &procs[NPROC]; np++) { if (np->parent == p) @@ -394,30 +488,34 @@ namespace ProcManager havekids = 1; if (np->state == ZOMBIE) { - // Found one - pid = np->pid; - if (addr != 0) + + struct cpu *child_cpu = np->cpu; + if (child_cpu) { - // copyout(p->pagetable, addr, (char*)&np->xstate, sizeof(np->xstate)); - // 暂时不做 copyout + proc_mem_lock.release(); + child_cpu->runqueue->lock.acquire(); + child_cpu->runqueue->lock.release(); + proc_mem_lock.acquire(); } + + pid = np->pid; freeproc(np); - proc_lock.release(); + proc_mem_lock.release(); return pid; } } } + proc_mem_lock.release(); + if (!havekids || p->state == ZOMBIE) - { - proc_lock.release(); return -1; - } - // sleep will atomically release proc_lock and sleep - // When returning, it will reacquire proc_lock - sleep(p, &proc_lock); + sleep(p, nullptr); } } - - + void create_kernel_thread(void (*func)(), const char *name) + { + (void)func; + (void)name; + } } \ No newline at end of file diff --git a/src/kernel/spinlock.cc b/src/kernel/spinlock.cc index 426f639..55dfc6b 100644 --- a/src/kernel/spinlock.cc +++ b/src/kernel/spinlock.cc @@ -1,18 +1,29 @@ #include "kernel/spinlock.h" #include "kernel/riscv.h" -#include "kernel/proc.h" +#include "kernel/cpu.h" +#include "kernel/proc_def.h" #include "drivers/uart.h" extern struct cpu cpus[]; -// Get the pointer of the current CPU -// Depends on r_tp() in riscv.h to read the tp register -struct cpu *mycpu() +namespace ProcManager { - int id = r_tp(); - return &cpus[id]; + void sleep(void *chan, Spinlock *lk); + void wakeup(void *chan); } +// Interrupt Depth Management +void push_off(void); +void pop_off(void); + +// // Get the pointer of the current CPU +// // Depends on r_tp() in riscv.h to read the tp register +// struct cpu *mycpu() +// { +// int id = r_tp(); +// return &cpus[id]; +// } + // Get the current process // Must be called with interrupts disabled, or read atomically in a safe manner struct Proc *myproc() @@ -24,10 +35,6 @@ struct Proc *myproc() return p; } -// Interrupt Depth Management -void push_off(void); -void pop_off(void); - // Spinlock Implementation void Spinlock::init(const char *lock_name) @@ -81,7 +88,7 @@ void Spinlock::release() // __ATOMIC_RELEASE: Ensures all reads and writes before the Release are completed __atomic_store_n(&locked, 0, __ATOMIC_RELEASE); - pop_off(); // 2. 恢复中断状态 + pop_off(); } // Check if the current CPU holds the lock @@ -103,7 +110,7 @@ void Mutex::init(const char *lock_name) name = lock_name; locked = 0; pid = 0; - lk.init("mutex_internal"); // 初始化内部自旋锁 + lk.init("mutex_internal"); } void Mutex::acquire() @@ -158,7 +165,7 @@ void push_off(void) struct cpu *c = mycpu(); if (c->noff == 0) - c->intena = old; // 记录最外层的中断状态 + c->intena = old; c->noff += 1; } diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc index 92b1a1b..1dfec73 100644 --- a/src/kernel/syscall.cc +++ b/src/kernel/syscall.cc @@ -5,18 +5,20 @@ #include "drivers/uart.h" #include "kernel/timer.h" #include "kernel/mm.h" +#include "kernel/trap.h" -extern int fork(); +extern "C++" int fork(); namespace ProcManager { void exit(int status); - int wait(uint64 addr); + int wait(uint64_t addr); } -uint64 argraw(int n) + +static uint64_t argraw(int n) { - struct Proc *p = myproc(); + Proc *p = myproc(); switch (n) { case 0: @@ -31,76 +33,84 @@ uint64 argraw(int n) return p->tf->a4; case 5: return p->tf->a5; + default: + return static_cast(-1); } - return -1; } -int argint(int n, int *ip) +static int argint(int n, int *ip) { - *ip = argraw(n); + *ip = static_cast(argraw(n)); return 0; } -uint64 sys_exit() + +static uint64_t sys_exit() { int n; if (argint(0, &n) < 0) - return -1; + return static_cast(-1); ProcManager::exit(n); return 0; } -uint64 sys_fork() +static uint64_t sys_fork() { - return fork(); + return static_cast(fork()); } -uint64 sys_wait() +static uint64_t sys_wait() { - uint64 p; - p = argraw(0); - return ProcManager::wait(p); + uint64_t p = argraw(0); + return static_cast(ProcManager::wait(p)); } -uint64 sys_getpid() +static uint64_t sys_getpid() { - return myproc()->pid; + return static_cast(myproc()->pid); } -uint64 sys_putc() +static uint64_t sys_putc() { - char c = (char)argraw(0); + char c = static_cast(argraw(0)); Drivers::uart_putc(c); return 0; } -uint64 sys_write() +static uint64_t sys_write() { int fd; - uint64 p; int n; + uint64_t p; + + if (argint(0, &fd) < 0 || argint(2, &n) < 0) + return static_cast(-1); - if (argint(0, &fd) < 0 || argint(2, &n) < 0 || argraw(1) == 0) - return -1; p = argraw(1); - if (fd == 1) + // Drivers::uart_puts("DEBUG: sys_write fd="); + // Drivers::uart_put_int(fd); + // Drivers::uart_puts(" len="); + // Drivers::uart_put_int(n); + // Drivers::uart_puts("\n"); + + if (fd == 1) // stdout { - struct Proc *proc = myproc(); - const int max = 128; - char buf[max]; + Proc *proc = myproc(); + constexpr int MAX_WRITE_BUF = 128; + char buf[MAX_WRITE_BUF]; int i = 0; while (i < n) { int len = n - i; - if (len > max) - len = max; + if (len > MAX_WRITE_BUF) + len = MAX_WRITE_BUF; - if (VM::copyin(proc->pagetable, buf, p + i, len) < 0) + if (VM::copyin(proc->pagetable, buf, p + i, static_cast(len)) < 0) { Drivers::uart_puts("sys_write: copyin failed\n"); - return -1; + return static_cast(-1); } for (int j = 0; j < len; j++) @@ -109,19 +119,27 @@ uint64 sys_write() } i += len; } - return n; + return static_cast(n); } - return -1; + return static_cast(-1); } + void syscall() { - struct Proc *p = myproc(); + Proc *p = myproc(); int num = p->tf->a7; - uint64 ret = -1; + uint64_t ret = static_cast(-1); + + Drivers::uart_puts("Syscall: "); + Drivers::print_hex(num); + Drivers::uart_puts("\n"); switch (num) { + case SYS_write: + ret = sys_write(); + break; case SYS_putc: ret = sys_putc(); break; @@ -137,14 +155,11 @@ void syscall() case SYS_getpid: ret = sys_getpid(); break; - case SYS_write: - ret = sys_write(); - break; default: Drivers::uart_puts("Unknown Syscall ID: "); Drivers::print_hex(num); Drivers::uart_puts("\n"); - ret = -1; + ret = static_cast(-1); break; } diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc index 14ef4c5..f7f8725 100644 --- a/src/kernel/trap/handler.cc +++ b/src/kernel/trap/handler.cc @@ -1,13 +1,16 @@ #include "kernel/trap.h" -#include "common/types.h" -#include "drivers/uart.h" +#include "kernel/riscv.h" #include "kernel/proc.h" -#include "kernel/timer.h" +#include "drivers/uart.h" #include "kernel/syscall.h" -#include "kernel/riscv.h" +#include "kernel/mm.h" +#include "kernel/timer.h" +#include "lib/string.h" -extern void usertrapret(); -extern void forkret(); + +extern "C" void kernelvec(); + +// Handle Function void panic(const char *s) { @@ -18,160 +21,153 @@ void panic(const char *s) ; } +// Trap Implementation + namespace Trap { void init() { - uint64 stvec_val = (uint64)kernelvec; - asm volatile("csrw stvec, %0" : : "r"(stvec_val)); + Drivers::uart_puts("[Trap] Global init done.\n"); + } - uint64 sstatus; - asm volatile("csrr %0, sstatus" : "=r"(sstatus)); - sstatus &= ~(1L << 1); - asm volatile("csrw sstatus, %0" : : "r"(sstatus)); + // Each CPU core needs to call this function when starting to set its own stvec + void inithart() + { + w_stvec((uint64)kernelvec); - Drivers::uart_puts("[Trap] Initialized stvec to: "); - Drivers::print_hex(stvec_val); - Drivers::uart_puts("\n"); + // Ensure that the S-Mode interrupt enable bit (SIE) is cleared during initialization + // Interrupt enabling will be done by the scheduler when the first process runs + w_sstatus(r_sstatus() & ~SSTATUS_SIE); + + // Enable the external interrupt, clock interrupt, and software interrupt bits in S-Mode (in SIE register) + uint64 sie = r_sie(); + sie |= SIE_SEIE | SIE_STIE | SIE_SSIE; + w_sie(sie); + + Drivers::uart_puts("[Trap] Hart initialized (stvec set).\n"); } - extern "C" void kerneltrap(struct Trapframe *tf) + // Device Interrupt Check + int devintr() { - uint64 scause, stval, sepc; + uint64 scause = r_scause(); - asm volatile("csrr %0, scause" : "=r"(scause)); - asm volatile("csrr %0, stval" : "=r"(stval)); - asm volatile("csrr %0, sepc" : "=r"(sepc)); + bool is_interrupt = (scause & 0x8000000000000000L) != 0; + uint64 code = scause & 0xff; - if (scause & (1L << 63)) + if (is_interrupt && code == 9) { - uint64 cause_code = scause & 0x7FFFFFFFFFFFFFFFL; - switch (cause_code) - { - case 1: - Drivers::uart_puts("[IRQ] Software Interrupt (Unexpected)\n"); - break; - - case 5: - Drivers::uart_puts("[IRQ] Timer Interrupt\n"); - Timer::set_next_trigger(); - ProcManager::yield(); - break; - - case 9: - Drivers::uart_puts("[IRQ] External Interrupt\n"); - break; - - default: - Drivers::uart_puts("[IRQ] Unknown Interrupt: "); - Drivers::print_hex(cause_code); - Drivers::uart_puts("\n"); - break; - } + // Supervisor External Interrupt (IRQ 9) + return 1; } - else + else if (is_interrupt && code == 5) { - switch (scause) - { - case 8: - Drivers::uart_puts("[Syscall] ecall from Kernel Mode? Panic.\n"); - panic("Kernel Ecall"); - break; - - case 12: - case 13: - case 15: - Drivers::uart_puts("\n--- PAGE FAULT ---\n"); - Drivers::uart_puts("Cause Code: "); - Drivers::print_hex(scause); - Drivers::uart_puts("\n"); - Drivers::uart_puts("Fault Addr (stval): "); - Drivers::print_hex(stval); - Drivers::uart_puts("\n"); - Drivers::uart_puts("Instruction (sepc): "); - Drivers::print_hex(sepc); - Drivers::uart_puts("\n"); - - if (stval == 0) - { - panic("Null Pointer Dereference!"); - } - else if (stval < 0x80000000) - { - panic("Invalid Low Memory Access!"); - } - else - { - panic("Segmentation Fault (Unmapped Area)"); - } - break; - - case 2: - Drivers::uart_puts("\n--- ILLEGAL INSTRUCTION ---\n"); - Drivers::uart_puts("Instruction (sepc): "); - Drivers::print_hex(sepc); - Drivers::uart_puts("\n"); - panic("CPU encountered an unknown opcode"); - break; - - default: - Drivers::uart_puts("\n--- UNHANDLED EXCEPTION ---\n"); - Drivers::uart_puts("Cause: "); - Drivers::print_hex(scause); - Drivers::uart_puts("\n"); - Drivers::uart_puts("sepc: "); - Drivers::print_hex(sepc); - Drivers::uart_puts("\n"); - panic("System Halt"); - break; - } + // Supervisor Timer Interrupt (IRQ 5) + Timer::set_next_trigger(); + // w_sip(r_sip() & ~2); + return 2; } + + return 0; } } +// Exception Handling Entry + +extern "C" void kerneltrap(struct Trapframe *tf) +{ + uint64 sepc = r_sepc(); + uint64 sstatus = r_sstatus(); + uint64 scause = r_scause(); + + if ((sstatus & SSTATUS_SPP) == 0) + panic("kerneltrap: not from supervisor mode"); + + if (intr_get() != 0) + panic("kerneltrap: interrupts enabled"); + + if (Trap::devintr() == 0) + { + Drivers::uart_puts("\n--- KERNEL EXCEPTION ---\n"); + Drivers::uart_puts("scause: "); + Drivers::print_hex(scause); + Drivers::uart_puts("\n"); + Drivers::uart_puts("sepc: "); + Drivers::print_hex(sepc); + Drivers::uart_puts("\n"); + Drivers::uart_puts("stval: "); + Drivers::print_hex(r_stval()); + Drivers::uart_puts("\n"); + panic("kerneltrap exception"); + } + + w_sepc(sepc); + w_sstatus(sstatus); +} + extern "C" void usertrap() { - asm volatile("csrw stvec, %0" : : "r"(Trap::kernelvec)); + // Drivers::uart_puts("[Debug] Entered usertrap!\n"); + int which_dev = 0; - uint64 scause; - asm volatile("csrr %0, scause" : "=r"(scause)); + if ((r_sstatus() & SSTATUS_SPP) != 0) + panic("usertrap: not from user mode"); + + w_stvec((uint64)kernelvec); struct Proc *p = myproc(); - - extern struct Proc procs[]; if (!p) - { - for (int i = 0; i < 10; ++i) - if (procs[i].state == RUNNING) - p = &procs[i]; - } + panic("usertrap: no process"); - uint64 sepc; - asm volatile("csrr %0, sepc" : "=r"(sepc)); - p->tf->epc = sepc; + p->tf->epc = r_sepc(); - if(scause == 8) + uint64 scause = r_scause(); + uint64 stval = r_stval(); + + if (scause == 8) // Syscall { - intr_on(); + if (p->state == ZOMBIE) + ProcManager::exit(-1); p->tf->epc += 4; - + intr_on(); syscall(); - intr_off(); } - else if ((scause & (1L << 63)) && (scause & 0xF) == 5) + else if (scause == 15) // Store Page Fault { - Drivers::uart_puts("\nTick\n"); - Timer::set_next_trigger(); - ProcManager::yield(); + if (VM::handle_cow_fault(p->pagetable, PGROUNDDOWN(stval)) != 0) + { + Drivers::uart_puts("usertrap: cow failed at "); + Drivers::print_hex(stval); + Drivers::uart_puts("\n"); + p->state = ZOMBIE; + ProcManager::exit(-1); + } + } + else if ((which_dev = Trap::devintr()) != 0) + { + if (which_dev == 2) + { + ProcManager::yield(); + } } else { - Drivers::uart_puts("Unexpected User Trap!\n"); + Drivers::uart_puts("\nusertrap(): unexpected scause "); Drivers::print_hex(scause); - while (1) - ; + Drivers::uart_puts(" pid="); + Drivers::uart_put_int(p->pid); + Drivers::uart_puts(" sepc="); + Drivers::print_hex(p->tf->epc); + Drivers::uart_puts(" stval="); + Drivers::print_hex(stval); + Drivers::uart_puts("\n"); + p->state = ZOMBIE; + ProcManager::exit(-1); } + if (p->state == ZOMBIE) + ProcManager::exit(-1); + usertrapret(); } \ No newline at end of file diff --git a/src/user/init.cc b/src/user/init.cc index 3c42adf..85252be 100644 --- a/src/user/init.cc +++ b/src/user/init.cc @@ -1,34 +1,118 @@ #include "user/user.h" -int main(); +int strlen(const char *s) +{ + int n = 0; + while (s[n]) + n++; + return n; +} -extern "C" void _start() +void print(const char *s) { - exit(main()); + write(1, s, strlen(s)); +} + +void print_int(int val) +{ + char buf[16]; + int i = 0; + if (val == 0) + { + print("0"); + return; + } + if (val < 0) + { + print("-"); + val = -val; + } + while (val > 0) + { + buf[i++] = (val % 10) + '0'; + val /= 10; + } + while (i > 0) + { + char c = buf[--i]; + write(1, &c, 1); + } +} + +void pass() { print(" -> [PASS]\n"); } +void fail() +{ + print(" -> [FAIL]\n"); + exit(1); } int main() { + print("\n=== Lume OS Full Validation ===\n"); + + print("[TEST 1] Write\n"); + print(" System call write is working."); + pass(); + + print("[TEST 2] GetPID\n"); + int parent_pid = getpid(); + print(" Parent PID: "); + print_int(parent_pid); + if (parent_pid > 0) + pass(); + else + fail(); + + print("[TEST 3] Fork, Wait & COW\n"); + int val = 100; int pid = fork(); if (pid < 0) { - write(1, "Fork failed\n", 12); - exit(1); + print(" Fork Failed\n"); + fail(); } if (pid == 0) { - write(1, "Hello from Child!\n", 18); + print(" [Child] PID: "); + print_int(getpid()); + print("\n"); + + if (val != 100) + { + print(" [Child] Data corruption!\n"); + exit(1); + } + + val = 200; + print(" [Child] Modified val to 200. Exiting.\n"); exit(0); } else { - write(1, "Parent waiting...\n", 18); - wait(0); - write(1, "Parent: Child exited.\n", 22); + print(" [Parent] Waiting for child...\n"); + int child_pid = wait(0); + + print(" [Parent] Child "); + print_int(child_pid); + print(" exited.\n"); + + print(" [Parent] Check val (Expect 100): "); + print_int(val); + + if (val == 100) + pass(); + else + { + print(" [Parent] Memory Isolation Failed! Val="); + print_int(val); + fail(); + } } - while (1); + print("\n=== All Tests Passed ===\n"); + while (1) + ; return 0; } \ No newline at end of file diff --git a/src/user/user.ld b/src/user/user.ld index 2111b14..8c9999a 100644 --- a/src/user/user.ld +++ b/src/user/user.ld @@ -1,26 +1,32 @@ -OUTPUT_ARCH(riscv) -ENTRY(_start) +OUTPUT_ARCH( "riscv" ) +ENTRY( _start ) SECTIONS { . = 0x0; - + .text : { *(.text.entry) *(.text .text.*) } .rodata : { + . = ALIGN(16); + *(.srodata .srodata.*) . = ALIGN(16); *(.rodata .rodata.*) } .data : { + . = ALIGN(16); + *(.sdata .sdata.*) . = ALIGN(16); *(.data .data.*) } .bss : { + . = ALIGN(16); + *(.sbss .sbss.*) . = ALIGN(16); *(.bss .bss.*) } -- cgit v1.2.3 From 2dde56422dcfb94affee2baffc8d240ad16ad4b2 Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Thu, 1 Jan 2026 15:04:47 +0800 Subject: dev(device): implement VirtIO See dev log for detail --- Makefile | 19 +- build/kernel.elf | Bin 156920 -> 184056 bytes build/src/drivers/plic.o | Bin 13800 -> 19656 bytes build/src/drivers/uart.o | Bin 57352 -> 92888 bytes build/src/drivers/virtio_dist.o | Bin 0 -> 93248 bytes build/src/kernel/initcode.o | Bin 2448 -> 3952 bytes build/src/kernel/main.o | Bin 17744 -> 19608 bytes build/src/kernel/mm/pmm.o | Bin 90424 -> 90424 bytes build/src/kernel/mm/slab.o | Bin 67304 -> 67664 bytes build/src/kernel/mm/vm.o | Bin 213776 -> 214608 bytes build/src/kernel/proc/proc.o | Bin 205000 -> 212272 bytes build/src/kernel/spinlock.o | Bin 99920 -> 99920 bytes build/src/kernel/syscall.o | Bin 47560 -> 61936 bytes build/src/kernel/trap/handler.o | Bin 66984 -> 70200 bytes build/user/entry.o | Bin 0 -> 3344 bytes build/user/init.o | Bin 45880 -> 112536 bytes build/user/initcode | Bin 1424 -> 2928 bytes build/user/initcode.asm | 1326 ++++++++++++++++++++++++++++----------- build/user/initcode.out | Bin 14168 -> 22440 bytes build/user/usys.o | Bin 5160 -> 5280 bytes docs/dev/dev_device.md | 23 + docs/dev/dev_memory.md | 37 ++ docs/dev/dev_memoty.md | 37 -- fs.img | Bin 0 -> 1048576 bytes include/drivers/plic.h | 2 +- include/drivers/uart.h | 26 +- include/drivers/virtio.h | 102 +++ include/kernel/proc.h | 2 + include/kernel/syscall.h | 1 + include/user/user.h | 3 +- src/drivers/plic.cc | 55 +- src/drivers/uart.cc | 226 +++++-- src/drivers/virtio_dist.cc | 338 ++++++++++ src/kernel/main.cc | 7 +- src/kernel/mm/pmm.cc | 67 -- src/kernel/mm/slab.cc | 11 +- src/kernel/mm/vm.cc | 3 +- src/kernel/proc/proc.cc | 33 +- src/kernel/syscall.cc | 53 +- src/kernel/trap/handler.cc | 13 +- src/user/entry.S | 12 + src/user/init.cc | 191 ++++-- src/user/usys.S | 3 +- 43 files changed, 1934 insertions(+), 656 deletions(-) create mode 100644 build/src/drivers/virtio_dist.o create mode 100644 build/user/entry.o create mode 100644 docs/dev/dev_device.md create mode 100644 docs/dev/dev_memory.md delete mode 100644 docs/dev/dev_memoty.md create mode 100644 fs.img create mode 100644 include/drivers/virtio.h create mode 100644 src/drivers/virtio_dist.cc create mode 100644 src/user/entry.S (limited to 'include/kernel/proc.h') diff --git a/Makefile b/Makefile index 7c3de2d..715fff8 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ CXXFLAGS := $(CFLAGS) -fno-exceptions -fno-rtti -fno-use-cxa-atexit LINKER_SCRIPT := linker.ld UPROGS_SRC := $(SRC_DIR)/user/init.cc -UPROGS_OBJ := $(BUILD_DIR)/user/init.o +UPROGS_OBJ := $(BUILD_DIR)/user/entry.o $(BUILD_DIR)/user/init.o ULIB_OBJ := $(BUILD_DIR)/user/usys.o USER_LD := $(SRC_DIR)/user/user.ld INITCODE_BIN := $(BUILD_DIR)/user/initcode @@ -24,6 +24,9 @@ OBJS := $(SRCS_S:%.S=$(BUILD_DIR)/%.o) $(SRCS_CXX:%.cc=$(BUILD_DIR)/%.o) TARGET := $(BUILD_DIR)/kernel.elf +QEMUOPTS = -drive file=fs.img,if=none,format=raw,id=x0 +QEMUOPTS += -device virtio-blk-device,drive=x0 -global virtio-mmio.force-legacy=false + .PHONY: all clean run debug all: $(TARGET) @@ -63,15 +66,19 @@ $(BUILD_DIR)/%.o: %.cc @echo " CXX $<" @$(CXX) $(CXXFLAGS) -c $< -o $@ -run: $(TARGET) +fs.img: + @echo " IMG Generating fs.img (1MB)" + @dd if=/dev/zero of=fs.img bs=1M count=1 2>/dev/null + +run: $(TARGET) fs.img @echo " QEMU Running..." @qemu-system-riscv64 -machine virt -nographic \ - -kernel $(TARGET) -m 128M + -kernel $(TARGET) -m 128M $(QEMUOPTS) -debug: $(TARGET) +debug: $(TARGET) fs.img @echo " QEMU (DEBUG) Waiting for GDB..." @qemu-system-riscv64 -machine virt -nographic \ - -kernel $(TARGET) -m 128M -s -S + -kernel $(TARGET) -m 128M -s -S $(QEMUOPTS) clean: - rm -rf $(BUILD_DIR) + rm -rf $(BUILD_DIR) fs.img diff --git a/build/kernel.elf b/build/kernel.elf index db7f94d..902f32b 100755 Binary files a/build/kernel.elf and b/build/kernel.elf differ diff --git a/build/src/drivers/plic.o b/build/src/drivers/plic.o index 846035b..cf2c85d 100644 Binary files a/build/src/drivers/plic.o and b/build/src/drivers/plic.o differ diff --git a/build/src/drivers/uart.o b/build/src/drivers/uart.o index 34a0840..e771c9f 100644 Binary files a/build/src/drivers/uart.o and b/build/src/drivers/uart.o differ diff --git a/build/src/drivers/virtio_dist.o b/build/src/drivers/virtio_dist.o new file mode 100644 index 0000000..cc608ca Binary files /dev/null and b/build/src/drivers/virtio_dist.o differ diff --git a/build/src/kernel/initcode.o b/build/src/kernel/initcode.o index e29dda3..a1c9bd8 100644 Binary files a/build/src/kernel/initcode.o and b/build/src/kernel/initcode.o differ diff --git a/build/src/kernel/main.o b/build/src/kernel/main.o index 54ee210..df27b46 100644 Binary files a/build/src/kernel/main.o and b/build/src/kernel/main.o differ diff --git a/build/src/kernel/mm/pmm.o b/build/src/kernel/mm/pmm.o index c77cdc9..db30140 100644 Binary files a/build/src/kernel/mm/pmm.o and b/build/src/kernel/mm/pmm.o differ diff --git a/build/src/kernel/mm/slab.o b/build/src/kernel/mm/slab.o index 23305aa..2d97ca1 100644 Binary files a/build/src/kernel/mm/slab.o and b/build/src/kernel/mm/slab.o differ diff --git a/build/src/kernel/mm/vm.o b/build/src/kernel/mm/vm.o index 2e3c0de..5d30dcd 100644 Binary files a/build/src/kernel/mm/vm.o and b/build/src/kernel/mm/vm.o differ diff --git a/build/src/kernel/proc/proc.o b/build/src/kernel/proc/proc.o index 63506e7..ad606f0 100644 Binary files a/build/src/kernel/proc/proc.o and b/build/src/kernel/proc/proc.o differ diff --git a/build/src/kernel/spinlock.o b/build/src/kernel/spinlock.o index f4a24bf..769f5e7 100644 Binary files a/build/src/kernel/spinlock.o and b/build/src/kernel/spinlock.o differ diff --git a/build/src/kernel/syscall.o b/build/src/kernel/syscall.o index a3df126..d398c30 100644 Binary files a/build/src/kernel/syscall.o and b/build/src/kernel/syscall.o differ diff --git a/build/src/kernel/trap/handler.o b/build/src/kernel/trap/handler.o index 43346a1..9949470 100644 Binary files a/build/src/kernel/trap/handler.o and b/build/src/kernel/trap/handler.o differ diff --git a/build/user/entry.o b/build/user/entry.o new file mode 100644 index 0000000..0130c78 Binary files /dev/null and b/build/user/entry.o differ diff --git a/build/user/init.o b/build/user/init.o index 13021f2..aea18f2 100644 Binary files a/build/user/init.o and b/build/user/init.o differ diff --git a/build/user/initcode b/build/user/initcode index 7d139ad..b6ac9a3 100755 Binary files a/build/user/initcode and b/build/user/initcode differ diff --git a/build/user/initcode.asm b/build/user/initcode.asm index c04fbab..1cb4088 100644 --- a/build/user/initcode.asm +++ b/build/user/initcode.asm @@ -4,482 +4,1050 @@ build/user/initcode.out: file format elf64-littleriscv Disassembly of section .text: -0000000000000000 <_Z6strlenPKc>: -#include "user/user.h" +0000000000000000 <_start>: +.section .text +.global _start + +_start: + li a0, 0 + 0: 4501 li a0,0 + li a1, 0 + 2: 4581 li a1,0 + + call main + 4: 578000ef jal 57c
+ + call exit + 8: 648000ef jal 650 + + c: a001 j c <_start+0xc> + +000000000000000e <_Z6strlenPKc>: +// ============================================================= int strlen(const char *s) { int n = 0; while (s[n]) - 0: 00054783 lbu a5,0(a0) - 4: cf81 beqz a5,1c <_Z6strlenPKc+0x1c> - 6: 0505 addi a0,a0,1 - 8: 87aa mv a5,a0 - a: 0007c703 lbu a4,0(a5) - e: 86be mv a3,a5 - 10: 0785 addi a5,a5,1 - 12: ff65 bnez a4,a <_Z6strlenPKc+0xa> + e: 00054783 lbu a5,0(a0) + 12: cf81 beqz a5,2a <_Z6strlenPKc+0x1c> + 14: 0505 addi a0,a0,1 + 16: 87aa mv a5,a0 + 18: 0007c703 lbu a4,0(a5) + 1c: 86be mv a3,a5 + 1e: 0785 addi a5,a5,1 + 20: ff65 bnez a4,18 <_Z6strlenPKc+0xa> n++; - 14: 40a6853b subw a0,a3,a0 - 18: 2505 addiw a0,a0,1 - 1a: 8082 ret + 22: 40a6853b subw a0,a3,a0 + 26: 2505 addiw a0,a0,1 + 28: 8082 ret int n = 0; - 1c: 4501 li a0,0 + 2a: 4501 li a0,0 return n; } - 1e: 8082 ret + 2c: 8082 ret -0000000000000020 <_Z5printPKc>: +000000000000002e <_Z5printPKc>: while (s[n]) - 20: 00054783 lbu a5,0(a0) + 2e: 00054783 lbu a5,0(a0) void print(const char *s) { - 24: 85aa mv a1,a0 - while (s[n]) - 26: cf89 beqz a5,40 <_Z5printPKc+0x20> - 28: 00150693 addi a3,a0,1 - 2c: 87b6 mv a5,a3 - 2e: 0007c703 lbu a4,0(a5) - 32: 863e mv a2,a5 - 34: 0785 addi a5,a5,1 - 36: ff65 bnez a4,2e <_Z5printPKc+0xe> + 32: 85aa mv a1,a0 + while (s[n]) + 34: cf89 beqz a5,4e <_Z5printPKc+0x20> + 36: 00150693 addi a3,a0,1 + 3a: 87b6 mv a5,a3 + 3c: 0007c703 lbu a4,0(a5) + 40: 863e mv a2,a5 + 42: 0785 addi a5,a5,1 + 44: ff65 bnez a4,3c <_Z5printPKc+0xe> n++; - 38: 9e15 subw a2,a2,a3 - 3a: 2605 addiw a2,a2,1 + 46: 9e15 subw a2,a2,a3 + 48: 2605 addiw a2,a2,1 write(1, s, strlen(s)); - 3c: 4505 li a0,1 - 3e: a491 j 282 + 4a: 4505 li a0,1 + 4c: a515 j 670 int n = 0; - 40: 4601 li a2,0 + 4e: 4601 li a2,0 write(1, s, strlen(s)); - 42: 4505 li a0,1 - 44: ac3d j 282 - -0000000000000046 <_Z9print_inti>: + 50: 4505 li a0,1 + 52: ad39 j 670 -void print_int(int val) +0000000000000054 <_Z9print_inti>: +void print_int(int n) { char buf[16]; int i = 0; - if (val == 0) - 46: c159 beqz a0,cc <_Z9print_inti+0x86> + int neg = 0; + if (n == 0) + 54: c149 beqz a0,d6 <_Z9print_inti+0x82> { - 48: 7139 addi sp,sp,-64 - 4a: f822 sd s0,48(sp) - 4c: fc06 sd ra,56(sp) - 4e: f426 sd s1,40(sp) - 50: f04a sd s2,32(sp) - 52: 842a mv s0,a0 + 56: 7179 addi sp,sp,-48 + 58: f406 sd ra,40(sp) + 5a: f022 sd s0,32(sp) + 5c: ec26 sd s1,24(sp) + int neg = 0; + 5e: 4801 li a6,0 { - print("0"); + write(1, "0", 1); return; } - if (val < 0) - 54: 06054163 bltz a0,b6 <_Z9print_inti+0x70> - 58: 081c addi a5,sp,16 -{ - 5a: 873e mv a4,a5 - print("-"); - val = -val; + if (n < 0) + 60: 04054c63 bltz a0,b8 <_Z9print_inti+0x64> + 64: 840a mv s0,sp + { + neg = 1; + 66: 86a2 mv a3,s0 + 68: 4701 li a4,0 + n = -n; } - while (val > 0) + while (n > 0) { - buf[i++] = (val % 10) + '0'; - 5c: 4629 li a2,10 - 5e: 02c466bb remw a3,s0,a2 - 62: 85ba mv a1,a4 - while (val > 0) - 64: 0705 addi a4,a4,1 - val /= 10; - 66: 02c4443b divw s0,s0,a2 - buf[i++] = (val % 10) + '0'; - 6a: 0306869b addiw a3,a3,48 - 6e: fed70fa3 sb a3,-1(a4) - while (val > 0) - 72: f475 bnez s0,5e <_Z9print_inti+0x18> - 74: 9d9d subw a1,a1,a5 - 76: 0015871b addiw a4,a1,1 - 7a: fff7059b addiw a1,a4,-1 - 7e: fff78493 addi s1,a5,-1 - 82: 1582 slli a1,a1,0x20 - 84: 94ba add s1,s1,a4 - 86: 9181 srli a1,a1,0x20 - 88: 00e78433 add s0,a5,a4 - 8c: 8c8d sub s1,s1,a1 - 8e: 00f10913 addi s2,sp,15 + buf[i++] = (n % 10) + '0'; + 6a: 4629 li a2,10 + 6c: 02c567bb remw a5,a0,a2 + while (n > 0) + 70: 0685 addi a3,a3,1 + 72: 85ba mv a1,a4 + buf[i++] = (n % 10) + '0'; + 74: 2705 addiw a4,a4,1 + n /= 10; + 76: 02c5453b divw a0,a0,a2 + buf[i++] = (n % 10) + '0'; + 7a: 0307879b addiw a5,a5,48 + 7e: fef68fa3 sb a5,-1(a3) + while (n > 0) + 82: f56d bnez a0,6c <_Z9print_inti+0x18> } + if (neg) + 84: 02081e63 bnez a6,c0 <_Z9print_inti+0x6c> + 88: fff7079b addiw a5,a4,-1 + 8c: ffe40493 addi s1,s0,-2 + 90: 1782 slli a5,a5,0x20 + 92: fff70693 addi a3,a4,-1 + 96: 94ba add s1,s1,a4 + 98: 9381 srli a5,a5,0x20 + 9a: 9436 add s0,s0,a3 + 9c: 8c9d sub s1,s1,a5 + buf[i++] = '-'; while (i > 0) - { - char c = buf[--i]; - 92: fff44783 lbu a5,-1(s0) - write(1, &c, 1); - 96: 4605 li a2,1 - 98: 85ca mv a1,s2 - 9a: 4505 li a0,1 + write(1, &buf[--i], 1); + 9e: 85a2 mv a1,s0 + a0: 4605 li a2,1 + a2: 4505 li a0,1 while (i > 0) - 9c: 147d addi s0,s0,-1 - char c = buf[--i]; - 9e: 00f107a3 sb a5,15(sp) - write(1, &c, 1); - a2: 1e0000ef jal 282 + a4: 147d addi s0,s0,-1 + write(1, &buf[--i], 1); + a6: 5ca000ef jal 670 while (i > 0) - a6: fe9416e3 bne s0,s1,92 <_Z9print_inti+0x4c> - } + aa: fe849ae3 bne s1,s0,9e <_Z9print_inti+0x4a> } - aa: 70e2 ld ra,56(sp) - ac: 7442 ld s0,48(sp) - ae: 74a2 ld s1,40(sp) - b0: 7902 ld s2,32(sp) - b2: 6121 addi sp,sp,64 - b4: 8082 ret - write(1, s, strlen(s)); - b6: 4605 li a2,1 - b8: 00000597 auipc a1,0x0 - bc: 26058593 addi a1,a1,608 # 318 - c0: 4505 li a0,1 - c2: 1c0000ef jal 282 - val = -val; - c6: 4080043b negw s0,s0 - while (val > 0) - ca: b779 j 58 <_Z9print_inti+0x12> - write(1, s, strlen(s)); - cc: 4605 li a2,1 - ce: 00000597 auipc a1,0x0 - d2: 24258593 addi a1,a1,578 # 310 - d6: 4505 li a0,1 - d8: a26d j 282 - -00000000000000da <_Z4passv>: - while (s[n]) - da: 00000697 auipc a3,0x0 - de: 24668693 addi a3,a3,582 # 320 - -void pass() { print(" -> [PASS]\n"); } - e2: 87b6 mv a5,a3 - while (s[n]) - e4: 0017c703 lbu a4,1(a5) - e8: 863e mv a2,a5 - ea: 0785 addi a5,a5,1 - ec: ff65 bnez a4,e4 <_Z4passv+0xa> - n++; - ee: 9e15 subw a2,a2,a3 - write(1, s, strlen(s)); - f0: 2605 addiw a2,a2,1 - f2: 00000597 auipc a1,0x0 - f6: 22e58593 addi a1,a1,558 # 320 - fa: 4505 li a0,1 - fc: a259 j 282 + ae: 70a2 ld ra,40(sp) + b0: 7402 ld s0,32(sp) + b2: 64e2 ld s1,24(sp) + b4: 6145 addi sp,sp,48 + b6: 8082 ret + n = -n; + b8: 40a0053b negw a0,a0 + neg = 1; + bc: 4805 li a6,1 + be: b75d j 64 <_Z9print_inti+0x10> + buf[i++] = '-'; + c0: 01070793 addi a5,a4,16 + c4: 00278733 add a4,a5,sp + c8: 02d00793 li a5,45 + cc: fef70823 sb a5,-16(a4) + d0: 0025871b addiw a4,a1,2 + d4: bf55 j 88 <_Z9print_inti+0x34> + write(1, "0", 1); + d6: 4605 li a2,1 + d8: 00000597 auipc a1,0x0 + dc: 62858593 addi a1,a1,1576 # 700 + e0: 4505 li a0,1 + e2: a379 j 670 -00000000000000fe <_Z4failv>: -void fail() +00000000000000e4 <_Z9print_hexy>: + +void print_hex(uint64 n) { - fe: 1141 addi sp,sp,-16 - 100: 00000697 auipc a3,0x0 - 104: 23068693 addi a3,a3,560 # 330 - 108: e406 sd ra,8(sp) - 10a: 87b6 mv a5,a3 - while (s[n]) - 10c: 0017c703 lbu a4,1(a5) - 110: 863e mv a2,a5 - 112: 0785 addi a5,a5,1 - 114: ff65 bnez a4,10c <_Z4failv+0xe> - n++; - 116: 9e15 subw a2,a2,a3 - write(1, s, strlen(s)); - 118: 2605 addiw a2,a2,1 - 11a: 00000597 auipc a1,0x0 - 11e: 21658593 addi a1,a1,534 # 330 - 122: 4505 li a0,1 - 124: 15e000ef jal 282 - print(" -> [FAIL]\n"); - exit(1); + char buf[16]; + char digits[] = "0123456789ABCDEF"; + e4: 00000797 auipc a5,0x0 + e8: 62c78793 addi a5,a5,1580 # 710 + ec: 6394 ld a3,0(a5) + ee: 6798 ld a4,8(a5) + f0: 0107c783 lbu a5,16(a5) +{ + f4: 715d addi sp,sp,-80 + f6: fc26 sd s1,56(sp) + write(1, "0x", 2); + f8: 4609 li a2,2 +{ + fa: 84aa mv s1,a0 + write(1, "0x", 2); + fc: 00000597 auipc a1,0x0 + 100: 60c58593 addi a1,a1,1548 # 708 + 104: 4505 li a0,1 +{ + 106: e486 sd ra,72(sp) + char digits[] = "0123456789ABCDEF"; + 108: ec36 sd a3,24(sp) + 10a: f03a sd a4,32(sp) + 10c: 02f10423 sb a5,40(sp) + write(1, "0x", 2); + 110: 560000ef jal 670 + if (n == 0) + 114: cca1 beqz s1,16c <_Z9print_hexy+0x88> + 116: e0a2 sd s0,64(sp) + 118: 0020 addi s0,sp,8 + 11a: 87a2 mv a5,s0 + return; + } + int i = 0; + while (n > 0) + { + buf[i++] = digits[n % 16]; + 11c: 00f4f713 andi a4,s1,15 + 120: 03070713 addi a4,a4,48 + 124: 970a add a4,a4,sp + 126: fe874683 lbu a3,-24(a4) + n /= 16; + 12a: 8091 srli s1,s1,0x4 + 12c: 873e mv a4,a5 + buf[i++] = digits[n % 16]; + 12e: 00d78023 sb a3,0(a5) + while (n > 0) + 132: 0785 addi a5,a5,1 + 134: f4e5 bnez s1,11c <_Z9print_hexy+0x38> + 136: 9f01 subw a4,a4,s0 + 138: 0017079b addiw a5,a4,1 + 13c: fff7871b addiw a4,a5,-1 + 140: ffe40493 addi s1,s0,-2 + 144: 1702 slli a4,a4,0x20 + 146: fff78693 addi a3,a5,-1 + 14a: 94be add s1,s1,a5 + 14c: 9301 srli a4,a4,0x20 + 14e: 9436 add s0,s0,a3 + 150: 8c99 sub s1,s1,a4 + } + while (i > 0) + write(1, &buf[--i], 1); + 152: 85a2 mv a1,s0 + 154: 4605 li a2,1 + 156: 4505 li a0,1 + while (i > 0) + 158: 147d addi s0,s0,-1 + write(1, &buf[--i], 1); + 15a: 516000ef jal 670 + while (i > 0) + 15e: fe941ae3 bne s0,s1,152 <_Z9print_hexy+0x6e> + 162: 6406 ld s0,64(sp) } - 128: 60a2 ld ra,8(sp) - exit(1); - 12a: 4505 li a0,1 + 164: 60a6 ld ra,72(sp) + 166: 74e2 ld s1,56(sp) + 168: 6161 addi sp,sp,80 + 16a: 8082 ret + 16c: 60a6 ld ra,72(sp) + 16e: 74e2 ld s1,56(sp) + write(1, "0", 1); + 170: 4605 li a2,1 + 172: 00000597 auipc a1,0x0 + 176: 58e58593 addi a1,a1,1422 # 700 + 17a: 4505 li a0,1 } - 12c: 0141 addi sp,sp,16 - exit(1); - 12e: aa15 j 262 + 17c: 6161 addi sp,sp,80 + write(1, "0", 1); + 17e: a9cd j 670 -0000000000000130
: +0000000000000180 <_Z13test_syscallsv>: +// ============================================================= +// 系统调用测试套件 +// ============================================================= -int main() +void test_syscalls() { - 130: 1141 addi sp,sp,-16 - print("\n=== Lume OS Full Validation ===\n"); - 132: 00000517 auipc a0,0x0 - 136: 20e50513 addi a0,a0,526 # 340 -{ - 13a: e406 sd ra,8(sp) - 13c: e022 sd s0,0(sp) - print("\n=== Lume OS Full Validation ===\n"); - 13e: ee3ff0ef jal 20 <_Z5printPKc> - - print("[TEST 1] Write\n"); - 142: 00000517 auipc a0,0x0 - 146: 22650513 addi a0,a0,550 # 368 - 14a: ed7ff0ef jal 20 <_Z5printPKc> - print(" System call write is working."); - 14e: 00000517 auipc a0,0x0 - 152: 22a50513 addi a0,a0,554 # 378 - 156: ecbff0ef jal 20 <_Z5printPKc> -void pass() { print(" -> [PASS]\n"); } - 15a: 00000517 auipc a0,0x0 - 15e: 1c650513 addi a0,a0,454 # 320 - 162: ebfff0ef jal 20 <_Z5printPKc> - pass(); - - print("[TEST 2] GetPID\n"); - 166: 00000517 auipc a0,0x0 - 16a: 23250513 addi a0,a0,562 # 398 - 16e: eb3ff0ef jal 20 <_Z5printPKc> - int parent_pid = getpid(); - 172: 170000ef jal 2e2 - 176: 842a mv s0,a0 - print(" Parent PID: "); - 178: 00000517 auipc a0,0x0 - 17c: 23850513 addi a0,a0,568 # 3b0 - 180: ea1ff0ef jal 20 <_Z5printPKc> - print_int(parent_pid); - 184: 8522 mv a0,s0 - 186: ec1ff0ef jal 46 <_Z9print_inti> - if (parent_pid > 0) - 18a: 0c805563 blez s0,254 -void pass() { print(" -> [PASS]\n"); } - 18e: 00000517 auipc a0,0x0 - 192: 19250513 addi a0,a0,402 # 320 - 196: e8bff0ef jal 20 <_Z5printPKc> - pass(); + 180: 1101 addi sp,sp,-32 + 182: 00000697 auipc a3,0x0 + 186: 5a668693 addi a3,a3,1446 # 728 + 18a: ec06 sd ra,24(sp) + 18c: e822 sd s0,16(sp) + 18e: e426 sd s1,8(sp) + 190: 87b6 mv a5,a3 + while (s[n]) + 192: 0017c703 lbu a4,1(a5) + 196: 863e mv a2,a5 + 198: 0785 addi a5,a5,1 + 19a: ff65 bnez a4,192 <_Z13test_syscallsv+0x12> + n++; + 19c: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 19e: 2605 addiw a2,a2,1 + 1a0: 00000597 auipc a1,0x0 + 1a4: 58858593 addi a1,a1,1416 # 728 + 1a8: 4505 li a0,1 + 1aa: 4c6000ef jal 670 + while (s[n]) + 1ae: 00000697 auipc a3,0x0 + 1b2: 5aa68693 addi a3,a3,1450 # 758 + write(1, s, strlen(s)); + 1b6: 87b6 mv a5,a3 + while (s[n]) + 1b8: 0017c703 lbu a4,1(a5) + 1bc: 863e mv a2,a5 + 1be: 0785 addi a5,a5,1 + 1c0: ff65 bnez a4,1b8 <_Z13test_syscallsv+0x38> + n++; + 1c2: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 1c4: 2605 addiw a2,a2,1 + 1c6: 00000597 auipc a1,0x0 + 1ca: 59258593 addi a1,a1,1426 # 758 + 1ce: 4505 li a0,1 + 1d0: 4a0000ef jal 670 + print("\n=== [Test] Starting System Call Check ===\n"); + + // 1. 测试 getpid + print("[1/4] Checking getpid()... "); + int my_pid = getpid(); + 1d4: 4fc000ef jal 6d0 + 1d8: 842a mv s0,a0 + if (my_pid > 0) + 1da: 2aa05463 blez a0,482 <_Z13test_syscallsv+0x302> + 1de: 00000697 auipc a3,0x0 + 1e2: 59a68693 addi a3,a3,1434 # 778 + 1e6: 87b6 mv a5,a3 + while (s[n]) + 1e8: 0017c703 lbu a4,1(a5) + 1ec: 863e mv a2,a5 + 1ee: 0785 addi a5,a5,1 + 1f0: ff65 bnez a4,1e8 <_Z13test_syscallsv+0x68> + n++; + 1f2: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 1f4: 2605 addiw a2,a2,1 + 1f6: 00000597 auipc a1,0x0 + 1fa: 58258593 addi a1,a1,1410 # 778 + 1fe: 4505 li a0,1 + 200: 470000ef jal 670 + { + print("PASS (PID="); + print_int(my_pid); + 204: 8522 mv a0,s0 + 206: e4fff0ef jal 54 <_Z9print_inti> + while (s[n]) + 20a: 00000697 auipc a3,0x0 + 20e: 57e68693 addi a3,a3,1406 # 788 + print_int(my_pid); + 212: 87b6 mv a5,a3 + while (s[n]) + 214: 0017c703 lbu a4,1(a5) + 218: 863e mv a2,a5 + 21a: 0785 addi a5,a5,1 + 21c: ff65 bnez a4,214 <_Z13test_syscallsv+0x94> + n++; + 21e: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 220: 2605 addiw a2,a2,1 + 222: 00000597 auipc a1,0x0 + 226: 56658593 addi a1,a1,1382 # 788 + 22a: 4505 li a0,1 + 22c: 444000ef jal 670 + while (s[n]) + 230: 00000697 auipc a3,0x0 + 234: 57868693 addi a3,a3,1400 # 7a8 + if (my_pid > 0) + 238: 87b6 mv a5,a3 + while (s[n]) + 23a: 0017c703 lbu a4,1(a5) + 23e: 863e mv a2,a5 + 240: 0785 addi a5,a5,1 + 242: ff65 bnez a4,23a <_Z13test_syscallsv+0xba> + n++; + 244: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 246: 2605 addiw a2,a2,1 + 248: 00000597 auipc a1,0x0 + 24c: 56058593 addi a1,a1,1376 # 7a8 + 250: 4505 li a0,1 + 252: 41e000ef jal 670 + print("FAIL (Invalid PID)\n"); + } + + // 2. 测试 sbrk (内存分配) + print("[2/4] Checking sbrk() heap allocation... "); + char *p = sbrk(4096); // 分配 4KB + 256: 6505 lui a0,0x1 + 258: 480000ef jal 6d8 + if (p == (char *)-1) + 25c: 57fd li a5,-1 + char *p = sbrk(4096); // 分配 4KB + 25e: 84aa mv s1,a0 + if (p == (char *)-1) + 260: 24f50563 beq a0,a5,4aa <_Z13test_syscallsv+0x32a> + print("FAIL (sbrk returned error)\n"); + } else - fail(); + { + // 写入测试,确保映射了物理页 + p[0] = 'A'; + 264: 04100793 li a5,65 + 268: 00f50023 sb a5,0(a0) # 1000 + p[4095] = 'Z'; + 26c: 6785 lui a5,0x1 + 26e: 97aa add a5,a5,a0 + 270: 00000697 auipc a3,0x0 + 274: 58868693 addi a3,a3,1416 # 7f8 + 278: 05a00713 li a4,90 + 27c: fee78fa3 sb a4,-1(a5) # fff + 280: 87b6 mv a5,a3 + while (s[n]) + 282: 0017c703 lbu a4,1(a5) + 286: 863e mv a2,a5 + 288: 0785 addi a5,a5,1 + 28a: ff65 bnez a4,282 <_Z13test_syscallsv+0x102> + n++; + 28c: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 28e: 2605 addiw a2,a2,1 + 290: 00000597 auipc a1,0x0 + 294: 56858593 addi a1,a1,1384 # 7f8 + 298: 4505 li a0,1 + 29a: 3d6000ef jal 670 + if (p[0] == 'A' && p[4095] == 'Z') + { + print("PASS (Allocated at "); + print_hex((uint64)p); + 29e: 8526 mv a0,s1 + 2a0: e45ff0ef jal e4 <_Z9print_hexy> + while (s[n]) + 2a4: 00000697 auipc a3,0x0 + 2a8: 4e468693 addi a3,a3,1252 # 788 + print_hex((uint64)p); + 2ac: 87b6 mv a5,a3 + while (s[n]) + 2ae: 0017c703 lbu a4,1(a5) + 2b2: 863e mv a2,a5 + 2b4: 0785 addi a5,a5,1 + 2b6: ff65 bnez a4,2ae <_Z13test_syscallsv+0x12e> + n++; + 2b8: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 2ba: 2605 addiw a2,a2,1 + 2bc: 00000597 auipc a1,0x0 + 2c0: 4cc58593 addi a1,a1,1228 # 788 + 2c4: 4505 li a0,1 + 2c6: 3aa000ef jal 670 + while (s[n]) + 2ca: 00000697 auipc a3,0x0 + 2ce: 54668693 addi a3,a3,1350 # 810 + print_hex((uint64)p); + 2d2: 87b6 mv a5,a3 + while (s[n]) + 2d4: 0017c703 lbu a4,1(a5) + 2d8: 863e mv a2,a5 + 2da: 0785 addi a5,a5,1 + 2dc: ff65 bnez a4,2d4 <_Z13test_syscallsv+0x154> + n++; + 2de: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 2e0: 2605 addiw a2,a2,1 + 2e2: 00000597 auipc a1,0x0 + 2e6: 52e58593 addi a1,a1,1326 # 810 + 2ea: 4505 li a0,1 + 2ec: 384000ef jal 670 + } + } - print("[TEST 3] Fork, Wait & COW\n"); - 19a: 00000517 auipc a0,0x0 - 19e: 22650513 addi a0,a0,550 # 3c0 - 1a2: e7fff0ef jal 20 <_Z5printPKc> - int val = 100; + // 3. 测试 fork 和 wait + print("[3/4] Checking fork() and wait()...\n"); int pid = fork(); - 1a6: 0b4000ef jal 25a + 2f0: 358000ef jal 648 + 2f4: 84aa mv s1,a0 if (pid < 0) - 1aa: 04054363 bltz a0,1f0 + 2f6: 1c054e63 bltz a0,4d2 <_Z13test_syscallsv+0x352> { - print(" Fork Failed\n"); - fail(); + print(" FAIL: fork error\n"); } - - if (pid == 0) - 1ae: e929 bnez a0,200 + else if (pid == 0) + 2fa: e179 bnez a0,3c0 <_Z13test_syscallsv+0x240> { - print(" [Child] PID: "); - 1b0: 00000517 auipc a0,0x0 - 1b4: 24050513 addi a0,a0,576 # 3f0 - 1b8: e69ff0ef jal 20 <_Z5printPKc> - print_int(getpid()); - 1bc: 126000ef jal 2e2 - 1c0: e87ff0ef jal 46 <_Z9print_inti> - print("\n"); - 1c4: 00000517 auipc a0,0x0 - 1c8: 23c50513 addi a0,a0,572 # 400 - 1cc: e55ff0ef jal 20 <_Z5printPKc> - print(" [Child] Data corruption!\n"); + // --- 子进程 --- + int child_pid = getpid(); + 2fc: 3d4000ef jal 6d0 + 300: 84aa mv s1,a0 + if (child_pid == my_pid) + 302: 24a40563 beq s0,a0,54c <_Z13test_syscallsv+0x3cc> + while (s[n]) + 306: 00000697 auipc a3,0x0 + 30a: 57a68693 addi a3,a3,1402 # 880 + if (child_pid == my_pid) + 30e: 87b6 mv a5,a3 + while (s[n]) + 310: 0017c703 lbu a4,1(a5) + 314: 863e mv a2,a5 + 316: 0785 addi a5,a5,1 + 318: ff65 bnez a4,310 <_Z13test_syscallsv+0x190> + n++; + 31a: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 31c: 2605 addiw a2,a2,1 + 31e: 00000597 auipc a1,0x0 + 322: 56258593 addi a1,a1,1378 # 880 + 326: 4505 li a0,1 + 328: 348000ef jal 670 + { + print(" FAIL: Child has same PID as parent\n"); exit(1); } - - val = 200; - print(" [Child] Modified val to 200. Exiting.\n"); - 1d0: 00000517 auipc a0,0x0 - 1d4: 23850513 addi a0,a0,568 # 408 - 1d8: e49ff0ef jal 20 <_Z5printPKc> + print(" [Child] I am alive. PID="); + print_int(child_pid); + 32c: 8526 mv a0,s1 + 32e: d27ff0ef jal 54 <_Z9print_inti> + write(1, s, strlen(s)); + 332: 4605 li a2,1 + 334: 00000597 auipc a1,0x0 + 338: 56c58593 addi a1,a1,1388 # 8a0 + 33c: 4505 li a0,1 + 33e: 332000ef jal 670 + while (s[n]) + 342: 00000697 auipc a3,0x0 + 346: 56668693 addi a3,a3,1382 # 8a8 + write(1, s, strlen(s)); + 34a: 87b6 mv a5,a3 + while (s[n]) + 34c: 0017c703 lbu a4,1(a5) + 350: 863e mv a2,a5 + 352: 0785 addi a5,a5,1 + 354: ff65 bnez a4,34c <_Z13test_syscallsv+0x1cc> + n++; + 356: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 358: 2605 addiw a2,a2,1 + 35a: 00000597 auipc a1,0x0 + 35e: 54e58593 addi a1,a1,1358 # 8a8 + 362: 4505 li a0,1 + 364: 30c000ef jal 670 + print("\n"); + print(" [Child] Exiting now.\n"); exit(0); - 1dc: 4501 li a0,0 - 1de: 084000ef jal 262 - print_int(val); - fail(); + 368: 4501 li a0,0 + 36a: 2e6000ef jal 650 + while (s[n]) + 36e: 00000697 auipc a3,0x0 + 372: 60a68693 addi a3,a3,1546 # 978 + print("PASS (Fork/Wait cycle)\n"); } - } + else + { + print("FAIL (Wait returned "); + print_int(waited_pid); + 376: 87b6 mv a5,a3 + while (s[n]) + 378: 0017c703 lbu a4,1(a5) + 37c: 863e mv a2,a5 + 37e: 0785 addi a5,a5,1 + 380: ff65 bnez a4,378 <_Z13test_syscallsv+0x1f8> + n++; + 382: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 384: 2605 addiw a2,a2,1 + 386: 00000597 auipc a1,0x0 + 38a: 5f258593 addi a1,a1,1522 # 978 + 38e: 4505 li a0,1 + 390: 2e0000ef jal 670 + while (s[n]) + 394: 00000697 auipc a3,0x0 + 398: 61468693 addi a3,a3,1556 # 9a8 + write(1, s, strlen(s)); + 39c: 87b6 mv a5,a3 + while (s[n]) + 39e: 0017c703 lbu a4,1(a5) + 3a2: 863e mv a2,a5 + 3a4: 0785 addi a5,a5,1 + 3a6: ff65 bnez a4,39e <_Z13test_syscallsv+0x21e> + + // 4. 测试 write (如果是能看到这些输出,说明 write 已经正常了) + print("[4/4] Checking write()... PASS (Self-evident)\n"); + + print("=== [Test] All Tests Finished ===\n"); +} + 3a8: 6442 ld s0,16(sp) + 3aa: 60e2 ld ra,24(sp) + 3ac: 64a2 ld s1,8(sp) + n++; + 3ae: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 3b0: 2605 addiw a2,a2,1 + 3b2: 00000597 auipc a1,0x0 + 3b6: 5f658593 addi a1,a1,1526 # 9a8 + 3ba: 4505 li a0,1 +} + 3bc: 6105 addi sp,sp,32 + write(1, s, strlen(s)); + 3be: ac4d j 670 + 3c0: 00000697 auipc a3,0x0 + 3c4: 50868693 addi a3,a3,1288 # 8c8 + else if (pid == 0) + 3c8: 87b6 mv a5,a3 + while (s[n]) + 3ca: 0017c703 lbu a4,1(a5) + 3ce: 863e mv a2,a5 + 3d0: 0785 addi a5,a5,1 + 3d2: ff65 bnez a4,3ca <_Z13test_syscallsv+0x24a> + n++; + 3d4: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 3d6: 2605 addiw a2,a2,1 + 3d8: 00000597 auipc a1,0x0 + 3dc: 4f058593 addi a1,a1,1264 # 8c8 + 3e0: 4505 li a0,1 + 3e2: 28e000ef jal 670 + print_int(pid); + 3e6: 8526 mv a0,s1 + 3e8: c6dff0ef jal 54 <_Z9print_inti> + write(1, s, strlen(s)); + 3ec: 4605 li a2,1 + 3ee: 00000597 auipc a1,0x0 + 3f2: 4b258593 addi a1,a1,1202 # 8a0 + 3f6: 4505 li a0,1 + 3f8: 278000ef jal 670 + while (s[n]) + 3fc: 00000697 auipc a3,0x0 + 400: 4f468693 addi a3,a3,1268 # 8f0 + write(1, s, strlen(s)); + 404: 87b6 mv a5,a3 + while (s[n]) + 406: 0017c703 lbu a4,1(a5) + 40a: 863e mv a2,a5 + 40c: 0785 addi a5,a5,1 + 40e: ff65 bnez a4,406 <_Z13test_syscallsv+0x286> + n++; + 410: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 412: 2605 addiw a2,a2,1 + 414: 00000597 auipc a1,0x0 + 418: 4dc58593 addi a1,a1,1244 # 8f0 + 41c: 4505 li a0,1 + 41e: 252000ef jal 670 + int waited_pid = wait(0); + 422: 4501 li a0,0 + 424: 234000ef jal 658 + 428: 00000697 auipc a3,0x0 + 42c: 53868693 addi a3,a3,1336 # 960 + 430: 842a mv s0,a0 + if (waited_pid == pid) + 432: 87b6 mv a5,a3 + 434: 0ca48363 beq s1,a0,4fa <_Z13test_syscallsv+0x37a> + while (s[n]) + 438: 0017c703 lbu a4,1(a5) + 43c: 863e mv a2,a5 + 43e: 0785 addi a5,a5,1 + 440: ff65 bnez a4,438 <_Z13test_syscallsv+0x2b8> + n++; + 442: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 444: 2605 addiw a2,a2,1 + 446: 00000597 auipc a1,0x0 + 44a: 51a58593 addi a1,a1,1306 # 960 + 44e: 4505 li a0,1 + 450: 220000ef jal 670 + print_int(waited_pid); + 454: 8522 mv a0,s0 + 456: bffff0ef jal 54 <_Z9print_inti> + while (s[n]) + 45a: 00000697 auipc a3,0x0 + 45e: 32e68693 addi a3,a3,814 # 788 + print_int(waited_pid); + 462: 87b6 mv a5,a3 + while (s[n]) + 464: 0017c703 lbu a4,1(a5) + 468: 863e mv a2,a5 + 46a: 0785 addi a5,a5,1 + 46c: ff65 bnez a4,464 <_Z13test_syscallsv+0x2e4> + n++; + 46e: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 470: 2605 addiw a2,a2,1 + 472: 00000597 auipc a1,0x0 + 476: 31658593 addi a1,a1,790 # 788 + 47a: 4505 li a0,1 + 47c: 1f4000ef jal 670 +} + 480: b5fd j 36e <_Z13test_syscallsv+0x1ee> + 482: 00000697 auipc a3,0x0 + 486: 30e68693 addi a3,a3,782 # 790 + if (my_pid > 0) + 48a: 87b6 mv a5,a3 + while (s[n]) + 48c: 0017c703 lbu a4,1(a5) + 490: 863e mv a2,a5 + 492: 0785 addi a5,a5,1 + 494: ff65 bnez a4,48c <_Z13test_syscallsv+0x30c> + n++; + 496: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 498: 2605 addiw a2,a2,1 + 49a: 00000597 auipc a1,0x0 + 49e: 2f658593 addi a1,a1,758 # 790 + 4a2: 4505 li a0,1 + 4a4: 1cc000ef jal 670 +} + 4a8: b361 j 230 <_Z13test_syscallsv+0xb0> + 4aa: 00000697 auipc a3,0x0 + 4ae: 32e68693 addi a3,a3,814 # 7d8 + if (p == (char *)-1) + 4b2: 87b6 mv a5,a3 + while (s[n]) + 4b4: 0017c703 lbu a4,1(a5) + 4b8: 863e mv a2,a5 + 4ba: 0785 addi a5,a5,1 + 4bc: ff65 bnez a4,4b4 <_Z13test_syscallsv+0x334> + n++; + 4be: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 4c0: 2605 addiw a2,a2,1 + 4c2: 00000597 auipc a1,0x0 + 4c6: 31658593 addi a1,a1,790 # 7d8 + 4ca: 4505 li a0,1 + 4cc: 1a4000ef jal 670 +} + 4d0: bbed j 2ca <_Z13test_syscallsv+0x14a> + 4d2: 00000697 auipc a3,0x0 + 4d6: 36668693 addi a3,a3,870 # 838 + if (pid < 0) + 4da: 87b6 mv a5,a3 + while (s[n]) + 4dc: 0017c703 lbu a4,1(a5) + 4e0: 863e mv a2,a5 + 4e2: 0785 addi a5,a5,1 + 4e4: ff65 bnez a4,4dc <_Z13test_syscallsv+0x35c> + n++; + 4e6: 9e15 subw a2,a2,a3 + write(1, s, strlen(s)); + 4e8: 2605 addiw a2,a2,1 + 4ea: 00000597 auipc a1,0x0 + 4ee: 34e58593 addi a1,a1,846 # 838 + 4f2: 4505 li a0,1 + 4f4: 17c000ef jal 670 +} + 4f8: bd9d j 36e <_Z13test_syscallsv+0x1ee> + 4fa: 00000617 auipc a2,0x0 + 4fe: 41e60613 addi a2,a2,1054 # 918 + if (waited_pid == pid) + 502: 87b2 mv a5,a2 + while (s[n]) + 504: 0017c703 lbu a4,1(a5) + 508: 86be mv a3,a5 + 50a: 0785 addi a5,a5,1 + 50c: ff65 bnez a4,504 <_Z13test_syscallsv+0x384> + n++; + 50e: 40c6863b subw a2,a3,a2 + write(1, s, strlen(s)); + 512: 2605 addiw a2,a2,1 + 514: 00000597 auipc a1,0x0 + 518: 40458593 addi a1,a1,1028 # 918 + 51c: 4505 li a0,1 + 51e: 152000ef jal 670 + while (s[n]) + 522: 00000617 auipc a2,0x0 + 526: 42660613 addi a2,a2,1062 # 948 + write(1, s, strlen(s)); + 52a: 87b2 mv a5,a2 + while (s[n]) + 52c: 0017c703 lbu a4,1(a5) + 530: 86be mv a3,a5 + 532: 0785 addi a5,a5,1 + 534: ff65 bnez a4,52c <_Z13test_syscallsv+0x3ac> + n++; + 536: 40c6863b subw a2,a3,a2 + write(1, s, strlen(s)); + 53a: 2605 addiw a2,a2,1 + 53c: 00000597 auipc a1,0x0 + 540: 40c58593 addi a1,a1,1036 # 948 + 544: 4505 li a0,1 + 546: 12a000ef jal 670 +} + 54a: b515 j 36e <_Z13test_syscallsv+0x1ee> + 54c: 00000617 auipc a2,0x0 + 550: 30460613 addi a2,a2,772 # 850 + if (child_pid == my_pid) + 554: 87b2 mv a5,a2 + while (s[n]) + 556: 0017c703 lbu a4,1(a5) + 55a: 86be mv a3,a5 + 55c: 0785 addi a5,a5,1 + 55e: ff65 bnez a4,556 <_Z13test_syscallsv+0x3d6> + n++; + 560: 40c6863b subw a2,a3,a2 + write(1, s, strlen(s)); + 564: 2605 addiw a2,a2,1 + 566: 00000597 auipc a1,0x0 + 56a: 2ea58593 addi a1,a1,746 # 850 + 56e: 4505 li a0,1 + 570: 100000ef jal 670 + exit(1); + 574: 4505 li a0,1 + 576: 0da000ef jal 650 + 57a: b371 j 306 <_Z13test_syscallsv+0x186> + +000000000000057c
: +// ============================================================= +// Shell 主循环 +// ============================================================= + +int main() +{ + 57c: 715d addi sp,sp,-80 + print("\n[Lume Shell] Ready.\n"); + 57e: 00000517 auipc a0,0x0 + 582: 45250513 addi a0,a0,1106 # 9d0 +{ + 586: e486 sd ra,72(sp) + 588: e0a2 sd s0,64(sp) + 58a: fc26 sd s1,56(sp) + 58c: f84a sd s2,48(sp) + 58e: f44e sd s3,40(sp) + 590: f052 sd s4,32(sp) + 592: ec56 sd s5,24(sp) + 594: e85a sd s6,16(sp) + print("\n[Lume Shell] Ready.\n"); + 596: a99ff0ef jal 2e <_Z5printPKc> + print("Commands:\n"); + 59a: 00000517 auipc a0,0x0 + 59e: 44e50513 addi a0,a0,1102 # 9e8 + 5a2: a8dff0ef jal 2e <_Z5printPKc> + print(" s: Run System Call Tests (fork, wait, mm)\n"); + 5a6: 00000517 auipc a0,0x0 + 5aa: 45250513 addi a0,a0,1106 # 9f8 + 5ae: a81ff0ef jal 2e <_Z5printPKc> + print(" t: Run Disk Driver Test (VirtIO)\n"); + 5b2: 00000517 auipc a0,0x0 + 5b6: 47650513 addi a0,a0,1142 # a28 + 5ba: 00000b17 auipc s6,0x0 + 5be: 49eb0b13 addi s6,s6,1182 # a58 + n++; + 5c2: 4a85 li s5,1 + print(" t: Run Disk Driver Test (VirtIO)\n"); + 5c4: a6bff0ef jal 2e <_Z5printPKc> + 5c8: 848a mv s1,sp - print("\n=== All Tests Passed ===\n"); - 1e2: 00000517 auipc a0,0x0 - 1e6: 2ce50513 addi a0,a0,718 # 4b0 - 1ea: e37ff0ef jal 20 <_Z5printPKc> while (1) - 1ee: a001 j 1ee - print(" Fork Failed\n"); - 1f0: 00000517 auipc a0,0x0 - 1f4: 1f050513 addi a0,a0,496 # 3e0 - 1f8: e29ff0ef jal 20 <_Z5printPKc> - fail(); - 1fc: f03ff0ef jal fe <_Z4failv> - print(" [Parent] Waiting for child...\n"); - 200: 00000517 auipc a0,0x0 - 204: 23850513 addi a0,a0,568 # 438 - 208: e19ff0ef jal 20 <_Z5printPKc> - int child_pid = wait(0); - 20c: 4501 li a0,0 - 20e: 05c000ef jal 26a - 212: 842a mv s0,a0 - print(" [Parent] Child "); - 214: 00000517 auipc a0,0x0 - 218: 24c50513 addi a0,a0,588 # 460 - 21c: e05ff0ef jal 20 <_Z5printPKc> - print_int(child_pid); - 220: 8522 mv a0,s0 - 222: e25ff0ef jal 46 <_Z9print_inti> - print(" exited.\n"); - 226: 00000517 auipc a0,0x0 - 22a: 25250513 addi a0,a0,594 # 478 - 22e: df3ff0ef jal 20 <_Z5printPKc> - print(" [Parent] Check val (Expect 100): "); - 232: 00000517 auipc a0,0x0 - 236: 25650513 addi a0,a0,598 # 488 - 23a: de7ff0ef jal 20 <_Z5printPKc> - print_int(val); - 23e: 06400513 li a0,100 - 242: e05ff0ef jal 46 <_Z9print_inti> -void pass() { print(" -> [PASS]\n"); } - 246: 00000517 auipc a0,0x0 - 24a: 0da50513 addi a0,a0,218 # 320 - 24e: dd3ff0ef jal 20 <_Z5printPKc> - 252: bf41 j 1e2 - fail(); - 254: eabff0ef jal fe <_Z4failv> - 258: b789 j 19a - -000000000000025a : + { + char buf[16]; + write(1, "$ ", 2); + 5ca: 00000417 auipc s0,0x0 + 5ce: 48640413 addi s0,s0,1158 # a50 + + int n = read(0, buf, sizeof(buf)); + if (n <= 0) + continue; + + if (buf[0] == 's') + 5d2: 07300913 li s2,115 + { + test_syscalls(); + } + else if (buf[0] == 't') + 5d6: 07400993 li s3,116 + disk_test(); + exit(0); + } + wait(0); + } + else if (buf[0] != '\n') + 5da: 4a29 li s4,10 + n++; + 5dc: 416a8abb subw s5,s5,s6 + write(1, "$ ", 2); + 5e0: 4609 li a2,2 + 5e2: 85a2 mv a1,s0 + 5e4: 4505 li a0,1 + 5e6: 08a000ef jal 670 + int n = read(0, buf, sizeof(buf)); + 5ea: 4641 li a2,16 + 5ec: 85a6 mv a1,s1 + 5ee: 4501 li a0,0 + 5f0: 078000ef jal 668 + if (n <= 0) + 5f4: fea056e3 blez a0,5e0 + if (buf[0] == 's') + 5f8: 00014783 lbu a5,0(sp) + 5fc: 03278663 beq a5,s2,628 + else if (buf[0] == 't') + 600: 03378763 beq a5,s3,62e + else if (buf[0] != '\n') + 604: fd478ee3 beq a5,s4,5e0 + 608: 00000797 auipc a5,0x0 + 60c: 45078793 addi a5,a5,1104 # a58 + while (s[n]) + 610: 0017c703 lbu a4,1(a5) + 614: 863e mv a2,a5 + 616: 0785 addi a5,a5,1 + 618: ff65 bnez a4,610 + write(1, s, strlen(s)); + 61a: 00ca863b addw a2,s5,a2 + 61e: 85da mv a1,s6 + 620: 4505 li a0,1 + 622: 04e000ef jal 670 +} + 626: bf6d j 5e0 + test_syscalls(); + 628: b59ff0ef jal 180 <_Z13test_syscallsv> + 62c: bf55 j 5e0 + if (fork() == 0) + 62e: 01a000ef jal 648 + 632: c509 beqz a0,63c + wait(0); + 634: 4501 li a0,0 + 636: 022000ef jal 658 + 63a: b75d j 5e0 + disk_test(); + 63c: 0bc000ef jal 6f8 + exit(0); + 640: 4501 li a0,0 + 642: 00e000ef jal 650 + 646: b7fd j 634 + +0000000000000648 : name: \ li a7, SYS_ ## name; \ ecall; \ ret SYSCALL(fork) - 25a: 4889 li a7,2 - 25c: 00000073 ecall - 260: 8082 ret + 648: 4889 li a7,2 + 64a: 00000073 ecall + 64e: 8082 ret -0000000000000262 : +0000000000000650 : SYSCALL(exit) - 262: 488d li a7,3 - 264: 00000073 ecall - 268: 8082 ret + 650: 488d li a7,3 + 652: 00000073 ecall + 656: 8082 ret -000000000000026a : +0000000000000658 : SYSCALL(wait) - 26a: 4891 li a7,4 - 26c: 00000073 ecall - 270: 8082 ret + 658: 4891 li a7,4 + 65a: 00000073 ecall + 65e: 8082 ret -0000000000000272 : +0000000000000660 : SYSCALL(pipe) - 272: 4895 li a7,5 - 274: 00000073 ecall - 278: 8082 ret + 660: 4895 li a7,5 + 662: 00000073 ecall + 666: 8082 ret -000000000000027a : +0000000000000668 : SYSCALL(read) - 27a: 4899 li a7,6 - 27c: 00000073 ecall - 280: 8082 ret + 668: 4899 li a7,6 + 66a: 00000073 ecall + 66e: 8082 ret -0000000000000282 : +0000000000000670 : SYSCALL(write) - 282: 48c5 li a7,17 - 284: 00000073 ecall - 288: 8082 ret + 670: 48c5 li a7,17 + 672: 00000073 ecall + 676: 8082 ret -000000000000028a : +0000000000000678 : SYSCALL(close) - 28a: 48d9 li a7,22 - 28c: 00000073 ecall - 290: 8082 ret + 678: 48d9 li a7,22 + 67a: 00000073 ecall + 67e: 8082 ret -0000000000000292 : +0000000000000680 : SYSCALL(kill) - 292: 489d li a7,7 - 294: 00000073 ecall - 298: 8082 ret + 680: 489d li a7,7 + 682: 00000073 ecall + 686: 8082 ret -000000000000029a : +0000000000000688 : SYSCALL(exec) - 29a: 48a1 li a7,8 - 29c: 00000073 ecall - 2a0: 8082 ret + 688: 48a1 li a7,8 + 68a: 00000073 ecall + 68e: 8082 ret -00000000000002a2 : +0000000000000690 : SYSCALL(open) - 2a2: 48c1 li a7,16 - 2a4: 00000073 ecall - 2a8: 8082 ret + 690: 48c1 li a7,16 + 692: 00000073 ecall + 696: 8082 ret -00000000000002aa : +0000000000000698 : SYSCALL(mknod) - 2aa: 48c9 li a7,18 - 2ac: 00000073 ecall - 2b0: 8082 ret + 698: 48c9 li a7,18 + 69a: 00000073 ecall + 69e: 8082 ret -00000000000002b2 : +00000000000006a0 : SYSCALL(unlink) - 2b2: 48cd li a7,19 - 2b4: 00000073 ecall - 2b8: 8082 ret + 6a0: 48cd li a7,19 + 6a2: 00000073 ecall + 6a6: 8082 ret -00000000000002ba : +00000000000006a8 : SYSCALL(fstat) - 2ba: 48a5 li a7,9 - 2bc: 00000073 ecall - 2c0: 8082 ret + 6a8: 48a5 li a7,9 + 6aa: 00000073 ecall + 6ae: 8082 ret -00000000000002c2 : +00000000000006b0 : SYSCALL(link) - 2c2: 48d1 li a7,20 - 2c4: 00000073 ecall - 2c8: 8082 ret + 6b0: 48d1 li a7,20 + 6b2: 00000073 ecall + 6b6: 8082 ret -00000000000002ca : +00000000000006b8 : SYSCALL(mkdir) - 2ca: 48d5 li a7,21 - 2cc: 00000073 ecall - 2d0: 8082 ret + 6b8: 48d5 li a7,21 + 6ba: 00000073 ecall + 6be: 8082 ret -00000000000002d2 : +00000000000006c0 : SYSCALL(chdir) - 2d2: 48a9 li a7,10 - 2d4: 00000073 ecall - 2d8: 8082 ret + 6c0: 48a9 li a7,10 + 6c2: 00000073 ecall + 6c6: 8082 ret -00000000000002da : +00000000000006c8 : SYSCALL(dup) - 2da: 48ad li a7,11 - 2dc: 00000073 ecall - 2e0: 8082 ret + 6c8: 48ad li a7,11 + 6ca: 00000073 ecall + 6ce: 8082 ret -00000000000002e2 : +00000000000006d0 : SYSCALL(getpid) - 2e2: 48b1 li a7,12 - 2e4: 00000073 ecall - 2e8: 8082 ret + 6d0: 48b1 li a7,12 + 6d2: 00000073 ecall + 6d6: 8082 ret -00000000000002ea : +00000000000006d8 : SYSCALL(sbrk) - 2ea: 48b5 li a7,13 - 2ec: 00000073 ecall - 2f0: 8082 ret + 6d8: 48b5 li a7,13 + 6da: 00000073 ecall + 6de: 8082 ret -00000000000002f2 : +00000000000006e0 : SYSCALL(sleep) - 2f2: 48b9 li a7,14 - 2f4: 00000073 ecall - 2f8: 8082 ret + 6e0: 48b9 li a7,14 + 6e2: 00000073 ecall + 6e6: 8082 ret -00000000000002fa : +00000000000006e8 : SYSCALL(uptime) - 2fa: 48bd li a7,15 - 2fc: 00000073 ecall - 300: 8082 ret - -0000000000000302 : - 302: 4885 li a7,1 - 304: 00000073 ecall - 308: 8082 ret + 6e8: 48bd li a7,15 + 6ea: 00000073 ecall + 6ee: 8082 ret + +00000000000006f0 : +SYSCALL(putc) + 6f0: 4885 li a7,1 + 6f2: 00000073 ecall + 6f6: 8082 ret + +00000000000006f8 : + 6f8: 48dd li a7,23 + 6fa: 00000073 ecall + 6fe: 8082 ret diff --git a/build/user/initcode.out b/build/user/initcode.out index af31998..c8d8b7f 100755 Binary files a/build/user/initcode.out and b/build/user/initcode.out differ diff --git a/build/user/usys.o b/build/user/usys.o index 9ac9e11..537c6db 100644 Binary files a/build/user/usys.o and b/build/user/usys.o differ diff --git a/docs/dev/dev_device.md b/docs/dev/dev_device.md new file mode 100644 index 0000000..1eb6462 --- /dev/null +++ b/docs/dev/dev_device.md @@ -0,0 +1,23 @@ +# Dev log +## **3.Device Model & HAL:** +* Interrupt Controller: PLIC: + + * Implement the PLIC (Platform-Level Interrupt Controller) driver. + + * Set the PLIC priority threshold and enable bits during the start() phase. + + * Dispatch Cause 9 (External Interrupt) in kerneltrap/usertrap. + +* Character Device: Interrupt-Driven Console: + + * Implement a Ring Buffer. uart_putc returns immediately after writing to the buffer. + + * UART transmit interrupt: triggers when the serial port is idle, the ISR takes data from the Ring Buffer and writes it to the register. + + * UART receive interrupt: triggers when a key is pressed, the ISR reads the character and wakes up the process waiting to read. + +* Block Device: VirtIO-Blk: + + * Implement a block device driver for the PCI or MMIO transport layer according to the VirtIO 2.0 standard. + + * DMA: Use the Buddy System to allocate contiguous memory as the descriptor table for the Virtqueue. \ No newline at end of file diff --git a/docs/dev/dev_memory.md b/docs/dev/dev_memory.md new file mode 100644 index 0000000..f05e336 --- /dev/null +++ b/docs/dev/dev_memory.md @@ -0,0 +1,37 @@ +# Dev log +## **1. Process Management:** +The core architecture has been upgraded from a simple single queue to a Per-CPU scheduler, supporting multi-core concurrency. + +* Process lifecycle: A complete process state machine has been implemented, including UNUSED, RUNNABLE, RUNNING, SLEEPING, and ZOMBIE states. + +* Core operations: + * fork(): process cloning, supporting COW (copy-on-write) isolation of memory space between parent and child processes. + * exit(): process termination and resource cleanup. + * wait(): parent process waits for child process to exit. + * sleep()/wakeup(): channel-based sleep and wakeup mechanism. + +* Scheduling algorithm: + * O(1) priority scheduling has been implemented (supporting 4 priority queues). + + * Per-CPU RunQueue: each CPU has its own independent run queue. + + * Supports Work Stealing: idle CPUs can fetch tasks from other CPUs’ queues. + +## **2. Memory Management:** +A complete virtual and physical memory management system has been implemented. + +* Physical Memory (PMM): Implements the Buddy System, supporting memory allocation and deallocation in $2^n$ pages. + +* Virtual Memory (VM): Based on RISC-V Sv39 paging mode. Provides secure data copying from user space to kernel space (copyin). + +* COW (Copy-On-Write): During fork, only page table entries are copied and pages are set to read-only; writes trigger page faults for physical copy, greatly improving process creation efficiency. + +* Kernel heap: Implements a Slab Allocator, providing efficient allocation of small objects (such as struct Proc). + +## **3. Synchronization:** + +* Spinlock: Used to protect very short critical sections (e.g., scheduler lock, PMM lock), supports disabling interrupts to prevent deadlocks. + +* Mutex (sleeping lock): Used for long critical sections (e.g., file I/O), allowing sleep while holding the lock. + +* Lock Handoff: Implements a complex lock handoff mechanism in the scheduler to ensure atomicity of context switches. \ No newline at end of file diff --git a/docs/dev/dev_memoty.md b/docs/dev/dev_memoty.md deleted file mode 100644 index f05e336..0000000 --- a/docs/dev/dev_memoty.md +++ /dev/null @@ -1,37 +0,0 @@ -# Dev log -## **1. Process Management:** -The core architecture has been upgraded from a simple single queue to a Per-CPU scheduler, supporting multi-core concurrency. - -* Process lifecycle: A complete process state machine has been implemented, including UNUSED, RUNNABLE, RUNNING, SLEEPING, and ZOMBIE states. - -* Core operations: - * fork(): process cloning, supporting COW (copy-on-write) isolation of memory space between parent and child processes. - * exit(): process termination and resource cleanup. - * wait(): parent process waits for child process to exit. - * sleep()/wakeup(): channel-based sleep and wakeup mechanism. - -* Scheduling algorithm: - * O(1) priority scheduling has been implemented (supporting 4 priority queues). - - * Per-CPU RunQueue: each CPU has its own independent run queue. - - * Supports Work Stealing: idle CPUs can fetch tasks from other CPUs’ queues. - -## **2. Memory Management:** -A complete virtual and physical memory management system has been implemented. - -* Physical Memory (PMM): Implements the Buddy System, supporting memory allocation and deallocation in $2^n$ pages. - -* Virtual Memory (VM): Based on RISC-V Sv39 paging mode. Provides secure data copying from user space to kernel space (copyin). - -* COW (Copy-On-Write): During fork, only page table entries are copied and pages are set to read-only; writes trigger page faults for physical copy, greatly improving process creation efficiency. - -* Kernel heap: Implements a Slab Allocator, providing efficient allocation of small objects (such as struct Proc). - -## **3. Synchronization:** - -* Spinlock: Used to protect very short critical sections (e.g., scheduler lock, PMM lock), supports disabling interrupts to prevent deadlocks. - -* Mutex (sleeping lock): Used for long critical sections (e.g., file I/O), allowing sleep while holding the lock. - -* Lock Handoff: Implements a complex lock handoff mechanism in the scheduler to ensure atomicity of context switches. \ No newline at end of file diff --git a/fs.img b/fs.img new file mode 100644 index 0000000..fada73c Binary files /dev/null and b/fs.img differ diff --git a/include/drivers/plic.h b/include/drivers/plic.h index 8e8d986..11e8c8a 100644 --- a/include/drivers/plic.h +++ b/include/drivers/plic.h @@ -1,7 +1,7 @@ #pragma once #include "common/types.h" -namespace PILC +namespace PLIC { // Global initialization (executed only once by hart 0) void init(); diff --git a/include/drivers/uart.h b/include/drivers/uart.h index cb84bde..26c2394 100644 --- a/include/drivers/uart.h +++ b/include/drivers/uart.h @@ -1,11 +1,35 @@ #pragma once #include "common/types.h" +#define UART0 0x10000000L +#define RHR 0 // Receive Holding Register (read mode) +#define THR 0 // Transmit Holding Register (write mode) +#define IER 1 // Interrupt Enable Register +#define FCR 2 // FIFO Control Register +#define ISR 2 // Interrupt Status Register +#define LCR 3 // Line Control Register +#define LSR 5 // Line Status Register + +#define LSR_RX_READY 0x01 // input is waiting to be read from RHR +#define LSR_TX_IDLE 0x20 // THR can accept another character to send + +#define UART_RX_BUF_SIZE 128 + +// ANSI Escape Codes for Modern Terminal Colors +#define ANSI_RESET "\033[0m" +#define ANSI_RED "\033[31m" +#define ANSI_GREEN "\033[32m" +#define ANSI_YELLOW "\033[33m" +#define ANSI_BLUE "\033[34m" +#define ANSI_CLEAR "\033[2J\033[1;1H" + namespace Drivers { void uart_init(); - void uart_putc(char c); + void uart_intr(); + int console_read(uint64 target, int len); + void uart_putc(char c); void uart_puts(const char *s); void uart_put_int(int value); void print_hex(uint64 value); diff --git a/include/drivers/virtio.h b/include/drivers/virtio.h new file mode 100644 index 0000000..308dae0 --- /dev/null +++ b/include/drivers/virtio.h @@ -0,0 +1,102 @@ +#pragma once +#include "common/types.h" + +// VirtIO MMIO Base Address +#define VIRTIO0 0x10001000 + +// MMIO Registers (Modern / Version 2) +#define VIRTIO_MMIO_MAGIC_VALUE 0x000 +#define VIRTIO_MMIO_VERSION 0x004 +#define VIRTIO_MMIO_DEVICE_ID 0x008 +#define VIRTIO_MMIO_VENDOR_ID 0x00c +#define VIRTIO_MMIO_DEVICE_FEATURES 0x010 +#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 +#define VIRTIO_MMIO_DRIVER_FEATURES 0x020 +#define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 +#define VIRTIO_MMIO_QUEUE_SEL 0x030 +#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 +#define VIRTIO_MMIO_QUEUE_NUM 0x038 +#define VIRTIO_MMIO_QUEUE_READY 0x044 +#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 +#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 +#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 +#define VIRTIO_MMIO_STATUS 0x070 + +// 64-bit Queue Address Registers (Modern) +#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 +#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 +#define VIRTIO_MMIO_QUEUE_DRIVER_LOW 0x090 +#define VIRTIO_MMIO_QUEUE_DRIVER_HIGH 0x094 +#define VIRTIO_MMIO_QUEUE_DEVICE_LOW 0x0a0 +#define VIRTIO_MMIO_QUEUE_DEVICE_HIGH 0x0a4 + +// Status Bits +#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 +#define VIRTIO_CONFIG_S_DRIVER 2 +#define VIRTIO_CONFIG_S_DRIVER_OK 4 +#define VIRTIO_CONFIG_S_FEATURES_OK 8 + +// Feature Bits +#define VIRTIO_BLK_F_RO 5 +#define VIRTIO_BLK_F_SCSI 7 +#define VIRTIO_BLK_F_CONFIG_WCE 11 +#define VIRTIO_BLK_F_MQ 12 +#define VIRTIO_F_ANY_LAYOUT 27 +#define VIRTIO_RING_F_INDIRECT_DESC 28 +#define VIRTIO_RING_F_EVENT_IDX 29 +#define VIRTIO_F_VERSION_1 32 + +// Descriptor Flags +#define VRING_DESC_F_NEXT 1 +#define VRING_DESC_F_WRITE 2 + +#define NUM_DESCS 8 + +#define VIRTIO_BLK_T_IN 0 +#define VIRTIO_BLK_T_OUT 1 + +// Device Configuration Layout (Offset 0x100) +#define VIRTIO_MMIO_CONFIG 0x100 + +namespace VirtIO +{ + struct VRingDesc + { + uint64 addr; + uint32 len; + uint16 flags; + uint16 next; + }; + + struct VRingAvail + { + uint16 flags; + uint16 idx; + uint16 ring[NUM_DESCS]; + }; + + struct VRingUsedElem + { + uint32 id; + uint32 len; + }; + + struct VRingUsed + { + uint16 flags; + uint16 idx; + struct VRingUsedElem ring[NUM_DESCS]; + }; + + struct __attribute__((packed)) BlockRequest + { + uint32 type; // 0=Read, 1=Write + uint32 reserved; + uint64 sector; + }; + + void init(); + void intr(); + void rw(int write, uint64 blockno, char *buf); + void test_rw(); +} \ No newline at end of file diff --git a/include/kernel/proc.h b/include/kernel/proc.h index d63ccf7..cbf2902 100644 --- a/include/kernel/proc.h +++ b/include/kernel/proc.h @@ -17,6 +17,8 @@ namespace ProcManager void sleep(void *chan, Spinlock *lk); void wakeup(void *chan); + + int growproc(int n); } void forkret(); diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index 222f2f4..1fcd1ff 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -22,6 +22,7 @@ #define SYS_link 20 #define SYS_mkdir 21 #define SYS_close 22 +#define SYS_disk_test 23 #ifndef __ASSEMBLER__ void syscall(); diff --git a/include/user/user.h b/include/user/user.h index 7ab4923..7624a21 100644 --- a/include/user/user.h +++ b/include/user/user.h @@ -24,6 +24,7 @@ extern "C" { int sleep(int ticks); int uptime(); - + // Debug void putc(char c); + int disk_test(); } \ No newline at end of file diff --git a/src/drivers/plic.cc b/src/drivers/plic.cc index a13537c..a759597 100644 --- a/src/drivers/plic.cc +++ b/src/drivers/plic.cc @@ -1,60 +1,59 @@ #include "common/types.h" #include "kernel/riscv.h" #include "drivers/plic.h" +#include "drivers/uart.h" -// QEMU Virt PLIC address constants +// Base Constants constexpr uint64 PLIC_BASE = 0x0c000000L; constexpr uint64 PLIC_PRIORITY = PLIC_BASE + 0x0; constexpr uint64 PLIC_PENDING = PLIC_BASE + 0x1000; -// S-Mode interrupt enable register: each Hart occupies 0x100 bytes -// Context 1 is Hart 0 S-Mode, Context 3 is Hart 1 S-Mode... -inline uint64 PLIC_SENABLE(int hart) -{ - return PLIC_BASE + 0x2080 + static_cast(hart) * 0x100; -} +// Helper Macros to calculate addresses +#define PLIC_SENABLE_ADDR(hart) (PLIC_BASE + 0x2080 + (hart) * 0x100) +#define PLIC_STHRESHOLD_ADDR(hart) (PLIC_BASE + 0x201000 + (hart) * 0x2000) +#define PLIC_SCLAIM_ADDR(hart) (PLIC_BASE + 0x201004 + (hart) * 0x2000) -// S-Mode priority threshold and claim register: 0x2000 bytes per Hart -inline uint64 PLIC_STHRESHOLD(int hart) +// Helper for Volatile Access +static inline volatile uint32 *REG32(uint64 addr) { - return PLIC_BASE + 0x201000 + static_cast(hart) * 0x2000; + return reinterpret_cast(addr); } -inline uint64 PLIC_SCLAIM(int hart) -{ - return PLIC_BASE + 0x201004 + static_cast(hart) * 0x2000; -} - -namespace PILC +namespace PLIC { void init() { - *reinterpret_cast(PLIC_PRIORITY + 10 * 4) = 1; // UART - *reinterpret_cast(PLIC_PRIORITY + 1 * 4) = 1; // VirtIO 0 + // Set Priority for UART (IRQ 10) and VirtIO (IRQ 1) + // Must use volatile write + *REG32(PLIC_PRIORITY + 10 * 4) = 1; + for (int i = 1; i <= 8; i++) + { + *REG32(PLIC_PRIORITY + i * 4) = 1; + } } void inithart() { - int hart = static_cast(r_tp()); // 获取当前 hartid + int hart = static_cast(r_tp()); + + // Enable UART(10) and VirtIO(1) for this Hart (S-Mode) + *REG32(PLIC_SENABLE_ADDR(hart)) = (1 << 10) | 0x1FE; - // Enable UART and VirtIO interrupts for the current Hart's S-Mode - // Set bit 10 and bit 1 in the register bitmap - *reinterpret_cast(PLIC_SENABLE(hart)) = (1 << 10) | (1 << 1); + // Set Priority Threshold to 0 (Allow all) + *REG32(PLIC_STHRESHOLD_ADDR(hart)) = 0; - // Set the current Hart's S-Mode priority threshold to 0 - // Only interrupts with a priority higher than this threshold will be delivered - *reinterpret_cast(PLIC_STHRESHOLD(hart)) = 0; + Drivers::uart_puts("[PLIC] Hart Init Done.\n"); } int claim() { int hart = static_cast(r_tp()); - return *reinterpret_cast(PLIC_SCLAIM(hart)); + return *REG32(PLIC_SCLAIM_ADDR(hart)); } void complete(int irq) { int hart = static_cast(r_tp()); - *reinterpret_cast(PLIC_SCLAIM(hart)) = static_cast(irq); + *REG32(PLIC_SCLAIM_ADDR(hart)) = static_cast(irq); } -} // namespace PILC +} \ No newline at end of file diff --git a/src/drivers/uart.cc b/src/drivers/uart.cc index fe051f8..9475d49 100644 --- a/src/drivers/uart.cc +++ b/src/drivers/uart.cc @@ -1,102 +1,206 @@ #include "drivers/uart.h" -#include "common/types.h" -#include "kernel/config.h" - -// #define UART0_BASE 0x10000000L - -#define UART_RBR 0x00 // Receiver Buffer Register (Read) -#define UART_THR 0x00 // Transmitter Holding Register (Write) -#define UART_IER 0x01 // Interrupt Enable Register -#define UART_FCR 0x02 // FIFO Control Register -#define UART_LCR 0x03 // Line Control Register -#define UART_LSR 0x05 // Line Status Register - -#define UART_LSR_RX_READY 0x01 -#define UART_LSR_TX_EMPTY 0x20 +#include "kernel/riscv.h" +#include "kernel/spinlock.h" +#include "kernel/proc.h" +#include "kernel/mm.h" +#include "lib/string.h" namespace Drivers { - - inline volatile uint8_t ®(uint32_t offset) + // Circular buffer structure + struct { - return *reinterpret_cast(g_uart_base + offset); - } + Spinlock lock; + char buf[UART_RX_BUF_SIZE]; + uint32 r; // read index + uint32 w; // write index + } uart_rx; + + Spinlock uart_tx_lock; void uart_init() { - if (g_uart_base == 0) - return; + uart_rx.lock.init("uart_rx"); + uart_tx_lock.init("uart_tx"); + uart_rx.r = 0; + uart_rx.w = 0; - reg(UART_IER) = 0x00; // Disable interrupt - reg(UART_LCR) = 0x80; // Set baud rate (LATCH bit) - reg(0x00) = 0x03; // LSB - reg(0x01) = 0x00; // MSB - reg(UART_LCR) = 0x03; // 8 bits, no parity, one stop bit - reg(UART_FCR) = 0x07; // Enable FIFO, clear TX/RX queues - } + // Disable interrupts and configure + *(volatile uint8 *)(UART0 + IER) = 0x00; - void uart_putc(char c) - { - if (g_uart_base == 0) - return; + // Enter baud rate setting mode (LCR_DLAB) = 0x80; + *(volatile uint8 *)(UART0 + LCR) = 0x80; + *(volatile uint8 *)(UART0 + 0) = 0x03; // DLL: 38.4K baud + *(volatile uint8 *)(UART0 + 1) = 0x00; // DLM - if (c == '\n') - { - uart_putc('\r'); - } + // Exit baud rate setting, set 8-bit word length, no parity + *(volatile uint8 *)(UART0 + LCR) = 0x03; - // Waiting for the send buffer to be empty - while ((reg(UART_LSR) & UART_LSR_TX_EMPTY) == 0) - ; + // Reset and enable FIFO + *(volatile uint8 *)(UART0 + FCR) = 0x07; - reg(UART_THR) = c; + // Enable Receive Data Available Interrupt + *(volatile uint8 *)(UART0 + IER) = 0x01; } + void uart_putc(char c) + { + uart_tx_lock.acquire(); + while ((*(volatile uint8 *)(UART0 + LSR) & LSR_TX_IDLE) == 0) + ; + *(volatile uint8 *)(UART0 + THR) = c; + uart_tx_lock.release(); + } void uart_puts(const char *s) { while (*s) - { uart_putc(*s++); - } } - void uart_put_int(int value) + void uart_put_int(int val) { - if (value == 0) + char buf[16]; + int i = 0; + if (val == 0) { - uart_putc('0'); + uart_puts("0"); return; } - - if (value < 0) + if (val < 0) { - uart_putc('-'); - value = -value; + uart_puts("-"); + val = -val; } - - char buffer[16]; - int i = 0; - while (value > 0) + while (val > 0) { - buffer[i++] = (value % 10) + '0'; - value /= 10; + buf[i++] = (val % 10) + '0'; + val /= 10; } - while (i > 0) { - uart_putc(buffer[--i]); + uart_putc(buf[--i]); } } - void print_hex(uint64 value) + void print_hex(uint64 val) { + char hex[] = "0123456789ABCDEF"; uart_puts("0x"); - char hex[] = "0123456789abcdef"; - for (int i = 15; i >= 0; i--) + for (int i = 60; i >= 0; i -= 4) { - int nibble = (value >> (i * 4)) & 0xF; - uart_putc(hex[nibble]); + uart_putc(hex[(val >> i) & 0xF]); } } + + void uart_intr() + { + uart_rx.lock.acquire(); + + while (1) + { + if ((*(volatile uint8 *)(UART0 + LSR) & LSR_RX_READY) == 0) + break; + + char c = *(volatile uint8 *)(UART0 + RHR); + + uart_rx.buf[uart_rx.w % UART_RX_BUF_SIZE] = c; + uart_rx.w++; + + ProcManager::wakeup(&uart_rx); + } + + uart_rx.lock.release(); + } + + // Modern console read: Line buffering + Editing Keys + Echo + int console_read(uint64 target, int len) + { + struct Proc *p = myproc(); + int target_idx = 0; + + uart_rx.lock.acquire(); + + while (target_idx < len) + { + while (uart_rx.r == uart_rx.w) + { + if (p->xstate != 0) + { + uart_rx.lock.release(); + return -1; + } + ProcManager::sleep(&uart_rx, &uart_rx.lock); + } + + char c = uart_rx.buf[uart_rx.r % UART_RX_BUF_SIZE]; + uart_rx.r++; + + uart_rx.lock.release(); + + // 1. Handle Backspace (127 or \b) + if (c == 127 || c == '\b') + { + if (target_idx > 0) + { + // Erase character from screen: Backspace, Space, Backspace + uart_putc('\b'); + uart_putc(' '); + uart_putc('\b'); + target_idx--; + } + uart_rx.lock.acquire(); + continue; + } + + // 2. Handle Ctrl+U (Kill Line) + if (c == 0x15) + { + while (target_idx > 0) + { + uart_putc('\b'); + uart_putc(' '); + uart_putc('\b'); + target_idx--; + } + uart_rx.lock.acquire(); + continue; + } + + // 3. Handle Ctrl+L (Clear Screen) + if (c == 0x0C) + { + uart_puts(ANSI_CLEAR); + uart_puts("$ "); + uart_rx.lock.acquire(); + continue; + } + + // 4. Handle Return (CR -> LF) + if (c == '\r') + { + c = '\n'; + } + + // Echo back to user + uart_putc(c); + + if (VM::copyout(p->pagetable, target + target_idx, &c, 1) < 0) + { + return -1; + } + + target_idx++; + + if (c == '\n') + { + return target_idx; + } + + uart_rx.lock.acquire(); + } + + uart_rx.lock.release(); + return target_idx; + } } \ No newline at end of file diff --git a/src/drivers/virtio_dist.cc b/src/drivers/virtio_dist.cc new file mode 100644 index 0000000..99d100f --- /dev/null +++ b/src/drivers/virtio_dist.cc @@ -0,0 +1,338 @@ +#include "drivers/virtio.h" +#include "kernel/riscv.h" +#include "kernel/pmm.h" +#include "kernel/spinlock.h" +#include "lib/string.h" +#include "drivers/uart.h" +#include "kernel/proc.h" + +static uint64 virtio_base = 0x10001000; + +// VirtIO Block Device Config Structure +struct virtio_blk_config +{ + uint64 capacity; + uint32 size_max; + uint32 seg_max; + struct virtio_blk_geometry + { + uint16 cylinders; + uint8 heads; + uint8 sectors; + } geometry; + uint32 blk_size; + uint8 physical_block_exp; + uint8 alignment_offset; + uint16 min_io_size; + uint32 opt_io_size; +} __attribute__((packed)); + +static inline volatile uint32 *REG(uint32 offset) +{ + return reinterpret_cast(virtio_base + offset); +} + +namespace VirtIO +{ + struct Disk + { + struct VRingDesc *desc; + struct VRingAvail *avail; + struct VRingUsed *used; + + int free_head; + int num_free; + int free_chain[NUM_DESCS]; + + uint16 used_idx; + + struct TraceInfo + { + int busy; + int status; + } info[NUM_DESCS]; + + struct BlockRequest reqs[NUM_DESCS]; + uint8 req_status[NUM_DESCS]; + + Spinlock lock; + } disk; + + void init() + { + disk.lock.init("virtio_disk"); + + // 1. Probing for VirtIO-MMIO device + bool found = false; + // Probe common VirtIO addresses in QEMU virt machine + for (uint64 addr = 0x10001000; addr < 0x10009000; addr += 0x1000) + { + volatile uint32 *magic = (volatile uint32 *)(addr + VIRTIO_MMIO_MAGIC_VALUE); + volatile uint32 *dev_id = (volatile uint32 *)(addr + VIRTIO_MMIO_DEVICE_ID); + + if (*magic == 0x74726976 && *dev_id == 2) // ID 2 = Block Device + { + virtio_base = addr; + found = true; + Drivers::uart_puts(ANSI_GREEN "[VirtIO] Found Block Device @ "); + Drivers::print_hex(addr); + Drivers::uart_puts(ANSI_RESET "\n"); + break; + } + } + + if (!found) + { + Drivers::uart_puts(ANSI_RED "[VirtIO] Fatal - No Block Device found.\n" ANSI_RESET); + return; + } + + // 2. Check Device Version (We want Modern v2) + if (*REG(VIRTIO_MMIO_VERSION) != 2) + { + Drivers::uart_puts(ANSI_YELLOW "[VirtIO] Warning: Legacy device detected (expected v2).\n" ANSI_RESET); + } + + // 3. Reset Device + *REG(VIRTIO_MMIO_STATUS) = 0; + + // 4. Set ACKNOWLEDGE & DRIVER status + uint32 status = *REG(VIRTIO_MMIO_STATUS); + status |= VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER; + *REG(VIRTIO_MMIO_STATUS) = status; + + // 5. Feature Negotiation + *REG(VIRTIO_MMIO_DEVICE_FEATURES_SEL) = 0; + uint32 device_features_lo = *REG(VIRTIO_MMIO_DEVICE_FEATURES); + (void)device_features_lo; + + *REG(VIRTIO_MMIO_DEVICE_FEATURES_SEL) = 1; + uint32 device_features_hi = *REG(VIRTIO_MMIO_DEVICE_FEATURES); + (void)device_features_hi; + + *REG(VIRTIO_MMIO_DRIVER_FEATURES_SEL) = 0; + *REG(VIRTIO_MMIO_DRIVER_FEATURES) = 0; + + *REG(VIRTIO_MMIO_DRIVER_FEATURES_SEL) = 1; + // VIRTIO_F_VERSION_1 is usually bit 32. + // If not defined in header, we hardcode logic here: (1ULL << 0) for high bits + *REG(VIRTIO_MMIO_DRIVER_FEATURES) = 1; + + status |= VIRTIO_CONFIG_S_FEATURES_OK; + *REG(VIRTIO_MMIO_STATUS) = status; + + if (!(*REG(VIRTIO_MMIO_STATUS) & VIRTIO_CONFIG_S_FEATURES_OK)) + { + Drivers::uart_puts("VirtIO: Feature negotiation failed.\n"); + return; + } + + // 6. Queue Configuration + *REG(VIRTIO_MMIO_QUEUE_SEL) = 0; + if (*REG(VIRTIO_MMIO_QUEUE_READY)) + { + Drivers::uart_puts("VirtIO: Queue 0 not ready.\n"); + } + + uint32 max_queue = *REG(VIRTIO_MMIO_QUEUE_NUM_MAX); + if (max_queue < NUM_DESCS) + { + Drivers::uart_puts("VirtIO: Queue size too small.\n"); + return; + } + + *REG(VIRTIO_MMIO_QUEUE_NUM) = NUM_DESCS; + + // Allocate Memory for VirtQueues + void *ptr = PMM::alloc_pages(1); // 4KB is enough for small rings + memset(ptr, 0, PGSIZE); + + uint64 base_addr = (uint64)ptr; + disk.desc = reinterpret_cast(base_addr); + disk.avail = reinterpret_cast(base_addr + NUM_DESCS * 16); + disk.used = reinterpret_cast(base_addr + PGSIZE / 2); + + *REG(VIRTIO_MMIO_QUEUE_DESC_LOW) = (uint32)base_addr; + *REG(VIRTIO_MMIO_QUEUE_DESC_HIGH) = (uint32)(base_addr >> 32); + + uint64 avail_addr = (uint64)disk.avail; + *REG(VIRTIO_MMIO_QUEUE_DRIVER_LOW) = (uint32)avail_addr; + *REG(VIRTIO_MMIO_QUEUE_DRIVER_HIGH) = (uint32)(avail_addr >> 32); + + uint64 used_addr = (uint64)disk.used; + *REG(VIRTIO_MMIO_QUEUE_DEVICE_LOW) = (uint32)used_addr; + *REG(VIRTIO_MMIO_QUEUE_DEVICE_HIGH) = (uint32)(used_addr >> 32); + + *REG(VIRTIO_MMIO_QUEUE_READY) = 1; + + // 7. Initialize Internal Structures + disk.free_head = 0; + disk.num_free = NUM_DESCS; + disk.used_idx = 0; + for (int i = 0; i < NUM_DESCS; i++) + { + disk.free_chain[i] = i + 1; + disk.info[i].busy = 0; + } + + // 8. Finalize Setup + status |= VIRTIO_CONFIG_S_DRIVER_OK; + *REG(VIRTIO_MMIO_STATUS) = status; + + // === [Feature] Read Capacity === + volatile struct virtio_blk_config *config = (volatile struct virtio_blk_config *)(virtio_base + VIRTIO_MMIO_CONFIG); + uint64 capacity_sectors = config->capacity; + uint64 size_mb = (capacity_sectors * 512) / (1024 * 1024); + + Drivers::uart_puts(ANSI_GREEN "[VirtIO] Initialized. Capacity: "); + Drivers::uart_put_int(size_mb); + Drivers::uart_puts(" MB\n" ANSI_RESET); + } + + static int alloc_desc() + { + if (disk.num_free == 0) + return -1; + int id = disk.free_head; + disk.free_head = disk.free_chain[id]; + disk.num_free--; + return id; + } + + static void free_desc(int id) + { + disk.free_chain[id] = disk.free_head; + disk.free_head = id; + disk.num_free++; + ProcManager::wakeup(&disk.free_head); + } + + static void free_chain_soft(int head_idx) + { + int curr = head_idx; + while (1) + { + int flag = disk.desc[curr].flags; + int next = disk.desc[curr].next; + free_desc(curr); + if (flag & VRING_DESC_F_NEXT) + curr = next; + else + break; + } + } + + void rw(int write, uint64 blockno, char *buf) + { + uint64 sector = blockno * (1024 / 512); // Assume 1KB blocks + + disk.lock.acquire(); + + // Wait for enough descriptors + while (disk.num_free < 3) + { + ProcManager::sleep(&disk.free_head, &disk.lock); + } + + int idx[3]; + idx[0] = alloc_desc(); + idx[1] = alloc_desc(); + idx[2] = alloc_desc(); + + // 1. Request Header + struct BlockRequest *req = &disk.reqs[idx[0]]; + req->type = write ? VIRTIO_BLK_T_OUT : VIRTIO_BLK_T_IN; + req->reserved = 0; + req->sector = sector; + + disk.desc[idx[0]].addr = (uint64)req; + disk.desc[idx[0]].len = sizeof(struct BlockRequest); + disk.desc[idx[0]].flags = VRING_DESC_F_NEXT; + disk.desc[idx[0]].next = idx[1]; + + // 2. Data Buffer + disk.desc[idx[1]].addr = (uint64)buf; + disk.desc[idx[1]].len = 1024; // Fixed 1KB for this test + disk.desc[idx[1]].flags = VRING_DESC_F_NEXT; + if (!write) + disk.desc[idx[1]].flags |= VRING_DESC_F_WRITE; + disk.desc[idx[1]].next = idx[2]; + + // 3. Status Byte + disk.desc[idx[2]].addr = (uint64)&disk.req_status[idx[0]]; + disk.desc[idx[2]].len = 1; + disk.desc[idx[2]].flags = VRING_DESC_F_WRITE; + disk.desc[idx[2]].next = 0; + + disk.info[idx[0]].busy = 1; + + // Submit to Avail Ring + disk.avail->ring[disk.avail->idx % NUM_DESCS] = idx[0]; + __sync_synchronize(); + disk.avail->idx++; + __sync_synchronize(); + + // Notify Device + *REG(VIRTIO_MMIO_QUEUE_NOTIFY) = 0; + + // Wait for Completion + while (disk.info[idx[0]].busy) + { + ProcManager::sleep(&disk.info[idx[0]], &disk.lock); + } + + free_chain_soft(idx[0]); + disk.lock.release(); + } + + void intr() + { + disk.lock.acquire(); + + uint32 status = *REG(VIRTIO_MMIO_INTERRUPT_STATUS); + *REG(VIRTIO_MMIO_INTERRUPT_ACK) = status & 0x3; + + volatile struct VRingUsed *used_ring = (volatile struct VRingUsed *)disk.used; + + while (disk.used_idx != used_ring->idx) + { + int id = used_ring->ring[disk.used_idx % NUM_DESCS].id; + + if (disk.info[id].busy) + { + disk.info[id].busy = 0; + ProcManager::wakeup(&disk.info[id]); + } + disk.used_idx++; + } + + disk.lock.release(); + } + + void test_rw() + { + Drivers::uart_puts(ANSI_BLUE "[VirtIO] Disk Test Start...\n" ANSI_RESET); + + char *buf = (char *)PMM::alloc_page(); + if (!buf) + return; + + const char *msg = "Lume OS Disk Driver Test Pattern"; + strcpy(buf, msg); + + rw(1, 0, buf); // Write + memset(buf, 0, PGSIZE); + rw(0, 0, buf); // Read + + if (strcmp(buf, msg) == 0) + { + Drivers::uart_puts(ANSI_GREEN "[VirtIO] Test PASSED (R/W Verified).\n" ANSI_RESET); + } + else + { + Drivers::uart_puts(ANSI_RED "[VirtIO] Test FAILED.\n" ANSI_RESET); + } + + PMM::free_page(buf); + } +} \ No newline at end of file diff --git a/src/kernel/main.cc b/src/kernel/main.cc index 081ab3e..6e3bdde 100644 --- a/src/kernel/main.cc +++ b/src/kernel/main.cc @@ -1,6 +1,8 @@ #include "common/types.h" #include "kernel/riscv.h" #include "drivers/uart.h" +#include "drivers/plic.h" +#include "drivers/virtio.h" #include "kernel/pmm.h" #include "kernel/mm.h" #include "kernel/proc.h" @@ -8,7 +10,6 @@ #include "kernel/timer.h" #include "kernel/cpu.h" -// 引用外部 FDT 初始化函数 extern void fdt_init(uint64 dtb); extern uint64 g_dtb_addr; @@ -30,6 +31,9 @@ extern "C" void kernel_main(uint64 hartid, uint64 dtb) VM::kvminithart(); // Enable MMU Trap::init(); // Trap Management Trap::inithart(); + PLIC::init(); + PLIC::inithart(); + VirtIO::init(); Timer::init(); ProcManager::init(); // Process Management ProcManager::user_init(); // Initialize first user process @@ -45,6 +49,7 @@ extern "C" void kernel_main(uint64 hartid, uint64 dtb) VM::kvminithart(); Trap::inithart(); + PLIC::inithart(); Timer::init(); Drivers::uart_puts("[Boot] Hart started.\n"); } diff --git a/src/kernel/mm/pmm.cc b/src/kernel/mm/pmm.cc index 09bd65b..3474a49 100644 --- a/src/kernel/mm/pmm.cc +++ b/src/kernel/mm/pmm.cc @@ -9,73 +9,6 @@ extern "C" char kernel_end[]; extern uint64 g_dtb_addr; -// namespace PMM -// { -// struct Run -// { -// struct Run *next; -// }; - -// struct -// { -// struct Run *freelist; -// } kmem; - -// inline uint64_t PGROUNDUP(uint64_t a) -// { -// return (a + PGSIZE - 1) & ~(PGSIZE - 1); -// } - -// void init() -// { -// uint64_t start = PGROUNDUP((uint64_t)kernel_end); - -// Drivers::uart_puts("PMM: Initializing from"); - -// for (uint64_t p = start; p + PGSIZE <= PHYSTOP; p += PGSIZE) -// { -// free_page((void *)p); -// } -// } - -// void free_page(void* pa) -// { -// struct Run *r; -// if (((uint64_t)pa % PGSIZE) != 0 || (uint64_t)pa < (uint64_t)kernel_end || (uint64_t)pa >= PHYSTOP) -// { -// Drivers::uart_puts("PMM: Error - Invalid free address\n"); -// return; -// } -// r = (struct Run*)pa; - -// r->next = kmem.freelist; -// kmem.freelist = r; - -// } - -// void* alloc_page() -// { -// struct Run* r; - -// r = kmem.freelist; -// if (r) -// { -// kmem.freelist = r->next; - -// uint64_t *p = (uint64_t *)r; -// for (int i = 0; i < PGSIZE / 8; i++) -// { -// p[i] = 0; -// } -// } -// else -// { -// Drivers::uart_puts("PMM: Out of memory!\n"); -// } -// return (void *)r; -// } -// } - namespace PMM { // Global metadata array pointer diff --git a/src/kernel/mm/slab.cc b/src/kernel/mm/slab.cc index 370074a..702dc5c 100644 --- a/src/kernel/mm/slab.cc +++ b/src/kernel/mm/slab.cc @@ -19,6 +19,7 @@ struct SlabHeader uint16 used_count; // Number of allocated objects // Followed immediately by object data... // The free list of objects is embedded in the first 2 bytes of the object itself (stores the index of the next object) + uint32 padding; }; struct KmemCache @@ -82,6 +83,7 @@ namespace Slab slab->next = nullptr; slab->used_count = 0; slab->free_idx = 0; + slab->padding = 0; // Initialize the free list of objects // The starting position of each object stores the index of the next object @@ -186,7 +188,7 @@ namespace Slab if (!page) return; - if (!(page->flags & PG_slab)) + if (!page || !(page->flags & PG_slab)) { PMM::free_pages(ptr, page->order); return; @@ -204,6 +206,13 @@ namespace Slab struct SlabHeader *slab = (struct SlabHeader *)PGROUNDDOWN((uint64)ptr); + if ((uint64)ptr < (uint64)(slab + 1) || (uint64)ptr >= (uint64)slab + PGSIZE) + { + Drivers::uart_puts("Slab: kfree invalid pointer\n"); + c->lock.release(); + return; + } + char *base = (char *)(slab + 1); int obj_idx = ((uint64)ptr - (uint64)base) / c->obj_size; diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc index c3c5f01..7057d88 100644 --- a/src/kernel/mm/vm.cc +++ b/src/kernel/mm/vm.cc @@ -360,11 +360,10 @@ namespace VM { kernel_pagetable = uvmcreate(); - kvmmap(0x10000000, 0x10000000, PGSIZE, PTE_R | PTE_W); + kvmmap(0x10000000, 0x10000000, 0x10000, PTE_R | PTE_W); kvmmap(0x0c000000, 0x0c000000, 0x400000, PTE_R | PTE_W); kvmmap(0x02000000, 0x02000000, 0x10000, PTE_R | PTE_W); // CLINT kvmmap(KERNBASE, KERNBASE, PHYSTOP - KERNBASE, PTE_R | PTE_W | PTE_X); - // kvmmap(TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X); } void kvminithart() diff --git a/src/kernel/proc/proc.cc b/src/kernel/proc/proc.cc index e99b83d..c8b6d1d 100644 --- a/src/kernel/proc/proc.cc +++ b/src/kernel/proc/proc.cc @@ -471,7 +471,6 @@ namespace ProcManager int wait(uint64 addr) { - (void)addr; struct Proc *np; int havekids, pid; @@ -499,6 +498,11 @@ namespace ProcManager } pid = np->pid; + if (addr != 0 && VM::copyout(p->pagetable, addr, (char *)&np->xstate, sizeof(np->xstate)) < 0) + { + proc_mem_lock.release(); + return -1; + } freeproc(np); proc_mem_lock.release(); return pid; @@ -509,8 +513,33 @@ namespace ProcManager if (!havekids || p->state == ZOMBIE) return -1; - sleep(p, nullptr); + sleep(p, &proc_mem_lock); + } + } + + int growproc(int n) + { + uint64 sz; + struct Proc *p = myproc(); + + sz = p->sz; + + if (n > 0) + { + // Call VM::uvmalloc to allocate memory + // Parameters: page table, old size, new size, permissions (PTE_W) + if ((sz = VM::uvmalloc(p->pagetable, sz, sz + n, PTE_W)) == 0) + { + return -1; + } } + else if (n < 0) + { + sz = VM::uvmdealloc(p->pagetable, sz, sz + n); + } + + p->sz = sz; + return 0; } void create_kernel_thread(void (*func)(), const char *name) diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc index 1dfec73..837ac2c 100644 --- a/src/kernel/syscall.cc +++ b/src/kernel/syscall.cc @@ -3,6 +3,7 @@ #include "kernel/proc.h" #include "kernel/riscv.h" #include "drivers/uart.h" +#include "drivers/virtio.h" #include "kernel/timer.h" #include "kernel/mm.h" #include "kernel/trap.h" @@ -124,6 +125,42 @@ static uint64_t sys_write() return static_cast(-1); } +static uint64_t sys_read() +{ + int fd; + int n; + uint64_t p; + + // get param: fd, buf, len + if (argint(0, &fd) < 0 || argint(2, &n) < 0) + return -1; + p = argraw(1); + + if (fd == 0) // stdin + { + return Drivers::console_read(p, n); + } + return -1; +} + +static uint64_t sys_sbrk() +{ + int n; + if (argint(0, &n) < 0) + return -1; + + uint64_t addr = myproc()->sz; + if (ProcManager::growproc(n) < 0) + return -1; + + return addr; +} + +static uint64_t sys_disk_test() +{ + VirtIO::test_rw(); + return 0; +} void syscall() { @@ -131,15 +168,19 @@ void syscall() int num = p->tf->a7; uint64_t ret = static_cast(-1); - Drivers::uart_puts("Syscall: "); - Drivers::print_hex(num); - Drivers::uart_puts("\n"); + /* Just For Debug */ + // Drivers::uart_puts("Syscall: "); + // Drivers::print_hex(num); + // Drivers::uart_puts("\n"); switch (num) { case SYS_write: ret = sys_write(); break; + case SYS_read: + ret = sys_read(); + break; case SYS_putc: ret = sys_putc(); break; @@ -155,6 +196,12 @@ void syscall() case SYS_getpid: ret = sys_getpid(); break; + case SYS_sbrk: + ret = sys_sbrk(); + break; + case SYS_disk_test: + ret = sys_disk_test(); + break; default: Drivers::uart_puts("Unknown Syscall ID: "); Drivers::print_hex(num); diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc index d7f78de..c1626cc 100644 --- a/src/kernel/trap/handler.cc +++ b/src/kernel/trap/handler.cc @@ -6,6 +6,7 @@ #include "kernel/mm.h" #include "kernel/timer.h" #include "drivers/plic.h" +#include "drivers/virtio.h" #include "lib/string.h" @@ -59,20 +60,24 @@ namespace Trap if (is_interrupt && code == 9) { // Supervisor External Interrupt (IRQ 9) - int irq = PILC::claim(); + int irq = PLIC::claim(); if (irq == 10) { - // uart_intr(); + Drivers::uart_intr(); + // Debug + // Drivers::uart_puts("[Interrupt] UART Input detected!\n"); } else if (irq >= 1 && irq <= 8) { - // virtio_disk_intr(); + VirtIO::intr(); + // Debug + // Drivers::uart_puts("[Interrupt] VirtIO disk finished!\n"); } if (irq > 0) { - PILC::complete(irq); + PLIC::complete(irq); } return 1; diff --git a/src/user/entry.S b/src/user/entry.S new file mode 100644 index 0000000..110ebbf --- /dev/null +++ b/src/user/entry.S @@ -0,0 +1,12 @@ +.section .text +.global _start + +_start: + li a0, 0 + li a1, 0 + + call main + + call exit + +1: j 1b \ No newline at end of file diff --git a/src/user/init.cc b/src/user/init.cc index 85252be..1646f6b 100644 --- a/src/user/init.cc +++ b/src/user/init.cc @@ -13,106 +13,175 @@ void print(const char *s) write(1, s, strlen(s)); } -void print_int(int val) +void print_int(int n) { char buf[16]; int i = 0; - if (val == 0) + int neg = 0; + if (n == 0) { - print("0"); + write(1, "0", 1); return; } - if (val < 0) + if (n < 0) { - print("-"); - val = -val; + neg = 1; + n = -n; } - while (val > 0) + while (n > 0) { - buf[i++] = (val % 10) + '0'; - val /= 10; + buf[i++] = (n % 10) + '0'; + n /= 10; } + if (neg) + buf[i++] = '-'; while (i > 0) - { - char c = buf[--i]; - write(1, &c, 1); - } + write(1, &buf[--i], 1); } -void pass() { print(" -> [PASS]\n"); } -void fail() +void print_hex(uint64 n) { - print(" -> [FAIL]\n"); - exit(1); + char buf[16]; + char digits[] = "0123456789ABCDEF"; + write(1, "0x", 2); + if (n == 0) + { + write(1, "0", 1); + return; + } + int i = 0; + while (n > 0) + { + buf[i++] = digits[n % 16]; + n /= 16; + } + while (i > 0) + write(1, &buf[--i], 1); } -int main() +void test_syscalls() { - print("\n=== Lume OS Full Validation ===\n"); - - print("[TEST 1] Write\n"); - print(" System call write is working."); - pass(); - - print("[TEST 2] GetPID\n"); - int parent_pid = getpid(); - print(" Parent PID: "); - print_int(parent_pid); - if (parent_pid > 0) - pass(); + print("\n=== [Test] Starting System Call Check ===\n"); + + print("[1/4] Checking getpid()... "); + int my_pid = getpid(); + if (my_pid > 0) + { + print("PASS (PID="); + print_int(my_pid); + print(")\n"); + } else - fail(); + { + print("FAIL (Invalid PID)\n"); + } + + print("[2/4] Checking sbrk() heap allocation... "); + char *p = sbrk(4096); + if (p == (char *)-1) + { + print("FAIL (sbrk returned error)\n"); + } + else + { + p[0] = 'A'; + p[4095] = 'Z'; + if (p[0] == 'A' && p[4095] == 'Z') + { + print("PASS (Allocated at "); + print_hex((uint64)p); + print(")\n"); + } + else + { + print("FAIL (Memory read/write check failed)\n"); + } + } - print("[TEST 3] Fork, Wait & COW\n"); - int val = 100; + print("[3/4] Checking fork() and wait()...\n"); int pid = fork(); if (pid < 0) { - print(" Fork Failed\n"); - fail(); + print(" FAIL: fork error\n"); } - - if (pid == 0) + else if (pid == 0) { - print(" [Child] PID: "); - print_int(getpid()); - print("\n"); - - if (val != 100) + int child_pid = getpid(); + if (child_pid == my_pid) { - print(" [Child] Data corruption!\n"); + print(" FAIL: Child has same PID as parent\n"); exit(1); } - - val = 200; - print(" [Child] Modified val to 200. Exiting.\n"); + print(" [Child] I am alive. PID="); + print_int(child_pid); + print("\n"); + print(" [Child] Exiting now.\n"); exit(0); } else { - print(" [Parent] Waiting for child...\n"); - int child_pid = wait(0); - - print(" [Parent] Child "); - print_int(child_pid); - print(" exited.\n"); + print(" [Parent] Forked child PID="); + print_int(pid); + print("\n"); + print(" [Parent] Waiting for child...\n"); - print(" [Parent] Check val (Expect 100): "); - print_int(val); + int waited_pid = wait(0); - if (val == 100) - pass(); + if (waited_pid == pid) + { + print(" [Parent] Wait returned correct PID.\n"); + print("PASS (Fork/Wait cycle)\n"); + } else { - print(" [Parent] Memory Isolation Failed! Val="); - print_int(val); - fail(); + print("FAIL (Wait returned "); + print_int(waited_pid); + print(")\n"); } } - print("\n=== All Tests Passed ===\n"); + print("[4/4] Checking write()... PASS (Self-evident)\n"); + + print("=== [Test] All Tests Finished ===\n"); +} + + +int main() +{ + print("\n[Lume Shell] Ready.\n"); + print("Commands:\n"); + print(" s: Run System Call Tests (fork, wait, mm)\n"); + print(" t: Run Disk Driver Test (VirtIO)\n"); + while (1) - ; + { + char buf[16]; + write(1, "$ ", 2); + + int n = read(0, buf, sizeof(buf)); + if (n <= 0) + continue; + + if (buf[0] == 's') + { + test_syscalls(); + } + else if (buf[0] == 't') + { + if (fork() == 0) + { + disk_test(); + exit(0); + } + wait(0); + } + else if (buf[0] != '\n') + { + print("Unknown command.\n"); + } + } + + exit(0); return 0; } \ No newline at end of file diff --git a/src/user/usys.S b/src/user/usys.S index e805d82..65937cc 100644 --- a/src/user/usys.S +++ b/src/user/usys.S @@ -28,4 +28,5 @@ SYSCALL(getpid) SYSCALL(sbrk) SYSCALL(sleep) SYSCALL(uptime) -SYSCALL(putc) \ No newline at end of file +SYSCALL(putc) +SYSCALL(disk_test) \ No newline at end of file -- cgit v1.2.3