compiled newlib, need to hook up the system calls
This commit is contained in:
@@ -37,6 +37,7 @@ higher:
|
||||
push %eax
|
||||
call kmain
|
||||
loop:
|
||||
hlt
|
||||
jmp loop
|
||||
|
||||
.section .bss
|
||||
|
||||
10
kernel/common.h
Normal file
10
kernel/common.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef KCOMMON_H
|
||||
#define KCOMMON_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void enable_interrupts();
|
||||
void disable_interrupts();
|
||||
uint32_t fetch_cr3();
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
.code32
|
||||
.global init_pit
|
||||
init_pit: # tickrate: 1193182/1000 = 0x04A9 (1000hz) (1ms)
|
||||
init_pit:
|
||||
movb $0x36, %al
|
||||
outb %al, $0x43
|
||||
|
||||
|
||||
@@ -129,6 +129,7 @@ void init_gdt() {
|
||||
for (uint32_t i = 0; i < sizeof(tss_entry); i++) {
|
||||
((char*)&tss)[i] = 0;
|
||||
}
|
||||
|
||||
tss.ss0 = 0x10;
|
||||
tss.iomap_base = sizeof(tss_entry);
|
||||
|
||||
@@ -136,6 +137,7 @@ void init_gdt() {
|
||||
|
||||
gdtr.limit = 6 * sizeof(uint64_t) - 1;
|
||||
gdtr.base = (uint32_t)&gdt;
|
||||
|
||||
load_gdt();
|
||||
tss_flush();
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ isr\num:
|
||||
jmp isr_common_stub
|
||||
.endm
|
||||
|
||||
.extern common_interrupt_handler
|
||||
.extern common_interrupt_handler # interrupts.c
|
||||
isr_common_stub:
|
||||
pushal
|
||||
|
||||
@@ -40,18 +40,20 @@ ISR_ERRCODE 14 # Page Fault (Has Error Code!)
|
||||
|
||||
// This is a special case so we need to handle it for task switching
|
||||
.global isr32
|
||||
.extern switch_context # scheduler.c
|
||||
.extern send_eoi_master # drivers/pic/pic.c
|
||||
isr32:
|
||||
cli
|
||||
|
||||
pushal
|
||||
|
||||
|
||||
pushl %esp
|
||||
call schedule_next_task
|
||||
call switch_context
|
||||
movl %eax, %esp
|
||||
|
||||
call send_eoi_master
|
||||
|
||||
popal
|
||||
|
||||
sti
|
||||
iret
|
||||
|
||||
|
||||
@@ -34,9 +34,8 @@ typedef struct __attribute__((packed)) {
|
||||
uint32_t eip, cs, eflags, useresp, ss;
|
||||
} registers;
|
||||
|
||||
// (interrupts.S)
|
||||
extern void load_idt(void);
|
||||
|
||||
// isr stubs
|
||||
extern void isr0();
|
||||
extern void isr1();
|
||||
extern void isr8();
|
||||
@@ -127,10 +126,6 @@ void common_interrupt_handler(registers *args) {
|
||||
while(1);
|
||||
break;
|
||||
}
|
||||
case 32:
|
||||
// wake the PIT timer driver
|
||||
send_eoi_master();
|
||||
break;
|
||||
case 33: {
|
||||
uint8_t data = ps2_read_data();
|
||||
send_eoi_master();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "multiboot.h"
|
||||
#include "interrupts.h"
|
||||
#include "elf.h"
|
||||
#include "gdt.h"
|
||||
#include "scheduler.h"
|
||||
#include "common.h"
|
||||
|
||||
#include <lib/print.h>
|
||||
#include <lib/stream.h>
|
||||
@@ -20,21 +20,22 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern void enable_interrupts();
|
||||
extern void disable_interrupts();
|
||||
extern uint32_t fetch_cr3();
|
||||
|
||||
extern char __kernel_start;
|
||||
extern char __kernel_end;
|
||||
|
||||
void kernel_test_task() {
|
||||
while (1) {
|
||||
kprintf("task sleeping...\n");
|
||||
sleep(10000000);
|
||||
void first_task() {
|
||||
kprintf("task started\n");
|
||||
int i = 5;
|
||||
while (i--) {
|
||||
sleep(1000);
|
||||
kprintf("task awake [%d]\n", i);
|
||||
}
|
||||
kprintf("exiting\n");
|
||||
exit();
|
||||
}
|
||||
|
||||
void kmain(uint32_t magic, multiboot_info* mbi) {
|
||||
disable_interrupts();
|
||||
if (!(mbi->flags & (1 << 6))) {
|
||||
return;
|
||||
}
|
||||
@@ -54,9 +55,14 @@ void kmain(uint32_t magic, multiboot_info* mbi) {
|
||||
|
||||
kprintf("basic initializations complete\n");
|
||||
|
||||
disable_interrupts();
|
||||
disable_interrupts(); // just paranoid... do it again
|
||||
init_scheduler();
|
||||
enable_interrupts();
|
||||
|
||||
while(1) yield();
|
||||
create_task((uint32_t)first_task, fetch_cr3());
|
||||
|
||||
while(1) {
|
||||
sleep(5000);
|
||||
kprintf("kernel awake\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
typedef enum {
|
||||
STATE_READY,
|
||||
STATE_SLEEPING,
|
||||
STATE_BLOCKED,
|
||||
STATE_DEAD
|
||||
} process_state_t;
|
||||
|
||||
@@ -15,6 +16,7 @@ typedef struct {
|
||||
uint32_t cr3;
|
||||
process_state_t state;
|
||||
uint32_t sleep;
|
||||
void* next;
|
||||
} __attribute__((packed)) process_t;
|
||||
|
||||
#endif
|
||||
@@ -1,12 +1,31 @@
|
||||
.code32
|
||||
.extern schedule_next_task
|
||||
|
||||
|
||||
.code32
|
||||
.global yield
|
||||
yield:
|
||||
cli
|
||||
pushal
|
||||
push %esp
|
||||
call schedule_next_task
|
||||
movl %eax, %esp
|
||||
popal
|
||||
sti
|
||||
ret
|
||||
.extern schedule_next_task
|
||||
yield: # void yield()
|
||||
cli
|
||||
|
||||
pushfl
|
||||
pushl %cs
|
||||
|
||||
movl 8(%esp), %eax
|
||||
pushl %eax
|
||||
|
||||
movl 4(%esp), %ebx # Get CS
|
||||
movl %ebx, 8(%esp) # Move CS over Old EIP
|
||||
movl 0(%esp), %ebx # Get Return EIP
|
||||
movl %ebx, 4(%esp) # Move Return EIP over CS
|
||||
addl $4, %esp # Adjust stack pointer up.
|
||||
|
||||
# the stack now looks like a hardware interrupt just happened, even though we never called one.
|
||||
|
||||
pushal
|
||||
|
||||
pushl %esp
|
||||
call switch_context
|
||||
movl %eax, %esp
|
||||
|
||||
popal
|
||||
sti
|
||||
iret
|
||||
@@ -5,24 +5,30 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "process.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
static process_t* process_table;
|
||||
static spinlock_t process_table_lock = {0};
|
||||
|
||||
static int current_process = 0;
|
||||
static int total_processes = 0;
|
||||
|
||||
extern uint32_t fetch_cr3();
|
||||
|
||||
#define IDLE_TASK_PID 1
|
||||
static void idle_task() {
|
||||
while (1) asm volatile("hlt");
|
||||
}
|
||||
|
||||
uint32_t schedule_next_task(uint32_t current_esp) {
|
||||
spin_lock(&process_table_lock);
|
||||
static void lock_scheduler() {
|
||||
disable_interrupts();
|
||||
}
|
||||
|
||||
static void unlock_scheduler() {
|
||||
enable_interrupts();
|
||||
}
|
||||
|
||||
// called from isr and yield, interrupts are already disabled and re enabled in the isr/yield func
|
||||
uint32_t switch_context(uint32_t current_esp) {
|
||||
process_table[current_process].esp = current_esp;
|
||||
|
||||
for (int i = 0; i < total_processes; i++) {
|
||||
@@ -39,6 +45,7 @@ uint32_t schedule_next_task(uint32_t current_esp) {
|
||||
|
||||
int next_process = current_process;
|
||||
int found_ready = 0;
|
||||
|
||||
while (1) {
|
||||
next_process = (next_process + 1) % total_processes;
|
||||
if (next_process != IDLE_TASK_PID && process_table[next_process].state == STATE_READY) {
|
||||
@@ -66,10 +73,7 @@ uint32_t schedule_next_task(uint32_t current_esp) {
|
||||
load_pd(process_table[current_process].cr3);
|
||||
}
|
||||
|
||||
uint32_t rtn = process_table[current_process].esp;
|
||||
spin_unlock(&process_table_lock);
|
||||
|
||||
return rtn;
|
||||
return process_table[current_process].esp;
|
||||
}
|
||||
|
||||
void init_scheduler() {
|
||||
@@ -94,9 +98,19 @@ int create_task(uint32_t entry_point, uint32_t cr3) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock(&process_table_lock);
|
||||
lock_scheduler();
|
||||
|
||||
// default to a new task, but if we find a dead one, re use it
|
||||
process_t* process = &process_table[total_processes];
|
||||
process->pid = total_processes;
|
||||
uint32_t pid = total_processes;
|
||||
for (uint32_t i = 0; i < total_processes; i++) {
|
||||
if (process_table[i].state == STATE_DEAD) {
|
||||
process = &process_table[i];
|
||||
pid = i;
|
||||
}
|
||||
}
|
||||
|
||||
process->pid = pid;
|
||||
process->cr3 = cr3;
|
||||
process->state = STATE_READY;
|
||||
process->sleep = 0;
|
||||
@@ -118,19 +132,24 @@ int create_task(uint32_t entry_point, uint32_t cr3) {
|
||||
*(--esp) = 0; // EDI
|
||||
|
||||
process->esp = (uint32_t)esp;
|
||||
spin_unlock(&process_table_lock);
|
||||
|
||||
total_processes++;
|
||||
unlock_scheduler();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void sleep(uint32_t ticks) {
|
||||
if (ticks == 0) return;
|
||||
|
||||
spin_lock(&process_table_lock);
|
||||
process_table[current_process].sleep = ticks;
|
||||
void sleep(uint32_t ms) {
|
||||
if (ms == 0) return;
|
||||
lock_scheduler();
|
||||
process_table[current_process].sleep = ms;
|
||||
process_table[current_process].state = STATE_SLEEPING;
|
||||
spin_unlock(&process_table_lock);
|
||||
|
||||
yield();
|
||||
}
|
||||
unlock_scheduler();
|
||||
}
|
||||
|
||||
void exit() {
|
||||
lock_scheduler();
|
||||
process_table[current_process].state = STATE_DEAD;
|
||||
yield(); // yield forever
|
||||
unlock_scheduler();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ void init_scheduler();
|
||||
|
||||
int create_task(uint32_t entry_point, uint32_t cr3);
|
||||
|
||||
void sleep(uint32_t ticks);
|
||||
void sleep(uint32_t ms);
|
||||
void yield();
|
||||
void exit();
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lib/print.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
typedef struct registers {
|
||||
uint32_t gs, fs, es, ds; // Pushed manually
|
||||
@@ -9,19 +9,35 @@ typedef struct registers {
|
||||
uint32_t eip, cs, eflags, useresp, ss; // Pushed automatically by CPU
|
||||
} registers_t;
|
||||
|
||||
int32_t sys_vga_text_write(char* buf);
|
||||
int32_t sys_exit();
|
||||
int32_t sys_read();
|
||||
int32_t sys_write();
|
||||
int32_t sys_open();
|
||||
int32_t sys_close();
|
||||
int32_t sys_brk();
|
||||
|
||||
int32_t syscall(registers_t* regs) {
|
||||
switch(regs->eax) {
|
||||
case 1: {
|
||||
return sys_vga_text_write((char*)regs->ebx);
|
||||
}
|
||||
case 1: return sys_exit();
|
||||
case 3: return sys_read();
|
||||
case 4: return sys_write();
|
||||
case 5: return sys_open();
|
||||
case 6: return sys_close();
|
||||
case 12: return sys_brk();
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t sys_vga_text_write(char* buf) {
|
||||
kprintf(buf);
|
||||
int32_t sys_exit() {
|
||||
exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t sys_read() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t sys_write() {
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user