feat: introduced tasking, added paging (no vm), moved malloc, added

syscalls, other stuff
This commit is contained in:
2021-02-27 11:46:26 +01:00
parent 8f615b259c
commit 9f72d4bb1a
42 changed files with 907 additions and 292 deletions

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.15) cmake_minimum_required(VERSION 3.15)
project(new_kernel C ASM) project(new_kernel C ASM)
#set(CMAKE_VERBOSE_MAKEFILE ON) #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_NASM_OBJECT_FORMAT "elf")
set(CMAKE_ASM_FLAGS --32) set(CMAKE_ASM_FLAGS --32)
#set(CMAKE_ASM-ATT_FLAGS --32) #set(CMAKE_ASM-ATT_FLAGS --32)

View File

@@ -92,6 +92,11 @@ _start:
*/ */
cli cli
lgdt (gdtr) 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 ljmp $0x8, $continue_boot
continue_boot: continue_boot:

16
kernel/attributes.h Normal file
View 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
View 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
View 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
View 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

View File

@@ -4,3 +4,30 @@
#include "cpuidx.h" #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("");
}

View File

@@ -5,10 +5,76 @@
#ifndef NEW_KERNEL_CPUIDX_H #ifndef NEW_KERNEL_CPUIDX_H
#define NEW_KERNEL_CPUIDX_H #define NEW_KERNEL_CPUIDX_H
#include <cpuid.h> #include <stdbool.h>
#include <stdint.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_SSE3 = 1 << 0,
CPUID_FEAT_ECX_PCLMUL = 1 << 1, CPUID_FEAT_ECX_PCLMUL = 1 << 1,
CPUID_FEAT_ECX_DTES64 = 1 << 2, CPUID_FEAT_ECX_DTES64 = 1 << 2,
@@ -68,16 +134,6 @@ enum {
CPUID_FEAT_EDX_PBE = 1 << 31 CPUID_FEAT_EDX_PBE = 1 << 31
}; };
static inline void cpuid(int code, uint32_t *a, uint32_t *d) { void cpuidx_print_info();
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];
}
#endif //NEW_KERNEL_CPUIDX_H #endif //NEW_KERNEL_CPUIDX_H

View File

@@ -5,6 +5,8 @@
#ifndef MY_KERNEL_IDT_H #ifndef MY_KERNEL_IDT_H
#define MY_KERNEL_IDT_H #define MY_KERNEL_IDT_H
#include <attributes.h>
#define KERNEL_CS 0x08 #define KERNEL_CS 0x08
/* How every interrupt gate (handler) is defined */ /* How every interrupt gate (handler) is defined */
@@ -19,12 +21,12 @@ typedef struct {
* Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */ * Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */
uint8_t flags; uint8_t flags;
uint16_t high_offset; /* Higher 16 bits of handler function address */ uint16_t high_offset; /* Higher 16 bits of handler function address */
} __attribute__((packed)) idt_gate_t; } packed idt_gate_t;
typedef struct { typedef struct {
uint16_t limit; uint16_t limit;
uint32_t base; uint32_t base;
} __attribute__((packed)) idt_register_t; } packed idt_register_t;
#define IDT_REGISTERS 256 #define IDT_REGISTERS 256

View File

@@ -109,6 +109,8 @@ irq_common_stub:
.global irq14 .global irq14
.global irq15 .global irq15
.global isr128
# 0: Divide By Zero Exception # 0: Divide By Zero Exception
isr0: isr0:
cli cli
@@ -424,3 +426,9 @@ irq15:
push $47 push $47
jmp irq_common_stub jmp irq_common_stub
# Syscall
isr128:
cli
push $0
push $128
jmp isr_common_stub

View File

