summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2025-12-31 18:00:55 +0800
committerRichard Qin <richard.qin.x@gmail.com>2025-12-31 18:00:55 +0800
commitdbba25aa24f86c1f8c3a0589c82985840adc1b6b (patch)
tree11d1d7ee552030d953db9f911d5af6e079291c47
parent7759eef8cdac79028dd5b468bd9ce0cf1c12b162 (diff)
downloadlume-dbba25aa24f86c1f8c3a0589c82985840adc1b6b.tar.gz
lume-dbba25aa24f86c1f8c3a0589c82985840adc1b6b.tar.xz
dev:Refactor Memory Management and Process Management
-rw-r--r--Makefile2
-rwxr-xr-xbuild/kernel.elfbin78448 -> 154536 bytes
-rw-r--r--build/src/boot/entry.obin1864 -> 5464 bytes
-rw-r--r--build/src/drivers/uart.obin4352 -> 57352 bytes
-rw-r--r--build/src/kernel/config.obin1272 -> 4376 bytes
-rw-r--r--build/src/kernel/fdt.obin4560 -> 40344 bytes
-rw-r--r--build/src/kernel/initcode.obin1488 -> 2448 bytes
-rw-r--r--build/src/kernel/main.obin7056 -> 17744 bytes
-rw-r--r--build/src/kernel/mm/pmm.obin5128 -> 90424 bytes
-rw-r--r--build/src/kernel/mm/slab.obin0 -> 67304 bytes
-rw-r--r--build/src/kernel/mm/vm.obin135304 -> 213776 bytes
-rw-r--r--build/src/kernel/proc/proc.obin118560 -> 205000 bytes
-rw-r--r--build/src/kernel/proc/swtch.obin1072 -> 5024 bytes
-rw-r--r--build/src/kernel/sbi.obin1832 -> 11584 bytes
-rw-r--r--build/src/kernel/spinlock.obin6968 -> 99920 bytes
-rw-r--r--build/src/kernel/syscall.obin81848 -> 47560 bytes
-rw-r--r--build/src/kernel/timer.obin2368 -> 10992 bytes
-rw-r--r--build/src/kernel/trap/handler.obin13992 -> 65848 bytes
-rw-r--r--build/src/kernel/trap/trampoline.obin13408 -> 20960 bytes
-rw-r--r--build/src/kernel/trap/trap.obin13440 -> 20904 bytes
-rw-r--r--build/src/lib/string.obin4136 -> 27632 bytes
-rw-r--r--build/user/init.obin11264 -> 45880 bytes
-rwxr-xr-xbuild/user/initcodebin464 -> 1424 bytes
-rw-r--r--build/user/initcode.asm558
-rwxr-xr-xbuild/user/initcode.outbin9256 -> 14168 bytes
-rw-r--r--include/drivers/uart.h11
-rw-r--r--include/kernel/cpu.h19
-rw-r--r--include/kernel/mm.h28
-rw-r--r--include/kernel/pmm.h3
-rw-r--r--include/kernel/proc.h65
-rw-r--r--include/kernel/proc_def.h59
-rw-r--r--include/kernel/riscv.h1
-rw-r--r--include/kernel/runqueue.h16
-rw-r--r--include/kernel/slab.h10
-rw-r--r--include/kernel/spinlock.h2
-rw-r--r--include/kernel/sync.h38
-rw-r--r--include/kernel/trap.h7
-rw-r--r--link.ld39
-rw-r--r--linker.ld45
-rw-r--r--src/boot/entry.S26
-rw-r--r--src/drivers/uart.cc71
-rw-r--r--src/kernel/fdt.cc11
-rw-r--r--src/kernel/main.cc92
-rw-r--r--src/kernel/mm/pmm.cc353
-rw-r--r--src/kernel/mm/slab.cc246
-rw-r--r--src/kernel/mm/vm.cc394
-rw-r--r--src/kernel/proc/proc.cc434
-rw-r--r--src/kernel/spinlock.cc33
-rw-r--r--src/kernel/syscall.cc93
-rw-r--r--src/kernel/trap/handler.cc242
-rw-r--r--src/user/init.cc104
-rw-r--r--src/user/user.ld12
52 files changed, 2090 insertions, 924 deletions
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
--- a/build/kernel.elf
+++ b/build/kernel.elf
Binary files differ
diff --git a/build/src/boot/entry.o b/build/src/boot/entry.o
index 2398fda..ca04d37 100644
--- a/build/src/boot/entry.o
+++ b/build/src/boot/entry.o
Binary files differ
diff --git a/build/src/drivers/uart.o b/build/src/drivers/uart.o
index bdbc317..34a0840 100644
--- a/build/src/drivers/uart.o
+++ b/build/src/drivers/uart.o
Binary files differ
diff --git a/build/src/kernel/config.o b/build/src/kernel/config.o
index eb2108d..a07739e 100644
--- a/build/src/kernel/config.o
+++ b/build/src/kernel/config.o
Binary files differ
diff --git a/build/src/kernel/fdt.o b/build/src/kernel/fdt.o
index 2dd29e3..c2e2fe3 100644
--- a/build/src/kernel/fdt.o
+++ b/build/src/kernel/fdt.o
Binary files differ
diff --git a/build/src/kernel/initcode.o b/build/src/kernel/initcode.o
index e53a8a5..e29dda3 100644
--- a/build/src/kernel/initcode.o
+++ b/build/src/kernel/initcode.o
Binary files differ
diff --git a/build/src/kernel/main.o b/build/src/kernel/main.o
index df2f4af..54ee210 100644
--- a/build/src/kernel/main.o
+++ b/build/src/kernel/main.o
Binary files differ
diff --git a/build/src/kernel/mm/pmm.o b/build/src/kernel/mm/pmm.o
index 7065343..c77cdc9 100644
--- a/build/src/kernel/mm/pmm.o
+++ b/build/src/kernel/mm/pmm.o
Binary files differ
diff --git a/build/src/kernel/mm/slab.o b/build/src/kernel/mm/slab.o
new file mode 100644
index 0000000..23305aa
--- /dev/null
+++ b/build/src/kernel/mm/slab.o
Binary files differ
diff --git a/build/src/kernel/mm/vm.o b/build/src/kernel/mm/vm.o
index 22cbbe3..2e3c0de 100644
--- a/build/src/kernel/mm/vm.o
+++ b/build/src/kernel/mm/vm.o
Binary files differ
diff --git a/build/src/kernel/proc/proc.o b/build/src/kernel/proc/proc.o
index ef1e81e..63506e7 100644
--- a/build/src/kernel/proc/proc.o
+++ b/build/src/kernel/proc/proc.o
Binary files differ
diff --git a/build/src/kernel/proc/swtch.o b/build/src/kernel/proc/swtch.o
index f3443f3..8fee25b 100644
--- a/build/src/kernel/proc/swtch.o
+++ b/build/src/kernel/proc/swtch.o
Binary files differ
diff --git a/build/src/kernel/sbi.o b/build/src/kernel/sbi.o
index 20dd9de..24e5e36 100644
--- a/build/src/kernel/sbi.o
+++ b/build/src/kernel/sbi.o
Binary files differ
diff --git a/build/src/kernel/spinlock.o b/build/src/kernel/spinlock.o
index 96b62d9..f4a24bf 100644
--- a/build/src/kernel/spinlock.o
+++ b/build/src/kernel/spinlock.o
Binary files differ
diff --git a/build/src/kernel/syscall.o b/build/src/kernel/syscall.o
index 259a780..a3df126 100644
--- a/build/src/kernel/syscall.o
+++ b/build/src/kernel/syscall.o
Binary files differ
diff --git a/build/src/kernel/timer.o b/build/src/kernel/timer.o
index 4728b8b..5f93af4 100644
--- a/build/src/kernel/timer.o
+++ b/build/src/kernel/timer.o
Binary files differ
diff --git a/build/src/kernel/trap/handler.o b/build/src/kernel/trap/handler.o
index 88daa0e..570f268 100644
--- a/build/src/kernel/trap/handler.o
+++ b/build/src/kernel/trap/handler.o
Binary files differ
diff --git a/build/src/kernel/trap/trampoline.o b/build/src/kernel/trap/trampoline.o
index 4419278..ce16681 100644
--- a/build/src/kernel/trap/trampoline.o
+++ b/build/src/kernel/trap/trampoline.o
Binary files differ
diff --git a/build/src/kernel/trap/trap.o b/build/src/kernel/trap/trap.o
index feb0976..ebb1b8f 100644
--- a/build/src/kernel/trap/trap.o
+++ b/build/src/kernel/trap/trap.o
Binary files differ
diff --git a/build/src/lib/string.o b/build/src/lib/string.o
index bceb813..6d50c43 100644
--- a/build/src/lib/string.o
+++ b/build/src/lib/string.o
Binary files differ
diff --git a/build/user/init.o b/build/user/init.o
index d32ad08..13021f2 100644
--- a/build/user/init.o
+++ b/build/user/init.o
Binary files differ
diff --git a/build/user/initcode b/build/user/initcode
index 511a518..7d139ad 100755
--- a/build/user/initcode
+++ b/build/user/initcode
Binary files 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 <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
index 0667728..af31998 100755
--- a/build/user/initcode.out
+++ b/build/user/initcode.out
Binary files 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 &reg(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