did some restructuring, got multitasking almost working
This commit is contained in:
@@ -9,11 +9,11 @@
|
|||||||
"-Wextra",
|
"-Wextra",
|
||||||
"-Ikernel",
|
"-Ikernel",
|
||||||
"-o",
|
"-o",
|
||||||
"obj/kernel/boot/boot.o",
|
"obj/kernel/drivers/pit/pit.S.o",
|
||||||
"kernel/boot/boot.S"
|
"kernel/drivers/pit/pit.S"
|
||||||
],
|
],
|
||||||
"directory": "/home/slinky/source/RockOS",
|
"directory": "/home/slinky/source/RockOS",
|
||||||
"file": "/home/slinky/source/RockOS/kernel/boot/boot.S",
|
"file": "/home/slinky/source/RockOS/kernel/drivers/pit/pit.S",
|
||||||
"output": "/home/slinky/source/RockOS/obj/kernel/boot/boot.o"
|
"output": "/home/slinky/source/RockOS/obj/kernel/drivers/pit/pit.S.o"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -116,3 +116,8 @@ outsw:
|
|||||||
pop %esi
|
pop %esi
|
||||||
leave
|
leave
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
.global fetch_cr3
|
||||||
|
fetch_cr3:
|
||||||
|
mov %cr3, %eax
|
||||||
|
ret
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
#include "drivers/pic/pic.h"
|
#define PIC1_ADDR 0x20 + 0xC0000000
|
||||||
|
#define PIC2_ADDR 0xA0 + 0xC0000000
|
||||||
|
#define PIC1_COMMAND PIC1_ADDR
|
||||||
|
#define PIC1_DATA (PIC1_ADDR+1)
|
||||||
|
#define PIC2_COMMAND PIC2_ADDR
|
||||||
|
#define PIC2_DATA (PIC2_ADDR+1)
|
||||||
|
#define PIC_EOI 0x20
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
.extern io_wait
|
|
||||||
|
|
||||||
.global init_pic
|
.global init_pic
|
||||||
init_pic:
|
init_pic:
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
#define PIC1_ADDR 0x20 + 0xC0000000
|
#ifndef DPIC_H
|
||||||
#define PIC2_ADDR 0xA0 + 0xC0000000
|
#define DPIC_H
|
||||||
#define PIC1_COMMAND PIC1_ADDR
|
|
||||||
#define PIC1_DATA (PIC1_ADDR+1)
|
void init_pic();
|
||||||
#define PIC2_COMMAND PIC2_ADDR
|
|
||||||
#define PIC2_DATA (PIC2_ADDR+1)
|
void send_eoi_master();
|
||||||
#define PIC_EOI 0x20
|
void send_eoi_slave();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
#include "drivers/pit/pit.h"
|
|
||||||
|
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
.global init_pit
|
.global init_pit
|
||||||
init_pit: # tickrate: 1193182/1000 = 0x04A9 (1000hz) (1ms)
|
init_pit: # tickrate: 1193182/1000 = 0x04A9 (1000hz) (1ms)
|
||||||
movb $0x36, %al
|
movb $0x36, %al
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef DPIT_H
|
||||||
|
#define DPIT_H
|
||||||
|
|
||||||
|
void init_pit();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -9,8 +9,6 @@
|
|||||||
.global ps2_write_data
|
.global ps2_write_data
|
||||||
.global ps2_flush_output_buffer
|
.global ps2_flush_output_buffer
|
||||||
|
|
||||||
.extern io_wait
|
|
||||||
|
|
||||||
# helpers
|
# helpers
|
||||||
ps2_wait_input_empty: #(void) -> void
|
ps2_wait_input_empty: #(void) -> void
|
||||||
push %ebp
|
push %ebp
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <drivers/ps2/ps2.h>
|
#include <drivers/ps2/ps2.h>
|
||||||
|
|
||||||
extern void ps2_wait_input_empty(void);
|
extern void ps2_wait_input_empty(void);
|
||||||
|
|||||||
@@ -16,4 +16,10 @@
|
|||||||
#define SELF_TEST_SUCCESS 0x55
|
#define SELF_TEST_SUCCESS 0x55
|
||||||
#define PORT_TEST_SUCCESS 0x00
|
#define PORT_TEST_SUCCESS 0x00
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
#include <stdint.h>
|
||||||
|
int init_ps2();
|
||||||
|
uint8_t ps2_read_data();
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -26,10 +26,10 @@ enum vga_color {
|
|||||||
VGA_COLOR_WHITE = 15,
|
VGA_COLOR_WHITE = 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t terminal_row;
|
static size_t terminal_row;
|
||||||
size_t terminal_column;
|
static size_t terminal_column;
|
||||||
uint8_t terminal_color;
|
static uint8_t terminal_color;
|
||||||
uint16_t* terminal_buffer = (uint16_t*)VGA_MEMORY;
|
static uint16_t* terminal_buffer = (uint16_t*)VGA_MEMORY;
|
||||||
|
|
||||||
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
|
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
|
||||||
{
|
{
|
||||||
@@ -41,8 +41,7 @@ static inline uint16_t vga_entry(unsigned char uc, uint8_t color)
|
|||||||
return (uint16_t) uc | (uint16_t) color << 8;
|
return (uint16_t) uc | (uint16_t) color << 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_initialize()
|
void vga_init() {
|
||||||
{
|
|
||||||
terminal_row = 0;
|
terminal_row = 0;
|
||||||
terminal_column = 0;
|
terminal_column = 0;
|
||||||
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
||||||
@@ -55,8 +54,7 @@ void vga_initialize()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_putchar(char c)
|
void vga_putchar(char c) {
|
||||||
{
|
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
terminal_row++;
|
terminal_row++;
|
||||||
terminal_column = 0;
|
terminal_column = 0;
|
||||||
@@ -78,8 +76,3 @@ void vga_putchar(char c)
|
|||||||
terminal_row = 0;
|
terminal_row = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_stream_t vga_print_stream = {
|
|
||||||
.putchar = vga_putchar,
|
|
||||||
.trunc = vga_initialize,
|
|
||||||
};
|
|
||||||
7
kernel/drivers/vga/vga.h
Normal file
7
kernel/drivers/vga/vga.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef DVGA_H
|
||||||
|
#define DVGA_H
|
||||||
|
|
||||||
|
void vga_init();
|
||||||
|
void vga_putchar(char c);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
.code32
|
.code32
|
||||||
|
|
||||||
.extern gdtr
|
.extern gdtr
|
||||||
.global load_gdt
|
.global load_gdt
|
||||||
load_gdt:
|
load_gdt:
|
||||||
@@ -84,7 +84,7 @@ tss_entry tss;
|
|||||||
extern void load_gdt();
|
extern void load_gdt();
|
||||||
extern void tss_flush();
|
extern void tss_flush();
|
||||||
|
|
||||||
uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
|
static uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
|
||||||
{
|
{
|
||||||
uint64_t descriptor;
|
uint64_t descriptor;
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag)
|
|||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t create_tss_descriptor(uint32_t base, uint32_t limit)
|
static uint64_t create_tss_descriptor(uint32_t base, uint32_t limit)
|
||||||
{
|
{
|
||||||
uint64_t descriptor;
|
uint64_t descriptor;
|
||||||
uint16_t tss_flags = SEG_PRES(1) | SEG_PRIV(0) | SEG_DESCTYPE(0) | 0x09;
|
uint16_t tss_flags = SEG_PRES(1) | SEG_PRIV(0) | SEG_DESCTYPE(0) | 0x09;
|
||||||
|
|||||||
6
kernel/gdt.h
Normal file
6
kernel/gdt.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef KGDT_H
|
||||||
|
#define KGDT_H
|
||||||
|
|
||||||
|
void init_gdt();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
#include <lib/stream.h>
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "multiboot.h"
|
#include "multiboot.h"
|
||||||
|
|
||||||
print_stream_t* kout;
|
|
||||||
multiboot_info* grub_boot_struct_ptr = NULL;
|
multiboot_info* grub_boot_struct_ptr = NULL;
|
||||||
|
|
||||||
extern char __kernel_start;
|
extern char __kernel_start;
|
||||||
|
|||||||
61
kernel/idt.c
61
kernel/idt.c
@@ -1,61 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <idt.h>
|
|
||||||
|
|
||||||
#define IDT_MAX_DESCRIPTORS 256
|
|
||||||
|
|
||||||
#define ATTR_KERN_32 0x8E // active(1), ring 0 (00), interrupt gate(0), 32 bit (1110)
|
|
||||||
#define ATTR_USER_32 0xEE // active, ring 3, 32bit
|
|
||||||
|
|
||||||
#define SEGMENT_KERN 0x08
|
|
||||||
|
|
||||||
extern void load_idt(void);
|
|
||||||
extern void enable_int(void);
|
|
||||||
|
|
||||||
extern void isr0();
|
|
||||||
extern void isr1();
|
|
||||||
extern void isr8();
|
|
||||||
extern void isr13();
|
|
||||||
extern void isr14();
|
|
||||||
extern void isr32();
|
|
||||||
extern void isr33();
|
|
||||||
|
|
||||||
void* isr_stub_table[256] = {
|
|
||||||
[0] = isr0,
|
|
||||||
[1] = isr1,
|
|
||||||
[8] = isr8,
|
|
||||||
[13] = isr13,
|
|
||||||
[14] = isr14,
|
|
||||||
[32] = isr32,
|
|
||||||
[33] = isr33,
|
|
||||||
};
|
|
||||||
|
|
||||||
idt_entry idt[IDT_MAX_DESCRIPTORS];
|
|
||||||
idt_ptr idtr;
|
|
||||||
|
|
||||||
void set_idtr(uint8_t vector, void* isr, uint16_t sel, uint8_t attributes) {
|
|
||||||
idt_entry* desc = &idt[vector];
|
|
||||||
|
|
||||||
desc->isr_low = (uint32_t)isr & 0xFFFF;
|
|
||||||
desc->selector = SEGMENT_KERN;
|
|
||||||
desc->reserved = 0;
|
|
||||||
desc->attributes = attributes;
|
|
||||||
desc->isr_high = ((uint32_t)isr >> 16) & 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_idt() {
|
|
||||||
idtr.limit = (sizeof(idt_entry) * IDT_MAX_DESCRIPTORS) - 1;
|
|
||||||
idtr.base = (uint32_t)&idt;
|
|
||||||
|
|
||||||
for (int i = 0; i < IDT_MAX_DESCRIPTORS; i++) {
|
|
||||||
if (isr_stub_table[i] != 0) {
|
|
||||||
set_idtr(i, isr_stub_table[i], SEGMENT_KERN, ATTR_KERN_32);
|
|
||||||
} else {
|
|
||||||
set_idtr(i, 0, SEGMENT_KERN, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void syscall_handler();
|
|
||||||
set_idtr(0x80, syscall_handler, SEGMENT_KERN, ATTR_USER_32);
|
|
||||||
|
|
||||||
load_idt();
|
|
||||||
}
|
|
||||||
19
kernel/idt.h
19
kernel/idt.h
@@ -1,19 +0,0 @@
|
|||||||
#ifndef KIDT_H
|
|
||||||
#define KIDT_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef struct __attribute__((packed)){
|
|
||||||
uint16_t isr_low;
|
|
||||||
uint16_t selector;
|
|
||||||
uint8_t reserved;
|
|
||||||
uint8_t attributes;
|
|
||||||
uint16_t isr_high;
|
|
||||||
} idt_entry;
|
|
||||||
|
|
||||||
typedef struct __attribute__((packed)){
|
|
||||||
uint16_t limit;
|
|
||||||
uint32_t base;
|
|
||||||
} idt_ptr;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
.code32
|
.code32
|
||||||
|
|
||||||
.macro ISR_NOERRCODE num
|
.macro ISR_NOERRCODE num
|
||||||
.global isr\num
|
.global isr\num
|
||||||
isr\num:
|
isr\num:
|
||||||
@@ -33,18 +32,29 @@ load_idt:
|
|||||||
lidt idtr
|
lidt idtr
|
||||||
ret
|
ret
|
||||||
|
|
||||||
.global enable_int
|
|
||||||
enable_int:
|
|
||||||
sti
|
|
||||||
ret
|
|
||||||
|
|
||||||
ISR_NOERRCODE 0 # Divide by Zero
|
ISR_NOERRCODE 0 # Divide by Zero
|
||||||
ISR_NOERRCODE 1 # Debug
|
ISR_NOERRCODE 1 # Debug
|
||||||
ISR_ERRCODE 8 # Double Fault (Has Error Code!)
|
ISR_ERRCODE 8 # Double Fault (Has Error Code!)
|
||||||
ISR_ERRCODE 13 # General Protection Fault (Has Error Code!)
|
ISR_ERRCODE 13 # General Protection Fault (Has Error Code!)
|
||||||
ISR_ERRCODE 14 # Page Fault (Has Error Code!)
|
ISR_ERRCODE 14 # Page Fault (Has Error Code!)
|
||||||
|
|
||||||
ISR_NOERRCODE 32 # IRQ0 - Timer
|
// This is a special case so we need to handle it for task switching
|
||||||
|
.global isr32
|
||||||
|
isr32:
|
||||||
|
cli
|
||||||
|
pushal
|
||||||
|
|
||||||
|
pushl %esp
|
||||||
|
call schedule_next_task
|
||||||
|
movl %eax, %esp
|
||||||
|
|
||||||
|
call send_eoi_master
|
||||||
|
|
||||||
|
popal
|
||||||
|
|
||||||
|
sti
|
||||||
|
iret
|
||||||
|
|
||||||
ISR_NOERRCODE 33 # IRQ1 - Keyboard
|
ISR_NOERRCODE 33 # IRQ1 - Keyboard
|
||||||
|
|
||||||
ISR_NOERRCODE 46 # IRQ14
|
ISR_NOERRCODE 46 # IRQ14
|
||||||
@@ -1,23 +1,61 @@
|
|||||||
#include "lib/print.h"
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
extern void send_eoi_master(void);
|
#include <lib/print.h>
|
||||||
extern void send_eoi_slave(void);
|
|
||||||
extern uint8_t read_isr_master(void);
|
|
||||||
extern uint8_t read_isr_slave(void);
|
|
||||||
|
|
||||||
extern uint8_t ps2_read_data();
|
#include "syscall.h"
|
||||||
|
|
||||||
struct registers {
|
#include <drivers/pic/pic.h>
|
||||||
|
#include <drivers/ps2/ps2.h>
|
||||||
|
|
||||||
|
#define IDT_MAX_DESCRIPTORS 256
|
||||||
|
#define ATTR_KERN_32 0x8E // active(1), ring 0 (00), interrupt gate(0), 32 bit (1110)
|
||||||
|
#define ATTR_USER_32 0xEE // active, ring 3, 32bit
|
||||||
|
#define SEGMENT_KERN 0x08
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) {
|
||||||
|
uint16_t isr_low;
|
||||||
|
uint16_t selector;
|
||||||
|
uint8_t reserved;
|
||||||
|
uint8_t attributes;
|
||||||
|
uint16_t isr_high;
|
||||||
|
} idt_entry;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) {
|
||||||
|
uint16_t limit;
|
||||||
|
uint32_t base;
|
||||||
|
} idt_ptr;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) {
|
||||||
uint32_t edi, esi, ebp, esp_dummy, ebx, edx, ecx, eax;
|
uint32_t edi, esi, ebp, esp_dummy, ebx, edx, ecx, eax;
|
||||||
|
|
||||||
uint32_t int_no;
|
uint32_t int_no;
|
||||||
uint32_t error_code;
|
uint32_t error_code;
|
||||||
|
|
||||||
uint32_t eip, cs, eflags, useresp, ss;
|
uint32_t eip, cs, eflags, useresp, ss;
|
||||||
|
} registers;
|
||||||
|
|
||||||
|
extern void load_idt(void);
|
||||||
|
|
||||||
|
// isr stubs
|
||||||
|
extern void isr0();
|
||||||
|
extern void isr1();
|
||||||
|
extern void isr8();
|
||||||
|
extern void isr13();
|
||||||
|
extern void isr14();
|
||||||
|
extern void isr32();
|
||||||
|
extern void isr33();
|
||||||
|
|
||||||
|
static void* isr_stub_table[256] = {
|
||||||
|
[0] = isr0,
|
||||||
|
[1] = isr1,
|
||||||
|
[8] = isr8,
|
||||||
|
[13] = isr13,
|
||||||
|
[14] = isr14,
|
||||||
|
[32] = isr32,
|
||||||
|
[33] = isr33,
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* err_messages[32] = {
|
static const char* err_messages[32] = {
|
||||||
[0] = "Divide by 0",
|
[0] = "Divide by 0",
|
||||||
[1] = "",
|
[1] = "",
|
||||||
[8] = "",
|
[8] = "",
|
||||||
@@ -25,7 +63,37 @@ const char* err_messages[32] = {
|
|||||||
[14] = "Page Fault",
|
[14] = "Page Fault",
|
||||||
};
|
};
|
||||||
|
|
||||||
void common_interrupt_handler(struct registers *args) {
|
idt_entry idt[IDT_MAX_DESCRIPTORS];
|
||||||
|
idt_ptr idtr;
|
||||||
|
|
||||||
|
static void set_idtr(uint8_t vector, void* isr, uint16_t sel, uint8_t attributes) {
|
||||||
|
idt_entry* desc = &idt[vector];
|
||||||
|
|
||||||
|
desc->isr_low = (uint32_t)isr & 0xFFFF;
|
||||||
|
desc->selector = SEGMENT_KERN;
|
||||||
|
desc->reserved = 0;
|
||||||
|
desc->attributes = attributes;
|
||||||
|
desc->isr_high = ((uint32_t)isr >> 16) & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_idt() {
|
||||||
|
idtr.limit = (sizeof(idt_entry) * IDT_MAX_DESCRIPTORS) - 1;
|
||||||
|
idtr.base = (uint32_t)&idt;
|
||||||
|
|
||||||
|
for (int i = 0; i < IDT_MAX_DESCRIPTORS; i++) {
|
||||||
|
if (isr_stub_table[i] != 0) {
|
||||||
|
set_idtr(i, isr_stub_table[i], SEGMENT_KERN, ATTR_KERN_32);
|
||||||
|
} else {
|
||||||
|
set_idtr(i, 0, SEGMENT_KERN, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_idtr(0x80, syscall_handler, SEGMENT_KERN, ATTR_USER_32);
|
||||||
|
|
||||||
|
load_idt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void common_interrupt_handler(registers *args) {
|
||||||
switch (args->int_no) {
|
switch (args->int_no) {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
|
|||||||
6
kernel/interrupts.h
Normal file
6
kernel/interrupts.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef KIDT_H
|
||||||
|
#define KIDT_H
|
||||||
|
|
||||||
|
void init_idt();
|
||||||
|
|
||||||
|
#endif
|
||||||
134
kernel/kmain.c
134
kernel/kmain.c
@@ -1,150 +1,62 @@
|
|||||||
#include "multiboot.h"
|
#include "multiboot.h"
|
||||||
#include "idt.h"
|
#include "interrupts.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
#include "gdt.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
|
||||||
#include <lib/print.h>
|
#include <lib/print.h>
|
||||||
#include <lib/stream.h>
|
#include <lib/stream.h>
|
||||||
#include <lib/memory.h>
|
#include <lib/memory.h>
|
||||||
|
|
||||||
#include "memory/mm.h"
|
#include <memory/mm.h>
|
||||||
|
|
||||||
#include "drivers/iso/iso.h"
|
#include <drivers/iso/iso.h>
|
||||||
#include "drivers/ide/ide.h"
|
#include <drivers/ide/ide.h>
|
||||||
|
#include <drivers/pic/pic.h>
|
||||||
|
#include <drivers/ps2/ps2.h>
|
||||||
|
#include <drivers/pit/pit.h>
|
||||||
|
#include <drivers/vga/vga.h>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
extern void init_idt();
|
|
||||||
extern void init_gdt();
|
|
||||||
extern void init_pic();
|
|
||||||
extern void init_pit();
|
|
||||||
extern int init_ps2();
|
|
||||||
extern void enable_interrupts();
|
extern void enable_interrupts();
|
||||||
|
extern void disable_interrupts();
|
||||||
void* page = NULL;
|
extern uint32_t fetch_cr3();
|
||||||
|
|
||||||
extern char __kernel_start;
|
extern char __kernel_start;
|
||||||
extern char __kernel_end;
|
extern char __kernel_end;
|
||||||
|
|
||||||
void* user_page_directories[10];
|
void kernel_test_task() {
|
||||||
|
while (1) {
|
||||||
void load_origin_program(multiboot_info* mbi) {
|
kprintf("task sleeping...\n");
|
||||||
user_page_directories[0] = create_user_pd();
|
sleep(10000000);
|
||||||
kprintf("Created origin process page directory @ [phys] 0x%x\n", user_page_directories[0]);
|
|
||||||
extern void load_pd(void* pd);
|
|
||||||
extern void flush_tlb();
|
|
||||||
load_pd(user_page_directories[0]);
|
|
||||||
flush_tlb();
|
|
||||||
kprintf("switched to user address space\n");
|
|
||||||
|
|
||||||
uint32_t mods_virtual_addr = mbi->mods_addr + 0xC0000000;
|
|
||||||
kprintf("parsing mutliboot modules @ 0x%x\n", mods_virtual_addr);
|
|
||||||
|
|
||||||
if (mbi->mods_count == 0) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
multiboot_module_entry* modules = (multiboot_module_entry*)mods_virtual_addr;
|
|
||||||
|
|
||||||
uint32_t elf_vbase = 0xE0000000;
|
|
||||||
uint32_t elf_pbase = modules[0].mod_start;
|
|
||||||
uint32_t elf_limit = modules[0].mod_end - modules[0].mod_start;
|
|
||||||
uint32_t elf_pages_needed = (elf_limit / 4096) + 1;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < elf_pages_needed; i++) {
|
|
||||||
const uint32_t vaddr = elf_vbase + (i * 4096);
|
|
||||||
const uint32_t paddr = elf_pbase + (i * 4096);
|
|
||||||
map_page(vaddr, paddr, PAGE_PRESENT | PAGE_WRITABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
elf_header_t* elf = (elf_header_t*)elf_vbase;
|
|
||||||
elf_program_header_t* ph = (elf_program_header_t*)(elf_vbase + elf->e_phoff);
|
|
||||||
|
|
||||||
kprintf("elf header @ 0x%x\n", elf);
|
|
||||||
kprintf("program headers @ 0x%x\n", ph);
|
|
||||||
|
|
||||||
// load program sections into physical memory and map the pages
|
|
||||||
for (int i = 0; i < elf->e_phnum; i++) {
|
|
||||||
if (ph[i].p_type == PT_LOAD) {
|
|
||||||
uint32_t v_start = ph[i].p_vaddr & 0xFFFFF000;
|
|
||||||
uint32_t v_end = (ph[i].p_vaddr + ph[i].p_memsz + 4095) & 0xFFFFF000;
|
|
||||||
|
|
||||||
for (uint32_t page = v_start; page < v_end; page += 4096) {
|
|
||||||
uint32_t frame_paddr = (uint32_t)p_alloc_frame();
|
|
||||||
map_page(page, frame_paddr, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t j = 0; j < ph[i].p_memsz; j++) {
|
|
||||||
((char*)ph[i].p_vaddr)[j] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t j = 0; j < ph[i].p_filesz; j++) {
|
|
||||||
((char*)ph[i].p_vaddr)[j] = ((char*)(elf_vbase + ph[i].p_offset))[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocate the user stack
|
|
||||||
uint32_t stack_paddr = (uint32_t)p_alloc_frame();
|
|
||||||
map_page(0xBFFFF000, stack_paddr, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER);
|
|
||||||
|
|
||||||
kprintf("program loaded into memory @ [virt] 0x%x\n", elf->e_entry);
|
|
||||||
|
|
||||||
extern void liftoff(uint32_t entry, uint32_t stack_top);
|
|
||||||
kprintf("launching origin process\n");
|
|
||||||
uint32_t stack_top = 0xBFFFF000 + 4095;
|
|
||||||
liftoff(elf->e_entry, stack_top);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void kmain(uint32_t magic, multiboot_info* mbi) {
|
void kmain(uint32_t magic, multiboot_info* mbi) {
|
||||||
extern print_stream_t vga_print_stream;
|
|
||||||
extern print_stream_t* kout;
|
|
||||||
kout = &vga_print_stream;
|
|
||||||
kout->trunc();
|
|
||||||
|
|
||||||
kprintf("kernel start: 0x%x\n", &__kernel_start);
|
|
||||||
kprintf("kernel end: 0x%x\n", &__kernel_end);
|
|
||||||
uint32_t size = (&__kernel_end - &__kernel_start) / 1024;
|
|
||||||
kprintf("kernel size: %dKB\n", size);
|
|
||||||
|
|
||||||
if (!(mbi->flags & (1 << 6))) {
|
if (!(mbi->flags & (1 << 6))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf("multiboot virtual address: 0x%x\n", mbi);
|
vga_init();
|
||||||
|
|
||||||
kprintf("parsing multiboot memory map\n");
|
|
||||||
uint32_t mmap_virtual_addr = mbi->mmap_addr + 0xC0000000;
|
uint32_t mmap_virtual_addr = mbi->mmap_addr + 0xC0000000;
|
||||||
kprintf("mmap virtual address: 0x%x\n", mmap_virtual_addr);
|
|
||||||
init_pmm((void*)mmap_virtual_addr, mbi->mmap_length);
|
init_pmm((void*)mmap_virtual_addr, mbi->mmap_length);
|
||||||
|
kprintf("memory detection complete. total free memory: %dMB\n", total_free_memory() / 1024 / 1024);
|
||||||
|
|
||||||
kprintf("RockOS booting...\n");
|
|
||||||
init_gdt();
|
init_gdt();
|
||||||
extern uint64_t gdt[5];
|
|
||||||
kprintf("GDT set @ 0x%x\n", &gdt);
|
|
||||||
|
|
||||||
init_idt();
|
init_idt();
|
||||||
extern idt_entry idt[256];
|
|
||||||
kprintf("IDT set @ 0x%x\n", &idt);
|
|
||||||
|
|
||||||
init_pic();
|
init_pic();
|
||||||
kprintf("PIC initialized\n");
|
|
||||||
|
|
||||||
init_pit();
|
init_pit();
|
||||||
kprintf("PIT initialized\n");
|
|
||||||
|
|
||||||
init_page_tables();
|
init_page_tables();
|
||||||
kprintf("Page tables initialized\n");
|
|
||||||
|
|
||||||
kgrow(1);
|
kprintf("basic initializations complete\n");
|
||||||
kprintf("Allocated 4kb for kernel heap\n");
|
|
||||||
|
|
||||||
kprintf("scanning for drives\n");
|
disable_interrupts();
|
||||||
extern void scan_drives();
|
init_scheduler();
|
||||||
scan_drives();
|
enable_interrupts();
|
||||||
|
|
||||||
ide_device_t* boot_cd_rom = get_ide_device(0);
|
while(1) yield();
|
||||||
read_iso(boot_cd_rom);
|
|
||||||
|
|
||||||
while(1);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
#define KHEAP_START 0xE0000000
|
#define KHEAP_START 0xE0000000
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) {
|
typedef struct __attribute__((packed)) {
|
||||||
|
size_t size;
|
||||||
uint8_t free;
|
uint8_t free;
|
||||||
uint32_t next_blk;
|
void* next_blk;
|
||||||
} alloc_header_t;
|
} alloc_header_t;
|
||||||
|
|
||||||
void memcpy(const void* src, void* dst, size_t sz) {
|
void memcpy(const void* src, void* dst, size_t sz) {
|
||||||
@@ -42,18 +43,6 @@ static void* kernel_heap_end = (void*)KHEAP_START;
|
|||||||
alloc_header_t* blk_list = NULL;
|
alloc_header_t* blk_list = NULL;
|
||||||
|
|
||||||
void kgrow(size_t pages) {
|
void kgrow(size_t pages) {
|
||||||
if (kernel_heap_end == kernel_heap_start) {
|
|
||||||
// probaably not great, but if we don't have a heap yet, allocate the first (or only) frame requested.
|
|
||||||
// Then initialize the first block header for the allocator
|
|
||||||
void* frame = p_alloc_frame();
|
|
||||||
map_page((uint32_t)kernel_heap_end, (uint32_t)frame, PAGE_PRESENT | PAGE_WRITABLE);
|
|
||||||
kernel_heap_end = (void*)((uint32_t)kernel_heap_end + PAGE_SIZE);
|
|
||||||
pages--;
|
|
||||||
blk_list = kernel_heap_start;
|
|
||||||
blk_list->free = 1;
|
|
||||||
blk_list->next_blk = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t p = 0; p < pages; p++) {
|
for (size_t p = 0; p < pages; p++) {
|
||||||
void* frame = p_alloc_frame();
|
void* frame = p_alloc_frame();
|
||||||
map_page((uint32_t)kernel_heap_end, (uint32_t)frame, PAGE_PRESENT | PAGE_WRITABLE);
|
map_page((uint32_t)kernel_heap_end, (uint32_t)frame, PAGE_PRESENT | PAGE_WRITABLE);
|
||||||
@@ -61,34 +50,60 @@ void kgrow(size_t pages) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ALIGNMENT 4
|
||||||
|
#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
|
||||||
void* kalloc(size_t sz) {
|
void* kalloc(size_t sz) {
|
||||||
if (sz == 0) {
|
sz = ALIGN(sz);
|
||||||
return NULL;
|
|
||||||
|
if (kernel_heap_end == kernel_heap_start) {
|
||||||
|
// probaably not great, but if we don't have a heap yet, allocate the first (or only) frame requested.
|
||||||
|
// Then initialize the first block header for the allocator
|
||||||
|
kgrow(4);
|
||||||
|
|
||||||
|
blk_list = (alloc_header_t*)kernel_heap_start;
|
||||||
|
blk_list->size = ((uint32_t)kernel_heap_end - (uint32_t)kernel_heap_start) - sizeof(alloc_header_t);
|
||||||
|
blk_list->free = 1;
|
||||||
|
blk_list->next_blk = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc_header_t* header = blk_list;
|
alloc_header_t* curr = blk_list;
|
||||||
while (!header->free) {
|
alloc_header_t* prev = NULL;
|
||||||
if (header->next_blk == 0) {
|
|
||||||
return NULL;
|
while (curr != NULL) {
|
||||||
}
|
if (curr->free && curr->size >= sz) {
|
||||||
header = (alloc_header_t*)header->next_blk;
|
if (curr->size >= sz + sizeof(alloc_header_t) + ALIGNMENT) {
|
||||||
|
alloc_header_t* new_blk = (alloc_header_t*)((uint32_t)curr + sizeof(alloc_header_t) + sz);
|
||||||
|
|
||||||
|
new_blk->size = curr->size - sz - sizeof(alloc_header_t);
|
||||||
|
new_blk->free = 1;
|
||||||
|
new_blk->next_blk = curr->next_blk;
|
||||||
|
|
||||||
|
curr->size = sz;
|
||||||
|
curr->next_blk = new_blk;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t data_ptr = (uint32_t)header + sizeof(alloc_header_t);
|
curr->free = 0;
|
||||||
if (data_ptr >= (uint32_t)kernel_heap_end) {
|
return (void*)((uint32_t)curr + sizeof(alloc_header_t));
|
||||||
return NULL;
|
}
|
||||||
} // if the start of the data is already at the end, we don't have room
|
prev = curr;
|
||||||
|
curr = curr->next_blk;
|
||||||
uint32_t end_of_blk = data_ptr + sz;
|
}
|
||||||
if (end_of_blk > (uint32_t)kernel_heap_end) {
|
|
||||||
return NULL;
|
// no more space, grow!!
|
||||||
} // if the end of the data is past the end, we don't have room
|
size_t required_space = sz + sizeof(alloc_header_t);
|
||||||
|
size_t pages_to_grow = (required_space + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||||
if (end_of_blk != header->next_blk && end_of_blk < ((uint32_t)kernel_heap_end - sizeof(alloc_header_t))) {
|
|
||||||
header->next_blk = end_of_blk;
|
alloc_header_t* new_heap_blk = (alloc_header_t*)kernel_heap_end;
|
||||||
alloc_header_t* next_header = (alloc_header_t*)header->next_blk;
|
|
||||||
next_header->f
|
kgrow(pages_to_grow);
|
||||||
} // see if we have room to place the next header and at least 1 byte of data
|
|
||||||
|
new_heap_blk->size = (pages_to_grow * PAGE_SIZE) - sizeof(alloc_header_t);
|
||||||
return (void*)data_ptr;
|
new_heap_blk->free = 1;
|
||||||
|
new_heap_blk->next_blk = NULL;
|
||||||
|
|
||||||
|
if (prev != NULL) {
|
||||||
|
prev->next_blk = new_heap_blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kalloc(sz);
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ int strcmp(const char *s1, const char *s2);
|
|||||||
int strlen(const char* str);
|
int strlen(const char* str);
|
||||||
|
|
||||||
void kgrow(size_t pages);
|
void kgrow(size_t pages);
|
||||||
void* alloc(size_t sz);
|
void* kalloc(size_t sz);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,20 +1,25 @@
|
|||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
#include "tasks.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
extern print_stream_t* kout;
|
#include <drivers/vga/vga.h>
|
||||||
|
|
||||||
|
spinlock_t kwrite_lock = {0};
|
||||||
|
|
||||||
static char* hex_chars = "0123456789abcdef";
|
static char* hex_chars = "0123456789abcdef";
|
||||||
|
|
||||||
static void kprint(const char *str) {
|
static void kprint(const char *str) {
|
||||||
while (*str) {
|
while (*str) {
|
||||||
kout->putchar(*str);
|
vga_putchar(*str);
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kputd(int d) {
|
static void kputd(int d) {
|
||||||
if (d == 0) {
|
if (d == 0) {
|
||||||
kout->putchar('0');
|
vga_putchar('0');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char buffer[12];
|
char buffer[12];
|
||||||
@@ -24,13 +29,13 @@ static void kputd(int d) {
|
|||||||
d /= 10;
|
d /= 10;
|
||||||
}
|
}
|
||||||
for (int j = i - 1; j >= 0; j--) {
|
for (int j = i - 1; j >= 0; j--) {
|
||||||
kout->putchar(buffer[j]);
|
vga_putchar(buffer[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kputx(unsigned int x) {
|
static void kputx(unsigned int x) {
|
||||||
if (x == 0) {
|
if (x == 0) {
|
||||||
kout->putchar('0');
|
vga_putchar('0');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
char buffer[8];
|
char buffer[8];
|
||||||
@@ -41,15 +46,18 @@ static void kputx(unsigned int x) {
|
|||||||
x >>= 4;
|
x >>= 4;
|
||||||
}
|
}
|
||||||
for (int j = i - 1; j >= 0; j--) {
|
for (int j = i - 1; j >= 0; j--) {
|
||||||
kout->putchar(buffer[j]);
|
vga_putchar(buffer[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void kputc(const char c) {
|
void kputc(const char c) {
|
||||||
kout->putchar(c);
|
spin_lock(&kwrite_lock);
|
||||||
|
vga_putchar(c);
|
||||||
|
spin_unlock(&kwrite_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kprintf(const char* fmt, ...) {
|
void kprintf(const char* fmt, ...) {
|
||||||
|
spin_lock(&kwrite_lock);
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
|
|
||||||
@@ -73,19 +81,20 @@ void kprintf(const char* fmt, ...) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case '%':
|
case '%':
|
||||||
kout->putchar('%');
|
vga_putchar('%');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
kout->putchar('%');
|
vga_putchar('%');
|
||||||
kout->putchar(*fmt);
|
vga_putchar(*fmt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fmt++;
|
fmt++;
|
||||||
} else {
|
} else {
|
||||||
kout->putchar(*fmt);
|
vga_putchar(*fmt);
|
||||||
fmt++;
|
fmt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
spin_unlock(&kwrite_lock);
|
||||||
}
|
}
|
||||||
11
kernel/lib/tasks.c
Normal file
11
kernel/lib/tasks.c
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include <lib/tasks.h>
|
||||||
|
|
||||||
|
void spin_lock(spinlock_t *lock) {
|
||||||
|
while (__sync_lock_test_and_set(&lock->locked, 1)) {
|
||||||
|
asm volatile("pause");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void spin_unlock(spinlock_t *lock) {
|
||||||
|
__sync_lock_release(&lock->locked);
|
||||||
|
}
|
||||||
13
kernel/lib/tasks.h
Normal file
13
kernel/lib/tasks.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef KTASKS_H
|
||||||
|
#define KTASKS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
volatile uint32_t locked;
|
||||||
|
} spinlock_t;
|
||||||
|
|
||||||
|
void spin_lock(spinlock_t *lock);
|
||||||
|
void spin_unlock(spinlock_t *lock);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -18,7 +18,7 @@ extern void disable_pae();
|
|||||||
#define PAGE_TABLES 0xFFC00000
|
#define PAGE_TABLES 0xFFC00000
|
||||||
#define PAGE_DIRECTORY 0xFFFFF000
|
#define PAGE_DIRECTORY 0xFFFFF000
|
||||||
|
|
||||||
#define TEMP_MAPPING_VADDR 0xE0000000
|
#define TEMP_MAPPING_VADDR 0xDFFF0000
|
||||||
|
|
||||||
static uint32_t max_address = 0;
|
static uint32_t max_address = 0;
|
||||||
static uint32_t total_available_memory = 0;
|
static uint32_t total_available_memory = 0;
|
||||||
@@ -141,8 +141,6 @@ void init_pmm(void* mmap_base, uint32_t mmap_limit) {
|
|||||||
if (mmap_base != NULL && mmap_limit > 0) {
|
if (mmap_base != NULL && mmap_limit > 0) {
|
||||||
parse_multiboot_mmap(mmap_base, mmap_limit);
|
parse_multiboot_mmap(mmap_base, mmap_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf("total free memory: %dMB\n", total_available_memory / 1024 / 1024);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_page_tables() {
|
void init_page_tables() {
|
||||||
@@ -165,7 +163,7 @@ uint32_t total_free_memory() {
|
|||||||
return total_available_memory;
|
return total_available_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* create_user_pd() {
|
void* create_task_pd() {
|
||||||
uint32_t pd_address = (uint32_t)p_alloc_frame();
|
uint32_t pd_address = (uint32_t)p_alloc_frame();
|
||||||
if (pd_address == 0) {
|
if (pd_address == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -173,18 +171,18 @@ void* create_user_pd() {
|
|||||||
|
|
||||||
map_page(TEMP_MAPPING_VADDR, pd_address, PAGE_PRESENT | PAGE_WRITABLE);
|
map_page(TEMP_MAPPING_VADDR, pd_address, PAGE_PRESENT | PAGE_WRITABLE);
|
||||||
|
|
||||||
uint32_t* user_pd = (uint32_t*)TEMP_MAPPING_VADDR;
|
uint32_t* task_pd = (uint32_t*)TEMP_MAPPING_VADDR;
|
||||||
uint32_t* kernel_pd = (uint32_t*)PAGE_DIRECTORY;
|
uint32_t* kernel_pd = (uint32_t*)PAGE_DIRECTORY;
|
||||||
|
|
||||||
for(int i = 0; i < 768; i++) {
|
for(int i = 0; i < 768; i++) {
|
||||||
user_pd[i] = 0;
|
task_pd[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 768; i < 1023; i++) {
|
for(int i = 768; i < 1023; i++) {
|
||||||
user_pd[i] = kernel_pd[i];
|
task_pd[i] = kernel_pd[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
user_pd[1023] = (uint32_t)pd_address | PAGE_PRESENT | PAGE_WRITABLE;
|
task_pd[1023] = (uint32_t)pd_address | PAGE_PRESENT | PAGE_WRITABLE;
|
||||||
|
|
||||||
uint32_t pde = TEMP_MAPPING_VADDR >> 22;
|
uint32_t pde = TEMP_MAPPING_VADDR >> 22;
|
||||||
uint32_t pte = (TEMP_MAPPING_VADDR >> 12) & 0x3FF;
|
uint32_t pte = (TEMP_MAPPING_VADDR >> 12) & 0x3FF;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ void* p_alloc_frame();
|
|||||||
|
|
||||||
uint32_t total_free_memory();
|
uint32_t total_free_memory();
|
||||||
|
|
||||||
void* create_user_pd();
|
void* create_task_pd();
|
||||||
|
|
||||||
void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags);
|
void map_page(uint32_t vaddr, uint32_t paddr, uint32_t flags);
|
||||||
|
|
||||||
|
|||||||
20
kernel/process.h
Normal file
20
kernel/process.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef KPROCESS_H
|
||||||
|
#define KPROCESS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
STATE_READY,
|
||||||
|
STATE_SLEEPING,
|
||||||
|
STATE_DEAD
|
||||||
|
} process_state_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t pid;
|
||||||
|
uint32_t esp;
|
||||||
|
uint32_t cr3;
|
||||||
|
process_state_t state;
|
||||||
|
uint32_t sleep;
|
||||||
|
} __attribute__((packed)) process_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
12
kernel/scheduler.S
Normal file
12
kernel/scheduler.S
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.code32
|
||||||
|
.extern schedule_next_task
|
||||||
|
.global yield
|
||||||
|
yield:
|
||||||
|
cli
|
||||||
|
pushal
|
||||||
|
push %esp
|
||||||
|
call schedule_next_task
|
||||||
|
movl %eax, %esp
|
||||||
|
popal
|
||||||
|
sti
|
||||||
|
ret
|
||||||
136
kernel/scheduler.c
Normal file
136
kernel/scheduler.c
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
#include <lib/tasks.h>
|
||||||
|
#include <lib/memory.h>
|
||||||
|
|
||||||
|
#include <memory/mm.h>
|
||||||
|
|
||||||
|
#include <stddef.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);
|
||||||
|
process_table[current_process].esp = current_esp;
|
||||||
|
|
||||||
|
for (int i = 0; i < total_processes; i++) {
|
||||||
|
if (process_table[i].state == STATE_SLEEPING) {
|
||||||
|
if (process_table[i].sleep > 0) {
|
||||||
|
process_table[i].sleep--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process_table[i].sleep == 0) {
|
||||||
|
process_table[i].state = STATE_READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
found_ready = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_process == current_process) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_ready) {
|
||||||
|
if (process_table[current_process].state == STATE_READY) {
|
||||||
|
next_process = current_process;
|
||||||
|
} else {
|
||||||
|
next_process = IDLE_TASK_PID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current_process = next_process;
|
||||||
|
|
||||||
|
if (fetch_cr3() != process_table[current_process].cr3) {
|
||||||
|
extern void load_pd(uint32_t table);
|
||||||
|
load_pd(process_table[current_process].cr3);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rtn = process_table[current_process].esp;
|
||||||
|
spin_unlock(&process_table_lock);
|
||||||
|
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_scheduler() {
|
||||||
|
process_table = kalloc(16 * sizeof(process_t));
|
||||||
|
total_processes = 0;
|
||||||
|
|
||||||
|
process_t* process = &process_table[total_processes];
|
||||||
|
process->pid = total_processes;
|
||||||
|
process->esp = 0;
|
||||||
|
process->cr3 = fetch_cr3();
|
||||||
|
process->state = STATE_READY;
|
||||||
|
process->sleep = 0;
|
||||||
|
total_processes++;
|
||||||
|
|
||||||
|
create_task((uint32_t)idle_task, fetch_cr3());
|
||||||
|
|
||||||
|
current_process = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_task(uint32_t entry_point, uint32_t cr3) {
|
||||||
|
if (total_processes >= 16) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock(&process_table_lock);
|
||||||
|
process_t* process = &process_table[total_processes];
|
||||||
|
process->pid = total_processes;
|
||||||
|
process->cr3 = cr3;
|
||||||
|
process->state = STATE_READY;
|
||||||
|
process->sleep = 0;
|
||||||
|
|
||||||
|
void* stack_bottom = kalloc(4096);
|
||||||
|
uint32_t* esp = (uint32_t*)((uint32_t)stack_bottom + 4096);
|
||||||
|
|
||||||
|
*(--esp) = 0x0202; // EFLAGS
|
||||||
|
*(--esp) = 0x08; // CS
|
||||||
|
*(--esp) = entry_point; // EIP
|
||||||
|
|
||||||
|
*(--esp) = 0; // EAX
|
||||||
|
*(--esp) = 0; // ECX
|
||||||
|
*(--esp) = 0; // EDX
|
||||||
|
*(--esp) = 0; // EBX
|
||||||
|
*(--esp) = 0; // ESP
|
||||||
|
*(--esp) = 0; // EBP
|
||||||
|
*(--esp) = 0; // ESI
|
||||||
|
*(--esp) = 0; // EDI
|
||||||
|
|
||||||
|
process->esp = (uint32_t)esp;
|
||||||
|
spin_unlock(&process_table_lock);
|
||||||
|
|
||||||
|
total_processes++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sleep(uint32_t ticks) {
|
||||||
|
if (ticks == 0) return;
|
||||||
|
|
||||||
|
spin_lock(&process_table_lock);
|
||||||
|
process_table[current_process].sleep = ticks;
|
||||||
|
process_table[current_process].state = STATE_SLEEPING;
|
||||||
|
spin_unlock(&process_table_lock);
|
||||||
|
|
||||||
|
yield();
|
||||||
|
}
|
||||||
13
kernel/scheduler.h
Normal file
13
kernel/scheduler.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef KSCHEDULER_H
|
||||||
|
#define KSCHEDULER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void init_scheduler();
|
||||||
|
|
||||||
|
int create_task(uint32_t entry_point, uint32_t cr3);
|
||||||
|
|
||||||
|
void sleep(uint32_t ticks);
|
||||||
|
void yield();
|
||||||
|
|
||||||
|
#endif
|
||||||
6
kernel/syscall.h
Normal file
6
kernel/syscall.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef KSYSCALL_H
|
||||||
|
#define KSYSCALL_H
|
||||||
|
|
||||||
|
void syscall_handler();
|
||||||
|
|
||||||
|
#endif
|
||||||
7
makefile
7
makefile
@@ -6,8 +6,7 @@ OSNAME := rockos
|
|||||||
C_SOURCES := $(shell find kernel -type f -name '*.c')
|
C_SOURCES := $(shell find kernel -type f -name '*.c')
|
||||||
S_SOURCES := $(shell find kernel -type f -name '*.S')
|
S_SOURCES := $(shell find kernel -type f -name '*.S')
|
||||||
|
|
||||||
# This correctly generates paths like obj/kernel/main.o
|
OBJECTS := $(patsubst %, obj/%.o, $(C_SOURCES) $(S_SOURCES))
|
||||||
OBJECTS := $(patsubst %.c, obj/%.o, $(C_SOURCES)) $(patsubst %.S, obj/%.o, $(S_SOURCES))
|
|
||||||
|
|
||||||
CFLAGS := -ffreestanding -O2 -Wall -Wextra -Ikernel
|
CFLAGS := -ffreestanding -O2 -Wall -Wextra -Ikernel
|
||||||
LDFLAGS := -T kernel/linker.ld
|
LDFLAGS := -T kernel/linker.ld
|
||||||
@@ -25,11 +24,11 @@ $(OSNAME).iso: $(OSNAME).bin grub.cfg
|
|||||||
cp grub.cfg isodir/boot/grub/grub.cfg
|
cp grub.cfg isodir/boot/grub/grub.cfg
|
||||||
grub-mkrescue -o $(OSNAME).iso isodir
|
grub-mkrescue -o $(OSNAME).iso isodir
|
||||||
|
|
||||||
obj/kernel/%.o: kernel/%.c
|
obj/%.c.o: %.c
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CC) -c $< -o $@ $(CFLAGS)
|
$(CC) -c $< -o $@ $(CFLAGS)
|
||||||
|
|
||||||
obj/kernel/%.o: kernel/%.S
|
obj/%.S.o: %.S
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
$(CC) -c $< -o $@ $(CFLAGS)
|
$(CC) -c $< -o $@ $(CFLAGS)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user