@@ -5,9 +5,11 @@
#include "isr.h" #include "isr.h"
#include <cpu/idt.h> #include <cpu/idt.h>
#include <cpu/syscall_handler.h>
#include <libc/libc.h> #include <libc/libc.h>
#include <drivers/ports.h> #include <drivers/ports.h>
#include <libc/kprintf.h> #include <libc/kprintf.h>
#include <libk.h>
#define PIC_END_OF_INTERRUPT 0x20 #define PIC_END_OF_INTERRUPT 0x20
@@ -48,6 +50,7 @@ void isr_install() {
set_idt_gate(31, (uint32_t) isr31); set_idt_gate(31, (uint32_t) isr31);
// Remap the PIC // Remap the PIC
// todo make readable
port_byte_out(0x20, 0x11); port_byte_out(0x20, 0x11);
port_byte_out(0xA0, 0x11); port_byte_out(0xA0, 0x11);
port_byte_out(0x21, 0x20); port_byte_out(0x21, 0x20);
@@ -77,6 +80,8 @@ void isr_install() {
set_idt_gate(46, (uint32_t) irq14); set_idt_gate(46, (uint32_t) irq14);
set_idt_gate(47, (uint32_t) irq15); set_idt_gate(47, (uint32_t) irq15);
set_idt_gate(128, (uint32_t) isr128);
set_idt(); // Load with ASM set_idt(); // Load with ASM
} }
@@ -118,15 +123,20 @@ char *exception_messages[] = {
"Reserved" "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]); 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) { void register_interrupt_handler(uint8_t n, isr_t handler) {
interrupt_handlers[n] = 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 /* After every interrupt we need to send an EOI to the PICs
* or they will not send another interrupt again */ * 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 */ 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 */ /* Handle the interrupt in a more modular way */
if (interrupt_handlers[r.int_no] != NULL) { if (interrupt_handlers[r.int_no] != NULL) {
isr_t handler = interrupt_handlers[r.int_no]; isr_t handler = interrupt_handlers[r.int_no];
handler(r); handler(&r);
} }
} }

View File

@@ -7,6 +7,8 @@
#ifndef MY_KERNEL_ISR_H #ifndef MY_KERNEL_ISR_H
#define MY_KERNEL_ISR_H #define MY_KERNEL_ISR_H
#include <cpu/cpu.h>
/* ISRs reserved for CPU exceptions */ /* ISRs reserved for CPU exceptions */
extern void isr0(); extern void isr0();
@@ -105,6 +107,8 @@ extern void irq14();
extern void irq15(); extern void irq15();
extern void isr128();
#define IRQ0 32 #define IRQ0 32
#define IRQ1 33 #define IRQ1 33
#define IRQ2 34 #define IRQ2 34
@@ -122,19 +126,12 @@ extern void irq15();
#define IRQ14 46 #define IRQ14 46
#define IRQ15 47 #define IRQ15 47
typedef struct { typedef void (*isr_t)(isr_registers_t*);
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);
void register_interrupt_handler(uint8_t n, isr_t handler); void register_interrupt_handler(uint8_t n, isr_t handler);
void isr_install(); void isr_install();
void isr_handler(registers_t r); void isr_handler(isr_registers_t r);
#endif //MY_KERNEL_ISR_H #endif //MY_KERNEL_ISR_H

View 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;
}
}

View 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

View File

