├── kernel ├── initrd │ ├── file2.txt │ ├── file.txt │ ├── initrd.h │ └── initrd.c ├── cpu │ ├── load_idt.asm │ ├── idt.h │ ├── load_gdt.asm │ ├── gdt.h │ ├── idt.c │ ├── irq.h │ ├── isr.h │ ├── gdt.c │ ├── irq.c │ ├── irq_asm.asm │ ├── isr.c │ └── isr_asm.asm ├── include │ ├── kernel │ │ ├── power.h │ │ ├── nmi.h │ │ ├── printm.h │ │ ├── pit.h │ │ ├── panic.h │ │ ├── framebuffer.h │ │ ├── io.h │ │ ├── pcspkr.h │ │ ├── serial.h │ │ ├── rtc.h │ │ ├── device.h │ │ ├── keyboard.h │ │ ├── tarfs.h │ │ ├── task.h │ │ ├── vga.h │ │ ├── floppy.h │ │ ├── elf.h │ │ ├── ordered_array.h │ │ ├── paging.h │ │ ├── kheap.h │ │ └── vfs.h │ ├── stdbool.h │ ├── stdnoreturn.h │ ├── assert.h │ ├── stddef.h │ ├── stdlib.h │ ├── stdarg.h │ ├── errno.h │ ├── ctype.h │ ├── stdio.h │ └── string.h ├── kernel │ ├── nmi.c │ ├── power │ │ └── reboot.c │ ├── io.c │ ├── printm │ │ └── printm.c │ ├── irq │ │ ├── irq_enable.c │ │ └── irq_disable.c │ ├── usermode.c │ ├── process.asm │ ├── elf.c │ ├── device.c │ ├── ordered_array.c │ ├── panic.c │ ├── task.c │ └── vsprintf.c ├── fs │ ├── mount.c │ ├── ls.c │ ├── tarfs │ │ └── tarfs.c │ └── vfs │ │ └── vfs.c ├── arch │ └── i386 │ │ ├── link.ld │ │ └── boot.asm ├── drivers │ ├── vga │ │ ├── framebuffer.c │ │ └── vga.c │ ├── pit │ │ └── pit.c │ ├── sound │ │ └── pcspkr.c │ ├── serial │ │ └── serial.c │ ├── rtc │ │ └── rtc.c │ ├── keyboard │ │ └── keyboard.c │ └── floppy │ │ └── floppy.c ├── init │ ├── main.c │ └── multiboot.h └── mm │ ├── paging.c │ └── kheap.c ├── docs ├── user-guide │ ├── Terminal.md │ └── User-Guide.md ├── Formatting-the-code.md └── Building.md ├── lib └── libc │ ├── errno │ └── errno.c │ ├── stdlib │ ├── _Exit.c │ ├── abs.c │ ├── exit.c │ ├── labs.c │ ├── llabs.c │ └── abort.c │ ├── ctype │ ├── isblank.c │ ├── isgraph.c │ ├── islower.c │ ├── isprint.c │ ├── isupper.c │ ├── isalnum.c │ ├── isalpha.c │ ├── isdigit.c │ ├── iscntrl.c │ ├── tolower.c │ ├── toupper.c │ ├── ispunct.c │ ├── isxdigit.c │ └── isspace.c │ ├── string │ ├── strcpy.c │ ├── strlen.c │ ├── strchr.c │ ├── strcmp.c │ ├── memcpy.c │ ├── memset.c │ ├── memsetw.c │ └── memcmp.c │ └── stdio │ └── printf.c ├── toolchain ├── .clang-format └── build_toolchain.sh ├── scripts ├── install_deps.sh ├── format_code.sh ├── run.sh ├── gen_config.sh ├── Makefile.build └── gen_initrd.c ├── screenshots └── Screenshot-0.11-rc2.png ├── user ├── commands │ ├── hello.c │ ├── version.c │ ├── whoami.c │ ├── help.c │ ├── echo.c │ ├── commands.h │ ├── uname.c │ └── cat.c └── terminal │ ├── terminal.h │ └── terminal.c ├── .gitignore ├── grub.cfg ├── MAINTAINERS ├── Makefile ├── .github ├── workflows │ ├── stale.yml │ └── build.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .clang-format ├── SECURITY.md ├── README.md └── LICENSE /kernel/initrd/file2.txt: -------------------------------------------------------------------------------- 1 | Initrd 2 | -------------------------------------------------------------------------------- /kernel/initrd/file.txt: -------------------------------------------------------------------------------- 1 | Hello World! 2 | -------------------------------------------------------------------------------- /docs/user-guide/Terminal.md: -------------------------------------------------------------------------------- 1 | # The Terminal 2 | -------------------------------------------------------------------------------- /lib/libc/errno/errno.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int errno; 4 | -------------------------------------------------------------------------------- /toolchain/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | DisableFormat: true 3 | SortIncludes: false 4 | ... 5 | -------------------------------------------------------------------------------- /lib/libc/stdlib/_Exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void _Exit(int status) { 4 | // TODO 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/ctype/isblank.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isblank(int ch) { 4 | return ch == ' '; 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/stdlib/abs.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int abs(int j) { 4 | return (j < 0) ? -j : j; 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/stdlib/exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void exit(int status) { 4 | _Exit(status); 5 | } 6 | -------------------------------------------------------------------------------- /scripts/install_deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sudo apt-get update 4 | sudo apt-get install nasm mtools xorriso 5 | -------------------------------------------------------------------------------- /kernel/cpu/load_idt.asm: -------------------------------------------------------------------------------- 1 | global idt_load 2 | extern idt_ptr 3 | 4 | idt_load: 5 | lidt [idt_ptr] 6 | ret 7 | -------------------------------------------------------------------------------- /lib/libc/ctype/isgraph.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isgraph(int ch) { 4 | return ch >= 0x21 && ch <= 0x7E; 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/ctype/islower.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int islower(int ch) { 4 | return ch >= 'a' && ch <= 'z'; 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/ctype/isprint.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isprint(int ch) { 4 | return ch >= 0x20 && ch <= 0x7E; 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/ctype/isupper.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isupper(int ch) { 4 | return ch >= 'A' && ch <= 'Z'; 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/stdlib/labs.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | long int labs(long int j) { 4 | return (j < 0) ? -j : j; 5 | } 6 | -------------------------------------------------------------------------------- /scripts/format_code.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | find . -name "*.c" -o -name "*.h" | sed 's| |\\ |g' | xargs clang-format -i 4 | -------------------------------------------------------------------------------- /lib/libc/ctype/isalnum.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isalnum(int ch) { 4 | return isdigit(ch) || isalpha(ch); 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/ctype/isalpha.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isalpha(int ch) { 4 | return islower(ch) || isupper(ch); 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/ctype/isdigit.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isdigit(int ch) { 4 | return ch >= MIN_DIGIT && ch <= MAX_DIGIT; 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/stdlib/llabs.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | long long int llabs(long long int j) { 4 | return (j < 0) ? -j : j; 5 | } 6 | -------------------------------------------------------------------------------- /screenshots/Screenshot-0.11-rc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Platypus-Tech/platypus-os/HEAD/screenshots/Screenshot-0.11-rc2.png -------------------------------------------------------------------------------- /lib/libc/ctype/iscntrl.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int iscntrl(int ch) { 4 | return (unsigned int)ch < 0x20 || ch == 0x7F; 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/ctype/tolower.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int tolower(int ch) { 4 | return isupper(ch) ? 'a' + (ch - 'A') : ch; 5 | } 6 | -------------------------------------------------------------------------------- /lib/libc/ctype/toupper.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int toupper(int ch) { 4 | return islower(ch) ? 'A' + (ch - 'a') : ch; 5 | } 6 | -------------------------------------------------------------------------------- /kernel/include/kernel/power.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_POWER_H 2 | #define _KERNEL_POWER_H 3 | 4 | void reboot(); 5 | 6 | #endif //_KERNEL_POWER_H 7 | -------------------------------------------------------------------------------- /lib/libc/ctype/ispunct.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int ispunct(int ch) { 4 | return isprint(ch) && !isspace(ch) && !isalnum(ch); 5 | } 6 | -------------------------------------------------------------------------------- /user/commands/hello.c: -------------------------------------------------------------------------------- 1 | #include "commands.h" 2 | #include 3 | 4 | void hello() { 5 | writestr("Hello to you too?\n"); 6 | } 7 | -------------------------------------------------------------------------------- /user/commands/version.c: -------------------------------------------------------------------------------- 1 | #include "commands.h" 2 | #include 3 | 4 | void version() { 5 | writestr("Version 0.11-rc3\n"); 6 | } 7 | -------------------------------------------------------------------------------- /kernel/include/kernel/nmi.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_NMI_H 2 | #define _KERNEL_NMI_H 3 | 4 | void nmi_enable(); 5 | void nmi_disable(); 6 | 7 | #endif //_KERNEL_NMI_H 8 | -------------------------------------------------------------------------------- /kernel/include/kernel/printm.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_PRINTM_H 2 | #define _KERNEL_PRINTM_H 3 | 4 | void printm(const char *fmt, ...); 5 | 6 | #endif //_KERNEL_PRINTM_H 7 | -------------------------------------------------------------------------------- /kernel/include/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDBOOL_H 2 | #define _STDBOOL_H 3 | 4 | #define bool _Bool 5 | #define true 1 6 | #define false 0 7 | 8 | #endif //_STDBOOL_H 9 | -------------------------------------------------------------------------------- /scripts/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ISO_FILE="$1" 4 | FLOPPY_FILE="$2" 5 | 6 | qemu-system-x86_64 -fda $FLOPPY_FILE -serial stdio -m 256 -soundhw pcspk $ISO_FILE 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iso 2 | *.o 3 | *.a 4 | *.bin 5 | *.img 6 | *.tar 7 | *.elf 8 | scripts/gen_initrd 9 | toolchain/compiler/ 10 | isodir/ 11 | kernel/include/generated/ 12 | -------------------------------------------------------------------------------- /user/commands/whoami.c: -------------------------------------------------------------------------------- 1 | #include "commands.h" 2 | #include 3 | #include 4 | 5 | void whoami() { 6 | writestr("%s\n", CONFIG_USERNAME); 7 | } 8 | -------------------------------------------------------------------------------- /kernel/include/stdnoreturn.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDNORETURN_H 2 | #define _STDNORETURN_H 3 | 4 | #ifndef __cplusplus 5 | #define noreturn _Noreturn 6 | #endif 7 | 8 | #endif //_STDNORETURN_H 9 | -------------------------------------------------------------------------------- /lib/libc/ctype/isxdigit.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isxdigit(int ch) { 4 | return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || 5 | (ch >= 'A' && ch <= 'F'); 6 | } 7 | -------------------------------------------------------------------------------- /docs/Formatting-the-code.md: -------------------------------------------------------------------------------- 1 | # Formatting the code 2 | Before creating a pull request you need to format the code. To format the code run `./scripts/format_code.sh` from the source directory. 3 | -------------------------------------------------------------------------------- /kernel/include/kernel/pit.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_PIT_H 2 | #define _KERNEL_PIT_H 3 | 4 | void handler_pit(); 5 | void sleep_pit(int ticks); 6 | void init_pit(int hz); 7 | 8 | #endif //_KERNEL_PIT_H 9 | -------------------------------------------------------------------------------- /kernel/include/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASSERT_H 2 | #define _ASSERT_H 3 | 4 | #include 5 | 6 | #define ASSERT(a) ((a) ? (void)0 : panic_assert(__FILE__, __LINE__, #a)) 7 | 8 | #endif //_ASSERT_H 9 | -------------------------------------------------------------------------------- /kernel/include/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDDEF_H 2 | #define _STDDEF_H 3 | 4 | #define NULL ((void *)0) 5 | 6 | typedef unsigned long size_t; 7 | typedef signed long ptrdiff_t; 8 | 9 | #endif //_STDDEF_H 10 | -------------------------------------------------------------------------------- /lib/libc/stdlib/abort.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void abort() { 4 | #ifdef __KERNEL__ 5 | panic("abort()\n"); 6 | #endif 7 | 8 | while (1) { 9 | } 10 | __builtin_unreachable(); 11 | } 12 | -------------------------------------------------------------------------------- /lib/libc/string/strcpy.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | char *strcpy(char *str1, const char *str2) { 4 | char *rc = str1; 5 | 6 | while ((*str1++ = *str2++)) { 7 | } 8 | 9 | return rc; 10 | } 11 | -------------------------------------------------------------------------------- /user/terminal/terminal.h: -------------------------------------------------------------------------------- 1 | #ifndef _USER_TERMINAL_H 2 | #define _USER_TERMINAL_H 3 | 4 | void put_prompt(); 5 | void run_command(char input[], char args[]); 6 | void init_terminal(); 7 | 8 | #endif //_USER_TERMINAL_H 9 | -------------------------------------------------------------------------------- /kernel/kernel/nmi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void nmi_enable() { 5 | outp(0x70, inp(0x70) & 0x7F); 6 | } 7 | 8 | void nmi_disable() { 9 | outp(0x70, inp(0x70) | 0x80); 10 | } 11 | -------------------------------------------------------------------------------- /lib/libc/string/strlen.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | size_t strlen(const char *string) { 4 | size_t length = 0; 5 | 6 | while (string[length]) { 7 | length++; 8 | } 9 | 10 | return length; 11 | } 12 | -------------------------------------------------------------------------------- /grub.cfg: -------------------------------------------------------------------------------- 1 | set timeout=5 2 | 3 | menuentry "Platypus OS" { 4 | echo "Loading the kernel..." 5 | multiboot /boot/kernel.elf 6 | echo "Loading the initrd..." 7 | module /boot/initrd.img 8 | boot 9 | } 10 | -------------------------------------------------------------------------------- /user/commands/help.c: -------------------------------------------------------------------------------- 1 | #include "commands.h" 2 | #include 3 | 4 | void help() { 5 | writestr( 6 | "Commands - version reboot help mount ls hello playsound stopsound panic \nuname whoami cat echo\n"); 7 | } 8 | -------------------------------------------------------------------------------- /kernel/include/kernel/panic.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_PANIC_H 2 | #define _KERNEL_PANIC_H 3 | 4 | void panic(char panicmessage[]); 5 | void panic_assert(const char *filename, int line, const char *desc); 6 | 7 | #endif //_KERNEL_PANIC_H 8 | -------------------------------------------------------------------------------- /kernel/include/kernel/framebuffer.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_FRAMEBUFFER_H 2 | #define _KERNEL_FRAMEBUFFER_H 3 | 4 | void put_pixel(int pos_x, int pos_y, unsigned char color); 5 | void init_framebuffer(); 6 | 7 | #endif //_KERNEL_FRAMEBUFFER_H 8 | -------------------------------------------------------------------------------- /lib/libc/string/strchr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | char *strchr(const char *s, int c) { 4 | while (*s != '\0' && *s != (char)c) { 5 | s++; 6 | } 7 | 8 | return (*s != '\0' || c == '\0') ? (char *)s : NULL; 9 | } 10 | -------------------------------------------------------------------------------- /docs/user-guide/User-Guide.md: -------------------------------------------------------------------------------- 1 | # User Guide 2 | This is what you should read if you're a user, and you want to try it out. 3 | 4 | ## Prerequisites 5 | 1. [Building](../Building.md) 6 | 7 | ## Table Of Contents 8 | 1. [The Terminal](Terminal.md) 9 | -------------------------------------------------------------------------------- /user/commands/echo.c: -------------------------------------------------------------------------------- 1 | #include "commands.h" 2 | #include 3 | #include 4 | 5 | int echo(char args[]) { 6 | if (strlen(args) == 0) { 7 | return 0; 8 | } 9 | writestr(args); 10 | writestr("\n"); 11 | } 12 | -------------------------------------------------------------------------------- /kernel/include/kernel/io.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_PORTS_H 2 | #define _KERNEL_PORTS_H 3 | 4 | #include 5 | 6 | uint8_t inp(unsigned short port); 7 | void outp(unsigned short port, unsigned char data); 8 | 9 | #endif //_KERNEL_PORTS_H 10 | -------------------------------------------------------------------------------- /kernel/cpu/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef _CPU_IDT_H 2 | #define _CPU_IDT_H 3 | 4 | #include 5 | 6 | void init_idt(); 7 | extern void idt_load(); 8 | void set_gate_idt(int num, uint32_t base, uint16_t sel, uint8_t flags); 9 | 10 | #endif //_CPU_IDT_H 11 | -------------------------------------------------------------------------------- /lib/libc/string/strcmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int strcmp(const char *str1, const char *str2) { 4 | while ((*str1) && (*str1 == *str2)) { 5 | ++str1; 6 | ++str2; 7 | } 8 | 9 | return (*(unsigned char *)str1 - *(unsigned char *)str2); 10 | } 11 | -------------------------------------------------------------------------------- /lib/libc/ctype/isspace.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isspace(int ch) { 4 | switch (ch) { 5 | case '\n': 6 | case '\r': 7 | case '\t': 8 | case '\f': 9 | case ' ': 10 | case '\v': 11 | return 1; 12 | default: 13 | return 0; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MAINTAINERS: -------------------------------------------------------------------------------- 1 | # MAINTAINERS FILE 2 | # N: Name, E: Email, M: Maintainer of ... 3 | 4 | N: DamieFC 5 | E: gnuoveryou@gmail.com 6 | M: Everything 7 | 8 | N: Kushagra 9 | E: kushagra765@outlook.com 10 | M: VGA, Sound, Keyboard, PIT and Timer Driver, VFS, Tarfs, printm(), mm. 11 | -------------------------------------------------------------------------------- /user/commands/commands.h: -------------------------------------------------------------------------------- 1 | #ifndef _USER_COMMANDS_H 2 | #define _USER_COMMANDS_H 3 | 4 | int cat(char args[]); 5 | int echo(char args[]); 6 | int uname(char args[]); 7 | void help(); 8 | void version(); 9 | void hello(); 10 | void whoami(); 11 | 12 | #endif //_USER_COMMANDS_H 13 | -------------------------------------------------------------------------------- /kernel/cpu/load_gdt.asm: -------------------------------------------------------------------------------- 1 | global gdt_load 2 | extern gdt_ptr 3 | 4 | gdt_load: 5 | lgdt [gdt_ptr] 6 | mov ax, 0x10 7 | mov ds, ax 8 | mov es, ax 9 | mov fs, ax 10 | mov gs, ax 11 | mov ss, ax 12 | jmp 0x08:flush_gdt 13 | 14 | flush_gdt: 15 | ret 16 | -------------------------------------------------------------------------------- /kernel/include/kernel/pcspkr.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_PCSPKR_H 2 | #define _KERNEL_PCSPKR_H 3 | 4 | #include 5 | 6 | void beep_pcspkr(); 7 | void play_sound_pcspkr(uint32_t frequency); 8 | void stop_sound_pcspkr(); 9 | int init_pcspkr(); 10 | 11 | #endif //_KERNEL_PCSPKR_H 12 | -------------------------------------------------------------------------------- /kernel/cpu/gdt.h: -------------------------------------------------------------------------------- 1 | #ifndef _CPU_GDT_H 2 | #define _CPU_GDT_H 3 | 4 | #include 5 | 6 | void init_gdt(); 7 | extern void gdt_load(); 8 | void set_gate_gdt(int num, uint32_t base, uint32_t limit, uint8_t access, 9 | uint8_t gran); 10 | 11 | #endif //_CPU_GDT_H 12 | -------------------------------------------------------------------------------- /kernel/kernel/power/reboot.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void reboot() { 6 | uint8_t t = 0x02; 7 | 8 | while (t & 0x02) { 9 | t = inp(0x64); 10 | } 11 | 12 | outp(0x64, 0xFE); 13 | __asm__ volatile("hlt"); 14 | } 15 | -------------------------------------------------------------------------------- /lib/libc/string/memcpy.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void *memcpy(void *dest, const void *src, size_t count) { 4 | const char *sp = (const char *)src; 5 | char *dp = (char *)dest; 6 | 7 | for (; count != 0; count--) { 8 | *dp++ = *sp++; 9 | } 10 | 11 | return dest; 12 | } 13 | -------------------------------------------------------------------------------- /kernel/fs/mount.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* mount - Print the mounted filesystems */ 5 | 6 | int mount() { 7 | if (!vfs_root) { 8 | writestr("No filesystem mounted\n"); 9 | return 1; 10 | } 11 | 12 | writestr("VFS: Mounted on %s\n", vfs_root); 13 | } 14 | -------------------------------------------------------------------------------- /kernel/include/kernel/serial.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_SERIAL_H 2 | #define _KERNEL_SERIAL_H 3 | 4 | void init_serial(); 5 | int received_serial(); 6 | char read_serial(); 7 | int transmit_empty(); 8 | void writechar_serial(char c); 9 | void writestr_serial(const char *str); 10 | 11 | #endif //_KERNEL_SERIAL_H 12 | -------------------------------------------------------------------------------- /lib/libc/stdio/printf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int printf(const char *format, ...) { 6 | static char buf[1024]; 7 | va_list args; 8 | va_start(args, format); 9 | vsprintf(buf, format, args); 10 | writestr(buf); 11 | va_end(args); 12 | } 13 | -------------------------------------------------------------------------------- /lib/libc/string/memset.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* This function is based on the PDCLIB memset function */ 5 | void *memset(void *ptr, int ch, size_t n) { 6 | 7 | uint8_t *p = (uint8_t *)ptr; 8 | 9 | while (n--) { 10 | *p++ = (uint8_t)ch; 11 | } 12 | 13 | return ptr; 14 | } 15 | -------------------------------------------------------------------------------- /lib/libc/string/memsetw.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned short *memsetw(unsigned short *dest, unsigned short val, 4 | size_t count) { 5 | unsigned short *temp = (unsigned short *)dest; 6 | 7 | for (; count != 0; count--) { 8 | *temp++ = val; 9 | } 10 | 11 | return dest; 12 | } 13 | -------------------------------------------------------------------------------- /kernel/kernel/io.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | uint8_t inp(unsigned short port) { 5 | unsigned char c; 6 | __asm__ volatile("inb %1, %0" : "=a"(c) : "dN"(port)); 7 | } 8 | 9 | void outp(unsigned short port, unsigned char data) { 10 | __asm__ volatile("outb %1, %0" : : "dN"(port), "a"(data)); 11 | } 12 | -------------------------------------------------------------------------------- /kernel/include/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDLIB_H 2 | #define _STDLIB_H 3 | 4 | #include "stddef.h" 5 | 6 | #define EXIT_FAILURE 1 7 | #define EXIT_SUCCESS 0 8 | 9 | void _Exit(int status); 10 | void exit(int status); 11 | void abort(); 12 | int abs(int j); 13 | long int labs(long int j); 14 | long long int llabs(long long int j); 15 | 16 | #endif //_STDLIB_H 17 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Platypus OS 2 | 3 | VERSION = 0.11 4 | EXTRAVERSION = -rc3 5 | 6 | MAKEFILE_BUILD = ./scripts/Makefile.build 7 | 8 | .PHONY: all 9 | 10 | all: 11 | @./scripts/gen_config.sh 12 | @make -f $(MAKEFILE_BUILD) -j$(nproc) 13 | 14 | clean: 15 | @make -f $(MAKEFILE_BUILD) clean 16 | 17 | run: 18 | @./scripts/run.sh PlatypusOS.iso floppy.img 19 | -------------------------------------------------------------------------------- /kernel/include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDARG_H 2 | #define _STDARG_H 3 | 4 | typedef __builtin_va_list va_list; 5 | 6 | #define va_arg(ap, type) (__builtin_va_arg(ap, type)) 7 | #define va_copy(dest, src) (__builtin_va_copy(dest, src)) 8 | #define va_end(ap) (__builtin_va_end(ap)) 9 | #define va_start(ap, parmN) (__builtin_va_start(ap, parmN)) 10 | 11 | #endif //_STDARG_H 12 | -------------------------------------------------------------------------------- /kernel/kernel/printm/printm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define PRINTM_BUF_SIZE 1024 6 | 7 | static char buf[PRINTM_BUF_SIZE]; 8 | 9 | void printm(const char *fmt, ...) { 10 | va_list args; 11 | va_start(args, fmt); 12 | vsprintf(buf, fmt, args); 13 | writestr("[kernel] "); 14 | writestr(buf); 15 | va_end(args); 16 | } 17 | -------------------------------------------------------------------------------- /kernel/include/kernel/rtc.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_RTC_H 2 | #define _KERNEL_RTC_H 3 | 4 | #include "io.h" 5 | 6 | typedef struct { 7 | unsigned char second; 8 | unsigned char minute; 9 | unsigned char hour; 10 | unsigned char month; 11 | unsigned char year; 12 | } time_t; 13 | 14 | void init_rtc(); 15 | void handler_rtc(); 16 | void gettime_rtc(time_t *time); 17 | 18 | #endif //_KERNEL_RTC_H 19 | -------------------------------------------------------------------------------- /kernel/include/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef _ERRNO_H 2 | #define _ERRNO_H 3 | 4 | #define EPERM 1 5 | #define ENOENT 2 6 | #define ESRCH 3 7 | #define EINTR 4 8 | #define EIO 5 9 | #define ENXIO 6 10 | #define ENOEXEC 8 11 | #define ENOMEM 12 12 | #define EACCES 13 13 | #define ENODEV 19 14 | #define ENOSPC 28 15 | #define EPIPE 32 16 | #define ENAMETOOLONG 36 17 | 18 | extern int errno; 19 | 20 | #endif //_ERRNO_H 21 | -------------------------------------------------------------------------------- /kernel/kernel/irq/irq_enable.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int irq_is_enabled = 0; 5 | extern int irq_is_disabled; 6 | 7 | int irq_enable() { 8 | if (irq_is_disabled == 0 && irq_is_enabled == 1) { 9 | writestr("irqs already enabled\n"); 10 | return 1; 11 | } 12 | 13 | __asm__ volatile("sti"); 14 | 15 | irq_is_disabled = 0; 16 | irq_is_enabled = 1; 17 | } 18 | -------------------------------------------------------------------------------- /kernel/kernel/irq/irq_disable.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int irq_is_disabled = 0; 5 | extern int irq_is_enabled; 6 | 7 | int irq_disable() { 8 | if (irq_is_enabled == 0 && irq_is_disabled == 1) { 9 | writestr("irqs already disabled\n"); 10 | return 1; 11 | } 12 | 13 | __asm__ volatile("cli"); 14 | 15 | irq_is_enabled = 0; 16 | irq_is_disabled = 1; 17 | } 18 | -------------------------------------------------------------------------------- /kernel/initrd/initrd.h: -------------------------------------------------------------------------------- 1 | #ifndef _INITRD_H 2 | #define _INITRD_H 3 | 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | uint32_t nfiles; 9 | } initrd_header_t; 10 | 11 | typedef struct { 12 | uint8_t magic; 13 | char name[64]; 14 | uint32_t offset; 15 | uint32_t length; 16 | } initrd_file_header_t; 17 | 18 | vfs_node_t *init_initrd(uint32_t location); 19 | 20 | #endif //_INITRD_H 21 | -------------------------------------------------------------------------------- /kernel/include/kernel/device.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_DEVICE_H 2 | #define _KERNEL_DEVICE_H 3 | 4 | #include 5 | 6 | struct device { 7 | const char *name; 8 | const char *path; 9 | uint32_t id; 10 | }; 11 | 12 | void add_device(struct device *dev); 13 | int get_device_by_id(int id); 14 | int remove_device_by_id(int id); 15 | int print_devices(); 16 | void init_device_manager(); 17 | 18 | #endif //_KERNEL_DEVICE_H 19 | -------------------------------------------------------------------------------- /lib/libc/string/memcmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int memcmp(const void *aptr, const void *bptr, size_t sz) { 4 | const unsigned char *a = (const unsigned char *)aptr; 5 | const unsigned char *b = (const unsigned char *)bptr; 6 | 7 | for (size_t i = 0; i < sz; i++) { 8 | if (a[i] < b[i]) { 9 | return -1; 10 | } else if (b[i] < a[i]) { 11 | return 1; 12 | } 13 | } 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /kernel/include/kernel/keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_KEYBOARD_H 2 | #define _KERNEL_KEYBOARD_H 3 | 4 | /* PS/2 Keyboard Driver */ 5 | 6 | #include 7 | 8 | #define KEYBOARD_DATA_PORT 0x60 9 | #define KEYBOARD_STATUS_PORT 0x64 10 | 11 | /* Initialize the keyboard */ 12 | void init_keyboard(); 13 | 14 | /* Keyboard Handler */ 15 | void handler_keyboard(); 16 | 17 | /* Save Input */ 18 | int save_input_buf(uint8_t input); 19 | 20 | #endif //_KERNEL_KEYBOARD_H 21 | -------------------------------------------------------------------------------- /kernel/include/ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef _CTYPE_H 2 | #define _CTYPE_H 3 | 4 | #define MIN_DIGIT 0 5 | #define MAX_DIGIT 9 6 | 7 | int isalpha(int ch); 8 | int isalnum(int ch); 9 | int isblank(int ch); 10 | int isdigit(int ch); 11 | int islower(int ch); 12 | int isupper(int ch); 13 | int isspace(int ch); 14 | int toupper(int ch); 15 | int tolower(int ch); 16 | int ispunct(int ch); 17 | int isxdigit(int ch); 18 | int isprint(int ch); 19 | int iscntrl(int ch); 20 | int isgraph(int ch); 21 | 22 | #endif //_CTYPE_H 23 | -------------------------------------------------------------------------------- /kernel/include/kernel/tarfs.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_TARFS_H 2 | #define _KERNEL_TARFS_H 3 | 4 | #include 5 | 6 | struct tarfs_header { 7 | char filename[100]; 8 | char mode[8]; 9 | char uid[8]; 10 | char gid[8]; 11 | char size[12]; 12 | char mtime[12]; 13 | char checksum[8]; 14 | char typeflag[1]; 15 | }; 16 | 17 | unsigned int getsize_tarfs(const char *in); 18 | unsigned int parse_tarfs(unsigned int addr); 19 | int init_tarfs(uint32_t location); 20 | 21 | #endif //_KERNEL_TARFS_H 22 | -------------------------------------------------------------------------------- /kernel/include/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDIO_H 2 | #define _STDIO_H 3 | 4 | #include "stdarg.h" 5 | #include "stddef.h" 6 | 7 | int printf(const char *format, ...); 8 | int scanf(const char *format, ...); 9 | int putchar(int ch); 10 | int getchar(); 11 | int puts(const char *string); 12 | int sprintf(char *string, const char *format, ...); 13 | int snprintf(char *string, size_t number, const char *format, ...); 14 | int vsprintf(char *buf, const char *fmt, va_list args); 15 | void perror(const char *string); 16 | 17 | #endif //_STDIO_H 18 | -------------------------------------------------------------------------------- /user/commands/uname.c: -------------------------------------------------------------------------------- 1 | #include "commands.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int uname(char args[]) { 7 | if (strcmp(args, "-s") == 0) { 8 | writestr("Platypus\n"); 9 | return 0; 10 | } else if (strcmp(args, "-o") == 0) { 11 | writestr("PlatypusOS\n"); 12 | return 0; 13 | } else if (strcmp(args, "-m") == 0) { 14 | writestr(CONFIG_ARCH); 15 | writestr("\n"); 16 | return 0; 17 | } else { 18 | writestr("PlatypusOS\n"); 19 | return 0; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /docs/Building.md: -------------------------------------------------------------------------------- 1 | # Building the OS (with toolchain) 2 | To build the OS, you need `i686-elf-gcc` toolchain and many other packages. You can build the toolchain by running: 3 | ``` 4 | cd ./toolchain/ 5 | sh ./build_toolchain.sh 6 | ``` 7 | 8 | After the toolchain is built, you can build the OS by running: `make` 9 | 10 | # Building the OS (without toolchain) 11 | If you already have the `i686-elf-gcc` toolchain, there's no need to build it again. Open the `scripts/Makefile.build` file and change the `CC` variable to the path where you have installed the toolchain and run `make`. 12 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark stale issues and pull requests 2 | 3 | on: 4 | schedule: 5 | - cron: "30 1 * * *" 6 | 7 | jobs: 8 | stale: 9 | 10 | runs-on: ubuntu-latest 11 | permissions: 12 | issues: write 13 | pull-requests: write 14 | 15 | steps: 16 | - uses: actions/stale@v3 17 | with: 18 | repo-token: ${{ secrets.GITHUB_TOKEN }} 19 | stale-issue-message: 'Stale issue message' 20 | stale-pr-message: 'Stale pull request message' 21 | stale-issue-label: 'no-issue-activity' 22 | stale-pr-label: 'no-pr-activity' 23 | -------------------------------------------------------------------------------- /kernel/arch/i386/link.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf32-i386) 2 | ENTRY(start) 3 | memory_address = 0x00100000; 4 | 5 | SECTIONS 6 | { 7 | .text memory_address : AT(memory_address) { 8 | . = ALIGN(8); 9 | KEEP(*(.multiboot)) 10 | code = .; 11 | *(.text) 12 | *(.rodata) 13 | . = ALIGN(4096); 14 | } 15 | 16 | .data : AT(memory_address + (data - code)) 17 | { 18 | data = .; 19 | *(.data) 20 | . = ALIGN(4096); 21 | } 22 | 23 | .bss : AT(memory_address + (bss - code)) 24 | { 25 | bss = .; 26 | *(.bss) 27 | . = ALIGN(4096); 28 | } 29 | 30 | end = .; 31 | } 32 | -------------------------------------------------------------------------------- /kernel/include/kernel/task.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_TASK_H 2 | #define _KERNEL_TASK_H 3 | 4 | #include "paging.h" 5 | #include 6 | 7 | typedef struct task { 8 | const char *name; 9 | int id; 10 | uint32_t esp, ebp; 11 | uint32_t eip; 12 | page_dir_t *page_directory; 13 | struct task *next; 14 | } task_t; 15 | 16 | void init_tasking(); 17 | int fork(); 18 | void switch_task(); 19 | void move_stack(void *new_stack_start, uint32_t size); 20 | extern void alloc_frame(page_t *, int, int); 21 | extern uint32_t read_eip(); 22 | extern void do_task_switch(uint32_t, uint32_t, uint32_t, uint32_t); 23 | int getpid(); 24 | 25 | #endif //_KERNEL_TASK_H 26 | -------------------------------------------------------------------------------- /scripts/gen_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # --- Configuration start --- 4 | CONFIG_USERNAME=`whoami` 5 | CONFIG_ARCH=`uname -m` 6 | CONFIG_USERMODE=n 7 | # --- Configuration end --- 8 | 9 | if [ ! -d kernel/include/generated/ ]; then 10 | mkdir kernel/include/generated/ 11 | fi 12 | 13 | if [ -f kernel/include/generated/config.h ]; then 14 | rm kernel/include/generated/config.h 15 | fi 16 | 17 | printf "#ifndef _GENERATED_CONFIG_H\n#define _GENERATED_CONFIG_H\n\n#define CONFIG_ARCH \"$CONFIG_ARCH\"\n#define CONFIG_USERNAME \"$CONFIG_USERNAME\"\n#define CONFIG_USERMODE '$CONFIG_USERMODE'\n\n#endif //_GENERATED_CONFIG_H" > kernel/include/generated/config.h 18 | -------------------------------------------------------------------------------- /kernel/drivers/vga/framebuffer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* Framebuffer Info */ 6 | static uint32_t framebuffer_width; 7 | static uint32_t framebuffer_height; 8 | uint32_t *framebuffer; 9 | int x = 0; 10 | int y = 0; 11 | 12 | void put_pixel(int pos_x, int pos_y, unsigned char color) { 13 | framebuffer[pos_y * framebuffer_width + pos_x] = color; 14 | } 15 | 16 | void init_framebuffer() { 17 | multiboot_info_t *mboot_fb_info; 18 | 19 | framebuffer = mboot_fb_info->framebuffer_addr; 20 | framebuffer_width = mboot_fb_info->framebuffer_width; 21 | framebuffer_height = mboot_fb_info->framebuffer_height; 22 | } 23 | -------------------------------------------------------------------------------- /kernel/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_H 2 | #define _STRING_H 3 | 4 | #include "stddef.h" 5 | 6 | int strcmp(const char *str1, const char *str2); 7 | char *strcpy(char *str1, const char *str2); 8 | char *strcat(char *str1, char *str2); 9 | size_t strlen(const char *string); 10 | char *strerror(int err_code); 11 | void *memcpy(void *str1, const void *str2, size_t n); 12 | void *memmove(void *s1, const void *s2, size_t n); 13 | int memcmp(const void *aptr, const void *bptr, size_t sz); 14 | void *memset(void *ptr, int ch, size_t n); 15 | unsigned short *memsetw(unsigned short *dest, unsigned short val, size_t count); 16 | char *strchr(const char *s, int c); 17 | 18 | #endif //_STRING_H 19 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -2 4 | AlignAfterOpenBracket: Align 5 | AlignEscapedNewlines: Right 6 | AlignTrailingComments: true 7 | AllowAllConstructorInitializersOnNextLine: true 8 | AllowAllParametersOfDeclarationOnNextLine: false 9 | AlignConsecutiveDeclarations: false 10 | AlignOperands: false 11 | AllowAllArgumentsOnNextLine: false 12 | AllowShortBlocksOnASingleLine: Never 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: None 15 | AllowShortIfStatementsOnASingleLine: Never 16 | AllowShortLoopsOnASingleLine: false 17 | BreakStringLiterals: false 18 | ReflowComments: true 19 | SortIncludes: true 20 | UseTab: Never 21 | ... 22 | -------------------------------------------------------------------------------- /kernel/kernel/usermode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if CONFIG_USERMODE == 'y' 5 | void switch_to_usermode() { 6 | printm("Switching to usermode...\n"); 7 | 8 | __asm__ volatile(" \ 9 | cli; \ 10 | mov $0x23, %ax; \ 11 | mov %ax, %ds; \ 12 | mov %ax, %es; \ 13 | mov %ax, %fs; \ 14 | mov %ax, %gs; \ 15 | \ 16 | mov %esp, %eax; \ 17 | pushl $0x23; \ 18 | pushl %eax; \ 19 | pushf; \ 20 | pushl $0x1B; \ 21 | push $1f; \ 22 | iret; \ 23 | 1: \ 24 | "); 25 | } 26 | #else 27 | void switch_to_usermode() { 28 | printm("CONFIG_USERMODE is set to n\n"); 29 | } 30 | #endif 31 | -------------------------------------------------------------------------------- /kernel/drivers/pit/pit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int pit_ticks = 0; 7 | int pit_hz = 0; 8 | 9 | void handler_pit() { 10 | pit_ticks++; 11 | switch_task(); 12 | } 13 | 14 | void phase_pit(int hz) { 15 | int divisor = 1193180 / hz; 16 | outp(0x43, 0x36); 17 | outp(0x40, divisor & 0xFF); 18 | outp(0x40, divisor >> 8); 19 | } 20 | 21 | void sleep_pit(int ticks) { 22 | unsigned long eticks; 23 | eticks = pit_ticks + ticks * pit_hz; 24 | while (pit_ticks < eticks) 25 | ; 26 | } 27 | 28 | void init_pit(int hz) { 29 | install_irq_handler(0, handler_pit); 30 | phase_pit(hz); 31 | pit_hz = hz; 32 | } 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /kernel/arch/i386/boot.asm: -------------------------------------------------------------------------------- 1 | [BITS 32] 2 | 3 | global start 4 | start: 5 | mov esp, sys_stack 6 | jmp stublet 7 | 8 | ALIGN 4 9 | multiboot: 10 | 11 | PAGE_ALIGN equ 1<<0 12 | MEMORY_INFO equ 1<<1 13 | MAGIC equ 0x1BADB002 14 | FLAGS equ PAGE_ALIGN | MEMORY_INFO 15 | CHECKSUM equ -(MAGIC + FLAGS) 16 | 17 | EXTERN code, bss, end 18 | dd MAGIC 19 | dd FLAGS 20 | dd CHECKSUM 21 | 22 | dd multiboot 23 | dd code 24 | dd bss 25 | dd end 26 | dd start 27 | 28 | stublet: 29 | extern kernel_main 30 | push esp 31 | push ebx 32 | call kernel_main 33 | jmp $ 34 | 35 | SECTION .bss 36 | resb 8192 37 | sys_stack: 38 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | 0.11-rc3 | :white_check_mark: | 8 | | 0.10 | :white_check_mark: | 9 | | 0.09 | :x: | 10 | | 0.08 | :x: | 11 | | 0.07 | :x: | 12 | | 0.06 | :x: | 13 | | 0.05 and others | :x: | 14 | 15 | Key: 16 | | Thing | Meaning | 17 | | ----- | ------- | 18 | | :white_check_mark: | Supported | 19 | | :x: | Not supported | 20 | 21 | ## Reporting a Vulnerability 22 | 23 | ### If you can fix it: 24 | Please fix the issue and create a pull request. 25 | ### If you can't fix it: 26 | Please create an issue. 27 | -------------------------------------------------------------------------------- /kernel/fs/ls.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int ls() { 7 | if (!vfs_root) { 8 | writestr("No filesystem mounted\n"); 9 | return 1; 10 | } 11 | 12 | int i = 0; 13 | struct vfs_dirent *node = 0; 14 | while ((node = readdir_vfs(vfs_root, i)) != 0) { 15 | vfs_node_t *__node = finddir_vfs(vfs_root, node->name); 16 | if ((__node->flags & 0x7) == VFS_DIR) { 17 | settextcolor(BLUE, BLACK); 18 | writestr("%s\n", node->name); 19 | settextcolor(LIGHT_YELLOW, BLACK); 20 | print_devices(); 21 | } else { 22 | settextcolor(LIGHT_YELLOW, BLACK); 23 | writestr("%s\n", node->name); 24 | } 25 | i++; 26 | } 27 | 28 | reset_text_color(); 29 | } 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Platypus OS 2 | New OS drafts, I stopped the old one :( 3 |

