process control and context switch

This commit is contained in:
2025-07-23 13:45:41 +03:00
parent af7b8d2851
commit 613145e8f6
5 changed files with 169 additions and 44 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@
*.bin
*.log
*.pcap
registers

View File

@@ -1,5 +1,41 @@
#include "common.h"
void *memcpy(void *dst, const void *src, size_t n) {
uint8_t *d = (uint8_t *) dst;
const uint8_t *s = (const uint8_t *) src;
while (n--)
*d++ = *s++;
return dst;
}
void *memset(void *buf, char c, size_t n) {
uint8_t *p = (uint8_t *) buf;
while (n--)
*p++ = c;
return buf;
}
char *strcpy(char *dst, const char *src) {
char *d = dst;
while (*src)
*d++ = *src++;
*d = '\0';
return dst;
} // The strcpy function continues copying even if
// src is longer than the memory area of dst.
// This can easily lead to bugs and vulnerabilities
int strcmp(const char *s1, const char *s2) {
while (*s1 && *s2) {
if (*s1 != *s2)
break;
s1++;
s2++;
}
return *(unsigned char *)s1 - *(unsigned char *)s2;
}
void putchar(char ch);
void printf(const char *fmt, ...) {
@@ -62,39 +98,3 @@ void printf(const char *fmt, ...) {
end:
va_end(vargs);
}
void *memcpy(void *dst, const void *src, size_t n) {
uint8_t *d = (uint8_t *) dst;
const uint8_t *s = (const uint8_t *) src;
while (n--)
*d++ = *s++;
return dst;
}
void *memset(void *buf, char c, size_t n) {
uint8_t *p = (uint8_t *) buf;
while (n--)
*p++ = c;
return buf;
}
char *strcpy(char *dst, const char *src) {
char *d = dst;
while (*src)
*d++ = *src++;
*d = '\0';
return dst;
} // The strcpy function continues copying even if
// src is longer than the memory area of dst.
// This can easily lead to bugs and vulnerabilities
int strcmp(const char *s1, const char *s2) {
while (*s1 && *s2) {
if (*s1 != *s2)
break;
s1++;
s2++;
}
return *(unsigned char *)s1 - *(unsigned char *)s2;
}

126
kernel.c
View File

@@ -125,6 +125,114 @@ void handle_trap(struct trap_frame *f) {
PANIC("Unexpected trap: scause=%x, stval=%x, sepc=%x\n", scause, stval, user_pc);
}
__attribute__((naked)) void switch_context(uint32_t *prev_sp,
uint32_t *next_sp) {
__asm__ __volatile__(
// Save calle-saved registers onto the stack of current proccess
"addi sp, sp, -13 * 4\n" // Allocate stack space for 13 4-byte registers
"sw ra, 0 * 4(sp)\n" // Save calle-saved registers only
"sw s0, 1 * 4(sp)\n"
"sw s1, 2 * 4(sp)\n"
"sw s2, 3 * 4(sp)\n"
"sw s3, 4 * 4(sp)\n"
"sw s4, 5 * 4(sp)\n"
"sw s5, 6 * 4(sp)\n"
"sw s6, 7 * 4(sp)\n"
"sw s7, 8 * 4(sp)\n"
"sw s8, 9 * 4(sp)\n"
"sw s9, 10 * 4(sp)\n"
"sw s10, 11 * 4(sp)\n"
"sw s11, 12 * 4(sp)\n"
// Switch stack pointer
"sw sp, (a0)\n" // *prev_sp = a0;
"lw sp, (a1)\n" // Switch stack pointer (sp) here
// Restore calle-saved registers from the next process's stack
"lw ra, 0 * 4(sp)\n" // Save calle-saved registers only
"lw s0, 1 * 4(sp)\n"
"lw s1, 2 * 4(sp)\n"
"lw s2, 3 * 4(sp)\n"
"lw s3, 4 * 4(sp)\n"
"lw s4, 5 * 4(sp)\n"
"lw s5, 6 * 4(sp)\n"
"lw s6, 7 * 4(sp)\n"
"lw s7, 8 * 4(sp)\n"
"lw s8, 9 * 4(sp)\n"
"lw s9, 10 * 4(sp)\n"
"lw s10, 11 * 4(sp)\n"
"lw s11, 12 * 4(sp)\n"
"addi sp, sp, 13 * 4\n" // We've popped 13 4-byte registers from the stack
"ret\n"
);
}
struct process procs[PROCS_MAX];
struct process *create_process(uint32_t pc) {
// Find an unused proccess control structure
struct process *proc = NULL;
int i;
for (i = 0; i <= PROCS_MAX; i++) {
if (procs[i].state == PROC_UNUSED) {
proc = &procs[i];
break;
}
}
if (!proc)
PANIC("No free process slots found! Fuck off!");
// Stack calle-saved registers
uint32_t *sp = (uint32_t *) &proc->stack[sizeof(proc->stack)];
*--sp = 0; // s11
*--sp = 0; // s10
*--sp = 0; // s9
*--sp = 0; // s8
*--sp = 0; // s7
*--sp = 0; // s6
*--sp = 0; // s5
*--sp = 0; // s4
*--sp = 0; // s3
*--sp = 0; // s2
*--sp = 0; // s1
*--sp = 0; // s0
*--sp = (uint32_t) pc; // ra
// Initialize fields
proc->pid = i + 1;
proc->state = PROC_RUNNABLE;
proc->sp = (uint32_t) sp;
return proc;
}
void delay(void) {
for (int i = 0; i < 69696969; i++)
__asm__ __volatile__("nop"); // do nothing
}
struct process *proc_a;
struct process *proc_b;
void proc_a_entry(void) {
printf("Start process A\n");
while (1) {
putchar('6');
switch_context(&proc_a->sp, &proc_b->sp);
delay();
}
}
void proc_b_entry(void) {
printf("Start process B\n");
while (1) {
putchar('9');
switch_context(&proc_b->sp, &proc_a->sp);
delay();
}
}
void kernel_main(void) {
printf("\n\nHello %s\n", "friend :3");
printf("60 + 9 = %d, %x\n", 60 + 9, 0x1234abcd);
@@ -135,14 +243,19 @@ void kernel_main(void) {
memset(__bss, 0, (size_t) __bss_end - (size_t) __bss);
paddr_t paddr0 = alloc_pages(2);
paddr_t paddr1 = alloc_pages(1);
printf("alloc_pages test paddr0=%x\n", paddr0);
printf("alloc_pages test paddr1=%x\n", paddr1);
WRITE_CSR(stvec, (uint32_t) kernel_entry);
PANIC("You booted successfully :3");
// paddr_t paddr0 = alloc_pages(2);
// paddr_t paddr1 = alloc_pages(1);
// printf("alloc_pages test paddr0=%x\n", paddr0);
// printf("alloc_pages test paddr1=%x\n", paddr1);
proc_a = create_process((uint32_t) proc_a_entry);
proc_b = create_process((uint32_t) proc_b_entry);
proc_a_entry();
PANIC("Your boot ended successfully :3");
// WRITE_CSR(stvec, (uint32_t) kernel_entry);
// __asm__ __volatile__("unimp"); // calls a unimp which triggers kernel panic
//
@@ -160,4 +273,3 @@ void boot(void) {
: [stack_top] "r" (__stack_top) // Pass the stack top address as %[stack_top]
);
}

View File

@@ -58,3 +58,15 @@ struct trap_frame {
printf("YOU GOT A PANIC ERROR: %s:%d: " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
while (1) {} \
} while (0)
#define PROCS_MAX 8 // Maximum ammount of processes
#define PROC_UNUSED 0 // Unused processes control structure
#define PROC_RUNNABLE 1 // Runnable proccess
struct process {
int pid; // ID of a process
int state; // State of the process: either PROC_UNUSED or PROC_RUNNABLE
vaddr_t sp; // Stack pointer
uint8_t stack[8192]; // Kernel stack
};

View File

@@ -28,6 +28,6 @@ SECTIONS {
. = ALIGN(4096);
__free_ram = .;
. += 128 * 1024 * 1048; /* 128MB */
. += 64 * 1024 * 1048; /* 64MB */
__free_ram_end = .;
}