@@ -9,6 +9,7 @@
#include <libc/libc.h> #include <libc/libc.h>
#include <libk.h> #include <libk.h>
#include <kprint.h> #include <kprint.h>
#include <tasks/task.h>
// https://wiki.osdev.org/PIT // https://wiki.osdev.org/PIT
#define PIT_MODE_BIN_BCD (1 << 0) #define PIT_MODE_BIN_BCD (1 << 0)
@@ -34,8 +35,13 @@
uint32_t tick = 0; uint32_t tick = 0;
static void timer_callback(registers_t regs) { static void timer_callback(isr_registers_t *regs) {
tick++; tick++;
task_switch_next();
}
uint32_t timer_get_tick() {
return tick;
} }
void sleep(uint32_t milliseconds) { void sleep(uint32_t milliseconds) {

View File

@@ -11,6 +11,8 @@ int init_timer(uint32_t freq);
void print_current_tick(); void print_current_tick();
uint32_t timer_get_tick();
void sleep(uint32_t milliseconds); void sleep(uint32_t milliseconds);
#endif //MY_KERNEL_TIMER_H #endif //MY_KERNEL_TIMER_H

View File

@@ -13,7 +13,7 @@
#include <cpu/timer.h> #include <cpu/timer.h>
#include <libc/kprintf.h> #include <libc/kprintf.h>
#include <fs/blockdev.h> #include <fs/blockdev.h>
#include <mem/mem.h> #include <mem/malloc.h>
#define ATA_SR_BSY 0x80 // Busy #define ATA_SR_BSY 0x80 // Busy
#define ATA_SR_DRDY 0x40 // Drive ready #define ATA_SR_DRDY 0x40 // Drive ready

View File

@@ -6,8 +6,8 @@
#include <drivers/ports.h> #include <drivers/ports.h>
#include <cpu/isr.h> #include <cpu/isr.h>
#include <libc/ringqueue.h> #include <libc/ringqueue.h>
#include <mem/mem.h>
#include <libk.h> #include <libk.h>
#include <mem/malloc.h>
const char scancode_map_lowercase[] = { const char scancode_map_lowercase[] = {
@@ -119,7 +119,7 @@ void publish_key_event(unsigned char scan_code) {
ring_buffer_put(keyboard_event_buffer, &event); 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); unsigned char status = port_byte_in(PORT_PS2_STATUS);
// check if data available // check if data available
if ((status & 0b00000001) == 0) { if ((status & 0b00000001) == 0) {

View File

@@ -4,8 +4,8 @@
#include <libc/libc.h> #include <libc/libc.h>
#include <libk.h> #include <libk.h>
#include <mem/mem.h>
#include <libc/kprintf.h> #include <libc/kprintf.h>
#include <mem/malloc.h>
#include "blockdev.h" #include "blockdev.h"
#define MAX_BLOCK_DEVS 64 #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; 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; return BLOCK_DEV_REGISTER_DRIVER_OK;
} }

View File

@@ -8,7 +8,8 @@
#include <types.h> #include <types.h>
#include <libc/libc.h> #include <libc/libc.h>
#include <libc/kprintf.h> #include <libc/kprintf.h>
#include <mem/mem.h> #include <mem/malloc.h>
#include <attributes.h>
#define FAT_TYPE_12 1 #define FAT_TYPE_12 1
#define FAT_TYPE_16 2 #define FAT_TYPE_16 2
@@ -31,7 +32,7 @@ typedef struct {
uint16_t heads_sides; uint16_t heads_sides;
uint32_t hidden_sectors; uint32_t hidden_sectors;
uint32_t large_total_sectors; uint32_t large_total_sectors;
} __attribute((packed)) bpb; } packed bpb;
union { union {
struct { struct {
uint8_t drive_number; uint8_t drive_number;
@@ -40,7 +41,7 @@ typedef struct {
uint32_t serial; uint32_t serial;
uint8_t label[11]; uint8_t label[11];
uint8_t system_id[8]; uint8_t system_id[8];
} __attribute((packed)) ebr_12_16; } packed ebr_12_16;
struct { struct {
uint32_t sectors_per_fat; uint32_t sectors_per_fat;
uint16_t flags; uint16_t flags;
@@ -55,21 +56,21 @@ typedef struct {
uint32_t serial; uint32_t serial;
uint8_t label[11]; uint8_t label[11];
uint8_t system_id[8]; uint8_t system_id[8];
} __attribute((packed)) ebr_32; } packed ebr_32;
}; };
} __attribute((packed)) fat_bpb; } packed fat_bpb;
typedef struct { typedef struct {
uint8_t hours: 5; uint8_t hours: 5;
uint8_t minutes: 6; uint8_t minutes: 6;
uint8_t seconds: 5; uint8_t seconds: 5;
} __attribute((packed)) time_83; } packed time_83;
typedef struct { typedef struct {
uint8_t hours: 5; uint8_t hours: 5;
uint8_t minutes: 6; uint8_t minutes: 6;
uint8_t seconds: 5; uint8_t seconds: 5;
} __attribute((packed)) date_83; } packed date_83;
typedef struct { typedef struct {
union { union {
@@ -86,7 +87,7 @@ typedef struct {
date_83 last_mod_date; date_83 last_mod_date;
uint16_t low_first_cluster; uint16_t low_first_cluster;
uint32_t file_size; uint32_t file_size;
} __attribute((packed)) name_83; } packed name_83;
struct { struct {
uint8_t order; uint8_t order;
uint16_t text_1[5]; uint16_t text_1[5];
@@ -96,9 +97,9 @@ typedef struct {
uint16_t text_2[6]; uint16_t text_2[6];
uint16_t reserved; uint16_t reserved;
uint16_t text_3[2]; 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); 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 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 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_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 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); 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;
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; uint32_t fat_offset;
table_result result = { table_result result = {
.value = 0, .value = 0,

View File

@@ -5,10 +5,11 @@
#include "mbr.h" #include "mbr.h"
#include <types.h> #include <types.h>
#include <drivers/ide.h> #include <drivers/ide.h>
#include <mem/mem.h>
#include <libc/kprintf.h> #include <libc/kprintf.h>
#include <fs/blockdev.h> #include <fs/blockdev.h>
#include <libc/libc.h> #include <libc/libc.h>
#include <mem/malloc.h>
#include <attributes.h>
typedef struct { typedef struct {
uint8_t bootable; uint8_t bootable;
@@ -21,14 +22,14 @@ typedef struct {
uint16_t ending_cylinder: 10; uint16_t ending_cylinder: 10;
uint32_t start_lba; uint32_t start_lba;
uint32_t num_lbas; uint32_t num_lbas;
} __attribute((packed)) mbr_partition_table_entry; } packed mbr_partition_table_entry;
typedef struct { typedef struct {
uint32_t unique_id; uint32_t unique_id;
uint16_t reserved; uint16_t reserved;
mbr_partition_table_entry entries[4]; mbr_partition_table_entry entries[4];
uint8_t signature[2]; uint8_t signature[2];
} __attribute((packed)) mbr_table; } packed mbr_table;
typedef struct { typedef struct {
const block_device *device; const block_device *device;

View File

@@ -1,6 +1,4 @@
#include <drivers/ports.h>
#include <drivers/vgascreen.h> #include <drivers/vgascreen.h>
#include <libc/libc.h>
#include <cpu/isr.h> #include <cpu/isr.h>
#include <cpu/timer.h> #include <cpu/timer.h>
#include <drivers/keyboard.h> #include <drivers/keyboard.h>
@@ -8,8 +6,6 @@
#include <multiboot.h> #include <multiboot.h>
#include <drivers/serial.h> #include <drivers/serial.h>
#include <kprint.h> #include <kprint.h>
#include <libc/readline.h>
#include <libc/string.h>
#include <libk.h> #include <libk.h>
#include <drivers/pci.h> #include <drivers/pci.h>
#include <drivers/ide.h> #include <drivers/ide.h>
@@ -18,118 +14,22 @@
#include <fs/blockdev.h> #include <fs/blockdev.h>
#include <fs/fat.h> #include <fs/fat.h>
#include <stdbool.h> #include <stdbool.h>
#include <cpu/cpuidx.h>
#define BOOTLOADER_NAME_MAX_LENGTH 64 #include <mem/malloc.h>
#define CMDLINE_MAX_LENGTH 256 #include <tasks/task.h>
#include <syscall.h>
#include <command.h>
#include <attributes.h>
const int version_major = 0, const int version_major = 0,
version_minor = 0, version_minor = 0,
version_patch = 1; 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) { void init_mmap(multiboot_info_t *multiboot_info) {
if (multiboot_info->flags & (1 << 6)) { 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)); multiboot_info->mmap_length / sizeof(struct multiboot_mmap_entry));
malloc_init();
// todo fallback on other mechanisms? // todo fallback on other mechanisms?
} else { } else {
k_panics("mmap invalid!\n"); k_panics("mmap invalid!\n");
@@ -156,7 +56,7 @@ void init_block_devices() {
block_dev_scan_repeat(); block_dev_scan_repeat();
} }
void kmain(multiboot_info_t *multiboot_info) { void noreturn kmain(multiboot_info_t *multiboot_info) {
isr_install(); isr_install();
vga_clear_screen(); vga_clear_screen();
vga_clear_screen(' ', VGA_WHITE | (VGA_GRAY << VGA_SHIFT_BG)); vga_clear_screen(' ', VGA_WHITE | (VGA_GRAY << VGA_SHIFT_BG));
@@ -164,6 +64,8 @@ void kmain(multiboot_info_t *multiboot_info) {
serial_init(); serial_init();
kprint_register(serial_kprint); kprint_register(serial_kprint);
cpuidx_print_info();
store_bootloader_info(multiboot_info); store_bootloader_info(multiboot_info);
init_mmap(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); printf("Booted successfully v%d.%d.%d\n", version_major, version_minor, version_patch);
// enter main loop task_spawn(main_loop, NULL);
while (true) { syscall_start_scheduler();
main_loop();
}
}
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);
} }

View File

@@ -15,7 +15,7 @@ int memcpy(uint8_t *dst, const uint8_t *src, int amount) {
return 0; 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) { for (int i = 0; i < amount; ++i) {
dst[i] = data; dst[i] = data;
} }

View File

@@ -12,7 +12,7 @@
int memcpy(uint8_t *dst, const uint8_t *src, int amount); 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); char *itoa(int value, char *buffer, int base);

View File

@@ -6,8 +6,8 @@
#include <libc/libc.h> #include <libc/libc.h>
#include <types.h> #include <types.h>
#include <kprint.h> #include <kprint.h>
#include <mem/mem.h>
#include <drivers/keyboard.h> #include <drivers/keyboard.h>
#include <mem/malloc.h>
#define RESULT_SIZE 256 #define RESULT_SIZE 256

View File

@@ -4,7 +4,7 @@
#include "ringqueue.h" #include "ringqueue.h"
#include <libc/libc.h> #include <libc/libc.h>
#include <mem/mem.h> #include <mem/malloc.h>
#define calc_pos(buffer, index) ((buffer->object_size) * (index)) #define calc_pos(buffer, index) ((buffer->object_size) * (index))

View File

@@ -52,7 +52,7 @@ int strncmp(const char *s1, const char *s2, int n) {
if (s1[i] > s2[i]) { if (s1[i] > s2[i]) {
return -1; return -1;
} }
if (s2[i] < s1[i]) { if (s1[i] < s2[i]) {
return 1; return 1;
} }
} }

View File

@@ -2,9 +2,14 @@
// Created by rick on 02-02-21. // Created by rick on 02-02-21.
// //
#include <stdbool.h>
#include "libk.h" #include "libk.h"
#include "kprint.h" #include "kprint.h"
bool k_addr_in_kspace(void* addr) {
return addr > kernel_start && addr < kernel_end;
}
void k_wait_for_interrupt() { void k_wait_for_interrupt() {
__asm__ __volatile__("hlt;"); __asm__ __volatile__("hlt;");
} }

View File

@@ -4,6 +4,14 @@
#ifndef NEW_KERNEL_LIBK_H #ifndef NEW_KERNEL_LIBK_H
#define 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(); void k_wait_for_interrupt();

90
kernel/mem/malloc.c Normal file
View 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
View 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

View File

@@ -2,9 +2,12 @@
// Created by rick on 22-04-20. // Created by rick on 22-04-20.
// //
#include "pmm.h"
#include <types.h> #include <types.h>
#include <mem/mem.h> #include <mem/mem.h>
#include <libc/kprintf.h> #include <libc/kprintf.h>
#include <libk.h>
#include <attributes.h>
#define MEMMAP_ENTRIES 16 #define MEMMAP_ENTRIES 16
@@ -15,26 +18,13 @@
#define MMAP_TYPE_NVS 4 #define MMAP_TYPE_NVS 4
#define MMAP_TYPE_BADRAM 5 #define MMAP_TYPE_BADRAM 5
#define MMAP_TYPE_KERNEL 6 #define MMAP_TYPE_KERNEL 6
#define MMAP_TYPE_MALLOC 7 #define MMAP_TYPE_PAGING 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;
typedef struct { typedef struct {
void *address; uint32_t address;
uint32_t length; uint32_t length;
uint32_t type; uint32_t type;
} __attribute((packed)) mmap_entry; } packed mmap_entry;
int malloc_entries = 0;
int malloc_used = 0;
int last_memmap_entry = 0; int last_memmap_entry = 0;
mmap_entry memmap[MEMMAP_ENTRIES] = { mmap_entry memmap[MEMMAP_ENTRIES] = {
@@ -56,114 +46,51 @@ mmap_entry memmap[MEMMAP_ENTRIES] = {
{0, 0, 0}, {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) { void use_mmap_entry(struct multiboot_mmap_entry *entry) {
mmap_entry *mm_entry = &memmap[last_memmap_entry++]; mmap_entry *mm_entry = &memmap[last_memmap_entry++];
mm_entry->address = (void *) entry->addr; mm_entry->address = (void *) entry->addr;
mm_entry->length = entry->len; mm_entry->length = entry->len;
mm_entry->type = entry->type; 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 // check if the entry overlaps with the kernel address space
if (kernel_start >= mm_entry->address && kernel_start <= mm_entry->address + mm_entry->length) { 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 // todo make this something proper
struct multiboot_mmap_entry extra_entry; struct multiboot_mmap_entry extra_entry;
extra_entry.size = entry->size; extra_entry.size = entry->size;
extra_entry.type = entry->type; extra_entry.type = entry->type;
extra_entry.addr = entry->addr + kernel_size; extra_entry.addr = page_after_kernel;
extra_entry.len = entry->size - kernel_size; extra_entry.len = entry->size - kernel_size_full_pages;
use_mmap_entry(&extra_entry); use_mmap_entry(&extra_entry);
mm_entry->length = kernel_size; mm_entry->length = kernel_size_full_pages;
mm_entry->type = MMAP_TYPE_KERNEL; 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) { for (uint32_t i = 0; i < count; ++i) {
use_mmap_entry(&entries[i]); use_mmap_entry(&entries[i]);
} }
}
void split_malloc_map(malloc_map *entry, unsigned int size) { // init page manager
malloc_entries++; for (int i = 0; i < last_memmap_entry; ++i) {
malloc_map *new_entry = entry + sizeof(malloc_map) + size; mmap_entry *entry = &memmap[i];
new_entry->size = entry->size - size - sizeof(malloc_map); if (entry->type != MMAP_TYPE_AVAILABLE) {
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) {
continue; continue;
} }
// get first first_map of address if (entry->address < kernel_start) {
malloc_map *first_map = (malloc_map *) memmap[i].address; continue; // skip for now
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);
malloc_find_next: pmm_init((void *) entry->address, entry->length);
current_map = current_map->next; entry->type = MMAP_TYPE_PAGING;
} while (current_map != first_map);
} }
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() { void print_mmap_info() {
printf("Kernel start: %8x\n"
"Kernel end: %8x\n", kernel_start, kernel_end);
for (int i = 0; i < 16; ++i) { for (int i = 0; i < 16; ++i) {
if (memmap[i].type == 0) { if (memmap[i].type == 0) {
break; break;

View File

@@ -7,14 +7,8 @@
#include <multiboot.h> #include <multiboot.h>
void init_mmap_multiboot(struct multiboot_mmap_entry *entries, uint32_t count); void mmap_init_multiboot(struct multiboot_mmap_entry *entries, uint32_t count);
void print_malloc_info();
void print_mmap_info(); void print_mmap_info();
void *malloc(size_t size);
void free(void *mem);
#endif //NEW_KERNEL_MEM_H #endif //NEW_KERNEL_MEM_H

98
kernel/mem/pmm.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@@ -9,7 +9,7 @@ SECTIONS
/* Begin putting sections at 1 MiB, a conventional place for kernels to be /* Begin putting sections at 1 MiB, a conventional place for kernels to be
loaded at by the bootloader. */ loaded at by the bootloader. */
. = 1M; . = 1M;
kernel_start = .; _kernel_start = .;
/* First put the multiboot header, as it is required to be put very early /* 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. early in the image or the bootloader won't recognize the file format.
@@ -38,6 +38,7 @@ SECTIONS
*(COMMON) *(COMMON)
*(.bss) *(.bss)
} }
_kernel_end = .;
/DISCARD/ : { /DISCARD/ : {
*(.eh_frame); *(.eh_frame);

View File

@@ -1,3 +1,3 @@
#!/bin/bash #!/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 disown