diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2025-12-31 18:00:55 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2025-12-31 18:00:55 +0800 |
| commit | dbba25aa24f86c1f8c3a0589c82985840adc1b6b (patch) | |
| tree | 11d1d7ee552030d953db9f911d5af6e079291c47 | |
| parent | 7759eef8cdac79028dd5b468bd9ce0cf1c12b162 (diff) | |
| download | lume-dbba25aa24f86c1f8c3a0589c82985840adc1b6b.tar.gz lume-dbba25aa24f86c1f8c3a0589c82985840adc1b6b.tar.xz | |
dev:Refactor Memory Management and Process Management
52 files changed, 2090 insertions, 924 deletions
@@ -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 Binary files differindex e13d2ff..679a7bb 100755 --- a/build/kernel.elf +++ b/build/kernel.elf diff --git a/build/src/boot/entry.o b/build/src/boot/entry.o Binary files differindex 2398fda..ca04d37 100644 --- a/build/src/boot/entry.o +++ b/build/src/boot/entry.o diff --git a/build/src/drivers/uart.o b/build/src/drivers/uart.o Binary files differindex bdbc317..34a0840 100644 --- a/build/src/drivers/uart.o +++ b/build/src/drivers/uart.o diff --git a/build/src/kernel/config.o b/build/src/kernel/config.o Binary files differindex eb2108d..a07739e 100644 --- a/build/src/kernel/config.o +++ b/build/src/kernel/config.o diff --git a/build/src/kernel/fdt.o b/build/src/kernel/fdt.o Binary files differindex 2dd29e3..c2e2fe3 100644 --- a/build/src/kernel/fdt.o +++ b/build/src/kernel/fdt.o diff --git a/build/src/kernel/initcode.o b/build/src/kernel/initcode.o Binary files differindex e53a8a5..e29dda3 100644 --- a/build/src/kernel/initcode.o +++ b/build/src/kernel/initcode.o diff --git a/build/src/kernel/main.o b/build/src/kernel/main.o Binary files differindex df2f4af..54ee210 100644 --- a/build/src/kernel/main.o +++ b/build/src/kernel/main.o diff --git a/build/src/kernel/mm/pmm.o b/build/src/kernel/mm/pmm.o Binary files differindex 7065343..c77cdc9 100644 --- a/build/src/kernel/mm/pmm.o +++ b/build/src/kernel/mm/pmm.o diff --git a/build/src/kernel/mm/slab.o b/build/src/kernel/mm/slab.o Binary files differnew file mode 100644 index 0000000..23305aa --- /dev/null +++ b/build/src/kernel/mm/slab.o diff --git a/build/src/kernel/mm/vm.o b/build/src/kernel/mm/vm.o Binary files differindex 22cbbe3..2e3c0de 100644 --- a/build/src/kernel/mm/vm.o +++ b/build/src/kernel/mm/vm.o diff --git a/build/src/kernel/proc/proc.o b/build/src/kernel/proc/proc.o Binary files differindex ef1e81e..63506e7 100644 --- a/build/src/kernel/proc/proc.o +++ b/build/src/kernel/proc/proc.o diff --git a/build/src/kernel/proc/swtch.o b/build/src/kernel/proc/swtch.o Binary files differindex f3443f3..8fee25b 100644 --- a/build/src/kernel/proc/swtch.o +++ b/build/src/kernel/proc/swtch.o diff --git a/build/src/kernel/sbi.o b/build/src/kernel/sbi.o Binary files differindex 20dd9de..24e5e36 100644 --- a/build/src/kernel/sbi.o +++ b/build/src/kernel/sbi.o diff --git a/build/src/kernel/spinlock.o b/build/src/kernel/spinlock.o Binary files differindex 96b62d9..f4a24bf 100644 --- a/build/src/kernel/spinlock.o +++ b/build/src/kernel/spinlock.o diff --git a/build/src/kernel/syscall.o b/build/src/kernel/syscall.o Binary files differindex 259a780..a3df126 100644 --- a/build/src/kernel/syscall.o +++ b/build/src/kernel/syscall.o diff --git a/build/src/kernel/timer.o b/build/src/kernel/timer.o Binary files differindex 4728b8b..5f93af4 100644 --- a/build/src/kernel/timer.o +++ b/build/src/kernel/timer.o diff --git a/build/src/kernel/trap/handler.o b/build/src/kernel/trap/handler.o Binary files differindex 88daa0e..570f268 100644 --- a/build/src/kernel/trap/handler.o +++ b/build/src/kernel/trap/handler.o diff --git a/build/src/kernel/trap/trampoline.o b/build/src/kernel/trap/trampoline.o Binary files differindex 4419278..ce16681 100644 --- a/build/src/kernel/trap/trampoline.o +++ b/build/src/kernel/trap/trampoline.o diff --git a/build/src/kernel/trap/trap.o b/build/src/kernel/trap/trap.o Binary files differindex feb0976..ebb1b8f 100644 --- a/build/src/kernel/trap/trap.o +++ b/build/src/kernel/trap/trap.o diff --git a/build/src/lib/string.o b/build/src/lib/string.o Binary files differindex bceb813..6d50c43 100644 --- a/build/src/lib/string.o +++ b/build/src/lib/string.o diff --git a/build/user/init.o b/build/user/init.o Binary files differindex d32ad08..13021f2 100644 --- a/build/user/init.o +++ b/build/user/init.o diff --git a/build/user/initcode b/build/user/initcode Binary files differindex 511a518..7d139ad 100755 --- a/build/user/initcode +++ b/build/user/initcode 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 <main> + 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 <main>: +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 <write> + int n = 0; + 40: 4601 li a2,0 + write(1, s, strlen(s)); + 42: 4505 li a0,1 + 44: ac3d j 282 <write> + +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 <write> + 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 <putc+0x16> + c0: 4505 li a0,1 + c2: 1c0000ef jal 282 <write> + 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 <putc+0xe> + d6: 4505 li a0,1 + d8: a26d j 282 <write> + +00000000000000da <_Z4passv>: + while (s[n]) + da: 00000697 auipc a3,0x0 + de: 24668693 addi a3,a3,582 # 320 <putc+0x1e> + +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 <putc+0x1e> + fa: 4505 li a0,1 + fc: a259 j 282 <write> + +00000000000000fe <_Z4failv>: +void fail() +{ + fe: 1141 addi sp,sp,-16 + 100: 00000697 auipc a3,0x0 + 104: 23068693 addi a3,a3,560 # 330 <putc+0x2e> + 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 <putc+0x2e> + 122: 4505 li a0,1 + 124: 15e000ef jal 282 <write> + 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 <exit> + +0000000000000130 <main>: 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 <putc+0x3e> +{ + 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 <putc+0x66> + 14a: ed7ff0ef jal 20 <_Z5printPKc> + print(" System call write is working."); + 14e: 00000517 auipc a0,0x0 + 152: 22a50513 addi a0,a0,554 # 378 <putc+0x76> + 156: ecbff0ef jal 20 <_Z5printPKc> +void pass() { print(" -> [PASS]\n"); } + 15a: 00000517 auipc a0,0x0 + 15e: 1c650513 addi a0,a0,454 # 320 <putc+0x1e> + 162: ebfff0ef jal 20 <_Z5printPKc> + pass(); + + print("[TEST 2] GetPID\n"); + 166: 00000517 auipc a0,0x0 + 16a: 23250513 addi a0,a0,562 # 398 <putc+0x96> + 16e: eb3ff0ef jal 20 <_Z5printPKc> + int parent_pid = getpid(); + 172: 170000ef jal 2e2 <getpid> + 176: 842a mv s0,a0 + print(" Parent PID: "); + 178: 00000517 auipc a0,0x0 + 17c: 23850513 addi a0,a0,568 # 3b0 <putc+0xae> + 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 <main+0x124> +void pass() { print(" -> [PASS]\n"); } + 18e: 00000517 auipc a0,0x0 + 192: 19250513 addi a0,a0,402 # 320 <putc+0x1e> + 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 <putc+0xbe> + 1a2: e7fff0ef jal 20 <_Z5printPKc> + int val = 100; int pid = fork(); - c: 060000ef jal 6c <fork> + 1a6: 0b4000ef jal 25a <fork> if (pid < 0) - 10: 00054f63 bltz a0,2e <main+0x26> + 1aa: 04054363 bltz a0,1f0 <main+0xc0> { - write(1, "Fork failed\n", 12); - exit(1); + print(" Fork Failed\n"); + fail(); } if (pid == 0) - 14: e905 bnez a0,44 <main+0x3c> + 1ae: e929 bnez a0,200 <main+0xd0> { - write(1, "Hello from Child!\n", 18); - 16: 4649 li a2,18 - 18: 00000597 auipc a1,0x0 - 1c: 12058593 addi a1,a1,288 # 138 <putc+0x24> - 20: 4505 li a0,1 - 22: 072000ef jal 94 <write> + print(" [Child] PID: "); + 1b0: 00000517 auipc a0,0x0 + 1b4: 24050513 addi a0,a0,576 # 3f0 <putc+0xee> + 1b8: e69ff0ef jal 20 <_Z5printPKc> + print_int(getpid()); + 1bc: 126000ef jal 2e2 <getpid> + 1c0: e87ff0ef jal 46 <_Z9print_inti> + print("\n"); + 1c4: 00000517 auipc a0,0x0 + 1c8: 23c50513 addi a0,a0,572 # 400 <putc+0xfe> + 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 <putc+0x106> + 1d8: e49ff0ef jal 20 <_Z5printPKc> exit(0); - 26: 4501 li a0,0 - 28: 04c000ef jal 74 <exit> - write(1, "Parent waiting...\n", 18); - wait(0); - write(1, "Parent: Child exited.\n", 22); + 1dc: 4501 li a0,0 + 1de: 084000ef jal 262 <exit> + print_int(val); + fail(); + } } - while (1); - 2c: a001 j 2c <main+0x24> - write(1, "Fork failed\n", 12); - 2e: 4631 li a2,12 - 30: 00000597 auipc a1,0x0 - 34: 0f058593 addi a1,a1,240 # 120 <putc+0xc> - 38: 4505 li a0,1 - 3a: 05a000ef jal 94 <write> - exit(1); - 3e: 4505 li a0,1 - 40: 034000ef jal 74 <exit> - write(1, "Parent waiting...\n", 18); - 44: 4649 li a2,18 - 46: 00000597 auipc a1,0x0 - 4a: 10a58593 addi a1,a1,266 # 150 <putc+0x3c> - 4e: 4505 li a0,1 - 50: 044000ef jal 94 <write> - wait(0); - 54: 4501 li a0,0 - 56: 026000ef jal 7c <wait> - write(1, "Parent: Child exited.\n", 22); - 5a: 4659 li a2,22 - 5c: 00000597 auipc a1,0x0 - 60: 10c58593 addi a1,a1,268 # 168 <putc+0x54> - 64: 4505 li a0,1 - 66: 02e000ef jal 94 <write> - 6a: b7c9 j 2c <main+0x24> - -000000000000006c <fork>: + print("\n=== All Tests Passed ===\n"); + 1e2: 00000517 auipc a0,0x0 + 1e6: 2ce50513 addi a0,a0,718 # 4b0 <putc+0x1ae> + 1ea: e37ff0ef jal 20 <_Z5printPKc> + while (1) + 1ee: a001 j 1ee <main+0xbe> + print(" Fork Failed\n"); + 1f0: 00000517 auipc a0,0x0 + 1f4: 1f050513 addi a0,a0,496 # 3e0 <putc+0xde> + 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 <putc+0x136> + 208: e19ff0ef jal 20 <_Z5printPKc> + int child_pid = wait(0); + 20c: 4501 li a0,0 + 20e: 05c000ef jal 26a <wait> + 212: 842a mv s0,a0 + print(" [Parent] Child "); + 214: 00000517 auipc a0,0x0 + 218: 24c50513 addi a0,a0,588 # 460 <putc+0x15e> + 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 <putc+0x176> + 22e: df3ff0ef jal 20 <_Z5printPKc> + print(" [Parent] Check val (Expect 100): "); + 232: 00000517 auipc a0,0x0 + 236: 25650513 addi a0,a0,598 # 488 <putc+0x186> + 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 <putc+0x1e> + 24e: dd3ff0ef jal 20 <_Z5printPKc> + 252: bf41 j 1e2 <main+0xb2> + fail(); + 254: eabff0ef jal fe <_Z4failv> + 258: b789 j 19a <main+0x6a> + +000000000000025a <fork>: 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 <exit>: +0000000000000262 <exit>: 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 <wait>: +000000000000026a <wait>: 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 <pipe>: +0000000000000272 <pipe>: 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 <read>: +000000000000027a <read>: 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 <write>: +0000000000000282 <write>: 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 <close>: +000000000000028a <close>: 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 <kill>: +0000000000000292 <kill>: 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 <exec>: +000000000000029a <exec>: 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 <open>: +00000000000002a2 <open>: 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 <mknod>: +00000000000002aa <mknod>: 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 <unlink>: +00000000000002b2 <unlink>: 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 <fstat>: +00000000000002ba <fstat>: 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 <link>: +00000000000002c2 <link>: 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 <mkdir>: +00000000000002ca <mkdir>: 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 <chdir>: +00000000000002d2 <chdir>: 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 <dup>: +00000000000002da <dup>: 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 <getpid>: +00000000000002e2 <getpid>: 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 <sbrk>: +00000000000002ea <sbrk>: 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 <sleep>: +00000000000002f2 <sleep>: 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 <uptime>: +00000000000002fa <uptime>: SYSCALL(uptime) - 10c: 48bd li a7,15 - 10e: 00000073 ecall - 112: 8082 ret - -0000000000000114 <putc>: - 114: 4885 li a7,1 - 116: 00000073 ecall - 11a: 8082 ret + 2fa: 48bd li a7,15 + 2fc: 00000073 ecall + 300: 8082 ret + +0000000000000302 <putc>: + 302: 4885 li a7,1 + 304: 00000073 ecall + 308: 8082 ret diff --git a/build/user/initcode.out b/build/user/initcode.out Binary files differindex 0667728..af31998 100755 --- a/build/user/initcode.out +++ b/build/user/initcode.out 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<volatile uint8_t *>(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<<k)] exactly corresponds to physical address + (1<<k)*PGSIZE + struct Page *buddy = page + (1 << current_order); + + // Add the buddy to a lower-level linked list + list_add(buddy, current_order); + } + + // Mark as Occupied + page->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<uint64_t>(-1); } - return -1; } -int argint(int n, int *ip) +static int argint(int n, int *ip) { - *ip = argraw(n); + *ip = static_cast<int>(argraw(n)); return 0; } -uint64 sys_exit() + +static uint64_t sys_exit() { int n; if (argint(0, &n) < 0) - return -1; + return static_cast<uint64_t>(-1); ProcManager::exit(n); return 0; } -uint64 sys_fork() +static uint64_t sys_fork() { - return fork(); + return static_cast<uint64_t>(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<uint64_t>(ProcManager::wait(p)); } -uint64 sys_getpid() +static uint64_t sys_getpid() { - return myproc()->pid; + return static_cast<uint64_t>(myproc()->pid); } -uint64 sys_putc() +static uint64_t sys_putc() { - char c = (char)argraw(0); + char c = static_cast<char>(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<uint64_t>(-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<uint64_t>(len)) < 0) { Drivers::uart_puts("sys_write: copyin failed\n"); - return -1; + return static_cast<uint64_t>(-1); } for (int j = 0; j < len; j++) @@ -109,19 +119,27 @@ uint64 sys_write() } i += len; } - return n; + return static_cast<uint64_t>(n); } - return -1; + return static_cast<uint64_t>(-1); } + void syscall() { - struct Proc *p = myproc(); + Proc *p = myproc(); int num = p->tf->a7; - uint64 ret = -1; + uint64_t ret = static_cast<uint64_t>(-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<uint64_t>(-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,10 +1,10 @@ -OUTPUT_ARCH(riscv) -ENTRY(_start) +OUTPUT_ARCH( "riscv" ) +ENTRY( _start ) SECTIONS { . = 0x0; - + .text : { *(.text.entry) *(.text .text.*) @@ -12,16 +12,22 @@ SECTIONS .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.*) } }
\ No newline at end of file |
