commit e4f160e8b65f0dcf24db042a9dc78b82eb4ba1a9 Author: Nathan Singer Date: Thu May 29 10:00:38 2025 -0400 reimplmenets the previous iteration with a brand new custom build system diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9f44571 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +sysroot/ +iso/ +*.o +*.d +com1.out +bochslog.txt +*.iso +*.a +*.elf diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8207c32 --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +CC = i686-elf-gcc +CFLAGS = -m32 -ffreestanding -Wall -Wextra -Werror -Wpedantic --sysroot=$(PWD)/sysroot -isystem=/usr/include -Iinclude -MD + +AS = nasm +ASFLAGS = -f elf + +LD = i686-elf-ld +LDFLAGS = -T $(shell find . -name "link.ld") -melf_i386 --sysroot=$(PWD)/sysroot -nostdlib -lk -lgcc + +AR = i686-elf-ar + +c_kern_objects := $(patsubst %.c,%.o,$(shell find kernel/ -name "*.c")) +asm_kern_objects := $(patsubst %.s,%.o,$(shell find kernel/ -name "*.s")) + + + +free_objs = $(patsubst %.c,%.o, $(shell find libc/ -path "libc/arch" -prune -o -type f | grep "\.c")) + +hosted_objs = $(patsubst, %.c,%.o,$(shell find libc/arch/ -name "*.c")) + +libc_objs = $(free_objs) $(hosted_objs) +libk_objs = $(free_objs) + +# binaries = libk.a libc.a # Not ready for libc yet +binaries = libk.a + +.PHONY: clean all run install-headers install-libs + +all: kernel.elf + +kernel.elf: install-headers install-libs $(c_kern_objects) $(asm_kern_objects) + $(CC) $(CFLAGS) -T $(shell find . -name "link.ld") -o $@ $(c_kern_objects) $(asm_kern_objects) -nostdlib -lk -lgcc + +os.iso: kernel.elf + mkdir -p iso/boot/grub + cp $(shell find . -name "kernel.elf") iso/boot/kernel.elf + cp util/grub.cfg iso/boot/grub/grub.cfg + grub-mkrescue -o $@ iso + +run: os.iso + bochs -f util/bochsrc.txt -q + +libc.a: $(libc_objs) + $(AR) rcs $@ $(libc_objs) + +libk.a: CFLAGS:=$(CFLAGS) -D__is_libk # Target rule to define __is_libk +libk.a: $(libk_objs) + $(AR) rcs $@ $(libk_objs) + +install-headers: + mkdir -p sysroot/usr/include + cp -r --preserve=timestamps kernel/include/. sysroot/usr/include/. + cp -r --preserve=timestamps libc/include/. sysroot/usr/include/. + +install-libs: $(binaries) + mkdir -p sysroot/usr/lib + cp -r --preserve=timestamps $(binaries) sysroot/usr/lib/. + +clean: + -rm -rf iso/ sysroot/ + -rm $(shell find . -name "*.o") + -rm $(shell find . -name "*.d") + -rm *.iso *.elf *.a com1.out bochslog.txt diff --git a/kernel/arch/boot.s b/kernel/arch/boot.s new file mode 100644 index 0000000..b30178e --- /dev/null +++ b/kernel/arch/boot.s @@ -0,0 +1,30 @@ +global loader ; entry symbol for ELF +extern kmain + +MAGIC_NUMBER equ 0x1BADB002 ; magic number constant +FLAGS equ 0x3 +CHECKSUM equ -(MAGIC_NUMBER + FLAGS) ; calculate the checksum +KERNEL_STACK_SIZE equ 4096 + +section .multiboot +align 4 ; code must be 4 byte aligned + dd MAGIC_NUMBER + dd FLAGS + dd CHECKSUM + +section .bss +align 4 +kernel_stack: + resb KERNEL_STACK_SIZE + +section .text +loader: + mov esp, kernel_stack + KERNEL_STACK_SIZE + + ;mov eax, 0xCAFEBABE + + call kmain + + cli +loop: hlt + jmp loop diff --git a/kernel/arch/gdt_entry.c b/kernel/arch/gdt_entry.c new file mode 100644 index 0000000..e8a298f --- /dev/null +++ b/kernel/arch/gdt_entry.c @@ -0,0 +1,19 @@ +#include + +uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag) +{ + uint64_t descriptor; + + descriptor = limit & 0x000F0000; + descriptor |= (flag << 8) & 0x00F0FF00; + descriptor |= (base >> 16) & 0x000000FF; + descriptor |= base & 0xFF000000; + + descriptor <<= 32; + + descriptor |= base << 16; + descriptor |= limit & 0x0000FFFF; + + return descriptor; +} + diff --git a/kernel/arch/io.h b/kernel/arch/io.h new file mode 100644 index 0000000..46bd467 --- /dev/null +++ b/kernel/arch/io.h @@ -0,0 +1,24 @@ +#ifndef ARCH_IO_H +#define ARCH_IO_H + +/** + * outb: + * Sends the given data to the I/O port. Defined in io.s + * + * @param port The I/O port to send the data to + * @param data TThe data to send to the I/O port + */ +void outb(unsigned short port, unsigned char data); + +/** + * inb: + * Read a byte from an I/O port + * + * @param port The address of the I/O port + * @return The read byte + */ +unsigned char inb(unsigned short port); + +#endif + + diff --git a/kernel/arch/io.s b/kernel/arch/io.s new file mode 100644 index 0000000..497bd93 --- /dev/null +++ b/kernel/arch/io.s @@ -0,0 +1,20 @@ +global outb +; out b - send a byte to an I/O port +; stack: [esp + 8] the data byte +; [esp + 4] the I/O port +; [esp ] return address +outb: + mov al, [esp + 8] + mov dx, [esp + 4] ; move the address into dx + out dx, al ; send the data to the I/O port + ret ; return to the calling function + +global inb +; inb - returns a byte from the given I/O port +; stack: [esp + 4] The address of the I/O port +; [esp ] The return address +inb: + mov dx, [esp + 4] ; move the address of the I/O port to the dx register + in al, dx ; read a byte from the I/O port and store it in the al register + ret ; return the read byte + diff --git a/kernel/arch/link.ld b/kernel/arch/link.ld new file mode 100644 index 0000000..a1ad6b1 --- /dev/null +++ b/kernel/arch/link.ld @@ -0,0 +1,28 @@ +ENTRY(loader) + +SECTIONS +{ + . = 1M; + + .text BLOCK(4K) : ALIGN(4K) + { + *(.multiboot) + *(.text) + } + + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } +} diff --git a/kernel/arch/serial.c b/kernel/arch/serial.c new file mode 100644 index 0000000..fcf0bd7 --- /dev/null +++ b/kernel/arch/serial.c @@ -0,0 +1,123 @@ +#include +#include +#include + +#include + + +#include "io.h" + +/* I/O ports */ + +/** + * All the I/O ports are calculated relative to their base. + * The ports (COM1, COM2, etc) have their ports in the same order, + * but they start at different values. + */ +#define SERIAL_COM1_BASE 0x3F8 + +#define SERIAL_DATA_PORT(base) (base) +#define SERIAL_FIFO_COMMAND_PORT(base) (base + 2) +#define SERIAL_LINE_COMMAND_PORT(base) (base + 3) +#define SERIAL_MODEM_COMMAND_PORT(base) (base + 4) +#define SERIAL_LINE_STATUS_PORT(base) (base + 5) + +/* I/O port commands */ + +/** + * SERIAL_LINE_ENABLE_DLAB: + * Tells the serial port to expect first the highest 8 bits on the data port, + * then the lowest 8 bits will follow + */ +#define SERIAL_LINE_ENABLE_DLAB 0x80 + +void serial_configure_baud_rate(unsigned short com, unsigned short divisor) +{ + outb(SERIAL_LINE_COMMAND_PORT(com), + SERIAL_LINE_ENABLE_DLAB); + outb(SERIAL_DATA_PORT(com), + (divisor >> 8) & 0x00FF); + outb(SERIAL_DATA_PORT(com), + divisor & 0x00FF); +} + +void serial_configure_line(unsigned short com) +{ + /** + * Bit: | 7 | 6 | 5 4 3 | 2 | 1 0 | + * Content: | d | b | prty | s | dl | + * d - Enabled (d = 1) or disables (d = 0) DLAB + * b - If break control is enabled (b = 1) or disabled (b = 0) + * prty - The number of parity bits to use + * s - The number of stop bits to use (s = 0 equals 1, s = 1 equals 1.5 or 2) + * dl - Describes the length of the data + * Value: | 0 | 0 | 0 0 0 | 0 | 1 1 | = 0x03 + */ + outb(SERIAL_LINE_COMMAND_PORT(com), 0x03); +} + +void serial_configure_buffers(unsigned short com) +{ + /** + * Bit: | 7 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * Content: | lvl | bs | r | dma | clt | clr | e | + * lvl - How many bytes should be stored in the FIFO buffers + * bs - If the buffers should be 16 or 64 bytes large + * r - Reserved for future use + * dma - How the serial port data should be accessed + * clt - Clear the transmission FIFO buffer + * clr - Clear the receiver FIFO buffer + * e - If the FIFO buffer should be enabled or not + * Value: | 1 1 | 0 | 0 | 0 | 1 | 1 | 1 | + */ + outb(SERIAL_FIFO_COMMAND_PORT(com), 0xC7); +} + +void serial_configure_modem(unsigned short com) +{ + /** + * Bit: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * Content: | r | r | af | lb | ao2 | ao1 | rts | dtr | + * r - Reserved + * af - Autoflow control enabled + * lb - Loopback mode (used for debugging serial ports) + * ao2 - Auxiliary output 2, used for receiving interrupts + * ao1 - Auxiliary output 1 + * rts - Ready to transmit + * dtr - Data Terminal ready + * Value: | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + */ + outb(SERIAL_MODEM_COMMAND_PORT(com), 0x03); +} + +int serial_is_transmit_fifo_empty(unsigned int com) +{ + /* 0x20 = 0010 0000 */ + return inb(SERIAL_LINE_STATUS_PORT(com)) & 0x20; +} + +void serial_initialize(void) +{ + serial_configure_baud_rate(SERIAL_COM1_BASE, 2); + serial_configure_line(SERIAL_COM1_BASE); + serial_configure_buffers(SERIAL_COM1_BASE); + serial_configure_modem(SERIAL_COM1_BASE); +} + +void serial_write_byte(unsigned short com, char c) +{ + while (!serial_is_transmit_fifo_empty(com)); + outb(SERIAL_DATA_PORT(com), c); +} + +void serial_write(const char* buf, size_t len) +{ + for (size_t i = 0; i < len; i++) + serial_write_byte(SERIAL_COM1_BASE, buf[i]); +} + +void serial_writestring(const char* buf) +{ + serial_write(buf, strlen(buf)); +} + diff --git a/kernel/arch/tty.c b/kernel/arch/tty.c new file mode 100644 index 0000000..2536a64 --- /dev/null +++ b/kernel/arch/tty.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include + +#include + +#include "vga.h" +#include "io.h" + +/* I/O ports */ +#define VGA_COMMAND_PORT 0x3D4 +#define VGA_DATA_PORT 0x3D5 + +/* I/O port commands */ +#define VGA_HIGH_BYTE_COMMAND 14 +#define VGA_LOW_BYTE_COMMAND 15 + +static const size_t VGA_WIDTH = 80; +static const size_t VGA_HEIGHT = 25; +static uint16_t* const VGA_MEMORY = (uint16_t*) 0xB8000; + +static size_t terminal_row; +static size_t terminal_column; +static uint8_t terminal_colour; +static struct vga_entry* terminal_buffer; + +struct vga_entry { + char c; + unsigned char colour; +} __attribute__((packed)); + +void terminal_set_colour(uint8_t colour) +{ + terminal_colour = colour; +} + +void terminal_clear(void) +{ + for (size_t y = 0; y < VGA_HEIGHT; y++) + for (size_t x = 0; x < VGA_WIDTH; x++) + terminal_write_cell((y * VGA_WIDTH) + x, ' '); + terminal_move_cursor(0); +} + +void terminal_initialize(void) +{ + terminal_row = 0; + terminal_column = 0; + + terminal_buffer = (struct vga_entry*) VGA_MEMORY; + terminal_set_colour(vga_entry_colour(VGA_COLOUR_LIGHT_GREY, VGA_COLOUR_BLACK)); + + terminal_clear(); +} + +void terminal_move_cursor(unsigned short pos) +{ + if (terminal_row >= VGA_HEIGHT) + terminal_scroll_screen(); + + outb(VGA_COMMAND_PORT, VGA_HIGH_BYTE_COMMAND); + outb(VGA_DATA_PORT, ((pos >> 8) & 0x00FF)); + outb(VGA_COMMAND_PORT, VGA_LOW_BYTE_COMMAND); + outb(VGA_DATA_PORT, pos & 0x00FF); +} + +inline size_t terminal_get_pos(void) + {return (terminal_row * VGA_WIDTH) + terminal_column;} + +void terminal_write_cell(unsigned int i, char c) +{ + struct vga_entry entry; + + entry.c = c; + entry.colour = terminal_colour; + + terminal_buffer[i] = entry; +} + +void terminal_write_character(unsigned int i, char c) +{ + switch(c) { + case '\n': + terminal_row += 1; + __attribute__((fallthrough)); + case '\r': + terminal_column = 0; + terminal_move_cursor(terminal_get_pos()); + break; + default: + terminal_write_cell(i, c); + + terminal_column += 1; + if (terminal_column >= VGA_WIDTH) { + terminal_column = 0; + terminal_row += 1; + } + + terminal_move_cursor(terminal_get_pos()); + } +} + +void terminal_write(const char* buf, size_t len) +{ + for (size_t i = 0; i < len; i++) + terminal_write_character(terminal_get_pos(), buf[i]); +} + +void terminal_writestring(const char* buf) +{ + terminal_write(buf, strlen(buf)); +} + +void terminal_scroll_screen(void) +{ + size_t y, x; + for (y = 0; y < VGA_HEIGHT -1; y++) { + for (x = 0; x < VGA_WIDTH; x++) { + terminal_buffer[(y * VGA_WIDTH) + x] = + terminal_buffer[((y + 1) * VGA_WIDTH) + x]; + } + } + for (x = 0; x < VGA_WIDTH; x++) + terminal_write_cell(((VGA_HEIGHT - 1) * VGA_WIDTH) + x, ' '); + + terminal_row -= 1; + terminal_column = 0; + terminal_move_cursor(terminal_get_pos()); +} + diff --git a/kernel/arch/vga.h b/kernel/arch/vga.h new file mode 100644 index 0000000..1e86446 --- /dev/null +++ b/kernel/arch/vga.h @@ -0,0 +1,30 @@ +#ifndef ARCH_VGA_H +#define ARCH_VGA_H + +#include + +typedef enum vga_colour { + VGA_COLOUR_BLACK = 0, + VGA_COLOUR_BLUE = 1, + VGA_COLOUR_GREEN = 2, + VGA_COLOUR_CYAN = 3, + VGA_COLOUR_RED = 4, + VGA_COLOUR_MAGENTA = 5, + VGA_COLOUR_BROWN = 6, + VGA_COLOUR_LIGHT_GREY = 7, + VGA_COLOUR_DARK_GREY = 8, + VGA_COLOUR_LIGHT_BLUE = 9, + VGA_COLOUR_LIGHT_GREEN = 10, + VGA_COLOUR_LIGHT_CYAN = 11, + VGA_COLOUR_LIGHT_RED = 12, + VGA_COLOUR_LIGHT_MAGENTA = 13, + VGA_COLOUR_LIGHT_BROWN = 14, + VGA_COLOUR_WHITE = 15, +} vga_colour_t; + +static inline uint8_t vga_entry_colour(vga_colour_t fg, vga_colour_t bg) { + return fg | bg << 4; +} + +#endif + diff --git a/kernel/include/kernel/_kernel.h b/kernel/include/kernel/_kernel.h new file mode 100644 index 0000000..694beda --- /dev/null +++ b/kernel/include/kernel/_kernel.h @@ -0,0 +1,12 @@ +#ifndef _KERNEL_KERNEL_H +#define _KERNEL_KERNEL_H + +void kerror(const char*); + +void kwarn(const char*); + +void kinfo(const char*); + + +#endif + diff --git a/kernel/include/kernel/serial.h b/kernel/include/kernel/serial.h new file mode 100644 index 0000000..cfb6ba4 --- /dev/null +++ b/kernel/include/kernel/serial.h @@ -0,0 +1,91 @@ +#include + +#ifndef _KERNEL_SERIAL_H +#define _KERNEL_SERIAL_H + +/** + * serial_initialize: + * Initializes the serial port for writing. + */ +void serial_initialize(void); + +/** + * serial_configure_baud_rate: + * Sets the speed of the data being sent. + * The argument is a divisor of that number, hence the speed becomes + * (speed / divisor) bits/s. + * + * @param com The COM port to configure + * @param divisor The divisor + */ +void serial_configure_baud_rate(unsigned short com, unsigned short divisor); + +/** + * serial_configure_line: + * Configures the line of the given serial port. The port is set to have a + * data length of 8 bits, no parity bits, one stop bit and break control + * disabled. + * + * @param com The serial port to configure + */ +void serial_configure_line(unsigned short com); + +/** + * serial_configure_buffers: + * Configures the buffer of the given serial port. The port is set to + * enable FIFO, clear the receiver and transmission FIFO queues, + * and to use 14 bytes as a size of the queue. + * + * @param com The serial port to configure + */ +void serial_configure_buffers(unsigned short com); + +/** + * serial_configure_modem: + * Configures the modem of the given serial port. + * We don't need interrupts, and just need RTS and DTS. + * + * @param com The serial port to configure + */ +void serial_configure_modem(unsigned short com); + +/** + * serial_is_transmit_fifo_empty: + * Checks whether the transmit FIFO queue is empty or not for the given COM port. + * + * @param com The COM port + * + * @return 0 if the transmit FIFO queue is not empty + * 1 if the transmit FIFO queue is empty + */ +int serial_is_transmit_fifo_empty(unsigned int com); + +/** + * serial_write_byte: + * Writes a byte to the serial port, and adhering to the FIFO queue, + * ensures bytes aren't overwritten + * + * @param com The serial port + * @param c The character to write + */ +void serial_write_byte(unsigned short com, char c); + +/** + * serial_write: + * Writes to the serial output (DEFAULTS TO COM1) + * + * @param buf The character buffer + * @param len The length of the buffer + */ +void serial_write(const char* buf, size_t len); + +/** + * serial_writestring: + * Writes toe the serial output (DEFAULT TO COM1) + * + * @param buf The character buffer + */ +void serial_writestring(const char* buf); + +#endif + diff --git a/kernel/include/kernel/tty.h b/kernel/include/kernel/tty.h new file mode 100644 index 0000000..81e3c85 --- /dev/null +++ b/kernel/include/kernel/tty.h @@ -0,0 +1,80 @@ +#ifndef _KERNEL_TTY_H +#define _KERNEL_TTY_H + +#include + +/** + * terminal_clear: + * Clears the terminal + */ +void terminal_clear(void); + +/** + * terminal_initialize: + * Initialize the framebuffer variables. + */ +void terminal_initialize(void); + +/** + * terminal_move_cursor: + * Moves the cursor of the framebuffer to the given position + * + * @param pos The new position of the cursor + */ +void terminal_move_cursor(unsigned short pos); + +/** + * terminal_get_pos: + * Calculates the position of the cursor + * + * @return The position + */ +size_t terminal_get_pos(void); + +/** + * terminal_write_cell: + * Writes a character with the given foreground and background to the framebuffer + * + * @param i The location in the framebuffer + * @param c The character + * @param fg The foreground colour + * @param bg The background colour + */ +void terminal_write_cell(unsigned int i, char c); + +/** + * terminal_write_character: + * Parses the given character, enacts any edge cases, and passes + * the rest of the write information down to terminal_write_cell + * + * @param i The location in the terminal_buffer + * @param c The character + * @param fg The foreground colour + * @param bg The background colour + */ +void terminal_write_character(unsigned int i, char c); + +/** + * terminal_write: + * Writes the content of the buffer to the framebuffer + * + * @param buf Buffer containing text to write to the framebuffer + * @param len Length of the buffer + */ +void terminal_write(const char* buf, size_t len); + +/** + * terminal_writestring: + * Writes the content of the buffer to the framebuffer + * + * @param buf Buffer containing text to write to the framebuffer + */ +void terminal_writestring(const char* buf); +/** + * terminal_scroll_screen: + * Scrolls the terminal screen up one. + */ +void terminal_scroll_screen(void); + +#endif + diff --git a/kernel/include/kernel/x86/gdt.h b/kernel/include/kernel/x86/gdt.h new file mode 100644 index 0000000..0d428df --- /dev/null +++ b/kernel/include/kernel/x86/gdt.h @@ -0,0 +1,60 @@ +#include + +#ifndef ARCH_I386_GDT_H +#define ARCH_I386_GDT_H + +// Each define here is for a specific flag in the descriptor. +// Refer to the intel documentation for a description of what each one does. +#define SEG_DESCTYPE(x) ((x) << 0x04) // Descriptor type (0 for system, 1 for code/data) +#define SEG_PRES(x) ((x) << 0x07) // Present +#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use +#define SEG_LONG(x) ((x) << 0x0D) // Long mode +#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32) +#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB) +#define SEG_PRIV(x) (((x) & 0x03) << 0x05) // Set privilege level (0 - 3) + +#define SEG_DATA_RD 0x00 // Read-Only +#define SEG_DATA_RDA 0x01 // Read-Only, accessed +#define SEG_DATA_RDWR 0x02 // Read/Write +#define SEG_DATA_RDWRA 0x03 // Read/Write, accessed +#define SEG_DATA_RDEXPD 0x04 // Read-Only, expand-down +#define SEG_DATA_RDEXPDA 0x05 // Read-Only, expand-down, accessed +#define SEG_DATA_RDWREXPD 0x06 // Read/Write, expand-down +#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed +#define SEG_CODE_EX 0x08 // Execute-Only +#define SEG_CODE_EXA 0x09 // Execute-Only, accessed +#define SEG_CODE_EXRD 0x0A // Execute/Read +#define SEG_CODE_EXRDA 0x0B // Execute/Read, accessed +#define SEG_CODE_EXC 0x0C // Execute-Only, conforming +#define SEG_CODE_EXCA 0x0D // Execute-Only, conforming, accessed +#define SEG_CODE_EXRDC 0x0E // Execute/Read, conforming +#define SEG_CODE_EXRDCA 0x0F // Execute/Read, conforming, accessed + +#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_CODE_EXRD + +#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(0) | SEG_DATA_RDWR + +#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_CODE_EXRD + +#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_SAVL(0) | \ + SEG_LONG(0) | SEG_SIZE(1) | SEG_GRAN(1) | \ + SEG_PRIV(3) | SEG_DATA_RDWR + + + +void setGdt(unsigned short limit, uint64_t* base); + +void reloadSegments(); + +uint64_t create_descriptor(uint32_t base, uint32_t limit, uint16_t flag); + + +#endif + + diff --git a/kernel/klog.c b/kernel/klog.c new file mode 100644 index 0000000..7907840 --- /dev/null +++ b/kernel/klog.c @@ -0,0 +1,38 @@ +#include + +#include +#include + +enum log_mode { + LOG_ERR, + LOG_WARN, + LOG_INFO, +}; + +void klog(const char* buf, enum log_mode mode) +{ + switch(mode) { + case LOG_ERR: + serial_writestring("ERROR: "); + break; + case LOG_WARN: + serial_writestring("WARNING: "); + break; + case LOG_INFO: + serial_writestring("INFO: "); + break; + } + serial_writestring(buf); + serial_writestring("\n"); +} + +void kerror(const char* buf) + {klog(buf, LOG_ERR);} + +void kwarn(const char* buf) + {klog(buf, LOG_WARN);} + +void kinfo(const char* buf) + {klog(buf, LOG_INFO);} + + diff --git a/kernel/kmain.c b/kernel/kmain.c new file mode 100644 index 0000000..44a4f48 --- /dev/null +++ b/kernel/kmain.c @@ -0,0 +1,17 @@ +#include + +#include +#include + +void kmain(void) +{ + terminal_initialize(); + serial_initialize(); + + + terminal_writestring("test"); + + serial_writestring("test!"); + + printf("test.."); +} diff --git a/libc/.gitignore b/libc/.gitignore new file mode 100644 index 0000000..268e074 --- /dev/null +++ b/libc/.gitignore @@ -0,0 +1,3 @@ +*.a +*.d +*.o diff --git a/libc/arch/README.md b/libc/arch/README.md new file mode 100644 index 0000000..b9c1190 --- /dev/null +++ b/libc/arch/README.md @@ -0,0 +1,4 @@ +## What is this folder? + +This is where we place hosted libraries, +when we inevitably add a proper libc (libk is freestanding) diff --git a/libc/include/limits.h b/libc/include/limits.h new file mode 100644 index 0000000..7bbc5e4 --- /dev/null +++ b/libc/include/limits.h @@ -0,0 +1,25 @@ +#ifndef LIMITS_H +#define LIMITS_H + +#define CHAR_BIT 8 +#define SCHAR_MIN -128 +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 +#define CHAR_MIN -128 +#define CHAR_MAX 127 + +#define MB_LEN_MAX 16 + +#define SHRT_MIN -32768 +#define SHRT_MAX 32767 +#define USHRT_MAX 65535 + +#define INT_MIN -2147483648 +#define INT_MAX 2147483647 +#define UINT_MAX 4294967295 + +#define LONG_MIN -9223372036854775808 +#define LONG_MAX 9223372036854775807 +#define ULONG_MAX 18446744073709551615 + +#endif diff --git a/libc/include/stdio.h b/libc/include/stdio.h new file mode 100644 index 0000000..b3be14e --- /dev/null +++ b/libc/include/stdio.h @@ -0,0 +1,20 @@ +#ifndef _STDIO_H +#define _STDIO_H 1 + +#include + +#define EOF (-1) + +#ifdef __cplusplus +extern "C" { +#endif + +int printf(const char* __restrict, ...); +int putchar(int); +int puts(const char*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h new file mode 100644 index 0000000..106802f --- /dev/null +++ b/libc/include/stdlib.h @@ -0,0 +1,17 @@ +#ifndef _STDLIB_H +#define _STDLIB_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((__noreturn__)) +void abort(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/include/string.h b/libc/include/string.h new file mode 100644 index 0000000..6849b2a --- /dev/null +++ b/libc/include/string.h @@ -0,0 +1,22 @@ +#ifndef _STRING_H +#define _STRING_H 1 + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int memcmp(const void*, const void*, size_t); +void* memcpy(void* __restrict, const void* __restrict, size_t); +void* memmove(void*, const void*, size_t); +void* memset(void*, int, size_t); +size_t strlen(const char*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h new file mode 100644 index 0000000..81ec768 --- /dev/null +++ b/libc/include/sys/cdefs.h @@ -0,0 +1,6 @@ +#ifndef _SYS_CDEFS_H +#define _SYS_CDEFS_H 1 + +#define __novaos_libc 1 + +#endif diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c new file mode 100644 index 0000000..f1f95ba --- /dev/null +++ b/libc/stdio/printf.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include + +static bool print(const char* data, size_t length) { + const unsigned char* bytes = (const unsigned char*) data; + for (size_t i = 0; i < length; i++) + if (putchar(bytes[i]) == EOF) + return false; + return true; +} + +int printf(const char* restrict format, ...) { + va_list parameters; + va_start(parameters, format); + + int written = 0; + + while (*format != '\0') { + size_t maxrem = INT_MAX - written; + + if (format[0] != '%' || format[1] == '%') { + if (format[0] == '%') + format++; + size_t amount = 1; + while (format[amount] && format[amount] != '%') + amount++; + if (maxrem < amount) { + // TODO: Set errno to EOVERFLOW. + return -1; + } + if (!print(format, amount)) + return -1; + format += amount; + written += amount; + continue; + } + + const char* format_begun_at = format++; + + if (*format == 'c') { + format++; + char c = (char) va_arg(parameters, int /* char promotes to int */); + if (!maxrem) { + // TODO: Set errno to EOVERFLOW. + return -1; + } + if (!print(&c, sizeof(c))) + return -1; + written++; + } else if (*format == 's') { + format++; + const char* str = va_arg(parameters, const char*); + size_t len = strlen(str); + if (maxrem < len) { + // TODO: Set errno to EOVERFLOW. + return -1; + } + if (!print(str, len)) + return -1; + written += len; + } else { + format = format_begun_at; + size_t len = strlen(format); + if (maxrem < len) { + // TODO: Set errno to EOVERFLOW. + return -1; + } + if (!print(format, len)) + return -1; + written += len; + format += len; + } + } + + va_end(parameters); + return written; +} diff --git a/libc/stdio/putchar.c b/libc/stdio/putchar.c new file mode 100644 index 0000000..32c1ecf --- /dev/null +++ b/libc/stdio/putchar.c @@ -0,0 +1,15 @@ +#include + +#if defined(__is_libk) +#include +#endif + +int putchar(int ic) { +#if defined(__is_libk) + char c = (char) ic; + terminal_write(&c, sizeof(c)); +#else + // TODO: Implement stdio and the write system call. +#endif + return ic; +} diff --git a/libc/stdio/puts.c b/libc/stdio/puts.c new file mode 100644 index 0000000..2a24cd1 --- /dev/null +++ b/libc/stdio/puts.c @@ -0,0 +1,5 @@ +#include + +int puts(const char* string) { + return printf("%s\n", string); +} diff --git a/libc/stdlib/abort.c b/libc/stdlib/abort.c new file mode 100644 index 0000000..eadba2c --- /dev/null +++ b/libc/stdlib/abort.c @@ -0,0 +1,15 @@ +#include +#include + +__attribute__((__noreturn__)) +void abort(void) { +#if defined(__is_libk) + // TODO: Add proper kernel panic. + printf("kernel: panic: abort()\n"); +#else + // TODO: Abnormally terminate the process as if by SIGABRT. + printf("abort()\n"); +#endif + while (1) { } + __builtin_unreachable(); +} diff --git a/libc/string/memcmp.c b/libc/string/memcmp.c new file mode 100644 index 0000000..576a242 --- /dev/null +++ b/libc/string/memcmp.c @@ -0,0 +1,13 @@ +#include + +int memcmp(const void* aptr, const void* bptr, size_t size) { + const unsigned char* a = (const unsigned char*) aptr; + const unsigned char* b = (const unsigned char*) bptr; + for (size_t i = 0; i < size; i++) { + if (a[i] < b[i]) + return -1; + else if (b[i] < a[i]) + return 1; + } + return 0; +} diff --git a/libc/string/memcpy.c b/libc/string/memcpy.c new file mode 100644 index 0000000..1834816 --- /dev/null +++ b/libc/string/memcpy.c @@ -0,0 +1,9 @@ +#include + +void* memcpy(void* restrict dstptr, const void* restrict srcptr, size_t size) { + unsigned char* dst = (unsigned char*) dstptr; + const unsigned char* src = (const unsigned char*) srcptr; + for (size_t i = 0; i < size; i++) + dst[i] = src[i]; + return dstptr; +} diff --git a/libc/string/memmove.c b/libc/string/memmove.c new file mode 100644 index 0000000..ceac1e1 --- /dev/null +++ b/libc/string/memmove.c @@ -0,0 +1,14 @@ +#include + +void* memmove(void* dstptr, const void* srcptr, size_t size) { + unsigned char* dst = (unsigned char*) dstptr; + const unsigned char* src = (const unsigned char*) srcptr; + if (dst < src) { + for (size_t i = 0; i < size; i++) + dst[i] = src[i]; + } else { + for (size_t i = size; i != 0; i--) + dst[i-1] = src[i-1]; + } + return dstptr; +} diff --git a/libc/string/memset.c b/libc/string/memset.c new file mode 100644 index 0000000..449d1e7 --- /dev/null +++ b/libc/string/memset.c @@ -0,0 +1,8 @@ +#include + +void* memset(void* bufptr, int value, size_t size) { + unsigned char* buf = (unsigned char*) bufptr; + for (size_t i = 0; i < size; i++) + buf[i] = (unsigned char) value; + return bufptr; +} diff --git a/libc/string/strlen.c b/libc/string/strlen.c new file mode 100644 index 0000000..8ac0dbe --- /dev/null +++ b/libc/string/strlen.c @@ -0,0 +1,8 @@ +#include + +size_t strlen(const char* str) { + size_t len = 0; + while (str[len]) + len++; + return len; +} diff --git a/libc/string/strlen.libk.c b/libc/string/strlen.libk.c new file mode 100644 index 0000000..8ac0dbe --- /dev/null +++ b/libc/string/strlen.libk.c @@ -0,0 +1,8 @@ +#include + +size_t strlen(const char* str) { + size_t len = 0; + while (str[len]) + len++; + return len; +} diff --git a/util/bochsrc.txt b/util/bochsrc.txt new file mode 100644 index 0000000..e357d67 --- /dev/null +++ b/util/bochsrc.txt @@ -0,0 +1,10 @@ +megs: 32 +display_library: sdl +romimage: file=/usr/share/bochs/BIOS-bochs-latest +vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest +ata0-master: type=cdrom, path=os.iso, status=inserted +boot: cdrom +log: bochslog.txt +clock: sync=realtime, time0=local +cpu: count=1, ips=1000000 +com1: enabled=1, mode=file, dev=com1.out diff --git a/util/grub.cfg b/util/grub.cfg new file mode 100644 index 0000000..e30ce98 --- /dev/null +++ b/util/grub.cfg @@ -0,0 +1,3 @@ +menuentry "myos" { + multiboot /boot/kernel.elf +}