diff --git a/CMakeLists.txt b/CMakeLists.txt index e8ee838..fa77148 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/boot/boot.S b/boot/boot.S index 7626dbc..7fdd074 100644 --- a/boot/boot.S +++ b/boot/boot.S @@ -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: diff --git a/kernel/attributes.h b/kernel/attributes.h new file mode 100644 index 0000000..02b18ca --- /dev/null +++ b/kernel/attributes.h @@ -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 diff --git a/kernel/command.c b/kernel/command.c new file mode 100644 index 0000000..d994173 --- /dev/null +++ b/kernel/command.c @@ -0,0 +1,144 @@ +// +// Created by rick on 23-02-21. +// + +#include "command.h" +#include "kprint.h" +#include "libk.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); + } +} diff --git a/kernel/command.h b/kernel/command.h new file mode 100644 index 0000000..d5b97cd --- /dev/null +++ b/kernel/command.h @@ -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 diff --git a/kernel/cpu/cpu.h b/kernel/cpu/cpu.h new file mode 100644 index 0000000..130ded5 --- /dev/null +++ b/kernel/cpu/cpu.h @@ -0,0 +1,20 @@ +// +// Created by rick on 22-02-21. +// + +#ifndef NEW_KERNEL_CPU_H +#define NEW_KERNEL_CPU_H +#include + +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 diff --git a/kernel/cpu/cpuidx.c b/kernel/cpu/cpuidx.c index 3a00b1f..d381ea7 100644 --- a/kernel/cpu/cpuidx.c +++ b/kernel/cpu/cpuidx.c @@ -4,3 +4,30 @@ #include "cpuidx.h" +#include +#include +#include + +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(""); + + +} diff --git a/kernel/cpu/cpuidx.h b/kernel/cpu/cpuidx.h index 3a418da..46b07f3 100644 --- a/kernel/cpu/cpuidx.h +++ b/kernel/cpu/cpuidx.h @@ -5,10 +5,76 @@ #ifndef NEW_KERNEL_CPUIDX_H #define NEW_KERNEL_CPUIDX_H -#include -#include +#include -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 diff --git a/kernel/cpu/idt.h b/kernel/cpu/idt.h index 669e6a0..91346db 100644 --- a/kernel/cpu/idt.h +++ b/kernel/cpu/idt.h @@ -5,6 +5,8 @@ #ifndef MY_KERNEL_IDT_H #define MY_KERNEL_IDT_H +#include + #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 diff --git a/kernel/cpu/interrupt.S b/kernel/cpu/interrupt.S index b2550db..05a11e0 100644 --- a/kernel/cpu/interrupt.S +++ b/kernel/cpu/interrupt.S @@ -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 diff --git a/kernel/cpu/isr.c b/kernel/cpu/isr.c index a5db213..e3b4f07 100644 --- a/kernel/cpu/isr.c +++ b/kernel/cpu/isr.c @@ -5,9 +5,11 @@ #include "isr.h" #include +#include #include #include #include +#include #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); } } \ No newline at end of file diff --git a/kernel/cpu/isr.h b/kernel/cpu/isr.h index 22d7837..4129708 100644 --- a/kernel/cpu/isr.h +++ b/kernel/cpu/isr.h @@ -7,6 +7,8 @@ #ifndef MY_KERNEL_ISR_H #define MY_KERNEL_ISR_H +#include + /* 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 diff --git a/kernel/cpu/syscall_handler.c b/kernel/cpu/syscall_handler.c new file mode 100644 index 0000000..5033675 --- /dev/null +++ b/kernel/cpu/syscall_handler.c @@ -0,0 +1,20 @@ +// +// Created by rick on 24-02-21. +// + +#include "syscall_handler.h" +#include +#include + +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; + } +} diff --git a/kernel/cpu/syscall_handler.h b/kernel/cpu/syscall_handler.h new file mode 100644 index 0000000..508667e --- /dev/null +++ b/kernel/cpu/syscall_handler.h @@ -0,0 +1,11 @@ +// +// Created by rick on 24-02-21. +// + +#ifndef NEW_KERNEL_SYSCALL_HANDLER_H +#define NEW_KERNEL_SYSCALL_HANDLER_H +#include + +void syscall_handle(isr_registers_t *registers); + +#endif //NEW_KERNEL_SYSCALL_HANDLER_H diff --git a/kernel/cpu/timer.c b/kernel/cpu/timer.c index 3608ab9..712f2eb 100644 --- a/kernel/cpu/timer.c +++ b/kernel/cpu/timer.c @@ -9,6 +9,7 @@ #include #include #include +#include // 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) { diff --git a/kernel/cpu/timer.h b/kernel/cpu/timer.h index 076ffdc..1b493c4 100644 --- a/kernel/cpu/timer.h +++ b/kernel/cpu/timer.h @@ -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 diff --git a/kernel/drivers/ide.c b/kernel/drivers/ide.c index 5863655..96f1253 100644 --- a/kernel/drivers/ide.c +++ b/kernel/drivers/ide.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #define ATA_SR_BSY 0x80 // Busy #define ATA_SR_DRDY 0x40 // Drive ready diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c index f018efa..da0f175 100644 --- a/kernel/drivers/keyboard.c +++ b/kernel/drivers/keyboard.c @@ -6,8 +6,8 @@ #include #include #include -#include #include +#include 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) { diff --git a/kernel/fs/blockdev.c b/kernel/fs/blockdev.c index 62dbf7a..2ee4b17 100644 --- a/kernel/fs/blockdev.c +++ b/kernel/fs/blockdev.c @@ -4,8 +4,8 @@ #include #include -#include #include +#include #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; } diff --git a/kernel/fs/fat.c b/kernel/fs/fat.c index f630e93..b57034d 100644 --- a/kernel/fs/fat.c +++ b/kernel/fs/fat.c @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #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, diff --git a/kernel/fs/mbr.c b/kernel/fs/mbr.c index 6d2a479..28a784d 100644 --- a/kernel/fs/mbr.c +++ b/kernel/fs/mbr.c @@ -5,10 +5,11 @@ #include "mbr.h" #include #include -#include #include #include #include +#include +#include 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; diff --git a/kernel/kernel.c b/kernel/kernel.c index bc51d1f..97cc0d0 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -1,6 +1,4 @@ -#include #include -#include #include #include #include @@ -8,8 +6,6 @@ #include #include #include -#include -#include #include #include #include @@ -18,118 +14,22 @@ #include #include #include - -#define BOOTLOADER_NAME_MAX_LENGTH 64 -#define CMDLINE_MAX_LENGTH 256 +#include +#include +#include +#include +#include +#include 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); -} \ No newline at end of file diff --git a/kernel/libc/libc.c b/kernel/libc/libc.c index c97cb58..9251bcd 100644 --- a/kernel/libc/libc.c +++ b/kernel/libc/libc.c @@ -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; } diff --git a/kernel/libc/libc.h b/kernel/libc/libc.h index a6b3a02..2fe3c76 100644 --- a/kernel/libc/libc.h +++ b/kernel/libc/libc.h @@ -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); diff --git a/kernel/libc/readline.c b/kernel/libc/readline.c index 612a619..00a24cc 100644 --- a/kernel/libc/readline.c +++ b/kernel/libc/readline.c @@ -6,8 +6,8 @@ #include #include #include -#include #include +#include #define RESULT_SIZE 256 diff --git a/kernel/libc/ringqueue.c b/kernel/libc/ringqueue.c index 7049827..ee75408 100644 --- a/kernel/libc/ringqueue.c +++ b/kernel/libc/ringqueue.c @@ -4,7 +4,7 @@ #include "ringqueue.h" #include -#include +#include #define calc_pos(buffer, index) ((buffer->object_size) * (index)) diff --git a/kernel/libc/string.c b/kernel/libc/string.c index e266212..3b6e0b8 100644 --- a/kernel/libc/string.c +++ b/kernel/libc/string.c @@ -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; } } diff --git a/kernel/libk.c b/kernel/libk.c index c9ae24e..373ac2e 100644 --- a/kernel/libk.c +++ b/kernel/libk.c @@ -2,9 +2,14 @@ // Created by rick on 02-02-21. // +#include #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;"); } diff --git a/kernel/libk.h b/kernel/libk.h index 7d5878a..17c0213 100644 --- a/kernel/libk.h +++ b/kernel/libk.h @@ -4,6 +4,14 @@ #ifndef NEW_KERNEL_LIBK_H #define NEW_KERNEL_LIBK_H +#include + +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(); diff --git a/kernel/mem/malloc.c b/kernel/mem/malloc.c new file mode 100644 index 0000000..4047257 --- /dev/null +++ b/kernel/mem/malloc.c @@ -0,0 +1,90 @@ +// +// Created by rick on 23-02-21. +// + +#include +#include +#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); +} + diff --git a/kernel/mem/malloc.h b/kernel/mem/malloc.h new file mode 100644 index 0000000..eb7e3ee --- /dev/null +++ b/kernel/mem/malloc.h @@ -0,0 +1,17 @@ +// +// Created by rick on 23-02-21. +// + +#ifndef NEW_KERNEL_MALLOC_H +#define NEW_KERNEL_MALLOC_H +#include + +void malloc_init(); + +void print_malloc_info(); + +void *malloc(size_t size); + +void free(void *mem); + +#endif //NEW_KERNEL_MALLOC_H diff --git a/kernel/mem/mem.c b/kernel/mem/mem.c index 03a7131..b23ce5c 100644 --- a/kernel/mem/mem.c +++ b/kernel/mem/mem.c @@ -2,9 +2,12 @@ // Created by rick on 22-04-20. // +#include "pmm.h" #include #include #include +#include +#include #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; diff --git a/kernel/mem/mem.h b/kernel/mem/mem.h index 21af4b8..14226ab 100644 --- a/kernel/mem/mem.h +++ b/kernel/mem/mem.h @@ -7,14 +7,8 @@ #include -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 diff --git a/kernel/mem/pmm.c b/kernel/mem/pmm.c new file mode 100644 index 0000000..b64347f --- /dev/null +++ b/kernel/mem/pmm.c @@ -0,0 +1,98 @@ +// +// Created by rick on 23-02-21. +// + +#include +#include +#include +#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); + } + } +} diff --git a/kernel/mem/pmm.h b/kernel/mem/pmm.h new file mode 100644 index 0000000..ba6d34d --- /dev/null +++ b/kernel/mem/pmm.h @@ -0,0 +1,16 @@ +// +// Created by rick on 23-02-21. +// + +#ifndef NEW_KERNEL_PMM_H +#define NEW_KERNEL_PMM_H +#include + +// 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 diff --git a/kernel/syscall.c b/kernel/syscall.c new file mode 100644 index 0000000..ba32da2 --- /dev/null +++ b/kernel/syscall.c @@ -0,0 +1,22 @@ +// +// Created by rick on 22-02-21. +// + +#include "syscall.h" +#include +#include + +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"); }; +} \ No newline at end of file diff --git a/kernel/syscall.h b/kernel/syscall.h new file mode 100644 index 0000000..3fd5c32 --- /dev/null +++ b/kernel/syscall.h @@ -0,0 +1,17 @@ +// +// Created by rick on 22-02-21. +// + +#ifndef NEW_KERNEL_SYSCALL_H +#define NEW_KERNEL_SYSCALL_H + +#include + +#define SYSCALL_START_SCHEDULER 0x01 +#define SYSCALL_YIELD_JOB 0x02 + +void syscall_yield_job(); + +void noreturn syscall_start_scheduler(); + +#endif //NEW_KERNEL_SYSCALL_H diff --git a/kernel/tasks/task.S b/kernel/tasks/task.S new file mode 100644 index 0000000..974b521 --- /dev/null +++ b/kernel/tasks/task.S @@ -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 + + + diff --git a/kernel/tasks/task.c b/kernel/tasks/task.c new file mode 100644 index 0000000..0a90a6e --- /dev/null +++ b/kernel/tasks/task.c @@ -0,0 +1,131 @@ +// +// Created by rick on 22-02-21. +// + +#include "task.h" +#include +#include +#include +#include +#include + +#include + +#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) { +} diff --git a/kernel/tasks/task.h b/kernel/tasks/task.h new file mode 100644 index 0000000..2774097 --- /dev/null +++ b/kernel/tasks/task.h @@ -0,0 +1,24 @@ +// +// Created by rick on 22-02-21. +// + +#ifndef NEW_KERNEL_TASK_H +#define NEW_KERNEL_TASK_H + +#include + +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 diff --git a/linker.ld b/linker.ld index 01adc88..654b1be 100644 --- a/linker.ld +++ b/linker.ld @@ -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); diff --git a/qemu-debug.sh b/qemu-debug.sh index 7bb6299..f43f94e 100755 --- a/qemu-debug.sh +++ b/qemu-debug.sh @@ -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