summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.x@gmail.com>2025-12-11 16:34:51 +0800
committerRichard Qin <richard.qin.x@gmail.com>2025-12-11 16:34:51 +0800
commit27fc7bda593c8bd2c24a334a368772b5f15d4e9e (patch)
treecee97c7b0ba2701be3981b587902e03ba8b85e12 /src
parent497e4a1b2f6f9181518e9887991c0464bd8f6bcf (diff)
downloadlume-27fc7bda593c8bd2c24a334a368772b5f15d4e9e.tar.gz
lume-27fc7bda593c8bd2c24a334a368772b5f15d4e9e.tar.xz
feat:Cooperative Multitasking
Diffstat (limited to 'src')
-rw-r--r--src/kernel/main.cc101
-rw-r--r--src/kernel/mm/vm.cc2
-rw-r--r--src/kernel/proc/proc.cc113
-rw-r--r--src/kernel/proc/swtch.S34
-rw-r--r--src/kernel/timer.cc28
-rw-r--r--src/kernel/trap/handler.cc6
6 files changed, 232 insertions, 52 deletions
diff --git a/src/kernel/main.cc b/src/kernel/main.cc
index 2fa10a2..5dfba9b 100644
--- a/src/kernel/main.cc
+++ b/src/kernel/main.cc
@@ -2,20 +2,37 @@
#include "kernel/pmm.h"
#include "kernel/mm.h"
#include "kernel/trap.h"
+#include "kernel/proc.h"
+#include "kernel/timer.h"
-// void print_hex(uint64_t val)
-// {
-// char buf[17];
-// buf[16] = 0;
-// const char *digits = "0123456789ABCDEF";
-// for (int i = 15; i >= 0; i--)
-// {
-// buf[i] = digits[val & 0xf];
-// val >>= 4;
-// }
-// Drivers::uart_puts("0x");
-// Drivers::uart_puts(buf);
-// }
+void delay()
+{
+ for(volatile int i = 0; i < 1000000; i++)
+ {
+
+ }
+}
+
+void task_a()
+{
+ while(1)
+ {
+ Drivers::uart_putc('A');
+ delay();
+ ProcManager::yield();
+ }
+}
+
+void task_b()
+{
+ while (1)
+ {
+ Drivers::uart_putc('B');
+ delay();
+ ProcManager::yield();
+ }
+
+}
extern "C" void kernel_main()
{
@@ -24,39 +41,10 @@ extern "C" void kernel_main()
Drivers::uart_puts("\n[Modern DOS 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");
- Drivers::uart_puts("[Kernel] Initializing PMM...\n");
PMM::init();
- Drivers::uart_puts("[Kernel] PMM initialized.\n");
-
- Drivers::uart_puts("[Kernel] Testing alloc_page...\n");
- void *p1 = PMM::alloc_page();
- void *p2 = PMM::alloc_page();
-
- Drivers::uart_puts("Allocated Page 1: ");
- Drivers::print_hex((uint64_t)p1);
- Drivers::uart_puts("\n");
-
- Drivers::uart_puts("Allocated Page 2: ");
- Drivers::print_hex((uint64_t)p2);
- Drivers::uart_puts("\n");
-
- Drivers::uart_puts("[Kernel] Freeing Page 1...\n");
- PMM::free_page(p1);
-
- void *p3 = PMM::alloc_page();
- Drivers::uart_puts("Allocated Page 3: ");
- Drivers::print_hex((uint64_t)p3);
- Drivers::uart_puts("\n");
-
- if (p3 == p1)
- {
- Drivers::uart_puts("[Test Passed] Reuse freed memory successfully.\n");
- }
- else
- {
- Drivers::uart_puts("[Test Failed] Memory leak or logic error.\n");
- }
+ Drivers::uart_puts("[Boot] PMM initialized.\n");
VM::kvminit();
Drivers::uart_puts("[Boot] Kernel page table created.\n");
@@ -67,15 +55,26 @@ extern "C" void kernel_main()
Trap::init();
Drivers::uart_puts("[Boot] Trap Handler Installed.\n");
- Drivers::uart_puts("\n[Test] Triggering Page Fault by reading 0x0...\n");
- volatile int *p = (int *)0x0;
- int crash = *p;
- (void)crash;
+ Timer::init();
+ Drivers::uart_puts("[Boot] Timer Interrupt Enabled.\n");
+
+ // Drivers::uart_puts("\n[Test] Triggering Page Fault by reading 0x0...\n");
+ // volatile int *p = (int *)0x0;
+ // int crash = *p;
+ // (void)crash;
+
+ // Drivers::uart_puts("[Test Failed] Shuold not reach here.\n");
+
+ // Drivers::uart_puts("\n[Test] Triggering Store Fault on Text Segment...\n");
+ // *(int*)0x80000000 = 1234;
+
+ ProcManager::init();
+ Drivers::uart_puts("[Boot] Process Manager initialized.\n");
- Drivers::uart_puts("[Test Failed] Shuold not reach here.\n");
+ ProcManager::create_kernel_thread(task_a, "Task A");
+ ProcManager::create_kernel_thread(task_b, "Task B");
- Drivers::uart_puts("\n[Test] Triggering Store Fault on Text Segment...\n");
- *(int*)0x80000000 = 1234;
+ ProcManager::scheduler();
while (1)
{
diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc
index 3c14d40..8696fdb 100644
--- a/src/kernel/mm/vm.cc
+++ b/src/kernel/mm/vm.cc
@@ -78,6 +78,8 @@ namespace VM
mappages(kernel_pagetable, 0x10000000, 0x10000, 0x10000000, PTE_R | PTE_W);
+ mappages(kernel_pagetable, 0x2000000, 0x10000, 0x2000000, PTE_R | PTE_W);
+
mappages(kernel_pagetable, (uint64)text_start, (uint64)text_end - (uint64)text_start,
(uint64)text_start, PTE_R | PTE_X);
diff --git a/src/kernel/proc/proc.cc b/src/kernel/proc/proc.cc
new file mode 100644
index 0000000..469b7eb
--- /dev/null
+++ b/src/kernel/proc/proc.cc
@@ -0,0 +1,113 @@
+#include "kernel/proc.h"
+#include "kernel/pmm.h"
+#include "drivers/uart.h"
+
+#define NPROC 10
+
+void str_copy(char *dst, const char *src)
+{
+ while (*src)
+ *dst++ = *src++;
+ *dst = 0;
+}
+
+extern "C" void swtch(struct Context *old_ctx, struct Context *new_ctx);
+
+struct Proc procs[NPROC];
+struct Context main_context;
+
+namespace ProcManager
+{
+ void init()
+ {
+ for (int i = 0; i < NPROC; i++)
+ {
+ procs[i].state = UNUSED;
+ }
+ }
+
+ void create_kernel_thread(void (*func)(), const char *name)
+ {
+ struct Proc *p = nullptr;
+ for(int i = 0; i < NPROC; i++)
+ {
+ if(procs[i].state == UNUSED)
+ {
+ p = &procs[i];
+ p->pid = i + 1;
+ break;
+ }
+ }
+
+ if (!p)
+ {
+ Drivers::uart_puts("Error: No free process slots!\n");
+ return;
+ }
+
+ p->kstack = PMM::alloc_page();
+ if (!p->kstack)
+ {
+ Drivers::uart_puts("Error: Alloc kstack failed!\n");
+ return;
+ }
+
+ p->context.ra = (uint64)func;
+
+ p->context.sp = (uint64)p->kstack + 4096;
+
+ p->state = RUNNABLE;
+ str_copy(p->name, name);
+
+ Drivers::uart_puts("[Proc] Created thread: ");
+ Drivers::uart_puts(name);
+ Drivers::uart_puts("\n");
+ }
+
+ void yield()
+ {
+ struct Proc *p = nullptr;
+ for(int i = 0; i < NPROC; i++)
+ {
+ if (procs[i].state == RUNNING)
+ {
+ p = &procs[i];
+ break;
+ }
+ }
+ if(p)
+ {
+ p->state = RUNNABLE;
+ swtch(&p->context, &main_context);
+ }
+ }
+
+ void scheduler()
+ {
+ struct Proc *p = nullptr;
+ Drivers::uart_puts("[Proc] Scheduler started.\n");
+
+ for (;;)
+ {
+ // int nothing_to_run = 1;
+
+ intr_off();
+
+ for (p = procs; p < &procs[NPROC]; p++)
+ {
+ if (p->state == RUNNABLE)
+ {
+ // nothing_to_run = 0;
+
+ p->state = RUNNING;
+
+ intr_on();
+
+ swtch(&main_context, &p->context);
+
+ intr_off();
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/kernel/proc/swtch.S b/src/kernel/proc/swtch.S
new file mode 100644
index 0000000..f59de20
--- /dev/null
+++ b/src/kernel/proc/swtch.S
@@ -0,0 +1,34 @@
+.global swtch
+
+swtch:
+ sd ra, 0(a0)
+ sd sp, 8(a0)
+ sd s0, 16(a0)
+ sd s1, 24(a0)
+ sd s2, 32(a0)
+ sd s3, 40(a0)
+ sd s4, 48(a0)
+ sd s5, 56(a0)
+ sd s6, 64(a0)
+ sd s7, 72(a0)
+ sd s8, 80(a0)
+ sd s9, 88(a0)
+ sd s10, 96(a0)
+ sd s11, 104(a0)
+
+ ld ra, 0(a1)
+ ld sp, 8(a1)
+ ld s0, 16(a1)
+ ld s1, 24(a1)
+ ld s2, 32(a1)
+ ld s3, 40(a1)
+ ld s4, 48(a1)
+ ld s5, 56(a1)
+ ld s6, 64(a1)
+ ld s7, 72(a1)
+ ld s8, 80(a1)
+ ld s9, 88(a1)
+ ld s10, 96(a1)
+ ld s11, 104(a1)
+
+ ret
diff --git a/src/kernel/timer.cc b/src/kernel/timer.cc
new file mode 100644
index 0000000..8cb3b0f
--- /dev/null
+++ b/src/kernel/timer.cc
@@ -0,0 +1,28 @@
+#include "common/types.h"
+#include "kernel/timer.h"
+
+#define CLINT_BASE 0x2000000L
+#define CLINT_MTIMECMP(hartid) (CLINT_BASE + 0x4000 + 8 * (hartid))
+#define CLINT_MTIME (CLINT_BASE + 0xBFF8)
+
+#define INTERVAL 1000000
+
+namespace Timer{
+ uint64 get_time(){
+ return *(volatile uint64*)CLINT_MTIME;
+ }
+
+ void set_next_trigger(){
+ uint64 mtime = get_time();
+
+ *(volatile uint64 *)CLINT_MTIMECMP(0) = mtime + INTERVAL;
+ }
+
+ void init(){
+ set_next_trigger();
+ uint64 sie;
+ asm volatile("csrr %0, sie" : "=r"(sie));
+ sie |= (1L << 5);
+ asm volatile("csrw sie, %0" : : "r"(sie));
+ }
+} \ No newline at end of file
diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc
index 9cc19d1..ecb6652 100644
--- a/src/kernel/trap/handler.cc
+++ b/src/kernel/trap/handler.cc
@@ -1,6 +1,9 @@
#include "kernel/trap.h"
#include "common/types.h"
#include "drivers/uart.h"
+#include "kernel/proc.h"
+#include "kernel/timer.h"
+
void panic(const char *s)
{
@@ -48,7 +51,8 @@ namespace Trap
case 5:
Drivers::uart_puts("[IRQ] Timer Interrupt\n");
-
+ Timer::set_next_trigger();
+ ProcManager::yield();
break;
case 9: