├── .clang ├── _config.yml ├── src ├── arch │ ├── build.mk │ └── i386 │ │ ├── build.mk │ │ ├── bootloader │ │ ├── crtn.s │ │ ├── crti.s │ │ ├── multiboot_header.asm │ │ └── boot.s │ │ ├── elf.c │ │ ├── paging.c │ │ └── acpi.c ├── kernel │ ├── cpu │ │ ├── idt │ │ │ ├── load_idt.s │ │ │ └── idt.c │ │ ├── gdt │ │ │ ├── load_gdt.s │ │ │ └── gdt.c │ │ ├── irq │ │ │ └── irq.c │ │ ├── pic.c │ │ ├── ports.c │ │ ├── isr │ │ │ └── isr.c │ │ ├── interrupt.asm │ │ ├── cpu.c │ │ └── bios │ │ │ └── cmos.c │ ├── kprintf.c │ ├── syscalls │ │ └── syscalls.c │ ├── stdio.c │ ├── io.c │ ├── panic.c │ ├── devices │ │ └── pcSpeaker.c │ ├── time │ │ ├── mktime.c │ │ ├── PIT.c │ │ └── rtc.c │ ├── memory.c │ └── kernel.c ├── assert.c ├── drivers │ ├── vga │ │ ├── cursor.asm │ │ ├── cursor.c │ │ └── vga.c │ ├── serial │ │ └── serial.c │ ├── video │ │ └── video.c │ ├── keyboard │ │ └── keyboard.c │ └── pci │ │ └── bus.c ├── sys │ ├── utils.c │ ├── char.c │ └── string.c └── debug │ └── qemu.c ├── .gitpod.yml ├── Assets ├── TinyKernel Preview.png ├── TinyKernelPreview2.png ├── TinyKernelPreview3.png ├── TinyKernel Cover Art.png └── Banner.svg ├── .gitpod.Dockerfile ├── scripts ├── changelog_gen └── gitpush ├── include ├── kernel │ ├── cpu │ │ ├── irq │ │ │ └── irq.h │ │ ├── pic.h │ │ ├── bios │ │ │ └── cmos.h │ │ ├── gdt │ │ │ └── gdt.h │ │ ├── cpu.h │ │ ├── isr │ │ │ └── isr.h │ │ ├── ports.h │ │ └── idt │ │ │ └── idt.h │ ├── kernel.h │ ├── devices │ │ └── pcSpeaker.h │ ├── syscalls │ │ └── syscalls.h │ ├── panic.h │ ├── time │ │ ├── rtc.h │ │ ├── time.h │ │ └── PIT.h │ ├── stdio.h │ ├── io.h │ ├── kprintf.h │ ├── memory.h │ └── errno.h ├── assert.h ├── drivers │ ├── vga │ │ ├── cursor.h │ │ └── vga.h │ ├── tty │ │ └── tty.h │ ├── video │ │ └── video.h │ ├── serial │ │ └── serial.h │ ├── sb16 │ │ ├── sound.h │ │ └── sb16.h │ ├── pci │ │ └── bus.h │ └── keyboard │ │ └── keyboard.h ├── sys │ ├── char.h │ ├── utils.h │ ├── string.h │ └── stddef.h ├── stdint.h ├── arch │ └── i386 │ │ ├── acpi.h │ │ ├── elf_core.h │ │ └── paging.h ├── buildinfo.h ├── debug │ └── qemu.h ├── system.h ├── config.h ├── AK │ └── printfImpl.h ├── cdefs.h └── types.h ├── todo.txt ├── .vscode └── c_cpp_properties.json ├── CITATION.cff ├── config ├── grub.cfg └── linker.ld ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── flawfinder.yml ├── colors.mk ├── config.cfg ├── CHANGELOG ├── README.md ├── .gitignore ├── docs └── kernel │ └── assert.md ├── CODE_OF_CONDUCT.md └── Makefile /.clang: -------------------------------------------------------------------------------- 1 | -Iinclude 2 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /src/arch/build.mk: -------------------------------------------------------------------------------- 1 | -include src/arch/$(BUILD_ARCH)/build.mk -------------------------------------------------------------------------------- /src/arch/i386/build.mk: -------------------------------------------------------------------------------- 1 | KERNEL_LDFLAGS += -z max-page-size=0x1000 -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.Dockerfile 3 | 4 | tasks: 5 | - init: make 6 | -------------------------------------------------------------------------------- /Assets/TinyKernel Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinyKern/TinyKernel/HEAD/Assets/TinyKernel Preview.png -------------------------------------------------------------------------------- /Assets/TinyKernelPreview2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinyKern/TinyKernel/HEAD/Assets/TinyKernelPreview2.png -------------------------------------------------------------------------------- /Assets/TinyKernelPreview3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinyKern/TinyKernel/HEAD/Assets/TinyKernelPreview3.png -------------------------------------------------------------------------------- /Assets/TinyKernel Cover Art.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinyKern/TinyKernel/HEAD/Assets/TinyKernel Cover Art.png -------------------------------------------------------------------------------- /src/kernel/cpu/idt/load_idt.s: -------------------------------------------------------------------------------- 1 | .section .text 2 | .global load_idt 3 | 4 | load_idt: 5 | mov 4(%esp), %eax 6 | lgdt (%eax) 7 | ret 8 | 9 | -------------------------------------------------------------------------------- /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-full 2 | 3 | # Install custom tools, runtimes, etc. 4 | # For example "bastet", a command-line tetris clone: 5 | # RUN brew install bastet 6 | # 7 | # More information: https://www.gitpod.io/docs/config-docker/ 8 | -------------------------------------------------------------------------------- /scripts/changelog_gen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git log --pretty="%as %an <%cE>%n%n%s%n%n%b" > CHANGELOG 4 | echo "Local Variables: 5 | mode: change-log 6 | left-margin: 8 7 | fill-column: 76 8 | version-control: never 9 | End:" >> CHANGELOG 10 | -------------------------------------------------------------------------------- /src/arch/i386/bootloader/crtn.s: -------------------------------------------------------------------------------- 1 | .section .init 2 | /* GCC will contain the contents of crtbegin.o's .init section. */ 3 | popl %ebp 4 | ret 5 | 6 | .section .fini 7 | /* GCC will contain the contents of crtbegin.o's .fini section. */ 8 | popl %ebp 9 | ret 10 | -------------------------------------------------------------------------------- /include/kernel/cpu/irq/irq.h: -------------------------------------------------------------------------------- 1 | #ifndef IRQ_H 2 | #define IRQ_H 3 | 4 | #include "../cpu.h" 5 | #include "../idt/idt.h" 6 | 7 | #include 8 | 9 | /** 10 | * @brief Initialize the IRQ subsystem. 11 | * 12 | * @return uint32_t 0 on success 13 | */ 14 | uint32_t irq_init(void); 15 | 16 | #endif /* IRQ_H */ -------------------------------------------------------------------------------- /include/assert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef ASSERT 4 | #ifdef NDEBUG 5 | void assertion_failed(char *exp, char *file, char *base_file, int line); 6 | # define Assert(exp) if (exp) ; \ 7 | else assertion_failed(#exp, __FILE__, __BASE_FILE__, __LINE__) 8 | #else 9 | # define Assert(exp) 10 | #endif /* NDEBUG */ 11 | #endif /* ASSERT */ 12 | -------------------------------------------------------------------------------- /include/kernel/cpu/pic.h: -------------------------------------------------------------------------------- 1 | #ifndef PIC_H 2 | #define PIC_H 3 | 4 | #include 5 | 6 | #define PIC1_CMD_PORT 0x20 7 | #define PIC1_DATA_PORT 0x21 8 | #define PIC2_CMD_PORT 0xA0 9 | #define PIC2_DATA_PORT 0xA1 10 | #define PIC_EOI 0x20 11 | 12 | #define ICW1 0x11 13 | #define ICW4 0x01 14 | 15 | void pic_init(); 16 | void irq_ack(uint8_t irq); 17 | 18 | #endif /* PIC_H */ -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | ============= 2 | = TODO List = 3 | ============= 4 | ./src/kernel/cpu/bios/cmos.c:169:// FIXME: This is a hack to get around the fact that QEMU doesn't support the CMOS registers 0x0B and 0x0C 5 | ./src/kernel/time/rtc.c:158: * @note FIXME: This function is not working properly. It is not setting the correct time. 6 | ./src/kernel/stdio.c:18:// TODO: Make the stdarg header file without using the real libc version 7 | -------------------------------------------------------------------------------- /src/arch/i386/bootloader/crti.s: -------------------------------------------------------------------------------- 1 | .section .init 2 | .global _init 3 | .type _init, @function 4 | _init: 5 | push %ebp 6 | movl %esp, %ebp 7 | /* GCC will contain the contents of crtbegin.o's .init section. */ 8 | 9 | .section .fini 10 | .global _fini 11 | .type _fini, @function 12 | _fini: 13 | push %ebp 14 | movl %esp, %ebp 15 | /* GCC will contain the contents of crtbegin.o's .fini section. */ 16 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "${workspaceFolder}/include" 8 | ], 9 | "defines": [], 10 | "compilerPath": "/usr/bin/gcc", 11 | "cStandard": "c11", 12 | "cppStandard": "c++14", 13 | "intelliSenseMode": "linux-clang-x64" 14 | } 15 | ], 16 | "version": 4 17 | } -------------------------------------------------------------------------------- /src/assert.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifdef ASSERT 6 | 7 | void assertion_failed(char *exp, char *file, char *base_file, int line) 8 | { 9 | if (!strcmp(file, base_file)) 10 | { 11 | qemu_error("Assert(%s) failed in file %s, line %d\n", exp, file, line); 12 | } 13 | else 14 | { 15 | qemu_error("Assert(%s) failed in file %s, (included from %s), line %d\n", exp, file, base_file, line); 16 | } 17 | } 18 | 19 | #endif /* ASSERT */ -------------------------------------------------------------------------------- /include/kernel/kernel.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file kernel.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.4 5 | * @date 2021-07-06 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef KERNEL_H 15 | #define KERNEL_H 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: "1.1.0" 2 | license: "Apache-2.0" 3 | message: "If you use this software, please cite it using these metadata." 4 | url: "https://github.com/TinyKern/TinyKernel" 5 | title: "TinyKernel" 6 | version: "0.1.4" 7 | authors: 8 | - affiliation: "Developer, Maintainer" 9 | family-names: Boreham 10 | given-names: Owen 11 | orcid: "https://orcid.org/0000-0003-4892-3843" 12 | doi: 10.5281/zenodo.1234 13 | date-released: 2021-07-06 14 | keywords: 15 | - "TinyKernel" 16 | - "TinyKern" 17 | - "Bobrossrtx" 18 | - "Owen Boreham" 19 | - "Kernel" 20 | - "Operating System" 21 | -------------------------------------------------------------------------------- /include/drivers/vga/cursor.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cursor.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.0 5 | * @date 2021-08-19 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef CURSOR_H 15 | #define CURSOR_H 16 | 17 | #include "vga.h" 18 | #include 19 | 20 | extern void enable_cursor(uint8_t start, uint8_t end); 21 | extern void disable_cursor(); 22 | 23 | #endif // CURSOR_H 24 | -------------------------------------------------------------------------------- /include/kernel/devices/pcSpeaker.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file pcSpeaker.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.0 5 | * @date 2021-08-12 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef PCSPEAKER_H 15 | #define PCSPEAKER_H 16 | 17 | #include 18 | 19 | extern void pcs_tone_on(uint32_t freq); 20 | extern void pcs_tone_off(); 21 | extern void pcs_beep(); 22 | 23 | #endif // PCSPEAKER_H -------------------------------------------------------------------------------- /config/grub.cfg: -------------------------------------------------------------------------------- 1 | # * @file grub.cfg 2 | # * @author Owen Boreham (owenkadeboreham@gmail.com) 3 | # * @version 0.1 4 | # * @date 2021-07-06 5 | # * 6 | # * @copyright Copyright (c) 2021 TinyKernel 7 | # * This file is part of TinyKernel which is released 8 | # * under Apache License 2.0. See file LICENSE or go 9 | # * to https://www.apache.org/licenses/LICENSE-2.0 for 10 | # * full license details. 11 | 12 | menuentry "TinyKernel 1.3.6" { 13 | insmod all_video 14 | insmod disk 15 | 16 | echo "Loading TinyKernel 1.3.6" 17 | multiboot2 /boot/TinyKernel.elf 18 | echo "TinyKernel 1.3.6 loaded" 19 | 20 | echo "Booting..." 21 | boot 22 | } 23 | -------------------------------------------------------------------------------- /src/kernel/kprintf.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file kprintf.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-08-11 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | 16 | int __kprintf(char *fmt, ...) 17 | { 18 | fmt += '\0'; 19 | va_list args; 20 | va_start(args, fmt); 21 | int ret = printf_internal(fmt, args); 22 | va_end(args); 23 | return ret; 24 | } 25 | -------------------------------------------------------------------------------- /include/drivers/tty/tty.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tty.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.0.7 5 | * @date 2021-08-24 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef TTY_H 15 | #define TTY_H 16 | 17 | #include 18 | 19 | struct tty; 20 | 21 | static ALWAYS_INLINE struct tty *get_curr_tty(void) 22 | { 23 | extern struct tty *__curr_tty; 24 | return __curr_tty; 25 | } 26 | 27 | #endif // TTY_H -------------------------------------------------------------------------------- /include/drivers/video/video.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file video.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-07-06 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef VIDEO_H 15 | #define VIDEO_H 16 | 17 | #define CTRL_SCREEN_REG 0x3d4 18 | #define DATA_SCREEN_REG 0x3d5 19 | 20 | extern int get_cursor_offset(); 21 | extern void set_cursor_offset(int offset); 22 | 23 | extern void clear_screen(); 24 | 25 | #endif -------------------------------------------------------------------------------- /src/drivers/vga/cursor.asm: -------------------------------------------------------------------------------- 1 | ; @file cursor.asm 2 | ; @author Owen Boreham (owenkadeboreham@gmail.com) 3 | ; @version 0.1.2 4 | ; @date 2021-08-19 5 | ; 6 | ; @copyright Copyright (c) 2021 TinyKernel 7 | ; This file is part of TinyKernel which is released 8 | ; under Apache License 2.0. See file LICENSE or go 9 | ; to https://www.apache.org/licenses/LICENSE-2.0 for 10 | ; full license details. 11 | 12 | global disable_cursor 13 | disable_cursor: 14 | pushf 15 | push eax 16 | push edx 17 | 18 | mov dx, 0x3D4 19 | mov al, 0xA 20 | out dx, al 21 | 22 | inc dx 23 | mov al, 0x20 24 | out dx, al 25 | 26 | pop edx 27 | pop eax 28 | popf 29 | ret 30 | -------------------------------------------------------------------------------- /include/sys/char.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file char.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef CHAR_H 15 | #define CHAR_H 16 | 17 | #include 18 | #include 19 | 20 | /** 21 | * @brief Get the ascii char object from the keyboard 22 | * 23 | * @return char 24 | */ 25 | extern char get_ascii_char(uint8_t); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/drivers/serial/serial.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file serial.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-22 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | 16 | int com_is_transmit_empty(uint16_t port) 17 | { 18 | return inb(port + 5) & 0x20; 19 | } 20 | 21 | void com_send_char(uint16_t port, char byte) 22 | { 23 | while (com_is_transmit_empty(port) == 0); 24 | outb(port, byte); 25 | } -------------------------------------------------------------------------------- /src/kernel/syscalls/syscalls.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file shutdown.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-08-12 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | void sys_shutdown(void) 18 | { 19 | out16(0x604, 0x2000); 20 | out16(0x4004, 3400); 21 | out16(0xb004, 0x2000); 22 | 23 | acpi_power_off(); 24 | 25 | kpanic(ESHUTD, "Failed to shutdown"); 26 | } -------------------------------------------------------------------------------- /include/kernel/syscalls/syscalls.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file syscalls.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-07-06 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef SYSCALLS_H 15 | #define SYSCALLS_H 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | /** 23 | * @brief Shutdown the system. 24 | */ 25 | extern void sys_shutdown(void); 26 | 27 | #endif // SYSCALLS_H -------------------------------------------------------------------------------- /src/kernel/stdio.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stdio.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.6 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | // TODO: Make the stdarg header file without using the real libc version 19 | #include 20 | 21 | void __kprint(const char* str) 22 | { 23 | while(*str) 24 | { 25 | vga_putchar(*str); 26 | ++str; 27 | } 28 | } -------------------------------------------------------------------------------- /include/drivers/serial/serial.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file serial.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-22 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef SERIAL_H 15 | #define SERIAL_H 16 | 17 | #include 18 | 19 | #define COM1_PORT 0x3F8 20 | #define COM2_PORT 0x2F8 21 | #define COM3_PORT 0x3E8 22 | #define COM4_PORT 0x2E8 23 | 24 | extern int com_is_transmit_empty(uint16_t port); 25 | extern void com_send_char(uint16_t port, char byte); 26 | 27 | #endif // SERIAL_H -------------------------------------------------------------------------------- /src/kernel/cpu/gdt/load_gdt.s: -------------------------------------------------------------------------------- 1 | /** 2 | * @file load_gdt.s 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-08-15 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | .section .text 15 | .global load_gdt 16 | 17 | load_gdt: 18 | mov 4(%esp), %eax 19 | lgdt (%eax) 20 | 21 | mov $0x10, %eax 22 | mov %eax, %ds 23 | mov %eax, %es 24 | mov %eax, %fs 25 | mov %eax, %gs 26 | mov %eax, %ss 27 | jmp $0x8, $.long_jump 28 | .long_jump: 29 | ret 30 | -------------------------------------------------------------------------------- /include/kernel/panic.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file panic.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-19 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef PANIC_H 15 | #define PANIC_H 16 | 17 | #include 18 | #include 19 | 20 | #include "cpu/cpu.h" 21 | #include "stdio.h" 22 | 23 | /** 24 | * @brief Kernel panic for unhandled exceptions 25 | * 26 | * @param errcode 27 | * @param errmsg 28 | */ 29 | extern void kpanic(int errcode, char* errmsg); 30 | 31 | #endif // PANIC_H -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Version [e.g. 22] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /include/kernel/time/rtc.h: -------------------------------------------------------------------------------- 1 | #ifndef RTC_H 2 | #define RTC_H 3 | #include 4 | #include 5 | 6 | #define CMOS_ADDR 0x70 7 | #define CMOS_DATA 0x71 8 | 9 | typedef struct datetime 10 | { 11 | uint8_t century; 12 | uint8_t year; 13 | uint8_t month; 14 | uint8_t day; 15 | uint8_t hour; 16 | uint8_t minute; 17 | uint8_t second; 18 | } datetime_t; 19 | 20 | int rtc_is_updating(); 21 | uint8_t rtc_get_register(uint8_t reg); 22 | void rtc_set_register(uint8_t reg, uint8_t val); 23 | void rtc_read_datetime(); 24 | void rtc_write_datetime(datetime_t *dt); 25 | char *rtc_datetime_string(datetime_t *dt); 26 | char *rtc_current_datetime_string(); 27 | int rtc_weekday_from_date(datetime_t *dt); 28 | int rtc_leap_year(int year, int month); 29 | void rtc_init(); 30 | 31 | #endif /* RTC_H */ -------------------------------------------------------------------------------- /include/drivers/sb16/sound.h: -------------------------------------------------------------------------------- 1 | #ifndef SOUND_H 2 | #define SOUND_H 3 | 4 | #include 5 | 6 | #define IOCTL_SOUND_ACQUIRE 1 7 | #define IOCTL_SOUND_RELEASE 2 8 | #define IOCTL_SOUND_SETUP 3 9 | #define IOCTL_SOUND_PAUSE 4 10 | #define IOCTL_SOUND_RESUME 5 11 | #define IOCTL_SOUND_GET_INFO 6 12 | #define IOCTL_SOUND_WAIT_COMPLETION 7 13 | 14 | struct sound_card_info 15 | { 16 | char name[32]; 17 | uint32_t max_sample_rate; 18 | uint32_t max_bits; 19 | uint32_t max_channels; 20 | }; 21 | 22 | struct sound_params 23 | { 24 | uint16_t sample_rate; // 441000..22050 etc. 25 | uint8_t bits; // 8..16 26 | uint8_t channels; // 1..2 27 | uint8_t sign; // 0 = unsigned, 1 = signed 28 | }; 29 | 30 | #endif // SOUND_H -------------------------------------------------------------------------------- /include/stdint.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stdint.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.0 5 | * @date 2021-08-24 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #define INT8_MIN (-128) 15 | #define INT8_MAX (127) 16 | 17 | #define INT16_MIN (-32768) 18 | #define INT16_MAX (32767) 19 | 20 | #define INT32_MIN (-2147483648) 21 | #define INT32_MAX (2147483647) 22 | 23 | #define INT64_MIN (-9223372036854775808) 24 | #define INT64_MAX (9223372036854775807) 25 | 26 | #define UINT8_MAX (255) 27 | #define UINT16_MAX (65535) 28 | #define UINT32_MAX (4294967295) 29 | #define UINT64_MAX (18446744073709551615) -------------------------------------------------------------------------------- /src/arch/i386/bootloader/multiboot_header.asm: -------------------------------------------------------------------------------- 1 | ; @file multiboot_header.asm 2 | ; @author Owen Boreham (owenkadeboreham@gmail.com) 3 | ; @version 0.1.2 4 | ; @date 2021-08-23 5 | ; 6 | ; @copyright Copyright (c) 2021 TinyKernel 7 | ; This file is part of TinyKernel which is released 8 | ; under Apache License 2.0. See file LICENSE or go 9 | ; to https://www.apache.org/licenses/LICENSE-2.0 for 10 | ; full license details. 11 | 12 | section .text 13 | header_start: 14 | dd 0xe85250d6 ; magic number 15 | dd 0 ; protected mode code 16 | dd header_end - header_start ; header size 17 | 18 | ; Checksum 19 | dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start)) 20 | 21 | ; required end tag 22 | dw 0 ; type 23 | dw 0 ; flags 24 | dw 8 ; size 25 | header_end: 26 | -------------------------------------------------------------------------------- /include/kernel/stdio.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file stdio.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.5 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef STDIO_H 15 | #define STDIO_H 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "kprintf.h" 24 | 25 | extern void __kprint(const char*); 26 | 27 | /** 28 | * @brief Prints a string on the screen 29 | * @param str - The string to print 30 | */ 31 | #define kprint(...) __kprint(__VA_ARGS__) 32 | #endif 33 | -------------------------------------------------------------------------------- /include/kernel/time/time.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file time.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.0 5 | * @date 2021-08-19 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef TIME_H 15 | #define TIME_H 16 | 17 | #include 18 | 19 | struct tm 20 | { 21 | int tm_sec; 22 | int tm_min; 23 | int tm_hour; 24 | int tm_mday; 25 | int tm_mon; 26 | int tm_year; 27 | int tm_wday; 28 | int tm_yday; 29 | int tm_isdst; 30 | }; 31 | 32 | #define BCD_TO_BIN(val) ((val) = ((val)&15) + ((val)>>4)*10) 33 | 34 | extern long mktime(struct tm*); 35 | 36 | #endif // TIME_H -------------------------------------------------------------------------------- /scripts/gitpush: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | remotes="origin" 4 | while getopts r:b: flag 5 | do 6 | case "${flag}" in 7 | r) remotes="${remotes} ${OPTARG}";; 8 | b) branch=${OPTARG} ;; 9 | *) branch=${OPTARG} ;; 10 | esac 11 | done 12 | 13 | usage() { 14 | echo "GitPush" 15 | echo "Push to multiple remotes on a single branch at the same time." 16 | echo 17 | echo "Syntax: gitpush -b [branch]" 18 | echo 19 | echo "options:" 20 | echo " -b branch name" 21 | echo " -r extra remotes" 22 | echo 23 | echo "refs:" 24 | for branch_t in $(git for-each-ref --shell --format='%(refname)') 25 | do 26 | echo " $(basename ${branch_t%\'})," 27 | done 28 | } 29 | 30 | if [ -z "$branch" ]; then 31 | usage 32 | else 33 | for remote in $remotes 34 | do 35 | echo "$remote -> $branch" 36 | git push -u "$remote" "$branch" 37 | done 38 | fi 39 | -------------------------------------------------------------------------------- /include/kernel/io.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file io.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-07-12 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef IO_H 15 | #define IO_H 16 | 17 | #include 18 | 19 | /** 20 | * keep the cpu busy for doing nothing(nop) 21 | * so that io port will not be processed by cpu 22 | * here timer can also be used, but lets do this in looping counter 23 | */ 24 | extern void wait_for_io(uint32_t timer_count); 25 | 26 | /** 27 | * @brief Sleep for a given number of milliseconds 28 | * 29 | * @param timer_count 30 | */ 31 | extern void sleep(uint32_t timer_count); 32 | 33 | #endif // IO_H -------------------------------------------------------------------------------- /src/kernel/io.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file io.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-12 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | 16 | /** 17 | * keep the cpu busy for doing nothing(nop) 18 | * so that io port will not be processed by cpu 19 | * here timer can also be used, but lets do this in looping counter 20 | */ 21 | void wait_for_io(uint32_t timer_count) 22 | { 23 | while (1) 24 | { 25 | asm volatile("nop"); 26 | timer_count--; 27 | if (timer_count <= 0) 28 | break; 29 | } 30 | } 31 | 32 | void sleep(uint32_t timer_count) 33 | { 34 | wait_for_io(timer_count); 35 | } -------------------------------------------------------------------------------- /include/arch/i386/acpi.h: -------------------------------------------------------------------------------- 1 | #ifndef ACPI_H 2 | #define ACPI_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct RSDPtr 12 | { 13 | byte signature[8]; 14 | byte checksum; 15 | byte oem_id[6]; 16 | byte revision; 17 | dword_t *rsdt_address; 18 | }; 19 | 20 | struct FACP 21 | { 22 | byte signature[4]; 23 | dword_t length; 24 | byte unneded1[40 - 8]; 25 | dword_t *dsdt_address; 26 | byte unneded2[48 - 44]; 27 | dword_t *SMI_CMD; 28 | byte ACPI_ENABLE; 29 | byte ACPI_DISABLE; 30 | byte unneded3[64 - 54]; 31 | dword_t *PM1a_CNT_BLK; 32 | dword_t *PM1b_CNT_BLK; 33 | byte unneded4[89 - 72]; 34 | byte PM1_CNT_LEN; 35 | }; 36 | 37 | int acpi_init(void); 38 | int acpi_enable(void); 39 | void acpi_power_off(void); 40 | 41 | #endif /* ACPI_H */ -------------------------------------------------------------------------------- /src/kernel/panic.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file panic.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.4 5 | * @date 2021-08-24 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | volatile bool __in_panic; 23 | volatile bool __in_double_fault; 24 | volatile bool __in_kernel_shutdown; 25 | 26 | void kpanic(int errcode, char* errmsg) 27 | { 28 | clear_screen(); 29 | vga_set_default_color(vga_create_color(BLACK, WHITE)); 30 | kprintf("Kernel panic: %s - 0x%x\n", errmsg, errcode); 31 | qemu_panic("Kernel panic: %s - %x\n", errmsg, errcode); 32 | for(;;) {} 33 | } 34 | -------------------------------------------------------------------------------- /colors.mk: -------------------------------------------------------------------------------- 1 | #* file Makefile 2 | #* author Owen Boreham (owenkadeboreham@gmail.com) 3 | #* version 0.1.8 4 | #* date 2021-07-08 5 | #* 6 | #* Copyright (c) 2021 TinyKernel 7 | #* This file is part of TinyKernel which is released 8 | #* under Apache License 2.0. See file LICENSE or go 9 | #* to https://www.apache.org/licenses/LICENSE-2.0 for 10 | #* full license details. 11 | 12 | ifneq (,$(findstring xterm,${TERM})) 13 | BLACK = $(shell tput -Txterm setaf 0) 14 | RED = $(shell tput -Txterm setaf 1) 15 | GREEN = $(shell tput -Txterm setaf 2) 16 | YELLOW = $(shell tput -Txterm setaf 3) 17 | LIGHT_PURPLE = $(shell tput -Txterm setaf 4) 18 | PURPLE = $(shell tput -Txterm setaf 5) 19 | BLUE = $(shell tput -Txterm setaf 6) 20 | WHITE = $(shell tput -Txterm setaf 7) 21 | RESET = $(shell tput -Txterm sgr0) 22 | else 23 | BLACK = "" 24 | RED = "" 25 | GREEN = "" 26 | YELLOW = "" 27 | LIGHT_PURPLE = "" 28 | PURPLE = "" 29 | BLUE = "" 30 | WHITE = "" 31 | RESET = "" 32 | endif 33 | -------------------------------------------------------------------------------- /src/kernel/cpu/irq/irq.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint32_t irq_init(void) 4 | { 5 | idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E); 6 | idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E); 7 | idt_set_gate(34, (uint32_t)irq2, 0x08, 0x8E); 8 | idt_set_gate(35, (uint32_t)irq3, 0x08, 0x8E); 9 | idt_set_gate(36, (uint32_t)irq4, 0x08, 0x8E); 10 | idt_set_gate(37, (uint32_t)irq5, 0x08, 0x8E); 11 | idt_set_gate(38, (uint32_t)irq6, 0x08, 0x8E); 12 | idt_set_gate(39, (uint32_t)irq7, 0x08, 0x8E); 13 | idt_set_gate(40, (uint32_t)irq8, 0x08, 0x8E); 14 | idt_set_gate(41, (uint32_t)irq9, 0x08, 0x8E); 15 | idt_set_gate(42, (uint32_t)irq10, 0x08, 0x8E); 16 | idt_set_gate(43, (uint32_t)irq11, 0x08, 0x8E); 17 | idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E); 18 | idt_set_gate(45, (uint32_t)irq13, 0x08, 0x8E); 19 | idt_set_gate(46, (uint32_t)irq14, 0x08, 0x8E); 20 | idt_set_gate(47, (uint32_t)irq15, 0x08, 0x8E); 21 | 22 | qemu_success("IRQ Loaded\r\n"); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /include/kernel/kprintf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file kprintf.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-11 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef KPRINTF_H 15 | #define KPRINTF_H 16 | 17 | extern int __kprintf(char *fmt, ...); 18 | 19 | /** 20 | * @brief Prints a format string to the kernel console 21 | * @param fmt Format string 22 | * @param %c - print a char 23 | * @param %d - print a decimal number 24 | * @param %o - print a octal number 25 | * @param %s - print a string 26 | * @param %x - print a hexadecimal number 27 | * @param %p - print a pointer 28 | * @param %u - print an unsigned decimal number 29 | * @param %f - print a float 30 | * @param %b - print a binary number 31 | */ 32 | #define kprintf(...) __kprintf(__VA_ARGS__) 33 | 34 | #endif // KPRINTF_H -------------------------------------------------------------------------------- /.github/workflows/flawfinder.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | name: flawfinder 7 | 8 | on: 9 | push: 10 | branches: [ "master" ] 11 | pull_request: 12 | # The branches below must be a subset of the branches above 13 | branches: [ "master" ] 14 | schedule: 15 | - cron: '38 19 * * 4' 16 | 17 | jobs: 18 | flawfinder: 19 | name: Flawfinder 20 | runs-on: ubuntu-latest 21 | permissions: 22 | actions: read 23 | contents: read 24 | security-events: write 25 | steps: 26 | - name: Checkout code 27 | uses: actions/checkout@v4 28 | 29 | - name: flawfinder_scan 30 | uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c 31 | with: 32 | arguments: '--sarif ./' 33 | output: 'flawfinder_results.sarif' 34 | 35 | - name: Upload analysis results to GitHub Security tab 36 | uses: github/codeql-action/upload-sarif@v3 37 | with: 38 | sarif_file: ${{github.workspace}}/flawfinder_results.sarif 39 | -------------------------------------------------------------------------------- /src/kernel/devices/pcSpeaker.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file pcSpeaker.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-08-13 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | void pcs_tone_on(uint32_t freq) 20 | { 21 | uint32_t div; 22 | uint8_t tmp; 23 | 24 | // Set the PIT to the desired frequency 25 | div = BASE_FREQ / freq; 26 | outb(0x43, 0xb6); 27 | outb(0x42, (uint8_t)(div)); 28 | outb(0x42, (uint8_t)(div >> 8)); 29 | 30 | // Play sound using PC speaker 31 | tmp = inb(0x61); 32 | if (tmp != (tmp | 3)) 33 | outb(0x61, tmp | 3); 34 | } 35 | 36 | void pcs_tone_off() 37 | { 38 | uint8_t tmp = inb(0x61) & 0xFC; 39 | 40 | outb(0x61, tmp); 41 | } 42 | 43 | void pcs_beep() 44 | { 45 | pcs_tone_on(1000); 46 | sleep(10000000); 47 | pcs_tone_off(); 48 | } -------------------------------------------------------------------------------- /include/sys/utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file utils.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef UTILS_H 15 | #define UTILS_H 16 | 17 | #include 18 | 19 | #include "string.h" 20 | 21 | /** 22 | * @brief Counts the number of digits in a number 23 | * 24 | * @param num The number to count the digits of 25 | * 26 | * @return uint32_t - Number of digits 27 | */ 28 | extern uint32_t digit_count(int); 29 | 30 | /** 31 | * @brief Converts a int to a string 32 | * 33 | * @param value - The value to convert 34 | * @param str - The string to write to 35 | */ 36 | extern void itoa(int, char*); 37 | 38 | /** 39 | * @brief Converts a number into a base string 40 | * 41 | * @param value - The number to convert 42 | * @param base - The base to convert the number to 43 | * 44 | * @return char* - The converted string. 45 | */ 46 | extern char* convert_to_base(unsigned int, int); 47 | 48 | #endif // UTILS_H 49 | -------------------------------------------------------------------------------- /include/buildinfo.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file buildinfo.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.0 5 | * @date 2021-08-26 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #pragma once 15 | 16 | #include "types.h" 17 | 18 | #ifndef __BUILD_ARCH__ 19 | # define __BUILD_ARCH__ "unknown" 20 | #endif /* __BUILD_ARCH__ */ 21 | 22 | #ifndef __BUILD_GITREF__ 23 | # define __BUILD_GITREF__ "unknown" 24 | #endif /* __BUILD_GITREF__ */ 25 | 26 | #ifndef __BUILD_UNAME__ 27 | # define __BUILD_UNAME__ "unknown" 28 | #endif /* __BUILD_UNAME__ */ 29 | 30 | #ifndef __BUILD_DATE__ 31 | # define __BUILD_DATE__ "unknown" 32 | #endif /* __BUILD_DATE__ */ 33 | 34 | #ifndef __BUILD_VERSION__ 35 | # define __BUILD_VERSION__ "unknown" 36 | #endif /* __BUILD_VERSION__ */ 37 | 38 | #ifndef __QEMU__ 39 | # define __QEMU__ FALSE 40 | #endif /* __QEMU__ */ 41 | 42 | #ifndef __SERIAL_COLORS__ 43 | # define __SERIAL_COLORS__ FALSE 44 | #endif /* __SERIAL_COLORS__ */ 45 | 46 | #ifndef __NDEBUG__ 47 | # define __NDEBUG__ FALSE 48 | #endif /* __NDEBUG__ */ 49 | -------------------------------------------------------------------------------- /include/kernel/cpu/bios/cmos.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmos.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-08-15 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef CMOS_C 15 | #define CMOS_C 16 | 17 | #include 18 | #include 19 | 20 | #define READ_CMOS(addr) ({ \ 21 | outb_p(0x80 | addr, 0x70); \ 22 | inb_p(0x71);}) 23 | 24 | extern uint8_t cmod_lowmem(); 25 | extern uint8_t cmod_highmem(); 26 | extern uint16_t cmod_totalmem(); 27 | 28 | extern uint8_t second; 29 | extern uint8_t minute; 30 | extern uint8_t hour; 31 | extern uint8_t day; 32 | extern uint8_t month; 33 | extern uint32_t year; 34 | extern uint8_t century; 35 | extern uint8_t last_second; 36 | extern uint8_t last_minute; 37 | extern uint8_t last_hour; 38 | extern uint8_t last_day; 39 | extern uint8_t last_month; 40 | extern uint8_t last_year; 41 | extern uint8_t last_century; 42 | extern uint8_t registerB; 43 | 44 | void read_rtc(); 45 | 46 | void get_current_time(); 47 | 48 | #endif // CMOS_C -------------------------------------------------------------------------------- /include/arch/i386/elf_core.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file elf_core.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-08-24 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | #include "elf.h" 19 | #include "paging.h" 20 | 21 | #if defined(USE_ELF32) && defined(USE_ELF64) 22 | # error Invalid configuration: USE_ELF32 and USE_ELF64 are both defined. 23 | #endif 24 | 25 | #if defined(USE_ELF32) || !defined(USE_ELF64) 26 | 27 | typedef Elf32_Addr Elf_Addr; 28 | typedef Elf32_Ehdr Elf_Ehdr; 29 | typedef Elf32_Phdr Elf_Phdr; 30 | typedef Elf32_Shdr Elf_Shdr; 31 | typedef Elf32_Sym Elf_Sym; 32 | 33 | #elif !defined(USE_ELF32) || defined(USE_ELF64) 34 | 35 | typedef Elf64_Addr Elf_Addr; 36 | typedef Elf64_Ehdr Elf_Ehdr; 37 | typedef Elf64_Phdr Elf_Phdr; 38 | typedef Elf64_Shdr Elf_Shdr; 39 | typedef Elf64_Sym Elf_Sym; 40 | 41 | #else 42 | 43 | # error Unknown architecture. 44 | 45 | #endif // USE_ELF32 || USE_ELF64 46 | 47 | const char *find_sym_at_addr(uint64_t vaddr, long *offset, uint32_t *sym_size); -------------------------------------------------------------------------------- /src/kernel/cpu/pic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /** 6 | * @brief Initialize the PIC (Programmable Interrupt Controller) 7 | */ 8 | void pic_init() 9 | { 10 | // ICW1: Initialization Command Word 1 11 | // - ICW4 required 12 | // - Cascade mode 13 | // - Level triggered mode 14 | // - 8086/88 mode 15 | outb(PIC1_CMD_PORT, ICW1); 16 | outb(PIC2_CMD_PORT, ICW1); 17 | 18 | // ICW2: Initialization Command Word 2 (IRQs 0-7) 19 | // - Interrupt vector offset 20 | outb(PIC1_DATA_PORT, 0x20); 21 | outb(PIC2_DATA_PORT, 0x28); 22 | 23 | // ICW3: Initialization Command Word 3 (connect master pic with slave pic) 24 | // - Slave PIC is connected to IRQ2 25 | outb(PIC1_DATA_PORT, 0x04); 26 | outb(PIC2_DATA_PORT, 0x02); 27 | 28 | // ICW4: Initialization Command Word 4 (x86 mode) 29 | outb(PIC1_DATA_PORT, ICW4); 30 | outb(PIC2_DATA_PORT, ICW4); 31 | 32 | // Clear the interrupt masks 33 | outb(PIC1_DATA_PORT, 0x00); 34 | outb(PIC2_DATA_PORT, 0x00); 35 | 36 | qemu_success("PIC Loaded"); 37 | } 38 | 39 | /** 40 | * @brief Tell the PIC interrupt is handled 41 | */ 42 | void irq_ack(uint8_t irq) 43 | { 44 | if (irq >= 0x28) 45 | outb(PIC2_CMD_PORT, PIC_EOI); 46 | outb(PIC1_CMD_PORT, PIC_EOI); 47 | } -------------------------------------------------------------------------------- /include/kernel/cpu/gdt/gdt.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file gdt.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-15 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef GDT_H 15 | #define GDT_H 16 | 17 | #include 18 | 19 | #define NULL_SEGMENT 0 20 | #define CODE_SEGMENT 1 21 | #define DATA_SEGMENT 2 22 | 23 | struct GDT 24 | { 25 | uint16_t segment_limit; // segment limit first 0-15 bits 26 | uint16_t base_low; // base first 0-15 bits 27 | uint8_t base_middle; // base 16-23 bits 28 | uint8_t access; // access rights 29 | uint8_t granularity; // high 4 bits (flags) low 4 bits (limit 4 last bits)(limit is 20 bit wide) 30 | uint8_t base_high; // base 24-31 bits 31 | } __attribute__((packed)); 32 | 33 | struct GDT_PTR 34 | { 35 | uint16_t limit_size; // limit size of all GDT segments 36 | struct GDT* base_address; // base address of the first GDT segment 37 | } __attribute__((packed)); 38 | 39 | extern struct GDT gdt_entries[3]; 40 | extern struct GDT_PTR gdt_first; 41 | 42 | void gdt_init(); 43 | 44 | #endif // GDT_H -------------------------------------------------------------------------------- /include/drivers/pci/bus.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bus.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-31 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef PCI_BUS_H 15 | #define PCI_BUS_H 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | void pci_enum_bus(void); 22 | void pci_check(uint8_t bus); 23 | void pci_slot_check(uint8_t bus, uint8_t slot); 24 | 25 | /** 26 | * Reads the PCI config registers for specified device. 27 | * @param bus 8-bit PCI bus number. 28 | * @param slot 5-bit Device slot number on bus. 29 | * @param func 3-bit Function of specified device/slot. 30 | * @param reg 6-bit PCI config register to read. (Multiple of 4) 31 | * @return 32-bit value read from specified register. 32 | */ 33 | uint32_t pci_read_config_reg(uint8_t bus, uint8_t slot, uint8_t func, uint8_t reg); 34 | 35 | typedef struct PciBusEntry_s 36 | { 37 | uint8_t bus; 38 | uint8_t slot; 39 | uint8_t func; 40 | uint16_t vendor_id; 41 | uint16_t device_id; 42 | struct PciDeviceEntry_s *next; 43 | } pci_bus_entry_t; 44 | 45 | #endif // PCI_BUS_H -------------------------------------------------------------------------------- /src/sys/utils.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file utils.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | uint32_t digit_count(int num) 18 | { 19 | uint32_t count = 0; 20 | if (num == 0) 21 | return 1; 22 | while (num > 0) 23 | { 24 | count++; 25 | num = num/10; 26 | } 27 | return count; 28 | } 29 | 30 | void itoa(int value, char* str) 31 | { 32 | int dgcount = digit_count(value); 33 | int index = dgcount - 1; 34 | char x; 35 | if (value == 0 && dgcount == 1) 36 | { 37 | str[0] = '0'; 38 | str[1] = '\0'; 39 | } 40 | else 41 | { 42 | while (value != 0) 43 | { 44 | x = value % 10; 45 | str[index] = x + '0'; 46 | index--; 47 | value = value/10; 48 | } 49 | str[dgcount] = '\0'; 50 | } 51 | } 52 | 53 | char* convert_to_base(unsigned int value, int base) 54 | { 55 | static char rep[] = "0123456789ABCDEF"; 56 | static char buf[50]; 57 | char *ptr; 58 | 59 | ptr = &buf[49]; 60 | *ptr = '\0'; 61 | 62 | do 63 | { 64 | *--ptr = rep[value % base]; 65 | value /= base; 66 | } while (value != 0); 67 | 68 | return (ptr); 69 | } -------------------------------------------------------------------------------- /config.cfg: -------------------------------------------------------------------------------- 1 | #* file config.cfg 2 | #* author Owen Boreham (owenkadeboreham@gmail.com) 3 | #* version 0.1.8 4 | #* date 2021-07-08 5 | #* 6 | #* Copyright (c) 2021 TinyKernel 7 | #* This file is part of TinyKernel which is released 8 | #* under Apache License 2.0. See file LICENSE or go 9 | #* to https://www.apache.org/licenses/LICENSE-2.0 for 10 | #* full license details. 11 | 12 | # General Settings 13 | VERSION=0.1.4 14 | AUTHOR=Bobrossrtx 15 | SERIAL_COLORS=1 16 | 17 | # Build Settings 18 | BUILD_ARCH=i386 19 | BUILD_GITREF=$(shell git rev-parse --abbrev-ref HEAD || echo unknown)@$(shell git rev-parse --short HEAD || echo unknown) 20 | BUILD_UNAME=$(shell uname -s -o -m -r) 21 | BUILD_DATE=$(shell date "+%Y-%m-%d %H:%M:%S") 22 | BUILD_VERSION=$(VERSION) 23 | 24 | # Compiler Settings 25 | BINUTILS_VERSION=2.37 26 | GCC_VERSION=11.2.0 27 | CROSS_PREFIX=${HOME}/.local/bin/TinyKernel-Toolchain 28 | # ^^^ Enter your toolchain location here ^^^ 29 | ARCH=$(BUILD_ARCH)-elf 30 | 31 | # Compilers, Linkers, Assemblers 32 | CC=$(CROSS_PREFIX)/bin/$(ARCH)-gcc 33 | CXX=$(CROSS_PREFIX)/bin/$(ARCH)-g++ 34 | AS=$(CROSS_PREFIX)/bin/$(ARCH)-as 35 | LD=$(CROSS_PREFIX)/bin/$(ARCH)-ld 36 | NASM=nasm 37 | 38 | # Directories 39 | BASE_DIR=$(shell pwd) 40 | SRC_DIRS=src 41 | INC_DIRS=include 42 | BUILD_DIR=build 43 | OBJ_DIR=$(BUILD_DIR)/obj 44 | ISO_DIR=$(BUILD_DIR)/iso 45 | BOOT_DIR=$(BUILD_DIR)/boot 46 | GRUB_DIR=$(BOOT_DIR)/grub 47 | PROJ_DIR=$(SRC_DIRS) $(INC_DIRS) $(OBJ_DIR) 48 | 49 | # Debug Settings 50 | QEMU_DEBUG=1 51 | NDEBUG=0 52 | -------------------------------------------------------------------------------- /include/kernel/cpu/cpu.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cpu.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-08-12 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef CPU_H 15 | #define CPU_H 16 | 17 | #include 18 | #include "ports.h" 19 | 20 | #define LSW(x) ((uint32)(x)&0xFFFF) 21 | #define MSW(x) (((uint32)(x) >> 16) & 0xFFFF) 22 | #define LSB(x) ((x)&0xFF) 23 | #define MSB(x) (((x) >> 8) & 0xFF) 24 | 25 | struct regs 26 | { 27 | size_t r15; 28 | size_t r14; 29 | size_t r13; 30 | size_t r12; 31 | size_t rbp; 32 | size_t rbx; 33 | size_t r11; 34 | size_t r10; 35 | size_t r9; 36 | size_t r8; 37 | size_t rax; 38 | size_t rcx; 39 | size_t rdx; 40 | size_t rsi; 41 | size_t rdi; 42 | size_t orig_rax; 43 | size_t rip; 44 | size_t cs; 45 | size_t eflags; 46 | size_t rsp; 47 | size_t ss; 48 | size_t fs_base; 49 | size_t gs_base; 50 | size_t ds; 51 | size_t es; 52 | size_t fs; 53 | size_t gs; 54 | size_t edi, esi, ebp, esp, ebx, edx, ecx, eax; 55 | }; 56 | 57 | typedef struct regs regs_t; 58 | 59 | // extern void cpuid(uint32_t value, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); 60 | extern void cpuid_info(); 61 | 62 | #endif // CPU_H -------------------------------------------------------------------------------- /src/drivers/vga/cursor.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cursor.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-19 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | uint8_t cursor_x = 0; 20 | uint8_t cursor_y = 0; 21 | 22 | static void update_cursor_position(void) 23 | { 24 | uint16_t cursor_location; 25 | 26 | /* Get the location of the cursor as a flat array index */ 27 | cursor_location = (cursor_y * 80) + cursor_x; 28 | 29 | /* Send the high cursor byte */ 30 | outb(0x3D4, 14); 31 | outb(0x3D5, (cursor_location >> 8)); 32 | 33 | /* Send the low cursor byte. */ 34 | outb(0x3D4, 15); 35 | outb(0x3D5, cursor_location); 36 | } 37 | 38 | void move_cursor(uint8_t x, uint8_t y) 39 | { 40 | uint8_t dest_x; 41 | uint8_t dest_y; 42 | 43 | dest_x = MIN(x, 80); 44 | dest_y = MIN(y, 25); 45 | 46 | cursor_x = dest_x; 47 | cursor_y = dest_y; 48 | update_cursor_position(); 49 | } 50 | 51 | void enable_cursor(uint8_t start, uint8_t end) 52 | { 53 | outb(0x3D4, 0x0A); 54 | outb(0x3D5, (inb(0x3D5) & 0xC0) | start); 55 | 56 | outb(0x3D4, 0x0A); 57 | outb(0x3D5, (inb(0x3D5) & 0xE0) | end); 58 | } 59 | -------------------------------------------------------------------------------- /src/drivers/video/video.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file video.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-07-06 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | int get_offset(int col, int row); 19 | 20 | int get_cursor_offset() 21 | { 22 | outb(CTRL_SCREEN_REG, 14); 23 | int off = inb(DATA_SCREEN_REG) << 8; // High byte: << 8 24 | outb(CTRL_SCREEN_REG, 15); 25 | off += inb(DATA_SCREEN_REG); 26 | 27 | return off * 2; // Position * size of char cell 28 | } 29 | 30 | void set_cursor_offset(int offset) 31 | { 32 | offset /= 2; 33 | outb(CTRL_SCREEN_REG, 14); 34 | outb(DATA_SCREEN_REG, (uint8_t)(offset >> 8)); 35 | outb(CTRL_SCREEN_REG, 15); 36 | outb(DATA_SCREEN_REG, (uint8_t)(offset & 0xff)); 37 | } 38 | 39 | void clear_screen() 40 | { 41 | for (int col = 0; col < VGA_COLS; col++) 42 | { 43 | for (int row = 0; row < VGA_ROWS; row++) 44 | { 45 | vga_put_entry(vga_create_entry(' ', vga_create_color(BLACK, BLACK)), col, row); 46 | } 47 | } 48 | 49 | vga_set_default_color(vga_create_color(BLACK, GREY)); 50 | set_cursor_offset(get_offset(0, 0)); 51 | set_buffer_position(0, 0); 52 | } 53 | 54 | int get_offset(int col, int row) { return 2 * (row * VGA_COLS + col); } -------------------------------------------------------------------------------- /src/kernel/time/mktime.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mktime.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-19 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | 15 | #include 16 | 17 | #define MINUTE 60 18 | #define HOUR (60 * MINUTE) 19 | #define DAY (24 * HOUR) 20 | #define YEAR (365 * DAY) 21 | 22 | static int monthk[12] = { 23 | 0, 24 | DAY * (31), 25 | DAY * (31+29), 26 | DAY * (31+29+31), 27 | DAY * (31+29+31+30), 28 | DAY * (31+29+31+30+31), 29 | DAY * (31+29+31+30+31+30), 30 | DAY * (31+29+31+30+31+30+31), 31 | DAY * (31+29+31+30+31+30+31+31), 32 | DAY * (31+29+31+30+31+30+31+31+30), 33 | DAY * (31+29+31+30+31+30+31+31+30+31), 34 | DAY * (31+29+31+30+31+30+31+31+30+31+30) 35 | }; 36 | 37 | long mktime(struct tm *tm) 38 | { 39 | long res; 40 | int year; 41 | 42 | year = tm->tm_year - 70; 43 | /* Magic offset (y+1) to get leap year */ 44 | res = YEAR*year + DAY*((year+1)/4); 45 | res += monthk[tm->tm_mon]; 46 | /* Magic offset (y+2) to get non-leap year */ 47 | if (tm->tm_mon > 1 && ((year+2) % 4)) 48 | res -= DAY; 49 | res += DAY * (tm->tm_mday - 1); 50 | res += HOUR * tm->tm_hour; 51 | res += MINUTE * tm->tm_min; 52 | res += tm->tm_sec; 53 | return res; 54 | } -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 2021-09-26 bobrossrtx 2 | 3 | * notes: Added some todo's/fixme's, going to work on rtc another time 4 | 5 | 6 | 2021-09-26 bobrossrtx 7 | 8 | * kernel & rtc: Started working on rtc time & cleaned up kernel_entry 9 | 10 | 11 | 2021-09-26 bobrossrtx 12 | 13 | * string.h/c: Cleaned up & updated memset function 14 | 15 | 16 | 2021-09-26 bobrossrtx 17 | 18 | * logging: Updated output of drivers 19 | 20 | 21 | 2021-09-26 bobrossrtx 22 | 23 | * cfg: Moved a couple things around 24 | 25 | 26 | 2021-09-24 owen 27 | 28 | Merge branch 'master' of github.com:TinyKern/TinyKernel 29 | 30 | * 'master' of github.com:TinyKern/TinyKernel: 31 | Moved bootloader & added global constructors 32 | 33 | 2021-09-24 owen 34 | 35 | * fix: removed undefined function call 36 | 37 | 38 | 2021-09-24 owen 39 | 40 | * bump: I don't even know what I added, just read through code, and it works 41 | 42 | 43 | 2021-09-21 bobrossrtx 44 | 45 | Moved bootloader & added global constructors 46 | 47 | 48 | 2021-09-17 Owen Boreham 49 | 50 | Merge pull request #14 from TinyKern/idt-irq-interrupts 51 | 52 | Added IRQ, ISR, IDT & Interrupts 53 | Local Variables: 54 | mode: change-log 55 | left-margin: 8 56 | fill-column: 76 57 | version-control: never 58 | End: 59 | -------------------------------------------------------------------------------- /include/drivers/vga/vga.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file vga.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef VGA_H 15 | #define VGA_H 16 | 17 | #include 18 | #include 19 | 20 | #include "cursor.h" 21 | 22 | #define VGA_ADDRESS 0xB8000 23 | #define VGA_COLS 80 24 | #define VGA_ROWS 25 25 | 26 | struct vga_entry_t { 27 | uint8_t ch; 28 | uint8_t color; 29 | }; 30 | 31 | // color 32 | 33 | uint8_t vga_create_color(uint8_t bg, uint8_t fg); 34 | void vga_set_default_color(uint8_t color); 35 | 36 | // entry 37 | 38 | struct vga_entry_t vga_create_entry(uint8_t ch, uint8_t color); 39 | void vga_put_entry(struct vga_entry_t, size_t x, size_t y); 40 | void vga_write_string(const char* str, size_t x, size_t y); 41 | void vga_init(); 42 | 43 | // output 44 | 45 | void vga_putchar(const char c); 46 | uint32_t draw(uint32_t x, uint32_t y, uint8_t color); 47 | 48 | void set_buffer_position(size_t x, size_t y); 49 | 50 | enum vga_color { 51 | BLACK, 52 | BLUE, 53 | GREEN, 54 | CYAN, 55 | RED, 56 | MAGENTA, 57 | BROWN, 58 | GREY, 59 | DARK_GREY, 60 | BRIGHT_BLUE, 61 | BRIGHT_GREEN, 62 | BRIGHT_CYAN, 63 | BRIGHT_RED, 64 | BRIGHT_MAGENTA, 65 | YELLOW, 66 | WHITE 67 | }; 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/kernel/time/PIT.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file PIT.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-08-24 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | void pit_init(uint32_t frequency) 21 | { 22 | uint32_t divisor = 1193180 / frequency; 23 | 24 | outb(0x43, 0x36); 25 | outb(0x40, (uint8_t)divisor & 0xFF); 26 | outb(0x40, (uint8_t)(divisor >> 8) & 0xFF); 27 | 28 | qemu_success("PIT Loaded, %uHz\r\n", frequency); 29 | } 30 | 31 | volatile uint64_t pit_ticks = 0; 32 | 33 | void pit_add_tick() 34 | { 35 | pit_ticks++; 36 | outb(0x20, 0x20); 37 | } 38 | 39 | void pit_add_ticks(uint64_t ticks) 40 | { 41 | pit_ticks += ticks; 42 | outb(0x20, 0x20); 43 | } 44 | 45 | uint64_t pit_get_ticks() 46 | { return pit_ticks; } 47 | 48 | unsigned read_pit_count(void) 49 | { 50 | unsigned count = 0; 51 | 52 | // Disables interrupts 53 | cli(); 54 | 55 | outb(0x43, 0b0000000); 56 | 57 | // Reads the count 58 | count = inb(0x40); // Low byte 59 | count |= inb(0x40) << 8; // High byte 60 | 61 | return count; 62 | } 63 | 64 | void set_pit_count(unsigned count) 65 | { 66 | // Disables interrupts 67 | cli(); 68 | 69 | // Set low byte 70 | outb(0x40, count & 0xFF); 71 | outb(0x40, (count & 0xFF00) >> 8); 72 | return; 73 | } 74 | -------------------------------------------------------------------------------- /include/debug/qemu.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file qemu.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-08-22 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef QEMU_H 15 | #define QEMU_H 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | void qemu_puthex(uint32_t i); 24 | void qemu_printf(char* fmt, ...); 25 | 26 | void _qemu_dbg(char *fmt, ...); 27 | void _qemu_success(char *fmt, ...); 28 | void _qemu_info(char *fmt, ...); 29 | void _qemu_error(char* fmt, ...); 30 | void _qemu_panic(char* fmt, ...); 31 | void _qemu_device(char* fmt, ...); 32 | void _qemu_warning(char* fmt, ...); 33 | 34 | #if CONFIG_QEMU_DEBUG 35 | # define qemu_dbg(fmt, ...) _qemu_dbg(fmt, ##__VA_ARGS__) 36 | # define qemu_success(fmt, ...) _qemu_success(fmt, ##__VA_ARGS__) 37 | # define qemu_info(fmt, ...) _qemu_info(fmt, ##__VA_ARGS__) 38 | # define qemu_error(fmt, ...) _qemu_error(fmt, ##__VA_ARGS__) 39 | # define qemu_panic(fmt, ...) _qemu_panic(fmt, ##__VA_ARGS__) 40 | # define qemu_device(fmt, ...) _qemu_device(fmt, ##__VA_ARGS__) 41 | # define qemu_warning(fmt, ...) _qemu_warning(fmt, ##__VA_ARGS__) 42 | #else 43 | # define qemu_dbg(fmt, ...) 44 | # define qemu_success(fmt, ...) 45 | # define qemu_info(fmt, ...) 46 | # define qemu_error(fmt, ...) 47 | # define qemu_panic(fmt, ...) 48 | # define qemu_device(fmt, ...) 49 | # define qemu_warning(fmt, ...) 50 | #endif /* CONFIG_QEMU_DEBUG */ 51 | 52 | #endif // QEMU_H -------------------------------------------------------------------------------- /config/linker.ld: -------------------------------------------------------------------------------- 1 | /** 2 | * @file linker.ld 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-07-06 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | /* entry point of our kernel */ 15 | ENTRY(_start) 16 | OUTPUT_FORMAT(elf32-i386) 17 | OUTPUT_ARCH(i386:i386) 18 | 19 | /* Tell where the various sections of the object files 20 | will be put in final kernel image. */ 21 | SECTIONS 22 | { 23 | /* we need 1MB of space atleast */ 24 | . = 1M; 25 | 26 | /* Define kernel image base address */ 27 | _kernel_start = .; 28 | 29 | /* First we put the multiboot header, as it is required 30 | to be put very early in the image or the bootloader 31 | won't recognize the file format. */ 32 | /* text section */ 33 | .text BLOCK(4K) : ALIGN(4K) 34 | { 35 | *(.multiboot) 36 | *(.text) 37 | } 38 | 39 | /* Read-only data. */ 40 | .rodata BLOCK(4K) : ALIGN(4K) 41 | { 42 | *(.rodata) 43 | } 44 | 45 | /* Read-Write data (initialized) */ 46 | .data BLOCK(4K) : ALIGN(4K) 47 | { 48 | start_ctors = .; 49 | KEEP(*(.init_array)); 50 | KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* ))); 51 | end_ctors = .; 52 | 53 | *(.data) 54 | } 55 | 56 | /* Read-Write data (uninitialized) & stack */ 57 | .bss BLOCK(4K) : ALIGN(4K) 58 | { 59 | *(COMMON) 60 | *(.bss) 61 | } 62 | 63 | /* Define kernel image end address */ 64 | _kernel_end = .; 65 | } -------------------------------------------------------------------------------- /src/kernel/cpu/ports.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ports.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | 16 | uint8_t inb(uint16_t port) 17 | { 18 | uint8_t ret; 19 | asm volatile("inb %1, %0" : "=a"(ret) : "d"(port)); 20 | return ret; 21 | } 22 | 23 | void outb(uint16_t port, uint8_t data) 24 | { 25 | asm volatile("outb %0, %1" : "=a"(data) : "d"(port)); 26 | } 27 | 28 | uint16_t inw(uint16_t port) 29 | { 30 | uint16_t ret; 31 | asm volatile("in %%dx, %%ax" : "=a"(ret) : "d"(port)); 32 | return ret; 33 | } 34 | 35 | 36 | void outw(uint16_t port, uint16_t data) 37 | { 38 | asm volatile("out %0, %1" : "=a"(data) : "d"(port)); 39 | } 40 | 41 | uint8_t in8(uint16_t port) 42 | { 43 | uint8_t ret; 44 | asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port)); 45 | return ret; 46 | } 47 | 48 | void out8(uint16_t port, uint8_t data) 49 | { 50 | asm volatile("outb %0, %1" ::"a"(data), "Nd"(port)); 51 | } 52 | 53 | uint16_t in16(uint16_t port) 54 | { 55 | uint16_t ret; 56 | asm volatile("inw %1, %0" : "=a"(ret) : "Nd"(port)); 57 | return ret; 58 | } 59 | 60 | void out16(uint16_t port, uint16_t data) 61 | { 62 | asm volatile("outw %0, %1" ::"a"(data), "Nd"(port)); 63 | } 64 | 65 | uint32_t in32(uint16_t port) 66 | { 67 | uint32_t ret; 68 | 69 | asm volatile("inl %w1, %0": "=a"(ret): "d"(port)); 70 | return ret; 71 | } 72 | 73 | void out32(uint16_t port, uint32_t data) 74 | { 75 | asm volatile("outl %0, %w1":: "a"(data), "d"(port)); 76 | } -------------------------------------------------------------------------------- /include/system.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYSTEM_H__ 2 | #define __SYSTEM_H__ 3 | 4 | /* Allignment macros */ 5 | #define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) 6 | #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) 7 | 8 | /* Load address (0xC0000000) - What low memory address such as 0xb800 you used to access, shoudl be LOAD_MEMORY_ADDRESS + 0xb800 */ 9 | #define LOAD_MEMORY_ADDRESS 0x00000000 10 | 11 | /* Sizes */ 12 | #define KB(x) ((x) * 1024) 13 | #define MB(x) ((x) * 1024 * 1024) 14 | #define GB(x) ((x) * 1024 * 1024 * 1024) 15 | 16 | /* CPU Instructions */ 17 | #define sti() __asm__ ("sti"::) 18 | #define cli() __asm__ ("cli"::) 19 | #define nop() __asm__ ("nop"::) 20 | #define hlt() __asm__ ("hlt"::) 21 | #define ret() __asm__ ("ret"::) 22 | #define iret() __asm__ ("iret"::) 23 | #define retf() __asm__ ("retf"::) 24 | #define clwb() __asm__ ("clwb"::) 25 | #define pause() __asm__ ("pause"::) 26 | #define rdtsc() __asm__ ("rdtsc"::) 27 | #define pause() __asm__ ("pause"::) 28 | #define rdtsc() __asm__ ("rdtsc"::) 29 | #define cpuid() __asm__ ("cpuid"::) 30 | #define rdmsr() __asm__ ("rdmsr"::) 31 | #define wrmsr() __asm__ ("wrmsr"::) 32 | #define rdtscp() __asm__ ("rdtscp"::) 33 | #define lfence() __asm__ ("lfence"::) 34 | #define mfence() __asm__ ("mfence"::) 35 | #define sfence() __asm__ ("sfence"::) 36 | #define clflush() __asm__ ("clflush"::) 37 | #define xorl(a,b) __asm__ ("xorl %0,%1"::"r"(a),"r"(b):"cc") 38 | #define xorl_r(a,b,c) __asm__ ("xorl %0,%1":"=r"(a):"0"(b),"1"(c):"cc") 39 | #define xorl_m(a,b,c) __asm__ ("xorl %0,%1":"=r"(a):"0"(b),"1"(c):"cc") 40 | 41 | #endif /* __SYSTEM_H__ */ -------------------------------------------------------------------------------- /include/kernel/time/PIT.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file PIT.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-08-12 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef PIT_H 15 | #define PIT_H 16 | 17 | #include 18 | 19 | #include 20 | 21 | /* Timer related ports */ 22 | #define TIMER_T0_CTL 0x40 23 | #define TIMER_T1_CTL 0x41 24 | #define TIMER_T2_CTL 0x42 25 | #define PIT_CTL 0x43 26 | 27 | /* Building blocks for PIT_CTL */ 28 | #define TIMER_T0_SELECT 0x00 29 | #define TIMER_T1_SELECT 0x40 30 | #define TIMER_T2_SELECT 0x80 31 | 32 | #define MODE_COUNTDOWN 0x00 33 | #define MODE_ONESHOT 0x02 34 | #define MODE_RATEGEN 0x04 35 | #define MODE_SQAURE_WAVE 0x06 36 | 37 | #define WRITE_WORD 0x30 38 | 39 | /* Addresses of PIT registers */ 40 | #define PIC_MASTER_COMMAND 0x20 41 | #define PIC_MASTER_DATA 0x21 42 | #define PIC_SLAVE_COMMAND 0xA0 43 | #define PIC_SLAVE_DATA 0xA1 44 | 45 | /* Macros for setting up the PIT */ 46 | #define PIC_MASTER_CMD_OUT(byte) outb(PIC_MASTER_COMMAND, (byte)) 47 | #define PIC_MASTER_DATA_OUT(byte) outb(PIC_MASTER_DATA, (byte)) 48 | #define PIC_SLAVE_CMD_OUT(byte) outb(PIC_SLAVE_COMMAND, (byte)) 49 | #define PIC_SLAVE_DATA_OUT(byte) outb(PIC_SLAVE_DATA, (byte)) 50 | 51 | #define BASE_FREQ 1193180 52 | 53 | void pit_init(uint32_t frequency); 54 | 55 | void pit_add_tick(); 56 | void pit_add_ticks(uint64_t ticks); 57 | uint64_t pit_get_ticks(); 58 | 59 | unsigned read_pit_count(void); 60 | void set_pit_count(unsigned count); 61 | 62 | #endif // PIT_H -------------------------------------------------------------------------------- /include/kernel/cpu/isr/isr.h: -------------------------------------------------------------------------------- 1 | #ifndef ISR_H 2 | #define ISR_H 3 | 4 | #include 5 | #include 6 | 7 | /* ISR_DEBUG (define if debugging) */ 8 | #define ISR_DEBUG 1 9 | 10 | #ifdef ISR_DEBUG 11 | # define isr_debug(...) { \ 12 | qemu_dbg("%s:%d, %s() ", \ 13 | __FILE__, __LINE__, __func__); \ 14 | }; 15 | #else 16 | # define isr_debug(f, ...) /* nothing */ 17 | #endif 18 | 19 | /* Interrupt Service Routine prototype */ 20 | typedef void (*isr_t)(register_t*); 21 | 22 | /* Interrupt handlers */ 23 | extern isr_t interrupt_handlers[256]; 24 | void register_interrupt_handler(uint8_t interrupt_number, isr_t handler); 25 | void final_irq_handler(register_t *reg); 26 | 27 | /* IRQ Map */ 28 | #define IRQ0 32 29 | #define IRQ1 33 30 | #define IRQ2 34 31 | #define IRQ3 35 32 | #define IRQ4 36 33 | #define IRQ5 37 34 | #define IRQ6 38 35 | #define IRQ7 39 36 | #define IRQ8 40 37 | #define IRQ9 41 38 | #define IRQ10 42 39 | #define IRQ11 43 40 | #define IRQ12 44 41 | #define IRQ13 45 42 | #define IRQ14 46 43 | #define IRQ15 47 44 | 45 | /* IRQ Constants */ 46 | #define IRQ_BASE 0x20 47 | #define IRQ_SLAVE_BASE 0x00 48 | #define IRQ1_Keyboard 0x01 49 | #define IRQ2_CASCADE 0x02 50 | #define IRQ3_SERIAL_PORT2 0x03 51 | #define IRQ4_SERIAL_PORT1 0x04 52 | #define IRQ5_RESERVED 0x05 53 | #define IRQ6_DISKETTE_DRIVE 0x06 54 | #define IRQ7_PARALLEL_PORT 0x07 55 | #define IRQ8_CMOS_CLOCK 0x08 56 | #define IRQ9_CGA 0x09 57 | #define IRQ10_RESERVED 0x0A 58 | #define IRQ11_RESERVED 0x0B 59 | #define IRQ12_AUXILIARY 0x0C 60 | #define IRQ13_FPU 0x0D 61 | #define IRQ14_HARD_DISK 0x0E 62 | #define IRQ15_RESERVED 0x0F 63 | 64 | #endif /* ISR_H */ -------------------------------------------------------------------------------- /src/kernel/cpu/gdt/gdt.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file gdt.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-15 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | struct GDT gdt_entries[3]; 18 | struct GDT_PTR gdt_first; 19 | 20 | extern void load_gdt(struct GDT*); 21 | 22 | void gdt_init() 23 | { 24 | // Set null segment 25 | gdt_entries[NULL_SEGMENT].segment_limit = 0; 26 | gdt_entries[NULL_SEGMENT].base_low = 0; 27 | gdt_entries[NULL_SEGMENT].base_middle = 0; 28 | gdt_entries[NULL_SEGMENT].access = 0; 29 | gdt_entries[NULL_SEGMENT].granularity = 0; 30 | gdt_entries[NULL_SEGMENT].base_high = 0; 31 | 32 | // Set code segment 33 | gdt_entries[CODE_SEGMENT].segment_limit = 0xFFFF; 34 | gdt_entries[CODE_SEGMENT].base_low = 0; 35 | gdt_entries[CODE_SEGMENT].base_middle = 0; 36 | gdt_entries[CODE_SEGMENT].access = 0x9A; 37 | gdt_entries[CODE_SEGMENT].granularity = 0b11001111; 38 | gdt_entries[CODE_SEGMENT].base_high = 0; 39 | 40 | // Set data segment 41 | gdt_entries[DATA_SEGMENT].segment_limit = 0xFFFF; 42 | gdt_entries[DATA_SEGMENT].base_low = 0; 43 | gdt_entries[DATA_SEGMENT].base_middle = 0; 44 | gdt_entries[DATA_SEGMENT].access = 0x92; 45 | gdt_entries[DATA_SEGMENT].granularity = 0b11001111; 46 | gdt_entries[DATA_SEGMENT].base_high = 0; 47 | 48 | gdt_first.limit_size = sizeof(gdt_entries) - 1; 49 | gdt_first.base_address = (struct GDT*)&gdt_entries; 50 | 51 | load_gdt((struct GDT*)&gdt_first); 52 | 53 | qemu_success("GDT Loaded, base->%p\r\n", gdt_first.base_address); 54 | } -------------------------------------------------------------------------------- /src/sys/char.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file char.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.1 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | 16 | char get_ascii_char(uint8_t key_code) 17 | { 18 | switch (key_code) 19 | { 20 | case KEY_A : return 'A'; 21 | case KEY_B : return 'B'; 22 | case KEY_C : return 'C'; 23 | case KEY_D : return 'D'; 24 | case KEY_E : return 'E'; 25 | case KEY_F : return 'F'; 26 | case KEY_G : return 'G'; 27 | case KEY_H : return 'H'; 28 | case KEY_I : return 'I'; 29 | case KEY_J : return 'J'; 30 | case KEY_K : return 'K'; 31 | case KEY_L : return 'L'; 32 | case KEY_M : return 'M'; 33 | case KEY_N : return 'N'; 34 | case KEY_O : return 'O'; 35 | case KEY_P : return 'P'; 36 | case KEY_Q : return 'Q'; 37 | case KEY_R : return 'R'; 38 | case KEY_S : return 'S'; 39 | case KEY_T : return 'T'; 40 | case KEY_U : return 'U'; 41 | case KEY_V : return 'V'; 42 | case KEY_W : return 'W'; 43 | case KEY_X : return 'X'; 44 | case KEY_Y : return 'Y'; 45 | case KEY_Z : return 'Z'; 46 | case KEY_0 : return '0'; 47 | case KEY_1 : return '1'; 48 | case KEY_2 : return '2'; 49 | case KEY_3 : return '3'; 50 | case KEY_4 : return '4'; 51 | case KEY_5 : return '5'; 52 | case KEY_6 : return '6'; 53 | case KEY_7 : return '7'; 54 | case KEY_8 : return '8'; 55 | case KEY_9 : return '9'; 56 | case KEY_MINUS : return '-'; 57 | case KEY_EQUAL : return '='; 58 | case KEY_SQUARE_OPEN_BRACKET : return '['; 59 | case KEY_SQUARE_CLOSE_BRACKET : return ']'; 60 | case KEY_SEMICOLON : return ';'; 61 | case KEY_BACKSLASH : return '\\'; 62 | case KEY_COMMA : return ','; 63 | case KEY_DOT : return '.'; 64 | case KEY_FORESLHASH : return '/'; 65 | case KEY_SPACE : return ' '; 66 | default : return 0; 67 | } 68 | } -------------------------------------------------------------------------------- /include/kernel/memory.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file memory.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-17 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef MEMORY_H 15 | #define MEMORY_H 16 | 17 | #include 18 | 19 | typedef struct MemorySegmentHeader 20 | { 21 | uint64_t length; 22 | struct MemorySegmentHeader *next; 23 | struct MemorySegmentHeader *prev; 24 | struct MemorySegmentHeader *next_free; 25 | struct MemorySegmentHeader *prev_free; 26 | bool free; 27 | } MemorySegmentHeader; 28 | 29 | #define ALLOC_UNIT 3 * (1024 * 4) 30 | 31 | void heap_init(uint64_t heap_address, uint64_t heap_size); 32 | 33 | /** 34 | * @brief Allocate memory for a new memory block 35 | * @param size The size of the memory block to allocate 36 | * @return A pointer to the allocated memory block 37 | */ 38 | void* kmalloc(size_t size); 39 | 40 | /** 41 | * @brief Free memory allocated for a memory block 42 | * @param ptr The pointer to the memory block to free 43 | * @return A pointer to the memory block 44 | */ 45 | void kfree(void* ptr); 46 | 47 | /** 48 | * @brief Allocate memory memory for an array of nmemb elements 49 | * @param nmemb The number of elements to allocate 50 | * @param size The size of each element 51 | * @return A pointer to the allocated memory block 52 | */ 53 | extern void* kcalloc(size_t nmemb, size_t size); 54 | 55 | /** 56 | * @brief changes the size of a memory block 57 | * @param ptr The pointer to the memory block 58 | * @param size The new size of the memory block 59 | * @return A pointer to the memory block 60 | * @note This function does not free the memory block 61 | * and the new memory block is not zeroed 62 | * @note This function does not check if the memory block 63 | * is already allocated 64 | */ 65 | extern void* krealloc(void* ptr, size_t size); 66 | 67 | 68 | #endif // MEMORY_H 69 | -------------------------------------------------------------------------------- /src/arch/i386/elf.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file elf.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-24 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | 16 | void get_symtab_and_strtab(Elf_Shdr **symtab, Elf_Shdr **strtab) 17 | { 18 | Elf_Ehdr *h = (Elf_Ehdr*)(KERNEL_PA_TO_VA(KERNEL_PADDR)); 19 | *symtab = NULL; 20 | *strtab = NULL; 21 | 22 | if (!KERNEL_SYMBOLS) 23 | return; 24 | 25 | VERIFY(h->e_shentsize == sizeof(Elf_Shdr)); 26 | Elf_Shdr *sections = (Elf_Shdr*)((void *)h + h->e_shoff); 27 | 28 | for (u32 i = 0; i < h->e_shnum; i++) 29 | { 30 | Elf_Shdr *s = sections + i; 31 | 32 | if (s -> sh_type == SHT_SYMTAB) 33 | { 34 | Assert(!*symtab); 35 | *symtab = s; 36 | } 37 | else if (s->sh_type == SHT_STRTAB && i != h->e_shstrndx) 38 | { 39 | Assert(!*strtab); 40 | *strtab = s; 41 | } 42 | } 43 | 44 | VERIFY(*symtab != NULL); 45 | VERIFY(*strtab != NULL); 46 | } 47 | 48 | const char *find_sym_at_addr(uint64_t vaddr, long *offset, uint32_t *sym_size) 49 | { 50 | Elf_Shdr *symtab; 51 | Elf_Shdr *strtab; 52 | 53 | if (!KERNEL_SYMBOLS) 54 | return NULL; 55 | 56 | get_symtab_and_strtab(&symtab, &strtab); 57 | 58 | Elf_Sym *syms = (Elf_Sym*) symtab->sh_addr; 59 | const uint64_t sym_count = symtab->sh_size / sizeof(Elf_Sym); 60 | 61 | for (u32 i = 0; i < sym_count; i++) 62 | { 63 | Elf_Sym *sym = syms + i; 64 | 65 | if (IN_RANGE(vaddr, sym->st_value, sym->st_value + sym->st_size)) 66 | { 67 | if (offset) 68 | *offset = (long)(vaddr - sym->st_value); 69 | 70 | if (sym_size) 71 | *sym_size = (uint32_t)sym->st_size; 72 | 73 | return (char*)strtab->sh_addr + sym->st_name; 74 | } 75 | } 76 | 77 | return NULL; 78 | } -------------------------------------------------------------------------------- /include/config.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file configure.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef CONFIG_H 15 | #define CONFIG_H 16 | 17 | #include "buildinfo.h" 18 | #include "types.h" 19 | 20 | extern uint16_t* vga_buffer; 21 | 22 | // Index for video buffer array 23 | extern uint32_t vga_index; 24 | 25 | extern uint8_t g_fore_color; 26 | extern uint8_t g_back_color; 27 | 28 | #define KERNEL_VERSION __BUILD_VERSION__ 29 | 30 | #ifdef __clang__ 31 | # define COMPILER_VERSION __clang_version__ 32 | # define COMPILER_NAME "clang" 33 | #elif __GNUC__ 34 | # define COMPILER_VERSION __GNUC__ 35 | # define COMPILER_NAME "gcc" 36 | #else 37 | # define COMPILER_VERSION "unknown" 38 | # define COMPILER_NAME "unknown" 39 | #endif 40 | 41 | #define CONFIG_QEMU_DEBUG __QEMU__ 42 | #define SERIAL_COLORS __SERIAL_COLORS__ 43 | 44 | #if __SERIAL_COLORS__ 45 | # define INFO_MESSAGE_PREFIX "[\033[1;36minfo\033[0m] " 46 | # define DEBUG_MESSAGE_PREFIX "[\033[0;33m\033[4mdebug\033[0m] " 47 | # define SUCCESS_MESSAGE_PREFIX "[\033[1;32msuccess\033[0m] " 48 | # define ERROR_MESSAGE_PREFIX "[\033[1;31merror\033[0m] " 49 | # define PANIC_MESSAGE_PREFIX "[\033[1;31mpanic\033[0m] " 50 | # define DEVICE_MESSAGE_PREFIX "[\033[1;34mdevice\033[0m] " 51 | # define WARNING_MESSAGE_PREFIX "[\033[1;33mwarning\033[0m] " 52 | #else 53 | # define INFO_MESSAGE_PREFIX "[info] " 54 | # define DEBUG_MESSAGE_PREFIX "[debug] " 55 | # define SUCCESS_MESSAGE_PREFIX "[success] " 56 | # define ERROR_MESSAGE_PREFIX "[error] " 57 | # define PANIC_MESSAGE_PREFIX "[panic] " 58 | # define DEVICE_MESSAGE_PREFIX "[device] " 59 | # define WARNING_MESSAGE_PREFIX "[warning] " 60 | #endif 61 | 62 | #define KB (1024u) 63 | #define MB (1024u*KB) 64 | 65 | #define USE_ELF32 66 | #define KERNEL_SYMBOLS 1 67 | 68 | #define KERNEL_BASE_VA 0xC0000000 69 | #define KERNEL_PADDR 0x00100000 70 | 71 | 72 | #define CURRENT_YEAR 2021 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /include/drivers/sb16/sb16.h: -------------------------------------------------------------------------------- 1 | #ifndef SB16_H 2 | #define SB16_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include "sound.h" 9 | 10 | #define SB16_DBG_ENABLED 0 11 | 12 | #define DSP_MIXER 0x224 13 | #define DSP_MIXER_DATA 0x225 14 | #define DSP_RESET 0x226 15 | #define DSP_READ 0x22A 16 | #define DSP_WRITE 0x22C 17 | #define DSP_READ_STATUS 0x22E 18 | 19 | #define DSP_8_BIT_ACK DSP_READ_STATUS 20 | #define DSP_16_BIT_ACK 0x22F 21 | 22 | #define DSP_16_BIT_PROGRAM 0xB0 23 | #define DSP_8_BIT_PROGRAM 0xC0 24 | #define DSP_AUTO_INIT 0x06 25 | #define DSP_PLAY 0x00 26 | #define DSP_RECORD 0x08 27 | #define DSP_MONO 0x00 28 | #define DSP_STEREO 0x20 29 | #define DSP_UNSIGNED 0x00 30 | #define DSP_SIGNED 0x10 31 | 32 | #define DSP_SET_SAMPLE_R 0x41 33 | #define DSP_ENABLE_SPKR 0xD1 34 | #define DSP_DISABLE_SPKR 0xD3 35 | #define DSP_GET_VER 0xE1 36 | #define DSP_8_BIT_PAUSE 0xD0 37 | #define DSP_8_BIT_CONT 0xD4 38 | #define DSP_16_BIT_PAUSE 0xD5 39 | #define DSP_16_BIT_CONT 0xD6 40 | 41 | struct sb16_info 42 | { 43 | uint8_t *buf; 44 | uint64_t buf_paddr; 45 | uint8_t irq; 46 | uint8_t var_major; 47 | uint8_t var_minor; 48 | }; 49 | 50 | extern struct sb16_info sb16_info; 51 | 52 | uint8_t sb16_get_irq(void); 53 | int sb16_detect_dsp_hw_and_reset(void); 54 | int sb16_check_version(void); 55 | void sb16_program_dma(uint8_t bits, uint32_t buf_size); 56 | void sb16_program(struct sound_params *sound_params, uint32_t buf_size); 57 | void sb16_generate_test_sound(void); 58 | 59 | static inline void sb16_irq_ack(void) 60 | { 61 | extern uint16_t sb16_curr_ack_cmd; 62 | inb(sb16_info.irq); 63 | } 64 | 65 | static inline void sb16_pause(void) 66 | { 67 | extern uint8_t sb16_curr_pause_cmd; 68 | outb(DSP_WRITE, sb16_curr_pause_cmd); 69 | } 70 | 71 | static inline void sb16_continue(void) 72 | { 73 | extern uint8_t sb16_curr_cont_cmd; 74 | outb(DSP_WRITE, sb16_curr_cont_cmd); 75 | } 76 | 77 | #if SB16_DBG_ENABLED 78 | # define SB16_DBG(...) kprintf(__VA_ARGS__) 79 | #else 80 | # define SB16_DBG(...) {} 81 | #endif // SB16_DBG_ENABLED 82 | 83 | #endif // SB16_H -------------------------------------------------------------------------------- /src/drivers/vga/vga.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file vga.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | size_t VGA_COL; 18 | size_t VGA_ROW; 19 | uint8_t VGA_DEF_COLOR; 20 | struct vga_entry_t* VGA_BUFFER; 21 | 22 | uint8_t vga_create_color(uint8_t bg, uint8_t fg) { 23 | return (bg << 4) | fg; 24 | } 25 | 26 | void vga_set_default_color(uint8_t color) { 27 | VGA_DEF_COLOR = color; 28 | } 29 | 30 | struct vga_entry_t vga_create_entry(uint8_t ch, uint8_t color) 31 | { return (struct vga_entry_t){ ch, color }; } 32 | 33 | void vga_put_entry(struct vga_entry_t entry, size_t x, size_t y) 34 | { 35 | VGA_BUFFER[y * VGA_COLS + x] = entry; 36 | } 37 | 38 | void vga_write_string(const char* str, size_t x, size_t y) 39 | { 40 | for (size_t i = 0; str[i] != '\0'; i++) 41 | { 42 | vga_put_entry(vga_create_entry(str[i], VGA_DEF_COLOR), x + i, y); 43 | } 44 | } 45 | 46 | void vga_set_pixel(uint32_t x, uint32_t y, uint8_t color) 47 | { 48 | vga_put_entry(vga_create_entry(' ', color), x, y); 49 | } 50 | 51 | uint32_t draw(uint32_t x, uint32_t y, uint8_t color) 52 | { 53 | vga_set_pixel(x, y, color); 54 | return (x /= y); 55 | } 56 | 57 | void vga_init() 58 | { 59 | VGA_COL = 0; 60 | VGA_ROW = 0; 61 | VGA_DEF_COLOR = vga_create_color(BLACK, GREY); 62 | VGA_BUFFER = (struct vga_entry_t*) VGA_ADDRESS; 63 | 64 | qemu_success("VGA initialized, buffer->%p\r\n", VGA_BUFFER); 65 | } 66 | 67 | void vga_putchar(const char c) { 68 | if (c == '\n') 69 | { 70 | VGA_COL = 0; 71 | ++VGA_ROW; 72 | } 73 | else if (c == '\r') 74 | { 75 | VGA_COL = 0; 76 | } 77 | else if (c == '\t') 78 | { 79 | VGA_COL += 4; 80 | } 81 | else 82 | { 83 | vga_put_entry(vga_create_entry(c, VGA_DEF_COLOR), VGA_COL, VGA_ROW); 84 | if(++VGA_COL == VGA_COLS) 85 | { 86 | VGA_COL = 0; 87 | ++VGA_ROW; 88 | } 89 | } 90 | } 91 | 92 | void set_buffer_position(size_t x, size_t y) 93 | { 94 | VGA_COL = x; 95 | VGA_ROW = y; 96 | } 97 | -------------------------------------------------------------------------------- /src/drivers/keyboard/keyboard.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file keyboard.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | char keyboard_map[128] = { 20 | 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', 21 | '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 22 | 0, /* left control */ 23 | 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 24 | 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 25 | 0, /* left alt */ 26 | ' ', 27 | 0, /* caps lock */ 28 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F1 ... F10 */ 29 | 0, /* num lock */ 30 | 0, /* scroll lock */ 31 | 0, /* home key */ 32 | 0, /* up arrow key */ 33 | 0, /* page up */ 34 | '-', 35 | 0, /* left arrow key */ 36 | 0, 37 | 0, /* right arrow key */ 38 | '+', 39 | 0, /* end key */ 40 | 0, /* down arrow key */ 41 | 0, /* page down */ 42 | 0, /* insert key */ 43 | 0, /* delete key */ 44 | 0, 0, 0, 45 | 0, /* F11 key */ 46 | 0, /* F12 key */ 47 | 0, /* All other keys are undefined */ 48 | }; 49 | 50 | void keyboard_handler(register_t *reg) 51 | { 52 | uint8_t i, scancode; 53 | 54 | /* Get the scancode */ 55 | for (i = 1000; i > 0; i++) 56 | { 57 | /* Check if scan code is ready */ 58 | if ((inb(0x64) & 0x1) == 0) continue; 59 | 60 | /* Read the scancode */ 61 | scancode = inb(0x60); 62 | break; 63 | } 64 | 65 | if (i > 0) 66 | { 67 | if (scancode & 0x80) 68 | { /* Key release */ } 69 | else 70 | { 71 | /* Key down */ 72 | qemu_dbg("Key Pressed %c\r\n", keyboard_map[scancode]); 73 | } 74 | } 75 | } 76 | 77 | void keyboard_init(void) 78 | { 79 | register_interrupt_handler(IRQ_BASE + 1, keyboard_handler); 80 | 81 | qemu_success("Keyboard Loaded\r\n"); 82 | } 83 | 84 | char get_input_keycode() 85 | { 86 | char ch = 0; 87 | while ((ch = inb(KEYBOARD_PORT)) != 0x60) 88 | { 89 | if (ch > 0) 90 | return ch; 91 | } 92 | return ch; 93 | } 94 | -------------------------------------------------------------------------------- /src/sys/string.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file string.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.4 5 | * @date 2021-07-29 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | 16 | uint32_t strlen(const char *str) 17 | { 18 | uint32_t length = 0; 19 | while (str[length]) 20 | length++; 21 | return length; 22 | } 23 | 24 | int strcmp(const char *s1, const char *s2) 25 | { 26 | while (*s1 == *s2++) 27 | if (*s1++ == 0) 28 | return 0; 29 | return (*(uint8_t*)s1 - *(uint8_t*)--s2); 30 | } 31 | 32 | const char *strchr(const char* s, char ch) 33 | { 34 | while (*s) 35 | { 36 | if (*s == ch) 37 | return s; 38 | s++; 39 | } 40 | return 0; 41 | } 42 | 43 | char *strtok(char* s, const char* delim) 44 | { 45 | static char* old = 0; 46 | char* word; 47 | 48 | if (!s) 49 | s = old; 50 | 51 | while (*s && strchr(delim, *s)) 52 | s++; 53 | 54 | if (!*s) 55 | { 56 | old = s; 57 | return 0; 58 | } 59 | 60 | word = s; 61 | while (*s && !strchr(delim, *s)) 62 | s++; 63 | 64 | if (*s) 65 | { 66 | *s = 0; 67 | old = s + 1; 68 | } 69 | else 70 | { 71 | old = s; 72 | } 73 | 74 | return word; 75 | } 76 | 77 | void* memcpy(void* dest, const void* src, uint32_t size) 78 | { 79 | char* d = dest; 80 | const char* s = src; 81 | while (size--) 82 | *d++ = *s++; 83 | return dest; 84 | } 85 | 86 | int memcmp(const void* ptr1, const void* ptr2, size_t num) 87 | { 88 | register const uint8_t *s1 = (const uint8_t *)ptr1; 89 | register const uint8_t *s2 = (const uint8_t *)ptr2; 90 | while (num-- > 0) 91 | if (*s1++ != *s2++) 92 | return s1[-1] < s2[-1] ? -1 : 1; 93 | return 0; 94 | } 95 | 96 | void *memset(void *dest, char *value, size_t length) 97 | { 98 | char *temp = dest; 99 | for(;length != 0; length--) *temp++ = value; 100 | return dest; 101 | } 102 | 103 | char* strcpy(char* dest, const char* src) 104 | { return memcpy(dest, src, strlen(src) + 1); } 105 | 106 | char* strcat(char* dest, const char* src) 107 | { 108 | strcpy(dest + strlen(dest), src); 109 | return dest; 110 | } -------------------------------------------------------------------------------- /src/arch/i386/bootloader/boot.s: -------------------------------------------------------------------------------- 1 | /** 2 | * @file boot.s 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-07-06 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | // Constants for the bootloader 15 | .set ALIGN, 1<<0 // align loaded modules on page boundaries 16 | .set MEMINFO, 1<<1 // load memory information 17 | .set FLAGS, ALIGN | MEMINFO // load all modules 18 | .set MAGIC, 0x1BADB002 // magic number for the bootloader 19 | .set CHECKSUM, -(MAGIC + FLAGS) // checksum for the bootloader 20 | 21 | // set multiboot enabled. This is required for the bootloader to work. 22 | .section .multiboot 23 | .align 4 // align to 4 bytes 24 | .long MAGIC // magic number 25 | .long FLAGS // flags 26 | .long CHECKSUM // checksum 27 | 28 | stackBottom: 29 | .skip 1024 // stack bottom 30 | stackTop: 31 | 32 | .section .text 33 | .global _start // entry point 34 | .type _start, @function // function type 35 | 36 | _start: 37 | // Disable interrupts: we don't want to be interrupted by anything 38 | // while we're loading the kernel. 39 | cli 40 | cld 41 | 42 | // Setup the stack pointer. We need to do this before loading the 43 | // kernel. 44 | mov $stackTop, %esp 45 | 46 | // Call global constructors. 47 | call _init 48 | 49 | // Enter the high-level kernel. This will load the kernel and 50 | // call the entry point. 51 | push %eax // save eax for later 52 | push %ebx // save ebx for later 53 | call kernel_entry // call the kernel entry point 54 | 55 | cli // disable interrupts 56 | 57 | // put system in infinite loop. This is a good place to put a breakpoint 58 | // to debug the kernel. 59 | hltLoop: 60 | hlt // halt the system 61 | jmp hltLoop // loop forever 62 | 63 | // kernel entry point, called by the high-level kernel. This will load 64 | // the kernel and call the entry point. 65 | .size _start, . - _start 66 | -------------------------------------------------------------------------------- /include/AK/printfImpl.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file printfImpl.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-11 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef PRINTF_IMPL_H 15 | #define PRINTF_IMPL_H 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | int printf_internal(char *fmt, va_list arg) 25 | { 26 | unsigned int i; 27 | char* position; 28 | char* s; 29 | 30 | for (position = fmt; *position != '\0'; position++) 31 | { 32 | if (*position == '%') 33 | { 34 | position++; 35 | 36 | switch (*position) 37 | { 38 | case 'c': 39 | i = va_arg(arg, int); 40 | if (i == 0) 41 | break; 42 | vga_putchar(i); 43 | break; 44 | 45 | case 'd': 46 | { 47 | i = va_arg(arg, int); 48 | if (i < 0) 49 | { 50 | i = -i; 51 | vga_putchar('-'); 52 | } 53 | 54 | char *s = convert_to_base(i, 10); 55 | kprint(s); 56 | break; 57 | } 58 | 59 | case 'o': 60 | i = va_arg(arg, unsigned int); 61 | kprint(convert_to_base(i, 8)); 62 | break; 63 | 64 | case 's': 65 | s = va_arg(arg, char *); 66 | if (s == 0) 67 | break; 68 | kprint(s); 69 | break; 70 | 71 | case 'x': 72 | i = va_arg(arg, unsigned int); 73 | kprint(convert_to_base(i, 16)); 74 | break; 75 | } 76 | } 77 | else 78 | { 79 | switch (*position) 80 | { 81 | case '\n': 82 | vga_putchar('\n'); 83 | break; 84 | 85 | case '\r': 86 | vga_putchar('\r'); 87 | break; 88 | 89 | case '\t': 90 | vga_putchar('\t'); 91 | break; 92 | 93 | case '\b': 94 | vga_putchar('\b'); 95 | break; 96 | 97 | case '\f': 98 | vga_putchar('\f'); 99 | break; 100 | 101 | case '\v': 102 | vga_putchar('\v'); 103 | break; 104 | 105 | default: 106 | vga_putchar(*position); 107 | break; 108 | } 109 | } 110 | } 111 | 112 | return i; 113 | } 114 | 115 | #endif // PRINTF_IMPL_H -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TinyKernel Cover Art 2 | 3 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TinyKern/TinyKernel) 4 | [![Lines of code](https://img.shields.io/tokei/lines/github/TinyKern/TinyKernel?color=pink)](https://github.com/TinyKern/TinyKernel/) 5 | [![Issues Closed](https://img.shields.io/github/issues-search/TinyKern/TinyKernel?color=red&label=Issues%20Closed&query=is%3Aclosed)](https://github.com/TinyKern/TinyKernel/issues) 6 | [![License](https://img.shields.io/github/license/TinyKern/TinyKernel)](https://github.com/TinyKern/TinyKernel/blob/0.1.3/LICENSE) 7 | [![Tag](https://img.shields.io/github/v/tag/TinyKern/TinyKernel)](https://github.com/TinyKern/TinyKernel/releases) 8 | 9 | 10 | 11 | # TinyKernel - 0.1.4 12 | Tiny Kernel is a work in progress Operating System kernel. 13 | 14 | By the end of the project, I hope to have a fully functional and working Kernel. Since System development is my prefered type of development, 15 | I thought it was time to finally create a project from the ground up, with its own x86 architecture and its own operating system to end up using 16 | the kernel. 17 | 18 | ## Setup 19 | 20 | Currently, there is too many files for people to just manually enter commands to run and build, therefor, you should really use the provided Makefile. just enter `make` into the commandline at the root of the project, & it will build the project for you. After, you can enter `make run` into the command line, & it will run the following project. 21 | ### ISO 22 | #### Debian/Ubuntu 23 | --- 24 | **Install Qemu:** 25 | - `sudo apt-get install qemu qemu-system-x86` 26 | 27 | After installing Qemu, you can then run the Iso file, the command is: 28 | - `qemu-system-x86_64 -cdrom path/to/iso` 29 | 30 | ## Screenshots 31 | 32 | Date: 7/25/2021 33 | 34 | TinyKernel Cover Art 35 | 36 | --- 37 | Date: 8/11/2021 38 | 39 | TinyKernel Cover Art 40 | 41 | --- 42 | Date: 8/17/2021 43 | 44 | TinyKernel Cover Art 45 | -------------------------------------------------------------------------------- /include/drivers/keyboard/keyboard.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file keyboard.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-07-06 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef KEYBOARD_H 15 | #define KEYBOARD_H 16 | 17 | #include 18 | #include 19 | 20 | void keyboard_init(void); 21 | 22 | char get_input_keycode(); 23 | 24 | #define KEYBOARD_PORT 0x60 25 | 26 | #define KEY_A 0x1E 27 | #define KEY_B 0x30 28 | #define KEY_C 0x2E 29 | #define KEY_D 0x20 30 | #define KEY_E 0x12 31 | #define KEY_F 0x21 32 | #define KEY_G 0x22 33 | #define KEY_H 0x23 34 | #define KEY_I 0x17 35 | #define KEY_J 0x24 36 | #define KEY_K 0x25 37 | #define KEY_L 0x26 38 | #define KEY_M 0x32 39 | #define KEY_N 0x31 40 | #define KEY_O 0x18 41 | #define KEY_P 0x19 42 | #define KEY_Q 0x10 43 | #define KEY_R 0x13 44 | #define KEY_S 0x1F 45 | #define KEY_T 0x14 46 | #define KEY_U 0x16 47 | #define KEY_V 0x2F 48 | #define KEY_W 0x11 49 | #define KEY_X 0x2D 50 | #define KEY_Y 0x15 51 | #define KEY_Z 0x2C 52 | #define KEY_1 0x02 53 | #define KEY_2 0x03 54 | #define KEY_3 0x04 55 | #define KEY_4 0x05 56 | #define KEY_5 0x06 57 | #define KEY_6 0x07 58 | #define KEY_7 0x08 59 | #define KEY_8 0x09 60 | #define KEY_9 0x0A 61 | #define KEY_0 0x0B 62 | #define KEY_MINUS 0x0C 63 | #define KEY_EQUAL 0x0D 64 | #define KEY_SQUARE_OPEN_BRACKET 0x1A 65 | #define KEY_SQUARE_CLOSE_BRACKET 0x1B 66 | #define KEY_SEMICOLON 0x27 67 | #define KEY_BACKSLASH 0x2B 68 | #define KEY_COMMA 0x33 69 | #define KEY_DOT 0x34 70 | #define KEY_FORESLHASH 0x35 71 | #define KEY_F1 0x3B 72 | #define KEY_F2 0x3C 73 | #define KEY_F3 0x3D 74 | #define KEY_F4 0x3E 75 | #define KEY_F5 0x3F 76 | #define KEY_F6 0x40 77 | #define KEY_F7 0x41 78 | #define KEY_F8 0x42 79 | #define KEY_F9 0x43 80 | #define KEY_F10 0x44 81 | #define KEY_F11 0x85 82 | #define KEY_F12 0x86 83 | #define KEY_BACKSPACE 0x0E 84 | #define KEY_DELETE 0x53 85 | #define KEY_DOWN 0x50 86 | #define KEY_END 0x4F 87 | #define KEY_ENTER 0x1C 88 | #define KEY_ESC 0x01 89 | #define KEY_HOME 0x47 90 | #define KEY_INSERT 0x52 91 | #define KEY_KEYPAD_5 0x4C 92 | #define KEY_KEYPAD_MUL 0x37 93 | #define KEY_KEYPAD_Minus 0x4A 94 | #define KEY_KEYPAD_PLUS 0x4E 95 | #define KEY_KEYPAD_DIV 0x35 96 | #define KEY_LEFT 0x4B 97 | #define KEY_PAGE_DOWN 0x51 98 | #define KEY_PAGE_UP 0x49 99 | #define KEY_PRINT_SCREEN 0x37 100 | #define KEY_RIGHT 0x4D 101 | #define KEY_SPACE 0x39 102 | #define KEY_TAB 0x0F 103 | #define KEY_UP 0x48 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------------- 2 | # File created using 'AnGitIgnored' extensions for Visual Studio Code: 3 | # https://marketplace.visualstudio.com/items?itemName=AnAppWiLos.angitignored 4 | #------------------------------------------------------------------------------- 5 | 6 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,assembler,c,c++ 7 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,linux,assembler,c,c++ 8 | 9 | ### Assembler ### 10 | *.exe 11 | *.o 12 | *.obj 13 | *.bc 14 | 15 | ### C ### 16 | # Prerequisites 17 | *.d 18 | 19 | # Object files 20 | *.ko 21 | *.elf 22 | 23 | # Linker output 24 | *.ilk 25 | *.map 26 | *.exp 27 | 28 | # Precompiled Headers 29 | *.gch 30 | *.pch 31 | 32 | # Libraries 33 | *.lib 34 | *.a 35 | *.la 36 | *.lo 37 | 38 | # Shared objects (inc. Windows DLLs) 39 | *.dll 40 | *.so 41 | *.so.* 42 | *.dylib 43 | 44 | # Executables 45 | *.out 46 | *.app 47 | *.i*86 48 | *.x86_64 49 | *.hex 50 | 51 | # Debug files 52 | *.dSYM/ 53 | *.su 54 | *.idb 55 | *.pdb 56 | 57 | # Kernel Module Compile Results 58 | *.mod* 59 | *.cmd 60 | .tmp_versions/ 61 | modules.order 62 | Module.symvers 63 | Mkfile.old 64 | dkms.conf 65 | 66 | ### C++ ### 67 | # Prerequisites 68 | 69 | # Compiled Object files 70 | *.slo 71 | 72 | # Precompiled Headers 73 | 74 | # Compiled Dynamic libraries 75 | 76 | # Fortran module files 77 | *.mod 78 | *.smod 79 | 80 | # Compiled Static libraries 81 | *.lai 82 | 83 | # Executables 84 | 85 | ### Linux ### 86 | *~ 87 | 88 | # temporary files which can be created if a process still has a handle open of a deleted file 89 | .fuse_hidden* 90 | 91 | # KDE directory preferences 92 | .directory 93 | 94 | # Linux trash folder which might appear on any partition or disk 95 | .Trash-* 96 | 97 | # .nfs files are created when an open file is removed but is still being accessed 98 | .nfs* 99 | 100 | ### VisualStudioCode ### 101 | .vscode/* 102 | !.vscode/c_cpp_properties.json 103 | *.code-workspace 104 | 105 | # Local History for Visual Studio Code 106 | .history/ 107 | 108 | ### VisualStudioCode Patch ### 109 | # Ignore all local history of files 110 | .history 111 | .ionide 112 | 113 | # End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,linux,assembler,c,c++ 114 | 115 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 116 | 117 | # vim 118 | *.swp 119 | .project_alt.json 120 | 121 | ### Build ### 122 | **/build 123 | test/ 124 | 125 | ### AutoTools ### 126 | *.m4 127 | *.log 128 | *.cache 129 | 130 | # Scripts # 131 | compile 132 | config.status 133 | install-sh 134 | missing -------------------------------------------------------------------------------- /docs/kernel/assert.md: -------------------------------------------------------------------------------- 1 | # Kernel - Assert 2 | # assert.h 3 | 4 | Assert is a macro that can be used to check that a condition is true. It is 5 | used to check that the program is behaving as expected. If the condition is 6 | false, the program will abort with an error message. The macro is used like 7 | this: 8 | ```c 9 | #include 10 | 11 | int foo(int x) 12 | { 13 | assert(x > 0); 14 | return x; 15 | } 16 | ``` 17 | 18 | The macro is defined in the header file `assert.h`. The kernel assert macro 19 | is not part of the standard library. It is defined in the kernel header file 20 | `include/assert.h`. The kernel assert macro is used to check that the kernel 21 | is behaving as expected. If the condition is false, the kernel will send a 22 | debug message to the kernel log and then abort. 23 | 24 | The definition of the macro assert depends on another macro, `NDEBUG`, which 25 | is not defined by default. If `NDEBUG` is defined, the macro is defined to 26 | nothing. Otherwise, the macro is defined to: 27 | ```c 28 | # define Assert(exp) if (exp) ; \ 29 | else assertion_failed(#exp, __FILE__, __BASE_FILE__, __LINE__) 30 | ``` 31 | You can enable or disable the NDEBUG macro inside of the build configuration. [config.cfg](../../config.cfg) 32 | 33 | ## Parameters 34 | - exp (condition) - expression of scalar type that is evaluated to true or false 35 | 36 | ## Return value 37 | - None 38 | 39 | ## Notes 40 | - Because assert is a [function-like macro](), commas anywhere in `condition` that are not protected by parentheses are interpreted as argument separators. 41 | - There is no standardized interface to add an additional message to assert errors. A portable way to include one is to use a [comma operator]() provided it has not been [overloaded](). 42 | 43 | ## Real world example: 44 | Here is a real world example of using the kernel assert macro: 45 | `src/arch/i386/paging.c` 46 | ```c 47 | #include 48 | 49 | ... 50 | 51 | static int virtual_write_unsafe(pdir_t *pdir, void *extern_va, void *src, size_t len) 52 | { 53 | uint64_t pgoff, pa; 54 | size_t tot, to_write; 55 | void *va; 56 | 57 | Assert(len <= INT32_MAX); 58 | 59 | for (tot = 0; tot < len; extern_va += to_write, tot += to_write) 60 | { 61 | if (get_mapping2(pdir, extern_va, &pa) < 0) 62 | return -EFAULT; 63 | 64 | pgoff = ((uint64_t) extern_va) & OFFSET_IN_PAGE_MASK; 65 | to_write = MIN(PAGE_SIZE - pgoff, len - tot); 66 | 67 | va = KERNEL_PA_TO_VA(pa); 68 | memcpy(va, src + tot, to_write); 69 | } 70 | 71 | return (int)tot; 72 | } 73 | 74 | ... 75 | 76 | ``` 77 | 78 | Here is a real world example from a regular user program: 79 | ```c 80 | #include 81 | 82 | int main() 83 | { 84 | Assert(2 + 2 == 4); 85 | return 0; 86 | } 87 | ``` -------------------------------------------------------------------------------- /include/kernel/cpu/ports.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ports.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef KERNEL_CPU_H 15 | #define KERNEL_CPU_H 16 | 17 | #include 18 | 19 | 20 | /** 21 | * @brief Reads a byte from the specified port. 22 | * 23 | * @param port 24 | * @return uint8_t 25 | */ 26 | extern uint8_t inb(uint16_t port); 27 | 28 | /** 29 | * @brief Writes a byte to the specified port. 30 | * 31 | * @param port 32 | * @param data 33 | */ 34 | extern void outb(uint16_t port, uint8_t data); 35 | 36 | /** 37 | * @brief Reads a word from the specified port. 38 | * 39 | * @param port 40 | * @return uint16_t 41 | */ 42 | extern uint16_t inw(uint16_t port); 43 | 44 | /** 45 | * @brief Writes a word to the specified port. 46 | * 47 | * @param port 48 | * @param data 49 | */ 50 | extern void outw(uint16_t port, uint16_t data); 51 | 52 | /** 53 | * @brief Reads a double word from the specified port. 54 | * 55 | * @param port 56 | * @return uint8_t 57 | */ 58 | extern uint8_t in8(uint16_t port); 59 | 60 | /** 61 | * @brief Writes a double word to the specified port. 62 | * 63 | * @param port 64 | * @param data 65 | */ 66 | extern void out8(uint16_t port, uint8_t data); 67 | 68 | /** 69 | * @brief Reads a double word from the specified port. 70 | * 71 | * @param port 72 | * @return uint16_t 73 | */ 74 | extern uint16_t in16(uint16_t port); 75 | 76 | /** 77 | * @brief Writes a double word to the specified port. 78 | * 79 | * @param port 80 | * @param data 81 | */ 82 | extern void out16(uint16_t port, uint16_t data); 83 | 84 | /** 85 | * @brief Reads a double word from the specified port. 86 | * 87 | * @param port 88 | * @return uint32_t 89 | */ 90 | uint32_t in32(uint16_t port); 91 | 92 | /** 93 | * @brief Writes a double word to the specified port. 94 | * 95 | * @param port 96 | * @param data 97 | */ 98 | void out32(uint16_t port, uint32_t data); 99 | 100 | #define outb_p(port, value) \ 101 | __asm__ ("outb %%al, %%dx\n" \ 102 | "\tjmp 1f\n" \ 103 | "1:\tjmp 1f\n" \ 104 | "1:"::"a" (value), "d" (port)) 105 | 106 | #define inb_p(port) ({ \ 107 | unsigned char __res; \ 108 | __asm__ volatile ("inb %%dx, %%al\n" \ 109 | "\tjmp 1f\n" \ 110 | "1:\tjmp 1f\n" \ 111 | "1:":"=a" (__res):"d" (port)); \ 112 | __res; \ 113 | }) 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /src/drivers/pci/bus.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bus.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-31 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | const char* class_names[] = { 20 | "Unclassified", 21 | "Mass Storage Controller", 22 | "Network Controller", 23 | "Display Controller", 24 | "Multimedia Controller", 25 | "Memory Controller", 26 | "Bridge Device", 27 | "Simple Communication Controller", 28 | "Base System Peripheral", 29 | "Input Device", 30 | "Docking Station", 31 | "Processor", 32 | "Serial Bus Controller", 33 | "Wireless Controller", 34 | "Intelligent I/O Controller", 35 | "Satellite Communication Controller", 36 | "Encryption/Decryption Controller", 37 | "Data Acquisition and Signal Processing Controller", 38 | "Reserved", 39 | }; 40 | 41 | void pci_enum_bus(void) 42 | { 43 | uint16_t bus; 44 | for (bus = 0; bus < 255; bus++) 45 | pci_check(bus); 46 | } 47 | 48 | void pci_check(uint8_t bus) 49 | { 50 | uint8_t slot; 51 | for (slot = 0; slot < 32; slot++) 52 | pci_slot_check(bus, slot); 53 | } 54 | 55 | void pci_slot_check(uint8_t bus, uint8_t slot) 56 | { 57 | uint8_t func; 58 | for (func = 0; func < 32; func++) 59 | { 60 | uint32_t device_and_vendor = pci_read_config_reg(bus, slot, func, 0x00); 61 | 62 | if ((device_and_vendor & 0xFFFF) == 0xFFFF) 63 | break; 64 | 65 | uint32_t class_register = pci_read_config_reg(bus, slot, func, 0x08); 66 | uint8_t class = (uint8_t)(class_register >> 24); 67 | 68 | // kprintf("Pci devices at %d:%d:%d has vendor %x and device %x, of class %s.\n", bus, slot, func, device_and_vendor&0xFFFF, device_and_vendor>>16, class_names[class]); 69 | qemu_device("Pci devices at %d:%d:%d has vendor %x and device %x, of class %s.\n", bus, slot, func, device_and_vendor&0xFFFF, device_and_vendor>>16, class_names[class]); 70 | } 71 | } 72 | 73 | uint32_t pci_read_config_reg(uint8_t bus, uint8_t slot, uint8_t func, uint8_t reg) 74 | { 75 | // Addres of register to be read from. This is an address in the "PCI" 76 | // config space, not the "I/O" space or general memory space. 77 | uint32_t address = 0x80000000 | (uint32_t)((bus & 0xFF) << 16) | (uint32_t)((slot & 0x1F) << 11) | (uint32_t)((func & 0x05) << 8) | (uint32_t)(reg & 0xFC); 78 | 79 | // Write the address to the PCI config space. This will cause the PCI 80 | // bus to respond to the address. The PCI bus will respond with the 81 | // value of the register. This is the value that we will read. 82 | out32(0xCF8, address); 83 | 84 | // Read the value from the PCI config space. This is the value that 85 | // the PCI bus responded with. 86 | return in32(0xCFC); 87 | } -------------------------------------------------------------------------------- /include/sys/string.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file string.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-07-29 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef STRING_H 15 | #define STRING_H 16 | 17 | #include 18 | 19 | /** 20 | * @brief Get the length of a string. 21 | * 22 | * @param str The string to get the length of. 23 | * 24 | * @return uint32_t - The length of the string. 25 | */ 26 | uint32_t strlen(const char*); 27 | 28 | /** 29 | * @brief Compares two strings 30 | * 31 | * @param s1 - The 1st string. 32 | * @param s2 - The 2nd string to compare to s1. 33 | * 34 | * @return int - 0 if the strings are equal, -1 if s1 is less than s2, 1 if s1 is greater than s2. 35 | */ 36 | int strcmp(const char*, const char*); 37 | 38 | /** 39 | * @brief Locates a char in a string 40 | * 41 | * @param src - The string to search in. 42 | * @param chr - The char to search for. 43 | * 44 | * @return const char* - The char if found, NULL otherwise. 45 | */ 46 | const char *strchr(const char*, char); 47 | 48 | /** 49 | * @brief Tokenizes a string 50 | * 51 | * @param str - The string to tokenize 52 | * @param delim - The delimiter to use 53 | * 54 | * @return char* - The tokenized string or NULL if no tokens were found. 55 | */ 56 | char *strtok(char*, const char*); 57 | 58 | /** 59 | * @brief Copies bytes from to 60 | * 61 | * @param dest 62 | * @param src 63 | * @param size 64 | * @return void* - The destination pointer where the copy ended. 65 | */ 66 | void *memcpy(void* dest, const void* src, uint32_t size); 67 | 68 | /** 69 | * @brief Compares two blocks of memory 70 | * 71 | * @param ptr1 72 | * @param ptr2 73 | * @param num 74 | * 75 | * @return int - 0 if the memory blocks are equal, -1 if ptr1 is less than ptr2, 1 if ptr1 is greater than ptr2. 76 | */ 77 | int memcmp(const void* ptr1, const void* ptr2, size_t num); 78 | 79 | /** 80 | * @brief Sets a block of memory to a value 81 | * 82 | * @param ptr - The pointer to the memory block to set. 83 | * @param value - The value to set the memory block to. 84 | * @param num - The number of bytes to set. 85 | * 86 | * @return void* - The pointer to the memory block where the set ended. 87 | */ 88 | // uint8_t *memset(uint8_t *dest, const uint8_t value, size_t length); 89 | void *memset(void *dest, char *value, size_t length); 90 | 91 | /** 92 | * @brief Copies the string to 93 | * 94 | * @param dest 95 | * @param src 96 | * @return char* - The destination pointer where the string was copied to. 97 | */ 98 | char *strcpy(char* dest, const char* src); 99 | 100 | /** 101 | * @brief Concatenates to 102 | * 103 | * @param dest 104 | * @param src 105 | * @return char* - The destination pointer where the string was concatenated to. 106 | */ 107 | char *strcat(char* dest, const char* src); 108 | #endif // STRING_H -------------------------------------------------------------------------------- /include/kernel/errno.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file errno.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef ERRNO_H 15 | #define ERRNO_H 16 | 17 | #define EFAULT 14 18 | 19 | // Syscall error codes 20 | #define ENOSYS 38 // Invalid system call number 21 | 22 | #define EINTR 4 // Interrupted system call 23 | #define EIO 5 // I/O error 24 | #define ENXIO 6 // No such device or address 25 | #define E2BIG 7 // Argument list too long 26 | #define ENOEXEC 8 // Exec format error 27 | 28 | #define ESHUTD 87 // Failed to send shutdown signal 29 | 30 | /** 31 | * 0 - Division by zero exception 32 | * 1 - Debug exception 33 | * 2 - Non maskable interrupt 34 | * 3 - Breakpoint exception 35 | * 4 - 'Into detected overflow' 36 | * 5 - Out of bounds exception 37 | * 6 - Invalid opcode exception 38 | * 7 - No coprocessor exception 39 | * 8 - Double fault (pushes an error code) 40 | * 9 - Coprocessor segment overrun 41 | * 10 - Bad TSS (pushes an error code) 42 | * 11 - Segment not present (pushes an error code) 43 | * 12 - Stack fault (pushes an error code) 44 | * 13 - General protection fault (pushes an error code) 45 | * 14 - Page fault (pushes an error code) 46 | * 15 - Unknown interrupt exception 47 | * 16 - Coprocessor fault 48 | * 17 - Alignment check exception 49 | * 18 - Machine check exception 50 | * 19-32 - Reserved 51 | */ 52 | enum interrupt_exception 53 | { 54 | EXCEPTION_DIVISION_BY_ZERO = 0, 55 | EXCEPTION_DEBUG = 1, 56 | EXCEPTION_NMI = 2, 57 | EXCEPTION_BREAKPOINT = 3, 58 | EXCEPTION_OVERFLOW = 4, 59 | EXCEPTION_BOUNDS = 5, 60 | EXCEPTION_INVALID_OPCODE = 6, 61 | EXCEPTION_NO_COPROCESSOR = 7, 62 | EXCEPTION_DOUBLE_FAULT = 8, 63 | EXCEPTION_COPROCESSOR_SEGMENT_OVERRUN = 9, 64 | EXCEPTION_BAD_TSS = 10, 65 | EXCEPTION_SEGMENT_NOT_PRESENT = 11, 66 | EXCEPTION_STACK_FAULT = 12, 67 | EXCEPTION_GENERAL_PROTECTION_FAULT = 13, 68 | EXCEPTION_PAGE_FAULT = 14, 69 | EXCEPTION_UNKNOWN_INTERRUPT = 15, 70 | EXCEPTION_COPROCESSOR_FAULT = 16, 71 | EXCEPTION_ALIGNMENT_CHECK = 17, 72 | EXCEPTION_MACHINE_CHECK = 18, 73 | EXCEPTION_RESERVED_19 = 19, 74 | EXCEPTION_RESERVED_20, EXCEPTION_RESERVED_21, EXCEPTION_RESERVED_22, 75 | EXCEPTION_RESERVED_23, EXCEPTION_RESERVED_24, EXCEPTION_RESERVED_25, 76 | EXCEPTION_RESERVED_26, EXCEPTION_RESERVED_27, EXCEPTION_RESERVED_28, 77 | EXCEPTION_RESERVED_29, EXCEPTION_RESERVED_30, EXCEPTION_RESERVED_31, 78 | EXCEPTION_RESERVED_32, 79 | }; 80 | 81 | enum ERR_CODES 82 | { 83 | ERRNO_KERNEL_INVALID_MAGIC = 0x01, //!< Invalid magic number 84 | ERRNO_KERNEL_INVALID_FLAGS, //!< Invalid flags 85 | ERRNO_KERNEL_INVALID_SYSCALL = 0x64, //!< Invalid syscall 86 | ERRNO_KERN_INVALID_ADDR, //!< Invalid address 87 | ERRNO_NO_FREE_PAGE_FRAME, //!< No free page frame available 88 | ERRNO_KERNEL_KILL_PROCESS, //!< Process killed 89 | ERRNO_NO_FREE_MEMORY = 0xA3, //!< No free memory available 90 | ERRNO_MEMORY_HEAP_LIMIT = 0xA4, //!< Memory heap limit reached 91 | ERRNO_NO_AVAILABLE_PAGE, //!< No available page 92 | }; 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /src/arch/i386/paging.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file paging.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-24 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | int get_mapping2(pdir_t *pdir, void *vaddrp, uint64_t *pa_ref) 21 | { 22 | page_table_t *pt; 23 | const uint64_t vaddr = (uint64_t)vaddrp; 24 | const uint32_t pt_index = (vaddr >> PAGE_SHIFT) & 0x3ff; 25 | const uint32_t pd_index = (vaddr >> BIG_PAGE_SHIFT) & 0x3ff; 26 | page_dir_entry_t e; 27 | page_t p; 28 | 29 | // Get page dir's entry for this vaddr 30 | e.raw = pdir->entries[pd_index].raw; 31 | 32 | if (!e.present) 33 | return -EFAULT; 34 | 35 | if (!e.psize) 36 | { 37 | Assert(e.ptaddr != 0); 38 | 39 | // get the page table 40 | pt = KERNEL_PA_TO_VA(e.ptaddr << PAGE_SHIFT); 41 | 42 | p.raw = pt->pages[pt_index].raw; 43 | 44 | if (!p.present) 45 | return -EFAULT; 46 | 47 | *pa_ref = ((uint64_t) p.page_addr << PAGE_SHIFT) | 48 | (vaddr & OFFSET_IN_PAGE_MASK); 49 | } 50 | else 51 | *pa_ref = ((uint64_t) e.big_4mb_page.paddr << BIG_PAGE_SHIFT) | 52 | (vaddr & (4 * MB - 1)); 53 | 54 | return 0; 55 | } 56 | 57 | static int virtual_read_unsafe(pdir_t *pdir, void *extern_va, void *dest, size_t len) 58 | { 59 | uint64_t pgoff, pa; 60 | size_t tot, to_read; 61 | void *va; 62 | 63 | Assert(len <= INT32_MAX); 64 | 65 | for (tot = 0; tot < len; extern_va += to_read, tot += to_read) 66 | { 67 | if (get_mapping2(pdir, extern_va, &pa) < 0) 68 | return -EFAULT; 69 | 70 | pgoff = ((uint64_t) extern_va) & OFFSET_IN_PAGE_MASK; 71 | to_read = MIN(PAGE_SIZE - pgoff, len - tot); 72 | 73 | va = KERNEL_PA_TO_VA(pa); 74 | memcpy(dest + tot, va, to_read); 75 | } 76 | 77 | return (int)tot; 78 | } 79 | 80 | static int virtual_write_unsafe(pdir_t *pdir, void *extern_va, void *src, size_t len) 81 | { 82 | uint64_t pgoff, pa; 83 | size_t tot, to_write; 84 | void *va; 85 | 86 | Assert(len <= INT32_MAX); 87 | 88 | for (tot = 0; tot < len; extern_va += to_write, tot += to_write) 89 | { 90 | if (get_mapping2(pdir, extern_va, &pa) < 0) 91 | return -EFAULT; 92 | 93 | pgoff = ((uint64_t) extern_va) & OFFSET_IN_PAGE_MASK; 94 | to_write = MIN(PAGE_SIZE - pgoff, len - tot); 95 | 96 | va = KERNEL_PA_TO_VA(pa); 97 | memcpy(va, src + tot, to_write); 98 | } 99 | 100 | return (int)tot; 101 | } 102 | 103 | 104 | int virtual_read(pdir_t *pdir, void *extern_va, void *dest, size_t len) 105 | { 106 | int rc; 107 | // disable_preemtion(); 108 | { 109 | rc = virtual_read_unsafe(pdir, extern_va, dest, len); 110 | } 111 | // enable_preemtion(); 112 | return rc; 113 | } 114 | 115 | int virtual_write(pdir_t *pdir, void *extern_va, void *src, size_t len) 116 | { 117 | int rc; 118 | // disable_preemtion(); 119 | { 120 | rc = virtual_write_unsafe(pdir, extern_va, src, len); 121 | } 122 | // enable_preemtion(); 123 | return rc; 124 | } 125 | -------------------------------------------------------------------------------- /src/kernel/cpu/isr/isr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static char *exception_messages[] = { 11 | "Division by zero", 12 | "Debug", 13 | "Non-maskable interrupt", 14 | "Breakpoint", 15 | "Overflow", 16 | "Bounds", 17 | "Invalid opcode", 18 | "No coprocessor", 19 | "Double fault", 20 | "Coprocessor segment overrun", 21 | "Bad TSS", 22 | "Segment not present", 23 | "Stack fault", 24 | "General protection fault", 25 | "Page fault", 26 | "Unknown interrupt", 27 | "Coprocessor fault", 28 | "Alignment check", 29 | "Machine check", 30 | "Reserved", "Reserved", "Reserved", "Reserved", 31 | "Reserved", "Reserved", "Reserved", "Reserved", 32 | "Reserved", "Reserved", "Reserved", "Reserved", 33 | "Reserved", 34 | }; 35 | 36 | isr_t interrupt_handlers[256]; 37 | 38 | static void handle_excecution(register_t registers) 39 | { 40 | if (registers.int_no < 32) 41 | { 42 | qemu_panic("EXCEPTION: %s (code %x)\r\n", exception_messages[registers.int_no], registers.err_code); 43 | kpanic(registers.err_code, "An exception occurred"); 44 | } 45 | if (interrupt_handlers[registers.int_no] != NULL) 46 | { 47 | isr_t handler = interrupt_handlers[registers.int_no]; 48 | handler(®isters); 49 | } 50 | } 51 | 52 | /** 53 | * @brief Handles an interrupt 54 | * 55 | * @note This function is called by the assembly interrupt handler 56 | * and is not meant to be called by the user. 57 | * 58 | * @param registers 59 | * @return void 60 | */ 61 | void isr_handler(register_t registers) 62 | { 63 | if (registers.int_no < 32) 64 | { 65 | char *exception_message = exception_messages[registers.int_no]; 66 | kpanic(registers.int_no, exception_message); 67 | } 68 | else 69 | { 70 | handle_excecution(registers); 71 | } 72 | } 73 | 74 | /** 75 | * @brief Interrupt request handler 76 | * 77 | * @note This function is called by the assembly interrupt handler 78 | * 79 | * @param registers 80 | * @return void 81 | */ 82 | void irq_handler(register_t registers) 83 | { 84 | /* If interrupt originated from slave PIC, send EOI to slave PIC */ 85 | if (registers.int_no >= 40) 86 | PIC_SLAVE_CMD_OUT(0x20); 87 | 88 | /* Send EOI to master PIC */ 89 | PIC_MASTER_CMD_OUT(0x20); 90 | 91 | if (registers.int_no < 32) 92 | { 93 | char *exception_message = exception_messages[registers.int_no]; 94 | kpanic(registers.int_no, exception_message); 95 | } 96 | else 97 | { 98 | handle_excecution(registers); 99 | } 100 | } 101 | 102 | /** 103 | * @brief Registers an interrupt handler 104 | * 105 | * @param int_no Interrupt number 106 | * @param handler Interrupt handler 107 | * 108 | * @return void 109 | */ 110 | void register_interrupt_handler(uint8_t interrupt_number, isr_t handler) 111 | { 112 | qemu_dbg("Register: [%d. %p]\n", interrupt_number, (uint32_t)handler); 113 | if (interrupt_number < 256) 114 | interrupt_handlers[interrupt_number] = handler; 115 | } 116 | 117 | void final_irq_handler(register_t *reg) 118 | { 119 | if (interrupt_handlers[reg->int_no] != NULL) 120 | { 121 | isr_t handler = interrupt_handlers[reg->int_no]; 122 | handler(reg); 123 | } 124 | irq_ack(reg->int_no); 125 | } 126 | -------------------------------------------------------------------------------- /src/kernel/cpu/interrupt.asm: -------------------------------------------------------------------------------- 1 | extern isr_handler 2 | extern irq_handler 3 | 4 | %macro ISR_NOERRCODE 1 5 | global isr%1 6 | isr%1: 7 | cli ; disable interrupts 8 | push byte 0 ; push the dummy error code 9 | push byte %1 ; push the interrupt number 10 | jmp isr_common ; jump to common handler 11 | %endmacro 12 | 13 | %macro ISR_ERRCODE 1 14 | global isr%1 15 | isr%1: 16 | cli ; disable interrupts 17 | push byte %1 ; push the interrupt number 18 | jmp isr_common ; jump to common handler 19 | %endmacro 20 | 21 | %macro IRQ 2 22 | global irq%1 23 | irq%1: 24 | cli ; disable interrupts 25 | push byte 0 26 | push byte %2 27 | jmp irq_common ; jump to common handler 28 | %endmacro 29 | 30 | ISR_NOERRCODE 0 31 | ISR_NOERRCODE 1 32 | ISR_NOERRCODE 2 33 | ISR_NOERRCODE 3 34 | ISR_NOERRCODE 4 35 | ISR_NOERRCODE 5 36 | ISR_NOERRCODE 6 37 | ISR_NOERRCODE 7 38 | ISR_ERRCODE 8 39 | ISR_NOERRCODE 9 40 | ISR_ERRCODE 10 41 | ISR_ERRCODE 11 42 | ISR_ERRCODE 12 43 | ISR_ERRCODE 13 44 | ISR_ERRCODE 14 45 | ISR_NOERRCODE 15 46 | ISR_NOERRCODE 16 47 | ISR_NOERRCODE 17 48 | ISR_NOERRCODE 18 49 | ISR_NOERRCODE 19 50 | ISR_NOERRCODE 20 51 | ISR_NOERRCODE 21 52 | ISR_NOERRCODE 22 53 | ISR_NOERRCODE 23 54 | ISR_NOERRCODE 24 55 | ISR_NOERRCODE 25 56 | ISR_NOERRCODE 26 57 | ISR_NOERRCODE 27 58 | ISR_NOERRCODE 28 59 | ISR_NOERRCODE 29 60 | ISR_NOERRCODE 30 61 | ISR_NOERRCODE 31 62 | IRQ 0, 32 63 | IRQ 1, 33 64 | IRQ 2, 34 65 | IRQ 3, 35 66 | IRQ 4, 36 67 | IRQ 5, 37 68 | IRQ 6, 38 69 | IRQ 7, 39 70 | IRQ 8, 40 71 | IRQ 9, 41 72 | IRQ 10, 42 73 | IRQ 11, 43 74 | IRQ 12, 44 75 | IRQ 13, 45 76 | IRQ 14, 46 77 | IRQ 15, 47 78 | 79 | isr_common: 80 | pusha ; save registers 81 | 82 | mov ax, ds 83 | push eax 84 | 85 | mov ax, 0x10 86 | mov ds, ax 87 | mov es, ax 88 | mov fs, ax 89 | mov gs, ax 90 | 91 | call isr_handler 92 | 93 | pop ebx 94 | mov ds, bx 95 | mov es, bx 96 | mov fs, bx 97 | mov gs, bx 98 | 99 | popa ; restore registers 100 | add esp, 8 ; pop error code 101 | sti 102 | iret 103 | 104 | irq_common: 105 | pusha ; save registers 106 | 107 | mov ax, ds 108 | push eax 109 | 110 | mov ax, 0x10 111 | mov ds, ax 112 | mov es, ax 113 | mov fs, ax 114 | mov gs, ax 115 | 116 | call irq_handler 117 | 118 | pop ebx 119 | mov ds, bx 120 | mov es, bx 121 | mov fs, bx 122 | mov gs, bx 123 | 124 | popa ; restore registers 125 | add esp, 8 ; pop error code 126 | sti 127 | iret 128 | 129 | extern final_irq_handler 130 | 131 | temp_irq_handler: 132 | pusha ; save registers 133 | 134 | mov ax, ds 135 | push eax 136 | 137 | mov ax, 0x10 138 | mov ds, ax 139 | mov es, ax 140 | mov fs, ax 141 | mov gs, ax 142 | 143 | push esp 144 | call final_irq_handler 145 | pop esp 146 | 147 | pop ebx ; restore registers 148 | mov ds, bx 149 | mov es, bx 150 | mov fs, bx 151 | mov gs, bx 152 | 153 | popa ; restore registers 154 | add esp, 0x8 ; pop error code 155 | 156 | sti ; enable interrupts 157 | iret 158 | 159 | -------------------------------------------------------------------------------- /include/kernel/cpu/idt/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef IDT_H 2 | #define IDT_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | /* IDT_DEBUG (define if debugging) */ 9 | #define IDT_DEBUG 0 10 | 11 | #ifdef IDT_DEBUG 12 | # define idt_debug(...) { \ 13 | qemu_dbg("%s:%d, %s() ", \ 14 | __FILE__, __LINE__, __func__); \ 15 | } 16 | #else 17 | # define idt_debug(f, ...) /* nothing */ 18 | #endif 19 | 20 | struct idt_entry 21 | { 22 | uint16_t base_low; /* Lower 16 bites of interrupt address. */ 23 | uint16_t selector; /* Segment selector */ 24 | uint8_t always0; 25 | uint8_t flags; 26 | uint16_t base_high; /* Upper 16 bits of address to jump to */ 27 | } __attribute__((packed)); 28 | 29 | struct idt_pointer 30 | { 31 | uint16_t limit; 32 | uint32_t base; /* Address to first element of idt_entry */ 33 | } __attribute__((packed)); 34 | 35 | /* IDT access flag positions */ 36 | #define IDT_FLAG_P_SHIFT 7 37 | #define IDT_FLAG_DPL_SHIFT 5 38 | 39 | /** 40 | * 0 - Division by zero exception 41 | * 1 - Debug exception 42 | * 2 - Non maskable interrupt 43 | * 3 - Breakpoint exception 44 | * 4 - 'Into detected overflow' 45 | * 5 - Out of bounds exception 46 | * 6 - Invalid opcode exception 47 | * 7 - No coprocessor exception 48 | * 8 - Double fault (pushes an error code) 49 | * 9 - Coprocessor segment overrun 50 | * 10 - Bad TSS (pushes an error code) 51 | * 11 - Segment not present (pushes an error code) 52 | * 12 - Stack fault (pushes an error code) 53 | * 13 - General protection fault (pushes an error code) 54 | * 14 - Page fault (pushes an error code) 55 | * 15 - Unknown interrupt exception 56 | * 16 - Coprocessor fault 57 | * 17 - Alignment check exception 58 | * 18 - Machine check exception 59 | * 19-32 - Reserved 60 | */ 61 | extern void isr0 (void); 62 | extern void isr1 (void); 63 | extern void isr2 (void); 64 | extern void isr3 (void); 65 | extern void isr4 (void); 66 | extern void isr5 (void); 67 | extern void isr6 (void); 68 | extern void isr7 (void); 69 | extern void isr8 (void); 70 | extern void isr9 (void); 71 | extern void isr10(void); 72 | extern void isr11(void); 73 | extern void isr12(void); 74 | extern void isr13(void); 75 | extern void isr14(void); 76 | extern void isr15(void); 77 | extern void isr16(void); 78 | extern void isr17(void); 79 | extern void isr18(void); 80 | extern void isr19(void); 81 | extern void isr20(void); 82 | extern void isr21(void); 83 | extern void isr22(void); 84 | extern void isr23(void); 85 | extern void isr24(void); 86 | extern void isr25(void); 87 | extern void isr26(void); 88 | extern void isr27(void); 89 | extern void isr28(void); 90 | extern void isr29(void); 91 | extern void isr30(void); 92 | extern void isr31(void); 93 | extern void irq0 (void); 94 | extern void irq1 (void); 95 | extern void irq2 (void); 96 | extern void irq3 (void); 97 | extern void irq4 (void); 98 | extern void irq5 (void); 99 | extern void irq6 (void); 100 | extern void irq7 (void); 101 | extern void irq8 (void); 102 | extern void irq9 (void); 103 | extern void irq10(void); 104 | extern void irq11(void); 105 | extern void irq12(void); 106 | extern void irq13(void); 107 | extern void irq14(void); 108 | extern void irq15(void); 109 | 110 | /** 111 | * @brief set the interrupt descriptor table (IDT) 112 | * 113 | * @param num 114 | * @param base 115 | * @param selector 116 | * @param flags 117 | */ 118 | void idt_set_gate(uint8_t num, uint32_t base, 119 | uint16_t selector, uint8_t flags); 120 | 121 | /** 122 | * @brief Initialize the IDT table and load it into the CPU 123 | */ 124 | void idt_init(); 125 | 126 | #endif /* IDT_H */ 127 | -------------------------------------------------------------------------------- /src/kernel/cpu/cpu.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cpu.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-07-29 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | void cpuid(uint32_t value, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) 18 | { 19 | uint32_t eaxres, ebxres, ecxres, edxres; 20 | asm("xorl\t%eax, %eax"); 21 | asm("xorl\t%ebx, %ebx"); 22 | asm("xorl\t%ecx, %ecx"); 23 | asm("xorl\t%edx, %edx"); 24 | asm("movl\t%0, %%eax" 25 | : "=m"(value)); 26 | asm("cpuid"); 27 | asm("movl\t%%eax, %0" 28 | : "=m"(eaxres)); 29 | asm("movl\t%%ebx, %0" 30 | : "=m"(ebxres)); 31 | asm("movl\t%%ecx, %0" 32 | : "=m"(ecxres)); 33 | asm("movl\t%%edx, %0" 34 | : "=m"(edxres)); 35 | *eax = eaxres; 36 | *ebx = ebxres; 37 | *ecx = ecxres; 38 | *edx = edxres; 39 | } 40 | 41 | static void print_eax(uint32_t eax) 42 | { 43 | uint32_t step_id, model, family_id, proc_type, ext_mod_id, ext_family_id; 44 | step_id = model = family_id = proc_type = ext_mod_id = ext_family_id = eax; 45 | 46 | step_id &= (2 << 3) - 1; // bits 0-3 47 | model >>= 4; // bits 4-7 48 | model &= (2 << 3) - 1; 49 | family_id >>= 8; // bits 8-11 50 | family_id &= (2 << 3) - 1; 51 | proc_type >>= 12; // bits 12-13 52 | proc_type &= (2 << 1) - 1; 53 | ext_mod_id >>= 16; // bits 16-19 54 | ext_mod_id &= (2 << 3) - 1; 55 | ext_family_id >>= 20; // bits 20-27 56 | ext_family_id &= (2 << 7) - 1; 57 | 58 | kprintf("\tEAX ------------------------|\n"); 59 | kprintf("\t\tStepping ID : %d\n", step_id); 60 | kprintf("\t\tModel : %d\n", model); 61 | kprintf("\t\tFamily ID : %d\n", family_id); 62 | kprintf("\t\tProcessorType : %d\n", proc_type); 63 | kprintf("\t\tExtended Model ID : %d\n", ext_mod_id); 64 | kprintf("\t\tExtended Family : %d\n", ext_family_id); 65 | } 66 | 67 | static void print_ebx(uint32_t ebx) 68 | { 69 | uint32_t brand_index, cache_line_size, max_addr_id, init_apic_id; 70 | brand_index = cache_line_size = max_addr_id = init_apic_id = 0; 71 | char* bytes = (char *)&ebx; 72 | 73 | brand_index = bytes[0]; // bits 0-7 74 | cache_line_size = bytes[1]; // bits 8-15 75 | max_addr_id = bytes[2]; // bits 16-23 76 | init_apic_id = bytes[3]; // bits 24-31 77 | 78 | kprintf("\tEBX ------------------------|\n"); 79 | kprintf("\t\tBrand Index : %d\n", brand_index); 80 | kprintf("\t\tCache Line Size : %d\n", cache_line_size); 81 | kprintf("\t\tMax Address Id : %d\n", max_addr_id); 82 | kprintf("\t\tAPIC ID : %d\n", init_apic_id); 83 | } 84 | 85 | static void print_edx(uint32_t edx) 86 | { 87 | uint32_t apic_id, max_log_proc, max_cores, max_threads; 88 | apic_id = max_log_proc = max_cores = max_threads = 0; 89 | char* bytes = (char *)&edx; 90 | 91 | apic_id = bytes[0]; // bits 0-7 92 | max_log_proc = bytes[1]; // bits 8-15 93 | max_cores = bytes[2]; // bits 16-23 94 | max_threads = bytes[3]; // bits 24-31 95 | 96 | kprintf("\tEDX ------------------------|\n"); 97 | kprintf("\t\tAPIC ID : %d\n", apic_id); 98 | kprintf("\t\tMax Logical Proc : %d\n", max_log_proc); 99 | kprintf("\t\tMax Cores : %d\n", max_cores); 100 | kprintf("\t\tMax Threads : %d\n", max_threads); 101 | } 102 | 103 | void cpuid_info() 104 | { 105 | uint32_t eax, ebx, ecx, edx; 106 | 107 | kprintf("CPUID :\n"); 108 | 109 | cpuid(0, &eax, &ebx, &ecx, &edx); 110 | 111 | print_eax(eax); 112 | print_ebx(ebx); 113 | print_edx(edx); 114 | } -------------------------------------------------------------------------------- /include/cdefs.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cdefs.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.3 5 | * @date 2021-08-17 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef CDEFS_H 15 | #define CDEFS_H 16 | 17 | #include "assert.h" 18 | 19 | #define assert_failed(expr, file, line) 20 | 21 | #define VERIFY(x) \ 22 | do { \ 23 | if (UNLIKELY(!(x))) \ 24 | { \ 25 | assert_failed(#x, __FILE__, __LINE__); \ 26 | } \ 27 | } while (0) 28 | 29 | #define TO_PTR(n) ((void*)(unsigned long)(n)) 30 | 31 | #define _CONCAT(a, b) a##b 32 | #define CONCAT(a, b) _CONCAT(a, b) 33 | 34 | #define LIKELY(cond) __builtin_expect((cond), true) 35 | #define UNLIKELY(cond) __builtin_expect((cond), false) 36 | 37 | #define STATIC_ASSERT(expr) _Static_assert(expr, "Static assertion failed"); 38 | 39 | #define IN_RANGE(addr, begin, end) ((begin) <= (addr) && (addr) < (end)) 40 | 41 | #define NORETURN __attribute__((noreturn)) 42 | 43 | #ifdef __cplusplus 44 | # define __BEGIN_DECLS extern "C" { 45 | # define __END_DECLS } 46 | #else 47 | # define __BEGIN_DECLS 48 | # define __END_DECLS 49 | #endif 50 | 51 | #define UNSAFE_MIN(x, y) (((x) <= (y)) ? (x) : (y)) 52 | #define UNSAFE_MAX(x, y) (((x) >= (y)) ? (x) : (y)) 53 | 54 | #define UNSAFE_MIN3(a, b, c) UNSAFE_MIN(UNSAFE_MIN((a), (b)), (c)) 55 | #define UNSAFE_MAX3(a, b, c) UNSAFE_MAX(UNSAFE_MAX((a), (b)), (c)) 56 | 57 | #define UNSAFE_ABS(x) ((x) >= 0 ? (x) : -(x)) 58 | 59 | #define MIN(a, b) \ 60 | ({ \ 61 | const typeof(a) CONCAT(_a, __LINE__) = (a); \ 62 | const typeof(b) CONCAT(_b, __LINE__) = (b); \ 63 | UNSAFE_MIN(CONCAT(_a, __LINE__), CONCAT(_b, __LINE__)); \ 64 | }) 65 | 66 | #define MAX(a, b) \ 67 | ({ \ 68 | const typeof(a) CONCAT(_a, __LINE__) = (a); \ 69 | const typeof(b) CONCAT(_b, __LINE__) = (b); \ 70 | UNSAFE_MAX(CONCAT(_a, __LINE__), CONCAT(_b, __LINE__)); \ 71 | }) 72 | 73 | #define MIN3(a, b, c) \ 74 | ({ \ 75 | const typeof(a) CONCAT(_a, __LINE__) = (a); \ 76 | const typeof(b) CONCAT(_b, __LINE__) = (b); \ 77 | const typeof(c) CONCAT(_c, __LINE__) = (c); \ 78 | UNSAFE_MIN3(CONCAT(_a, __LINE__), \ 79 | CONCAT(_b, __LINE__), \ 80 | CONCAT(_c, __LINE__)); \ 81 | }) 82 | 83 | #define MAX3(a, b, c) \ 84 | ({ \ 85 | const typeof(a) CONCAT(_a, __LINE__) = (a); \ 86 | const typeof(b) CONCAT(_b, __LINE__) = (b); \ 87 | const typeof(c) CONCAT(_c, __LINE__) = (c); \ 88 | UNSAFE_MAX3(CONCAT(_a, __LINE__), \ 89 | CONCAT(_b, __LINE__), \ 90 | CONCAT(_c, __LINE__)); \ 91 | }) 92 | 93 | #define ABS(x) \ 94 | ({ \ 95 | const typeof(x) CONCAT(_x, __LINE__) = (x); \ 96 | UNSAFE_ABS(CONCAT(_x, __LINE__)); \ 97 | }) 98 | 99 | #define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof((a)[0]))) 100 | 101 | #endif // CDEFS_H -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file types.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.5 5 | * @date 2021-07-09 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef TYPES_H 15 | #define TYPES_H 16 | 17 | #include 18 | #include "cdefs.h" 19 | 20 | // Byte 21 | typedef unsigned char byte; 22 | typedef signed char sbyte; 23 | 24 | // Unsigned types 25 | typedef unsigned char uint8_t; 26 | typedef unsigned short uint16_t; 27 | typedef unsigned int uint32_t; 28 | typedef unsigned long uint64_t; 29 | typedef unsigned long long uint128_t; 30 | 31 | // Signed types 32 | typedef signed char int8_t; 33 | typedef signed short int16_t; 34 | typedef signed int int32_t; 35 | typedef signed long int64_t; 36 | typedef signed long long int128_t; 37 | 38 | // Words 39 | typedef short word_t; 40 | typedef int dword_t; 41 | typedef long qword_t; 42 | 43 | typedef short word; 44 | typedef int dword; 45 | typedef long qword; 46 | 47 | 48 | // float types 49 | typedef float float_t; 50 | typedef float float32_t; 51 | typedef double float64_t; 52 | typedef long double float128_t; 53 | 54 | // aliases 55 | typedef uint8_t u8; 56 | typedef uint16_t u16; 57 | typedef uint32_t u32; 58 | typedef uint64_t u64; 59 | typedef int8_t s8; 60 | typedef int16_t s16; 61 | typedef int32_t s32; 62 | typedef int64_t s64; 63 | typedef float32_t f32; 64 | typedef float64_t f64; 65 | typedef float128_t f128; 66 | 67 | // unsigned pointers 68 | typedef unsigned long int uintptr_t; 69 | typedef unsigned long int uintptr; 70 | 71 | #define NULLPTR NULL 72 | 73 | // Pointer types 74 | typedef char *string; 75 | typedef void *voidptr; 76 | typedef int *intptr; 77 | typedef uint8_t *uint8ptr; 78 | typedef uint16_t *uint16ptr; 79 | typedef uint32_t *uint32ptr; 80 | typedef uint64_t *uint64ptr; 81 | typedef int8_t *int8ptr; 82 | typedef int16_t *int16ptr; 83 | typedef int32_t *int32ptr; 84 | typedef int64_t *int64ptr; 85 | typedef float32_t *float32ptr; 86 | typedef float64_t *float64ptr; 87 | typedef float128_t *float128ptr; 88 | 89 | /* Boolean */ 90 | typedef enum {false=0, true} bool; 91 | #define FALSE false 92 | #define TRUE true 93 | 94 | /* Registers - interrupt/exception */ 95 | typedef struct Registers 96 | { 97 | uint32_t ds; 98 | uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; 99 | uint32_t int_no, err_code; 100 | uint32_t eip, cs, eflags, useresp, ss; 101 | } register_t; 102 | 103 | /* Registers - Bios service */ 104 | typedef struct Register16 105 | { 106 | uint16_t di, si, bp, sp, bx, dx, cx, ax; 107 | uint16_t ds, es, fs, gs, ss; 108 | uint16_t eflags; 109 | } register16_t; 110 | 111 | #define ALWAYS_INLINE __attribute__((always_inline)) 112 | #define NO_RETURN __attribute__((noreturn)) 113 | #define UNUSED __attribute__((unused)) 114 | #define PACKED __attribute__((packed)) 115 | #define ALIGNED(x) __attribute__((aligned(x))) 116 | #define ALIGNED_STRUCT(x) __attribute__((aligned(x))) struct 117 | #define ALIGNED_UNION(x) __attribute__((aligned(x))) union 118 | #define ALIGNED_TYPEDEF(x) __attribute__((aligned(x))) typedef 119 | #define ALIGNED_ENUM(x) __attribute__((aligned(x))) enum 120 | #define DEPRECATED __attribute__((deprecated)) 121 | 122 | #define __always_inline inline __attribute__((always_inline)) 123 | #define __no_return __attribute__((noreturn)) 124 | #define __unused __attribute__((unused)) 125 | #define __packed __attribute__((packed)) 126 | #define __aligned(x) __attribute__((aligned(x))) 127 | #define __aligned_struct(x) __attribute__((aligned(x))) struct 128 | #define __aligned_union(x) __attribute__((aligned(x))) union 129 | #define __aligned_typedef(x) __attribute__((aligned(x))) typedef 130 | #define __aligned_enum(x) __attribute__((aligned(x))) enum 131 | #define __deprecated __attribute__((deprecated)) 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /Assets/Banner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/kernel/cpu/idt/idt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | extern void load_idt(uint32_t); 8 | 9 | extern isr_t interrupt_handlers[]; 10 | 11 | static struct idt_entry idt_entries[256]; 12 | static struct idt_pointer idt_ptr; 13 | 14 | void idt_init() 15 | { 16 | idt_ptr.limit = sizeof(struct idt_entry) * 256 - 1; 17 | idt_ptr.base = (uint32_t)&idt_entries; 18 | 19 | memset((void *)&idt_entries, 0, (sizeof(struct idt_entry) * 256)); 20 | memset((void *)&interrupt_handlers, 0, (sizeof(isr_t) * 256)); 21 | 22 | /* 23 | * When the computer is booted, the default interrupt handlers are 24 | * IRQ 0..7 - INT 0x8..0xF 25 | * IRQ 8..15 - INT 0x70..0x77 26 | * 27 | * This causes a problem when we want to use the default handlers. 28 | * The master IRQ maps (0x8-0xF) conflict with the interrupt numbers 29 | * used by the CPU to signal exceptions and faults. The normal way 30 | * to solve this problem is to use the PIC (Programmable Interrupt 31 | * Controller) to remap the IRQs. (31 being the last CPU used ISR). 32 | */ 33 | PIC_MASTER_CMD_OUT (0x11); 34 | PIC_SLAVE_CMD_OUT (0x11); 35 | PIC_MASTER_DATA_OUT (0x20); 36 | PIC_SLAVE_DATA_OUT (0x28); 37 | PIC_MASTER_DATA_OUT (0x04); 38 | PIC_SLAVE_DATA_OUT (0x02); 39 | PIC_MASTER_DATA_OUT (0x01); 40 | PIC_SLAVE_DATA_OUT (0x01); 41 | PIC_MASTER_DATA_OUT (0x00); 42 | PIC_SLAVE_DATA_OUT (0x00); 43 | 44 | idt_set_gate( 0, (uint32_t)isr0 , 0x08, 0x8E); 45 | idt_set_gate( 1, (uint32_t)isr1 , 0x08, 0x8E); 46 | idt_set_gate( 2, (uint32_t)isr2 , 0x08, 0x8E); 47 | idt_set_gate( 3, (uint32_t)isr3 , 0x08, 0x8E); 48 | idt_set_gate( 4, (uint32_t)isr4 , 0x08, 0x8E); 49 | idt_set_gate( 5, (uint32_t)isr5 , 0x08, 0x8E); 50 | idt_set_gate( 6, (uint32_t)isr6 , 0x08, 0x8E); 51 | idt_set_gate( 7, (uint32_t)isr7 , 0x08, 0x8E); 52 | idt_set_gate( 8, (uint32_t)isr8 , 0x08, 0x8E); 53 | idt_set_gate( 9, (uint32_t)isr9 , 0x08, 0x8E); 54 | idt_set_gate(10, (uint32_t)isr10, 0x08, 0x8E); 55 | idt_set_gate(11, (uint32_t)isr11, 0x08, 0x8E); 56 | idt_set_gate(12, (uint32_t)isr12, 0x08, 0x8E); 57 | idt_set_gate(13, (uint32_t)isr13, 0x08, 0x8E); 58 | idt_set_gate(14, (uint32_t)isr14, 0x08, 0x8E); 59 | idt_set_gate(15, (uint32_t)isr15, 0x08, 0x8E); 60 | idt_set_gate(16, (uint32_t)isr16, 0x08, 0x8E); 61 | idt_set_gate(17, (uint32_t)isr17, 0x08, 0x8E); 62 | idt_set_gate(18, (uint32_t)isr18, 0x08, 0x8E); 63 | idt_set_gate(19, (uint32_t)isr19, 0x08, 0x8E); 64 | idt_set_gate(20, (uint32_t)isr20, 0x08, 0x8E); 65 | idt_set_gate(21, (uint32_t)isr21, 0x08, 0x8E); 66 | idt_set_gate(22, (uint32_t)isr22, 0x08, 0x8E); 67 | idt_set_gate(23, (uint32_t)isr23, 0x08, 0x8E); 68 | idt_set_gate(24, (uint32_t)isr24, 0x08, 0x8E); 69 | idt_set_gate(25, (uint32_t)isr25, 0x08, 0x8E); 70 | idt_set_gate(26, (uint32_t)isr26, 0x08, 0x8E); 71 | idt_set_gate(27, (uint32_t)isr27, 0x08, 0x8E); 72 | idt_set_gate(28, (uint32_t)isr28, 0x08, 0x8E); 73 | idt_set_gate(29, (uint32_t)isr29, 0x08, 0x8E); 74 | idt_set_gate(30, (uint32_t)isr30, 0x08, 0x8E); 75 | idt_set_gate(31, (uint32_t)isr31, 0x08, 0x8E); 76 | idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E); 77 | idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E); 78 | idt_set_gate(34, (uint32_t)irq2, 0x08, 0x8E); 79 | idt_set_gate(35, (uint32_t)irq3, 0x08, 0x8E); 80 | idt_set_gate(36, (uint32_t)irq4, 0x08, 0x8E); 81 | idt_set_gate(37, (uint32_t)irq5, 0x08, 0x8E); 82 | idt_set_gate(38, (uint32_t)irq6, 0x08, 0x8E); 83 | idt_set_gate(39, (uint32_t)irq7, 0x08, 0x8E); 84 | idt_set_gate(40, (uint32_t)irq8, 0x08, 0x8E); 85 | idt_set_gate(41, (uint32_t)irq9, 0x08, 0x8E); 86 | idt_set_gate(42, (uint32_t)irq10, 0x08, 0x8E); 87 | idt_set_gate(43, (uint32_t)irq11, 0x08, 0x8E); 88 | idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E); 89 | idt_set_gate(45, (uint32_t)irq13, 0x08, 0x8E); 90 | idt_set_gate(46, (uint32_t)irq14, 0x08, 0x8E); 91 | idt_set_gate(47, (uint32_t)irq15, 0x08, 0x8E); 92 | 93 | load_idt((uint32_t)&idt_ptr); 94 | qemu_success("IDT Loaded, base->%p\r\n", &idt_ptr.base); 95 | } 96 | 97 | void idt_set_gate(uint8_t num, uint32_t base, 98 | uint16_t selector, uint8_t flags) 99 | { 100 | idt_entries[num].base_low = base & 0xFFFF; 101 | idt_entries[num].base_high = (base >> 16) & 0xFFFF; 102 | 103 | idt_entries[num].selector = selector; 104 | idt_entries[num].always0 = 0; 105 | 106 | /* 107 | * We must uncomment the OR below when we get to using user-mode. 108 | * It sets the interrupt gate's privilege level to 3. 109 | */ 110 | idt_entries[num].flags = flags; /* | 0x60 */ 111 | } 112 | -------------------------------------------------------------------------------- /include/arch/i386/paging.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file paging.h 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-24 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #ifndef PAGING_INT_H 15 | #define PAGING_INT_H 16 | 17 | #include 18 | 19 | #define KERNEL_BASE_VA 0xC0000000 20 | 21 | #define KERNEL_PA_TO_VA(pa) ((void *) ((uint64_t)(pa) + KERNEL_BASE_VA)) 22 | #define KERNEL_VA_TO_PA(va) ((uint64_t)(va) - KERNEL_BASE_VA) 23 | 24 | #define PG_PRESENT_BIT_POS 0u 25 | #define PG_RW_BIT_POS 1u 26 | #define PG_US_BIT_POS 2u 27 | #define PG_WT_BIT_POS 3u 28 | #define PG_CD_BIT_POS 4u 29 | #define PG_ACC_BIT_POS 5u 30 | #define PG_DIRTY_BIT_POS 6u // page_t only 31 | #define PG_PAGE_PAT_BIT_POS 7u // page_t only 32 | #define PG_4MB_BIT_POS 7u // page_dir_entry_t only 33 | #define PG_GLOBAL_BIT_POS 8u // page_t only 34 | #define PG_CUSTOM_B0_POS 9u 35 | #define PG_CUSTOM_B1_POS 10u 36 | #define PG_CUSTOM_B2_POS 11u 37 | #define PG_4MB_PAT_BIT_POS 12u // page_dir_entry_t only with psize = 1 38 | 39 | #define PG_PRESENT_BIT (1u << PG_PRESENT_BIT_POS) 40 | #define PG_RW_BIT (1u << PG_RW_BIT_POS) 41 | #define PG_US_BIT (1u << PG_US_BIT_POS) 42 | #define PG_WT_BIT (1u << PG_WT_BIT_POS) 43 | #define PG_CD_BIT (1u << PG_CD_BIT_POS) 44 | #define PG_ACC_BIT (1u << PG_ACC_BIT_POS) 45 | #define PG_DIRTY_BIT (1u << PG_DIRTY_BIT_POS) // page_t only 46 | #define PG_PAGE_PAT_BIT (1u << PG_PAGE_PAT_BIT_POS) // page_t only 47 | #define PG_4MB_BIT (1u << PG_4MB_BIT_POS) // page_dir_entry_t only 48 | #define PG_GLOBAL_BIT (1u << PG_GLOBAL_BIT_POS) // page_t only 49 | #define PG_CUSTOM_B0 (1u << PG_CUSTOM_B0_POS) 50 | #define PG_CUSTOM_B1 (1u << PG_CUSTOM_B1_POS) 51 | #define PG_CUSTOM_B2 (1u << PG_CUSTOM_B2_POS) 52 | #define PG_CUSTOM_BITS (PG_CUSTOM_B0 | PG_CUSTOM_B1 | PG_CUSTOM_B2) 53 | #define PG_4MB_PAT_BIT (1u << PG_4MB_PAT_BIT_POS) 54 | 55 | #define PAGE_FAULT_FL_PRESENT (1u << 0) 56 | #define PAGE_FAULT_FL_RW (1u << 1) 57 | #define PAGE_FAULT_FL_US (1u << 2) 58 | 59 | #define PAGE_FAULT_FL_COW (PAGE_FAULT_FL_PRESENT | PAGE_FAULT_FL_RW) 60 | #define BIG_PAGE_SHIFT 22 61 | #define KERNEL_BASE_PD_IDX (KERNEL_BASE_VA >> BIG_PAGE_SHIFT) 62 | 63 | #define PAGE_SIZE 4096u 64 | #define PAGE_SHIFT 12u 65 | #define OFFSET_IN_PAGE_MASK (PAGE_SIZE - 1) 66 | 67 | union x86_page 68 | { 69 | struct 70 | { 71 | uint32_t present : 1; 72 | uint32_t rw : 1; 73 | uint32_t us : 1; 74 | uint32_t wt : 1; 75 | uint32_t cd : 1; 76 | uint32_t accessed : 1; 77 | uint32_t dirty : 1; 78 | uint32_t pat : 1; 79 | uint32_t global : 1; 80 | uint32_t avail : 3; 81 | uint32_t page_addr : 20; 82 | }; 83 | 84 | uint32_t raw; 85 | }; 86 | 87 | struct x86_page_table 88 | { 89 | union x86_page pages[1024]; 90 | }; 91 | 92 | union x86_page_dir_entry 93 | { 94 | struct 95 | { 96 | uint32_t present : 1; 97 | uint32_t rw : 1; 98 | uint32_t us : 1; 99 | uint32_t wt : 1; 100 | uint32_t cd : 1; 101 | uint32_t accessed : 1; 102 | uint32_t zero : 1; 103 | uint32_t psize : 1; 104 | uint32_t ignored : 1; 105 | uint32_t avail : 3; 106 | uint32_t ptaddr : 20; 107 | }; 108 | 109 | struct 110 | { 111 | uint32_t present : 1; 112 | uint32_t rw : 1; 113 | uint32_t us : 1; 114 | uint32_t wt : 1; 115 | uint32_t cd : 1; 116 | uint32_t accessed : 1; 117 | uint32_t zero : 1; 118 | uint32_t one : 1; 119 | uint32_t ignored : 1; 120 | uint32_t avail : 3; 121 | uint32_t pat : 1; 122 | uint32_t paddr_zero : 9; 123 | uint32_t paddr : 10; 124 | } big_4mb_page; 125 | 126 | uint32_t raw; 127 | }; 128 | 129 | struct x86_pdir 130 | { 131 | union x86_page_dir_entry entries[1024]; 132 | }; 133 | 134 | STATIC_ASSERT(sizeof(struct x86_pdir) == 4096u); 135 | 136 | typedef union x86_page page_t; 137 | typedef struct x86_page_table page_table_t; 138 | typedef union x86_page_dir_entry page_dir_entry_t; 139 | typedef struct x86_pdir pdir_t; 140 | 141 | int virtual_read(pdir_t *pdir, void *extern_va, void *dest, size_t len); 142 | int virtual_write(pdir_t *pdir, void *extern_va, void *src, size_t len); 143 | 144 | #endif // PAGING_INT_H -------------------------------------------------------------------------------- /src/kernel/cpu/bios/cmos.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cmos.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.0 5 | * @date 2021-08-15 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | uint8_t cmod_lowmem() 21 | { 22 | uint8_t lowmem; 23 | 24 | // Get the low memory size from CMOS 25 | outb(0x70, 0x30); 26 | lowmem = inb(0x71); 27 | return lowmem; 28 | } 29 | 30 | uint8_t cmod_highmem() 31 | { 32 | uint8_t highmem; 33 | 34 | // Get the high memory size from CMOS 35 | outb(0x70, 0x31); 36 | highmem = inb(0x71); 37 | return highmem; 38 | } 39 | 40 | uint16_t cmod_totalmem() 41 | { 42 | uint16_t totalmem; 43 | uint8_t lowmem, highmem; 44 | 45 | lowmem = cmod_lowmem(); 46 | highmem = cmod_highmem(); 47 | 48 | // Calculate the total memory size 49 | totalmem = lowmem | highmem << 8; 50 | return totalmem; 51 | } 52 | 53 | uint8_t second; 54 | uint8_t minute; 55 | uint8_t hour; 56 | uint8_t day; 57 | uint8_t month; 58 | uint32_t year; 59 | uint8_t century; 60 | uint8_t last_second; 61 | uint8_t last_minute; 62 | uint8_t last_hour; 63 | uint8_t last_day; 64 | uint8_t last_month; 65 | uint8_t last_year; 66 | uint8_t last_century; 67 | uint8_t registerB; 68 | 69 | int century_register = 0x00; 70 | 71 | enum 72 | { 73 | cmos_address = 0x70, 74 | cmos_data = 0x71 75 | }; 76 | 77 | int get_update_in_progress_flag() { 78 | outb(cmos_address, 0x0A); 79 | return (inb(cmos_data) & 0x80); 80 | } 81 | 82 | 83 | uint8_t get_rtc_register(int reg) { 84 | outb(cmos_address, reg); 85 | return inb(cmos_data); 86 | } 87 | 88 | void read_rtc() 89 | { 90 | /* Note: This uses the "read registers until you 91 | get the same values in a row" technique 92 | to avoid getting inconsistent values due to RTC updates 93 | */ 94 | 95 | // Make sure that an update isn't in progress 96 | while (get_update_in_progress_flag()); 97 | 98 | second = get_rtc_register(0x00); 99 | minute = get_rtc_register(0x02); 100 | hour = get_rtc_register(0x04); 101 | day = get_rtc_register(0x07); 102 | month = get_rtc_register(0x08); 103 | year = get_rtc_register(0x09); 104 | 105 | if (century_register != 0) 106 | century = get_rtc_register(century_register); 107 | 108 | do 109 | { 110 | last_second = second; 111 | last_minute = minute; 112 | last_hour = hour; 113 | last_day = day; 114 | last_month = month; 115 | last_year = year; 116 | last_century = century; 117 | 118 | while (get_update_in_progress_flag()); // Wait for update to finish 119 | 120 | second = get_rtc_register(0x00); 121 | minute = get_rtc_register(0x02); 122 | hour = get_rtc_register(0x04); 123 | day = get_rtc_register(0x07); 124 | month = get_rtc_register(0x08); 125 | year = get_rtc_register(0x09); 126 | 127 | if (century_register != 0) 128 | century = get_rtc_register(century_register); 129 | } while( 130 | (last_second != second) || 131 | (last_minute != minute) || 132 | (last_hour != hour) || 133 | (last_day != day) || 134 | (last_month != month) || 135 | (last_year != year) || 136 | (last_century != century) 137 | ); 138 | 139 | registerB = get_rtc_register(0x0B); 140 | 141 | // Convert BCD to binary values if necessary 142 | if (!(registerB & 0x04)) 143 | { 144 | second = (second & 0x0F) + ((second / 16) * 10); 145 | minute = (minute & 0x0F) + ((minute / 16) * 10); 146 | hour = ((hour & 0x0F) + (((hour & 0x70) / 16) * 10)) | (hour & 0x80); 147 | day = (day & 0x0F) + ((day / 16) * 10); 148 | month = (month & 0x0F) + ((month / 16) * 10); 149 | year = (year & 0x0F) + ((year / 16) * 10); 150 | 151 | if (century_register != 0) 152 | century = (century & 0x0F) + ((century / 16) * 10); 153 | } 154 | 155 | // Convert 12 hour clock to 24 hour clock if necessary 156 | if (!(registerB & 0x02) && (hour & 0x80)) 157 | hour = ((hour & 0x7F) + 12) % 24; 158 | 159 | // Calculate the full (4-digit) year 160 | if (century_register != 0) 161 | year += century * 100; 162 | else 163 | { 164 | year += (CURRENT_YEAR / 100) * 100; 165 | if (year < CURRENT_YEAR) year += 100; 166 | } 167 | } 168 | 169 | // FIXME: This is a hack to get around the fact that QEMU doesn't support the CMOS registers 0x0B and 0x0C 170 | void get_current_time() 171 | { 172 | read_rtc(); 173 | qemu_info("time: %u.%u.%u %u:%u\n", day, month, year, hour, minute); 174 | } -------------------------------------------------------------------------------- /src/debug/qemu.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file qemu.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-22 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | void qemu_puts(const char *str) 19 | { 20 | for (size_t i = 0; i < strlen(str); i++) 21 | com_send_char(COM1_PORT, str[i]); 22 | } 23 | 24 | void qemu_putuint(int i) 25 | { 26 | uint32_t n, d = 1000000000; 27 | char str[255]; 28 | uint32_t dec_index = 0; 29 | while ((i/d == 0) && (d >= 10)) d /= 10; 30 | n = i; 31 | 32 | while (d >= 10) 33 | { 34 | str[dec_index++] = ((char)((int)'0' + n/d)); 35 | n %= d; 36 | d /= 10; 37 | } 38 | 39 | str[dec_index++] = ((char)((int)'0' + n)); 40 | str[dec_index] = 0; 41 | qemu_puts(str); 42 | } 43 | 44 | void qemu_putint(int i) 45 | { 46 | if (i < 0) 47 | { 48 | i = -i; 49 | qemu_puts("-"); 50 | } 51 | 52 | qemu_putuint(i); 53 | } 54 | 55 | void qemu_puthex(uint32_t i) 56 | { 57 | const uint8_t hex_chars[16] = { '0', '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' }; 58 | uint32_t n, d = 0x10000000; 59 | 60 | qemu_puts("0x"); 61 | while ((i/d == 0) && (d >= 0x10)) d /= 0x10; 62 | n = i; 63 | 64 | while (d >= 0xF) 65 | { 66 | com_send_char(COM1_PORT, hex_chars[n/d]); 67 | n %= d; 68 | d /= 0x10; 69 | } 70 | 71 | com_send_char(COM1_PORT, hex_chars[n]); 72 | } 73 | 74 | void qemu_print(const char *str, va_list args) 75 | { 76 | int i = 0; 77 | char* string; 78 | 79 | while (str[i] != 0) 80 | { 81 | if (str[i] == '%') 82 | { 83 | i++; 84 | switch (str[i]) 85 | { 86 | case 's': 87 | string = va_arg(args, char*); 88 | qemu_puts(string); 89 | break; 90 | 91 | case 'c': 92 | com_send_char(COM1_PORT, va_arg(args, int)); 93 | break; 94 | 95 | case 'd': 96 | qemu_putint(va_arg(args, int)); 97 | break; 98 | 99 | case 'i': 100 | qemu_putint(va_arg(args, int)); 101 | break; 102 | 103 | case 'u': 104 | qemu_putuint(va_arg(args, uint32_t)); 105 | break; 106 | 107 | case 'x': 108 | qemu_puthex(va_arg(args, uint32_t)); 109 | break; 110 | 111 | case 'p': 112 | qemu_puthex(va_arg(args, uint32_t)); 113 | break; 114 | 115 | default: 116 | com_send_char(COM1_PORT, str[i]); 117 | break; 118 | } 119 | } 120 | else 121 | com_send_char(COM1_PORT, str[i]); 122 | i++; 123 | } 124 | } 125 | 126 | void qemu_printf(char *fmt, ...) 127 | { 128 | va_list args; 129 | va_start(args, fmt); 130 | qemu_print(fmt, args); 131 | va_end(args); 132 | } 133 | 134 | char* output; 135 | 136 | void _qemu_dbg(char *fmt, ...) 137 | { 138 | strcpy(output, DEBUG_MESSAGE_PREFIX ); 139 | strcat(output, fmt); 140 | 141 | va_list args; 142 | va_start(args, fmt); 143 | qemu_print(output, args); 144 | va_end(args); 145 | } 146 | 147 | void _qemu_success(char *fmt, ...) 148 | { 149 | strcpy(output, SUCCESS_MESSAGE_PREFIX ); 150 | strcat(output, fmt); 151 | 152 | va_list args; 153 | va_start(args, fmt); 154 | qemu_print(output, args); 155 | va_end(args); 156 | } 157 | 158 | void _qemu_info(char *fmt, ...) 159 | { 160 | strcpy(output, INFO_MESSAGE_PREFIX ); 161 | strcat(output, fmt); 162 | 163 | va_list args; 164 | va_start(args, fmt); 165 | qemu_print(output, args); 166 | va_end(args); 167 | } 168 | 169 | void _qemu_error(char* fmt, ...) 170 | { 171 | strcpy(output, ERROR_MESSAGE_PREFIX ); 172 | strcat(output, fmt); 173 | 174 | va_list args; 175 | va_start(args, fmt); 176 | qemu_print(output, args); 177 | va_end(args); 178 | } 179 | 180 | void _qemu_panic(char* fmt, ...) 181 | { 182 | strcpy(output, PANIC_MESSAGE_PREFIX ); 183 | strcat(output, fmt); 184 | 185 | va_list args; 186 | va_start(args, fmt); 187 | qemu_print(output, args); 188 | va_end(args); 189 | } 190 | 191 | void _qemu_device(char* fmt, ...) 192 | { 193 | strcpy(output, DEVICE_MESSAGE_PREFIX ); 194 | strcat(output, fmt); 195 | 196 | va_list args; 197 | va_start(args, fmt); 198 | qemu_print(output, args); 199 | va_end(args); 200 | } 201 | 202 | void _qemu_warning(char* fmt, ...) 203 | { 204 | strcpy(output, WARNING_MESSAGE_PREFIX ); 205 | strcat(output, fmt); 206 | 207 | va_list args; 208 | va_start(args, fmt); 209 | qemu_print(output, args); 210 | va_end(args); 211 | } 212 | -------------------------------------------------------------------------------- /src/kernel/memory.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file memory.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.2 5 | * @date 2021-08-17 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | MemorySegmentHeader* first_free_segment; 20 | 21 | void heap_init(uint64_t heap_address, uint64_t heap_size) 22 | { 23 | first_free_segment = (MemorySegmentHeader*)heap_address; 24 | first_free_segment->length = heap_size - sizeof(MemorySegmentHeader); 25 | first_free_segment->next = NULL; 26 | first_free_segment->prev = NULL; 27 | first_free_segment->next_free = NULL; 28 | first_free_segment->prev_free = NULL; 29 | first_free_segment->free = true; 30 | } 31 | 32 | void* kmalloc(size_t size) 33 | { 34 | size_t remainder = size % 8; 35 | size -= remainder; 36 | if (remainder != 0) size += 8; 37 | 38 | MemorySegmentHeader* current_segment = first_free_segment; 39 | 40 | while (true) 41 | { 42 | if (current_segment->length >= size) 43 | { 44 | if (current_segment->length > size + sizeof(MemorySegmentHeader)) 45 | { 46 | MemorySegmentHeader* new_segment = (MemorySegmentHeader*)((uint64_t)current_segment + sizeof(MemorySegmentHeader) + size); 47 | 48 | new_segment->free = true; 49 | new_segment->length = ((uint64_t)current_segment->length) - (sizeof(MemorySegmentHeader) + size); 50 | new_segment->next = current_segment->next; 51 | new_segment->prev = current_segment; 52 | new_segment->next_free = current_segment->next_free; 53 | new_segment->prev_free = current_segment->prev_free; 54 | 55 | current_segment->next_free = new_segment; 56 | current_segment->next = new_segment; 57 | current_segment->length = size; 58 | } 59 | 60 | if (current_segment == first_free_segment) 61 | first_free_segment = current_segment->next_free; 62 | 63 | current_segment->free = false; 64 | 65 | if (current_segment->prev_free != NULLPTR) 66 | current_segment->prev_free->next_free = current_segment->next_free; 67 | 68 | if (current_segment->next_free != NULLPTR) 69 | current_segment->next_free->prev_free = current_segment->prev_free; 70 | 71 | if (current_segment->prev != NULLPTR) 72 | current_segment->prev->next_free = current_segment->next_free; 73 | 74 | if (current_segment->next != NULLPTR) 75 | current_segment->next->prev_free = current_segment->prev_free; 76 | 77 | return current_segment + 1; 78 | } 79 | 80 | // Should never happen, but if does, no memory remaining 81 | if (current_segment->next_free == NULLPTR) 82 | return 0; 83 | 84 | current_segment = current_segment->next_free; 85 | } 86 | 87 | return 0; // Should never get here 88 | } 89 | 90 | void combine_free(MemorySegmentHeader* segment_a, MemorySegmentHeader* segment_b) 91 | { 92 | if (segment_a == NULLPTR || segment_b == NULLPTR) return; 93 | 94 | if (segment_a < segment_b) 95 | { 96 | segment_a->length += segment_b->length + sizeof(MemorySegmentHeader); 97 | segment_a->next = segment_b->next; 98 | segment_a->next_free = segment_b->next_free; 99 | segment_b->prev = segment_a; 100 | segment_b->next->prev_free = segment_a; 101 | segment_b->next_free->prev_free = segment_a; 102 | } 103 | else 104 | { 105 | segment_b->length += segment_a->length + sizeof(MemorySegmentHeader); 106 | segment_b->next = segment_a->next; 107 | segment_b->next_free = segment_a->next_free; 108 | segment_a->prev = segment_b; 109 | segment_a->next->prev_free = segment_b; 110 | segment_a->next_free->prev_free = segment_b; 111 | } 112 | } 113 | 114 | void kfree(void* ptr) 115 | { 116 | MemorySegmentHeader* current_segment = ((MemorySegmentHeader*)ptr) - 1; 117 | current_segment->free = true; 118 | 119 | if (current_segment < first_free_segment) 120 | first_free_segment = current_segment; 121 | 122 | if (current_segment->next_free != NULLPTR) 123 | if (current_segment->next_free->prev_free < current_segment) 124 | current_segment->next_free->prev_free = current_segment; 125 | if (current_segment->prev_free != NULLPTR) 126 | if (current_segment->prev_free->next_free > current_segment) 127 | current_segment->prev_free->next_free = current_segment; 128 | 129 | if (current_segment->next != NULLPTR) 130 | { 131 | current_segment->next->prev = current_segment->prev_free; 132 | if (current_segment->next->free) 133 | combine_free(current_segment, current_segment->next); 134 | } 135 | if (current_segment->prev != NULLPTR) 136 | { 137 | current_segment->prev->next = current_segment->next_free; 138 | if (current_segment->prev->free) 139 | combine_free(current_segment->prev, current_segment); 140 | } 141 | } -------------------------------------------------------------------------------- /src/kernel/time/rtc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* Global date time variable */ 8 | datetime_t current_datetime; 9 | 10 | char *weekday_map[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 11 | 12 | /** 13 | * @brief Check if the RTC is updating the time 14 | */ 15 | int rtc_is_updating() 16 | { 17 | outb(CMOS_ADDR, 0x0A); 18 | uint32_t status = inb(CMOS_DATA); 19 | return (status & 0x80); 20 | } 21 | 22 | /** 23 | * @brief Get the value of a specific rtc register 24 | * 25 | * @param reg 26 | * @return uint8_t 27 | */ 28 | uint8_t rtc_get_register(uint8_t reg) 29 | { 30 | outb(CMOS_ADDR, reg); 31 | return inb(CMOS_DATA); 32 | } 33 | 34 | /** 35 | * @brief Set the value of a specific rtc register 36 | * 37 | * @param reg 38 | * @param val 39 | */ 40 | void rtc_set_register(uint8_t reg, uint8_t val) 41 | { 42 | outb(CMOS_ADDR, reg); 43 | outb(CMOS_DATA, val); 44 | } 45 | 46 | 47 | /** 48 | * @brief Read the current time from the RTC, and update the global variable 49 | */ 50 | void rtc_read_datetime() 51 | { 52 | /* Wait for the RTC to be updated */ 53 | while (rtc_is_updating()); 54 | 55 | current_datetime.second = rtc_get_register(0x00); 56 | current_datetime.minute = rtc_get_register(0x02); 57 | current_datetime.hour = rtc_get_register(0x04); 58 | current_datetime.day = rtc_get_register(0x07); 59 | current_datetime.month = rtc_get_register(0x08); 60 | current_datetime.year = rtc_get_register(0x09); 61 | 62 | uint8_t register_b = rtc_get_register(0x0B); 63 | 64 | /* Convert BCD to binary values if necessary */ 65 | if (!(register_b & 0x04)) 66 | { 67 | current_datetime.second = (current_datetime.second & 0x0F) + ((current_datetime.second / 16) * 10); 68 | current_datetime.minute = (current_datetime.minute & 0x0F) + ((current_datetime.minute / 16) * 10); 69 | current_datetime.hour = ( (current_datetime.hour & 0x0F) + (((current_datetime.hour & 0x70) / 16) * 10) ) | (current_datetime.hour & 0x80); 70 | current_datetime.day = (current_datetime.day & 0x0F) + ((current_datetime.day / 16) * 10); 71 | current_datetime.month = (current_datetime.month & 0x0F) + ((current_datetime.month / 16) * 10); 72 | current_datetime.year = (current_datetime.year & 0x0F) + ((current_datetime.year / 16) * 10); 73 | } 74 | } 75 | 76 | /** 77 | * @brief Write a datetime struct to the RTC 78 | * 79 | * @param dt 80 | */ 81 | void rtc_write_datetime(datetime_t *dt) 82 | { 83 | /* Wait for the RTC to be updated */ 84 | while (rtc_is_updating()); 85 | 86 | rtc_set_register(0x00, dt->second); 87 | rtc_set_register(0x02, dt->minute); 88 | rtc_set_register(0x04, dt->hour); 89 | rtc_set_register(0x07, dt->day); 90 | rtc_set_register(0x08, dt->month); 91 | rtc_set_register(0x09, dt->year); 92 | } 93 | 94 | /** 95 | * @brief Convenient function to convert a datetime struct to a string. 96 | * Output format: "day hour:minute" 97 | * Example: "Sun 10:30" 98 | * 99 | * @param dt 100 | * @return char* 101 | */ 102 | char *rtc_datetime_string(datetime_t *dt) 103 | { 104 | char *ret = kmalloc(sizeof(char) * 16); 105 | char day[4]; 106 | char hour[3]; 107 | char minute[3]; 108 | 109 | memset(&day, 0x0, 4); 110 | memset(&hour, 0x0, 3); 111 | memset(&minute, 0x0, 3); 112 | 113 | const char *weekday = weekday_map[rtc_weekday_from_date(dt)]; 114 | strcpy(day, weekday); 115 | itoa(hour, dt->hour); 116 | itoa(minute, dt->minute); 117 | 118 | strcpy(ret, day); 119 | strcat(ret, " "); 120 | strcat(ret, hour); 121 | strcat(ret, ":"); 122 | strcat(ret, minute); 123 | return ret; 124 | } 125 | 126 | char *rtc_current_datetime_string() 127 | { 128 | return rtc_datetime_string(¤t_datetime); 129 | } 130 | 131 | int rtc_weekday_from_date(datetime_t *dt) 132 | { 133 | char month_code_array[] = {0x0,0x3, 0x3, 0x6, 0x1, 0x4, 0x6, 0x2, 0x5, 0x0, 0x3, 0x5}; 134 | char century_code_array[] = {0x4, 0x2, 0x0, 0x6, 0x4, 0x2, 0x0}; /* Starting with 18th century */ 135 | 136 | /* Set current century */ 137 | dt->century = 21; 138 | 139 | /* Calculate the year code */ 140 | int year_code = (dt->year + (dt->year / 4)) % 7; 141 | int month_code = month_code_array[dt->month - 1]; 142 | int century_code = century_code_array[dt->century - 18]; 143 | int leap_year_code = rtc_leap_year(dt->year, dt->month); 144 | 145 | int ret = (year_code + month_code + century_code + leap_year_code) % 7; 146 | return ret; 147 | } 148 | 149 | int rtc_leap_year(int year, int month) 150 | { 151 | if (year % 4 == 0 && (month == 1 || month == 2)) return 1; 152 | return 0; 153 | } 154 | 155 | /** 156 | * @brief Initialize the RTC 157 | * 158 | * @note FIXME: This function is not working properly. It is not setting the correct time. 159 | * It is also not setting the correct date. 160 | * 161 | * @note NOTE: copilot idea: The rtc_read_datetime() function is not working properly. 162 | * It is not reading the correct time. This could be because of the way the RTC is set. 163 | * The RTC is set using the `-rtc base=localtime` command line argument for qemu. 164 | * The RTC is not being read correctly. via the rtc_read_datetime() function. 165 | * 166 | */ 167 | void rtc_init() 168 | { 169 | rtc_read_datetime(); 170 | } 171 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | bobrossrtx@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #* file Makefile 2 | #* author Owen Boreham (owenkadeboreham@gmail.com) 3 | #* version 0.1.8 4 | #* date 2021-07-08 5 | #* 6 | #* Copyright (c) 2021 TinyKernel 7 | #* This file is part of TinyKernel which is released 8 | #* under Apache License 2.0. See file LICENSE or go 9 | #* to https://www.apache.org/licenses/LICENSE-2.0 for 10 | #* full license details. 11 | 12 | # Project imports 13 | include config.cfg 14 | include colors.mk 15 | include src/arch/build.mk 16 | 17 | # Files 18 | AUXS := Makefile README.md LICENSE CODE_OF_CONDUCT.md 19 | SRCS := $(shell find $(PROJ_DIRS) -name *.cpp -or -name *.c -or -name *.s -or -name *.asm) 20 | HDRS := $(shell find $(PROJ_DIRS) -name *.h -or -name *.hh) 21 | OBJS := $(SRCS:%=$(OBJ_DIR)/%.o) 22 | DEPS := $(SRCS:%=$(OBJ_DIR)/%.d) 23 | TARGET ?= $(BOOT_DIR)/TinyKernel.elf 24 | ISO ?= TinyKernel_$(AUTHOR)-$(BUILD_VERSION).iso 25 | 26 | ALLFILES := $(SRCS) $(HDRS) $(OBJS) $(AUXS) 27 | 28 | # GCC Definitions 29 | BUILD_DEFS := \ 30 | -DASSERT \ 31 | -D__BUILD_ARCH__=\""$(BUILD_ARCH)"\" \ 32 | -D__BUID_GITREF__=\""$(BUILD_GITREF)"\" \ 33 | -D__BUILD_UNAME__=\""$(BUILD_UNAME)"\" \ 34 | -D__BUILD_DATE__=\""$(BUILD_DATE)"\" \ 35 | -D__QEMU__="$(QEMU_DEBUG)" \ 36 | -D__SERIAL_COLORS__="$(SERIAL_COLORS)" \ 37 | -D__NDEBUG__="$(NDEBUG)" \ 38 | -D__BUILD_VERSION__=\""$(BUILD_VERSION)"\" 39 | 40 | # Flags 41 | LOWER_WARNINGS := -Wall -Wextra 42 | 43 | ## Warning flags for later use when refactoring & cleaning 44 | WARNING_FLAGS := $(LOWER_WARNINGS) -pedantic -Wshadow -Wpointer-arith -Wcast-align \ 45 | -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations \ 46 | -Wredundant-decls -Wnested-externs -Winline -Wno-long-long \ 47 | -Wconversion -Wstrict-prototypes 48 | 49 | INC_FLAGS := $(addprefix -I ,$(INC_DIRS)) 50 | CFLAGS := $(INC_FLAGS) $(BUILD_DEFS) -MMD -MP -std=gnu99 -ffreestanding -O2 -m32 -fno-stack-protector $(LOWER_WARNINGS) -g 51 | LDFLAGS := -nostdlib -znocombreloc 52 | LDFLAGS += -m elf_i386 -T config/linker.ld 53 | ASFLAGS := --32 54 | NASMFLAGS := -f elf32 55 | QEMUFLAGS := cdrom $(ISO_DIR)/$(ISO) 56 | 57 | # Backups 58 | CURR_DIR := $(shell basename `pwd`) 59 | TODAY := $(shell date +%Y-%m-%d) 60 | BACKUP_DIR := Backups/$(TODAY) 61 | 62 | # Package managers 63 | pacman := $(shell command -v pacman 2>/dev/null) 64 | yum := $(shell command -v yum 2>/dev/null) 65 | apt := $(shell command -v apt 2>/dev/null) 66 | 67 | # Grub 68 | grub := $(shell command -v grub-file 2>/dev/null) 69 | 70 | .PHONY: clean iso build 71 | iso: build 72 | @echo "${YELLOW}GRUB $^ -> ${BLUE}$(ISO)${GREEN}" 73 | @grub-mkrescue -o $(ISO_DIR)/$(ISO) $(BUILD_DIR) 74 | @echo "${RESET}" 75 | 76 | build: $(TARGET) 77 | 78 | $(TARGET): clean $(OBJS) 79 | @$(MKDIR_P) $(dir $@) 80 | @echo "${YELLOW}Linking -> ${BLUE}$@${RESET}" 81 | @$(LD) $(KERNEL_LDFLAGS) $(LDFLAGS) -nostdlib $(OBJS) -o $(TARGET) 82 | ifndef grub 83 | @echo "Installing grub requirements" 84 | ifdef apt 85 | @sudo apt-get install grub-common xorriso grub-pc-bin 86 | endif #apt 87 | ifdef pacman 88 | @sudo pacman -S grub 89 | endif #pacman 90 | endif #grub 91 | @grub-file --is-x86-multiboot $(TARGET) 92 | @$(MKDIR_P) $(GRUB_DIR) $(ISO_DIR) 93 | @cp config/grub.cfg $(GRUB_DIR)/ 94 | 95 | $(OBJ_DIR)/%.s.o: %.s 96 | @$(MKDIR_P) $(dir $@) 97 | @echo "${YELLOW}AS $< -> ${BLUE}$@${RESET}" 98 | @$(AS) $(ASFLAGS) $< -o $@ 99 | 100 | $(OBJ_DIR)/%.asm.o: %.asm 101 | @$(MKDIR_P) $(dir $@) 102 | @echo "${YELLOW}NASM $< -> ${BLUE}$@${RESET}" 103 | @$(NASM) $(NASMFLAGS) $< -o $@ 104 | 105 | $(OBJ_DIR)/%.c.o: %.c 106 | @$(MKDIR_P) $(dir $@) 107 | @echo "${YELLOW}CC $< -> ${BLUE}$@${RESET}" 108 | @$(CC) $(CFLAGS) -c $< -o $@ 109 | 110 | $(OBJ_DIR)/%.cxx.o: %.cpp 111 | @$(MKDIR_P) $(dir $@) 112 | @echo "${YELLOW}CXX $< -> ${BLUE}$@${RESET}" 113 | @$(CXX) $(CFLAGS) -c $< -o $@ 114 | 115 | run: 116 | qemu-system-x86_64 -kernel build/boot/TinyKernel.elf -append "root=/dev/sda console=ttyS0" -serial stdio -m 256M 117 | 118 | run-debug: 119 | qemu-system-x86_64 -kernel build/boot/TinyKernel.elf -append "root=/dev/sda console=ttyS0" -serial stdio -m 256M -S -s 120 | 121 | run-iso: 122 | qemu-system-x86_64 -device sb16 -cdrom $(ISO_DIR)/$(ISO) -serial stdio -m 256M 123 | 124 | run-iso-debug: 125 | qemu-system-x86_64 -device sb16 -cdrom $(ISO_DIR)/$(ISO) -serial stdio -m 256M -S -s 126 | 127 | .PHONY: clean 128 | clean: 129 | @$(RM) -r $(BUILD_DIR) 130 | 131 | install-toolchain: 132 | @rm -rf $(CROSS_PREFIX) 133 | @echo "${PURPLE}========================${RESET}" 134 | @echo "${PURPLE}=${RESET} Installing toolchain ${PURPLE}=${RESET}" 135 | @echo "${PURPLE}========================${RESET}" 136 | @echo 137 | git clone https://github.com/TinyKern/toolchain.git $(CROSS_PREFIX) 138 | @echo 139 | @echo "${PURPLE}========================${RESET}" 140 | @echo 141 | @echo "Toolchain installed to ${LIGHT_PURPLE}$(CROSS_PREFIX)${RESET}" 142 | @echo "run ${LIGHT_PURPLE}'bash install.sh'${RESET} in ${LIGHT_PURPLE}$(CROSS_PREFIX)${RESET} to build the toolchain" 143 | 144 | git-sizes: 145 | @git ls-tree -r -t -l --full-name HEAD | sort -n -k 4 | tail -n 10 146 | 147 | info: 148 | @echo "========================" 149 | @echo "= TinyKernel info =" 150 | @echo "========================" 151 | @echo 152 | @echo "${PURPLE}Build directory${RESET}: $(BUILD_DIR)" 153 | @echo "${PURPLE}Build target${RESET}: $(TARGET)" 154 | @echo "${PURPLE}Build flags${RESET}: $(BUILD_DEFS)" 155 | @echo "${PURPLE}Build includes${RESET}: $(INC_FLAGS)" 156 | @echo "${PURPLE}Build libraries${RESET}: $(LIB_FLAGS)" 157 | @echo "${PURPLE}Build linker flags${RESET}: $(LDFLAGS)" 158 | @echo "${PURPLE}Build kernel linker flags${RESET}: $(KERNEL_LDFLAGS)" 159 | @echo "${PURPLE}Build C flags${RESET}: $(CFLAGS)" 160 | @echo "${PURPLE}Build C++ flags${RESET}: $(CXXFLAGS)" 161 | @echo "${PURPLE}Build AS flags${RESET}: $(ASFLAGS)" 162 | @echo "${PURPLE}Build NASM flags${RESET}: $(NASMFLAGS)" 163 | @echo "${PURPLE}Build LD flags${RESET}: $(LDFLAGS)" 164 | 165 | 166 | .PHONY: clean todos todolist 167 | todolist: todos 168 | todos: 169 | @echo "=============" 170 | @echo "= TODO List =" 171 | @echo "=============" 172 | -@for file in $(ALLFILES:Makefile=); do fgrep -H -n -e TODO -e FIXME $$file; done; true 173 | 174 | backup: clean 175 | @echo "====================" 176 | @echo "= Backing up files =" 177 | @echo "====================" 178 | @tar cf - ../$(CURR_DIR) | 7za a -si ../$(BACKUP_DIR)/$(CURR_DIR).$(TODAY)_`date +%H%M`.tar.7z 179 | 180 | MKDIR_P ?= mkdir -p 181 | -------------------------------------------------------------------------------- /src/kernel/kernel.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file kernel.c 3 | * @author Owen Boreham (owenkadeboreham@gmail.com) 4 | * @version 0.1.9 5 | * @date 2021-07-06 6 | * 7 | * @copyright Copyright (c) 2021 TinyKernel 8 | * This file is part of TinyKernel which is released 9 | * under Apache License 2.0. See file LICENSE or go 10 | * to https://www.apache.org/licenses/LICENSE-2.0 for 11 | * full license details. 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | void kernel_entry(); 39 | 40 | void input() 41 | { 42 | char ch = 0; 43 | do 44 | { 45 | char keycode = get_input_keycode(); 46 | if (keycode == KEY_ENTER) 47 | { 48 | vga_putchar('\n'); 49 | } 50 | else 51 | { 52 | ch = get_ascii_char(keycode); 53 | vga_putchar(ch); 54 | } 55 | sleep(0x03FFFFFF); 56 | } while (ch > 0); 57 | } 58 | 59 | bool readKey(char key) 60 | { 61 | char keycode = 0; 62 | do 63 | { 64 | keycode = get_input_keycode(); 65 | } while (keycode != key); 66 | return true; 67 | } 68 | 69 | typedef void (*constructor)(); 70 | extern constructor *start_ctors; 71 | extern constructor *end_ctors; 72 | extern void call_constructors() 73 | { 74 | for (constructor *i = start_ctors; 75 | i != end_ctors; 76 | i++) 77 | { 78 | (*i)(); 79 | } 80 | } 81 | 82 | void loading_bar(int x, int y, int len, char* message, uint8_t color) 83 | { 84 | int i = 0; 85 | 86 | set_buffer_position((x - (len / 2)), y - 1); 87 | kprintf(message); 88 | 89 | x -= (len / 2); 90 | for (i = 0; i < len; i++) 91 | { 92 | draw(x, y, color); 93 | sleep(15000000); 94 | x += 1; 95 | } 96 | sleep(200000000); 97 | clear_screen(); 98 | } 99 | 100 | long startup_time; 101 | static void time_init(void) 102 | { 103 | struct tm time; 104 | 105 | do { 106 | time.tm_sec = READ_CMOS(0); 107 | time.tm_min = READ_CMOS(2); 108 | time.tm_hour = READ_CMOS(4); 109 | time.tm_mday = READ_CMOS(7); 110 | time.tm_mon = READ_CMOS(8) - 1; 111 | time.tm_year = READ_CMOS(9); 112 | } while (time.tm_sec != READ_CMOS(0)); 113 | 114 | BCD_TO_BIN(time.tm_sec); 115 | BCD_TO_BIN(time.tm_min); 116 | BCD_TO_BIN(time.tm_hour); 117 | BCD_TO_BIN(time.tm_mday); 118 | BCD_TO_BIN(time.tm_mon); 119 | BCD_TO_BIN(time.tm_year); 120 | 121 | startup_time = mktime(&time); 122 | } 123 | #define CURRENT_TIME (startup_time + 0/100) 124 | 125 | void kernel_entry(multiboot_info_t *mbi, uint32_t magic) 126 | { 127 | // Initialise the kernel since interupts are not enabled 128 | gdt_init(); /* Initialise the global descriptor table */ 129 | idt_init(); /* Initialise the interrupt descriptor table */ 130 | irq_init(); /* Initialise the interrupt request handler */ 131 | vga_init(); /* Initialise the VGA driver */ 132 | acpi_init(); /* Initialise the ACPI driver */ 133 | time_init(); /* Initialise the time driver */ 134 | heap_init(0x100000, 0x100000); /* Initialise the heap */ 135 | keyboard_init(); /* Initialise the keyboard driver */ 136 | pit_init(1000); /* Initialise the PIT driver */ 137 | rtc_init(); /* Initialise the RTC driver */ 138 | 139 | switch (magic) 140 | { 141 | case MULTIBOOT_BOOTLOADER_MAGIC: 142 | break; 143 | case MULTIBOOT_BOOTLOADER_MAGIC_S: 144 | break; 145 | default: 146 | kpanic(ERRNO_KERNEL_INVALID_MAGIC, "Invalid magic number"); 147 | } 148 | 149 | multiboot_uint32_t checksum = -(mbi->flags + magic); 150 | 151 | qemu_info("Version: %s\r\n", KERNEL_VERSION); 152 | qemu_info("Compiler: %s - %u\r\n", COMPILER_NAME, COMPILER_VERSION); 153 | qemu_info("Architecture: %s\r\n", __BUILD_ARCH__); 154 | qemu_info("Build: %s\r\n", __BUILD_DATE__); 155 | qemu_info("magic x: %x\n", magic); 156 | qemu_info("magic u: %u\n", magic); 157 | qemu_dbg("current date and time: %s\r\n", rtc_datetime_string(rtc_read_datetime)); 158 | qemu_info("Multiboot flags: %x\n", mbi->flags); 159 | qemu_info("Multiboot boot_device: %x\n", mbi->boot_device); 160 | qemu_info("Multiboot cmdline: %x\n", mbi->cmdline); 161 | qemu_info("Multiboot mmap_length: %u\n", mbi->mmap_length); 162 | qemu_info("Multiboot mmap_addr: %x\n", mbi->mmap_addr); 163 | qemu_info("Multiboot mem_lower: %x\n", mbi->mem_lower); 164 | qemu_info("Multiboot mem_upper: %x\n", mbi->mem_upper); 165 | qemu_info("Multiboot config_table: %x\n", mbi->config_table); 166 | qemu_info("Multiboot drives_length: %u\n", mbi->drives_length); 167 | qemu_info("Multiboot drives_addr: %x\n", mbi->drives_addr); 168 | qemu_info("Multiboot modules_count: %u\n", mbi->mods_count); 169 | qemu_info("Multiboot checksum: %x\n", checksum); 170 | pci_enum_bus(); 171 | 172 | disable_cursor(); /* Disable the cursor */ 173 | clear_screen(); /* Clear the screen */ 174 | 175 | char* loading_message = "TinyKernel Booting"; 176 | loading_bar(VGA_COLS / 2, VGA_ROWS / 2, strlen(loading_message), loading_message, 0xff); 177 | 178 | qemu_success("Kernel Initialization Complete\r\n"); 179 | 180 | kprintf("TinyKernel - %s\n", KERNEL_VERSION); 181 | 182 | cpuid_info(); 183 | 184 | void* kmalloc_test = kmalloc(0x10); 185 | void* kmalloc_test1 = kmalloc(0x10); 186 | void* kmalloc_test2 = kmalloc(0x10); 187 | qemu_dbg("kmalloc_test: %x\r\n", kmalloc_test); 188 | qemu_dbg("kmalloc_test1: %x\r\n", kmalloc_test1); 189 | qemu_dbg("kmalloc_test2: %x\r\n", kmalloc_test2); 190 | vga_write_string("Heap Allocation Test: --------", 35, 0); 191 | vga_write_string("[0] kmalloc: 0x10 -> 0x", 40, 1); vga_write_string(convert_to_base((uint64_t)kmalloc_test, 16), 63, 1); 192 | vga_write_string("[1] kmalloc: 0x10 -> 0x", 40, 2); vga_write_string(convert_to_base((uint64_t)kmalloc_test1, 16), 63, 2); 193 | vga_write_string("[2] kmalloc: 0x10 -> 0x", 40, 3); vga_write_string(convert_to_base((uint64_t)kmalloc_test2, 16), 63, 3); 194 | 195 | qemu_dbg("free\r\n"); 196 | kfree(kmalloc_test); 197 | kfree(kmalloc_test1); 198 | kfree(kmalloc_test2); 199 | qemu_dbg("kmalloc_test: %x\r\n", kmalloc_test); 200 | qemu_dbg("kmalloc_test1: %x\r\n", kmalloc_test1); 201 | qemu_dbg("kmalloc_test2: %x\r\n", kmalloc_test2); 202 | 203 | void* kmalloc_test3 = kmalloc(0x10); 204 | void* kmalloc_test4 = kmalloc(0x10); 205 | void* kmalloc_test5 = kmalloc(0x10); 206 | qemu_dbg("kmalloc_test3: %x\r\n", kmalloc_test3); 207 | qemu_dbg("kmalloc_test4: %x\r\n", kmalloc_test4); 208 | qemu_dbg("kmalloc_test5: %x\r\n", kmalloc_test5); 209 | vga_write_string("Heap Free Test: --------", 35, 4); 210 | vga_write_string("[3] kmalloc: 0x10 -> 0x", 40, 5); vga_write_string(convert_to_base((uint64_t)kmalloc_test3, 16), 63, 5); 211 | vga_write_string("[4] kmalloc: 0x10 -> 0x", 40, 6); vga_write_string(convert_to_base((uint64_t)kmalloc_test4, 16), 63, 6); 212 | vga_write_string("[5] kmalloc: 0x10 -> 0x", 40, 7); vga_write_string(convert_to_base((uint64_t)kmalloc_test5, 16), 63, 7); 213 | 214 | kprintf("\n\tPress enter to shut down\n"); 215 | while (true) 216 | { 217 | if (readKey(KEY_ENTER) == true) 218 | { 219 | qemu_success("Shutting Down\r\n"); 220 | sys_shutdown(); 221 | } 222 | } 223 | 224 | sti(); 225 | } 226 | -------------------------------------------------------------------------------- /src/arch/i386/acpi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | dword_t *SMI_CMD; 5 | byte ACPI_ENABLE; 6 | byte ACPI_DISABLE; 7 | dword_t *PM1a_CNT; 8 | dword_t *PM1b_CNT; 9 | word_t SLP_TYPa; 10 | word_t SLP_TYPb; 11 | word_t SLP_EN; 12 | word_t SCI_EN; 13 | byte PM1_CNT_LEN; 14 | 15 | // Check if the given address has a valid header 16 | static uint32_t *acpi_check_rsd_ptr(uint32_t *ptr) 17 | { 18 | char *sig = "RSD PTR "; 19 | struct RSDPtr *rsdp = (struct RSDPtr *)ptr; 20 | byte *bptr; 21 | byte check = 0; 22 | size_t i; 23 | 24 | if (memcmp(sig, rsdp, 8) == 0) 25 | { 26 | // Check checksum of the header 27 | bptr = (byte *) ptr; 28 | for (i = 0; i < sizeof(struct RSDPtr); i++) 29 | { 30 | check += *bptr; 31 | bptr++; 32 | } 33 | 34 | // Found a valid header 35 | if (check == 0) 36 | return (uint32_t *) rsdp->rsdt_address; 37 | } 38 | 39 | return NULL; 40 | } 41 | 42 | // Finds the acpi header and returns a pointer to it 43 | uint32_t *acpi_get_rsd_ptr(void) 44 | { 45 | uint32_t *addr; 46 | uint32_t *rsdp; 47 | 48 | // Search below 1MB for an RSDP signature 49 | for (addr = (uint32_t *) 0x000E0000; (int) addr < 0x00100000; addr += 0x10/sizeof(addr)) 50 | { 51 | rsdp = acpi_check_rsd_ptr(addr); 52 | if (rsdp != NULL) 53 | return rsdp; 54 | } 55 | 56 | // At address 0x40:0x0E is the RM segment of the ebda 57 | int ebda = *((short *) 0x40E); // EBDA address 58 | ebda = ebda*0x10 & 0x000FFFFF; // Convert to linear address 59 | 60 | // Search extended BIOS data area for the Root System Description Pointer signature 61 | for (addr = (uint32_t *) ebda; (int) addr < ebda + 1024; addr += 0x10/sizeof(addr)) 62 | { 63 | rsdp = acpi_check_rsd_ptr(addr); 64 | if (rsdp != NULL) 65 | return rsdp; 66 | } 67 | 68 | return NULL; 69 | } 70 | 71 | // Checks for a given header and validates checksum 72 | static bool acpi_check_header(uint32_t *ptr, char *sig) 73 | { 74 | if (memcmp(ptr, sig, 4) == 0) 75 | { 76 | char *check_ptr = (char *) ptr; 77 | int len = *(check_ptr + 1); 78 | char check = 0; 79 | while (0 < len--) 80 | { 81 | check += *check_ptr; 82 | check_ptr++; 83 | } 84 | 85 | if (check == 0) 86 | return true; 87 | } 88 | 89 | return false; 90 | } 91 | 92 | int acpi_enable(void) 93 | { 94 | // Check if acpi is enabled 95 | if ((inw((uint32_t) PM1a_CNT) &SCI_EN) == 0) 96 | { 97 | // check if acpi is supported 98 | if (SMI_CMD != 0 && ACPI_ENABLE != 0) 99 | { 100 | // Enable acpi 101 | outb((uint32_t) SMI_CMD, ACPI_ENABLE); // Send acpi enable command 102 | 103 | // Wait for acpi to be enabled 104 | int i; 105 | for (i = 0; i < 300; i++) 106 | { 107 | if ((inw((uint32_t) PM1a_CNT) &SCI_EN) == 1) 108 | break; 109 | sleep(10); 110 | } 111 | 112 | if (PM1b_CNT != 0) 113 | { 114 | for (; i < 300; i++) 115 | { 116 | if ((inw((uint32_t) PM1b_CNT) &SCI_EN) == 1) 117 | break; 118 | sleep(10); 119 | } 120 | } 121 | 122 | if (i < 300) 123 | { 124 | qemu_success("ACPI enabled\n"); 125 | return 0; 126 | } 127 | else 128 | { 129 | qemu_error("ACPI failed to enable\n"); 130 | return -1; 131 | } 132 | } 133 | else 134 | { 135 | qemu_error("ACPI not supported\n"); 136 | return -1; 137 | } 138 | } 139 | else 140 | { 141 | qemu_info("ACPI already enabled\n"); 142 | return 0; 143 | } 144 | } 145 | 146 | /** 147 | * This function initializes the ACPI subsystem. It will search for the 148 | * RSDP signature and load the RSDT tables. It will also enable the 149 | * ACPI subsystem. 150 | * More information can be found in the ACPI specification. 151 | * 152 | * @return int 0 on success, -1 on failure 153 | */ 154 | int acpi_init(void) 155 | { 156 | uint32_t *ptr = acpi_get_rsd_ptr(); 157 | 158 | // Check if address is valid ( if acpi is supported ) 159 | if (ptr != NULL && acpi_check_header(ptr, "RSDT") == 0) 160 | { 161 | // the RSDT contains an unknown number of pointers to other tables 162 | // we need to read the number of pointers from the header 163 | int entries = *(ptr + 1); 164 | entries = (entries - 36) / 4; 165 | ptr += 36/4; // Skip header info 166 | 167 | // Loop through all the entries and load the tables 168 | while (0 < entries--) 169 | { 170 | // Check if the desired table has been reached 171 | if (acpi_check_header((uint32_t *) *ptr, "FACP") == 0) 172 | { 173 | // Found the FACP table 174 | entries = -2; 175 | struct FACP *facp = (struct FACP *) *ptr; 176 | if (acpi_check_header((uint32_t *) facp->dsdt_address, "DSDT") == 0) 177 | { 178 | // Search the \_S5 package in the DSDT 179 | char *S5addr = (char *) facp->dsdt_address + 36; // Skip header 180 | int dsdt_len = *(facp->dsdt_address + 1) - 36; 181 | 182 | while (0 < dsdt_len--) 183 | { 184 | if (memcmp(S5addr, "_S5_", 4) == 0) 185 | break; 186 | S5addr++; 187 | } 188 | 189 | // Check is \_S5 was found 190 | if (dsdt_len > 0) 191 | { 192 | // Check for valid AML structure 193 | if ((*(S5addr-1) == 0x08 || (*(S5addr-2) == 0x08 && *(S5addr-1) == '\\')) 194 | && *(S5addr+4) == 0x12 ) 195 | { 196 | S5addr += 5; // Skip the \_S5 package 197 | S5addr += ((*S5addr & 0xC0) >> 6) + 2; // calculate the length of the package 198 | 199 | // Check if the \_S5 package is valid 200 | if (*S5addr == 0x0A) 201 | S5addr++; // skip the byteprefix 202 | SLP_TYPa = *(S5addr) << 10; 203 | S5addr++; 204 | 205 | if (*S5addr == 0x0A) 206 | S5addr++; // skip the byteprefix 207 | SLP_TYPb = *(S5addr) << 10; 208 | 209 | SMI_CMD = facp->SMI_CMD; 210 | 211 | // Enable acpi 212 | ACPI_ENABLE = facp->ACPI_ENABLE; 213 | ACPI_DISABLE = facp->ACPI_DISABLE; 214 | 215 | PM1a_CNT = facp->PM1a_CNT_BLK; 216 | PM1b_CNT = facp->PM1b_CNT_BLK; 217 | 218 | PM1_CNT_LEN = facp->PM1_CNT_LEN; 219 | 220 | SLP_EN = 1 << 13; 221 | SCI_EN = 1; 222 | 223 | return 0; 224 | } 225 | else 226 | { 227 | qemu_error("Invalid DSDT, \\_S5 parse error\n"); 228 | } 229 | } 230 | else 231 | { 232 | qemu_error("Invalid DSDT, \\_S5 not present\n"); 233 | } 234 | } 235 | else 236 | { 237 | qemu_error("Invalid DSDT\n"); 238 | } 239 | } 240 | ptr++; 241 | } 242 | 243 | qemu_error("FACP not found\n"); 244 | } 245 | else 246 | { 247 | qemu_warning("ACPI not found\n"); 248 | } 249 | 250 | return -1; 251 | } 252 | 253 | void acpi_power_off(void) 254 | { 255 | // SCI_EN is set to 1 if acpi shutdown is possible 256 | if (SCI_EN == 0) 257 | return; 258 | 259 | acpi_enable(); 260 | 261 | // send the shutdown command 262 | outw((uint32_t) PM1a_CNT, SLP_TYPa | SLP_EN); 263 | if (PM1b_CNT != 0) 264 | outw((uint32_t) PM1b_CNT, SLP_TYPb | SLP_EN); 265 | 266 | qemu_error("ACPI shutdown failed\n"); 267 | } 268 | -------------------------------------------------------------------------------- /include/sys/stddef.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 1989-2020 Free Software Foundation, Inc. 2 | 3 | This file is part of GCC. 4 | 5 | GCC is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 3, or (at your option) 8 | any later version. 9 | 10 | GCC is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | Under Section 7 of GPL version 3, you are granted additional 16 | permissions described in the GCC Runtime Library Exception, version 17 | 3.1, as published by the Free Software Foundation. 18 | 19 | You should have received a copy of the GNU General Public License and 20 | a copy of the GCC Runtime Library Exception along with this program; 21 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 22 | . */ 23 | 24 | /* 25 | * ISO C Standard: 7.17 Common definitions 26 | */ 27 | #if (!defined(_STDDEF_H) && !defined(_STDDEF_H_) && !defined(_ANSI_STDDEF_H) \ 28 | && !defined(__STDDEF_H__)) \ 29 | || defined(__need_wchar_t) || defined(__need_size_t) \ 30 | || defined(__need_ptrdiff_t) || defined(__need_NULL) \ 31 | || defined(__need_wint_t) 32 | 33 | /* Any one of these symbols __need_* means that GNU libc 34 | wants us just to define one data type. So don't define 35 | the symbols that indicate this file's entire job has been done. */ 36 | #if (!defined(__need_wchar_t) && !defined(__need_size_t) \ 37 | && !defined(__need_ptrdiff_t) && !defined(__need_NULL) \ 38 | && !defined(__need_wint_t)) 39 | #define _STDDEF_H 40 | #define _STDDEF_H_ 41 | /* snaroff@next.com says the NeXT needs this. */ 42 | #define _ANSI_STDDEF_H 43 | #endif 44 | 45 | #ifndef __sys_stdtypes_h 46 | /* This avoids lossage on SunOS but only if stdtypes.h comes first. 47 | There's no way to win with the other order! Sun lossage. */ 48 | 49 | /* Sequent's header files use _PTRDIFF_T_ in some conflicting way. 50 | Just ignore it. */ 51 | #if defined (__sequent__) && defined (_PTRDIFF_T_) 52 | #undef _PTRDIFF_T_ 53 | #endif 54 | 55 | /* On VxWorks, may have defined macros like 56 | _TYPE_size_t which will typedef size_t. fixincludes patched the 57 | vxTypesBase.h so that this macro is only defined if _GCC_SIZE_T is 58 | not defined, and so that defining this macro defines _GCC_SIZE_T. 59 | If we find that the macros are still defined at this point, we must 60 | invoke them so that the type is defined as expected. */ 61 | #if defined (_TYPE_ptrdiff_t) && (defined (__need_ptrdiff_t) || defined (_STDDEF_H_)) 62 | _TYPE_ptrdiff_t; 63 | #undef _TYPE_ptrdiff_t 64 | #endif 65 | #if defined (_TYPE_size_t) && (defined (__need_size_t) || defined (_STDDEF_H_)) 66 | _TYPE_size_t; 67 | #undef _TYPE_size_t 68 | #endif 69 | #if defined (_TYPE_wchar_t) && (defined (__need_wchar_t) || defined (_STDDEF_H_)) 70 | _TYPE_wchar_t; 71 | #undef _TYPE_wchar_t 72 | #endif 73 | 74 | /* In case nobody has defined these types, but we aren't running under 75 | GCC 2.00, make sure that __PTRDIFF_TYPE__, __SIZE_TYPE__, and 76 | __WCHAR_TYPE__ have reasonable values. This can happen if the 77 | parts of GCC is compiled by an older compiler, that actually 78 | include gstddef.h, such as collect2. */ 79 | 80 | /* Signed type of difference of two pointers. */ 81 | 82 | /* Define this type if we are doing the whole job, 83 | or if we want this type in particular. */ 84 | #if defined (_STDDEF_H) || defined (__need_ptrdiff_t) 85 | #ifndef _PTRDIFF_T /* in case has defined it. */ 86 | #ifndef _T_PTRDIFF_ 87 | #ifndef _T_PTRDIFF 88 | #ifndef __PTRDIFF_T 89 | #ifndef _PTRDIFF_T_ 90 | #ifndef _BSD_PTRDIFF_T_ 91 | #ifndef ___int_ptrdiff_t_h 92 | #ifndef _GCC_PTRDIFF_T 93 | #ifndef _PTRDIFF_T_DECLARED /* DragonFly */ 94 | #define _PTRDIFF_T 95 | #define _T_PTRDIFF_ 96 | #define _T_PTRDIFF 97 | #define __PTRDIFF_T 98 | #define _PTRDIFF_T_ 99 | #define _BSD_PTRDIFF_T_ 100 | #define ___int_ptrdiff_t_h 101 | #define _GCC_PTRDIFF_T 102 | #define _PTRDIFF_T_DECLARED 103 | #ifndef __PTRDIFF_TYPE__ 104 | #define __PTRDIFF_TYPE__ long int 105 | #endif 106 | typedef __PTRDIFF_TYPE__ ptrdiff_t; 107 | #endif /* _PTRDIFF_T_DECLARED */ 108 | #endif /* _GCC_PTRDIFF_T */ 109 | #endif /* ___int_ptrdiff_t_h */ 110 | #endif /* _BSD_PTRDIFF_T_ */ 111 | #endif /* _PTRDIFF_T_ */ 112 | #endif /* __PTRDIFF_T */ 113 | #endif /* _T_PTRDIFF */ 114 | #endif /* _T_PTRDIFF_ */ 115 | #endif /* _PTRDIFF_T */ 116 | 117 | /* If this symbol has done its job, get rid of it. */ 118 | #undef __need_ptrdiff_t 119 | 120 | #endif /* _STDDEF_H or __need_ptrdiff_t. */ 121 | 122 | /* Unsigned type of `sizeof' something. */ 123 | 124 | /* Define this type if we are doing the whole job, 125 | or if we want this type in particular. */ 126 | #if defined (_STDDEF_H) || defined (__need_size_t) 127 | #ifndef _SIZE_T /* in case has defined it. */ 128 | #ifndef _SYS_SIZE_T_H 129 | #ifndef _T_SIZE_ 130 | #ifndef _T_SIZE 131 | #ifndef __SIZE_T 132 | #ifndef _SIZE_T_ 133 | #ifndef _BSD_SIZE_T_ 134 | #ifndef _SIZE_T_DEFINED_ 135 | #ifndef _SIZE_T_DEFINED 136 | #ifndef ___int_size_t_h 137 | #ifndef _GCC_SIZE_T 138 | #ifndef _SIZET_ 139 | #ifndef __size_t 140 | #define _SIZE_T 141 | #define _SYS_SIZE_T_H 142 | #define _T_SIZE_ 143 | #define _T_SIZE 144 | #define __SIZE_T 145 | #define _SIZE_T_ 146 | #define _BSD_SIZE_T_ 147 | #define _SIZE_T_DEFINED_ 148 | #define _SIZE_T_DEFINED 149 | #define ___int_size_t_h 150 | #define _GCC_SIZE_T 151 | #define _SIZET_ 152 | #define __size_t 153 | #ifndef __SIZE_TYPE__ 154 | #define __SIZE_TYPE__ long unsigned int 155 | #endif 156 | #if !(defined (__GNUG__) && defined (size_t)) 157 | typedef __SIZE_TYPE__ size_t; 158 | #ifdef __BEOS__ 159 | typedef long ssize_t; 160 | #endif /* __BEOS__ */ 161 | #endif /* !(defined (__GNUG__) && defined (size_t)) */ 162 | #endif /* __size_t */ 163 | #endif /* _SIZET_ */ 164 | #endif /* _GCC_SIZE_T */ 165 | #endif /* ___int_size_t_h */ 166 | #endif /* _SIZE_T_DECLARED */ 167 | #endif /* _BSD_SIZE_T_DEFINED_ */ 168 | #endif /* _SIZE_T_DEFINED */ 169 | #endif /* _SIZE_T_DEFINED_ */ 170 | #endif /* _BSD_SIZE_T_ */ 171 | #endif /* _SIZE_T_ */ 172 | #endif /* __SIZE_T */ 173 | #endif /* _T_SIZE */ 174 | #endif /* _T_SIZE_ */ 175 | #endif /* _SYS_SIZE_T_H */ 176 | #endif /* _SIZE_T */ 177 | #endif /* __SIZE_T__ */ 178 | #undef __need_size_t 179 | 180 | 181 | /* Wide character type. 182 | Locale-writers should change this as necessary to 183 | be big enough to hold unique values not between 0 and 127, 184 | and not (wchar_t) -1, for each defined multibyte character. */ 185 | 186 | /* Define this type if we are doing the whole job, 187 | or if we want this type in particular. */ 188 | #if defined (_STDDEF_H) || defined (__need_wchar_t) 189 | #ifndef _WCHAR_T 190 | #ifndef _T_WCHAR_ 191 | #ifndef _T_WCHAR 192 | #ifndef __WCHAR_T 193 | #ifndef _WCHAR_T_ 194 | #ifndef _BSD_WCHAR_T_ 195 | #ifndef _WCHAR_T_DEFINED_ 196 | #ifndef _WCHAR_T_DEFINED 197 | #ifndef _WCHAR_T_H 198 | #ifndef ___int_wchar_t_h 199 | #ifndef __INT_WCHAR_T_H 200 | #ifndef _GCC_WCHAR_T 201 | #define _WCHAR_T 202 | #define _T_WCHAR_ 203 | #define _T_WCHAR 204 | #define __WCHAR_T 205 | #define _WCHAR_T_ 206 | #define _BSD_WCHAR_T_ 207 | #define _WCHAR_T_DEFINED_ 208 | #define _WCHAR_T_DEFINED 209 | #define _WCHAR_T_H 210 | #define ___int_wchar_t_h 211 | #define __INT_WCHAR_T_H 212 | #define _GCC_WCHAR_T 213 | #define _WCHAR_T_DECLARED 214 | 215 | /* On BSD/386 1.1, at least, machine/ansi.h defines _BSD_WCHAR_T_ 216 | instead of _WCHAR_T_, and _BSD_RUNE_T_ (which, unlike the other 217 | symbols in the _FOO_T_ family, stays defined even after its 218 | corresponding type is defined). If we define wchar_t, then we 219 | must undef _WCHAR_T_; for BSD/386 1.1 (and perhaps others), if 220 | we undef _WCHAR_T_, then we must also define rune_t, since 221 | headers like runetype.h assume that if machine/ansi.h is included, 222 | and _BSD_WCHAR_T_ is not defined, then rune_t is available. 223 | machine/ansi.h says, "Note that _WCHAR_T_ and _RUNE_T_ must be of 224 | the same type." */ 225 | #ifdef _BSD_WCHAR_T_ 226 | #undef _BSD_WCHAR_T_ 227 | #ifdef _BSD_RUNE_T_ 228 | #if !defined (_ANSI_SOURCE) && !defined (_POSIX_SOURCE) 229 | typedef _BSD_RUNE_T_ rune_t; 230 | #define _BSD_WCHAR_T_DEFINED_ 231 | #define _BSD_RUNE_T_DEFINED_ /* Darwin */ 232 | #endif 233 | #endif 234 | #endif 235 | /* FreeBSD 5 can't be handled well using "traditional" logic above 236 | since it no longer defines _BSD_RUNE_T_ yet still desires to export 237 | rune_t in some cases... */ 238 | 239 | #ifndef __WCHAR_TYPE__ 240 | #define __WCHAR_TYPE__ int 241 | #endif 242 | #ifndef __cplusplus 243 | typedef __WCHAR_TYPE__ wchar_t; 244 | #endif 245 | #endif 246 | #endif 247 | #endif 248 | #endif 249 | #endif 250 | #endif 251 | #endif /* _WCHAR_T_DECLARED */ 252 | #endif /* _BSD_RUNE_T_DEFINED_ */ 253 | #endif 254 | #endif 255 | #endif 256 | #endif 257 | #endif 258 | #undef __need_wchar_t 259 | 260 | #if defined (__need_wint_t) 261 | #ifndef _WINT_T 262 | #define _WINT_T 263 | 264 | #ifndef __WINT_TYPE__ 265 | #define __WINT_TYPE__ unsigned int 266 | #endif 267 | typedef __WINT_TYPE__ wint_t; 268 | #endif 269 | #undef __need_wint_t 270 | #endif 271 | 272 | /* A null pointer constant. */ 273 | 274 | #if defined (_STDDEF_H) || defined (__need_NULL) 275 | #undef NULL /* in case has defined it. */ 276 | #ifdef __GNUG__ 277 | #define NULL __null 278 | #else /* G++ */ 279 | #ifndef __cplusplus 280 | #define NULL ((void *)0) 281 | #else /* C++ */ 282 | #define NULL 0 283 | #endif /* C++ */ 284 | #endif /* G++ */ 285 | #endif /* NULL not defined and or need NULL. */ 286 | #undef __need_NULL 287 | 288 | #ifdef _STDDEF_H 289 | 290 | /* Offset of member MEMBER in a struct of type TYPE. */ 291 | #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER) 292 | 293 | #if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \ 294 | || (defined(__cplusplus) && __cplusplus >= 201103L) 295 | #ifndef _GCC_MAX_ALIGN_T 296 | #define _GCC_MAX_ALIGN_T 297 | /* Type whose alignment is supported in every context and is at least 298 | as great as that of any standard type not using alignment 299 | specifiers. */ 300 | typedef struct { 301 | long long __max_align_ll __attribute__((__aligned__(__alignof__(long long)))); 302 | long double __max_align_ld __attribute__((__aligned__(__alignof__(long double)))); 303 | /* _Float128 is defined as a basic type, so max_align_t must be 304 | sufficiently aligned for it. This code must work in C++, so we 305 | use __float128 here; that is only available on some 306 | architectures, but only on i386 is extra alignment needed for 307 | __float128. */ 308 | #ifdef __i386__ 309 | __float128 __max_align_f128 __attribute__((__aligned__(__alignof(__float128)))); 310 | #endif 311 | } max_align_t; 312 | #endif 313 | #endif /* C11 or C++11. */ 314 | 315 | #if defined(__cplusplus) && __cplusplus >= 201103L 316 | #ifndef _GXX_NULLPTR_T 317 | #define _GXX_NULLPTR_T 318 | typedef decltype(nullptr) nullptr_t; 319 | #endif 320 | #endif /* C++11. */ 321 | 322 | #endif /* _STDDEF_H was defined this time */ --------------------------------------------------------------------------------