process control and context switch
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@
|
||||
*.bin
|
||||
*.log
|
||||
*.pcap
|
||||
registers
|
||||
|
72
common.c
72
common.c
@@ -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
126
kernel.c
@@ -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]
|
||||
);
|
||||
}
|
||||
|
||||
|
12
kernel.h
12
kernel.h
@@ -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
|
||||
};
|
||||
|
Reference in New Issue
Block a user