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)
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)

View File

@@ -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
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 <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
#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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

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 <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) {

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

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

View File

@@ -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,

View File

@@ -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;

View File

@@ -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();
}
}
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);
task_spawn(main_loop, NULL);
syscall_start_scheduler();
}

View File

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

View File

@@ -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);

View File

@@ -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

View File

@@ -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))

View File

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

View File

@@ -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;");
}

View File

@@ -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
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.
//
#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;

View File

@@ -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
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
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);

View File

@@ -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