4 | Chat about development on [Discord](https://discord.gg/t6keJw974q)! 5 | 6 | # What this is for 7 | I want it to be for: 8 | 1. Programming 9 | 2. Pentesting 10 | 3. Playing video games 11 | 12 | Seems like an odd combination, but that's what I like to do: program, pentest, and play video games. 13 | 14 | # Building 15 | To build the OS, read the [build guide](docs/Building.md). 16 | 17 | # Screenshot 18 | Version 0.11-rc2 19 | ![Image](screenshots/Screenshot-0.11-rc2.png) 20 | 21 | # Acknowledgments 22 | ## Projects 23 | - [pdclib](https://github.com/DevSolar/pdclib) 24 | - [libc11](https://github.com/dryc/libc11) 25 | 26 | # License 27 | This project is licensed under GPL v2. See the [`LICENSE`](LICENSE) file for more info. 28 | -------------------------------------------------------------------------------- /kernel/drivers/sound/pcspkr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int is_registered = 0; 5 | 6 | void play_sound_pcspkr(uint32_t frequency) { 7 | if (is_registered != 1) { 8 | return; 9 | } 10 | 11 | uint32_t d; 12 | uint8_t t; 13 | 14 | d = 1193180 / frequency; 15 | outp(0x43, 0xb6); 16 | outp(0x42, (uint8_t)(d)); 17 | outp(0x42, (uint8_t)(d >> 8)); 18 | 19 | t = inp(0x61); 20 | 21 | if (t != (t | 3)) { 22 | outp(0x61, t | 3); 23 | } 24 | } 25 | 26 | void stop_sound_pcspkr() { 27 | uint8_t t = inp(0x61) & 0xFC; 28 | 29 | outp(0x61, t); 30 | } 31 | 32 | void beep_pcspkr() { 33 | play_sound_pcspkr(1000); 34 | } 35 | 36 | int init_pcspkr() { 37 | if (is_registered == 1) { 38 | return -1; 39 | } else { 40 | is_registered = 1; 41 | return 0; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 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: 28 | - Version: 29 | - Emulator: 30 | 31 | **OS Info:** 32 | - PlatypusOS Version: 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /kernel/include/kernel/vga.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_VGA_H 2 | #define _KERNEL_VGA_H 3 | 4 | #include 5 | 6 | #define BLACK 0x0 7 | #define GREEN 0x2 8 | #define CYAN 0x3 9 | #define RED 0x4 10 | #define MAGENTA 0x5 11 | #define BROWN 0x6 12 | #define LIGHT_GRAY 0x7 13 | #define GRAY 0x8 14 | #define BLUE 0x9 15 | #define LIGHT_GREEN 0xA 16 | #define LIGHT_CYAN 0xB 17 | #define LIGHT_RED 0xC 18 | #define LIGHT_MAGENTA 0xD 19 | #define LIGHT_YELLOW 0xE 20 | #define WHITE 0xF 21 | 22 | void scroll(); 23 | void move_csr(); 24 | void disable_csr(); 25 | uint16_t get_csr_position(); 26 | void cls(); 27 | void putch(uint8_t c); 28 | void writestr(const char *fmt, ...); 29 | void writeint(uint32_t num); 30 | void writehex(uint32_t num); 31 | void settextcolor(uint8_t forecolor, uint8_t backcolor); 32 | void reset_text_color(); 33 | void init_vga(); 34 | 35 | #endif //_KERNEL_VGA_H 36 | -------------------------------------------------------------------------------- /kernel/include/kernel/floppy.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_FLOPPY_H 2 | #define _KERNEL_FLOPPY_H 3 | 4 | #include 5 | 6 | #define FLOPPY_BASE 0x03F0 7 | 8 | enum floppy_registers { 9 | DIGITAL_OUTPUT_REGISTER = 0x3F2, 10 | MAIN_STATUS_REGISTER = 0x3F4, 11 | DATA_FIFO = 0x3F5, 12 | CONFIGURATION_CONTROL_REGISTER = 0x3F7 13 | }; 14 | 15 | enum floppy_commands { 16 | SPECIFY = 3, 17 | WRITE_DATA = 5, 18 | READ_DATA = 6, 19 | RECALIBRATE = 7, 20 | SENSE_INTERRUPT = 8, 21 | SEEK = 15 22 | }; 23 | 24 | enum floppy_motor_states { MOTOR_OFF = 0, MOTOR_ON, MOTOR_WAIT }; 25 | 26 | void detect_drives_floppy(); 27 | void write_command_floppy(int base, char command); 28 | uint8_t read_data_floppy(int base); 29 | void check_interrupt_floppy(int base, int *st0, int *cyl); 30 | int calibrate_floppy(int base); 31 | int reset_floppy(int base); 32 | void motor_floppy(int base, int state); 33 | 34 | #endif //_KERNEL_FLOPPY_H 35 | -------------------------------------------------------------------------------- /kernel/cpu/idt.c: -------------------------------------------------------------------------------- 1 | #include "idt.h" 2 | #include 3 | #include 4 | #include 5 | 6 | struct entry_idt { 7 | uint16_t lo_base; 8 | uint16_t sel; 9 | uint8_t always0; 10 | uint8_t flags; 11 | uint16_t hi_base; 12 | } __attribute__((packed)); 13 | 14 | struct pointer_idt { 15 | uint16_t limit; 16 | uint32_t base; 17 | } __attribute__((packed)); 18 | 19 | struct entry_idt idt[256]; 20 | struct pointer_idt idt_ptr; 21 | 22 | void set_gate_idt(int num, uint32_t base, uint16_t sel, uint8_t flags) { 23 | 24 | idt[num].lo_base = base & 0xFFFF; 25 | idt[num].hi_base = (base >> 16) & 0xFFFF; 26 | idt[num].sel = sel; 27 | idt[num].always0 = 0; 28 | idt[num].flags = flags; 29 | } 30 | 31 | void init_idt() { 32 | 33 | idt_ptr.limit = (sizeof(struct entry_idt) * 256) - 1; 34 | idt_ptr.base = (uintptr_t)&idt; 35 | memset(&idt, 0, sizeof(struct entry_idt) * 256); 36 | 37 | idt_load(); 38 | } 39 | -------------------------------------------------------------------------------- /user/commands/cat.c: -------------------------------------------------------------------------------- 1 | #include "commands.h" 2 | #include 3 | #include 4 | #include 5 | 6 | int cat(char args[]) { 7 | if (strlen(args) == 0) { 8 | return 0; 9 | } 10 | 11 | int i = 0; 12 | struct vfs_dirent *node = 0; 13 | while ((node = readdir_vfs(vfs_root, i)) != 0) { 14 | vfs_node_t *fsnode = finddir_vfs(vfs_root, node->name); 15 | 16 | if ((fsnode->flags & 0x7) == VFS_DIR && strcmp(fsnode->name, args) == 0) { 17 | writestr("cat: %s: is a directory\n", args); 18 | return 0; 19 | } else { 20 | if (strcmp(fsnode->name, args) == 0) { 21 | char buf[256]; 22 | uint32_t sz = read_vfs(fsnode, 0, 256, buf); 23 | for (int j = 0; j < sz; j++) { 24 | putch(buf[j]); 25 | } 26 | return 0; 27 | } 28 | } 29 | i++; 30 | } 31 | 32 | writestr("cat: %s: no such file or directory\n", args); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /kernel/include/kernel/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_ELF_H 2 | #define _KERNEL_ELF_H 3 | 4 | #include 5 | #include 6 | 7 | #define ELF32_ST_TYPE(i) ((i)&0xF) 8 | 9 | typedef struct { 10 | uint32_t name; 11 | uint32_t type; 12 | uint32_t flags; 13 | uint32_t addr; 14 | uint32_t offset; 15 | uint32_t size; 16 | uint32_t link; 17 | uint32_t info; 18 | uint32_t addralign; 19 | uint32_t entsize; 20 | } __attribute__((packed)) elf_section_header_t; 21 | 22 | typedef struct { 23 | uint32_t name; 24 | uint32_t value; 25 | uint32_t size; 26 | uint8_t info; 27 | uint8_t other; 28 | uint16_t shndx; 29 | } __attribute__((packed)) elf_symbol_t; 30 | 31 | typedef struct { 32 | elf_symbol_t *symtab; 33 | uint32_t symtabsz; 34 | const char *strtab; 35 | uint32_t strtabsz; 36 | } elf_t; 37 | 38 | elf_t elf_from_multiboot(multiboot_elf_section_header_table_t elfinfo); 39 | const char *lookup_symbol_elf(uint32_t addr, elf_t *elf); 40 | 41 | #endif //_KERNEL_ELF_H 42 | -------------------------------------------------------------------------------- /kernel/include/kernel/ordered_array.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_ORDERED_ARRAY_H 2 | #define _KERNEL_ORDERED_ARRAY_H 3 | 4 | #include 5 | 6 | typedef void *type_t; 7 | typedef int8_t (*lessthan_predicate_t)(type_t, type_t); 8 | 9 | typedef struct { 10 | type_t *array; 11 | uint32_t size; 12 | uint32_t max_size; 13 | lessthan_predicate_t less_than; 14 | } ordered_array_t; 15 | 16 | int8_t standard_lessthan_predicate(type_t a, type_t b); 17 | ordered_array_t create_ordered_array(uint32_t max_size, 18 | lessthan_predicate_t less_than); 19 | ordered_array_t place_ordered_array(void *addr, uint32_t max_size, 20 | lessthan_predicate_t less_than); 21 | void destroy_ordered_array(ordered_array_t *array); 22 | void insert_ordered_array(type_t item, ordered_array_t *array); 23 | type_t lookup_ordered_array(uint32_t i, ordered_array_t *array); 24 | void remove_ordered_array(uint32_t i, ordered_array_t *array); 25 | 26 | #endif //_KERNEL_ORDERED_ARRAY_H 27 | -------------------------------------------------------------------------------- /kernel/drivers/serial/serial.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define SERIAL_COM1 0x3f8 5 | 6 | int received_serial() { 7 | return inp(SERIAL_COM1 + 5) & 1; 8 | } 9 | 10 | char read_serial() { 11 | while (received_serial() == 0) 12 | ; 13 | 14 | return inp(SERIAL_COM1); 15 | } 16 | 17 | int transmit_empty() { 18 | return inp(SERIAL_COM1 + 5) & 0x20; 19 | } 20 | 21 | void writechar_serial(char c) { 22 | while (transmit_empty() == 0) 23 | ; 24 | 25 | outp(SERIAL_COM1, c); 26 | } 27 | 28 | void writestr_serial(const char *str) { 29 | while (*str) { 30 | writechar_serial(*str++); 31 | } 32 | } 33 | 34 | void init_serial() { 35 | outp(SERIAL_COM1 + 1, 0x00); 36 | outp(SERIAL_COM1 + 3, 0x80); 37 | outp(SERIAL_COM1 + 0, 0x03); 38 | outp(SERIAL_COM1 + 1, 0x00); 39 | outp(SERIAL_COM1 + 3, 0x03); 40 | outp(SERIAL_COM1 + 2, 0xC7); 41 | outp(SERIAL_COM1 + 4, 0x0B); 42 | outp(SERIAL_COM1 + 4, 0x1E); 43 | outp(SERIAL_COM1 + 0, 0xAE); 44 | outp(SERIAL_COM1 + 4, 0x0F); 45 | } 46 | -------------------------------------------------------------------------------- /kernel/fs/tarfs/tarfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct tarfs_header *headers[32]; 6 | int total_files = 0; 7 | 8 | unsigned int getsize_tarfs(const char *in) { 9 | unsigned int size = 0; 10 | unsigned int count = 1; 11 | unsigned int j; 12 | 13 | for (j = 11; j > 0; j--, count *= 8) { 14 | size += ((in[j - 1] - '0') * count); 15 | } 16 | 17 | return size; 18 | } 19 | 20 | unsigned int parse_tarfs(unsigned int addr) { 21 | unsigned int i; 22 | 23 | for (i = 0;; i++) { 24 | struct tarfs_header *header = (struct tarfs_header *)addr; 25 | 26 | if (header->filename[0] == '\0') { 27 | break; 28 | } 29 | 30 | unsigned int size = getsize_tarfs(header->size); 31 | 32 | headers[i] = header; 33 | 34 | addr += ((size / 512) + 1) * 512; 35 | 36 | if (size % 512) { 37 | addr += 512; 38 | } 39 | } 40 | 41 | total_files = i; 42 | 43 | return i; 44 | } 45 | 46 | int init_tarfs(uint32_t location) { 47 | kmalloc(headers); 48 | parse_tarfs(location); 49 | } 50 | -------------------------------------------------------------------------------- /kernel/kernel/process.asm: -------------------------------------------------------------------------------- 1 | global read_eip 2 | read_eip: 3 | pop eax 4 | jmp eax 5 | 6 | 7 | global do_task_switch 8 | do_task_switch: 9 | cli 10 | mov ecx, [esp+4] 11 | mov eax, [esp+8] 12 | mov ebp, [esp+12] 13 | mov esp, [esp+16] 14 | mov cr3, eax 15 | mov eax, 0x12345 16 | sti 17 | jmp ecx 18 | 19 | 20 | global copy_page_physical 21 | copy_page_physical: 22 | push ebx 23 | pushf 24 | cli 25 | mov ebx, [esp+12] 26 | mov ecx, [esp+16] 27 | mov edx, cr0 28 | and edx, 0x7fffffff 29 | mov cr0, edx 30 | mov edx, 1024 31 | 32 | .loop: 33 | mov eax, [ebx] 34 | mov [ecx], eax 35 | add ebx, 4 36 | add ecx, 4 37 | dec edx 38 | jnz .loop 39 | 40 | mov edx, cr0 41 | or edx, 0x80000000 42 | mov cr0, edx 43 | 44 | popf 45 | pop ebx 46 | ret 47 | -------------------------------------------------------------------------------- /kernel/cpu/irq.h: -------------------------------------------------------------------------------- 1 | #ifndef _CPU_IRQ_H 2 | #define _CPU_IRQ_H 3 | 4 | #include "isr.h" 5 | 6 | // IRQ 7 | #define IRQ0 32 8 | #define IRQ1 33 9 | #define IRQ2 34 10 | #define IRQ3 35 11 | #define IRQ4 36 12 | #define IRQ5 37 13 | #define IRQ6 38 14 | #define IRQ7 39 15 | #define IRQ8 40 16 | #define IRQ9 41 17 | #define IRQ10 42 18 | #define IRQ11 43 19 | #define IRQ12 44 20 | #define IRQ13 45 21 | #define IRQ14 46 22 | #define IRQ15 47 23 | 24 | extern void irq0(); 25 | extern void irq1(); 26 | extern void irq2(); 27 | extern void irq3(); 28 | extern void irq4(); 29 | extern void irq5(); 30 | extern void irq6(); 31 | extern void irq7(); 32 | extern void irq8(); 33 | extern void irq9(); 34 | extern void irq10(); 35 | extern void irq11(); 36 | extern void irq12(); 37 | extern void irq13(); 38 | extern void irq14(); 39 | extern void irq15(); 40 | 41 | void install_irq_handler(int irq_num, 42 | void (*kernel_irq_handler)(struct registers *regs)); 43 | void uninstall_irq_handler(int irq_num); 44 | void init_irq(); 45 | void remap_kernel_irq(); 46 | int irq_enable(); 47 | int irq_disable(); 48 | void handler_irq(struct registers *regs); 49 | 50 | #endif //_CPU_IRQ_H 51 | -------------------------------------------------------------------------------- /kernel/cpu/isr.h: -------------------------------------------------------------------------------- 1 | #ifndef _CPU_ISR_H 2 | #define _CPU_ISR_H 3 | 4 | extern void isr0(); 5 | extern void isr1(); 6 | extern void isr2(); 7 | extern void isr3(); 8 | extern void isr4(); 9 | extern void isr5(); 10 | extern void isr6(); 11 | extern void isr7(); 12 | extern void isr8(); 13 | extern void isr9(); 14 | extern void isr10(); 15 | extern void isr11(); 16 | extern void isr12(); 17 | extern void isr13(); 18 | extern void isr14(); 19 | extern void isr15(); 20 | extern void isr16(); 21 | extern void isr17(); 22 | extern void isr18(); 23 | extern void isr19(); 24 | extern void isr20(); 25 | extern void isr21(); 26 | extern void isr22(); 27 | extern void isr23(); 28 | extern void isr24(); 29 | extern void isr25(); 30 | extern void isr26(); 31 | extern void isr27(); 32 | extern void isr28(); 33 | extern void isr29(); 34 | extern void isr30(); 35 | extern void isr31(); 36 | 37 | struct registers { 38 | unsigned int gs, fs, es, ds; 39 | unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; 40 | unsigned int int_no, err_code; 41 | unsigned int eip, cs, eflags, useresp, ss; 42 | }; 43 | 44 | void init_isr(); 45 | void handler_isr(struct registers *regs); 46 | 47 | #endif //_CPU_ISR_H 48 | -------------------------------------------------------------------------------- /kernel/include/kernel/paging.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_PAGING_H 2 | #define _KERNEL_PAGING_H 3 | 4 | #include 5 | 6 | #define INDEX_FROM_BIT(a) (a / (8 * 4)) 7 | #define OFFSET_FROM_BIT(a) (a % (8 * 4)) 8 | 9 | typedef struct page { 10 | uint32_t present : 1; 11 | uint32_t rw : 1; 12 | uint32_t user : 1; 13 | uint32_t accessed : 1; 14 | uint32_t dirty : 1; 15 | uint32_t unused : 7; 16 | uint32_t frame : 20; 17 | } page_t; 18 | 19 | typedef struct page_table { 20 | page_t pages[1024]; 21 | } page_table_t; 22 | 23 | typedef struct page_directory { 24 | page_table_t *tables[1024]; 25 | uint32_t tablesPhysical[1024]; 26 | uint32_t physicalAddr; 27 | } page_dir_t; 28 | 29 | void switch_page_directory(page_dir_t *dir); 30 | extern int copy_page_physical(uint32_t, uint32_t); 31 | page_t *get_page(uint32_t address, int make, page_dir_t *dir); 32 | page_dir_t *clone_directory(page_dir_t *src); 33 | void set_frame(uint32_t frame_addr); 34 | void clear_frame(uint32_t frame_addr); 35 | uint32_t test_frame(uint32_t frame_addr); 36 | uint32_t first_frame(); 37 | void alloc_frame(page_t *page, int is_kernel, int is_writeable); 38 | void free_frame(page_t *page); 39 | void init_paging(); 40 | 41 | #endif //_KERNEL_PAGING_H 42 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: GitHub CI 2 | on: 3 | push: 4 | branches: [ 0.11 ] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | 14 | - name: Cache Toolchain 15 | uses: actions/cache@v2 16 | env: 17 | cache-name: cache-toolchain 18 | with: 19 | path: | 20 | **/toolchain 21 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/build_toolchain.sh') }} 22 | restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/build_toolchain.sh') }} 23 | 24 | - name: Build i686-elf-gcc Toolchain 25 | run: | 26 | cd ./toolchain/ 27 | chmod +x ./build_toolchain.sh 28 | ./build_toolchain.sh 29 | 30 | - name: Install Dependencies 31 | run: | 32 | sh ./scripts/install_deps.sh 33 | 34 | - name: Build PlatypusOS 35 | run: | 36 | make 37 | 38 | - name: Upload Build Artifact 39 | uses: actions/upload-artifact@v2.2.3 40 | with: 41 | name: PlatypusOS-Build.iso 42 | path: PlatypusOS.iso 43 | if-no-files-found: warn 44 | -------------------------------------------------------------------------------- /kernel/kernel/elf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const char *lookup_symbol_elf(uint32_t addr, elf_t *elf) { 6 | for (int i = 0; i < (elf->symtabsz / sizeof(elf_symbol_t)); i++) { 7 | if (ELF32_ST_TYPE(elf->symtab[i].info) != 0x2) { 8 | continue; 9 | } 10 | 11 | if ((addr >= elf->symtab[i].value) && 12 | (addr < (elf->symtab[i].value + elf->symtab[i].size))) { 13 | const char *name = 14 | (const char *)((uint32_t)elf->strtab + elf->symtab[i].name); 15 | return name; 16 | } 17 | } 18 | } 19 | 20 | elf_t elf_from_multiboot(multiboot_elf_section_header_table_t elfinfo) { 21 | elf_t elf; 22 | elf_section_header_t *sh = (elf_section_header_t *)elfinfo.addr; 23 | 24 | uint32_t shstrtab = sh[elfinfo.shndx].addr; 25 | 26 | for (int i = 0; i < elfinfo.num; i++) { 27 | const char *name = (const char *)(shstrtab + sh[i].name); 28 | if (strcmp(name, ".strtab") == 0) { 29 | elf.strtab = (const char *)sh[i].addr; 30 | elf.strtabsz = sh[i].size; 31 | } 32 | if (strcmp(name, ".symtab") == 0) { 33 | elf.symtab = (elf_symbol_t *)sh[i].addr; 34 | elf.symtabsz = sh[i].size; 35 | } 36 | } 37 | return elf; 38 | } 39 | -------------------------------------------------------------------------------- /kernel/include/kernel/kheap.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_KHEAP_H 2 | #define _KERNEL_KHEAP_H 3 | 4 | #include 5 | #include 6 | 7 | #define KHEAP_START 0xC0000000 8 | #define KHEAP_INITIAL_SIZE 0x100000 9 | 10 | #define HEAP_INDEX_SIZE 0x20000 11 | #define HEAP_MAGIC 0x123890AB 12 | #define HEAP_MIN_SIZE 0x70000 13 | 14 | typedef struct { 15 | uint32_t magic; 16 | uint8_t is_hole; 17 | uint32_t size; 18 | } header_t; 19 | 20 | typedef struct { 21 | uint32_t magic; 22 | header_t *header; 23 | } footer_t; 24 | 25 | typedef struct { 26 | ordered_array_t index; 27 | uint32_t start_address; 28 | uint32_t end_address; 29 | uint32_t max_address; 30 | uint8_t supervisor; 31 | uint8_t readonly; 32 | } heap_t; 33 | 34 | heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, 35 | uint8_t supervisor, uint8_t readonly); 36 | void *alloc(uint32_t size, uint8_t page_align, heap_t *heap); 37 | void free(void *p, heap_t *heap); 38 | uint32_t kmalloc_int(uint32_t sz, int align, uint32_t *phys); 39 | uint32_t kmalloc_a(uint32_t sz); 40 | uint32_t kmalloc_p(uint32_t sz, uint32_t *phys); 41 | uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys); 42 | uint32_t kmalloc(uint32_t sz); 43 | void kfree(void *p); 44 | 45 | #endif //_KERNEL_KHEAP_H 46 | -------------------------------------------------------------------------------- /kernel/cpu/gdt.c: -------------------------------------------------------------------------------- 1 | #include "gdt.h" 2 | #include 3 | #include 4 | 5 | struct entry_gdt { 6 | uint16_t low_limit; 7 | uint16_t low_base; 8 | uint8_t middle_base; 9 | uint8_t access; 10 | uint8_t granularity; 11 | uint8_t high_base; 12 | } __attribute__((packed)); 13 | 14 | struct pointer_gdt { 15 | uint16_t limit; 16 | uint32_t base; 17 | } __attribute__((packed)); 18 | 19 | struct entry_gdt gdt[3]; 20 | struct pointer_gdt gdt_ptr; 21 | 22 | void set_gate_gdt(int num, uint32_t base, uint32_t limit, uint8_t access, 23 | uint8_t gran) { 24 | 25 | /* Set the base address */ 26 | gdt[num].low_base = (base & 0xFFFF); 27 | gdt[num].middle_base = (base >> 16) & 0xFF; 28 | gdt[num].high_base = (base >> 24) & 0xFF; 29 | 30 | /* Set the limits */ 31 | gdt[num].low_limit = (limit & 0xFFFF); 32 | gdt[num].granularity = ((limit >> 16) & 0x0F); 33 | 34 | /* Set the granularity and access flags */ 35 | gdt[num].granularity |= (gran & 0xF0); 36 | gdt[num].access = access; 37 | } 38 | 39 | void init_gdt() { 40 | gdt_ptr.limit = (sizeof(struct entry_gdt) * 6) - 1; 41 | gdt_ptr.base = (uintptr_t)&gdt; 42 | 43 | set_gate_gdt(0, 0, 0, 0, 0); 44 | set_gate_gdt(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); 45 | set_gate_gdt(2, 0, 0xFFFFFFFF, 0x92, 0xCF); 46 | 47 | gdt_load(); 48 | } 49 | -------------------------------------------------------------------------------- /toolchain/build_toolchain.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | GCC_VERSION=11.2.0 4 | BINUTILS_VERSION=2.38 5 | 6 | if [ -d "compiler/" ]; then 7 | echo "Found i686-elf-gcc Toolchain" 8 | exit 0; 9 | fi 10 | 11 | sudo apt-get update 12 | sudo apt install make nasm gcc bison flex libgmp3-dev libmpc-dev libmpfr-dev texinfo libisl-dev tar xorriso mtools 13 | 14 | export PREFIX="$PWD/compiler" 15 | export TARGET=i686-elf 16 | export PATH="$PREFIX/bin:$PATH" 17 | 18 | mkdir ./compiler 19 | 20 | mkdir ./src 21 | cd ./src 22 | 23 | wget https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS_VERSION.tar.gz 24 | wget https://ftp.gnu.org/gnu/gcc/gcc-$GCC_VERSION/gcc-$GCC_VERSION.tar.gz 25 | 26 | tar -xf gcc-$GCC_VERSION.tar.gz 27 | tar -xf binutils-$BINUTILS_VERSION.tar.gz 28 | 29 | mkdir binutils-build 30 | cd binutils-build 31 | ../binutils-$BINUTILS_VERSION/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror 32 | make -j$(nproc) 33 | make install 34 | 35 | cd .. 36 | 37 | which -- $TARGET-as || echo $TARGET-as not found 38 | 39 | mkdir gcc-build 40 | cd gcc-build 41 | ../gcc-$GCC_VERSION/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers 42 | make -j$(nproc) all-gcc 43 | make -j$(nproc) all-target-libgcc 44 | make install-gcc 45 | make install-target-libgcc 46 | 47 | # Remove the sources 48 | cd .. 49 | cd .. 50 | rm -rf src/ 51 | -------------------------------------------------------------------------------- /kernel/kernel/device.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define MAX_DEVICES 10 8 | 9 | struct device *devices[MAX_DEVICES]; 10 | int next_device_entry = 0; 11 | 12 | void add_device(struct device *dev) { 13 | if (!dev || next_device_entry == MAX_DEVICES) { 14 | return; 15 | } 16 | 17 | devices[next_device_entry] = dev; 18 | next_device_entry++; 19 | printm("Registered device %s. id=%d , path=%s\n", dev->name, dev->id, 20 | dev->path); 21 | } 22 | 23 | int get_device_by_id(int id) { 24 | for (int i = 0; i < next_device_entry; i++) { 25 | if (devices[i]->id == id) { 26 | return &devices[i]; 27 | } 28 | } 29 | } 30 | 31 | int remove_device_by_id(int id) { 32 | for (int i = 0; i < next_device_entry; i++) { 33 | if (devices[i]->id == id) { 34 | printm("Removing device %s... ", devices[i]->name); 35 | devices[i] = 0; 36 | printm("done\n"); 37 | return 0; 38 | } 39 | } 40 | return 1; 41 | } 42 | 43 | int print_devices() { 44 | if (next_device_entry == 0) { 45 | return 1; 46 | } 47 | 48 | for (int i = 0; i < next_device_entry; i++) { 49 | writestr(" %s ", devices[i]->name); 50 | } 51 | 52 | writestr("\n"); 53 | return 0; 54 | } 55 | 56 | void init_device_manager() { 57 | kmalloc(devices); 58 | printm("Initialized Device Manager\n"); 59 | } 60 | -------------------------------------------------------------------------------- /kernel/fs/vfs/vfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* A simple VFS, based on JamesM's kernel development tutorials */ 7 | 8 | vfs_node_t *vfs_root = 0; 9 | 10 | uint32_t read_vfs(vfs_node_t *node, uint32_t offset, uint32_t size, 11 | uint8_t *buf) { 12 | if (node->read != 0) { 13 | return node->read(node, offset, size, buf); 14 | } else { 15 | return -ENOENT; 16 | } 17 | } 18 | 19 | uint32_t write_vfs(vfs_node_t *node, uint32_t offset, uint32_t size, 20 | uint8_t *buf) { 21 | if (node->write != 0) { 22 | return node->write(node, offset, size, buf); 23 | } else { 24 | return -ENOENT; 25 | } 26 | } 27 | 28 | void open_vfs(vfs_node_t *node, uint8_t read, uint8_t write) { 29 | if (node->open != 0) { 30 | return node->open(node); 31 | } 32 | } 33 | 34 | void close_vfs(vfs_node_t *node) { 35 | if (node == vfs_root) { 36 | panic("Attempted to close vfs_root!"); 37 | } 38 | 39 | if (node->close != 0) { 40 | return node->close(node); 41 | } 42 | } 43 | 44 | struct vfs_dirent *readdir_vfs(vfs_node_t *node, uint32_t index) { 45 | if ((node->flags & 0x7) == VFS_DIR && node->readdir != 0) { 46 | return node->readdir(node, index); 47 | } 48 | } 49 | 50 | vfs_node_t *finddir_vfs(vfs_node_t *node, char *name) { 51 | if ((node->flags & 0x7) == VFS_DIR && node->finddir != 0) { 52 | return node->finddir(node, name); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/Makefile.build: -------------------------------------------------------------------------------- 1 | ARCH = i386 2 | CC = ./toolchain/compiler/bin/i686-elf-gcc 3 | LD = $(CC) 4 | AS = nasm 5 | ISO_FILE = PlatypusOS.iso 6 | FLOPPY_FILE = floppy.img 7 | KERNEL_FILE = kernel.elf 8 | INITRD_FILE = initrd.img 9 | INCLUDE = -I$(PWD) -I./kernel/ -I./kernel/drivers/ -I./kernel/fs/ -I./kernel/include/ -I./user/ 10 | 11 | CFLAGS = -Wno-attributes -Wno-discarded-qualifiers -Wno-int-conversion -ffreestanding $(INCLUDE) 12 | ASFLAGS = -f elf32 13 | LDFLAGS = -T./kernel/arch/$(ARCH)/link.ld -ffreestanding -O2 -nostdlib 14 | 15 | C_SOURCES = $(shell find kernel/ lib/ user/ -name '*.c') 16 | ASM_SOURCES = $(shell find kernel/ -name '*.asm') 17 | OBJ_FILES = $(C_SOURCES:.c=.o) $(ASM_SOURCES:.asm=.o) 18 | INITRD_FILES = kernel/initrd/file.txt file.txt kernel/initrd/file2.txt file2.txt 19 | 20 | $(ISO_FILE): $(KERNEL_FILE) 21 | @gcc -o ./scripts/gen_initrd ./scripts/gen_initrd.c 22 | @./scripts/gen_initrd $(INITRD_FILES) 23 | @dd if=/dev/zero of=$(FLOPPY_FILE) bs=512 count=2880 24 | @mkdir -p isodir/boot/grub/ 25 | @cp grub.cfg isodir/boot/grub/ 26 | @cp $(KERNEL_FILE) $(INITRD_FILE) isodir/boot/ 27 | @grub-mkrescue -o $(ISO_FILE) isodir 28 | 29 | $(KERNEL_FILE): kernel/arch/$(ARCH)/boot.o $(OBJ_FILES) 30 | @echo "LD $@" 31 | @$(LD) $(LDFLAGS) $^ -o $@ 32 | 33 | %.o: %.c 34 | @echo "CC $<" 35 | @$(CC) $(CFLAGS) -c $< -o $@ 36 | 37 | %.o: %.asm 38 | @echo "AS $<" 39 | @$(AS) $(ASFLAGS) $< -o $@ 40 | 41 | clean: 42 | @rm -rf isodir/ kernel/include/generated/ $(KERNEL_FILE) $(INITRD_FILE) $(ISO_FILE) $(FLOPPY_FILE) $(OBJ_FILES) 43 | -------------------------------------------------------------------------------- /kernel/drivers/rtc/rtc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | unsigned char read_reg(unsigned char reg) { 8 | outp(0x70, reg); 9 | return inp(0x71); 10 | } 11 | 12 | void write_reg(unsigned char reg, unsigned char val) { 13 | outp(0x70, reg); 14 | outp(0x71, val); 15 | } 16 | 17 | unsigned char bcd_to_bin(unsigned char bcd) { 18 | return ((bcd >> 4) * 10) + (bcd & 0x0F); 19 | } 20 | 21 | time_t time_global; 22 | bool bcd; 23 | 24 | void gettime_rtc(time_t *time) { 25 | memcpy(time, &time_global, sizeof(time_t)); 26 | } 27 | 28 | void handler_rtc() { 29 | if (read_reg(0x0C) & 0x40) { 30 | if (bcd) { 31 | time_global.second = bcd_to_bin(read_reg(0x00)); 32 | time_global.minute = bcd_to_bin(read_reg(0x02)); 33 | time_global.hour = bcd_to_bin(read_reg(0x04)); 34 | time_global.month = bcd_to_bin(read_reg(0x08)); 35 | time_global.year = bcd_to_bin(read_reg(0x09)); 36 | } else { 37 | time_global.second = read_reg(0x00); 38 | time_global.minute = read_reg(0x02); 39 | time_global.hour = read_reg(0x04); 40 | time_global.month = read_reg(0x08); 41 | time_global.year = read_reg(0x09); 42 | } 43 | } 44 | } 45 | 46 | void init_rtc() { 47 | uint8_t status; 48 | 49 | write_reg(0x0A, read_reg(0x0A) | 0x0F); 50 | 51 | status = read_reg(0x0B); 52 | status |= 0x02; 53 | status &= 0x10; 54 | status &= ~0x20; 55 | status |= 0x40; 56 | 57 | bcd = !(status & 0x04); 58 | write_reg(0x0B, status); 59 | read_reg(0x0C); 60 | install_irq_handler(8, handler_rtc); 61 | } 62 | -------------------------------------------------------------------------------- /user/terminal/terminal.c: -------------------------------------------------------------------------------- 1 | #include "terminal.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void put_prompt() { 13 | writestr("%s@platypusOS:# ", CONFIG_USERNAME); 14 | } 15 | 16 | void run_command(char input[], char args[]) { 17 | if (strcmp(input, "version") == 0) { 18 | version(); 19 | } else if (strcmp(input, "help") == 0) { 20 | help(); 21 | } else if (strcmp(input, "uname") == 0) { 22 | uname(args); 23 | } else if (strcmp(input, "whoami") == 0) { 24 | whoami(); 25 | } else if (strcmp(input, "cat") == 0) { 26 | cat(args); 27 | } else if (strcmp(input, "reboot") == 0) { 28 | reboot(); 29 | } else if (strcmp(input, "ls") == 0) { 30 | ls(); 31 | } else if (strcmp(input, "echo") == 0) { 32 | echo(args); 33 | } else if (strcmp(input, "playsound") == 0) { 34 | beep_pcspkr(); 35 | } else if (strcmp(input, "stopsound") == 0) { 36 | stop_sound_pcspkr(); 37 | } else if (strcmp(input, "panic") == 0) { 38 | panic("panic command used!"); 39 | } else if (strcmp(input, "hello") == 0) { 40 | hello(); 41 | } else if (strcmp(input, "mount") == 0) { 42 | mount(); 43 | } else if (strcmp(input, "\0") == 0) { 44 | 45 | } else { 46 | writestr("%s: command not found!\n", input); 47 | } 48 | 49 | for (int i = 0; input[i] != '\0'; i++) { 50 | input[i] = '\0'; 51 | } 52 | for (int j = 0; args[j] != '\0'; j++) { 53 | args[j] = '\0'; 54 | } 55 | 56 | put_prompt(); 57 | } 58 | 59 | void init_terminal() { 60 | put_prompt(); 61 | } 62 | -------------------------------------------------------------------------------- /scripts/gen_initrd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct initrd_header { 7 | uint8_t magic; 8 | char name[64]; 9 | uint32_t offset; 10 | uint32_t length; 11 | }; 12 | 13 | int main(int argc, char *argv[]) { 14 | 15 | int nheaders = (argc - 1) / 2; 16 | struct initrd_header headers[64]; 17 | 18 | printf("Size of Header: %ld\n", sizeof(struct initrd_header)); 19 | 20 | unsigned int off = sizeof(struct initrd_header) * 64 + sizeof(int); 21 | 22 | for (int i = 0; i < nheaders; i++) { 23 | printf("Writing file %s->%s at 0x%x\n", argv[i * 2 + 1], argv[i * 2 + 2], 24 | off); 25 | strcpy(headers[i].name, argv[i * 2 + 2]); 26 | headers[i].offset = off; 27 | FILE *stream = fopen(argv[i * 2 + 1], "r"); 28 | 29 | if (stream == 0) { 30 | printf("Error: %s : file not found\n", argv[i * 2 + 1]); 31 | return 1; 32 | } 33 | 34 | fseek(stream, 0, SEEK_END); 35 | headers[i].length = ftell(stream); 36 | off += headers[i].length; 37 | fclose(stream); 38 | headers[i].magic = 0xBF; 39 | } 40 | 41 | FILE *wstream = fopen("./initrd.img", "w"); 42 | unsigned char *data = (unsigned char *)malloc(off); 43 | fwrite(&nheaders, sizeof(int), 1, wstream); 44 | fwrite(headers, sizeof(struct initrd_header), 64, wstream); 45 | 46 | for (int i = 0; i < nheaders; i++) { 47 | FILE *stream = fopen(argv[i * 2 + 1], "r"); 48 | unsigned char *buf = (unsigned char *)malloc(headers[i].length); 49 | fread(buf, 1, headers[i].length, stream); 50 | fwrite(buf, 1, headers[i].length, wstream); 51 | fclose(stream); 52 | free(buf); 53 | } 54 | 55 | fclose(wstream); 56 | free(data); 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /kernel/include/kernel/vfs.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_VFS_H 2 | #define _KERNEL_VFS_H 3 | 4 | #include 5 | 6 | #define VFS_FILE 0x01 7 | #define VFS_DIR 0x02 8 | #define VFS_CHARDEVICE 0x03 9 | #define VFS_BLOCKDEVICE 0x04 10 | #define VFS_PIPE 0x05 11 | #define VFS_SYMLINK 0x06 12 | #define VFS_MOUNTPOINT 0x08 13 | 14 | struct vfs_dirent { 15 | char name[128]; 16 | uint32_t inode_num; 17 | }; 18 | 19 | struct vfs_node; 20 | 21 | typedef uint32_t (*read_type_t)(struct vfs_node *, uint32_t, uint32_t, 22 | uint8_t *); 23 | typedef uint32_t (*write_type_t)(struct vfs_node *, uint32_t, uint32_t, 24 | uint8_t *); 25 | typedef void (*open_type_t)(struct vfs_node *); 26 | typedef void (*close_type_t)(struct vfs_node *); 27 | typedef struct vfs_dirent *(*readdir_type_t)(struct vfs_node *, uint32_t); 28 | typedef struct vfs_node *(*finddir_type_t)(struct vfs_node *, char *name); 29 | 30 | typedef struct vfs_node { 31 | char name[128]; 32 | uint32_t mask; 33 | uint32_t uid; 34 | uint32_t gid; 35 | uint32_t flags; 36 | uint32_t inode; 37 | uint32_t length; 38 | uint32_t impl; 39 | read_type_t read; 40 | write_type_t write; 41 | open_type_t open; 42 | close_type_t close; 43 | readdir_type_t readdir; 44 | finddir_type_t finddir; 45 | struct vfs_node *ptr; 46 | } vfs_node_t; 47 | 48 | extern vfs_node_t *vfs_root; 49 | 50 | uint32_t read_vfs(vfs_node_t *node, uint32_t offset, uint32_t size, 51 | uint8_t *buf); 52 | uint32_t write_vfs(vfs_node_t *node, uint32_t offset, uint32_t size, 53 | uint8_t *buf); 54 | void open_vfs(vfs_node_t *node, uint8_t read, uint8_t write); 55 | void close_vfs(vfs_node_t *node); 56 | int ls(); 57 | int mount(); 58 | struct vfs_dirent *readdir_vfs(vfs_node_t *node, uint32_t index); 59 | vfs_node_t *finddir_vfs(vfs_node_t *node, char *name); 60 | 61 | #endif //_KERNEL_VFS_H 62 | -------------------------------------------------------------------------------- /kernel/cpu/irq.c: -------------------------------------------------------------------------------- 1 | #include "irq.h" 2 | #include "idt.h" 3 | #include "isr.h" 4 | #include 5 | #include 6 | 7 | void *kernel_routines_irq[16] = {0, 0, 0, 0, 0, 0, 0, 0, 8 | 0, 0, 0, 0, 0, 0, 0, 0}; 9 | 10 | void install_irq_handler(int irq_num, 11 | void (*kernel_irq_handler)(struct registers *regs)) { 12 | kernel_routines_irq[irq_num] = kernel_irq_handler; 13 | } 14 | 15 | void uninstall_irq_handler(int irq_num) { 16 | kernel_routines_irq[irq_num] = 0; 17 | } 18 | 19 | void remap_kernel_irq() { 20 | outp(0x20, 0x11); 21 | outp(0xA0, 0x11); 22 | outp(0x21, 0x20); 23 | outp(0xA1, 0x28); 24 | outp(0x21, 0x04); 25 | outp(0xA1, 0x02); 26 | outp(0x21, 0x01); 27 | outp(0xA1, 0x01); 28 | outp(0x21, 0x0); 29 | outp(0xA1, 0x0); 30 | } 31 | 32 | void init_irq() { 33 | remap_kernel_irq(); 34 | set_gate_idt(32, (uintptr_t)irq0, 0x08, 0x8E); 35 | set_gate_idt(33, (uintptr_t)irq1, 0x08, 0x8E); 36 | set_gate_idt(34, (uintptr_t)irq2, 0x08, 0x8E); 37 | set_gate_idt(35, (uintptr_t)irq3, 0x08, 0x8E); 38 | set_gate_idt(36, (uintptr_t)irq4, 0x08, 0x8E); 39 | set_gate_idt(37, (uintptr_t)irq5, 0x08, 0x8E); 40 | set_gate_idt(38, (uintptr_t)irq6, 0x08, 0x8E); 41 | set_gate_idt(39, (uintptr_t)irq7, 0x08, 0x8E); 42 | set_gate_idt(40, (uintptr_t)irq8, 0x08, 0x8E); 43 | set_gate_idt(41, (uintptr_t)irq9, 0x08, 0x8E); 44 | set_gate_idt(42, (uintptr_t)irq10, 0x08, 0x8E); 45 | set_gate_idt(43, (uintptr_t)irq11, 0x08, 0x8E); 46 | set_gate_idt(44, (uintptr_t)irq12, 0x08, 0x8E); 47 | set_gate_idt(45, (uintptr_t)irq13, 0x08, 0x8E); 48 | set_gate_idt(46, (uintptr_t)irq14, 0x08, 0x8E); 49 | set_gate_idt(47, (uintptr_t)irq15, 0x08, 0x8E); 50 | } 51 | 52 | void handler_irq(struct registers *regs) { 53 | void (*kernel_irq_handler)(struct registers * regs); 54 | 55 | kernel_irq_handler = kernel_routines_irq[regs->int_no - 32]; 56 | 57 | if (kernel_irq_handler) { 58 | kernel_irq_handler(regs); 59 | } 60 | 61 | if (regs->int_no >= 40) { 62 | outp(0xA0, 0x20); 63 | } 64 | 65 | outp(0x20, 0x20); 66 | } 67 | -------------------------------------------------------------------------------- /kernel/cpu/irq_asm.asm: -------------------------------------------------------------------------------- 1 | global irq0 2 | global irq1 3 | global irq2 4 | global irq3 5 | global irq4 6 | global irq5 7 | global irq6 8 | global irq7 9 | global irq8 10 | global irq9 11 | global irq10 12 | global irq11 13 | global irq12 14 | global irq13 15 | global irq14 16 | global irq15 17 | 18 | irq0: 19 | push byte 0 20 | push byte 32 21 | jmp irq_common_stub 22 | 23 | irq1: 24 | push byte 1 25 | push byte 33 26 | jmp irq_common_stub 27 | 28 | irq2: 29 | push byte 2 30 | push byte 34 31 | jmp irq_common_stub 32 | 33 | irq3: 34 | push byte 3 35 | push byte 35 36 | jmp irq_common_stub 37 | 38 | irq4: 39 | push byte 4 40 | push byte 36 41 | jmp irq_common_stub 42 | 43 | irq5: 44 | push byte 5 45 | push byte 37 46 | jmp irq_common_stub 47 | 48 | irq6: 49 | push byte 6 50 | push byte 38 51 | jmp irq_common_stub 52 | 53 | irq7: 54 | push byte 7 55 | push byte 39 56 | jmp irq_common_stub 57 | 58 | irq8: 59 | push byte 8 60 | push byte 40 61 | jmp irq_common_stub 62 | 63 | irq9: 64 | push byte 9 65 | push byte 41 66 | jmp irq_common_stub 67 | 68 | irq10: 69 | push byte 10 70 | push byte 42 71 | jmp irq_common_stub 72 | 73 | irq11: 74 | push byte 11 75 | push byte 43 76 | jmp irq_common_stub 77 | 78 | irq12: 79 | push byte 12 80 | push byte 44 81 | jmp irq_common_stub 82 | 83 | irq13: 84 | push byte 13 85 | push byte 45 86 | jmp irq_common_stub 87 | 88 | irq14: 89 | push byte 14 90 | push byte 46 91 | jmp irq_common_stub 92 | 93 | irq15: 94 | push byte 15 95 | push byte 47 96 | jmp irq_common_stub 97 | 98 | 99 | extern handler_irq 100 | 101 | irq_common_stub: 102 | pusha 103 | push ds 104 | push es 105 | push fs 106 | push gs 107 | mov ax, 0x10 108 | mov ds, ax 109 | mov es, ax 110 | mov fs, ax 111 | mov gs, ax 112 | mov eax, esp 113 | push eax 114 | mov eax, handler_irq 115 | call eax 116 | pop eax 117 | pop gs 118 | pop fs 119 | pop es 120 | pop ds 121 | popa 122 | add esp, 8 123 | iret 124 | -------------------------------------------------------------------------------- /kernel/kernel/ordered_array.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int8_t standard_lessthan_predicate(type_t a, type_t b) { 8 | return (a < b) ? 1 : 0; 9 | } 10 | 11 | ordered_array_t create_ordered_array(uint32_t max_size, 12 | lessthan_predicate_t less_than) { 13 | ordered_array_t to_ret; 14 | to_ret.array = (void *)kmalloc(max_size * sizeof(type_t)); 15 | memset(to_ret.array, 0, max_size * sizeof(type_t)); 16 | to_ret.size = 0; 17 | to_ret.max_size = max_size; 18 | to_ret.less_than = less_than; 19 | return to_ret; 20 | } 21 | 22 | ordered_array_t place_ordered_array(void *addr, uint32_t max_size, 23 | lessthan_predicate_t less_than) { 24 | ordered_array_t to_ret; 25 | to_ret.array = (type_t *)addr; 26 | memset(to_ret.array, 0, max_size * sizeof(type_t)); 27 | to_ret.size = 0; 28 | to_ret.max_size = max_size; 29 | to_ret.less_than = less_than; 30 | return to_ret; 31 | } 32 | 33 | void destroy_ordered_array(ordered_array_t *array) { 34 | kfree(array->array); 35 | } 36 | 37 | void insert_ordered_array(type_t item, ordered_array_t *array) { 38 | uint32_t iterator = 0; 39 | while (iterator < array->size && 40 | array->less_than(array->array[iterator], item)) { 41 | iterator++; 42 | } 43 | 44 | if (iterator == array->size) { 45 | array->array[array->size++] = item; 46 | } else { 47 | type_t tmp = array->array[iterator]; 48 | array->array[iterator] = item; 49 | while (iterator < array->size) { 50 | iterator++; 51 | type_t tmp2 = array->array[iterator]; 52 | array->array[iterator] = tmp; 53 | tmp = tmp2; 54 | } 55 | array->size++; 56 | } 57 | } 58 | 59 | type_t lookup_ordered_array(uint32_t i, ordered_array_t *array) { 60 | return array->array[i]; 61 | } 62 | 63 | void remove_ordered_array(uint32_t i, ordered_array_t *array) { 64 | while (i < array->size) { 65 | array->array[i] = array->array[i + 1]; 66 | i++; 67 | } 68 | array->size--; 69 | } 70 | -------------------------------------------------------------------------------- /kernel/kernel/panic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | bool assert_panic_in_progress; 13 | extern elf_t kernel_elf; 14 | extern task_t *current_task; 15 | 16 | void panic_remove_newline(char str[]) { 17 | for (int i = 0; i < strlen(str); i++) { 18 | if (str[i] == '\n') { 19 | str[i] = '\0'; 20 | } 21 | } 22 | } 23 | 24 | void panic_assert(const char *filename, int line, const char *desc) { 25 | assert_panic_in_progress = true; 26 | irq_disable(); 27 | 28 | printm("Assertion failed (%s) : %s:%d\n", desc, filename, line); 29 | panic("Assertion failed\n"); 30 | } 31 | 32 | void print_stack_trace() { 33 | uint32_t *ebp, *eip; 34 | __asm__ volatile("mov %%ebp, %0" : "=r"(ebp)); 35 | 36 | printm("Stack Trace: \n"); 37 | 38 | while (ebp) { 39 | eip = ebp + 1; 40 | printm(" [0x%x] %s\n", *eip, 41 | lookup_symbol_elf(*eip, &kernel_elf)); 42 | ebp = (uint32_t *)*ebp; 43 | } 44 | } 45 | 46 | void panic(char panicmessage[]) { 47 | struct registers *regs; 48 | 49 | if (!assert_panic_in_progress) { 50 | irq_disable(); 51 | } 52 | 53 | panic_remove_newline(panicmessage); 54 | settextcolor(LIGHT_GRAY, BLACK); 55 | 56 | /* This is based on Linux */ 57 | printm("Kernel Panic: not syncing, %s\n", panicmessage); 58 | printm("PID: %d Comm: %s\n", current_task->id, current_task->name); 59 | 60 | printm("Registers: "); 61 | printm("GS: 0x%x FS: 0x%x ES: 0x%x DS: 0x%x CS: 0x%x SS: 0x%x\n", regs->gs, 62 | regs->fs, regs->es, regs->ds, regs->cs, regs->ss); 63 | printm( 64 | "EDI: 0x%x ESI: 0x%x EBP: 0x%x ESP: 0x%x EBX: 0x%x EDX: 0x%x ECX: 0x%x EAX: 0x%x\n", 65 | regs->edi, regs->esi, regs->ebp, regs->esp, regs->ebx, regs->edx, 66 | regs->ecx, regs->eax); 67 | print_stack_trace(); 68 | printm("---[end Kernel Panic: not syncing, %s ]---", panicmessage); 69 | 70 | /* Halt the CPU */ 71 | __asm__ volatile("hlt"); 72 | } 73 | -------------------------------------------------------------------------------- /kernel/drivers/keyboard/keyboard.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | uint8_t keyboard_layout[128] = { 11 | 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', 12 | '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 13 | '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 14 | ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', 15 | '.', '/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0, 0, 17 | '+', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18 | }; 19 | 20 | void handler_keyboard() { 21 | uint8_t keyboard_key_scancode; 22 | 23 | keyboard_key_scancode = inp(KEYBOARD_DATA_PORT); 24 | 25 | if (keyboard_key_scancode & 0x80) { 26 | // Shift, Ctrl keys to be implemented 27 | 28 | } else { 29 | uint8_t input = keyboard_layout[keyboard_key_scancode]; 30 | putch(input); 31 | save_input_buf(input); 32 | } 33 | } 34 | 35 | char buf[40]; 36 | int buf_num = 0; 37 | char args[45]; 38 | int args_num = 0; 39 | bool is_arg = false; 40 | 41 | int save_input_buf(uint8_t input) { 42 | if (input == '\n') { 43 | run_command(buf, args); 44 | buf_num = 0; 45 | args_num = 0; 46 | is_arg = false; 47 | for (int i = 0; buf[i] != '\0'; i++) { 48 | buf[i] = '\0'; 49 | } 50 | for (int j = 0; args[j] != '\0'; j++) { 51 | args[j] = '\0'; 52 | } 53 | } else if (input == ' ') { 54 | if (is_arg) { 55 | args[args_num] = input; 56 | args_num++; 57 | return 0; 58 | } 59 | is_arg = true; 60 | return 0; 61 | } else { 62 | if (is_arg) { 63 | args[args_num] = input; 64 | args_num++; 65 | return 0; 66 | } 67 | buf[buf_num] = input; 68 | buf_num++; 69 | } 70 | } 71 | 72 | struct device kb_dev = {.name = "keyboard", .id = 1, .path = "/dev/keyboard"}; 73 | 74 | void init_keyboard() { 75 | install_irq_handler(1, handler_keyboard); 76 | add_device(&kb_dev); 77 | } 78 | -------------------------------------------------------------------------------- /kernel/init/main.c: -------------------------------------------------------------------------------- 1 | #include "multiboot.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | uint32_t initial_esp; 25 | extern uint32_t placement_address; 26 | elf_t kernel_elf; 27 | 28 | void welcome_screen() { 29 | settextcolor(LIGHT_YELLOW, BLACK); 30 | writestr( 31 | " -------------------------------------------------------------------\n"); 32 | writestr( 33 | "| Welcome to Platypus OS! |\n"); 34 | writestr( 35 | " -------------------------------------------------------------------\n"); 36 | settextcolor(BLUE, BLACK); 37 | writestr("OS: "); 38 | settextcolor(LIGHT_CYAN, BLACK); 39 | writestr("Platypus OS "); 40 | settextcolor(LIGHT_YELLOW, BLACK); 41 | writestr("x86_32 "); 42 | settextcolor(LIGHT_GREEN, BLACK); 43 | writestr("x86_64\n"); 44 | settextcolor(BLUE, BLACK); 45 | writestr("Kernel: "); 46 | settextcolor(LIGHT_GREEN, BLACK); 47 | writestr("Platypus\n"); 48 | settextcolor(BLUE, BLACK); 49 | writestr("Version: "); 50 | settextcolor(LIGHT_RED, BLACK); 51 | writestr("0.11-rc3\n"); 52 | reset_text_color(); 53 | writestr("\n"); 54 | } 55 | 56 | void kernel_main(multiboot_info_t *mboot_info, uint32_t initial_stack) { 57 | initial_esp = initial_stack; 58 | 59 | init_vga(); 60 | 61 | init_gdt(); 62 | init_idt(); 63 | init_isr(); 64 | init_irq(); 65 | printm("GDT, IDT, ISR and IRQ initialized\n"); 66 | 67 | init_pit(100); 68 | init_keyboard(); 69 | init_pcspkr(); 70 | init_serial(); 71 | init_rtc(); 72 | printm("Drivers initialized\n"); 73 | 74 | kernel_elf = elf_from_multiboot(mboot_info->u.elf_sec); 75 | 76 | ASSERT(mboot_info->mods_count > 0); 77 | uint32_t initrd = *((uint32_t *)mboot_info->mods_addr); 78 | uint32_t initrd_end = *(uint32_t *)(mboot_info->mods_addr + 4); 79 | placement_address = initrd_end; 80 | 81 | init_paging(); 82 | init_tasking(); 83 | printm("Paging and tasking initialized\n"); 84 | 85 | init_device_manager(); 86 | 87 | cls(); 88 | welcome_screen(); 89 | 90 | writestr("Kernel command line: %s\n", mboot_info->cmdline); 91 | uint32_t memsize = (mboot_info->mem_lower + mboot_info->mem_upper) / 1024; 92 | writestr("Total memory: %d MB\n", memsize); 93 | writestr("Initrd at address: %x\n", initrd); 94 | detect_drives_floppy(); 95 | writestr("\n"); 96 | 97 | vfs_root = init_initrd(initrd); 98 | 99 | init_terminal(); 100 | } 101 | -------------------------------------------------------------------------------- /kernel/drivers/floppy/floppy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static const char *drive_types[7] = {"no drive", "360 KB 5.25 Drive", 9 | "1.2 MB 5.25 Drive", "720 KB 3.5 Drive", 10 | "1.44 MB 3.5 Drive", "2.88 MB 3.5 Drive", 11 | "unknown drive"}; 12 | 13 | static const char *drive_status[] = {0, "error", "invalid", "drive"}; 14 | 15 | int floppy_motor_state = 0; 16 | 17 | void detect_drives_floppy() { 18 | outp(0x70, 0x10); 19 | uint8_t drives = inp(0x71); 20 | writestr("Floppy drive 0: %s, 1: %s\n", drive_types[drives >> 4], 21 | drive_types[drives & 0xF]); 22 | } 23 | 24 | void write_command_floppy(int base, char command) { 25 | for (int i = 0; i < 300; i++) { 26 | sleep_pit(1); 27 | 28 | if (0x80 & inp(base + MAIN_STATUS_REGISTER)) { 29 | return (void)outp(base + DATA_FIFO, command); 30 | } 31 | } 32 | 33 | printm("Floppy: write_command_floppy: timeout\n"); 34 | } 35 | 36 | uint8_t read_data_floppy(int base) { 37 | for (int i = 0; i < 300; i++) { 38 | sleep_pit(1); 39 | 40 | if (0x80 & inp(base + MAIN_STATUS_REGISTER)) { 41 | return inp(base + DATA_FIFO); 42 | } 43 | } 44 | 45 | printm("Floppy: read_data_floppy: timeout\n"); 46 | } 47 | 48 | void check_interrupt_floppy(int base, int *st0, int *cyl) { 49 | write_command_floppy(base, SENSE_INTERRUPT); 50 | *st0 = read_data_floppy(base); 51 | *cyl = read_data_floppy(base); 52 | } 53 | 54 | int calibrate_floppy(int base) { 55 | int st0, cyl = -1; 56 | 57 | motor_floppy(base, MOTOR_ON); 58 | 59 | for (int i = 0; i < 10; i++) { 60 | write_command_floppy(base, RECALIBRATE); 61 | write_command_floppy(base, 0); 62 | sleep_pit(3); 63 | check_interrupt_floppy(base, &st0, &cyl); 64 | 65 | if (st0 & 0xC0) { 66 | printm("Floppy: calibrate: status = %s\n", drive_status[st0 >> 6]); 67 | continue; 68 | } 69 | 70 | if (!cyl) { 71 | motor_floppy(base, MOTOR_OFF); 72 | return 0; 73 | } 74 | } 75 | 76 | printm("Floppy: error: cannot calibrate\n"); 77 | motor_floppy(base, MOTOR_OFF); 78 | return -1; 79 | } 80 | 81 | int reset_floppy(int base) { 82 | outp(base + DIGITAL_OUTPUT_REGISTER, 0x00); 83 | outp(base + DIGITAL_OUTPUT_REGISTER, 0x0C); 84 | 85 | sleep_pit(3); 86 | 87 | int st0, cyl; 88 | check_interrupt_floppy(base, &st0, &cyl); 89 | 90 | outp(base + CONFIGURATION_CONTROL_REGISTER, 0x00); 91 | write_command_floppy(base, SPECIFY); 92 | write_command_floppy(base, 0xDF); 93 | write_command_floppy(base, 0x02); 94 | 95 | if (calibrate_floppy(base)) { 96 | return -1; 97 | } 98 | } 99 | 100 | void motor_floppy(int base, int state) { 101 | if (state) { 102 | if (!floppy_motor_state) { 103 | outp(base + DIGITAL_OUTPUT_REGISTER, 0x1C); 104 | sleep_pit(1); 105 | } 106 | floppy_motor_state = MOTOR_ON; 107 | } else { 108 | if (floppy_motor_state == MOTOR_WAIT) { 109 | printm("Floppy: notice: motor is already waiting\n"); 110 | } 111 | floppy_motor_state = MOTOR_WAIT; 112 | } 113 | } 114 | 115 | void kill_motor_floppy(int base) { 116 | outp(base + DIGITAL_OUTPUT_REGISTER, 0x0C); 117 | floppy_motor_state = MOTOR_OFF; 118 | } 119 | -------------------------------------------------------------------------------- /kernel/cpu/isr.c: -------------------------------------------------------------------------------- 1 | #include "isr.h" 2 | #include "idt.h" 3 | #include 4 | #include 5 | 6 | void init_isr() { 7 | 8 | set_gate_idt(0, (uintptr_t)isr0, 0x08, 0x8E); 9 | set_gate_idt(1, (uintptr_t)isr1, 0x08, 0x8E); 10 | set_gate_idt(2, (uintptr_t)isr2, 0x08, 0x8E); 11 | set_gate_idt(3, (uintptr_t)isr3, 0x08, 0x8E); 12 | set_gate_idt(4, (uintptr_t)isr4, 0x08, 0x8E); 13 | set_gate_idt(5, (uintptr_t)isr5, 0x08, 0x8E); 14 | set_gate_idt(6, (uintptr_t)isr6, 0x08, 0x8E); 15 | set_gate_idt(7, (uintptr_t)isr7, 0x08, 0x8E); 16 | set_gate_idt(8, (uintptr_t)isr8, 0x08, 0x8E); 17 | set_gate_idt(9, (uintptr_t)isr9, 0x08, 0x8E); 18 | set_gate_idt(10, (uintptr_t)isr10, 0x08, 0x8E); 19 | set_gate_idt(11, (uintptr_t)isr11, 0x08, 0x8E); 20 | set_gate_idt(12, (uintptr_t)isr12, 0x08, 0x8E); 21 | set_gate_idt(13, (uintptr_t)isr13, 0x08, 0x8E); 22 | set_gate_idt(14, (uintptr_t)isr14, 0x08, 0x8E); 23 | set_gate_idt(15, (uintptr_t)isr15, 0x08, 0x8E); 24 | set_gate_idt(16, (uintptr_t)isr16, 0x08, 0x8E); 25 | set_gate_idt(17, (uintptr_t)isr17, 0x08, 0x8E); 26 | set_gate_idt(18, (uintptr_t)isr18, 0x08, 0x8E); 27 | set_gate_idt(19, (uintptr_t)isr19, 0x08, 0x8E); 28 | set_gate_idt(20, (uintptr_t)isr20, 0x08, 0x8E); 29 | set_gate_idt(21, (uintptr_t)isr21, 0x08, 0x8E); 30 | set_gate_idt(22, (uintptr_t)isr22, 0x08, 0x8E); 31 | set_gate_idt(23, (uintptr_t)isr23, 0x08, 0x8E); 32 | set_gate_idt(24, (uintptr_t)isr24, 0x08, 0x8E); 33 | set_gate_idt(25, (uintptr_t)isr25, 0x08, 0x8E); 34 | set_gate_idt(26, (uintptr_t)isr26, 0x08, 0x8E); 35 | set_gate_idt(27, (uintptr_t)isr27, 0x08, 0x8E); 36 | set_gate_idt(28, (uintptr_t)isr28, 0x08, 0x8E); 37 | set_gate_idt(29, (uintptr_t)isr29, 0x08, 0x8E); 38 | set_gate_idt(30, (uintptr_t)isr30, 0x08, 0x8E); 39 | set_gate_idt(31, (uintptr_t)isr31, 0x08, 0x8E); 40 | } 41 | 42 | const char *exceptions[] = {"Division by zero", 43 | "Debug", 44 | "Non Maskable Interrupt", 45 | "Breakpoint exception", 46 | "Into Detected Overflow", 47 | "Out of Bounds exception", 48 | "Invalid Opcode exception", 49 | "No Coprocessor exception", 50 | 51 | "Double Fault exception", 52 | "Coprocessor Segment Overrun", 53 | "Bad TSS exception", 54 | "Segment Not Present", 55 | "Stack Fault exception", 56 | "General Protection Fault", 57 | "Page Fault exception", 58 | "Unknown Interrupt exception", 59 | 60 | "Coprocessor Fault exception", 61 | "Alignment Check exception", 62 | "Machine Check exception", 63 | "Reserved", 64 | "Reserved", 65 | "Reserved", 66 | "Reserved", 67 | "Reserved", 68 | 69 | "Reserved", 70 | "Reserved", 71 | "Reserved", 72 | "Reserved", 73 | "Reserved", 74 | "Reserved", 75 | "Reserved", 76 | "Reserved"}; 77 | 78 | void handler_isr(struct registers *regs) { 79 | 80 | if (regs->int_no <= 31) { 81 | panic(exceptions[regs->int_no]); 82 | for (;;) 83 | ; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /kernel/initrd/initrd.c: -------------------------------------------------------------------------------- 1 | #include "initrd.h" 2 | #include 3 | #include 4 | #include 5 | 6 | initrd_header_t *initrd_header; 7 | initrd_file_header_t *file_headers; 8 | vfs_node_t *initrd_root; 9 | vfs_node_t *initrd_dev; 10 | vfs_node_t *root_nodes; 11 | int nroot_nodes; 12 | 13 | struct vfs_dirent dirent; 14 | 15 | uint32_t initrd_read(vfs_node_t *node, uint32_t offset, uint32_t size, 16 | uint8_t *buffer) { 17 | initrd_file_header_t header = file_headers[node->inode]; 18 | 19 | if (offset > header.length) { 20 | return 0; 21 | } 22 | if (offset + size > header.length) { 23 | size = header.length - offset; 24 | } 25 | 26 | memcpy(buffer, (uint8_t *)(header.offset + offset), size); 27 | 28 | return size; 29 | } 30 | 31 | struct vfs_dirent *initrd_readdir(vfs_node_t *node, uint32_t index) { 32 | if (node == initrd_root && index == 0) { 33 | strcpy(dirent.name, "dev"); 34 | dirent.name[3] = 0; 35 | dirent.inode_num = 0; 36 | return &dirent; 37 | } 38 | 39 | if (index - 1 >= nroot_nodes) { 40 | return 0; 41 | } 42 | 43 | strcpy(dirent.name, root_nodes[index - 1].name); 44 | dirent.name[strlen(root_nodes[index - 1].name)] = 0; 45 | dirent.inode_num = root_nodes[index - 1].inode; 46 | 47 | return &dirent; 48 | } 49 | 50 | vfs_node_t *initrd_finddir(vfs_node_t *node, char *name) { 51 | if (node == initrd_root && !strcmp(name, "dev")) { 52 | return initrd_dev; 53 | } 54 | 55 | for (int i = 0; i < nroot_nodes; i++) { 56 | if (strcmp(name, root_nodes[i].name) == 0) { 57 | return &root_nodes[i]; 58 | } 59 | } 60 | 61 | return 0; 62 | } 63 | 64 | vfs_node_t *init_initrd(uint32_t location) { 65 | 66 | initrd_header = (initrd_header_t *)location; 67 | file_headers = (initrd_file_header_t *)(location + sizeof(initrd_header_t)); 68 | 69 | initrd_root = (vfs_node_t *)kmalloc(sizeof(vfs_node_t)); 70 | strcpy(initrd_root->name, "initrd"); 71 | initrd_root->mask = initrd_root->uid = initrd_root->gid = initrd_root->inode = 72 | initrd_root->length = 0; 73 | initrd_root->flags = VFS_DIR; 74 | initrd_root->read = 0; 75 | initrd_root->write = 0; 76 | initrd_root->open = 0; 77 | initrd_root->close = 0; 78 | initrd_root->readdir = &initrd_readdir; 79 | initrd_root->finddir = &initrd_finddir; 80 | initrd_root->ptr = 0; 81 | initrd_root->impl = 0; 82 | 83 | initrd_dev = (vfs_node_t *)kmalloc(sizeof(vfs_node_t)); 84 | strcpy(initrd_dev->name, "dev"); 85 | initrd_dev->mask = initrd_dev->uid = initrd_dev->gid = initrd_dev->inode = 86 | initrd_dev->length = 0; 87 | initrd_dev->flags = VFS_DIR; 88 | initrd_dev->read = 0; 89 | initrd_dev->write = 0; 90 | initrd_dev->open = 0; 91 | initrd_dev->close = 0; 92 | initrd_dev->readdir = &initrd_readdir; 93 | initrd_dev->finddir = &initrd_finddir; 94 | initrd_dev->ptr = 0; 95 | initrd_dev->impl = 0; 96 | 97 | root_nodes = 98 | (vfs_node_t *)kmalloc(sizeof(vfs_node_t) * initrd_header->nfiles); 99 | nroot_nodes = initrd_header->nfiles; 100 | 101 | for (int i = 0; i < initrd_header->nfiles; i++) { 102 | file_headers[i].offset += location; 103 | strcpy(root_nodes[i].name, &file_headers[i].name); 104 | root_nodes[i].mask = root_nodes[i].uid = root_nodes[i].gid = 0; 105 | root_nodes[i].length = file_headers[i].length; 106 | root_nodes[i].inode = i; 107 | root_nodes[i].flags = VFS_FILE; 108 | root_nodes[i].read = &initrd_read; 109 | root_nodes[i].write = 0; 110 | root_nodes[i].readdir = 0; 111 | root_nodes[i].finddir = 0; 112 | root_nodes[i].open = 0; 113 | root_nodes[i].close = 0; 114 | root_nodes[i].impl = 0; 115 | } 116 | 117 | return initrd_root; 118 | } 119 | -------------------------------------------------------------------------------- /kernel/cpu/isr_asm.asm: -------------------------------------------------------------------------------- 1 | global isr0 2 | global isr1 3 | global isr2 4 | global isr3 5 | global isr4 6 | global isr5 7 | global isr6 8 | global isr7 9 | global isr8 10 | global isr9 11 | global isr10 12 | global isr11 13 | global isr12 14 | global isr13 15 | global isr14 16 | global isr15 17 | global isr16 18 | global isr17 19 | global isr18 20 | global isr19 21 | global isr20 22 | global isr21 23 | global isr22 24 | global isr23 25 | global isr24 26 | global isr25 27 | global isr26 28 | global isr27 29 | global isr28 30 | global isr29 31 | global isr30 32 | global isr31 33 | 34 | isr0: 35 | push byte 0 36 | push byte 0 37 | jmp isr_common_stub 38 | 39 | isr1: 40 | push byte 0 41 | push byte 1 42 | jmp isr_common_stub 43 | 44 | isr2: 45 | push byte 0 46 | push byte 2 47 | jmp isr_common_stub 48 | 49 | isr3: 50 | push byte 0 51 | push byte 3 52 | jmp isr_common_stub 53 | 54 | isr4: 55 | push byte 0 56 | push byte 4 57 | jmp isr_common_stub 58 | 59 | isr5: 60 | push byte 0 61 | push byte 5 62 | jmp isr_common_stub 63 | 64 | isr6: 65 | push byte 0 66 | push byte 6 67 | jmp isr_common_stub 68 | 69 | isr7: 70 | push byte 0 71 | push byte 7 72 | jmp isr_common_stub 73 | 74 | isr8: 75 | push byte 8 76 | jmp isr_common_stub 77 | 78 | isr9: 79 | push byte 0 80 | push byte 9 81 | jmp isr_common_stub 82 | 83 | isr10: 84 | push byte 10 85 | jmp isr_common_stub 86 | 87 | isr11: 88 | push byte 11 89 | jmp isr_common_stub 90 | 91 | isr12: 92 | push byte 12 93 | jmp isr_common_stub 94 | 95 | isr13: 96 | push byte 13 97 | jmp isr_common_stub 98 | 99 | isr14: 100 | push byte 14 101 | jmp isr_common_stub 102 | 103 | isr15: 104 | push byte 0 105 | push byte 15 106 | jmp isr_common_stub 107 | 108 | isr16: 109 | push byte 0 110 | push byte 16 111 | jmp isr_common_stub 112 | 113 | isr17: 114 | push byte 0 115 | push byte 17 116 | jmp isr_common_stub 117 | 118 | isr18: 119 | push byte 0 120 | push byte 18 121 | jmp isr_common_stub 122 | 123 | isr19: 124 | push byte 0 125 | push byte 19 126 | jmp isr_common_stub 127 | 128 | isr20: 129 | push byte 0 130 | push byte 20 131 | jmp isr_common_stub 132 | 133 | isr21: 134 | push byte 0 135 | push byte 21 136 | jmp isr_common_stub 137 | 138 | isr22: 139 | push byte 0 140 | push byte 22 141 | jmp isr_common_stub 142 | 143 | isr23: 144 | push byte 0 145 | push byte 23 146 | jmp isr_common_stub 147 | 148 | isr24: 149 | push byte 0 150 | push byte 24 151 | jmp isr_common_stub 152 | 153 | isr25: 154 | push byte 0 155 | push byte 25 156 | jmp isr_common_stub 157 | 158 | isr26: 159 | push byte 0 160 | push byte 26 161 | jmp isr_common_stub 162 | 163 | isr27: 164 | push byte 0 165 | push byte 27 166 | jmp isr_common_stub 167 | 168 | isr28: 169 | push byte 0 170 | push byte 28 171 | jmp isr_common_stub 172 | 173 | isr29: 174 | push byte 0 175 | push byte 29 176 | jmp isr_common_stub 177 | 178 | isr30: 179 | push byte 0 180 | push byte 30 181 | jmp isr_common_stub 182 | 183 | isr31: 184 | push byte 0 185 | push byte 31 186 | jmp isr_common_stub 187 | 188 | 189 | extern handler_isr 190 | 191 | isr_common_stub: 192 | pusha 193 | push ds 194 | push es 195 | push fs 196 | push gs 197 | mov ax, 0x10 198 | mov ds, ax 199 | mov es, ax 200 | mov fs, ax 201 | mov gs, ax 202 | mov eax, esp 203 | push eax 204 | mov eax, handler_isr 205 | call eax 206 | pop eax 207 | pop gs 208 | pop fs 209 | pop es 210 | pop ds 211 | popa 212 | add esp, 8 213 | iret 214 | -------------------------------------------------------------------------------- /kernel/drivers/vga/vga.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | uint16_t *textmemptr; 8 | int attrib = 0x0F; 9 | int csr_x = 0, csr_y = 0; 10 | 11 | void scroll() { 12 | unsigned blank, temp; 13 | 14 | blank = 0x20 | (attrib << 8); 15 | 16 | if (csr_y >= 25) { 17 | temp = csr_y - 25 + 1; 18 | memcpy(textmemptr, textmemptr + temp * 80, (25 - temp) * 80 * 2); 19 | memsetw(textmemptr + (25 - temp) * 80, blank, 80); 20 | csr_y = 25 - 1; 21 | } 22 | } 23 | 24 | void move_csr() { 25 | unsigned temp; 26 | 27 | temp = csr_y * 80 + csr_x; 28 | 29 | outp(0x3D4, 14); 30 | outp(0x3D5, temp >> 8); 31 | outp(0x3D4, 15); 32 | outp(0x3D5, temp); 33 | } 34 | 35 | void disable_csr() { 36 | outp(0x3D4, 0x0A); 37 | outp(0x3D5, 0x20); 38 | } 39 | 40 | uint16_t get_csr_position() { 41 | uint16_t pos = 0; 42 | outp(0x3D4, 0x0F); 43 | pos |= inp(0x3D5); 44 | outp(0x3D4, 0x0E); 45 | pos |= ((uint16_t)inp(0x3D5)) << 8; 46 | return pos; 47 | } 48 | 49 | void cls() { 50 | unsigned blank; 51 | 52 | blank = 0x20 | (attrib << 8); 53 | 54 | for (int i = 0; i < 25; i++) { 55 | memsetw(textmemptr + i * 80, blank, 80); 56 | } 57 | 58 | csr_x = 0; 59 | csr_y = 0; 60 | move_csr(); 61 | } 62 | 63 | void putch(uint8_t c) { 64 | uint16_t *where; 65 | unsigned att = attrib << 8; 66 | 67 | if (c == 0x08) { 68 | if (csr_x != 0) { 69 | csr_x--; 70 | } 71 | } 72 | 73 | else if (c == 0x09) { 74 | csr_x = (csr_x + 8) & ~(8 - 1); 75 | } 76 | 77 | else if (c == '\r') { 78 | csr_x = 0; 79 | } 80 | 81 | else if (c == '\n') { 82 | csr_x = 0; 83 | csr_y++; 84 | } 85 | 86 | else if (c >= ' ') { 87 | where = textmemptr + (csr_y * 80 + csr_x); 88 | *where = c | att; 89 | csr_x++; 90 | } 91 | 92 | if (csr_x >= 80) { 93 | csr_x = 0; 94 | csr_y++; 95 | } 96 | 97 | scroll(); 98 | move_csr(); 99 | } 100 | 101 | void writestr(const char *fmt, ...) { 102 | va_list ap; 103 | char *p, *sval; 104 | int ival; 105 | int xval; 106 | 107 | va_start(ap, fmt); 108 | 109 | for (p = fmt; *p; p++) { 110 | if (*p != '%') { 111 | putch(*p); 112 | continue; 113 | } 114 | 115 | switch (*++p) { 116 | case 'd': 117 | ival = va_arg(ap, int); 118 | writeint(ival); 119 | break; 120 | case 's': 121 | for (sval = va_arg(ap, char *); *sval; sval++) { 122 | putch(*sval); 123 | } 124 | break; 125 | case 'x': 126 | xval = va_arg(ap, int); 127 | writehex(xval); 128 | break; 129 | default: 130 | putch(*p); 131 | break; 132 | } 133 | } 134 | 135 | va_end(ap); 136 | } 137 | 138 | void writeint(uint32_t num) { 139 | int a = num; 140 | int i = 0; 141 | char c[30]; 142 | 143 | if (num == 0) { 144 | writestr("0"); 145 | return; 146 | } 147 | 148 | while (a > 0) { 149 | c[i] = '0' + a % 10; 150 | a /= 10; 151 | i++; 152 | } 153 | 154 | c[i] = 0; 155 | 156 | char c2[30]; 157 | c2[i--] = 0; 158 | int j = 0; 159 | 160 | while (i >= 0) { 161 | c2[i--] = c[j++]; 162 | } 163 | 164 | writestr(c2); 165 | } 166 | 167 | void writehex(uint32_t num) { 168 | signed int t; 169 | 170 | writestr("0x"); 171 | 172 | int no_zeroes = 1; 173 | 174 | for (int i = 28; i > 0; i -= 4) { 175 | t = (num >> i) & 0xF; 176 | if (t == 0 && no_zeroes != 0) { 177 | continue; 178 | } 179 | 180 | if (t >= 0xA) { 181 | no_zeroes = 0; 182 | putch(t - 0xA + 'a'); 183 | } else { 184 | no_zeroes = 0; 185 | putch(t + '0'); 186 | } 187 | } 188 | 189 | t = num & 0xF; 190 | if (t >= 0xA) { 191 | putch(t - 0xA + 'a'); 192 | } else { 193 | putch(t + '0'); 194 | } 195 | } 196 | 197 | void settextcolor(uint8_t forecolor, uint8_t backcolor) { 198 | attrib = (backcolor << 4) | (forecolor & 0x0F); 199 | } 200 | 201 | void reset_text_color() { 202 | settextcolor(WHITE, BLACK); 203 | } 204 | 205 | void init_vga() { 206 | textmemptr = (uint16_t *)0xB8000; 207 | cls(); 208 | } 209 | -------------------------------------------------------------------------------- /kernel/kernel/task.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | volatile task_t *current_task; 8 | volatile task_t *ready_queue; 9 | 10 | extern page_dir_t *kernel_directory; 11 | extern page_dir_t *current_directory; 12 | extern uint32_t initial_esp; 13 | 14 | uint32_t next_pid = 1; 15 | 16 | void move_stack(void *new_stack_start, uint32_t size) { 17 | uint32_t i; 18 | for (i = (uint32_t)new_stack_start; i >= ((uint32_t)new_stack_start - size); 19 | i -= 0x1000) { 20 | alloc_frame(get_page(i, 1, current_directory), 0, 1); 21 | } 22 | 23 | uint32_t pd_addr; 24 | __asm__ volatile("mov %%cr3, %0" : "=r"(pd_addr)); 25 | __asm__ volatile("mov %0, %%cr3" : : "r"(pd_addr)); 26 | 27 | uint32_t old_stack_pointer; 28 | __asm__ volatile("mov %%esp, %0" : "=r"(old_stack_pointer)); 29 | uint32_t old_base_pointer; 30 | __asm__ volatile("mov %%ebp, %0" : "=r"(old_base_pointer)); 31 | uint32_t offset = (uint32_t)new_stack_start - initial_esp; 32 | 33 | uint32_t new_stack_pointer = old_stack_pointer + offset; 34 | uint32_t new_base_pointer = old_base_pointer + offset; 35 | 36 | memcpy((void *)new_stack_pointer, (void *)old_stack_pointer, 37 | initial_esp - old_stack_pointer); 38 | 39 | for (i = (uint32_t)new_stack_start; i > (uint32_t)new_stack_start - size; 40 | i -= 4) { 41 | uint32_t tmp = *(uint32_t *)i; 42 | if ((old_stack_pointer < tmp) && (tmp < initial_esp)) { 43 | tmp = tmp + offset; 44 | uint32_t *tmp2 = (uint32_t *)i; 45 | *tmp2 = tmp; 46 | } 47 | } 48 | 49 | __asm__ volatile("mov %0, %%esp" : : "r"(new_stack_pointer)); 50 | __asm__ volatile("mov %0, %%ebp" : : "r"(new_base_pointer)); 51 | } 52 | 53 | void switch_task() { 54 | if (!current_task) { 55 | return; 56 | } 57 | 58 | uint32_t esp, ebp, eip; 59 | 60 | __asm__ volatile("mov %%esp, %0" : "=r"(esp)); 61 | __asm__ volatile("mov %%ebp, %0" : "=r"(ebp)); 62 | 63 | eip = read_eip(); 64 | 65 | if (eip == 0x12345) { 66 | return; 67 | } 68 | 69 | current_task->eip = eip; 70 | current_task->esp = esp; 71 | current_task->ebp = ebp; 72 | 73 | current_task = current_task->next; 74 | 75 | if (!current_task) { 76 | current_task = ready_queue; 77 | } 78 | 79 | eip = current_task->eip; 80 | esp = current_task->esp; 81 | ebp = current_task->ebp; 82 | 83 | current_directory = current_task->page_directory; 84 | 85 | do_task_switch(eip, current_directory->physicalAddr, ebp, esp); 86 | } 87 | 88 | int fork() { 89 | irq_disable(); 90 | 91 | task_t *parent_task = (task_t *)current_task; 92 | page_dir_t *directory = clone_directory(current_directory); 93 | 94 | task_t *new_task = (task_t *)kmalloc(sizeof(task_t)); 95 | 96 | new_task->id = next_pid++; 97 | new_task->esp = new_task->ebp = 0; 98 | new_task->eip = 0; 99 | new_task->page_directory = directory; 100 | new_task->next = 0; 101 | 102 | task_t *tmp_task = (task_t *)ready_queue; 103 | 104 | while (tmp_task->next) { 105 | tmp_task = tmp_task->next; 106 | } 107 | 108 | tmp_task->next = new_task; 109 | 110 | uint32_t eip = read_eip(); 111 | 112 | if (current_task == parent_task) { 113 | uint32_t esp; 114 | __asm__ volatile("mov %%esp, %0" : "=r"(esp)); 115 | uint32_t ebp; 116 | __asm__ volatile("mov %%ebp, %0" : "=r"(ebp)); 117 | new_task->esp = esp; 118 | new_task->ebp = ebp; 119 | new_task->eip = eip; 120 | 121 | irq_enable(); 122 | return new_task->id; 123 | } else { 124 | irq_enable(); 125 | return 0; 126 | } 127 | } 128 | 129 | int getpid() { 130 | return current_task->id; 131 | } 132 | 133 | void init_tasking() { 134 | irq_disable(); 135 | 136 | move_stack((void *)0xE0000000, 0x2000); 137 | 138 | current_task = ready_queue = (task_t *)kmalloc(sizeof(task_t)); 139 | current_task->name = "init"; 140 | current_task->id = next_pid++; 141 | current_task->esp = current_task->ebp = 0; 142 | current_task->eip = 0; 143 | current_task->page_directory = current_directory; 144 | current_task->next = 0; 145 | 146 | irq_enable(); 147 | } 148 | -------------------------------------------------------------------------------- /kernel/mm/paging.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | page_dir_t *kernel_directory = 0; 8 | page_dir_t *current_directory = 0; 9 | 10 | uint32_t *frames; 11 | uint32_t nframes; 12 | 13 | extern uint32_t placement_address; 14 | extern heap_t *kheap; 15 | 16 | void set_frame(uint32_t frame_addr) { 17 | uint32_t frame = frame_addr / 0x1000; 18 | uint32_t idx = INDEX_FROM_BIT(frame); 19 | uint32_t off = OFFSET_FROM_BIT(frame); 20 | frames[idx] |= (0x1 << off); 21 | } 22 | 23 | void clear_frame(uint32_t frame_addr) { 24 | uint32_t frame = frame_addr / 0x1000; 25 | uint32_t idx = INDEX_FROM_BIT(frame); 26 | uint32_t off = OFFSET_FROM_BIT(frame); 27 | frames[idx] &= ~(0x1 << off); 28 | } 29 | 30 | uint32_t test_frame(uint32_t frame_addr) { 31 | uint32_t frame = frame_addr / 0x1000; 32 | uint32_t idx = INDEX_FROM_BIT(frame); 33 | uint32_t off = OFFSET_FROM_BIT(frame); 34 | return (frames[idx] & (0x1 << off)); 35 | } 36 | 37 | uint32_t first_frame() { 38 | uint32_t i, j; 39 | for (i = 0; i < INDEX_FROM_BIT(nframes); i++) { 40 | if (frames[i] != 0xFFFFFFFF) { 41 | for (j = 0; j < 32; j++) { 42 | uint32_t toTest = 0x1 << j; 43 | if (!(frames[i] & toTest)) { 44 | return i * 4 * 8 + j; 45 | } 46 | } 47 | } 48 | } 49 | } 50 | 51 | void alloc_frame(page_t *page, int is_kernel, int is_writeable) { 52 | if (page->frame != 0) { 53 | return; 54 | } else { 55 | uint32_t idx = first_frame(); 56 | if (idx == (uint32_t)-1) { 57 | panic("No free frames found!\n"); 58 | } 59 | set_frame(idx * 0x1000); 60 | page->present = 1; 61 | page->rw = (is_writeable) ? 1 : 0; 62 | page->user = (is_kernel) ? 0 : 1; 63 | page->frame = idx; 64 | } 65 | } 66 | 67 | void free_frame(page_t *page) { 68 | uint32_t frame; 69 | if (!(frame = page->frame)) { 70 | return; 71 | } else { 72 | clear_frame(frame); 73 | page->frame = 0x0; 74 | } 75 | } 76 | 77 | void switch_page_directory(page_dir_t *dir) { 78 | current_directory = dir; 79 | __asm__ volatile("mov %0, %%cr3" ::"r"(dir->physicalAddr)); 80 | uint32_t cr0; 81 | __asm__ volatile("mov %%cr0, %0" : "=r"(cr0)); 82 | cr0 |= 0x80000000; 83 | __asm__ volatile("mov %0, %%cr0" ::"r"(cr0)); 84 | } 85 | 86 | page_t *get_page(uint32_t address, int make, page_dir_t *dir) { 87 | address /= 0x1000; 88 | uint32_t table_idx = address / 1024; 89 | if (dir->tables[table_idx]) { 90 | return &dir->tables[table_idx]->pages[address % 1024]; 91 | } else if (make) { 92 | uint32_t tmp; 93 | dir->tables[table_idx] = 94 | (page_table_t *)kmalloc_ap(sizeof(page_table_t), &tmp); 95 | dir->tablesPhysical[table_idx] = tmp | 0x7; 96 | return &dir->tables[table_idx]->pages[address % 1024]; 97 | } else { 98 | return 0; 99 | } 100 | } 101 | 102 | static page_table_t *clone_table(page_table_t *src, uint32_t *physAddr) { 103 | page_table_t *table = 104 | (page_table_t *)kmalloc_ap(sizeof(page_table_t), physAddr); 105 | memset(table, 0, sizeof(page_dir_t)); 106 | 107 | for (int i = 0; i < 1024; i++) { 108 | if (src->pages[i].frame) { 109 | alloc_frame(&table->pages[i], 0, 0); 110 | 111 | if (src->pages[i].present) { 112 | table->pages[i].present = 1; 113 | } 114 | if (src->pages[i].rw) { 115 | table->pages[i].rw = 1; 116 | } 117 | if (src->pages[i].user) { 118 | table->pages[i].user = 1; 119 | } 120 | if (src->pages[i].accessed) { 121 | table->pages[i].accessed = 1; 122 | } 123 | if (src->pages[i].dirty) { 124 | table->pages[i].dirty = 1; 125 | } 126 | copy_page_physical(src->pages[i].frame * 0x1000, 127 | table->pages[i].frame * 0x1000); 128 | } 129 | } 130 | return table; 131 | } 132 | 133 | page_dir_t *clone_directory(page_dir_t *src) { 134 | uint32_t phys; 135 | page_dir_t *dir = (page_dir_t *)kmalloc_ap(sizeof(page_dir_t), &phys); 136 | memset(dir, 0, sizeof(page_dir_t)); 137 | 138 | uint32_t offset = (uint32_t)dir->tablesPhysical - (uint32_t)dir; 139 | dir->physicalAddr = phys + offset; 140 | 141 | for (int i = 0; i < 1024; i++) { 142 | if (!src->tables[i]) { 143 | continue; 144 | } 145 | 146 | if (kernel_directory->tables[i] == src->tables[i]) { 147 | dir->tables[i] = src->tables[i]; 148 | dir->tablesPhysical[i] = src->tablesPhysical[i]; 149 | } else { 150 | uint32_t phys; 151 | dir->tables[i] = clone_table(src->tables[i], &phys); 152 | dir->tablesPhysical[i] = phys | 0x07; 153 | } 154 | } 155 | return dir; 156 | } 157 | 158 | void init_paging() { 159 | uint32_t mem_end_page = 0x1000000; 160 | 161 | nframes = mem_end_page / 0x1000; 162 | frames = (uint32_t *)kmalloc(INDEX_FROM_BIT(nframes)); 163 | memset(frames, 0, INDEX_FROM_BIT(nframes)); 164 | 165 | uint32_t phys; 166 | kernel_directory = (page_dir_t *)kmalloc_a(sizeof(page_dir_t)); 167 | memset(kernel_directory, 0, sizeof(page_dir_t)); 168 | kernel_directory->physicalAddr = (uint32_t)kernel_directory->tablesPhysical; 169 | 170 | int i = 0; 171 | for (i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += 0x1000) { 172 | get_page(i, 1, kernel_directory); 173 | } 174 | 175 | i = 0; 176 | while (i < 0x400000) { 177 | alloc_frame(get_page(i, 1, kernel_directory), 0, 0); 178 | i += 0x1000; 179 | } 180 | 181 | for (i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += 0x1000) { 182 | alloc_frame(get_page(i, 1, kernel_directory), 0, 0); 183 | } 184 | 185 | switch_page_directory(kernel_directory); 186 | kheap = create_heap(KHEAP_START, KHEAP_START + KHEAP_INITIAL_SIZE, 0xCFFFF000, 187 | 0, 0); 188 | current_directory = clone_directory(kernel_directory); 189 | switch_page_directory(current_directory); 190 | } 191 | -------------------------------------------------------------------------------- /kernel/kernel/vsprintf.c: -------------------------------------------------------------------------------- 1 | /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ 2 | /* 3 | * Copied from linux-0.01 :-) 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | /* we use this so that we can do without the ctype library */ 11 | #define is_digit(c) ((c) >= '0' && (c) <= '9') 12 | 13 | static int skip_atoi(const char **s) { 14 | int i = 0; 15 | 16 | while (is_digit(**s)) 17 | i = i * 10 + *((*s)++) - '0'; 18 | return i; 19 | } 20 | 21 | #define ZEROPAD 1 /* pad with zero */ 22 | #define SIGN 2 /* unsigned/signed long */ 23 | #define PLUS 4 /* show plus */ 24 | #define SPACE 8 /* space if plus */ 25 | #define LEFT 16 /* left justified */ 26 | #define SPECIAL 32 /* 0x */ 27 | #define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ 28 | 29 | #define do_div(n, base) \ 30 | ({ \ 31 | int __res; \ 32 | __asm__("divl %4" : "=a"(n), "=d"(__res) : "0"(n), "1"(0), "r"(base)); \ 33 | __res; \ 34 | }) 35 | 36 | static char *number(char *str, int num, int base, int size, int precision, 37 | int type) { 38 | char c, sign, tmp[36]; 39 | const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 40 | int i; 41 | 42 | if (type & SMALL) 43 | digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 44 | if (type & LEFT) 45 | type &= ~ZEROPAD; 46 | if (base < 2 || base > 36) 47 | return 0; 48 | c = (type & ZEROPAD) ? '0' : ' '; 49 | if (type & SIGN && num < 0) { 50 | sign = '-'; 51 | num = -num; 52 | } else 53 | sign = (type & PLUS) ? '+' : ((type & SPACE) ? ' ' : 0); 54 | if (sign) 55 | size--; 56 | if (type & SPECIAL) 57 | if (base == 16) 58 | size -= 2; 59 | else if (base == 8) 60 | size--; 61 | i = 0; 62 | if (num == 0) 63 | tmp[i++] = '0'; 64 | else 65 | while (num != 0) 66 | tmp[i++] = digits[do_div(num, base)]; 67 | if (i > precision) 68 | precision = i; 69 | size -= precision; 70 | if (!(type & (ZEROPAD + LEFT))) 71 | while (size-- > 0) 72 | *str++ = ' '; 73 | if (sign) 74 | *str++ = sign; 75 | if (type & SPECIAL) 76 | if (base == 8) 77 | *str++ = '0'; 78 | else if (base == 16) { 79 | *str++ = '0'; 80 | *str++ = digits[33]; 81 | } 82 | if (!(type & LEFT)) 83 | while (size-- > 0) 84 | *str++ = c; 85 | while (i < precision--) 86 | *str++ = '0'; 87 | while (i-- > 0) 88 | *str++ = tmp[i]; 89 | while (size-- > 0) 90 | *str++ = ' '; 91 | return str; 92 | } 93 | 94 | int vsprintf(char *buf, const char *fmt, va_list args) { 95 | int len; 96 | int i; 97 | char *str; 98 | char *s; 99 | int *ip; 100 | 101 | int flags; /* flags to number() */ 102 | 103 | int field_width; /* width of output field */ 104 | int precision; /* min. # of digits for integers; max 105 | number of chars for from string */ 106 | int qualifier; /* 'h', 'l', or 'L' for integer fields */ 107 | 108 | for (str = buf; *fmt; ++fmt) { 109 | if (*fmt != '%') { 110 | *str++ = *fmt; 111 | continue; 112 | } 113 | 114 | /* process flags */ 115 | flags = 0; 116 | repeat: 117 | ++fmt; /* this also skips first '%' */ 118 | switch (*fmt) { 119 | case '-': 120 | flags |= LEFT; 121 | goto repeat; 122 | case '+': 123 | flags |= PLUS; 124 | goto repeat; 125 | case ' ': 126 | flags |= SPACE; 127 | goto repeat; 128 | case '#': 129 | flags |= SPECIAL; 130 | goto repeat; 131 | case '0': 132 | flags |= ZEROPAD; 133 | goto repeat; 134 | } 135 | 136 | /* get field width */ 137 | field_width = -1; 138 | if (is_digit(*fmt)) 139 | field_width = skip_atoi(&fmt); 140 | else if (*fmt == '*') { 141 | /* it's the next argument */ 142 | field_width = va_arg(args, int); 143 | if (field_width < 0) { 144 | field_width = -field_width; 145 | flags |= LEFT; 146 | } 147 | } 148 | 149 | /* get the precision */ 150 | precision = -1; 151 | if (*fmt == '.') { 152 | ++fmt; 153 | if (is_digit(*fmt)) 154 | precision = skip_atoi(&fmt); 155 | else if (*fmt == '*') { 156 | /* it's the next argument */ 157 | precision = va_arg(args, int); 158 | } 159 | if (precision < 0) 160 | precision = 0; 161 | } 162 | 163 | /* get the conversion qualifier */ 164 | qualifier = -1; 165 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { 166 | qualifier = *fmt; 167 | ++fmt; 168 | } 169 | 170 | switch (*fmt) { 171 | case 'c': 172 | if (!(flags & LEFT)) 173 | while (--field_width > 0) 174 | *str++ = ' '; 175 | *str++ = (unsigned char)va_arg(args, int); 176 | while (--field_width > 0) 177 | *str++ = ' '; 178 | break; 179 | 180 | case 's': 181 | s = va_arg(args, char *); 182 | len = strlen(s); 183 | if (precision < 0) 184 | precision = len; 185 | else if (len > precision) 186 | len = precision; 187 | 188 | if (!(flags & LEFT)) 189 | while (len < field_width--) 190 | *str++ = ' '; 191 | for (i = 0; i < len; ++i) 192 | *str++ = *s++; 193 | while (len < field_width--) 194 | *str++ = ' '; 195 | break; 196 | 197 | case 'o': 198 | str = number(str, va_arg(args, unsigned long), 8, field_width, precision, 199 | flags); 200 | break; 201 | 202 | case 'p': 203 | if (field_width == -1) { 204 | field_width = 8; 205 | flags |= ZEROPAD; 206 | } 207 | str = number(str, (unsigned long)va_arg(args, void *), 16, field_width, 208 | precision, flags); 209 | break; 210 | 211 | case 'x': 212 | flags |= SMALL; 213 | case 'X': 214 | str = number(str, va_arg(args, unsigned long), 16, field_width, precision, 215 | flags); 216 | break; 217 | 218 | case 'd': 219 | case 'i': 220 | flags |= SIGN; 221 | case 'u': 222 | str = number(str, va_arg(args, unsigned long), 10, field_width, precision, 223 | flags); 224 | break; 225 | 226 | case 'n': 227 | ip = va_arg(args, int *); 228 | *ip = (str - buf); 229 | break; 230 | 231 | default: 232 | if (*fmt != '%') 233 | *str++ = '%'; 234 | if (*fmt) 235 | *str++ = *fmt; 236 | else 237 | --fmt; 238 | break; 239 | } 240 | } 241 | *str = '\0'; 242 | return str - buf; 243 | } 244 | -------------------------------------------------------------------------------- /kernel/init/multiboot.h: -------------------------------------------------------------------------------- 1 | /* multiboot.h - Multiboot header file. */ 2 | /* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY 17 | * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef MULTIBOOT_HEADER 24 | #define MULTIBOOT_HEADER 1 25 | 26 | /* How many bytes from the start of the file we search for the header. */ 27 | #define MULTIBOOT_SEARCH 8192 28 | #define MULTIBOOT_HEADER_ALIGN 4 29 | 30 | /* The magic field should contain this. */ 31 | #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 32 | 33 | /* This should be in %eax. */ 34 | #define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 35 | 36 | /* Alignment of multiboot modules. */ 37 | #define MULTIBOOT_MOD_ALIGN 0x00001000 38 | 39 | /* Alignment of the multiboot info structure. */ 40 | #define MULTIBOOT_INFO_ALIGN 0x00000004 41 | 42 | /* Flags set in the 'flags' member of the multiboot header. */ 43 | 44 | /* Align all boot modules on i386 page (4KB) boundaries. */ 45 | #define MULTIBOOT_PAGE_ALIGN 0x00000001 46 | 47 | /* Must pass memory information to OS. */ 48 | #define MULTIBOOT_MEMORY_INFO 0x00000002 49 | 50 | /* Must pass video information to OS. */ 51 | #define MULTIBOOT_VIDEO_MODE 0x00000004 52 | 53 | /* This flag indicates the use of the address fields in the header. */ 54 | #define MULTIBOOT_AOUT_KLUDGE 0x00010000 55 | 56 | /* Flags to be set in the 'flags' member of the multiboot info structure. */ 57 | 58 | /* is there basic lower/upper memory information? */ 59 | #define MULTIBOOT_INFO_MEMORY 0x00000001 60 | /* is there a boot device set? */ 61 | #define MULTIBOOT_INFO_BOOTDEV 0x00000002 62 | /* is the command-line defined? */ 63 | #define MULTIBOOT_INFO_CMDLINE 0x00000004 64 | /* are there modules to do something with? */ 65 | #define MULTIBOOT_INFO_MODS 0x00000008 66 | 67 | /* These next two are mutually exclusive */ 68 | 69 | /* is there a symbol table loaded? */ 70 | #define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 71 | /* is there an ELF section header table? */ 72 | #define MULTIBOOT_INFO_ELF_SHDR 0X00000020 73 | 74 | /* is there a full memory map? */ 75 | #define MULTIBOOT_INFO_MEM_MAP 0x00000040 76 | 77 | /* Is there drive info? */ 78 | #define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 79 | 80 | /* Is there a config table? */ 81 | #define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 82 | 83 | /* Is there a boot loader name? */ 84 | #define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 85 | 86 | /* Is there a APM table? */ 87 | #define MULTIBOOT_INFO_APM_TABLE 0x00000400 88 | 89 | /* Is there video information? */ 90 | #define MULTIBOOT_INFO_VBE_INFO 0x00000800 91 | #define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 92 | 93 | #ifndef ASM_FILE 94 | 95 | typedef unsigned char multiboot_uint8_t; 96 | typedef unsigned short multiboot_uint16_t; 97 | typedef unsigned int multiboot_uint32_t; 98 | typedef unsigned long long multiboot_uint64_t; 99 | 100 | struct multiboot_header { 101 | /* Must be MULTIBOOT_MAGIC - see above. */ 102 | multiboot_uint32_t magic; 103 | 104 | /* Feature flags. */ 105 | multiboot_uint32_t flags; 106 | 107 | /* The above fields plus this one must equal 0 mod 2^32. */ 108 | multiboot_uint32_t checksum; 109 | 110 | /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ 111 | multiboot_uint32_t header_addr; 112 | multiboot_uint32_t load_addr; 113 | multiboot_uint32_t load_end_addr; 114 | multiboot_uint32_t bss_end_addr; 115 | multiboot_uint32_t entry_addr; 116 | 117 | /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ 118 | multiboot_uint32_t mode_type; 119 | multiboot_uint32_t width; 120 | multiboot_uint32_t height; 121 | multiboot_uint32_t depth; 122 | } __attribute__((section(".multiboot"))); 123 | 124 | /* The symbol table for a.out. */ 125 | struct multiboot_aout_symbol_table { 126 | multiboot_uint32_t tabsize; 127 | multiboot_uint32_t strsize; 128 | multiboot_uint32_t addr; 129 | multiboot_uint32_t reserved; 130 | }; 131 | typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; 132 | 133 | /* The section header table for ELF. */ 134 | struct multiboot_elf_section_header_table { 135 | multiboot_uint32_t num; 136 | multiboot_uint32_t size; 137 | multiboot_uint32_t addr; 138 | multiboot_uint32_t shndx; 139 | }; 140 | typedef struct multiboot_elf_section_header_table 141 | multiboot_elf_section_header_table_t; 142 | 143 | struct multiboot_info { 144 | /* Multiboot info version number */ 145 | multiboot_uint32_t flags; 146 | 147 | /* Available memory from BIOS */ 148 | multiboot_uint32_t mem_lower; 149 | multiboot_uint32_t mem_upper; 150 | 151 | /* "root" partition */ 152 | multiboot_uint32_t boot_device; 153 | 154 | /* Kernel command line */ 155 | multiboot_uint32_t cmdline; 156 | 157 | /* Boot-Module list */ 158 | multiboot_uint32_t mods_count; 159 | multiboot_uint32_t mods_addr; 160 | 161 | union { 162 | multiboot_aout_symbol_table_t aout_sym; 163 | multiboot_elf_section_header_table_t elf_sec; 164 | } u; 165 | 166 | /* Memory Mapping buffer */ 167 | multiboot_uint32_t mmap_length; 168 | multiboot_uint32_t mmap_addr; 169 | 170 | /* Drive Info buffer */ 171 | multiboot_uint32_t drives_length; 172 | multiboot_uint32_t drives_addr; 173 | 174 | /* ROM configuration table */ 175 | multiboot_uint32_t config_table; 176 | 177 | /* Boot Loader Name */ 178 | multiboot_uint32_t boot_loader_name; 179 | 180 | /* APM table */ 181 | multiboot_uint32_t apm_table; 182 | 183 | /* Video */ 184 | multiboot_uint32_t vbe_control_info; 185 | multiboot_uint32_t vbe_mode_info; 186 | multiboot_uint16_t vbe_mode; 187 | multiboot_uint16_t vbe_interface_seg; 188 | multiboot_uint16_t vbe_interface_off; 189 | multiboot_uint16_t vbe_interface_len; 190 | 191 | multiboot_uint64_t framebuffer_addr; 192 | multiboot_uint32_t framebuffer_pitch; 193 | multiboot_uint32_t framebuffer_width; 194 | multiboot_uint32_t framebuffer_height; 195 | multiboot_uint8_t framebuffer_bpp; 196 | #define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 197 | #define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 198 | #define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 199 | multiboot_uint8_t framebuffer_type; 200 | union { 201 | struct { 202 | multiboot_uint32_t framebuffer_palette_addr; 203 | multiboot_uint16_t framebuffer_palette_num_colors; 204 | }; 205 | struct { 206 | multiboot_uint8_t framebuffer_red_field_position; 207 | multiboot_uint8_t framebuffer_red_mask_size; 208 | multiboot_uint8_t framebuffer_green_field_position; 209 | multiboot_uint8_t framebuffer_green_mask_size; 210 | multiboot_uint8_t framebuffer_blue_field_position; 211 | multiboot_uint8_t framebuffer_blue_mask_size; 212 | }; 213 | }; 214 | }; 215 | typedef struct multiboot_info multiboot_info_t; 216 | 217 | struct multiboot_color { 218 | multiboot_uint8_t red; 219 | multiboot_uint8_t green; 220 | multiboot_uint8_t blue; 221 | }; 222 | 223 | struct multiboot_mmap_entry { 224 | multiboot_uint32_t size; 225 | multiboot_uint32_t base_addr_low; 226 | multiboot_uint32_t base_addr_high; 227 | multiboot_uint32_t length_low; 228 | multiboot_uint32_t length_high; 229 | #define MULTIBOOT_MEMORY_AVAILABLE 1 230 | #define MULTIBOOT_MEMORY_RESERVED 2 231 | #define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 232 | #define MULTIBOOT_MEMORY_NVS 4 233 | #define MULTIBOOT_MEMORY_BADRAM 5 234 | multiboot_uint32_t type; 235 | } __attribute__((packed)); 236 | typedef struct multiboot_mmap_entry multiboot_memory_map_t; 237 | 238 | struct multiboot_mod_list { 239 | /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ 240 | multiboot_uint32_t mod_start; 241 | multiboot_uint32_t mod_end; 242 | 243 | /* Module command line */ 244 | multiboot_uint32_t cmdline; 245 | 246 | /* padding to take it to 16 bytes (must be zero) */ 247 | multiboot_uint32_t pad; 248 | }; 249 | typedef struct multiboot_mod_list multiboot_module_t; 250 | 251 | /* APM BIOS info. */ 252 | struct multiboot_apm_info { 253 | multiboot_uint16_t version; 254 | multiboot_uint16_t cseg; 255 | multiboot_uint32_t offset; 256 | multiboot_uint16_t cseg_16; 257 | multiboot_uint16_t dseg; 258 | multiboot_uint16_t flags; 259 | multiboot_uint16_t cseg_len; 260 | multiboot_uint16_t cseg_16_len; 261 | multiboot_uint16_t dseg_len; 262 | }; 263 | 264 | #endif /* ! ASM_FILE */ 265 | 266 | #endif /* ! MULTIBOOT_HEADER */ 267 | -------------------------------------------------------------------------------- /kernel/mm/kheap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern uint32_t end; 7 | uint32_t placement_address = (uint32_t)&end; 8 | extern page_dir_t *kernel_directory; 9 | heap_t *kheap = 0; 10 | 11 | uint32_t kmalloc_int(uint32_t sz, int align, uint32_t *phys) { 12 | if (kheap != 0) { 13 | void *addr = alloc(sz, (uint8_t)align, kheap); 14 | if (phys != 0) { 15 | page_t *page = get_page((uint32_t)addr, 0, kernel_directory); 16 | *phys = page->frame * 0x1000 + ((uint32_t)addr & 0xFFF); 17 | } 18 | return (uint32_t)addr; 19 | } else { 20 | if (align == 1 && (placement_address & 0x00000FFF)) { 21 | placement_address &= 0xFFFFF000; 22 | placement_address += 0x1000; 23 | } 24 | if (phys) { 25 | *phys = placement_address; 26 | } 27 | uint32_t tmp = placement_address; 28 | placement_address += sz; 29 | return tmp; 30 | } 31 | } 32 | 33 | void kfree(void *p) { 34 | free(p, kheap); 35 | } 36 | 37 | uint32_t kmalloc_a(uint32_t sz) { 38 | return kmalloc_int(sz, 1, 0); 39 | } 40 | 41 | uint32_t kmalloc_p(uint32_t sz, uint32_t *phys) { 42 | return kmalloc_int(sz, 0, phys); 43 | } 44 | 45 | uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys) { 46 | return kmalloc_int(sz, 1, phys); 47 | } 48 | 49 | uint32_t kmalloc(uint32_t sz) { 50 | return kmalloc_int(sz, 0, 0); 51 | } 52 | 53 | static void expand(uint32_t new_size, heap_t *heap) { 54 | ASSERT(new_size > heap->end_address - heap->start_address); 55 | 56 | if (new_size & 0xFFFFF000 != 0) { 57 | new_size &= 0xFFFFF000; 58 | new_size += 0x1000; 59 | } 60 | 61 | ASSERT(heap->start_address + new_size <= heap->max_address); 62 | 63 | uint32_t old_size = heap->end_address - heap->start_address; 64 | 65 | uint32_t i = old_size; 66 | while (i < new_size) { 67 | alloc_frame(get_page(heap->start_address + i, 1, kernel_directory), 68 | (heap->supervisor) ? 1 : 0, (heap->readonly) ? 0 : 1); 69 | i += 0x1000; 70 | } 71 | heap->end_address = heap->start_address + new_size; 72 | } 73 | 74 | static uint32_t contract(uint32_t new_size, heap_t *heap) { 75 | ASSERT(new_size < heap->end_address - heap->start_address); 76 | 77 | if (new_size & 0x1000) { 78 | new_size &= 0x1000; 79 | new_size += 0x1000; 80 | } 81 | 82 | if (new_size < HEAP_MIN_SIZE) { 83 | new_size = HEAP_MIN_SIZE; 84 | } 85 | 86 | uint32_t old_size = heap->end_address - heap->start_address; 87 | uint32_t i = old_size - 0x1000; 88 | 89 | while (new_size < i) { 90 | free_frame(get_page(heap->start_address + i, 0, kernel_directory)); 91 | i -= 0x1000; 92 | } 93 | 94 | heap->end_address = heap->start_address + new_size; 95 | return new_size; 96 | } 97 | 98 | static int32_t find_smallest_hole(uint32_t size, uint8_t page_align, 99 | heap_t *heap) { 100 | uint32_t iterator = 0; 101 | while (iterator < heap->index.size) { 102 | header_t *header = (header_t *)lookup_ordered_array(iterator, &heap->index); 103 | 104 | if (page_align > 0) { 105 | uint32_t location = (uint32_t)header; 106 | int32_t offset = 0; 107 | if ((location + sizeof(header_t) & 0xFFFFF000) != 0) { 108 | offset = 0x1000 - (location + sizeof(header_t)) % 0x1000; 109 | } 110 | int32_t hole_size = (int32_t)header->size - offset; 111 | 112 | if (hole_size >= (int32_t)size) { 113 | break; 114 | } 115 | } else if (header->size >= size) { 116 | break; 117 | } 118 | iterator++; 119 | } 120 | 121 | if (iterator == heap->index.size) { 122 | return -1; 123 | } else { 124 | return iterator; 125 | } 126 | } 127 | 128 | static int8_t header_t_less_than(void *a, void *b) { 129 | return (((header_t *)a)->size < ((header_t *)b)->size) ? 1 : 0; 130 | } 131 | 132 | heap_t *create_heap(uint32_t start, uint32_t end_addr, uint32_t max, 133 | uint8_t supervisor, uint8_t readonly) { 134 | 135 | heap_t *heap = (heap_t *)kmalloc(sizeof(heap_t)); 136 | 137 | ASSERT(start % 0x1000 == 0); 138 | ASSERT(end_addr % 0x1000 == 0); 139 | 140 | heap->index = 141 | place_ordered_array((void *)start, HEAP_INDEX_SIZE, &header_t_less_than); 142 | 143 | start += sizeof(type_t) * HEAP_INDEX_SIZE; 144 | 145 | if (start & 0xFFFFF000 != 0) { 146 | start &= 0xFFFFF000; 147 | start += 0x1000; 148 | } 149 | 150 | heap->start_address = start; 151 | heap->end_address = end_addr; 152 | heap->max_address = max; 153 | heap->supervisor = supervisor; 154 | heap->readonly = readonly; 155 | 156 | header_t *hole = (header_t *)start; 157 | hole->size = end_addr - start; 158 | hole->magic = HEAP_MAGIC; 159 | hole->is_hole = 1; 160 | insert_ordered_array((void *)hole, &heap->index); 161 | 162 | return heap; 163 | } 164 | 165 | void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) { 166 | 167 | uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t); 168 | int32_t iterator = find_smallest_hole(new_size, page_align, heap); 169 | 170 | if (iterator == -1) { 171 | uint32_t old_length = heap->end_address - heap->start_address; 172 | uint32_t old_end_address = heap->end_address; 173 | 174 | expand(old_length + new_size, heap); 175 | uint32_t new_length = heap->end_address - heap->start_address; 176 | 177 | iterator = 0; 178 | 179 | uint32_t idx = -1; 180 | uint32_t value = 0x0; 181 | while (iterator < heap->index.size) { 182 | uint32_t tmp = (uint32_t)lookup_ordered_array(iterator, &heap->index); 183 | if (tmp > value) { 184 | value = tmp; 185 | idx = iterator; 186 | } 187 | iterator++; 188 | } 189 | 190 | if (idx == -1) { 191 | header_t *header = (header_t *)old_end_address; 192 | header->magic = HEAP_MAGIC; 193 | header->size = new_length - old_length; 194 | header->is_hole = 1; 195 | footer_t *footer = 196 | (footer_t *)(old_end_address + header->size - sizeof(footer_t)); 197 | footer->magic = HEAP_MAGIC; 198 | footer->header = header; 199 | insert_ordered_array((void *)header, &heap->index); 200 | } else { 201 | header_t *header = lookup_ordered_array(idx, &heap->index); 202 | header->size += new_length - old_length; 203 | footer_t *footer = 204 | (footer_t *)((uint32_t)header + header->size - sizeof(footer_t)); 205 | footer->header = header; 206 | footer->magic = HEAP_MAGIC; 207 | } 208 | return alloc(size, page_align, heap); 209 | } 210 | 211 | header_t *orig_hole_header = 212 | (header_t *)lookup_ordered_array(iterator, &heap->index); 213 | uint32_t orig_hole_pos = (uint32_t)orig_hole_header; 214 | uint32_t orig_hole_size = orig_hole_header->size; 215 | 216 | if (orig_hole_size - new_size < sizeof(header_t) + sizeof(footer_t)) { 217 | size += orig_hole_size - new_size; 218 | new_size = orig_hole_size; 219 | } 220 | 221 | if (page_align && orig_hole_pos & 0xFFFFF000) { 222 | uint32_t new_location = 223 | orig_hole_pos + 0x1000 - (orig_hole_pos & 0xFFF) - sizeof(header_t); 224 | header_t *hole_header = (header_t *)orig_hole_pos; 225 | hole_header->size = 0x1000 - (orig_hole_pos & 0xFFF) - sizeof(header_t); 226 | hole_header->magic = HEAP_MAGIC; 227 | hole_header->is_hole = 1; 228 | footer_t *hole_footer = 229 | (footer_t *)((uint32_t)new_location - sizeof(footer_t)); 230 | hole_footer->magic = HEAP_MAGIC; 231 | hole_footer->header = hole_header; 232 | orig_hole_pos = new_location; 233 | orig_hole_size = orig_hole_size - hole_header->size; 234 | } else { 235 | remove_ordered_array(iterator, &heap->index); 236 | } 237 | 238 | header_t *block_header = (header_t *)orig_hole_pos; 239 | block_header->magic = HEAP_MAGIC; 240 | block_header->is_hole = 0; 241 | block_header->size = new_size; 242 | footer_t *block_footer = 243 | (footer_t *)(orig_hole_pos + sizeof(header_t) + size); 244 | block_footer->magic = HEAP_MAGIC; 245 | block_footer->header = block_header; 246 | 247 | if (orig_hole_size - new_size > 0) { 248 | header_t *hole_header = (header_t *)(orig_hole_pos + sizeof(header_t) + 249 | size + sizeof(footer_t)); 250 | hole_header->magic = HEAP_MAGIC; 251 | hole_header->is_hole = 1; 252 | hole_header->size = orig_hole_size - new_size; 253 | footer_t *hole_footer = 254 | (footer_t *)((uint32_t)hole_header + orig_hole_size - new_size - 255 | sizeof(footer_t)); 256 | if ((uint32_t)hole_footer < heap->end_address) { 257 | hole_footer->magic = HEAP_MAGIC; 258 | hole_footer->header = hole_header; 259 | } 260 | insert_ordered_array((void *)hole_header, &heap->index); 261 | } 262 | 263 | return (void *)((uint32_t)block_header + sizeof(header_t)); 264 | } 265 | 266 | void free(void *p, heap_t *heap) { 267 | if (p == 0 || heap == 0) { 268 | return; 269 | } 270 | 271 | header_t *header = (header_t *)((uint32_t)p - sizeof(header_t)); 272 | footer_t *footer = 273 | (footer_t *)((uint32_t)header + header->size - sizeof(footer_t)); 274 | 275 | ASSERT(header->magic == HEAP_MAGIC); 276 | ASSERT(footer->magic == HEAP_MAGIC); 277 | 278 | header->is_hole = 1; 279 | int do_add = 1; 280 | 281 | footer_t *test_footer = (footer_t *)((uint32_t)header - sizeof(footer_t)); 282 | if (test_footer->magic == HEAP_MAGIC && test_footer->header->is_hole == 1) { 283 | uint32_t cache_size = header->size; 284 | header = test_footer->header; 285 | footer->header = header; 286 | header->size += cache_size; 287 | do_add = 0; 288 | } 289 | 290 | header_t *test_header = (header_t *)((uint32_t)footer + sizeof(footer_t)); 291 | if (test_header->magic == HEAP_MAGIC && test_header->is_hole) { 292 | header->size += test_header->size; 293 | test_footer = (footer_t *)((uint32_t)test_header + test_header->size - 294 | sizeof(footer_t)); 295 | footer = test_footer; 296 | 297 | uint32_t iterator = 0; 298 | while ( 299 | (iterator < heap->index.size) && 300 | (lookup_ordered_array(iterator, &heap->index) != (void *)test_header)) { 301 | iterator++; 302 | } 303 | 304 | ASSERT(iterator < heap->index.size); 305 | remove_ordered_array(iterator, &heap->index); 306 | } 307 | 308 | if ((uint32_t)footer + sizeof(footer_t) == heap->end_address) { 309 | uint32_t old_length = heap->end_address - heap->start_address; 310 | uint32_t new_length = 311 | contract((uint32_t)header - heap->start_address, heap); 312 | 313 | if (header->size - (old_length - new_length) > 0) { 314 | header->size -= old_length - new_length; 315 | footer = (footer_t *)((uint32_t)header + header->size - sizeof(footer_t)); 316 | footer->magic = HEAP_MAGIC; 317 | footer->header = header; 318 | } else { 319 | uint32_t iterator = 0; 320 | while ( 321 | (iterator < heap->index.size) && 322 | (lookup_ordered_array(iterator, &heap->index) != (void *)test_header)) 323 | iterator++; 324 | 325 | if (iterator < heap->index.size) { 326 | remove_ordered_array(iterator, &heap->index); 327 | } 328 | } 329 | } 330 | 331 | if (do_add == 1) { 332 | insert_ordered_array((void *)header, &heap->index); 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | --------------------------------------------------------------------------------