commit d7f0e8dd3639081ddfe4714ebae31de3010bb8bc Author: Rick Rongen Date: Thu Jan 28 22:59:39 2021 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f161ad5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,114 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/cmake,jetbrains+all +# Edit at https://www.toptal.com/developers/gitignore?templates=cmake,jetbrains+all + +### CMake ### +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +CMakeUserPresets.json + +### CMake Patch ### +# External projects +*-prefix/ + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin +.idea/sonarlint + +# End of https://www.toptal.com/developers/gitignore/api/cmake,jetbrains+all + +*.old \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e25c6fc --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.15) +project(new_kernel C ASM) +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_C_FLAGS "-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) +SET(CMAKE_EXE_LINKER_FLAGS "-T${CMAKE_CURRENT_LIST_DIR}/linker.ld -lgcc -ffreestanding -nostdlib") +set(CMAKE_ASM_COMPILER "/usr/bin/as") +#ENABLE_LANGUAGE(ASM_NASM) +#enable_language(ASM) + +include_directories(AFTER kernel boot) + +set(CMAKE_C_STANDARD 99) + +FILE(GLOB_RECURSE kernel_src kernel/**.c) +FILE(GLOB_RECURSE kernel_asm kernel/**.S) +FILE(GLOB_RECURSE boot_asm boot/boot.S) + +add_executable(my-kernel.bin ${kernel_src} ${kernel_asm} ${boot_asm}) +set_source_files_properties(${kernel_src} PROPERTIES LANGUAGE C COMPILE_FLAGS "") +set_target_properties(my-kernel.bin PROPERTIES LINKER_LANGUAGE C PREFIX "" SUFFIX "" LINK_FLAGS "") + + diff --git a/boot/boot.S b/boot/boot.S new file mode 100644 index 0000000..7626dbc --- /dev/null +++ b/boot/boot.S @@ -0,0 +1,130 @@ +/* Declare constants for the multiboot header. */ +.set ALIGN, 1<<0 /* align loaded modules on page boundaries */ +.set MEMINFO, 1<<1 /* provide memory map */ +.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */ +.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */ +.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */ + +/* +Declare a multiboot header that marks the program as a kernel. These are magic +values that are documented in the multiboot standard. The bootloader will +search for this signature in the first 8 KiB of the kernel file, aligned at a +32-bit boundary. The signature is in its own section so the header can be +forced to be within the first 8 KiB of the kernel file. +*/ +.section .multiboot +.align 4 +.long MAGIC +.long FLAGS +.long CHECKSUM + +#.include "gdt.S" +.section .data +gdt: +.quad 0x0000000000000000 +.quad 0x00CF9A000000FFFF +.quad 0x00CF92000000FFFF +.quad 0x00CFFA000000FFFF +.quad 0x00CFF2000000FFFF + +gdtr: + .word 40 + .long gdt # For base storage +/* +The multiboot standard does not define the value of the stack pointer register +(esp) and it is up to the kernel to provide a stack. This allocates room for a +small stack by creating a symbol at the bottom of it, then allocating 16384 +bytes for it, and finally creating a symbol at the top. The stack grows +downwards on x86. The stack is in its own section so it can be marked nobits, +which means the kernel file is smaller because it does not contain an +uninitialized stack. The stack on x86 must be 16-byte aligned according to the +System V ABI standard and de-facto extensions. The compiler will assume the +stack is properly aligned and failure to align the stack will result in +undefined behavior. +*/ +.section .bss +.align 16 +stack_bottom: +.skip 16384 # 16 KiB +stack_top: + +/* +The linker script specifies _start as the entry point to the kernel and the +bootloader will jump to this position once the kernel has been loaded. It +doesn't make sense to return from this function as the bootloader is gone. +*/ +.section .text +.global _start +.type _start, @function +_start: + /* + The bootloader has loaded us into 32-bit protected mode on a x86 + machine. Interrupts are disabled. Paging is disabled. The processor + state is as defined in the multiboot standard. The kernel has full + control of the CPU. The kernel can only make use of hardware features + and any code it provides as part of itself. There's no printf + function, unless the kernel provides its own header and a + printf implementation. There are no security restrictions, no + safeguards, no debugging mechanisms, only what the kernel provides + itself. It has absolute and complete power over the + machine. + */ + + /* + To set up a stack, we set the esp register to point to the top of the + stack (as it grows downwards on x86 systems). This is necessarily done + in assembly as languages such as C cannot function without a stack. + */ + mov $stack_top, %esp + + // store multiboot on stack + pushl %ebx + + /* + This is a good place to initialize crucial processor state before the + high-level kernel is entered. It's best to minimize the early + environment where crucial features are offline. Note that the + processor is not fully initialized yet: Features such as floating + point instructions and instruction set extensions are not initialized + yet. The GDT should be loaded here. Paging should be enabled here. + C++ features such as global constructors and exceptions will require + runtime support to work as well. + */ + cli + lgdt (gdtr) + ljmp $0x8, $continue_boot + +continue_boot: + sti + /* + Enter the high-level kernel. The ABI requires the stack is 16-byte + aligned at the time of the call instruction (which afterwards pushes + the return pointer of size 4 bytes). The stack was originally 16-byte + aligned above and we've pushed a multiple of 16 bytes to the + stack since (pushed 0 bytes so far), so the alignment has thus been + preserved and the call is well defined. + */ + // top of stack is multiboot object + call kmain + + /* + If the system has nothing more to do, put the computer into an + infinite loop. To do that: + 1) Disable interrupts with cli (clear interrupt enable in eflags). + They are already disabled by the bootloader, so this is not needed. + Mind that you might later enable interrupts and return from + kernel_main (which is sort of nonsensical to do). + 2) Wait for the next interrupt to arrive with hlt (halt instruction). + Since they are disabled, this will lock up the computer. + 3) Jump to the hlt instruction if it ever wakes up due to a + non-maskable interrupt occurring or due to system management mode. + */ + cli +1: #hlt + jmp 1b + +/* +Set the size of the _start symbol to the current location '.' minus its start. +This is useful when debugging or when you implement call tracing. +*/ +.size _start, . - _start diff --git a/boot/gdt.S b/boot/gdt.S new file mode 100644 index 0000000..fd6c2c2 --- /dev/null +++ b/boot/gdt.S @@ -0,0 +1,39 @@ +.section .data +gdt_start: # don't remove the labels, they're needed to compute sizes and jumps + # the GDT starts with a null 8-byte + .long 0x0 # 4 byte + .long 0x0 # 4 byte + +# GDT for code segment. base = 0x00000000, length = 0xfffff +# for flags, refer to os-dev.pdf document, page 36 +gdt_code: + .word 0xffff # segment length, bits 0-15 + .word 0x0 # segment base, bits 0-15 + .byte 0x0 # segment base, bits 16-23 + .byte 0b10011010 # flags (8 bits) + .byte 0b11001111 # flags (4 bits) + segment length, bits 16-19 + .byte 0x0 # segment base, bits 24-31 + +# GDT for data segment. base and length identical to code segment +# some flags changed, again, refer to os-dev.pdf +gdt_data: + .word 0xffff + .word 0x0 + .byte 0x0 + .byte 0b10010010 + .byte 0b11001111 + .byte 0x0 + +gdt_end: + +# GDT descriptor +gdt_descriptor: +.long gdt_end-gdt_start-1 +.long gdt_start +//MISMATCH: " dw gdt_end - gdt_start - 1 " +//MISMATCH: " dd gdt_start " + +# define some constants for later use +code_seg: .long gdt_code - gdt_start +data_seg: .long gdt_data - gdt_start + diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c new file mode 100644 index 0000000..a558d1b --- /dev/null +++ b/kernel/cpu/idt.c @@ -0,0 +1,23 @@ +// +// Created by rick on 8/18/19. +// + +#include "idt.h" + +idt_gate_t idt[IDT_REGISTERS]; +idt_register_t idt_reg; + +void set_idt_gate(int n, u32 handler) { + idt[n].low_offset = handler & 0xffff; + idt[n].sel = KERNEL_CS; + idt[n].always0 = 0; + idt[n].flags = 0x8E; + idt[n].high_offset = handler >> 16 & 0xFFFF; +} + +void set_idt() { + idt_reg.base = (u32) &idt; + idt_reg.limit = IDT_REGISTERS * sizeof(idt_gate_t) - 1; + + __asm__ __volatile__("lidtl (%0)" : : "r" (&idt_reg)); +} diff --git a/kernel/cpu/idt.h b/kernel/cpu/idt.h new file mode 100644 index 0000000..de9cbb2 --- /dev/null +++ b/kernel/cpu/idt.h @@ -0,0 +1,35 @@ +// +// Created by rick on 8/18/19. +// +#include "../types.h" + +#ifndef MY_KERNEL_IDT_H +#define MY_KERNEL_IDT_H +#define KERNEL_CS 0x08 + +/* How every interrupt gate (handler) is defined */ +typedef struct { + u16 low_offset; /* Lower 16 bits of handler function address */ + u16 sel; /* Kernel segment selector */ + u8 always0; + /* First byte + * Bit 7: "Interrupt is present" + * Bits 6-5: Privilege level of caller (0=kernel..3=user) + * Bit 4: Set to 0 for interrupt gates + * Bits 3-0: bits 1110 = decimal 14 = "32 bit interrupt gate" */ + u8 flags; + u16 high_offset; /* Higher 16 bits of handler function address */ +} __attribute__((packed)) idt_gate_t; + +typedef struct { + u16 limit; + u32 base; +} __attribute__((packed)) idt_register_t; + +#define IDT_REGISTERS 256 + +void set_idt_gate(int n, u32 handler); + +void set_idt(); + +#endif //MY_KERNEL_IDT_H diff --git a/kernel/cpu/interrupt.S b/kernel/cpu/interrupt.S new file mode 100644 index 0000000..b2550db --- /dev/null +++ b/kernel/cpu/interrupt.S @@ -0,0 +1,426 @@ +.code32 +# Defined in isr.c +#MISMATCH: "[extern isr_handler]" +#MISMATCH: "[extern irq_handler]" + +# Common ISR code +isr_common_stub: + # 1. Save CPU state + pusha # Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax + movw %ds,%ax # Lower 16-bits of eax = ds. + pushl %eax # save the data segment descriptor + movw $0x10,%ax # kernel data segment descriptor + movw %ax,%ds + movw %ax,%es + movw %ax,%fs + movw %ax,%gs + + # 2. Call C handler + call isr_handler + + # 3. Restore state + popl %eax + movw %ax,%ds + movw %ax,%es + movw %ax,%fs + movw %ax,%gs + popa + addl $8,%esp # Cleans up the pushed error code and pushed ISR number + sti + iret # pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP + +# Common IRQ code. Identical to ISR code except for the 'call' +# and the 'pop ebx' +irq_common_stub: + pusha + movw %ds,%ax + pushl %eax + movw $0x10,%ax + movw %ax,%ds + movw %ax,%es + movw %ax,%fs + movw %ax,%gs + call irq_handler # Different than the ISR code + popl %ebx # Different than the ISR code + movw %bx,%ds + movw %bx,%es + movw %bx,%fs + movw %bx,%gs + popa + addl $8,%esp + sti + iret + +# We don't get information about which interrupt was caller +# when the handler is run, so we will need to have a different handler +# for every interrupt. +# Furthermore, some interrupts push an error code onto the stack but others +# don't, so we will push a dummy error code for those which don't, so that +# we have a consistent stack for all of them. + +# First make the ISRs global +.global isr0 +.global isr1 +.global isr2 +.global isr3 +.global isr4 +.global isr5 +.global isr6 +.global isr7 +.global isr8 +.global isr9 +.global isr10 +.global isr11 +.global isr12 +.global isr13 +.global isr14 +.global isr15 +.global isr16 +.global isr17 +.global isr18 +.global isr19 +.global isr20 +.global isr21 +.global isr22 +.global isr23 +.global isr24 +.global isr25 +.global isr26 +.global isr27 +.global isr28 +.global isr29 +.global isr30 +.global isr31 + +.global irq0 +.global irq1 +.global irq2 +.global irq3 +.global irq4 +.global irq5 +.global irq6 +.global irq7 +.global irq8 +.global irq9 +.global irq10 +.global irq11 +.global irq12 +.global irq13 +.global irq14 +.global irq15 + +# 0: Divide By Zero Exception +isr0: + cli + push $0 + push $0 + jmp isr_common_stub + +# 1: Debug Exception +isr1: + cli + push $0 + push $1 + jmp isr_common_stub + +# 2: Non Maskable Interrupt Exception +isr2: + cli + push $0 + push $2 + jmp isr_common_stub + +# 3: Int 3 Exception +isr3: + cli + push $0 + push $3 + jmp isr_common_stub + +# 4: INTO Exception +isr4: + cli + push $0 + push $4 + jmp isr_common_stub + +# 5: Out of Bounds Exception +isr5: + cli + push $0 + push $5 + jmp isr_common_stub + +# 6: Invalid Opcode Exception +isr6: + cli + push $0 + push $6 + jmp isr_common_stub + +# 7: Coprocessor Not Available Exception +isr7: + cli + push $0 + push $7 + jmp isr_common_stub + +# 8: Double Fault Exception (With Error Code!) +isr8: + cli + push $8 + jmp isr_common_stub + +# 9: Coprocessor Segment Overrun Exception +isr9: + cli + push $0 + push $9 + jmp isr_common_stub + +# 10: Bad TSS Exception (With Error Code!) +isr10: + cli + push $10 + jmp isr_common_stub + +# 11: Segment Not Present Exception (With Error Code!) +isr11: + cli + push $11 + jmp isr_common_stub + +# 12: Stack Fault Exception (With Error Code!) +isr12: + cli + push $12 + jmp isr_common_stub + +# 13: General Protection Fault Exception (With Error Code!) +isr13: + cli + push $13 + jmp isr_common_stub + +# 14: Page Fault Exception (With Error Code!) +isr14: + cli + push $14 + jmp isr_common_stub + +# 15: Reserved Exception +isr15: + cli + push $0 + push $15 + jmp isr_common_stub + +# 16: Floating Point Exception +isr16: + cli + push $0 + push $16 + jmp isr_common_stub + +# 17: Alignment Check Exception +isr17: + cli + push $0 + push $17 + jmp isr_common_stub + +# 18: Machine Check Exception +isr18: + cli + push $0 + push $18 + jmp isr_common_stub + +# 19: Reserved +isr19: + cli + push $0 + push $19 + jmp isr_common_stub + +# 20: Reserved +isr20: + cli + push $0 + push $20 + jmp isr_common_stub + +# 21: Reserved +isr21: + cli + push $0 + push $21 + jmp isr_common_stub + +# 22: Reserved +isr22: + cli + push $0 + push $22 + jmp isr_common_stub + +# 23: Reserved +isr23: + cli + push $0 + push $23 + jmp isr_common_stub + +# 24: Reserved +isr24: + cli + push $0 + push $24 + jmp isr_common_stub + +# 25: Reserved +isr25: + cli + push $0 + push $25 + jmp isr_common_stub + +# 26: Reserved +isr26: + cli + push $0 + push $26 + jmp isr_common_stub + +# 27: Reserved +isr27: + cli + push $0 + push $27 + jmp isr_common_stub + +# 28: Reserved +isr28: + cli + push $0 + push $28 + jmp isr_common_stub + +# 29: Reserved +isr29: + cli + push $0 + push $29 + jmp isr_common_stub + +# 30: Reserved +isr30: + cli + push $0 + push $30 + jmp isr_common_stub + +# 31: Reserved +isr31: + cli + push $0 + push $31 + jmp isr_common_stub + +# IRQ handlers +irq0: + cli + push $0 + push $32 + jmp irq_common_stub + +irq1: + cli + push $1 + push $33 + jmp irq_common_stub + +irq2: + cli + push $2 + push $34 + jmp irq_common_stub + +irq3: + cli + push $3 + push $35 + jmp irq_common_stub + +irq4: + cli + push $4 + push $36 + jmp irq_common_stub + +irq5: + cli + push $5 + push $37 + jmp irq_common_stub + +irq6: + cli + push $6 + push $38 + jmp irq_common_stub + +irq7: + cli + push $7 + push $39 + jmp irq_common_stub + +irq8: + cli + push $8 + push $40 + jmp irq_common_stub + +irq9: + cli + push $9 + push $41 + jmp irq_common_stub + +irq10: + cli + push $10 + push $42 + jmp irq_common_stub + +irq11: + cli + push $11 + push $43 + jmp irq_common_stub + +irq12: + cli + push $12 + push $44 + jmp irq_common_stub + +irq13: + cli + push $13 + push $45 + jmp irq_common_stub + +irq14: + cli + push $14 + push $46 + jmp irq_common_stub + +irq15: + cli + push $15 + push $47 + jmp irq_common_stub + diff --git a/kernel/cpu/isr.c b/kernel/cpu/isr.c new file mode 100644 index 0000000..0057c9f --- /dev/null +++ b/kernel/cpu/isr.c @@ -0,0 +1,144 @@ +// +// Created by rick on 8/18/19. +// + +#include "isr.h" +#include + +#include +#include +#include + +isr_t interrupt_handlers[256]; + +void isr_install() { + set_idt_gate(0, (u32) isr0); + set_idt_gate(1, (u32) isr1); + set_idt_gate(2, (u32) isr2); + set_idt_gate(3, (u32) isr3); + set_idt_gate(4, (u32) isr4); + set_idt_gate(5, (u32) isr5); + set_idt_gate(6, (u32) isr6); + set_idt_gate(7, (u32) isr7); + set_idt_gate(8, (u32) isr8); + set_idt_gate(9, (u32) isr9); + set_idt_gate(10, (u32) isr10); + set_idt_gate(11, (u32) isr11); + set_idt_gate(12, (u32) isr12); + set_idt_gate(13, (u32) isr13); + set_idt_gate(14, (u32) isr14); + set_idt_gate(15, (u32) isr15); + set_idt_gate(16, (u32) isr16); + set_idt_gate(17, (u32) isr17); + set_idt_gate(18, (u32) isr18); + set_idt_gate(19, (u32) isr19); + set_idt_gate(20, (u32) isr20); + set_idt_gate(21, (u32) isr21); + set_idt_gate(22, (u32) isr22); + set_idt_gate(23, (u32) isr23); + set_idt_gate(24, (u32) isr24); + set_idt_gate(25, (u32) isr25); + set_idt_gate(26, (u32) isr26); + set_idt_gate(27, (u32) isr27); + set_idt_gate(28, (u32) isr28); + set_idt_gate(29, (u32) isr29); + set_idt_gate(30, (u32) isr30); + set_idt_gate(31, (u32) isr31); + + // Remap the PIC + port_byte_out(0x20, 0x11); + port_byte_out(0xA0, 0x11); + port_byte_out(0x21, 0x20); + port_byte_out(0xA1, 0x28); + port_byte_out(0x21, 0x04); + port_byte_out(0xA1, 0x02); + port_byte_out(0x21, 0x01); + port_byte_out(0xA1, 0x01); + port_byte_out(0x21, 0x0); + port_byte_out(0xA1, 0x0); + + // Install the IRQs + set_idt_gate(32, (u32) irq0); + set_idt_gate(33, (u32) irq1); + set_idt_gate(34, (u32) irq2); + set_idt_gate(35, (u32) irq3); + set_idt_gate(36, (u32) irq4); + set_idt_gate(37, (u32) irq5); + set_idt_gate(38, (u32) irq6); + set_idt_gate(39, (u32) irq7); + set_idt_gate(40, (u32) irq8); + set_idt_gate(41, (u32) irq9); + set_idt_gate(42, (u32) irq10); + set_idt_gate(43, (u32) irq11); + set_idt_gate(44, (u32) irq12); + set_idt_gate(45, (u32) irq13); + set_idt_gate(46, (u32) irq14); + set_idt_gate(47, (u32) irq15); + + set_idt(); // Load with ASM +} + +char *exception_messages[] = { + "Division By Zero", + "Debug", + "Non Maskable Interrupt", + "Breakpoint", + "Into Detected Overflow", + "Out of Bounds", + "Invalid Opcode", + "No Coprocessor", + + "Double Fault", + "Coprocessor Segment Overrun", + "Bad TSS", + "Segment Not Present", + "Stack Fault", + "General Protection Fault", + "Page Fault", + "Unknown Interrupt", + + "Coprocessor Fault", + "Alignment Check", + "Machine Check", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved" +}; + +void isr_handler(registers_t r) { + kprint("received interrupt: "); + char s[3]; + itoa(r.int_no, s); + kprint(s); + kprint("\n"); + kprint(exception_messages[r.int_no]); + kprint("\n"); +} + +void register_interrupt_handler(u8 n, isr_t handler) { + interrupt_handlers[n] = handler; +} + +void irq_handler(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(0xA0, 0x20); /* slave */ + port_byte_out(0x20, 0x20); /* master */ + + /* Handle the interrupt in a more modular way */ + if (interrupt_handlers[r.int_no] != 0) { + isr_t handler = interrupt_handlers[r.int_no]; + handler(r); + } +} \ No newline at end of file diff --git a/kernel/cpu/isr.h b/kernel/cpu/isr.h new file mode 100644 index 0000000..01afdd7 --- /dev/null +++ b/kernel/cpu/isr.h @@ -0,0 +1,140 @@ +// +// Created by rick on 8/18/19. +// + +#include "../types.h" + +#ifndef MY_KERNEL_ISR_H +#define MY_KERNEL_ISR_H + +/* ISRs reserved for CPU exceptions */ +extern void isr0(); + +extern void isr1(); + +extern void isr2(); + +extern void isr3(); + +extern void isr4(); + +extern void isr5(); + +extern void isr6(); + +extern void isr7(); + +extern void isr8(); + +extern void isr9(); + +extern void isr10(); + +extern void isr11(); + +extern void isr12(); + +extern void isr13(); + +extern void isr14(); + +extern void isr15(); + +extern void isr16(); + +extern void isr17(); + +extern void isr18(); + +extern void isr19(); + +extern void isr20(); + +extern void isr21(); + +extern void isr22(); + +extern void isr23(); + +extern void isr24(); + +extern void isr25(); + +extern void isr26(); + +extern void isr27(); + +extern void isr28(); + +extern void isr29(); + +extern void isr30(); + +extern void isr31(); + +/* IRQ definitions */ +extern void irq0(); + +extern void irq1(); + +extern void irq2(); + +extern void irq3(); + +extern void irq4(); + +extern void irq5(); + +extern void irq6(); + +extern void irq7(); + +extern void irq8(); + +extern void irq9(); + +extern void irq10(); + +extern void irq11(); + +extern void irq12(); + +extern void irq13(); + +extern void irq14(); + +extern void irq15(); + +#define IRQ0 32 +#define IRQ1 33 +#define IRQ2 34 +#define IRQ3 35 +#define IRQ4 36 +#define IRQ5 37 +#define IRQ6 38 +#define IRQ7 39 +#define IRQ8 40 +#define IRQ9 41 +#define IRQ10 42 +#define IRQ11 43 +#define IRQ12 44 +#define IRQ13 45 +#define IRQ14 46 +#define IRQ15 47 + +typedef struct { + u32 ds; + u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; + u32 int_no, err_code; + u32 eip, cs, eflags, useresp, ss; +} registers_t; + +typedef void (*isr_t)(registers_t); + +void register_interrupt_handler(u8 n, isr_t handler); + +void isr_install(); + +void isr_handler(registers_t r); + +#endif //MY_KERNEL_ISR_H diff --git a/kernel/cpu/timer.c b/kernel/cpu/timer.c new file mode 100644 index 0000000..d5e2c9d --- /dev/null +++ b/kernel/cpu/timer.c @@ -0,0 +1,26 @@ +// +// Created by rick on 9/22/19. +// + +#include "timer.h" + +#include +#include + +u32 tick = 0; + +static void timer_callback(registers_t regs) { + tick++; +} + +int init_timer(u32 freq) { + register_interrupt_handler(IRQ0, timer_callback); + + u32 divisor = 1193180 / freq; + u8 low = (u8) (divisor & 0xFF); + u8 high = (u8) ((divisor >> 8) & 0xFF); + port_byte_out(PORT_PIT_COMMAND, PIT_MODE_BIN | PIT_MODE_SQUARE_WAVE | PIT_ACCESS_MODE_HL | PIT_CHANNEL_0); + port_byte_out(PORT_PIT_DATA_0, low); + port_byte_out(PORT_PIT_DATA_0, high); + return 0; +} diff --git a/kernel/cpu/timer.h b/kernel/cpu/timer.h new file mode 100644 index 0000000..569348a --- /dev/null +++ b/kernel/cpu/timer.h @@ -0,0 +1,12 @@ +// +// Created by rick on 9/22/19. +// + +#ifndef MY_KERNEL_TIMER_H +#define MY_KERNEL_TIMER_H + +#include "../types.h" + +int init_timer(u32 freq); + +#endif //MY_KERNEL_TIMER_H diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c new file mode 100644 index 0000000..3ac8d7c --- /dev/null +++ b/kernel/drivers/keyboard.c @@ -0,0 +1,70 @@ +// +// Created by rick on 23-03-20. +// +#include "keyboard.h" + +#include +#include +#include +#include + +char scancodes_ascii[] = { + 0, 0, + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0, + 0, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0, + 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', + 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, + '*', + 0, ' ', + 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F1-F10 + 0, 0, + '7', '8', '9', '-', + '4', '5', '6', '+', + '1', '2', '3', + '0', 0, + 0, // sysrq + 0, 0, // weird + 0, 0, // F11 F12 + // weid +}; + +char *MSG_KEY = "Clicked on key 'x'\n"; + +void print_scancode(unsigned char scancode); + +static void keyboard_callback(registers_t regs) { + unsigned char status = port_byte_in(PORT_PS2_STATUS); + // check if data available + if ((status & 0b00000001) == 0) { + return; + } + unsigned char scancode = port_byte_in(0x60); + print_scancode(scancode); +} + +void init_keyboard() { + register_interrupt_handler(IRQ1, keyboard_callback); +} + +void print_scancode(unsigned char scancode) { + char msg[256]; + char release = 0; + if (scancode > 0x80) { + // release + release = 1; + scancode -= 0x80; + } + char code = scancodes_ascii[scancode]; + if (code == 0) { + // special + } else { + if (release && code > 0x60 && code < 0x7B) { + code -= 0x20; // to lowercase + } + + memcpy(msg, MSG_KEY, strlen(MSG_KEY)); + msg[strlen(msg) - 3] = code; + kprint(msg); + } +} \ No newline at end of file diff --git a/kernel/drivers/keyboard.h b/kernel/drivers/keyboard.h new file mode 100644 index 0000000..3027fed --- /dev/null +++ b/kernel/drivers/keyboard.h @@ -0,0 +1,10 @@ +// +// Created by rick on 23-03-20. +// + +#ifndef MY_KERNEL_KEYBOARD_H +#define MY_KERNEL_KEYBOARD_H + +void init_keyboard(); + +#endif //MY_KERNEL_KEYBOARD_H diff --git a/kernel/drivers/ports.c b/kernel/drivers/ports.c new file mode 100644 index 0000000..9837225 --- /dev/null +++ b/kernel/drivers/ports.c @@ -0,0 +1,33 @@ +/* + * ports.c + * + * Created on: Aug 18, 2019 + * Author: rick + */ + + +#include "ports.h" + +/** + * Read a byte from the specified port + */ +unsigned char port_byte_in(unsigned short port) { + unsigned char result; + __asm__("in %%dx, %%al" : "=a" (result) : "d" (port)); + return result; +} + + +void port_byte_out(unsigned short port, unsigned char data) { + __asm__("out %%al, %%dx" : : "a" (data), "d" (port)); +} + +unsigned short port_word_in(unsigned short port) { + unsigned short result; + __asm__("in %%dx, %%ax" : "=a" (result) : "d" (port)); + return result; +} + +void port_wordt_out(unsigned short port, unsigned short data) { + __asm__("out %%ax, %%dx" : : "a" (data), "d" (port)); +} diff --git a/kernel/drivers/ports.h b/kernel/drivers/ports.h new file mode 100644 index 0000000..fad2d61 --- /dev/null +++ b/kernel/drivers/ports.h @@ -0,0 +1,51 @@ +#ifndef MY_KERNEL_DRIVERS_PORT_H +#define MY_KERNEL_DRIVERS_PORT_H + +//http://www.osdever.net/FreeVGA/vga/crtcreg.htm#0A +#define PORT_REG_SCREEN_CTRL 0x3d4 +#define PORT_REG_SCREEN_CTRL_CURSOR_H 0x0E +#define PORT_REG_SCREEN_CTRL_CURSOR_L 0x0F +#define PORT_REG_SCREEN_DATA 0x3d5 + +// https://wiki.osdev.org/Serial_Ports +#define PORT_SERIAL_0 0x3f8 +#define PORT_SERIAL_1 0x2f8 +#define PORT_SERIAL_2 0x3e8 +#define PORT_SERIAL_3 0x2e8 + +#define PORT_SERIAL_DATA 0 +#define PORT_SERIAL_INTERRUPT 1 +#define PORT_SERIAL_DLAB_LSB 0 +#define PORT_SERIAL_DLAB_MSB 1 +#define PORT_SERIAL_INTERRUPT_ID_FIFO 2 +#define PORT_SERIAL_LINE_CONTROL 3 +#define PORT_SERIAL_MODEM_CONTROL 4 +#define PORT_SERIAL_LINE_STATUS 5 +#define PORT_SERIAL_MODEM_STATUS 6 +#define PORT_SERIAL_SCRATCH 6 + +// https://wiki.osdev.org/PIT +#define PORT_PIT_COMMAND 0x43 +#define PIT_MODE_BIN 0x0 +#define PIT_MODE_HW_STROBE 0b0101 +#define PIT_MODE_SQUARE_WAVE 0b0110 +#define PIT_ACCESS_MODE_HL 0b000011 +#define PIT_CHANNEL_0 0b00000000 +#define PORT_PIT_DATA_0 0x40 +#define PORT_PIT_DATA_1 0x41 +#define PORT_PIT_DATA_3 0x42 + +// https://wiki.osdev.org/%228042%22_PS/2_Controller +#define PORT_PS2_DATA 0x60 +#define PORT_PS2_STATUS 0x64 +#define PORT_PS2_COMMAND 0x64 + +unsigned char port_byte_in(unsigned short port); + +void port_byte_out(unsigned short port, unsigned char data); + +unsigned short port_word_in(unsigned short port); + +void port_word_out(unsigned short port, unsigned short data); + +#endif diff --git a/kernel/drivers/serial.c b/kernel/drivers/serial.c new file mode 100644 index 0000000..595c066 --- /dev/null +++ b/kernel/drivers/serial.c @@ -0,0 +1,56 @@ +// +// Created by rick on 28-01-21. +// + +#include "serial.h" +#include +#include + +int serial_init() { + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_INTERRUPT, 0x00); // Disable all interrupts + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_LINE_CONTROL, 0x80); // Enable DLAB (set baud rate divisor) + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_DLAB_LSB, 0x03); // Set divisor to 3 (lo byte) 38400 baud + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_DLAB_MSB, 0x00); // (hi byte) + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_LINE_CONTROL, 0x03); // 8 bits, no parity, one stop bit + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_INTERRUPT_ID_FIFO, + 0xC7); // Enable FIFO, clear them, with 14-byte threshold + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_MODEM_CONTROL, 0x0B); // IRQs enabled, RTS/DSR set + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_MODEM_CONTROL, 0x1E); // Set in loopback mode, test the serial chip + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_DATA, + 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) + + // Check if serial is faulty (i.e: not same byte as sent) + if (port_byte_in(PORT_SERIAL_0 + PORT_SERIAL_DATA) != 0xAE) { + return 1; + } + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_MODEM_CONTROL, 0x0F); + return 0; +} + +int is_transmit_empty() { + return port_byte_in(PORT_SERIAL_0 + PORT_SERIAL_LINE_STATUS) & 0x20; +} + +void write_serial(char a) { + while (is_transmit_empty() == 0); + + port_byte_out(PORT_SERIAL_0 + PORT_SERIAL_DATA, a); +} + +void serial_kprint(char *msg) { + u32 i = 0; + while (1) { + char c = msg[i]; + if (c == 0) { + break; + } + if (c == '\n') { + write_serial('\r'); + } + write_serial(c); + i++; + } +} \ No newline at end of file diff --git a/kernel/drivers/serial.h b/kernel/drivers/serial.h new file mode 100644 index 0000000..049de5d --- /dev/null +++ b/kernel/drivers/serial.h @@ -0,0 +1,12 @@ +// +// Created by rick on 28-01-21. +// + +#ifndef NEW_KERNEL_SERIAL_H +#define NEW_KERNEL_SERIAL_H + +int serial_init(); + +void serial_kprint(char *msg); + +#endif //NEW_KERNEL_SERIAL_H diff --git a/kernel/drivers/vgascreen.c b/kernel/drivers/vgascreen.c new file mode 100644 index 0000000..b345383 --- /dev/null +++ b/kernel/drivers/vgascreen.c @@ -0,0 +1,122 @@ +// +// Created by rick on 8/18/19. +// + +#include "vgascreen.h" + +#include +#include + +char *_vga_character_memory = (char *) VGA_CHARACTER_MEMORY_LOCATION; + +int get_offset(int col, int row); + +int get_cursor_offset(); + +void set_cursor_offset(int offset); + +int get_offset_row(int offset); + +int get_offset_col(int offset); + +int print_char(char character, int col, int row, char attributes); + + +void vga_clear_screen() { + int size = VGA_COL_MAX * VGA_ROW_MAX; + for (int i = 0; i < size; ++i) { + _vga_character_memory[i * 2] = ' '; + _vga_character_memory[i * 2 + 1] = VGA_WHITE | (VGA_BLACK << VGA_SHIFT_BG); + } + set_cursor_offset(0); +} + +void kprint_at(char *message, int col, int row) { + int offset; + if (col > 0 && row > 0) { + offset = get_offset(col, row); + } else { + offset = get_cursor_offset(); + row = get_offset_row(offset); + col = get_offset_col(offset); + } + + int i = 0; + while (message[i] != 0) { + offset = print_char(message[i++], col, row, VGA_WHITE | (VGA_BLACK << VGA_SHIFT_BG)); + row = get_offset_row(offset); + col = get_offset_col(offset); + } +} + + +void vga_kprint(char *message) { + kprint_at(message, -1, -1); +} + +int print_char(char character, int col, int row, char attributes) { + if (!attributes) attributes = VGA_WHITE | (VGA_BLACK < VGA_SHIFT_BG); + + if (col >= VGA_COL_MAX || row > +VGA_ROW_MAX) { + _vga_character_memory[2 * (VGA_COL_MAX) * (VGA_ROW_MAX) - 2] = 'E'; + _vga_character_memory[2 * (VGA_COL_MAX) * (VGA_ROW_MAX) - 1] = VGA_RED | (VGA_WHITE < VGA_SHIFT_BG); + return get_offset(col, row); + } + + int offset; + if (col >= 0 && row >= 0) { + offset = get_offset(col, row); + } else { + offset = get_cursor_offset(); + } + + if (character == '\n') { + row = get_offset_row(offset); + offset = get_offset(0, row + 1); + } else { + _vga_character_memory[offset] = character; + _vga_character_memory[offset + 1] = attributes; + offset += 2; + } + + if (offset >= (VGA_COL_MAX * 2 * VGA_ROW_MAX)) { + memcpy(_vga_character_memory, + _vga_character_memory + (VGA_COL_MAX * 2), + (2 * VGA_COL_MAX * VGA_ROW_MAX) - (2 * VGA_COL_MAX)); + for (int i = 0; i < VGA_COL_MAX; ++i) { + _vga_character_memory[get_offset(i, VGA_ROW_MAX - 1)] = ' '; + } + offset = get_offset(0, VGA_ROW_MAX - 1); + } + + set_cursor_offset(offset); + return offset; +} + +int get_cursor_offset() { + port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_H); + int offset = ((int) port_byte_in(PORT_REG_SCREEN_DATA)) << 8; + port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_L); + offset += port_byte_in(PORT_REG_SCREEN_DATA); + return offset * 2; +} + +void set_cursor_offset(int offset) { + offset /= 2; + port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_L); + port_byte_out(PORT_REG_SCREEN_DATA, (unsigned char) (offset & 0xFF)); + port_byte_out(PORT_REG_SCREEN_CTRL, PORT_REG_SCREEN_CTRL_CURSOR_H); + port_byte_out(PORT_REG_SCREEN_DATA, (unsigned char) (offset >> 8) & 0xFF); +} + +int get_offset(int col, int row) { + return (row * VGA_COL_MAX + col) * 2; +} + +int get_offset_row(int offset) { + return offset / (VGA_COL_MAX * 2); +} + +int get_offset_col(int offset) { + return (offset - (get_offset_row(offset) * 2 * VGA_COL_MAX)) / 2; +} diff --git a/kernel/drivers/vgascreen.h b/kernel/drivers/vgascreen.h new file mode 100644 index 0000000..7b485a9 --- /dev/null +++ b/kernel/drivers/vgascreen.h @@ -0,0 +1,34 @@ +// +// Created by rick on 8/18/19. +// + +#ifndef MY_KERNEL_DRIVERS_VGASCREEN_H +#define MY_KERNEL_DRIVERS_VGASCREEN_H +#define VGA_CHARACTER_MEMORY_LOCATION 0xb8000 + +#define VGA_BLACK 0x0 +#define VGA_BLUE 0x1 +#define VGA_GREEN 0x2 +#define VGA_CIAN 0x3 +#define VGA_RED 0x4 +#define VGA_PURPLE 0x5 +#define VGA_ORANGE 0x6 +#define VGA_GRAY 0x7 +#define VGA_DARK_GRAY 0x8 +#define VGA_LIGHT_BLUE 0x9 +#define VGA_LIGHT_GREEN 0xA +#define VGA_LIGHT_RED 0xB +#define VGA_PINK 0xD +#define VGA_YELLOW 0xE +#define VGA_WHITE 0xF +#define VGA_SHIFT_BG 4 +#define VGA_BLINK 0x80 + +#define VGA_COL_MAX 80 +#define VGA_ROW_MAX 25 + +void vga_clear_screen(); + +void vga_kprint(char *msg); + +#endif //MY_KERNEL_VGASCREEN_H diff --git a/kernel/kernel.c b/kernel/kernel.c new file mode 100644 index 0000000..fcee24d --- /dev/null +++ b/kernel/kernel.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kprint.h" + +char *msg_booted = "Booted Successfully!\n"; + + +void kmain(multiboot_info_t *multiboot_info) { + isr_install(); + init_mmap((struct multiboot_mmap_entry *) multiboot_info->mmap_addr, + multiboot_info->mmap_length / sizeof(struct multiboot_mmap_entry)); + vga_clear_screen(); + vga_clear_screen(' ', VGA_WHITE | (VGA_GRAY << VGA_SHIFT_BG)); + kprint_register(vga_kprint); + serial_init(); + kprint_register(serial_kprint); + +// vga_print_string(msg_booted, VGA_WHITE | (VGA_DARK_GRAY << VGA_SHIFT_BG)); + kprint(msg_booted); + kprint((char *) multiboot_info->boot_loader_name); + multiboot_memory_map_t *fe = multiboot_info->mmap_addr; + +// port_byte_out(0x3d4, 14); +// int pos = port_byte_in(0x3d5); +// pos <<= 8; +// +// port_byte_out(0x3d4, 15); +// pos += port_byte_in(0x3d5); + + asm volatile("sti"); + init_timer(50); + init_keyboard(); + + print_mmap_info(); + +// vga_set_raw(pos * 2, 'X'); +// vga_set_raw(pos * 2 + 1, 0xf); + do {} while (1); +} diff --git a/kernel/kprint.c b/kernel/kprint.c new file mode 100644 index 0000000..21b21b9 --- /dev/null +++ b/kernel/kprint.c @@ -0,0 +1,37 @@ +// +// Created by rick on 28-01-21. +// + +#include "kprint.h" + +#define MAX_HANDLERS 8 + +kprint_handler handlers[MAX_HANDLERS] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +void kprint_register(kprint_handler handler) { + for (int i = 0; i < MAX_HANDLERS; ++i) { + if (handlers[i] == NULL) { + handlers[i] = handler; + break; + } + } + // todo handle +} + +void kprint(char *msg) { + for (int i = 0; i < MAX_HANDLERS; ++i) { + if (handlers[i] == NULL) { + continue; + } + handlers[i](msg); + } +} \ No newline at end of file diff --git a/kernel/kprint.h b/kernel/kprint.h new file mode 100644 index 0000000..86b5b34 --- /dev/null +++ b/kernel/kprint.h @@ -0,0 +1,16 @@ +// +// Created by rick on 28-01-21. +// + +#ifndef NEW_KERNEL_KPRINT_H +#define NEW_KERNEL_KPRINT_H + +#endif //NEW_KERNEL_KPRINT_H + +#include + +typedef void (*kprint_handler)(char *); + +void kprint_register(kprint_handler); + +void kprint(char *msg); \ No newline at end of file diff --git a/kernel/libc/libc.c b/kernel/libc/libc.c new file mode 100644 index 0000000..81cf78c --- /dev/null +++ b/kernel/libc/libc.c @@ -0,0 +1,40 @@ +/* + * libc.c + * + * Created on: Oct 11, 2018 + * Author: rick + */ + +#include "libc.h" + +int memcpy(char *dst, char *src, int amount) { + for (int i = 0; i < amount; i++) { + dst[i] = src[i]; + } + return 0; +} + +int memset(char *dst, char data, int amount) { + for (int i = 0; i < amount; ++i) { + dst[i] = data; + } + return 0; +} + +int itoa(int i, char *target) { + target[0] = (char) (i % 10 + '0'); + target[1] = '\0'; + if (i > 9) { + itoa(i / 10, target + 1); + } + return 0; +} + +int strlen(char *str) { + int length = 0; + while (str[length] != 0) { + length++; + } + return length; +} + diff --git a/kernel/libc/libc.h b/kernel/libc/libc.h new file mode 100644 index 0000000..53c07ea --- /dev/null +++ b/kernel/libc/libc.h @@ -0,0 +1,19 @@ +/* + * libc.h + * + * Created on: Oct 11, 2018 + * Author: rick + */ + +#ifndef KERNEL_LIBC_LIBC_H_ +#define KERNEL_LIBC_LIBC_H_ + +int memcpy(char *dst, char *src, int amount); + +int memset(char *dst, char data, int amount); + +int itoa(int i, char *target); + +int strlen(char *str); + +#endif /* KERNEL_LIBC_LIBC_H_ */ diff --git a/kernel/mem/mem.c b/kernel/mem/mem.c new file mode 100644 index 0000000..943ac20 --- /dev/null +++ b/kernel/mem/mem.c @@ -0,0 +1,88 @@ +// +// Created by rick on 22-04-20. +// + +#include +#include +#include +#include + +char *msg_index = "Idx: "; +char *msg_addr = "Address: "; +char *msg_len = "Length: "; +char *msg_type = "Type: "; +char *msg_nl = "\n"; + +typedef struct { + u64 address; + u64 length; +#define MMAP_TYPE_UNDEFINED 0 +#define MMAP_TYPE_AVAILABLE 1 +#define MMAP_TYPE_RESERVED 2 +#define MMAP_TYPE_ACPI_RECLAIMABLE 3 +#define MMAP_TYPE_NVS 4 +#define MMAP_TYPE_BADRAM 5 + u32 type; +} __attribute((packed)) mmap_entry; + +char *msg_lu = "0123456789ABCDEF"; + +mmap_entry memmap[16] = { + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, + {0, 0, 0}, +}; + +void init_mmap(struct multiboot_mmap_entry *entries, u32 count) { + for (u32 i = 0; i < count; ++i) { + memmap[i].address = entries[i].addr; + memmap[i].length = entries[i].len; + memmap[i].type = entries[i].type; + } +} + +void print_hex_u64(u64 input) { + char msg[18] = "0x0000000000000000"; + for (int i = 0; i < 16; ++i) { + int val = input >> (4 * i) & 0xF; + msg[17 - i] = msg_lu[val]; + } + kprint(msg); +} + +void print_mmap_info() { + for (int i = 0; i < 16; ++i) { + if (memmap[i].type == 0) { + break; + } + char *tmp_str = " "; + kprint(msg_index); + itoa(i, tmp_str); + kprint(tmp_str); + kprint(msg_nl); + kprint(msg_addr); + print_hex_u64(memmap[i].address); + kprint(msg_nl); + kprint(msg_len); + print_hex_u64(memmap[i].length); + kprint(msg_nl); + kprint(msg_type); + itoa(memmap[i].type, tmp_str); + kprint(tmp_str); + kprint(msg_nl); + kprint(msg_nl); + } +} diff --git a/kernel/mem/mem.h b/kernel/mem/mem.h new file mode 100644 index 0000000..8ca778c --- /dev/null +++ b/kernel/mem/mem.h @@ -0,0 +1,14 @@ +// +// Created by rick on 22-04-20. +// + +#ifndef NEW_KERNEL_MEM_H +#define NEW_KERNEL_MEM_H + +#include + +void init_mmap(struct multiboot_mmap_entry *entries, u32 count); + +void print_mmap_info(); + +#endif //NEW_KERNEL_MEM_H diff --git a/kernel/multiboot.h b/kernel/multiboot.h new file mode 100644 index 0000000..d8d0165 --- /dev/null +++ b/kernel/multiboot.h @@ -0,0 +1,262 @@ +//* multiboot.h - Multiboot header file. */ +/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MULTIBOOT_HEADER +#define MULTIBOOT_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_HEADER_ALIGN 4 + +/* The magic field should contain this. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* This should be in %eax. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000004 + +/* Flags set in the ’flags’ member of the multiboot header. */ + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +/* Flags to be set in the ’flags’ member of the multiboot info structure. */ + +/* is there basic lower/upper memory information? */ +#define MULTIBOOT_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define MULTIBOOT_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define MULTIBOOT_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define MULTIBOOT_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define MULTIBOOT_INFO_ELF_SHDR 0X00000020 + +/* is there a full memory map? */ +#define MULTIBOOT_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define MULTIBOOT_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define MULTIBOOT_INFO_VBE_INFO 0x00000800 +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 + +#ifndef ASM_FILE + +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; + +struct multiboot_header { + /* Must be MULTIBOOT_MAGIC - see above. */ + multiboot_uint32_t magic; + + /* Feature flags. */ + multiboot_uint32_t flags; + + /* The above fields plus this one must equal 0 mod 2^32. */ + multiboot_uint32_t checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; + multiboot_uint32_t entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + multiboot_uint32_t mode_type; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +/* The symbol table for a.out. */ +struct multiboot_aout_symbol_table { + multiboot_uint32_t tabsize; + multiboot_uint32_t strsize; + multiboot_uint32_t addr; + multiboot_uint32_t reserved; +}; +typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; + +/* The section header table for ELF. */ +struct multiboot_elf_section_header_table { + multiboot_uint32_t num; + multiboot_uint32_t size; + multiboot_uint32_t addr; + multiboot_uint32_t shndx; +}; +typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; + +struct multiboot_info { + /* Multiboot info version number */ + multiboot_uint32_t flags; + + /* Available memory from BIOS */ + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; + + /* "root" partition */ + multiboot_uint32_t boot_device; + + /* Kernel command line */ + multiboot_uint32_t cmdline; + + /* Boot-Module list */ + multiboot_uint32_t mods_count; + multiboot_uint32_t mods_addr; + + union { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; + + /* Memory Mapping buffer */ + multiboot_uint32_t mmap_length; + multiboot_uint32_t mmap_addr; + + /* Drive Info buffer */ + multiboot_uint32_t drives_length; + multiboot_uint32_t drives_addr; + + /* ROM configuration table */ + multiboot_uint32_t config_table; + + /* Boot Loader Name */ + multiboot_uint32_t boot_loader_name; + + /* APM table */ + multiboot_uint32_t apm_table; + + /* Video */ + multiboot_uint32_t vbe_control_info; + multiboot_uint32_t vbe_mode_info; + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + union { + struct { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; +typedef struct multiboot_info multiboot_info_t; + +struct multiboot_color { + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; + +struct multiboot_mmap_entry { + multiboot_uint32_t size; + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + multiboot_uint32_t type; +} __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_mod_list { + /* the memory used goes from bytes ’mod_start’ to ’mod_end-1’ inclusive */ + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + + /* Module command line */ + multiboot_uint32_t cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + multiboot_uint32_t pad; +}; +typedef struct multiboot_mod_list multiboot_module_t; + +/* APM BIOS info. */ +struct multiboot_apm_info { + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ \ No newline at end of file diff --git a/kernel/types.h b/kernel/types.h new file mode 100644 index 0000000..b09f878 --- /dev/null +++ b/kernel/types.h @@ -0,0 +1,22 @@ +/* + * types.h + * + * Created on: Nov 1, 2018 + * Author: rick + */ + +#ifndef KERNEL_LIBC_TYPES_H_ +#define KERNEL_LIBC_TYPES_H_ + +# define NULL (void *)0 + +typedef unsigned long long u64; +typedef long long s64; +typedef unsigned int u32; +typedef int s32; +typedef unsigned short u16; +typedef short s16; +typedef unsigned char u8; +typedef char s8; + +#endif /* KERNEL_LIBC_TYPES_H_ */ diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..f61e130 --- /dev/null +++ b/linker.ld @@ -0,0 +1,43 @@ +/* The bootloader will look at this image and start execution at the symbol + designated as the entry point. */ +ENTRY(_start) + +/* Tell where the various sections of the object files will be put in the final + kernel image. */ +SECTIONS +{ + /* Begin putting sections at 1 MiB, a conventional place for kernels to be + loaded at by the bootloader. */ + . = 1M; + + /* 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. + Next we'll put the .text section. */ + .text BLOCK(4K) : ALIGN(4K) + { + *(.multiboot) + *(.text) + } + + /* Read-only data. */ + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + /* Read-write data (initialized) */ + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + /* Read-write data (uninitialized) and stack */ + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } + + /* The compiler may produce other sections, by default it will put them in + a segment with the same name. Simply add stuff here as needed. */ +} \ No newline at end of file diff --git a/qemu-debug.sh b/qemu-debug.sh new file mode 100755 index 0000000..1cecd86 --- /dev/null +++ b/qemu-debug.sh @@ -0,0 +1,3 @@ +#!/bin/bash +nohup qemu-system-i386 -S -s -kernel cmake-build-debug/my-kernel.bin -d guest_errors,int -m 1G & +disown