Compare commits
13 Commits
memory
...
7f997f6611
| Author | SHA1 | Date | |
|---|---|---|---|
|
7f997f6611
|
|||
|
7bb542d901
|
|||
|
4a90de9521
|
|||
|
c46157fad0
|
|||
| 6e633b44b7 | |||
|
b8a155fada
|
|||
|
091f94f89e
|
|||
|
b469952d91
|
|||
|
9cbecc1689
|
|||
|
12ab12f1b2
|
|||
|
0f72987bc1
|
|||
|
d9dfd4c749
|
|||
| be1be41a64 |
6
Makefile
6
Makefile
@@ -1,8 +1,10 @@
|
||||
SOURCES = src/mem/heap/kheap.c src/mem/paging/vmm.c src/mem/paging/paging.c src/mem/paging/pmm.c src/string/string.c src/io/kbd/ps2.c src/io/serial/serial.c src/io/term/printf.c src/io/term/term.c src/idt/idt.c src/mem/gdt/gdt.c src/mem/misc/utils.c src/time/timer.c src/kmain.c
|
||||
SOURCES = src/sched/scheduler.c src/sched/process.c src/mem/heap/kheap.c src/mem/paging/vmm.c src/mem/paging/paging.c src/mem/paging/pmm.c src/string/string.c src/io/kbd/ps2.c src/io/serial/serial.c src/io/term/printf.c src/io/term/term.c src/idt/idt.c src/mem/gdt/gdt.c src/mem/misc/utils.c src/time/timer.c src/kmain.c
|
||||
|
||||
PROBLEMATIC_FLAGS=-Wno-unused-parameter -Wno-unused-variable
|
||||
|
||||
build:
|
||||
rm -f *.o
|
||||
x86_64-elf-gcc -g -c -Isrc $(SOURCES) -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel
|
||||
x86_64-elf-gcc -g -c -Isrc $(SOURCES) $(PROBLEMATIC_FLAGS) -Wall -Wextra -std=gnu99 -nostdlib -ffreestanding -fno-stack-protector -fno-omit-frame-pointer -fno-stack-check -fno-PIC -ffunction-sections -fdata-sections -mcmodel=kernel
|
||||
objcopy -O elf64-x86-64 -B i386 -I binary zap-light16.psf zap-light16.o
|
||||
nasm -f elf64 src/idt/idt.S -o idt_stub.o
|
||||
x86_64-elf-ld -o pepperk -T linker.ld *.o
|
||||
|
||||
20
README.md
20
README.md
@@ -11,18 +11,28 @@ To run it with QEMU, `make run`
|
||||
|
||||
The basics that I'm targeting are:
|
||||
|
||||
### Basic utility of what we call a "kernel"
|
||||
|
||||
- Fix terminal driver (backspace issues, scrolling) OR add Flanterm or equivalent
|
||||
- Implement paging / see what Limine does at boot with memory management
|
||||
- Implement tasks, and task switching
|
||||
- Load an executable
|
||||
- Scheduler (round-robin using the PIT timer interrupt)
|
||||
- Filesystem (TAR for read-only initfs, then maybe read-write using FAT12/16/32
|
||||
- Filesystem (TAR for read-only initfs, then maybe read-write using FAT12/16/32 or easier fs) w/ VFS layer
|
||||
- Getting to userspace (syscalls)
|
||||
- Porting musl libc or equivalent
|
||||
|
||||
In the future, maybe?
|
||||
### Scalability/maintenance/expansion features
|
||||
|
||||
- SMP support
|
||||
- Global config header file
|
||||
- Documentation
|
||||
- SOME error handling in functions
|
||||
- Unit tests
|
||||
- Good error codes (like Linux kernel: ENOMEM, ENOENT, ...)
|
||||
- Make the panic function work within itself without dependencies + error message (and still get cpu context?)
|
||||
|
||||
### Optional features
|
||||
|
||||
In the future, maybe?
|
||||
- SMP support (Limine provides functionality to make this easier)
|
||||
- Parsing the ACPI tables and using them for something
|
||||
- Replacing the PIT timer with APIC
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "io/serial/serial.h"
|
||||
#include "io/kbd/ps2.h"
|
||||
#include <kernel.h>
|
||||
#include <stdbool.h>
|
||||
#include "sched/scheduler.h"
|
||||
|
||||
struct interrupt_descriptor idt[256];
|
||||
struct idtr idt_reg;
|
||||
@@ -53,6 +55,64 @@ void idt_init()
|
||||
DEBUG("IDT initialized");
|
||||
}
|
||||
|
||||
static inline uint64_t read_cr2(void)
|
||||
{
|
||||
uint64_t val;
|
||||
asm volatile ("mov %%cr2, %0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static void page_fault_handler(struct cpu_status_t* ctx)
|
||||
{
|
||||
// It could be used to remap pages etc. to fix the fault, but right now what I'm more
|
||||
// interested in is getting more info out of those numbers cause i'm lost each time i have
|
||||
// to read all this mess
|
||||
uint64_t cr2 = read_cr2();
|
||||
|
||||
DEBUG("\x1b[38;5;231mPage Fault at rip=0x%p, err=%u (%s%s%s%s%s%s%s%s) when accessing addr=0x%p\x1b[0m", ctx->iret_rip, ctx->error_code,
|
||||
CHECK_BIT(ctx->error_code, 0) ? "PAGE_PROTECTION_VIOLATION " : "PAGE_NOT_PRESENT ",
|
||||
CHECK_BIT(ctx->error_code, 1) ? "ON_WRITE " : "ON_READ ",
|
||||
CHECK_BIT(ctx->error_code, 2) ? "IN_USER_MODE" : "IN_KERNEL_MODE",
|
||||
CHECK_BIT(ctx->error_code, 3) ? " WAS_RESERVED" : "",
|
||||
CHECK_BIT(ctx->error_code, 4) ? " ON_INSTRUCTION_FETCH" : "",
|
||||
CHECK_BIT(ctx->error_code, 5) ? " PK_VIOLATION" : "",
|
||||
CHECK_BIT(ctx->error_code, 6) ? " ON_SHADOWSTACK_ACCESS" : "",
|
||||
CHECK_BIT(ctx->error_code, 7) ? " SGX_VIOLATION" : "",
|
||||
cr2);
|
||||
|
||||
/* if (CHECK_BIT(ctx->error_code, 0))
|
||||
{
|
||||
panic(ctx);
|
||||
} */
|
||||
panic(ctx);
|
||||
}
|
||||
|
||||
static void gp_fault_handler(struct cpu_status_t* ctx)
|
||||
{
|
||||
DEBUG("\x1b[38;5;231mGeneral Protection Fault at rip=0x%p, err=%u (%s)\x1b[0m",
|
||||
ctx->iret_rip,
|
||||
ctx->error_code,
|
||||
(ctx->error_code == 0) ? "NOT_SEGMENT_RELATED" : "SEGMENT_RELATED");
|
||||
|
||||
// Segment-related
|
||||
if (ctx->error_code != 0)
|
||||
{
|
||||
bool is_external = CHECK_BIT(ctx->error_code, 0);
|
||||
// is it IDT, GDT, LDT?
|
||||
uint8_t table = ctx->error_code & 0x6; // 0b110 (isolate table)
|
||||
uint16_t index = ctx->error_code & 0xFFF8; // 13*1 1111111111111 + 000 = 1111111111111000
|
||||
|
||||
char* table_names[4] = {"GDT", "IDT", "LDT", "IDT"};
|
||||
|
||||
DEBUG("\x1b[38;5;231m%s in %s index %u\x1b[0m",
|
||||
is_external ? "EXTERNAL" : "INTERNAL",
|
||||
table_names[table],
|
||||
index);
|
||||
}
|
||||
|
||||
panic(ctx);
|
||||
}
|
||||
|
||||
struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
||||
{
|
||||
switch(context->vector_number)
|
||||
@@ -97,10 +157,11 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
||||
DEBUG("Stack-Segment Fault!");
|
||||
break;
|
||||
case 13:
|
||||
DEBUG("General Protection Fault!");
|
||||
gp_fault_handler(context);
|
||||
break;
|
||||
case 14:
|
||||
DEBUG("Page Fault!");
|
||||
// Better debugging for page faults...
|
||||
page_fault_handler(context);
|
||||
break;
|
||||
case 15:
|
||||
DEBUG("Intel Reserved Interrupt! (Achievement unlocked: How Did We Get Here?)");
|
||||
@@ -125,13 +186,22 @@ struct cpu_status_t* interrupt_dispatch(struct cpu_status_t* context)
|
||||
break;
|
||||
|
||||
case 32:
|
||||
//DEBUG("Tick!");
|
||||
//DEBUG("Timer Interrupt");
|
||||
ticks++;
|
||||
|
||||
if (ticks % SCHEDULER_QUANTUM == 0)
|
||||
{
|
||||
CLEAR_INTERRUPTS;
|
||||
scheduler_schedule();
|
||||
SET_INTERRUPTS;
|
||||
}
|
||||
|
||||
// Send an EOI so that we can continue having interrupts
|
||||
outb(0x20, 0x20);
|
||||
break;
|
||||
|
||||
case 33:
|
||||
DEBUG("Keyboard Interrupt");
|
||||
keyboard_handler();
|
||||
break;
|
||||
|
||||
|
||||
@@ -201,12 +201,11 @@ void keyboard_handler()
|
||||
|
||||
if (c)
|
||||
{
|
||||
// Should probably have a keyboard buffer here... instead of this
|
||||
putchar(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skputs("key pressed!\n");
|
||||
}
|
||||
|
||||
// End of Interrupt (to master PIC)
|
||||
@@ -233,5 +232,11 @@ void keyboard_init(unsigned char layout)
|
||||
skputs("Unsupported layout.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Unmask IRQ1
|
||||
uint8_t mask = inb(0x21);
|
||||
mask &= ~(1 << 1);
|
||||
outb(0x21, mask);
|
||||
|
||||
DEBUG("PS/2 Keyboard initialized");
|
||||
}
|
||||
@@ -9,8 +9,9 @@ because this shitty implementation will be replaced one day by Flanterm
|
||||
#include <stddef.h>
|
||||
#include <kernel.h>
|
||||
#include "term.h"
|
||||
#include "mem/misc/utils.h"
|
||||
|
||||
extern struct limine_framebuffer* framebuffer;
|
||||
extern struct boot_context boot_ctx;
|
||||
|
||||
// Importing the PSF object file
|
||||
extern unsigned char _binary_zap_light16_psf_start[];
|
||||
@@ -22,61 +23,88 @@ uint8_t* glyphs = _binary_zap_light16_psf_start + sizeof(PSF1_Header);
|
||||
#define FONT_WIDTH 8
|
||||
#define FONT_HEIGHT font->characterSize
|
||||
|
||||
|
||||
|
||||
// Character cursor
|
||||
typedef struct
|
||||
{
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
size_t x;
|
||||
size_t y;
|
||||
} Cursor;
|
||||
|
||||
Cursor cursor = {0};
|
||||
static Cursor cursor = {0, 0};
|
||||
|
||||
unsigned char* fb;
|
||||
static uint8_t* fb;
|
||||
static struct limine_framebuffer* framebuffer;
|
||||
|
||||
uint8_t lines_length[MAX_LINES];
|
||||
|
||||
static inline size_t term_max_cols(void)
|
||||
{
|
||||
return framebuffer->width / FONT_WIDTH;
|
||||
}
|
||||
|
||||
static inline size_t term_max_lines(void)
|
||||
{
|
||||
return framebuffer->height / FONT_HEIGHT;
|
||||
}
|
||||
|
||||
int term_init()
|
||||
{
|
||||
// Get framebuffer address from Limine struct
|
||||
|
||||
if (framebuffer)
|
||||
if (!boot_ctx.fb)
|
||||
{
|
||||
fb = framebuffer->address;
|
||||
DEBUG("terminal initialized");
|
||||
return 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
return -ENOMEM;
|
||||
|
||||
framebuffer = boot_ctx.fb;
|
||||
fb = (uint8_t*)framebuffer->address;
|
||||
|
||||
memset(lines_length, 0, sizeof(lines_length));
|
||||
|
||||
DEBUG("terminal initialized, fb=0x%p (width=%u height=%u pitch=%u bpp=%u)", fb, framebuffer->width, framebuffer->height, framebuffer->pitch, framebuffer->bpp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// These are marked "static" because we don't wanna expose them all around
|
||||
// AKA they should just be seen here (kind of like private functions in cpp)
|
||||
static void putpixel(int x, int y, int color)
|
||||
static inline void putpixel(size_t x, size_t y, uint32_t color)
|
||||
{
|
||||
// Guard so we don't write past fb boundaries
|
||||
if (x >= framebuffer->width || y >= framebuffer->height) return;
|
||||
// Depth isn't part of limine_framebuffer attributes so it will be 4
|
||||
unsigned pos = x*4 + y*framebuffer->pitch;
|
||||
size_t pos = x*4 + y*framebuffer->pitch;
|
||||
fb[pos] = color & 255; // blue channel
|
||||
fb[pos+1] = (color >> 8) & 255; // green
|
||||
fb[pos+2] = (color >> 16) & 255; // blue
|
||||
}
|
||||
|
||||
static void draw_char(char c, int px, int py, int fg, int bg)
|
||||
static void draw_char(char c, size_t px, size_t py, uint32_t fg, uint32_t bg)
|
||||
{
|
||||
// So we cannot write past fb
|
||||
if (px+FONT_WIDTH > framebuffer->width || py+FONT_HEIGHT > framebuffer->height) return;
|
||||
|
||||
uint8_t* glyph = glyphs + ((unsigned char)c * FONT_HEIGHT);
|
||||
|
||||
for (size_t y=0; y<FONT_HEIGHT; y++)
|
||||
{
|
||||
uint8_t row = glyph[y];
|
||||
for (size_t x=0; x<8; x++)
|
||||
for (size_t x=0; x<FONT_WIDTH; x++)
|
||||
{
|
||||
int color = (row & (0x80 >> x)) ? fg : bg;
|
||||
uint32_t color = (row & (0x80 >> x)) ? fg : bg;
|
||||
putpixel(px+x, py+y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void erase_char(int px, int py)
|
||||
static void erase_char(size_t px, size_t py)
|
||||
{
|
||||
if (px+FONT_WIDTH > framebuffer->width || py+FONT_HEIGHT > framebuffer->height) return;
|
||||
|
||||
for (size_t y=0; y<FONT_HEIGHT; y++)
|
||||
{
|
||||
for (size_t x=0; x<8; x++)
|
||||
for (size_t x=0; x<FONT_WIDTH; x++)
|
||||
{
|
||||
// Black
|
||||
putpixel(px+x, py+y, 0);
|
||||
@@ -84,50 +112,81 @@ static void erase_char(int px, int py)
|
||||
}
|
||||
}
|
||||
|
||||
void term_scroll()
|
||||
{
|
||||
// Erase first text line
|
||||
memset(fb, 255, FONT_HEIGHT*framebuffer->pitch);
|
||||
|
||||
// Move whole framebuffer up by one text line
|
||||
memmove(fb, fb+(FONT_HEIGHT*framebuffer->pitch), (framebuffer->height-FONT_HEIGHT)*framebuffer->pitch);
|
||||
|
||||
// Clear last text line
|
||||
size_t clear_start = (framebuffer->height - FONT_HEIGHT) * framebuffer->pitch;
|
||||
memset(fb + clear_start, 255, FONT_HEIGHT * framebuffer->pitch);
|
||||
|
||||
// Shift line lengths by 1 (for backspace handling)
|
||||
size_t max_lines = term_max_lines();
|
||||
for (size_t i = 1; i < max_lines; i++)
|
||||
{
|
||||
lines_length[i - 1] = lines_length[i];
|
||||
}
|
||||
lines_length[max_lines - 1] = 0;
|
||||
}
|
||||
|
||||
void putchar(char c)
|
||||
{
|
||||
if (c == '\n')
|
||||
{
|
||||
const size_t max_cols = term_max_cols();
|
||||
const size_t max_lines = term_max_lines();
|
||||
|
||||
if (c == '\n') {
|
||||
lines_length[cursor.y] = cursor.x;
|
||||
cursor.x = 0;
|
||||
cursor.y++;
|
||||
|
||||
if (cursor.y + 1 >= max_lines)
|
||||
{
|
||||
term_scroll();
|
||||
}
|
||||
else
|
||||
{
|
||||
cursor.y++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Improperly handled.
|
||||
// When we're on an empty line it should get to the upper line's last character
|
||||
// NOT just the last position possible; we would need to track the last line's character amount for that
|
||||
if (c == '\b')
|
||||
{
|
||||
if (cursor.x == 0 && cursor.y == 0)
|
||||
if (cursor.x > 0)
|
||||
{
|
||||
cursor.x--;
|
||||
}
|
||||
else if (cursor.y > 0)
|
||||
{
|
||||
cursor.y--;
|
||||
cursor.x = lines_length[cursor.y];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Top-left corner
|
||||
return;
|
||||
}
|
||||
|
||||
if (cursor.x == 0)
|
||||
{
|
||||
cursor.y--;
|
||||
cursor.x = (framebuffer->width / FONT_WIDTH) -1; // here
|
||||
}
|
||||
else {
|
||||
cursor.x--;
|
||||
}
|
||||
|
||||
int px = cursor.x * FONT_WIDTH;
|
||||
int py = cursor.y * FONT_HEIGHT;
|
||||
erase_char(px, py);
|
||||
erase_char(cursor.x * FONT_WIDTH, cursor.y * FONT_HEIGHT);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((cursor.x+1)*FONT_WIDTH >= framebuffer->width)
|
||||
if (cursor.x >= max_cols)
|
||||
{
|
||||
cursor.x = 0;
|
||||
cursor.y++;
|
||||
if (cursor.y + 1 >= max_lines)
|
||||
{
|
||||
term_scroll();
|
||||
}
|
||||
else
|
||||
{
|
||||
cursor.y++;
|
||||
}
|
||||
}
|
||||
|
||||
int px = cursor.x * FONT_WIDTH;
|
||||
int py = cursor.y * FONT_HEIGHT;
|
||||
draw_char(c, px, py, WHITE, BLACK);
|
||||
draw_char(c, cursor.x * FONT_WIDTH, cursor.y * FONT_HEIGHT, WHITE, BLACK);
|
||||
cursor.x++;
|
||||
}
|
||||
|
||||
@@ -140,7 +199,7 @@ void _putchar(char character)
|
||||
// Debug-printing
|
||||
void kputs(const char* str)
|
||||
{
|
||||
unsigned int i=0;
|
||||
size_t i=0;
|
||||
while (str[i] != 0)
|
||||
{
|
||||
putchar(str[i]);
|
||||
|
||||
@@ -11,6 +11,8 @@ enum TermColors
|
||||
WHITE = 0xffffff
|
||||
};
|
||||
|
||||
#define MAX_LINES 256
|
||||
|
||||
#define PSF1_FONT_MAGIC 0x0436
|
||||
|
||||
typedef struct
|
||||
@@ -20,4 +22,7 @@ typedef struct
|
||||
uint8_t characterSize; // height
|
||||
} PSF1_Header;
|
||||
|
||||
// debug
|
||||
void term_scroll();
|
||||
|
||||
#endif
|
||||
|
||||
19
src/kernel.h
19
src/kernel.h
@@ -1,6 +1,10 @@
|
||||
#ifndef KERNEL_H
|
||||
#define KERNEL_H
|
||||
|
||||
#define PEPPEROS_VERSION_MAJOR "0"
|
||||
#define PEPPEROS_VERSION_MINOR "0"
|
||||
#define PEPPEROS_VERSION_PATCH "1"
|
||||
|
||||
enum ErrorCodes
|
||||
{
|
||||
ENOMEM,
|
||||
@@ -12,12 +16,27 @@ enum ErrorCodes
|
||||
|
||||
#include "io/serial/serial.h"
|
||||
#include "io/term/printf.h"
|
||||
#include "idt/idt.h"
|
||||
|
||||
#define DEBUG(log, ...) fctprintf((void*)&skputc, 0, "debug: [%s]: " log "\r\n", __FILE__, ##__VA_ARGS__)
|
||||
|
||||
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
|
||||
|
||||
// printf("debug: [%s]: " log "\n", __FILE__, ##__VA_ARGS__);
|
||||
|
||||
void panic(struct cpu_status_t* ctx);
|
||||
void hcf();
|
||||
#define assert(check) do { if(!(check)) hcf(); } while(0)
|
||||
|
||||
struct boot_context
|
||||
{
|
||||
struct limine_framebuffer* fb;
|
||||
struct limine_memmap_response* mmap;
|
||||
struct limine_hhdm_response* hhdm;
|
||||
struct limine_kernel_address_response* kaddr;
|
||||
};
|
||||
|
||||
// 1 tick = 1 ms => quantum = 10ms
|
||||
#define SCHEDULER_QUANTUM 10
|
||||
|
||||
#endif
|
||||
|
||||
86
src/kmain.c
86
src/kmain.c
@@ -14,6 +14,8 @@
|
||||
#include "mem/paging/paging.h"
|
||||
#include "mem/paging/vmm.h"
|
||||
#include "mem/heap/kheap.h"
|
||||
#include "sched/process.h"
|
||||
#include "sched/scheduler.h"
|
||||
|
||||
// Limine version used
|
||||
__attribute__((used, section(".limine_requests")))
|
||||
@@ -53,67 +55,91 @@ static volatile LIMINE_REQUESTS_START_MARKER;
|
||||
__attribute__((used, section(".limine_requests_end")))
|
||||
static volatile LIMINE_REQUESTS_END_MARKER;
|
||||
|
||||
struct limine_framebuffer* framebuffer;
|
||||
|
||||
// Panic (should dump registers etc. in the future)
|
||||
void hcf()
|
||||
{
|
||||
//CLEAR_INTERRUPTS;
|
||||
for (;;)
|
||||
{
|
||||
asm("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
void panic(struct cpu_status_t* ctx)
|
||||
{
|
||||
DEBUG("\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[0m at rip=%p\nSomething went horribly wrong! vect=0x%.2x errcode=0x%x\n\rrax=%p rbx=%p rcx=%p rdx=%p\n\rrsi=%p rdi=%p r8=%p r9=%p\n\rr10=%p r11=%p r12=%p r13=%p\n\rr14=%p r15=%p\n\n\rflags=%p\n\rstack at rbp=%p\n\rHalting...",
|
||||
ctx->iret_rip,
|
||||
ctx->vector_number, ctx->error_code, ctx->rax, ctx->rbx, ctx->rcx, ctx->rdx, ctx->rsi, ctx->rdi,
|
||||
ctx->r8, ctx->r9, ctx->r10, ctx->r11, ctx->r12, ctx->r13, ctx->r14, ctx->r15, ctx->iret_flags,
|
||||
ctx->rbp);
|
||||
hcf();
|
||||
}
|
||||
|
||||
const char* splash = "pepperOS version "PEPPEROS_VERSION_MAJOR"."PEPPEROS_VERSION_MINOR"."PEPPEROS_VERSION_PATCH"\n";
|
||||
|
||||
struct boot_context boot_ctx;
|
||||
|
||||
extern struct process_t* processes_list;
|
||||
extern struct process_t* current_process;
|
||||
|
||||
void pedicel_main(void* arg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void two_main(void* arg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void three_main(void* arg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// This is our entry point
|
||||
void kmain()
|
||||
{
|
||||
if (!LIMINE_BASE_REVISION_SUPPORTED) hcf();
|
||||
if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) hcf();
|
||||
|
||||
// We should probably grab all the boot info in a boot context struct
|
||||
// that would be a bit cleaner than this mess
|
||||
|
||||
// Get the first framebuffer from the response
|
||||
framebuffer = framebuffer_request.response->framebuffers[0];
|
||||
// Populate boot context
|
||||
boot_ctx.fb = framebuffer_request.response ? framebuffer_request.response->framebuffers[0] : NULL;
|
||||
boot_ctx.mmap = memmap_request.response ? memmap_request.response : NULL;
|
||||
boot_ctx.hhdm = hhdm_request.response ? hhdm_request.response : NULL;
|
||||
boot_ctx.kaddr = kerneladdr_request.response ? kerneladdr_request.response : NULL;
|
||||
|
||||
serial_init();
|
||||
|
||||
if (memmap_request.response == NULL) hcf();
|
||||
memmap_display(memmap_request.response);
|
||||
|
||||
if (hhdm_request.response == NULL) hcf();
|
||||
hhdm_display(hhdm_request.response);
|
||||
|
||||
if (kerneladdr_request.response == NULL) hcf();
|
||||
DEBUG("kernel: phys_base=0x%p virt_base=0x%p", kerneladdr_request.response->physical_base, kerneladdr_request.response->virtual_base);
|
||||
memmap_display(boot_ctx.mmap);
|
||||
hhdm_display(boot_ctx.hhdm);
|
||||
DEBUG("kernel: phys_base=0x%p virt_base=0x%p", boot_ctx.kaddr->physical_base, boot_ctx.kaddr->virtual_base);
|
||||
|
||||
CLEAR_INTERRUPTS;
|
||||
gdt_init();
|
||||
idt_init();
|
||||
timer_init();
|
||||
SET_INTERRUPTS;
|
||||
|
||||
pmm_init(memmap_request.response, hhdm_request.response);
|
||||
pmm_init(boot_ctx.mmap, boot_ctx.hhdm);
|
||||
|
||||
// Remap kernel , HHDM and framebuffer
|
||||
paging_init(kerneladdr_request.response, framebuffer);
|
||||
paging_init(boot_ctx.kaddr, boot_ctx.fb);
|
||||
|
||||
kheap_init();
|
||||
|
||||
void* ptr = kmalloc(10); DEBUG("(KMALLOC TEST) Allocated 10 bytes at 0x%p", ptr);
|
||||
void* ptr2 = kmalloc(200); DEBUG("(KMALLOC TEST) Allocated 200 bytes at 0x%p", ptr2);
|
||||
kfree(ptr);
|
||||
void* ptr3 = kmalloc(5); DEBUG("(KMALLOC TEST) Allocated 5 bytes at 0x%p", ptr3);
|
||||
|
||||
vmm_init();
|
||||
|
||||
keyboard_init(FR);
|
||||
struct process_t* pedicel = process_create("pedicel", (void*)pedicel_main, 0);
|
||||
struct process_t* two = process_create("two", (void*)two_main, 0);
|
||||
struct process_t* three = process_create("three", (void*)three_main, 0);
|
||||
process_display_list(processes_list);
|
||||
|
||||
scheduler_init();
|
||||
|
||||
SET_INTERRUPTS;
|
||||
|
||||
keyboard_init(FR);
|
||||
term_init();
|
||||
// Draw something
|
||||
printf("%s, %s!\n", "Hello", "world");
|
||||
// Yoohoooooo!
|
||||
//DEBUG("kernel initialized successfully! hanging... wow=%d", 42);
|
||||
printf("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non justo a magna bibendum auctor viverra rutrum diam. In hac habitasse platea dictumst. Vestibulum suscipit ipsum eget tortor maximus lobortis. Donec vel ipsum id lacus fringilla bibendum id eget risus. Fusce vestibulum diam sit amet nunc ultricies, nec rutrum nibh congue. Donec fringilla a dui sit amet ullamcorper. Donec pharetra quis tortor id congue. Aliquam erat volutpat. Duis suscipit nulla vel ligula iaculis, in gravida mauris pellentesque. Vestibulum nunc nisl, posuere eu eros et, dictum molestie dolor. Donec posuere laoreet hendrerit. Suspendisse potenti. Proin fringilla vehicula malesuada. Quisque a dui est. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur nec aliquam lacus, at lacinia enim. ");
|
||||
kputs(splash);
|
||||
|
||||
hcf();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "mem/paging/pmm.h"
|
||||
#include <stddef.h>
|
||||
#include <kernel.h>
|
||||
#include "sched/process.h"
|
||||
|
||||
extern uint64_t kernel_phys_base;
|
||||
extern uint64_t kernel_virt_base;
|
||||
@@ -15,12 +16,24 @@ static uintptr_t end;
|
||||
// Kernel root table (level 4)
|
||||
extern uint64_t *kernel_pml4;
|
||||
|
||||
static void kheap_map_page()
|
||||
static void kheap_grow(size_t size)
|
||||
{
|
||||
size_t pages = ALIGN_UP(size + sizeof(struct heap_block_t), PAGE_SIZE) / PAGE_SIZE;
|
||||
|
||||
if (pages == 0) pages = 1;
|
||||
|
||||
for (size_t i = 0; i < pages; i++)
|
||||
{
|
||||
kheap_map_page();
|
||||
}
|
||||
}
|
||||
|
||||
void kheap_map_page()
|
||||
{
|
||||
uintptr_t phys = pmm_alloc();
|
||||
paging_map_page(kernel_pml4, end, phys, PTE_PRESENT | PTE_WRITABLE | PTE_NOEXEC);
|
||||
end += PAGE_SIZE;
|
||||
DEBUG("Mapped first kheap page");
|
||||
//DEBUG("Mapped first kheap page");
|
||||
}
|
||||
|
||||
void kheap_init()
|
||||
@@ -43,6 +56,7 @@ void* kmalloc(size_t size)
|
||||
{
|
||||
// No size, no memory allocated!
|
||||
if (!size) return NULL;
|
||||
size = ALIGN(size);
|
||||
|
||||
struct heap_block_t* curr = head;
|
||||
|
||||
@@ -52,17 +66,16 @@ void* kmalloc(size_t size)
|
||||
if (curr->free && curr->size >= size)
|
||||
{
|
||||
// We split the block if it is big enough
|
||||
if (curr->size > size + sizeof(struct heap_block_t))
|
||||
if (curr->size >= size + BLOCK_MIN_SIZE)
|
||||
{
|
||||
struct heap_block_t* new_block = (struct heap_block_t*)((uintptr_t)curr + sizeof(struct heap_block_t) + size);
|
||||
// We have to subtract the size of our block struct
|
||||
new_block->size = curr->size - size - sizeof(struct heap_block_t);
|
||||
new_block->free = true;
|
||||
//struct heap_block_t* new_block = (struct heap_block_t*)((uintptr_t)curr + sizeof(struct heap_block_t) + size);
|
||||
struct heap_block_t* split = (struct heap_block_t*)((uintptr_t)curr + sizeof(*curr) + size);
|
||||
|
||||
// Then we chain up the block in the list
|
||||
new_block->next = curr->next;
|
||||
curr->next = new_block;
|
||||
split->size = curr->size - size - sizeof(*curr);
|
||||
split->free = true;
|
||||
split->next = curr->next;
|
||||
|
||||
curr->next = split;
|
||||
curr->size = size;
|
||||
}
|
||||
|
||||
@@ -74,14 +87,14 @@ void* kmalloc(size_t size)
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
// If we're hear it means we didn't have enough memory
|
||||
// If we're here it means we didn't have enough memory
|
||||
// for the block allocation. So we will allocate more..
|
||||
uintptr_t old_end = end;
|
||||
kheap_map_page();
|
||||
kheap_grow(size + sizeof(struct heap_block_t));
|
||||
|
||||
struct heap_block_t* block = (struct heap_block_t*)old_end;
|
||||
block->size = PAGE_SIZE - sizeof(struct heap_block_t);
|
||||
block->free = false;
|
||||
block->size = ALIGN_UP(end - old_end - sizeof(struct heap_block_t), 16);
|
||||
block->free = true;
|
||||
block->next = NULL;
|
||||
|
||||
// Put the block at the end of the list
|
||||
@@ -92,7 +105,7 @@ void* kmalloc(size_t size)
|
||||
}
|
||||
curr->next = block;
|
||||
|
||||
return (void*)((uintptr_t)block + sizeof(struct heap_block_t));
|
||||
return kmalloc(size);
|
||||
}
|
||||
|
||||
void kfree(void* ptr)
|
||||
@@ -103,4 +116,25 @@ void kfree(void* ptr)
|
||||
// Set it free!
|
||||
struct heap_block_t* block = (struct heap_block_t*)((uintptr_t)ptr - sizeof(struct heap_block_t));
|
||||
block->free = true;
|
||||
|
||||
// merge adjacent free blocks (coalescing)
|
||||
struct heap_block_t* curr = head;
|
||||
while (curr && curr->next)
|
||||
{
|
||||
if (curr->free && curr->next->free)
|
||||
{
|
||||
curr->size += sizeof(*curr) + curr->next->size;
|
||||
curr->next = curr->next->next;
|
||||
continue;
|
||||
}
|
||||
curr = curr->next;
|
||||
}
|
||||
}
|
||||
|
||||
// Should alloc enough for a stack (at least 64kb) to be used for a process.
|
||||
// Should return a pointer to top of the stack (as stack grows DOWNWARDS)
|
||||
void* kalloc_stack()
|
||||
{
|
||||
uint8_t* ptr = kmalloc(PROCESS_STACK_SIZE);
|
||||
return ptr ? ptr+PROCESS_STACK_SIZE : NULL;
|
||||
}
|
||||
@@ -22,5 +22,7 @@ struct heap_block_t
|
||||
void kheap_init();
|
||||
void* kmalloc(size_t size);
|
||||
void kfree(void* ptr);
|
||||
void* kalloc_stack();
|
||||
void kheap_map_page();
|
||||
|
||||
#endif
|
||||
@@ -69,7 +69,7 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_
|
||||
root_table[pml4_i] = VIRT_TO_PHYS(pdpt) | PTE_PRESENT | PTE_WRITABLE;
|
||||
}
|
||||
else {
|
||||
pdpt = (uint64_t *)PHYS_TO_VIRT(root_table[pml4_i] & ~0xFFFULL);
|
||||
pdpt = (uint64_t *)PHYS_TO_VIRT(root_table[pml4_i] & PTE_ADDR_MASK);
|
||||
}
|
||||
|
||||
// PDPT: same here
|
||||
@@ -79,7 +79,7 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_
|
||||
pdpt[pdpt_i] = VIRT_TO_PHYS(pd) | PTE_PRESENT | PTE_WRITABLE;
|
||||
}
|
||||
else {
|
||||
pd = (uint64_t *)PHYS_TO_VIRT(pdpt[pdpt_i] & ~0xFFFULL);
|
||||
pd = (uint64_t *)PHYS_TO_VIRT(pdpt[pdpt_i] & PTE_ADDR_MASK);
|
||||
}
|
||||
|
||||
// PD: and here
|
||||
@@ -89,7 +89,7 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_
|
||||
pd[pd_i] = VIRT_TO_PHYS(pt) | PTE_PRESENT | PTE_WRITABLE;
|
||||
}
|
||||
else {
|
||||
pt = (uint64_t *)PHYS_TO_VIRT(pd[pd_i] & ~0xFFFULL);
|
||||
pt = (uint64_t *)PHYS_TO_VIRT(pd[pd_i] & PTE_ADDR_MASK);
|
||||
}
|
||||
|
||||
// PT: finally, populate the page table entry
|
||||
@@ -102,13 +102,16 @@ void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_
|
||||
uint64_t kernel_phys_base;
|
||||
uint64_t kernel_virt_base;
|
||||
|
||||
void paging_init(struct limine_kernel_address_response* kaddr, struct limine_framebuffer* fb)
|
||||
extern struct boot_context boot_ctx;
|
||||
|
||||
void paging_init()
|
||||
{
|
||||
// We should map the kernel, GDT, IDT, stack, framebuffer.
|
||||
// Optionally we could map ACPI tables (we can find them in the Limine memmap)
|
||||
|
||||
kernel_phys_base = kaddr->physical_base;
|
||||
kernel_virt_base = kaddr->virtual_base;
|
||||
kernel_phys_base = boot_ctx.kaddr->physical_base;
|
||||
kernel_virt_base = boot_ctx.kaddr->virtual_base;
|
||||
struct limine_framebuffer* fb = boot_ctx.fb;
|
||||
|
||||
DEBUG("Kernel lives at virt=0x%p phys=0x%p", kernel_virt_base, kernel_phys_base);
|
||||
|
||||
@@ -117,14 +120,38 @@ void paging_init(struct limine_kernel_address_response* kaddr, struct limine_fra
|
||||
// for debug
|
||||
uint64_t page_count = 0;
|
||||
|
||||
// HHDM map first 1 GB using given offset
|
||||
for (uint64_t i=0; i<0x40000000; i += PAGE_SIZE)
|
||||
// Find max physical address from limine memmap
|
||||
uint64_t max_phys = 0;
|
||||
for (uint64_t i=0; i<boot_ctx.mmap->entry_count; i++)
|
||||
{
|
||||
struct limine_memmap_entry* entry = boot_ctx.mmap->entries[i];
|
||||
if (entry->length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
uint64_t top = entry->base + entry->length;
|
||||
if (top > max_phys)
|
||||
{
|
||||
max_phys = top;
|
||||
}
|
||||
//DEBUG("max_phys=0x%p", max_phys);
|
||||
}
|
||||
|
||||
// 4GB
|
||||
if (max_phys > 0x100000000)
|
||||
{
|
||||
DEBUG("WARNING: max_phys capped to 4GB (0x100000000) (from max_phys=%p)", max_phys);
|
||||
max_phys = 0x100000000;
|
||||
}
|
||||
|
||||
// HHDM map up to max_phys or 4GB, whichever is smaller, using given offset
|
||||
for (uint64_t i=0; i<max_phys; i += PAGE_SIZE)
|
||||
{
|
||||
//paging_kmap_page(i+hhdm_off, i, PTE_WRITABLE);
|
||||
paging_map_page(kernel_pml4, i+hhdm_off, i, PTE_WRITABLE);
|
||||
paging_map_page(kernel_pml4, i+hhdm_off, i, PTE_WRITABLE | PTE_PRESENT);
|
||||
page_count++;
|
||||
}
|
||||
DEBUG("Mapped %u pages for first 1GB (HHDM)", page_count); page_count = 0;
|
||||
DEBUG("Mapped %u pages up to 0x%p (HHDM)", page_count, max_phys); page_count = 0;
|
||||
|
||||
// Map the kernel (according to virt/phys_base given by Limine)
|
||||
// SOME DAY when we want a safer kernel we should map .text as Read/Exec
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limine.h>
|
||||
#include "mem/heap/kheap.h"
|
||||
|
||||
void paging_init(struct limine_kernel_address_response* kaddr, struct limine_framebuffer* fb);
|
||||
void paging_init();
|
||||
void paging_map_page(uint64_t* root_table, uint64_t virt, uint64_t phys, uint64_t flags);
|
||||
|
||||
extern uint64_t hhdm_off;
|
||||
@@ -15,10 +16,14 @@ extern uint64_t hhdm_off;
|
||||
#define PHYS_TO_VIRT(x) ((void*)((uintptr_t)(x) + hhdm_off))
|
||||
#define VIRT_TO_PHYS(x) ((uintptr_t)(x) - hhdm_off)
|
||||
|
||||
#define PTE_ADDR_MASK 0x000FFFFFFFFFF000
|
||||
// Stole it
|
||||
#define ALIGN_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
|
||||
#define ALIGN_DOWN(x, align) ((x) & ~((align) - 1))
|
||||
#define PAGE_ALIGN_DOWN(x) ((x) & ~0xFFFULL)
|
||||
#define PAGE_ALIGN_DOWN(x) ((x) & PTE_ADDR_MASK)
|
||||
|
||||
#define ALIGN(size) ALIGN_UP(size, 16)
|
||||
#define BLOCK_MIN_SIZE (sizeof(struct heap_block_t) + 16)
|
||||
|
||||
#define PML4_INDEX(x) (((x) >> 39) & 0x1FF)
|
||||
#define PDPT_INDEX(x) (((x) >> 30) & 0x1FF)
|
||||
|
||||
@@ -49,7 +49,7 @@ void vmm_setup_pt_root()
|
||||
DEBUG("VMM setup: vmm_pt_root=0x%p (phys=0x%p)", vmm_pt_root, phys);
|
||||
}
|
||||
|
||||
void* vmm_alloc(size_t length, size_t flags)
|
||||
/* void* vmm_alloc(size_t length, size_t flags)
|
||||
{
|
||||
// We will try to allocate at least length bytes, which have to be rounded UP to
|
||||
// the next page so its coherent with the PMM
|
||||
@@ -58,7 +58,7 @@ void* vmm_alloc(size_t length, size_t flags)
|
||||
// Need to implement this (as linked list)
|
||||
// but for now kernel heap is sufficient
|
||||
// The VMM will prob be more useful when we have userspace
|
||||
}
|
||||
} */
|
||||
|
||||
void vmm_init()
|
||||
{
|
||||
|
||||
122
src/sched/process.c
Normal file
122
src/sched/process.c
Normal file
@@ -0,0 +1,122 @@
|
||||
#include <stddef.h>
|
||||
#include "process.h"
|
||||
#include "mem/heap/kheap.h"
|
||||
#include "kernel.h"
|
||||
#include "string/string.h"
|
||||
#include "mem/gdt/gdt.h"
|
||||
|
||||
struct process_t* processes_list;
|
||||
struct process_t* current_process;
|
||||
|
||||
size_t next_free_pid = 0;
|
||||
|
||||
void process_init()
|
||||
{
|
||||
processes_list = NULL;
|
||||
current_process = NULL;
|
||||
}
|
||||
|
||||
// Only for debug
|
||||
void process_display_list(struct process_t* processes_list)
|
||||
{
|
||||
int process_view_id = 0;
|
||||
struct process_t* tmp = processes_list;
|
||||
while (tmp != NULL)
|
||||
{
|
||||
DEBUG("{%d: %p} -> ", process_view_id, tmp);
|
||||
tmp = tmp->next;
|
||||
process_view_id++;
|
||||
}
|
||||
DEBUG("NULL");
|
||||
}
|
||||
|
||||
struct process_t* process_create(char* name, void(*function)(void*), void* arg)
|
||||
{
|
||||
CLEAR_INTERRUPTS;
|
||||
struct process_t* proc = (struct process_t*)kmalloc(sizeof(struct process_t));
|
||||
|
||||
struct cpu_status_t* ctx = (struct cpu_status_t*)kmalloc(sizeof(struct cpu_status_t));
|
||||
|
||||
// No more memory?
|
||||
if (!proc) return NULL;
|
||||
if (!ctx) return NULL;
|
||||
|
||||
strncpy(proc->name, name, PROCESS_NAME_MAX);
|
||||
proc->pid = next_free_pid++;
|
||||
proc->status = READY;
|
||||
|
||||
proc->context = ctx;
|
||||
proc->context->iret_ss = KERNEL_DATA_SEGMENT; // process will live in kernel mode
|
||||
proc->context->iret_rsp = (uint64_t)kalloc_stack();
|
||||
proc->context->iret_flags = 0x202; //bit 2 and 9 set (Interrupt Flag)
|
||||
proc->context->iret_cs = KERNEL_CODE_SEGMENT;
|
||||
proc->context->iret_rip = (uint64_t)function; // beginning of executable code
|
||||
proc->context->rdi = (uint64_t)arg; // 1st arg is in rdi (as per x64 calling convention)
|
||||
proc->context->rbp = 0;
|
||||
|
||||
proc->next = 0;
|
||||
|
||||
process_add(&processes_list, proc);
|
||||
|
||||
SET_INTERRUPTS;
|
||||
return proc;
|
||||
}
|
||||
|
||||
void process_add(struct process_t** processes_list, struct process_t* process)
|
||||
{
|
||||
if (!process) return;
|
||||
process->next = NULL;
|
||||
|
||||
if (*processes_list == NULL)
|
||||
{
|
||||
// List is empty
|
||||
*processes_list = process;
|
||||
return;
|
||||
}
|
||||
|
||||
struct process_t* tmp = *processes_list;
|
||||
while (tmp->next != NULL)
|
||||
{
|
||||
tmp = tmp->next;
|
||||
}
|
||||
// We're at last process before NULL
|
||||
tmp->next = process;
|
||||
// process->next = NULL;
|
||||
}
|
||||
|
||||
void process_delete(struct process_t** processes_list, struct process_t* process)
|
||||
{
|
||||
if (!processes_list || !*processes_list || !process) return;
|
||||
|
||||
if (*processes_list == process)
|
||||
{
|
||||
// process to delete is at head
|
||||
*processes_list = process->next;
|
||||
process->next = NULL;
|
||||
kfree(process);
|
||||
return;
|
||||
}
|
||||
|
||||
struct process_t* tmp = *processes_list;
|
||||
while (tmp->next && tmp->next != process)
|
||||
{
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if (tmp->next == NULL)
|
||||
{
|
||||
// Didn't find the process
|
||||
return;
|
||||
}
|
||||
|
||||
// We're at process before the one we want to delete
|
||||
tmp->next = process->next;
|
||||
process->next = NULL;
|
||||
kfree(process);
|
||||
}
|
||||
|
||||
struct process_t* process_get_next(struct process_t* process)
|
||||
{
|
||||
if (!process) return NULL;
|
||||
return process->next;
|
||||
}
|
||||
34
src/sched/process.h
Normal file
34
src/sched/process.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef PROCESS_H
|
||||
#define PROCESS_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
READY,
|
||||
RUNNING,
|
||||
DEAD
|
||||
} status_t;
|
||||
|
||||
#define PROCESS_NAME_MAX 64
|
||||
#define PROCESS_STACK_SIZE 0x10000 // 64kb
|
||||
|
||||
struct process_t
|
||||
{
|
||||
size_t pid;
|
||||
char name[PROCESS_NAME_MAX];
|
||||
|
||||
status_t status;
|
||||
struct cpu_status_t* context;
|
||||
struct process_t* next;
|
||||
};
|
||||
|
||||
void process_init();
|
||||
struct process_t* process_create(char* name, void(*function)(void*), void* arg);
|
||||
void process_add(struct process_t** processes_list, struct process_t* process);
|
||||
void process_delete(struct process_t** processes_list, struct process_t* process);
|
||||
struct process_t* process_get_next(struct process_t* process);
|
||||
|
||||
void process_display_list(struct process_t* processes_list);
|
||||
|
||||
#endif
|
||||
40
src/sched/scheduler.c
Normal file
40
src/sched/scheduler.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "kernel.h"
|
||||
#include "process.h"
|
||||
|
||||
extern struct process_t* processes_list;
|
||||
extern struct process_t* current_process;
|
||||
|
||||
void scheduler_init()
|
||||
{
|
||||
// Choose first process?
|
||||
current_process = processes_list;
|
||||
}
|
||||
|
||||
struct cpu_status_t* scheduler_schedule(struct cpu_status_t* context)
|
||||
{
|
||||
current_process->context = context;
|
||||
current_process->status = READY;
|
||||
|
||||
for (;;) {
|
||||
struct process_t* prev_process = current_process;
|
||||
if (current_process->next != NULL)
|
||||
{
|
||||
current_process = current_process->next;
|
||||
} else
|
||||
{
|
||||
current_process = processes_list;
|
||||
}
|
||||
|
||||
if (current_process != NULL && current_process->status == DEAD)
|
||||
{
|
||||
process_delete(&prev_process, current_process);
|
||||
} else
|
||||
{
|
||||
current_process->status = RUNNING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG("SCHEDULER CALLED: current_process=%p", current_process);
|
||||
return current_process->context;
|
||||
}
|
||||
7
src/sched/scheduler.h
Normal file
7
src/sched/scheduler.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef SCHEDULER_H
|
||||
#define SCHEDULER_H
|
||||
|
||||
void scheduler_schedule();
|
||||
void scheduler_init();
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,26 @@
|
||||
#include <stddef.h>
|
||||
|
||||
char* strcpy(char *dest, const char *src)
|
||||
{
|
||||
char *temp = dest;
|
||||
while((*dest++ = *src++));
|
||||
return temp;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/2488563/strcat-implementation
|
||||
char *strcat(char *dest, const char *src){
|
||||
size_t i,j;
|
||||
for (i = 0; dest[i] != '\0'; i++)
|
||||
;
|
||||
for (j = 0; src[j] != '\0'; j++)
|
||||
dest[i+j] = src[j];
|
||||
dest[i+j] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/14159625/implementation-of-strncpy
|
||||
void strncpy(char* dst, const char* src, size_t n)
|
||||
{
|
||||
size_t i = 0;
|
||||
while(i++ != n && (*dst++ = *src++));
|
||||
}
|
||||
@@ -2,5 +2,7 @@
|
||||
#define STRING_H
|
||||
|
||||
char *strcpy(char *dest, const char *src);
|
||||
char *strcat(char *dest, const char *src);
|
||||
void strncpy(char* dst, const char* src, size_t n);
|
||||
|
||||
#endif
|
||||
@@ -44,7 +44,7 @@ void pic_enable()
|
||||
// Enabling IRQ0 (unmasking it) but not the others
|
||||
uint8_t mask = inb(0x21);
|
||||
mask &= ~(1 << 0); // Set IRQ0 (timer, clear bit 0)
|
||||
mask &= ~(1 << 1); // Set IRQ1 (PS/2 Keyboard, clear bit 1)
|
||||
//mask &= ~(1 << 1); // Set IRQ1 (PS/2 Keyboard, clear bit 1)
|
||||
outb(0x21, mask);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,17 @@ void pit_init()
|
||||
outb(0x40, (divisor >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
// Wait n ticks
|
||||
// Given that there's a tick every 1ms, wait n milliseconds
|
||||
void timer_wait(uint64_t wait_ticks)
|
||||
{
|
||||
uint64_t then = ticks + wait_ticks;
|
||||
while (ticks < then)
|
||||
{
|
||||
asm("hlt");
|
||||
};
|
||||
}
|
||||
|
||||
void timer_init()
|
||||
{
|
||||
// Remapping the PIC, because at startup it conflicts with
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
#define TIMER_H
|
||||
|
||||
void timer_init();
|
||||
void timer_wait(unsigned int wait_ticks);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user