commit a42aab766721c5946fdde075fff28d2e1b29440b Author: sam Date: Sat Feb 24 20:24:22 2024 +1300 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36305ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +obj/* +radix.iso diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..05722e6 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +KERNEL=obj/radix.bin +ISO=radix.iso + +CC=gcc +LD=ld +CFLAGS=-ffreestanding -fno-stack-protector -fno-stack-check -O3 -Wall -Wextra -Werror -m32 -Isrc +LDFLAGS=-T linker.ld -m elf_i386 +NASMFLAGS=-f elf32 + +CFILES=$(shell cd src && find -L * -type f -name '*.c') +ASMFILES=$(shell cd src && find -L * -type f -name '*.asm') +OBJ=$(addprefix obj/,$(CFILES:.c=.c.o) $(ASMFILES:.asm=.asm.o)) + +$(ISO): $(KERNEL) isolinux.cfg + cp isolinux.cfg cdroot/isolinux/ + cp $(KERNEL) cdroot/ + mkisofs -o $(ISO) -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table cdroot/ + +$(KERNEL): makedir linker.ld $(OBJ) + $(LD) $(LDFLAGS) $(OBJ) -o $@ + +obj/%.c.o: src/%.c + $(CC) $(CFLAGS) -c $< -o $@ +obj/%.asm.o: src/%.asm + nasm $(NASMFLAGS) $< -o $@ + +makedir: + mkdir -p obj + +run: $(ISO) + qemu-system-i386 -boot d -cdrom $(ISO) -m 1G -enable-kvm -cpu host -serial stdio + +clean: + rm -rf $(OBJ) $(KERNEL) diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/cdroot/isolinux/isolinux.bin b/cdroot/isolinux/isolinux.bin new file mode 100644 index 0000000..995cd2d Binary files /dev/null and b/cdroot/isolinux/isolinux.bin differ diff --git a/cdroot/isolinux/isolinux.cfg b/cdroot/isolinux/isolinux.cfg new file mode 100644 index 0000000..2a41f17 --- /dev/null +++ b/cdroot/isolinux/isolinux.cfg @@ -0,0 +1,4 @@ +DEFAULT radix +LABEL radix + KERNEL mboot.c32 + APPEND /radix.bin diff --git a/cdroot/isolinux/ldlinux.c32 b/cdroot/isolinux/ldlinux.c32 new file mode 100644 index 0000000..e43c6cd Binary files /dev/null and b/cdroot/isolinux/ldlinux.c32 differ diff --git a/cdroot/isolinux/libcom32.c32 b/cdroot/isolinux/libcom32.c32 new file mode 100644 index 0000000..73d3f8d Binary files /dev/null and b/cdroot/isolinux/libcom32.c32 differ diff --git a/cdroot/isolinux/mboot.c32 b/cdroot/isolinux/mboot.c32 new file mode 100644 index 0000000..22ab5cc Binary files /dev/null and b/cdroot/isolinux/mboot.c32 differ diff --git a/cdroot/radix.bin b/cdroot/radix.bin new file mode 100755 index 0000000..92db9d1 Binary files /dev/null and b/cdroot/radix.bin differ diff --git a/isolinux.cfg b/isolinux.cfg new file mode 100644 index 0000000..2a41f17 --- /dev/null +++ b/isolinux.cfg @@ -0,0 +1,4 @@ +DEFAULT radix +LABEL radix + KERNEL mboot.c32 + APPEND /radix.bin diff --git a/linker.ld b/linker.ld new file mode 100644 index 0000000..0e93f9b --- /dev/null +++ b/linker.ld @@ -0,0 +1,28 @@ +ENTRY(_start) + +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/src/boot.asm b/src/boot.asm new file mode 100644 index 0000000..bc45745 --- /dev/null +++ b/src/boot.asm @@ -0,0 +1,36 @@ +extern kernel_main + +MBALIGN equ 1 << 0 +MEMINFO equ 1 << 1 +VIDINFO equ 1 << 2 +MBFLAGS equ MBALIGN | MEMINFO | VIDINFO +MAGIC equ 0x1BADB002 +CHECKSUM equ -(MAGIC + MBFLAGS) + +section .multiboot +align 4 + dd MAGIC + dd MBFLAGS + dd CHECKSUM + dd 0, 0, 0, 0, 0 + dd 0 + dd 320, 200, 8 + +section .bss +align 16 +stack_bottom: +resb 16384 +stack_top: + +section .text +global _start:function (_start.end - _start) +_start: + mov esp, stack_top + push ebx + push eax + + call kernel_main + cli +.hang: + jmp .hang +.end: diff --git a/src/ctype.c b/src/ctype.c new file mode 100644 index 0000000..6a3efa7 --- /dev/null +++ b/src/ctype.c @@ -0,0 +1,5 @@ +#include + +int isdigit(char c) { + return c >= '0' && c <= '9'; +} diff --git a/src/ctype.h b/src/ctype.h new file mode 100644 index 0000000..c27dc9e --- /dev/null +++ b/src/ctype.h @@ -0,0 +1,6 @@ +#ifndef __CTYPE_H__ +#define __CTYPE_H__ + +int isdigit(char arg); + +#endif diff --git a/src/hcf.asm b/src/hcf.asm new file mode 100644 index 0000000..23c911d --- /dev/null +++ b/src/hcf.asm @@ -0,0 +1,7 @@ +global hcf + +hcf: + cli +.loop: + hlt + jmp .loop diff --git a/src/hcf.h b/src/hcf.h new file mode 100644 index 0000000..9ca36eb --- /dev/null +++ b/src/hcf.h @@ -0,0 +1,6 @@ +#ifndef __HCF_H__ +#define __HCF_H__ + +void hcf(); + +#endif diff --git a/src/kernel.c b/src/kernel.c new file mode 100644 index 0000000..1904027 --- /dev/null +++ b/src/kernel.c @@ -0,0 +1,241 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +void putpixel(unsigned char* addr, int pos_x, int pos_y, unsigned char VGA_COLOR) +{ + unsigned char* location = addr + 320 * pos_y + pos_x; + *location = VGA_COLOR; +} + +static inline void outb(uint16_t port, uint8_t val) +{ + __asm__ volatile ( "outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory"); + /* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint). + * Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint). + * The outb %al, %dx encoding is the only option for all other cases. + * %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */ +} + +static inline uint8_t inb(uint16_t port) +{ + uint8_t ret; + __asm__ volatile ( "inb %w1, %b0" + : "=a"(ret) + : "Nd"(port) + : "memory"); + return ret; +} + +#define PORT 0x3f8 // COM1 + +static int init_serial() { + outb(PORT + 1, 0x00); // Disable all interrupts + outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + outb(PORT + 1, 0x00); // (hi byte) + outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit + outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold + outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set + outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip + outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) + + // Check if serial is faulty (i.e: not same byte as sent) + if(inb(PORT + 0) != 0xAE) { + return 1; + } + + // If serial is not faulty set it in normal operation mode + // (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled) + outb(PORT + 4, 0x0F); + return 0; +} + +int is_transmit_empty() { + return inb(PORT + 5) & 0x20; +} + +void write_serial(char a) { + while (is_transmit_empty() == 0); + + outb(PORT,a); +} + +void serial_puts(const char* s) { + do { + write_serial(*s); + } while(*++s != '\0'); +} + +void sprintf(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + + for(int i = 0; fmt[i] != '\0'; i++) + { + switch(fmt[i]) + { + case '%': + i++; + + char buf[512]; + + size_t width = 0; + char padding_char = fmt[i]; + if(isdigit(fmt[i]) || fmt[i] == ' ') { + i++; + int pos = 0; + while(isdigit(fmt[i])) { + buf[pos++] = fmt[i++]; + } + buf[pos] = '\0'; + width = atoi(buf); + } + + const char* out = 0; + + if(fmt[i] == 's') + out = va_arg(args, const char*); + if(fmt[i] == 'd') + out = itoa(va_arg(args, int), buf, 10); + if(fmt[i] == 'u') + out = ultoa(va_arg(args, uint32_t), buf, 10); + if(fmt[i] == 'x') + out = ultoa(va_arg(args, uint32_t), buf, 16); + if(fmt[i] == 'c') + write_serial(va_arg(args, int)); + + size_t len = strlen(out); + if(width > len) { + char padding[256]; + size_t j = 0; + for(; j < width - len; j++) + padding[j] = padding_char; + padding[j] = '\0'; + serial_puts(padding); + } + + serial_puts(out); + break; + default: + write_serial(fmt[i]); + break; + } + } + + va_end(args); +} + +#define CHECK_FLAG(flags,bit) ((flags) & (1 << (bit))) + +void kernel_main(uint32_t magic, multiboot_info_t* mbi) { + init_vga(); + init_serial(); + + if(magic != MULTIBOOT_BOOTLOADER_MAGIC) { + printf("Invalid bootloader magic: %x", magic); + hcf(); + } + + printf("flags: 0x%x\n", mbi->flags); + + uint32_t mem_total = mbi->mem_upper - mbi->mem_lower; + printf("mem_lower: %uKB, mem_upper: %uKB, mem_total: %uKB\n", mbi->mem_lower, mbi->mem_upper, mem_total); + + //sprintf("checking for flag"); +//if (CHECK_FLAG (mbi->flags, 12)) + //{ + //sprintf("flag present"); + multiboot_uint32_t color; + unsigned i; + void *fb = (void *) (unsigned long) mbi->framebuffer_addr; + +sprintf("fb_addr: %x, fb_width: %u, fb_height: %u", fb, mbi->framebuffer_width, mbi->framebuffer_height); + + switch (mbi->framebuffer_type) + { + case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED: + { + //sprintf("indexed"); + unsigned best_distance, distance; + struct multiboot_color *palette; + + palette = (struct multiboot_color *) mbi->framebuffer_palette_addr; + + color = 0; + best_distance = 4*256*256; + + for (i = 0; i < mbi->framebuffer_palette_num_colors; i++) + { + distance = (0xff - palette[i].blue) * (0xff - palette[i].blue) + + palette[i].red * palette[i].red + + palette[i].green * palette[i].green; + if (distance < best_distance) + { + color = i; + best_distance = distance; + } + } + } + break; + + case MULTIBOOT_FRAMEBUFFER_TYPE_RGB: + color = ((1 << mbi->framebuffer_blue_mask_size) - 1) + << mbi->framebuffer_blue_field_position; + break; + + case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT: + color = '\\' | 0x0100; + break; + + default: + color = 0xffffffff; + break; + } + for (i = 0; i < mbi->framebuffer_width + && i < mbi->framebuffer_height; i++) + { + switch (mbi->framebuffer_bpp) + { + case 8: + { + multiboot_uint8_t *pixel = fb + mbi->framebuffer_pitch * i + i; + *pixel = color; + } + break; + case 15: + case 16: + { + multiboot_uint16_t *pixel + = fb + mbi->framebuffer_pitch * i + 2 * i; + *pixel = color; + } + break; + case 24: + { + multiboot_uint32_t *pixel + = fb + mbi->framebuffer_pitch * i + 3 * i; + *pixel = (color & 0xffffff) | (*pixel & 0xff000000); + } + break; + + case 32: + { + multiboot_uint32_t *pixel + = fb + mbi->framebuffer_pitch * i + 4 * i; + *pixel = color; + } + break; + } + } + //} + + hcf(); +} diff --git a/src/multiboot.h b/src/multiboot.h new file mode 100644 index 0000000..1ba51c4 --- /dev/null +++ b/src/multiboot.h @@ -0,0 +1,274 @@ +/* multiboot.h - Multiboot header file. */ +/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MULTIBOOT_HEADER +#define MULTIBOOT_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_HEADER_ALIGN 4 + +/* The magic field should contain this. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* This should be in %eax. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000004 + +/* Flags set in the 'flags' member of the multiboot header. */ + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +/* Flags to be set in the 'flags' member of the multiboot info structure. */ + +/* is there basic lower/upper memory information? */ +#define MULTIBOOT_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define MULTIBOOT_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define MULTIBOOT_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define MULTIBOOT_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define MULTIBOOT_INFO_ELF_SHDR 0X00000020 + +/* is there a full memory map? */ +#define MULTIBOOT_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define MULTIBOOT_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define MULTIBOOT_INFO_VBE_INFO 0x00000800 +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 + +#ifndef ASM_FILE + +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + multiboot_uint32_t magic; + + /* Feature flags. */ + multiboot_uint32_t flags; + + /* The above fields plus this one must equal 0 mod 2^32. */ + multiboot_uint32_t checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; + multiboot_uint32_t entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + multiboot_uint32_t mode_type; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +/* The symbol table for a.out. */ +struct multiboot_aout_symbol_table +{ + multiboot_uint32_t tabsize; + multiboot_uint32_t strsize; + multiboot_uint32_t addr; + multiboot_uint32_t reserved; +}; +typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; + +/* The section header table for ELF. */ +struct multiboot_elf_section_header_table +{ + multiboot_uint32_t num; + multiboot_uint32_t size; + multiboot_uint32_t addr; + multiboot_uint32_t shndx; +}; +typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; + +struct multiboot_info +{ + /* Multiboot info version number */ + multiboot_uint32_t flags; + + /* Available memory from BIOS */ + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; + + /* "root" partition */ + multiboot_uint32_t boot_device; + + /* Kernel command line */ + multiboot_uint32_t cmdline; + + /* Boot-Module list */ + multiboot_uint32_t mods_count; + multiboot_uint32_t mods_addr; + + union + { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; + + /* Memory Mapping buffer */ + multiboot_uint32_t mmap_length; + multiboot_uint32_t mmap_addr; + + /* Drive Info buffer */ + multiboot_uint32_t drives_length; + multiboot_uint32_t drives_addr; + + /* ROM configuration table */ + multiboot_uint32_t config_table; + + /* Boot Loader Name */ + multiboot_uint32_t boot_loader_name; + + /* APM table */ + multiboot_uint32_t apm_table; + + /* Video */ + multiboot_uint32_t vbe_control_info; + multiboot_uint32_t vbe_mode_info; + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + union + { + struct + { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; +typedef struct multiboot_info multiboot_info_t; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; + +struct multiboot_mmap_entry +{ + multiboot_uint32_t size; + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + multiboot_uint32_t type; +} __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_mod_list +{ + /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + + /* Module command line */ + multiboot_uint32_t cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + multiboot_uint32_t pad; +}; +typedef struct multiboot_mod_list multiboot_module_t; + +/* APM BIOS info. */ +struct multiboot_apm_info +{ + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ diff --git a/src/stdio.c b/src/stdio.c new file mode 100644 index 0000000..f1c9678 --- /dev/null +++ b/src/stdio.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include + +void putc(char ch) { + vga_putc(ch); +} + +void puts(const char* str) { + do { + putc(*str); + } while(*++str != '\0'); +} + +void printf(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + + for(int i = 0; fmt[i] != '\0'; i++) + { + switch(fmt[i]) + { + case '%': + i++; + + char buf[512]; + + size_t width = 0; + char padding_char = fmt[i]; + if(isdigit(fmt[i]) || fmt[i] == ' ') { + i++; + int pos = 0; + while(isdigit(fmt[i])) { + buf[pos++] = fmt[i++]; + } + buf[pos] = '\0'; + width = atoi(buf); + } + + const char* out = 0; + + if(fmt[i] == 's') + out = va_arg(args, const char*); + if(fmt[i] == 'd') + out = itoa(va_arg(args, int), buf, 10); + if(fmt[i] == 'u') + out = ultoa(va_arg(args, uint32_t), buf, 10); + if(fmt[i] == 'x') + out = ultoa(va_arg(args, uint32_t), buf, 16); + if(fmt[i] == 'c') + putc(va_arg(args, int)); + + size_t len = strlen(out); + if(width > len) { + char padding[256]; + size_t j = 0; + for(; j < width - len; j++) + padding[j] = padding_char; + padding[j] = '\0'; + puts(padding); + } + + puts(out); + break; + default: + putc(fmt[i]); + break; + } + } + + va_end(args); +} diff --git a/src/stdio.h b/src/stdio.h new file mode 100644 index 0000000..35a69fe --- /dev/null +++ b/src/stdio.h @@ -0,0 +1,9 @@ +#ifndef __STDIO_H__ +#define __STDIO_H__ +#include + +void putc(char ch); +void puts(const char* str); +void printf(const char* fmt, ...); + +#endif diff --git a/src/stdlib.c b/src/stdlib.c new file mode 100644 index 0000000..4d12dcf --- /dev/null +++ b/src/stdlib.c @@ -0,0 +1,77 @@ +#include +#include + +const char* itoa(int value, char* str, int base) +{ + char* rc; + char* ptr; + char* low; + + if (base < 2 || base > 36) + { + *str = '\0'; + return str; + } + rc = ptr = str; + if (value < 0 && base == 10) + { + *ptr++ = '-'; + } + + low = ptr; + do + { + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + value % base]; + value /= base; + } while (value); + + *ptr-- = '\0'; + while (low < ptr) + { + char tmp = *low; + *low++ = *ptr; + *ptr-- = tmp; + } + return rc; +} + +const char* ultoa(uint32_t value, char* str, int base) +{ + char* rc; + char* ptr; + char* low; + + if (base < 2 || base > 36) + { + *str = '\0'; + return str; + } + rc = ptr = str; + + low = ptr; + do + { + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + value % base]; + value /= base; + } while (value); + + *ptr-- = '\0'; + while (low < ptr) + { + char tmp = *low; + *low++ = *ptr; + *ptr-- = tmp; + } + return rc; +} + +int atoi(const char* str) { + int value = 0; + while(isdigit(*str)) { + value *= 10; + value += (*str)-'0'; + str++; + } + + return value; +} diff --git a/src/stdlib.h b/src/stdlib.h new file mode 100644 index 0000000..dc98a47 --- /dev/null +++ b/src/stdlib.h @@ -0,0 +1,9 @@ +#ifndef __STDLIB_H__ +#define __STDLIB_H__ +#include + +const char* itoa(int value, char* str, int base); +const char* ultoa(uint32_t value, char* str, int base); +int atoi(const char* str); + +#endif diff --git a/src/string.c b/src/string.c new file mode 100644 index 0000000..8ac0dbe --- /dev/null +++ b/src/string.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/src/string.h b/src/string.h new file mode 100644 index 0000000..7a3003c --- /dev/null +++ b/src/string.h @@ -0,0 +1,7 @@ +#ifndef __STRING_H__ +#define __STRING_H__ +#include + +size_t strlen(const char* str); + +#endif diff --git a/src/vga.c b/src/vga.c new file mode 100644 index 0000000..ce72f9d --- /dev/null +++ b/src/vga.c @@ -0,0 +1,39 @@ +#include +#include + +struct vga_terminal vga_term = { 0 }; +uint16_t* VGA = (uint16_t*)0xb8000; + +void vga_putc(char ch) { + if(ch == '\n') { + vga_term.x = 0; + vga_term.y++; + } else { + int index = vga_term.y * VGA_WIDTH + vga_term.x; + + VGA[index] = ch | (vga_term.fg | vga_term.bg << 4) << 8; + + vga_term.x++; + if(vga_term.x > VGA_WIDTH) { + vga_term.x = 0; + vga_term.y++; + } + } +} + +void vga_clear() { + vga_term.x = 0; + vga_term.y = 0; + for(int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++) + putc(' '); +} + +void init_vga(void) { + vga_term.fg = 7; + vga_term.bg = 0; + + vga_clear(); + + vga_term.x = 0; + vga_term.y = 0; +} diff --git a/src/vga.h b/src/vga.h new file mode 100644 index 0000000..807033b --- /dev/null +++ b/src/vga.h @@ -0,0 +1,20 @@ +#ifndef __VGA_H__ +#define __VGA_H__ +#include + +#define VGA_WIDTH 80 +#define VGA_HEIGHT 25 + +struct vga_terminal { + uint8_t bg; + uint8_t fg; + uint8_t x; + uint8_t y; +}; + +extern struct vga_terminal vga_term; + +void init_vga(void); +void vga_putc(char ch); + +#endif