feat: introduced tasking, added paging (no vm), moved malloc, added
syscalls, other stuff
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(new_kernel C ASM)
|
||||
#set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(CMAKE_C_FLAGS "-I/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include -g -ffreestanding -Wall -Wextra -fno-exceptions -fno-stack-protector -nostdinc -nostdlib -fno-pie -m32")
|
||||
set(CMAKE_C_FLAGS "-I/usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/include -mno-sse -g -ffreestanding -Wall -Wextra -fno-exceptions -fno-stack-protector -nostdinc -nostdlib -fno-pie -m32")
|
||||
#set(CMAKE_ASM_NASM_OBJECT_FORMAT "elf")
|
||||
set(CMAKE_ASM_FLAGS --32)
|
||||
#set(CMAKE_ASM-ATT_FLAGS --32)
|
||||
|
||||
@@ -92,6 +92,11 @@ _start:
|
||||
*/
|
||||
cli
|
||||
lgdt (gdtr)
|
||||
movw $0x10,%ax # kernel data segment descriptor
|
||||
movw %ax,%ds
|
||||
movw %ax,%es
|
||||
movw %ax,%fs
|
||||
movw %ax,%gs
|
||||
ljmp $0x8, $continue_boot
|
||||
|
||||
continue_boot:
|
||||
|
||||
16
kernel/attributes.h
Normal file
16
kernel/attributes.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by rick on 24-02-21.
|
||||
//
|
||||
|
||||
#ifndef NEW_KERNEL_ATTRIBUTES_H
|
||||
#define NEW_KERNEL_ATTRIBUTES_H
|
||||
|
||||
// function
|
||||
#define noreturn __attribute((noreturn))
|
||||
#define cdecl __attribute((cdecl))
|
||||
// structure
|
||||
#define packed __attribute((packed))
|
||||
// field
|
||||
#define at_aligned(size) __attribute((aligned(size)))
|
||||
|
||||
#endif //NEW_KERNEL_ATTRIBUTES_H
|
||||
144
kernel/command.c
Normal file
144
kernel/command.c
Normal file
@@ -0,0 +1,144 @@
|
||||
//
|
||||
// Created by rick on 23-02-21.
|
||||
//
|
||||
|
||||
#include "command.h"
|
||||
#include "kprint.h"
|
||||
#include "libk.h"
|
||||
#include <types.h>
|
||||
#include <libc/kprintf.h>
|
||||
#include <stdbool.h>
|
||||
#include <libc/string.h>
|
||||
#include <mem/mem.h>
|
||||
#include <mem/malloc.h>
|
||||
#include <cpu/timer.h>
|
||||
#include <drivers/pci.h>
|
||||
#include <drivers/ide.h>
|
||||
#include <fs/blockdev.h>
|
||||
#include <fs/mbr.h>
|
||||
#include <libc/readline.h>
|
||||
#include <libc/libc.h>
|
||||
#include <attributes.h>
|
||||
|
||||
#define BOOTLOADER_NAME_MAX_LENGTH 64
|
||||
#define CMDLINE_MAX_LENGTH 256
|
||||
|
||||
char bootloader_name[BOOTLOADER_NAME_MAX_LENGTH];
|
||||
char cmdline[CMDLINE_MAX_LENGTH];
|
||||
|
||||
typedef void (*cmd_handler_func)(const char *);
|
||||
|
||||
typedef struct {
|
||||
char *cmd;
|
||||
cmd_handler_func handler;
|
||||
} cmd_handler;
|
||||
|
||||
void print(const char *arg);
|
||||
|
||||
void ide(const char *arg);
|
||||
|
||||
void echo(const char *arg);
|
||||
|
||||
void help(const char *arg);
|
||||
|
||||
cmd_handler cmd_handlers[] = {
|
||||
{"help", help},
|
||||
{"echo", echo},
|
||||
{"print", print},
|
||||
{"ide", ide},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
void print_bootinfo() {
|
||||
printf("Bootloader name: %s\n"
|
||||
"cmdline: %s\n",
|
||||
(bootloader_name[0] == 0 ? "NULL" : bootloader_name),
|
||||
(cmdline[0] == 0 ? "NULL" : cmdline));
|
||||
}
|
||||
|
||||
|
||||
void help(const char *arg) {
|
||||
kprint("Available commands:\n");
|
||||
int index = 0;
|
||||
while (true) {
|
||||
if (cmd_handlers[index].cmd == NULL) {
|
||||
break;
|
||||
}
|
||||
printf("%s\n", cmd_handlers[index].cmd);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void echo(const char *arg) {
|
||||
printf("%s\n", arg);
|
||||
}
|
||||
|
||||
void print(const char *arg) {
|
||||
if (strcmp(arg, "mmap") == 0) {
|
||||
print_mmap_info();
|
||||
} else if (strcmp(arg, "malloc") == 0) {
|
||||
print_malloc_info();
|
||||
} else if (strcmp(arg, "tick") == 0) {
|
||||
print_current_tick();
|
||||
} else if (strcmp(arg, "bootinfo") == 0) {
|
||||
print_bootinfo();
|
||||
} else if (strcmp(arg, "pci") == 0) {
|
||||
pci_print_info();
|
||||
} else if (strcmp(arg, "ide") == 0) {
|
||||
ide_print_devices();
|
||||
} else {
|
||||
printf("Unknown print %s\n", arg);
|
||||
}
|
||||
}
|
||||
|
||||
void ide(const char *arg) {
|
||||
if (strcmp(arg, "block_devices") == 0) {
|
||||
block_dev_print_info();
|
||||
} else if (strcmp(arg, "ide_devices") == 0) {
|
||||
ide_print_devices();
|
||||
} else if (strcmp(arg, "mbr") == 0) {
|
||||
mbr_read_from_ide(0);
|
||||
} else {
|
||||
printf("Unknown print %s\n", arg);
|
||||
}
|
||||
}
|
||||
|
||||
void store_bootloader_info(multiboot_info_t *multiboot_info) {
|
||||
// get bootloader and cmdline
|
||||
if (multiboot_info->flags & MULTIBOOT_INFO_CMDLINE) {
|
||||
int cmdline_length = strlen((const char *) multiboot_info->cmdline);
|
||||
if (cmdline_length > CMDLINE_MAX_LENGTH) {
|
||||
k_panics("cmdline to long!\n");
|
||||
}
|
||||
memcpy(cmdline, (char *) multiboot_info->cmdline, cmdline_length);
|
||||
}
|
||||
if (multiboot_info->flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) {
|
||||
int bootloader_length = strlen((const char *) multiboot_info->boot_loader_name);
|
||||
if (bootloader_length > BOOTLOADER_NAME_MAX_LENGTH) {
|
||||
k_panics("bootloader name to long!\n");
|
||||
}
|
||||
memcpy(bootloader_name, (char *) multiboot_info->boot_loader_name, bootloader_length);
|
||||
}
|
||||
}
|
||||
|
||||
void noreturn main_loop(void* data) {
|
||||
while (true) {
|
||||
char *msg = readline(NULL);
|
||||
char *args = strchr(msg, ' ') + 1;
|
||||
args[-1] = 0;
|
||||
int test_index = 0;
|
||||
while (true) {
|
||||
if (cmd_handlers[test_index].cmd == 0) {
|
||||
printf("Unknown command: %s\n", msg);
|
||||
break;
|
||||
}
|
||||
if (strcmp(cmd_handlers[test_index].cmd, msg) == 0) {
|
||||
cmd_handlers[test_index].handler(args);
|
||||
break;
|
||||
}
|
||||
test_index++;
|
||||
}
|
||||
free(msg);
|
||||
}
|
||||
}
|
||||
14
kernel/command.h
Normal file
14
kernel/command.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Created by rick on 23-02-21.
|
||||
//
|
||||
|
||||
#ifndef NEW_KERNEL_COMMAND_H
|
||||
#define NEW_KERNEL_COMMAND_H
|
||||
|
||||
#include "multiboot.h"
|
||||
|
||||
void store_bootloader_info(multiboot_info_t *multiboot_info);
|
||||
|
||||
void main_loop(void* data);
|
||||
|
||||
#endif //NEW_KERNEL_COMMAND_H
|
||||
20
kernel/cpu/cpu.h
Normal file
20
kernel/cpu/cpu.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by rick on 22-02-21.
|
||||
//
|
||||
|
||||
#ifndef NEW_KERNEL_CPU_H
|
||||
#define NEW_KERNEL_CPU_H
|
||||
#include <types.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t edi, esi, ebx, ebp, eip;
|
||||
} task_registers_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t ds; // pushed in common handler
|
||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // pusha/popa
|
||||
uint32_t int_no, err_code; // pushed by handlers
|
||||
uint32_t eip, cs, eflags, useresp, ss; // isr/iret
|
||||
} isr_registers_t;
|
||||
|
||||
#endif //NEW_KERNEL_CPU_H
|
||||
@@ -4,3 +4,30 @@
|
||||
|
||||
#include "cpuidx.h"
|
||||
|
||||
#include <types.h>
|
||||
#include <cpuid.h>
|
||||
#include <libc/kprintf.h>
|
||||
|
||||
union cpu_name {
|
||||
uint32_t parts[3];
|
||||
struct {
|
||||
char name[12];
|
||||
char end;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
void cpuidx_print_info() {
|
||||
union cpu_name name;
|
||||
__get_cpuid(0, NULL, &name.parts[0], &name.parts[2], &name.parts[1]);
|
||||
name.end = 0;
|
||||
printf("CPU: %s\n", &name.name);
|
||||
|
||||
cpu_features_ecx features_ecx;
|
||||
cpu_features_edx features_edx;
|
||||
__get_cpuid(1, NULL, NULL, (uint32_t *) &features_ecx, (uint32_t *) &features_edx);
|
||||
|
||||
printf("");
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -5,10 +5,76 @@
|
||||
#ifndef NEW_KERNEL_CPUIDX_H
|
||||
#define NEW_KERNEL_CPUIDX_H
|
||||
|
||||
#include <cpuid.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
enum {
|
||||
typedef struct {
|
||||
bool sse3: 1;
|
||||
bool pclmul: 1;
|
||||
bool dtes64: 1;
|
||||
bool monitor: 1;
|
||||
bool ds_cpl: 1;
|
||||
bool vmx: 1;
|
||||
bool smx: 1;
|
||||
bool est: 1;
|
||||
bool tm2: 1;
|
||||
bool ssse3: 1;
|
||||
bool cid: 1;
|
||||
bool reserved: 1;
|
||||
bool fma: 1;
|
||||
bool cx16: 1;
|
||||
bool etprd: 1;
|
||||
bool pdcm: 1;
|
||||
bool pcide: 1;
|
||||
bool dca: 1;
|
||||
bool sse4_1: 1;
|
||||
bool sse4_2: 1;
|
||||
bool x2APIC: 1;
|
||||
bool movbe: 1;
|
||||
bool popcnt: 1;
|
||||
bool reserved2: 1;
|
||||
bool aes: 1;
|
||||
bool xsave: 1;
|
||||
bool osxsave: 1;
|
||||
bool avx: 1;
|
||||
} cpu_features_ecx ;
|
||||
|
||||
typedef struct {
|
||||
bool fpu: 1;
|
||||
bool vme: 1;
|
||||
bool de: 1;
|
||||
bool pse: 1;
|
||||
bool tsc: 1;
|
||||
bool msr: 1;
|
||||
bool pae: 1;
|
||||
bool mce: 1;
|
||||
bool cx8: 1;
|
||||
bool apic: 1;
|
||||
bool reserved: 1;
|
||||
bool sep: 1;
|
||||
bool mtrr: 1;
|
||||
bool pge: 1;
|
||||
bool mca: 1;
|
||||
bool cmov: 1;
|
||||
bool pat: 1;
|
||||
bool pse36: 1;
|
||||
bool psn: 1;
|
||||
bool clf: 1;
|
||||
bool reserved2: 1;
|
||||
bool dtes: 1;
|
||||
bool acpi: 1;
|
||||
bool mmx: 1;
|
||||
bool fxsr: 1;
|
||||
bool sse: 1;
|
||||
bool sse2: 1;
|
||||
bool ss: 1;
|
||||
bool htt: 1;
|
||||
bool tm1: 1;
|
||||
bool ia64: 1;
|
||||
bool pbe: 1;
|
||||
|
||||
} cpu_features_edx ;
|
||||
|
||||
enum cpu_features {
|
||||
CPUID_FEAT_ECX_SSE3 = 1 << 0,
|
||||
CPUID_FEAT_ECX_PCLMUL = 1 << 1,
|
||||
CPUID_FEAT_ECX_DTES64 = 1 << 2,
|
||||
@@ -68,16 +134,6 @@ enum {
|
||||
CPUID_FEAT_EDX_PBE = 1 << 31
|
||||
};
|
||||
|
||||
static inline void cpuid(int code, uint32_t *a, uint32_t *d) {
|
||||
asm volatile("cpuid":"=a"(*a), "=d"(*d):"a"(code):"ecx", "ebx");
|
||||
}
|
||||
|
||||
/** issue a complete request, storing general registers output as a string
|
||||
*/
|
||||
static inline int cpuid_string(int code, uint32_t where[4]) {
|
||||
asm volatile("cpuid":"=a"(*where), "=b"(*(where + 1)),
|
||||
"=c"(*(where + 2)), "=d"(*(where + 3)):"a"(code));
|
||||
return (int) where[0];
|
||||
}
|
||||
void cpuidx_print_info();
|
||||
|
||||
#endif //NEW_KERNEL_CPUIDX_H
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#ifndef MY_KERNEL_IDT_H
|
||||
#define MY_KERNEL_IDT_H
|
||||
#include <attributes.h>
|
||||
|
||||
#define KERNEL_CS 0x08
|
||||
|
||||
/* How every interrupt gate (handler) is defined */
|
||||
@@ -19,12 +21,12 @@ typedef struct {
|
||||
* Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */
|
||||
uint8_t flags;
|
||||
uint16_t high_offset; /* Higher 16 bits of handler function address */
|
||||
} __attribute__((packed)) idt_gate_t;
|
||||
} packed idt_gate_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t limit;
|
||||
uint32_t base;
|
||||
} __attribute__((packed)) idt_register_t;
|
||||
} packed idt_register_t;
|
||||
|
||||
#define IDT_REGISTERS 256
|
||||
|
||||
|
||||
@@ -109,6 +109,8 @@ irq_common_stub:
|
||||
.global irq14
|
||||
.global irq15
|
||||
|
||||
.global isr128
|
||||
|
||||
# 0: Divide By Zero Exception
|
||||
isr0:
|
||||
cli
|
||||
@@ -424,3 +426,9 @@ irq15:
|
||||
push $47
|
||||
jmp irq_common_stub
|
||||
|
||||
# Syscall
|
||||
isr128:
|
||||
cli
|
||||
push $0
|
||||
push $128
|
||||
jmp isr_common_stub
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
#include "isr.h"
|
||||
|
||||
#include <cpu/idt.h>
|
||||
#include <cpu/syscall_handler.h>
|
||||
#include <libc/libc.h>
|
||||
#include <drivers/ports.h>
|
||||
#include <libc/kprintf.h>
|
||||
#include <libk.h>
|
||||
|
||||
#define PIC_END_OF_INTERRUPT 0x20
|
||||
|
||||
@@ -48,6 +50,7 @@ void isr_install() {
|
||||
set_idt_gate(31, (uint32_t) isr31);
|
||||
|
||||
// Remap the PIC
|
||||
// todo make readable
|
||||
port_byte_out(0x20, 0x11);
|
||||
port_byte_out(0xA0, 0x11);
|
||||
port_byte_out(0x21, 0x20);
|
||||
@@ -77,6 +80,8 @@ void isr_install() {
|
||||
set_idt_gate(46, (uint32_t) irq14);
|
||||
set_idt_gate(47, (uint32_t) irq15);
|
||||
|
||||
set_idt_gate(128, (uint32_t) isr128);
|
||||
|
||||
set_idt(); // Load with ASM
|
||||
}
|
||||
|
||||
@@ -118,15 +123,20 @@ char *exception_messages[] = {
|
||||
"Reserved"
|
||||
};
|
||||
|
||||
void isr_handler(registers_t r) {
|
||||
void isr_handler(isr_registers_t r) {
|
||||
if (r.int_no == 128) {
|
||||
syscall_handle(&r);
|
||||
return;
|
||||
}
|
||||
printf("Received interrupt: %d - %s\n", r.int_no, exception_messages[r.int_no]);
|
||||
k_panic();
|
||||
}
|
||||
|
||||
void register_interrupt_handler(uint8_t n, isr_t handler) {
|
||||
interrupt_handlers[n] = handler;
|
||||
}
|
||||
|
||||
void irq_handler(registers_t r) {
|
||||
void irq_handler(isr_registers_t r) {
|
||||
/* After every interrupt we need to send an EOI to the PICs
|
||||
* or they will not send another interrupt again */
|
||||
if (r.int_no >= 40) port_byte_out(PORT_PIC_SLAVE_COMMAND, PIC_END_OF_INTERRUPT); /* slave */
|
||||
@@ -135,6 +145,6 @@ void irq_handler(registers_t r) {
|
||||
/* Handle the interrupt in a more modular way */
|
||||
if (interrupt_handlers[r.int_no] != NULL) {
|
||||
isr_t handler = interrupt_handlers[r.int_no];
|
||||
handler(r);
|
||||
handler(&r);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@
|
||||
#ifndef MY_KERNEL_ISR_H
|
||||
#define MY_KERNEL_ISR_H
|
||||
|
||||
#include <cpu/cpu.h>
|
||||
|
||||
/* ISRs reserved for CPU exceptions */
|
||||
extern void isr0();
|
||||
|
||||
@@ -105,6 +107,8 @@ extern void irq14();
|
||||
|
||||
extern void irq15();
|
||||
|
||||
extern void isr128();
|
||||
|
||||
#define IRQ0 32
|
||||
#define IRQ1 33
|
||||
#define IRQ2 34
|
||||
@@ -122,19 +126,12 @@ extern void irq15();
|
||||
#define IRQ14 46
|
||||
#define IRQ15 47
|
||||
|
||||
typedef struct {
|
||||
uint32_t ds;
|
||||
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
|
||||
uint32_t int_no, err_code;
|
||||
uint32_t eip, cs, eflags, useresp, ss;
|
||||
} registers_t;
|
||||
|
||||
typedef void (*isr_t)(registers_t);
|
||||
typedef void (*isr_t)(isr_registers_t*);
|
||||
|
||||
void register_interrupt_handler(uint8_t n, isr_t handler);
|
||||
|
||||
void isr_install();
|
||||
|
||||
void isr_handler(registers_t r);
|
||||
void isr_handler(isr_registers_t r);
|
||||
|
||||
#endif //MY_KERNEL_ISR_H
|
||||
|
||||
20
kernel/cpu/syscall_handler.c
Normal file
20
kernel/cpu/syscall_handler.c
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by rick on 24-02-21.
|
||||
//
|
||||
|
||||
#include "syscall_handler.h"
|
||||
#include <syscall.h>
|
||||
#include <tasks/task.h>
|
||||
|
||||
void syscall_handle(isr_registers_t *registers) {
|
||||
switch (registers->eax) {
|
||||
case SYSCALL_START_SCHEDULER:
|
||||
task_start_first();
|
||||
break;
|
||||
case SYSCALL_YIELD_JOB:
|
||||
task_switch_next();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
11
kernel/cpu/syscall_handler.h
Normal file
11
kernel/cpu/syscall_handler.h
Normal file
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// Created by rick on 24-02-21.
|
||||
//
|
||||
|
||||
#ifndef NEW_KERNEL_SYSCALL_HANDLER_H
|
||||
#define NEW_KERNEL_SYSCALL_HANDLER_H
|
||||
#include <cpu/cpu.h>
|
||||
|
||||
void syscall_handle(isr_registers_t *registers);
|
||||
|
||||
#endif //NEW_KERNEL_SYSCALL_HANDLER_H
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <libc/libc.h>
|
||||
#include <libk.h>
|
||||
#include <kprint.h>
|
||||
#include <tasks/task.h>
|
||||
|
||||
// https://wiki.osdev.org/PIT
|
||||
#define PIT_MODE_BIN_BCD (1 << 0)
|
||||
@@ -34,8 +35,13 @@
|
||||
|
||||
uint32_t tick = 0;
|
||||
|
||||
static void timer_callback(registers_t regs) {
|
||||
static void timer_callback(isr_registers_t *regs) {
|
||||
tick++;
|
||||
task_switch_next();
|
||||
}
|
||||
|
||||
uint32_t timer_get_tick() {
|
||||
return tick;
|
||||
}
|
||||
|
||||
void sleep(uint32_t milliseconds) {
|
||||
|
||||
@@ -11,6 +11,8 @@ int init_timer(uint32_t freq);
|
||||
|
||||
void print_current_tick();
|
||||
|
||||
uint32_t timer_get_tick();
|
||||
|
||||
void sleep(uint32_t milliseconds);
|
||||
|
||||
#endif //MY_KERNEL_TIMER_H
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <cpu/timer.h>
|
||||
#include <libc/kprintf.h>
|
||||
#include <fs/blockdev.h>
|
||||
#include <mem/mem.h>
|
||||
#include <mem/malloc.h>
|
||||
|
||||
#define ATA_SR_BSY 0x80 // Busy
|
||||
#define ATA_SR_DRDY 0x40 // Drive ready
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include <drivers/ports.h>
|
||||
#include <cpu/isr.h>
|
||||
#include <libc/ringqueue.h>
|
||||
#include <mem/mem.h>
|
||||
#include <libk.h>
|
||||
#include <mem/malloc.h>
|
||||
|
||||
|
||||
const char scancode_map_lowercase[] = {
|
||||
@@ -119,7 +119,7 @@ void publish_key_event(unsigned char scan_code) {
|
||||
ring_buffer_put(keyboard_event_buffer, &event);
|
||||
}
|
||||
|
||||
static void keyboard_callback(registers_t regs) {
|
||||
static void keyboard_callback(isr_registers_t *regs) {
|
||||
unsigned char status = port_byte_in(PORT_PS2_STATUS);
|
||||
// check if data available
|
||||
if ((status & 0b00000001) == 0) {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <libc/libc.h>
|
||||
#include <libk.h>
|
||||
#include <mem/mem.h>
|
||||
#include <libc/kprintf.h>
|
||||
#include <mem/malloc.h>
|
||||
#include "blockdev.h"
|
||||
|
||||
#define MAX_BLOCK_DEVS 64
|
||||
@@ -21,7 +21,7 @@ uint8_t block_dev_register_driver(block_dev_driver *driver) {
|
||||
return BLOCK_DEV_REGISTER_DRIVER_FULL;
|
||||
}
|
||||
|
||||
memcpy((uint8_t *) &block_dev_drivers[last_block_driver++], (const uint8_t *) driver, sizeof(block_dev_drivers));
|
||||
memcpy((uint8_t *) &block_dev_drivers[last_block_driver++], (const uint8_t *) driver, sizeof(block_dev_driver));
|
||||
return BLOCK_DEV_REGISTER_DRIVER_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
#include <types.h>
|
||||
#include <libc/libc.h>
|
||||
#include <libc/kprintf.h>
|
||||
#include <mem/mem.h>
|
||||
#include <mem/malloc.h>
|
||||
#include <attributes.h>
|
||||
|
||||
#define FAT_TYPE_12 1
|
||||
#define FAT_TYPE_16 2
|
||||
@@ -31,7 +32,7 @@ typedef struct {
|
||||
uint16_t heads_sides;
|
||||
uint32_t hidden_sectors;
|
||||
uint32_t large_total_sectors;
|
||||
} __attribute((packed)) bpb;
|
||||
} packed bpb;
|
||||
union {
|
||||
struct {
|
||||
uint8_t drive_number;
|
||||
@@ -40,7 +41,7 @@ typedef struct {
|
||||
uint32_t serial;
|
||||
uint8_t label[11];
|
||||
uint8_t system_id[8];
|
||||
} __attribute((packed)) ebr_12_16;
|
||||
} packed ebr_12_16;
|
||||
struct {
|
||||
uint32_t sectors_per_fat;
|
||||
uint16_t flags;
|
||||
@@ -55,21 +56,21 @@ typedef struct {
|
||||
uint32_t serial;
|
||||
uint8_t label[11];
|
||||
uint8_t system_id[8];
|
||||
} __attribute((packed)) ebr_32;
|
||||
} packed ebr_32;
|
||||
};
|
||||
} __attribute((packed)) fat_bpb;
|
||||
} packed fat_bpb;
|
||||
|
||||
typedef struct {
|
||||
uint8_t hours: 5;
|
||||
uint8_t minutes: 6;
|
||||
uint8_t seconds: 5;
|
||||
} __attribute((packed)) time_83;
|
||||
} packed time_83;
|
||||
|
||||
typedef struct {
|
||||
uint8_t hours: 5;
|
||||
uint8_t minutes: 6;
|
||||
uint8_t seconds: 5;
|
||||
} __attribute((packed)) date_83;
|
||||
} packed date_83;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
@@ -86,7 +87,7 @@ typedef struct {
|
||||
date_83 last_mod_date;
|
||||
uint16_t low_first_cluster;
|
||||
uint32_t file_size;
|
||||
} __attribute((packed)) name_83;
|
||||
} packed name_83;
|
||||
struct {
|
||||
uint8_t order;
|
||||
uint16_t text_1[5];
|
||||
@@ -96,9 +97,9 @@ typedef struct {
|
||||
uint16_t text_2[6];
|
||||
uint16_t reserved;
|
||||
uint16_t text_3[2];
|
||||
} __attribute((packed)) long_name;
|
||||
} packed long_name;
|
||||
};
|
||||
} __attribute((packed)) fat_directory_entry;
|
||||
} packed fat_directory_entry;
|
||||
|
||||
uint8_t fat_check_device(const block_device *device, uint8_t *first_sector);
|
||||
|
||||
@@ -128,7 +129,8 @@ uint8_t fat_check_device(const block_device *device, uint8_t *first_sector) {
|
||||
|
||||
uint32_t total_sectors = bpb.bpb.total_sectors == 0 ? bpb.bpb.large_total_sectors : bpb.bpb.total_sectors;
|
||||
uint32_t fat_size = bpb.bpb.sectors_per_fat == 0 ? bpb.ebr_32.sectors_per_fat : bpb.bpb.sectors_per_fat;
|
||||
uint32_t root_dir_sectors = ((bpb.bpb.directories * 32) + (bpb.bpb.bytes_per_sector - 1)) / bpb.bpb.bytes_per_sector;
|
||||
uint32_t root_dir_sectors =
|
||||
((bpb.bpb.directories * 32) + (bpb.bpb.bytes_per_sector - 1)) / bpb.bpb.bytes_per_sector;
|
||||
uint32_t first_data_sector = bpb.bpb.reserved_sectors + (bpb.bpb.fats * fat_size) + root_dir_sectors;
|
||||
uint32_t first_fat_sector = bpb.bpb.reserved_sectors;
|
||||
uint32_t data_sectors = total_sectors - (bpb.bpb.reserved_sectors + (bpb.bpb.fats * fat_size) + root_dir_sectors);
|
||||
@@ -163,7 +165,8 @@ typedef struct {
|
||||
} table_result;
|
||||
|
||||
table_result
|
||||
get_fat_table_value(uint8_t fat_type, const uint8_t *fat_table, uint32_t active_cluster, uint32_t first_fat_cluster, uint32_t sector_size) {
|
||||
get_fat_table_value(uint8_t fat_type, const uint8_t *fat_table, uint32_t active_cluster, uint32_t first_fat_cluster,
|
||||
uint32_t sector_size) {
|
||||
uint32_t fat_offset;
|
||||
table_result result = {
|
||||
.value = 0,
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
#include "mbr.h"
|
||||
#include <types.h>
|
||||
#include <drivers/ide.h>
|
||||
#include <mem/mem.h>
|
||||
#include <libc/kprintf.h>
|
||||
#include <fs/blockdev.h>
|
||||
#include <libc/libc.h>
|
||||
#include <mem/malloc.h>
|
||||
#include <attributes.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t bootable;
|
||||
@@ -21,14 +22,14 @@ typedef struct {
|
||||
uint16_t ending_cylinder: 10;
|
||||
uint32_t start_lba;
|
||||
uint32_t num_lbas;
|
||||
} __attribute((packed)) mbr_partition_table_entry;
|
||||
} packed mbr_partition_table_entry;
|
||||
|
||||
typedef struct {
|
||||
uint32_t unique_id;
|
||||
uint16_t reserved;
|
||||
mbr_partition_table_entry entries[4];
|
||||
uint8_t signature[2];
|
||||
} __attribute((packed)) mbr_table;
|
||||
} packed mbr_table;
|
||||
|
||||
typedef struct {
|
||||
const block_device *device;
|
||||
|
||||
145
kernel/kernel.c
145
kernel/kernel.c
@@ -1,6 +1,4 @@
|
||||
#include <drivers/ports.h>
|
||||
#include <drivers/vgascreen.h>
|
||||
#include <libc/libc.h>
|
||||
#include <cpu/isr.h>
|
||||
#include <cpu/timer.h>
|
||||
#include <drivers/keyboard.h>
|
||||
@@ -8,8 +6,6 @@
|
||||
#include <multiboot.h>
|
||||
#include <drivers/serial.h>
|
||||
#include <kprint.h>
|
||||
#include <libc/readline.h>
|
||||
#include <libc/string.h>
|
||||
#include <libk.h>
|
||||
#include <drivers/pci.h>
|
||||
#include <drivers/ide.h>
|
||||
@@ -18,118 +14,22 @@
|
||||
#include <fs/blockdev.h>
|
||||
#include <fs/fat.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define BOOTLOADER_NAME_MAX_LENGTH 64
|
||||
#define CMDLINE_MAX_LENGTH 256
|
||||
#include <cpu/cpuidx.h>
|
||||
#include <mem/malloc.h>
|
||||
#include <tasks/task.h>
|
||||
#include <syscall.h>
|
||||
#include <command.h>
|
||||
#include <attributes.h>
|
||||
|
||||
const int version_major = 0,
|
||||
version_minor = 0,
|
||||
version_patch = 1;
|
||||
|
||||
char bootloader_name[BOOTLOADER_NAME_MAX_LENGTH];
|
||||
char cmdline[CMDLINE_MAX_LENGTH];
|
||||
|
||||
typedef void (*cmd_handler_func)(const char *);
|
||||
|
||||
typedef struct {
|
||||
char *cmd;
|
||||
cmd_handler_func handler;
|
||||
} cmd_handler;
|
||||
|
||||
void print(const char *arg);
|
||||
|
||||
void ide(const char *arg);
|
||||
|
||||
void echo(const char *arg);
|
||||
|
||||
void help(const char *arg);
|
||||
|
||||
cmd_handler cmd_handlers[] = {
|
||||
{"help", help},
|
||||
{"echo", echo},
|
||||
{"print", print},
|
||||
{"ide", ide},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
void print_bootinfo() {
|
||||
printf("Bootloader name: %s\n"
|
||||
"cmdline: %s\n",
|
||||
(bootloader_name[0] == 0 ? "NULL" : bootloader_name),
|
||||
(cmdline[0] == 0 ? "NULL" : cmdline));
|
||||
}
|
||||
|
||||
void help(const char *arg) {
|
||||
kprint("Available commands:\n");
|
||||
int index = 0;
|
||||
while (true) {
|
||||
if (cmd_handlers[index].cmd == NULL) {
|
||||
break;
|
||||
}
|
||||
printf("%s\n", cmd_handlers[index].cmd);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void echo(const char *arg) {
|
||||
printf("%s\n", arg);
|
||||
}
|
||||
|
||||
void print(const char *arg) {
|
||||
if (strcmp(arg, "mmap") == 0) {
|
||||
print_mmap_info();
|
||||
} else if (strcmp(arg, "malloc") == 0) {
|
||||
print_malloc_info();
|
||||
} else if (strcmp(arg, "tick") == 0) {
|
||||
print_current_tick();
|
||||
} else if (strcmp(arg, "bootinfo") == 0) {
|
||||
print_bootinfo();
|
||||
} else if (strcmp(arg, "pci") == 0) {
|
||||
pci_print_info();
|
||||
} else if (strcmp(arg, "ide") == 0) {
|
||||
ide_print_devices();
|
||||
} else {
|
||||
printf("Unknown print %s\n", arg);
|
||||
}
|
||||
}
|
||||
|
||||
void ide(const char *arg) {
|
||||
if (strcmp(arg, "block_devices") == 0) {
|
||||
block_dev_print_info();
|
||||
} else if (strcmp(arg, "ide_devices") == 0) {
|
||||
ide_print_devices();
|
||||
} else if (strcmp(arg, "mbr") == 0) {
|
||||
mbr_read_from_ide(0);
|
||||
} else {
|
||||
printf("Unknown print %s\n", arg);
|
||||
}
|
||||
}
|
||||
|
||||
void main_loop();
|
||||
|
||||
void store_bootloader_info(multiboot_info_t *multiboot_info) {
|
||||
// get bootloader and cmdline
|
||||
if (multiboot_info->flags & MULTIBOOT_INFO_CMDLINE) {
|
||||
int cmdline_length = strlen((const char *) multiboot_info->cmdline);
|
||||
if (cmdline_length > CMDLINE_MAX_LENGTH) {
|
||||
k_panics("cmdline to long!\n");
|
||||
}
|
||||
memcpy(cmdline, (char *) multiboot_info->cmdline, cmdline_length);
|
||||
}
|
||||
if (multiboot_info->flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) {
|
||||
int bootloader_length = strlen((const char *) multiboot_info->boot_loader_name);
|
||||
if (bootloader_length > BOOTLOADER_NAME_MAX_LENGTH) {
|
||||
k_panics("bootloader name to long!\n");
|
||||
}
|
||||
memcpy(bootloader_name, (char *) multiboot_info->boot_loader_name, bootloader_length);
|
||||
}
|
||||
}
|
||||
|
||||
void init_mmap(multiboot_info_t *multiboot_info) {
|
||||
if (multiboot_info->flags & (1 << 6)) {
|
||||
init_mmap_multiboot((struct multiboot_mmap_entry *) multiboot_info->mmap_addr,
|
||||
mmap_init_multiboot((struct multiboot_mmap_entry *) multiboot_info->mmap_addr,
|
||||
multiboot_info->mmap_length / sizeof(struct multiboot_mmap_entry));
|
||||
malloc_init();
|
||||
// todo fallback on other mechanisms?
|
||||
} else {
|
||||
k_panics("mmap invalid!\n");
|
||||
@@ -156,7 +56,7 @@ void init_block_devices() {
|
||||
block_dev_scan_repeat();
|
||||
}
|
||||
|
||||
void kmain(multiboot_info_t *multiboot_info) {
|
||||
void noreturn kmain(multiboot_info_t *multiboot_info) {
|
||||
isr_install();
|
||||
vga_clear_screen();
|
||||
vga_clear_screen(' ', VGA_WHITE | (VGA_GRAY << VGA_SHIFT_BG));
|
||||
@@ -164,6 +64,8 @@ void kmain(multiboot_info_t *multiboot_info) {
|
||||
serial_init();
|
||||
kprint_register(serial_kprint);
|
||||
|
||||
cpuidx_print_info();
|
||||
|
||||
store_bootloader_info(multiboot_info);
|
||||
init_mmap(multiboot_info);
|
||||
|
||||
@@ -176,27 +78,6 @@ void kmain(multiboot_info_t *multiboot_info) {
|
||||
|
||||
printf("Booted successfully v%d.%d.%d\n", version_major, version_minor, version_patch);
|
||||
|
||||
// enter main loop
|
||||
while (true) {
|
||||
main_loop();
|
||||
}
|
||||
task_spawn(main_loop, NULL);
|
||||
syscall_start_scheduler();
|
||||
}
|
||||
|
||||
void main_loop() {
|
||||
char *msg = readline(NULL);
|
||||
char *args = strchr(msg, ' ') + 1;
|
||||
args[-1] = 0;
|
||||
int test_index = 0;
|
||||
while (true) {
|
||||
if (cmd_handlers[test_index].cmd == 0) {
|
||||
printf("Unknown command: %s\n", msg);
|
||||
break;
|
||||
}
|
||||
if (strcmp(cmd_handlers[test_index].cmd, msg) == 0) {
|
||||
cmd_handlers[test_index].handler(args);
|
||||
break;
|
||||
}
|
||||
test_index++;
|
||||
}
|
||||
free(msg);
|
||||
}
|
||||
@@ -15,7 +15,7 @@ int memcpy(uint8_t *dst, const uint8_t *src, int amount) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int memset(char *dst, char data, int amount) {
|
||||
int memset(uint8_t *dst, char data, int amount) {
|
||||
for (int i = 0; i < amount; ++i) {
|
||||
dst[i] = data;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
int memcpy(uint8_t *dst, const uint8_t *src, int amount);
|
||||
|
||||
int memset(char *dst, char data, int amount);
|
||||
int memset(uint8_t *dst, char data, int amount);
|
||||
|
||||
char *itoa(int value, char *buffer, int base);
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include <libc/libc.h>
|
||||
#include <types.h>
|
||||
#include <kprint.h>
|
||||
#include <mem/mem.h>
|
||||
#include <drivers/keyboard.h>
|
||||
#include <mem/malloc.h>
|
||||
|
||||
#define RESULT_SIZE 256
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "ringqueue.h"
|
||||
#include <libc/libc.h>
|
||||
#include <mem/mem.h>
|
||||
#include <mem/malloc.h>
|
||||
|
||||
#define calc_pos(buffer, index) ((buffer->object_size) * (index))
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ int strncmp(const char *s1, const char *s2, int n) {
|
||||
if (s1[i] > s2[i]) {
|
||||
return -1;
|
||||
}
|
||||
if (s2[i] < s1[i]) {
|
||||
if (s1[i] < s2[i]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,14 @@
|
||||
// Created by rick on 02-02-21.
|
||||
//
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "libk.h"
|
||||
#include "kprint.h"
|
||||
|
||||
bool k_addr_in_kspace(void* addr) {
|
||||
return addr > kernel_start && addr < kernel_end;
|
||||
}
|
||||
|
||||
void k_wait_for_interrupt() {
|
||||
__asm__ __volatile__("hlt;");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,14 @@
|
||||
|
||||
#ifndef NEW_KERNEL_LIBK_H
|
||||
#define NEW_KERNEL_LIBK_H
|
||||
#include <stdbool.h>
|
||||
|
||||
extern void* _kernel_start;
|
||||
extern void* _kernel_end;
|
||||
#define kernel_start ((uint32_t)(&_kernel_start))
|
||||
#define kernel_end ((uint32_t)(&_kernel_end))
|
||||
|
||||
bool k_addr_in_kspace(void *addr);
|
||||
|
||||
void k_wait_for_interrupt();
|
||||
|
||||
|
||||
90
kernel/mem/malloc.c
Normal file
90
kernel/mem/malloc.c
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// Created by rick on 23-02-21.
|
||||
//
|
||||
|
||||
#include <libc/kprintf.h>
|
||||
#include <tasks/task.h>
|
||||
#include "malloc.h"
|
||||
#include "pmm.h"
|
||||
|
||||
#define MALLOC_TYPE_FREE 0
|
||||
#define MALLOC_TYPE_USED 1
|
||||
|
||||
int malloc_entries = 0;
|
||||
int malloc_used = 0;
|
||||
|
||||
typedef struct malloc_map {
|
||||
struct malloc_map *next;
|
||||
struct malloc_map *prev;
|
||||
uint32_t size;
|
||||
int type;
|
||||
} malloc_map;
|
||||
|
||||
malloc_map *first_malloc_entry;
|
||||
|
||||
void malloc_init() {
|
||||
first_malloc_entry = pmm_get_pages(16);
|
||||
first_malloc_entry->next = first_malloc_entry;
|
||||
first_malloc_entry->prev = first_malloc_entry;
|
||||
first_malloc_entry->size = PAGE_SIZE * 16;
|
||||
first_malloc_entry->type = MALLOC_TYPE_FREE;
|
||||
malloc_entries++;
|
||||
}
|
||||
|
||||
void split_malloc_map(malloc_map *entry, unsigned int size) {
|
||||
malloc_entries++;
|
||||
malloc_map *new_entry = entry + sizeof(malloc_map) + size;
|
||||
new_entry->size = entry->size - size - sizeof(malloc_map);
|
||||
new_entry->next = entry->next;
|
||||
new_entry->prev = entry;
|
||||
new_entry->type = MALLOC_TYPE_FREE;
|
||||
entry->next->prev = new_entry;
|
||||
entry->next = new_entry;
|
||||
entry->size = size;
|
||||
}
|
||||
|
||||
void *malloc(size_t size) {
|
||||
// todo replace this horrible mess!
|
||||
// this lacks any page alignment and what so ever
|
||||
void* result = NULL;
|
||||
task_lock_acquire();
|
||||
malloc_map *current_map = first_malloc_entry;
|
||||
// iterate through maps
|
||||
do {
|
||||
if (current_map->type == MALLOC_TYPE_USED) {
|
||||
goto malloc_find_next;
|
||||
}
|
||||
if ((unsigned int) current_map->size < size) {
|
||||
goto malloc_find_next;
|
||||
}
|
||||
if ((unsigned int) current_map->size > (size + sizeof(malloc_map))) {
|
||||
// big enough to split
|
||||
split_malloc_map(current_map, size);
|
||||
}
|
||||
malloc_used++;
|
||||
current_map->type = MALLOC_TYPE_USED;
|
||||
result = ((void *) current_map) + sizeof(malloc_map);
|
||||
break;
|
||||
|
||||
malloc_find_next:
|
||||
current_map = current_map->next;
|
||||
} while (current_map != first_malloc_entry);
|
||||
task_lock_free();
|
||||
return result;
|
||||
}
|
||||
|
||||
void free(void *mem) {
|
||||
if (mem == NULL) {
|
||||
return;
|
||||
}
|
||||
malloc_used--;
|
||||
malloc_map *map = (mem - sizeof(malloc_map));
|
||||
map->type = MALLOC_TYPE_FREE;
|
||||
};
|
||||
|
||||
|
||||
void print_malloc_info() {
|
||||
printf("Malloc avail entries: %d\n"
|
||||
"Malloc used entries: %d\n", malloc_entries, malloc_used);
|
||||
}
|
||||
|
||||
17
kernel/mem/malloc.h
Normal file
17
kernel/mem/malloc.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by rick on 23-02-21.
|
||||
//
|
||||
|
||||
#ifndef NEW_KERNEL_MALLOC_H
|
||||
#define NEW_KERNEL_MALLOC_H
|
||||
#include <types.h>
|
||||
|
||||
void malloc_init();
|
||||
|
||||
void print_malloc_info();
|
||||
|
||||
void *malloc(size_t size);
|
||||
|
||||
void free(void *mem);
|
||||
|
||||
#endif //NEW_KERNEL_MALLOC_H
|
||||
119
kernel/mem/mem.c
119
kernel/mem/mem.c
@@ -2,9 +2,12 @@
|
||||
// Created by rick on 22-04-20.
|
||||
//
|
||||
|
||||
#include "pmm.h"
|
||||
#include <types.h>
|
||||
#include <mem/mem.h>
|
||||
#include <libc/kprintf.h>
|
||||
#include <libk.h>
|
||||
#include <attributes.h>
|
||||
|
||||
#define MEMMAP_ENTRIES 16
|
||||
|
||||
@@ -15,26 +18,13 @@
|
||||
#define MMAP_TYPE_NVS 4
|
||||
#define MMAP_TYPE_BADRAM 5
|
||||
#define MMAP_TYPE_KERNEL 6
|
||||
#define MMAP_TYPE_MALLOC 7
|
||||
|
||||
#define MALLOC_TYPE_FREE 0
|
||||
#define MALLOC_TYPE_USED 1
|
||||
|
||||
#define kilobyte (1024)
|
||||
//#define kernel_start (one_meg)
|
||||
#define kernel_size (32 * kilobyte)
|
||||
#define kernel_end (kernel_start + kernel_size)
|
||||
extern void *kernel_start;
|
||||
//extern void *kernel_end;
|
||||
#define MMAP_TYPE_PAGING 7
|
||||
|
||||
typedef struct {
|
||||
void *address;
|
||||
uint32_t address;
|
||||
uint32_t length;
|
||||
uint32_t type;
|
||||
} __attribute((packed)) mmap_entry;
|
||||
|
||||
int malloc_entries = 0;
|
||||
int malloc_used = 0;
|
||||
} packed mmap_entry;
|
||||
|
||||
int last_memmap_entry = 0;
|
||||
mmap_entry memmap[MEMMAP_ENTRIES] = {
|
||||
@@ -56,114 +46,51 @@ mmap_entry memmap[MEMMAP_ENTRIES] = {
|
||||
{0, 0, 0},
|
||||
};
|
||||
|
||||
typedef struct malloc_map {
|
||||
struct malloc_map *next;
|
||||
struct malloc_map *pref;
|
||||
uint32_t size;
|
||||
int type;
|
||||
} malloc_map;
|
||||
|
||||
void use_mmap_entry(struct multiboot_mmap_entry *entry) {
|
||||
mmap_entry *mm_entry = &memmap[last_memmap_entry++];
|
||||
mm_entry->address = (void *) entry->addr;
|
||||
mm_entry->length = entry->len;
|
||||
mm_entry->type = entry->type;
|
||||
if (last_memmap_entry == 1) {
|
||||
// not using first map entry for now
|
||||
return;
|
||||
}
|
||||
// check if the entry overlaps with the kernel address space
|
||||
if (kernel_start >= mm_entry->address && kernel_start <= mm_entry->address + mm_entry->length) {
|
||||
uint32_t page_after_kernel = kernel_end + PAGE_SIZE & ~(PAGE_SIZE - 1);
|
||||
uint32_t kernel_size_full_pages = page_after_kernel - mm_entry->address;
|
||||
// todo make this something proper
|
||||
struct multiboot_mmap_entry extra_entry;
|
||||
extra_entry.size = entry->size;
|
||||
extra_entry.type = entry->type;
|
||||
extra_entry.addr = entry->addr + kernel_size;
|
||||
extra_entry.len = entry->size - kernel_size;
|
||||
extra_entry.addr = page_after_kernel;
|
||||
extra_entry.len = entry->size - kernel_size_full_pages;
|
||||
use_mmap_entry(&extra_entry);
|
||||
|
||||
mm_entry->length = kernel_size;
|
||||
mm_entry->length = kernel_size_full_pages;
|
||||
mm_entry->type = MMAP_TYPE_KERNEL;
|
||||
}
|
||||
if (mm_entry->type == MMAP_TYPE_AVAILABLE && (unsigned int) mm_entry->length > sizeof(malloc_map)) {
|
||||
mm_entry->type = MMAP_TYPE_MALLOC;
|
||||
malloc_map *map = (malloc_map *) mm_entry->address;
|
||||
map->type = MALLOC_TYPE_FREE;
|
||||
map->size = mm_entry->length - sizeof(malloc_map);
|
||||
map->pref = map;
|
||||
map->next = map;
|
||||
malloc_entries++;
|
||||
}
|
||||
}
|
||||
|
||||
void init_mmap_multiboot(struct multiboot_mmap_entry *entries, uint32_t count) {
|
||||
void mmap_init_multiboot(struct multiboot_mmap_entry *entries, uint32_t count) {
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
use_mmap_entry(&entries[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void split_malloc_map(malloc_map *entry, unsigned int size) {
|
||||
malloc_entries++;
|
||||
malloc_map *new_entry = entry + sizeof(malloc_map) + size;
|
||||
new_entry->size = entry->size - size - sizeof(malloc_map);
|
||||
new_entry->next = entry->next;
|
||||
new_entry->pref = entry;
|
||||
new_entry->type = MALLOC_TYPE_FREE;
|
||||
entry->next->pref = new_entry;
|
||||
entry->next = new_entry;
|
||||
entry->size = size;
|
||||
}
|
||||
|
||||
void *malloc(size_t size) {
|
||||
// todo replace this horrible mess!
|
||||
// this lacks any page alignment and what so ever
|
||||
for (int i = 0; i < MEMMAP_ENTRIES; ++i) {
|
||||
if (memmap[i].type != MMAP_TYPE_MALLOC) {
|
||||
// init page manager
|
||||
for (int i = 0; i < last_memmap_entry; ++i) {
|
||||
mmap_entry *entry = &memmap[i];
|
||||
if (entry->type != MMAP_TYPE_AVAILABLE) {
|
||||
continue;
|
||||
}
|
||||
// get first first_map of address
|
||||
malloc_map *first_map = (malloc_map *) memmap[i].address;
|
||||
malloc_map *current_map = first_map;
|
||||
// iterate through maps
|
||||
do {
|
||||
if (current_map->type == MALLOC_TYPE_USED) {
|
||||
goto malloc_find_next;
|
||||
}
|
||||
if ((unsigned int) current_map->size < size) {
|
||||
goto malloc_find_next;
|
||||
}
|
||||
if ((unsigned int) current_map->size > (size + sizeof(malloc_map))) {
|
||||
// big enough to split
|
||||
split_malloc_map(current_map, size);
|
||||
}
|
||||
malloc_used++;
|
||||
current_map->type = MALLOC_TYPE_USED;
|
||||
return ((void *) current_map) + sizeof(malloc_map);
|
||||
if (entry->address < kernel_start) {
|
||||
continue; // skip for now
|
||||
}
|
||||
|
||||
malloc_find_next:
|
||||
current_map = current_map->next;
|
||||
} while (current_map != first_map);
|
||||
pmm_init((void *) entry->address, entry->length);
|
||||
entry->type = MMAP_TYPE_PAGING;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free(void *mem) {
|
||||
if (mem == NULL) {
|
||||
return;
|
||||
}
|
||||
malloc_used--;
|
||||
malloc_map *map = (mem - sizeof(malloc_map));
|
||||
map->type = MALLOC_TYPE_FREE;
|
||||
};
|
||||
|
||||
|
||||
void print_malloc_info() {
|
||||
printf("Malloc avail entries: %d\n"
|
||||
"Malloc used entries: %d\n", malloc_entries, malloc_used);
|
||||
}
|
||||
|
||||
|
||||
void print_mmap_info() {
|
||||
printf("Kernel start: %8x\n"
|
||||
"Kernel end: %8x\n", kernel_start, kernel_end);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (memmap[i].type == 0) {
|
||||
break;
|
||||
|
||||
@@ -7,14 +7,8 @@
|
||||
|
||||
#include <multiboot.h>
|
||||
|
||||
void init_mmap_multiboot(struct multiboot_mmap_entry *entries, uint32_t count);
|
||||
|
||||
void print_malloc_info();
|
||||
void mmap_init_multiboot(struct multiboot_mmap_entry *entries, uint32_t count);
|
||||
|
||||
void print_mmap_info();
|
||||
|
||||
void *malloc(size_t size);
|
||||
|
||||
void free(void *mem);
|
||||
|
||||
#endif //NEW_KERNEL_MEM_H
|
||||
|
||||
98
kernel/mem/pmm.c
Normal file
98
kernel/mem/pmm.c
Normal file
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// Created by rick on 23-02-21.
|
||||
//
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <libc/libc.h>
|
||||
#include <libk.h>
|
||||
#include "pmm.h"
|
||||
|
||||
#define NUM_PAGING_INFOS 16
|
||||
|
||||
#define BLOCK_USED 1
|
||||
#define BLOCK_FREE 0
|
||||
|
||||
#define bitmap_block_byte(block) ((block) / 8)
|
||||
#define bitmap_block_bit(block) ((block) % 8)
|
||||
|
||||
#define bitmap_set(addr, block) (addr)[bitmap_block_byte(block)] = ((addr)[bitmap_block_byte(block)] | (1 << (bitmap_block_bit(block))))
|
||||
#define bitmap_unset(addr, block) (addr)[bitmap_block_byte(block)] = ((addr)[bitmap_block_byte(block)] & ~(1 << (bitmap_block_bit(block))))
|
||||
|
||||
#define bitmap_get(addr, block) ((addr)[bitmap_block_byte(block)] >> bitmap_block_bit(block))
|
||||
|
||||
#define page_to_addr(base_addr, block) ((base_addr) + ((block) * PAGE_SIZE))
|
||||
#define addr_to_page(base_addr, addr) (((addr) - (base_addr)) / PAGE_SIZE)
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
uint8_t *page_bitmap;
|
||||
void *first_page;
|
||||
};
|
||||
uint32_t num_pages;
|
||||
size_t size;
|
||||
struct {
|
||||
bool present: 1;
|
||||
} flags;
|
||||
} paging_info;
|
||||
|
||||
uint8_t last_paging_info = 0;
|
||||
paging_info paging_infos[NUM_PAGING_INFOS];
|
||||
|
||||
void pmm_init(void *start_addr, size_t size) {
|
||||
uint32_t num_pages = size / PAGE_SIZE;
|
||||
uint32_t bitmap_size = num_pages / 8;
|
||||
uint32_t bitmap_pages = bitmap_size / PAGE_SIZE;
|
||||
paging_infos[last_paging_info].page_bitmap = start_addr;
|
||||
paging_infos[last_paging_info].num_pages = num_pages;
|
||||
paging_infos[last_paging_info].size = size;
|
||||
paging_infos[last_paging_info].flags.present = true;
|
||||
|
||||
memset(start_addr, BLOCK_FREE, bitmap_pages);
|
||||
for (uint32_t i = 0; i < bitmap_pages; ++i) {
|
||||
bitmap_set((uint8_t *) start_addr, i);
|
||||
}
|
||||
last_paging_info++;
|
||||
}
|
||||
|
||||
void *pmm_get_pages(uint32_t num_pages) {
|
||||
for (int i = 0; i < last_paging_info; ++i) {
|
||||
paging_info *info = &paging_infos[i];
|
||||
if (!info->flags.present) continue;
|
||||
|
||||
for (uint32_t j = 0; j < info->num_pages; ++j) {
|
||||
if (bitmap_get(info->page_bitmap, j) == BLOCK_FREE) {
|
||||
uint32_t k;
|
||||
bool usable = true;
|
||||
for (k = j + 1; k < j + num_pages; ++k) {
|
||||
if (bitmap_get(info->page_bitmap, k) == BLOCK_USED) {
|
||||
usable = false;
|
||||
j = k; // skip ahead
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!usable) break;
|
||||
for (k = j; k < j + num_pages; ++k) {
|
||||
bitmap_set(info->page_bitmap, k);
|
||||
}
|
||||
return page_to_addr(info->first_page, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
k_panics("No page found!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pmm_free_pages(void *page, uint32_t num_pages) {
|
||||
for (int i = 0; i < last_paging_info; ++i) {
|
||||
paging_info *info = &paging_infos[i];
|
||||
if (!info->flags.present) continue;
|
||||
// check if page is in memory area
|
||||
if (page < info->first_page || page > (info->first_page + info->size)) continue;
|
||||
|
||||
// free page
|
||||
uint32_t first_page = addr_to_page(info->first_page, page);
|
||||
for (uint32_t current_page = first_page; current_page < first_page + num_pages; ++current_page) {
|
||||
bitmap_unset(info->page_bitmap, current_page);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
kernel/mem/pmm.h
Normal file
16
kernel/mem/pmm.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Created by rick on 23-02-21.
|
||||
//
|
||||
|
||||
#ifndef NEW_KERNEL_PMM_H
|
||||
#define NEW_KERNEL_PMM_H
|
||||
#include <types.h>
|
||||
|
||||
// 4k blocks
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
void pmm_init(void* start_addr, size_t size);
|
||||
void *pmm_get_pages(uint32_t num_pages);
|
||||
void pmm_free_pages(void* page, uint32_t num_pages);
|
||||
|
||||
#endif //NEW_KERNEL_PMM_H
|
||||
22
kernel/syscall.c
Normal file
22
kernel/syscall.c
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Created by rick on 22-02-21.
|
||||
//
|
||||
|
||||
#include "syscall.h"
|
||||
#include <types.h>
|
||||
#include <attributes.h>
|
||||
|
||||
void syscall1(uint32_t arg1) {
|
||||
__asm__("int $0x80"
|
||||
:
|
||||
: "a"(arg1));
|
||||
}
|
||||
|
||||
void syscall_yield_job() {
|
||||
syscall1(SYSCALL_YIELD_JOB);
|
||||
}
|
||||
|
||||
void noreturn syscall_start_scheduler() {
|
||||
syscall1(SYSCALL_START_SCHEDULER);
|
||||
while (1) { __asm__("hlt"); };
|
||||
}
|
||||
17
kernel/syscall.h
Normal file
17
kernel/syscall.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by rick on 22-02-21.
|
||||
//
|
||||
|
||||
#ifndef NEW_KERNEL_SYSCALL_H
|
||||
#define NEW_KERNEL_SYSCALL_H
|
||||
|
||||
#include <attributes.h>
|
||||
|
||||
#define SYSCALL_START_SCHEDULER 0x01
|
||||
#define SYSCALL_YIELD_JOB 0x02
|
||||
|
||||
void syscall_yield_job();
|
||||
|
||||
void noreturn syscall_start_scheduler();
|
||||
|
||||
#endif //NEW_KERNEL_SYSCALL_H
|
||||
42
kernel/tasks/task.S
Normal file
42
kernel/tasks/task.S
Normal file
@@ -0,0 +1,42 @@
|
||||
.code32
|
||||
|
||||
.global __task_entry_point
|
||||
__task_entry_point:
|
||||
# Load segments
|
||||
popl %eax
|
||||
movw %ax,%ds
|
||||
movw %ax,%es
|
||||
movw %ax,%fs
|
||||
movw %ax,%gs
|
||||
# pop isr_registers
|
||||
popa
|
||||
# Remove errono etc.
|
||||
addl $8,%esp # Cleans up the pushed error code and pushed ISR number
|
||||
sti
|
||||
# return to program
|
||||
iret # pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
|
||||
.global __task_entry_point_inner
|
||||
__task_entry_point_inner:
|
||||
add $8, %esp # Remove useresp and ss (only exists in user space)
|
||||
call task_entry_point
|
||||
.global switch_task
|
||||
switch_task:
|
||||
movl 4(%esp), %eax
|
||||
movl 8(%esp), %edx
|
||||
test %eax, %eax
|
||||
jz _st_no_store
|
||||
pushl %ebp
|
||||
pushl %ebx
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
movl %esp, (%eax)
|
||||
_st_no_store:
|
||||
movl %edx, %esp
|
||||
popl %edi
|
||||
popl %esi
|
||||
popl %ebx
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
|
||||
|
||||
131
kernel/tasks/task.c
Normal file
131
kernel/tasks/task.c
Normal file
@@ -0,0 +1,131 @@
|
||||
//
|
||||
// Created by rick on 22-02-21.
|
||||
//
|
||||
|
||||
#include "task.h"
|
||||
#include <cpu/cpu.h>
|
||||
#include <stdbool.h>
|
||||
#include <libc/libc.h>
|
||||
#include <mem/malloc.h>
|
||||
#include <mem/pmm.h>
|
||||
|
||||
#include <attributes.h>
|
||||
|
||||
#define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE))
|
||||
|
||||
typedef struct task {
|
||||
bool present: 1;
|
||||
uint8_t wait_irq: 4;
|
||||
|
||||
uint32_t tid;
|
||||
|
||||
struct task *next;
|
||||
|
||||
void* stack;
|
||||
uint32_t stack_page_count;
|
||||
|
||||
task_registers_t *task_registers;
|
||||
} task_t;
|
||||
|
||||
typedef struct {
|
||||
task_registers_t task_registers;
|
||||
isr_registers_t isr_registers;
|
||||
task_entrypoint entrypoint;
|
||||
void *entry_data;
|
||||
char alignment[4];
|
||||
} packed task_stack_start;
|
||||
|
||||
bool task_locked = false;
|
||||
|
||||
task_t *first_task = NULL;
|
||||
task_t *last_task = NULL;
|
||||
task_t *current_task = NULL;
|
||||
|
||||
uint32_t last_tid = 0;
|
||||
|
||||
extern switch_task(task_registers_t**, task_registers_t*);
|
||||
extern cdecl noreturn void __task_entry_point();
|
||||
extern noreturn void __task_entry_point_inner();
|
||||
// explicit cdecl calling convention
|
||||
void cdecl noreturn task_entry_point(task_entrypoint entrypoint, void *entry_data) {
|
||||
entrypoint(entry_data);
|
||||
// task_end_self();
|
||||
while (true); // halt
|
||||
}
|
||||
|
||||
void task_lock_acquire() {
|
||||
task_locked = true;
|
||||
}
|
||||
|
||||
void task_lock_free() {
|
||||
task_locked = false;
|
||||
}
|
||||
|
||||
void task_switch_next_inner(task_t *next_task) {
|
||||
if (task_locked) {
|
||||
return; // don't switch while the task is locked
|
||||
}
|
||||
if (next_task == current_task) {
|
||||
return;
|
||||
}
|
||||
task_t *previous_task = current_task;
|
||||
current_task = next_task;
|
||||
// switch task
|
||||
switch_task(previous_task == NULL ? NULL : &previous_task->task_registers, current_task->task_registers);
|
||||
}
|
||||
|
||||
void task_start_first() {
|
||||
task_switch_next_inner(first_task);
|
||||
}
|
||||
|
||||
void task_switch_next() {
|
||||
if (current_task == NULL) {
|
||||
return;
|
||||
}
|
||||
task_switch_next_inner(current_task->next == NULL ? first_task : current_task->next);
|
||||
}
|
||||
|
||||
uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) {
|
||||
task_t *new_task = malloc(sizeof(task_t));
|
||||
memset((uint8_t *) new_task, 0, sizeof(task_t));
|
||||
new_task->tid = last_tid++;
|
||||
|
||||
new_task->stack = pmm_get_pages(16);
|
||||
new_task->stack_page_count = 16;
|
||||
// todo check for null
|
||||
|
||||
|
||||
if (first_task == NULL) {
|
||||
// first task
|
||||
first_task = new_task;
|
||||
} else {
|
||||
last_task->next = new_task;
|
||||
}
|
||||
last_task = new_task;
|
||||
|
||||
// prepare stack
|
||||
// cdecl format
|
||||
task_stack_start* stack = (task_stack_start *) (stack_end(new_task) - sizeof(task_stack_start));
|
||||
memset((uint8_t *) stack, 0, sizeof(task_stack_start));
|
||||
// setup isr return frame
|
||||
stack->isr_registers.cs = 0x08; // todo proper gdt setup
|
||||
stack->isr_registers.ds = 0x10; // todo
|
||||
// stack->isr_registers.ss = 0x10; // todo
|
||||
|
||||
stack->isr_registers.eip = (uint32_t) __task_entry_point_inner;
|
||||
stack->isr_registers.eflags = 0x200;
|
||||
// setup task switch frame
|
||||
stack->task_registers.eip = (uint32_t) __task_entry_point;
|
||||
stack->task_registers.ebp = (uint32_t) stack_end(new_task);
|
||||
// setup entrypoint
|
||||
stack->entrypoint = entrypoint;
|
||||
stack->entry_data = entry_data;
|
||||
|
||||
new_task->task_registers = &stack->task_registers;
|
||||
|
||||
new_task->present = true;
|
||||
return new_task->tid;
|
||||
}
|
||||
|
||||
void task_end(uint32_t pid) {
|
||||
}
|
||||
24
kernel/tasks/task.h
Normal file
24
kernel/tasks/task.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// Created by rick on 22-02-21.
|
||||
//
|
||||
|
||||
#ifndef NEW_KERNEL_TASK_H
|
||||
#define NEW_KERNEL_TASK_H
|
||||
|
||||
#include <cpu/cpu.h>
|
||||
|
||||
typedef void (*task_entrypoint)(void *entry_data);
|
||||
|
||||
void task_start_first();
|
||||
|
||||
void task_switch_next();
|
||||
|
||||
uint32_t task_spawn(task_entrypoint, void *entry_data);
|
||||
|
||||
void task_end(uint32_t pid);
|
||||
|
||||
void task_lock_acquire();
|
||||
|
||||
void task_lock_free();
|
||||
|
||||
#endif //NEW_KERNEL_TASK_H
|
||||
@@ -9,7 +9,7 @@ SECTIONS
|
||||
/* Begin putting sections at 1 MiB, a conventional place for kernels to be
|
||||
loaded at by the bootloader. */
|
||||
. = 1M;
|
||||
kernel_start = .;
|
||||
_kernel_start = .;
|
||||
|
||||
/* First put the multiboot header, as it is required to be put very early
|
||||
early in the image or the bootloader won't recognize the file format.
|
||||
@@ -38,6 +38,7 @@ SECTIONS
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
_kernel_end = .;
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
nohup qemu-system-i386 -S -s -kernel cmake-build-debug/my-kernel.bin -hda tmp.img -d guest_errors,int -m 1G > /dev/null &
|
||||
nohup qemu-system-i386 -cpu max -S -s -kernel cmake-build-debug/my-kernel.bin -hda tmp.img -d guest_errors,int -m 1G > /dev/null &
|
||||
disown
|
||||
|
||||
Reference in New Issue
Block a user