diff --git a/Makefile b/Makefile index 8b38f24..2a8c565 100644 --- a/Makefile +++ b/Makefile @@ -52,5 +52,7 @@ run: all qemu-system-x86_64 \ -cdrom $(BUILD_DIR)/$(ISO_NAME) \ -serial stdio \ + -display gtk,show-menubar=off,zoom-to-fit=on \ -m 4G \ + -enable-kvm \ -name corn diff --git a/include/lib.h b/include/lib.h index 1b6d1f4..3be1f8b 100644 --- a/include/lib.h +++ b/include/lib.h @@ -1,5 +1,6 @@ #pragma once +#include #include /** @@ -109,7 +110,7 @@ long long int atoll(const char* s); /** * Converts a integer to asci inside a string with a given radix (base). - * @param n - the number to conver + * @param n - the number to conver * @param buffer - the string buffer * @param radix - the base to convert */ @@ -117,15 +118,23 @@ char *itoa(int n, char *buffer, int radix); /** * Converts a long to asci inside a string with a given radix (base). - * @param n - the number to conver + * @param n - the number to conver * @param buffer - the string buffer * @param radix - the base to convert */ char *ltoa(long int n, char *buffer, int radix); +/** + * Converts a long long to asci inside a string with a given radix (base). + * @param n - the number to conver + * @param buffer - the string buffer + * @param radix - the base to convert + */ +char *lltoa(long long int n, char *buffer, int radix); + /** * Converts a unsigned integer to asci inside a string with a given radix (base). - * @param n - the number to conver + * @param n - the number to conver * @param buffer - the string buffer * @param radix - the base to convert */ @@ -133,12 +142,20 @@ char *utoa(unsigned int n, char *buffer, int radix); /** * Converts a unsigned long to asci inside a string with a given radix (base). - * @param n - the number to conver + * @param n - the number to conver * @param buffer - the string buffer * @param radix - the base to convert */ char *ultoa(unsigned long int n, char *buffer, int radix); +/** + * Converts a unsigned long long to asci inside a string with a given radix (base). + * @param n - the number to conver + * @param buffer - the string buffer + * @param radix - the base to convert + */ +char *ulltoa(unsigned long long int n, char *buffer, int radix); + /** * Converts the string in str to an int value based on the given base. * The endptr is updated to where the string was no longer valid. @@ -168,3 +185,30 @@ long int strtol(const char *str, char **endptr, int base); * @returns 0 on error or success, error if endptr is still equal to str */ long long int strtoll(const char *str, char **endptr, int base); + +/** + * Prints out a char + * @param c - the char + */ +void kputc(char c); + +/** + * Prints out a null terminated string + * @param s - the string + */ +void kputs(const char *s); + +/** + * Prints out a formatted string + * @param format - the format string + * @param ... - variable args for the format + */ +void kvprintf(const char *format, va_list args); + +/** + * Prints out a formatted string + * @param format - the format string + * @param ... - variable args for the format + */ +__attribute__((format(printf, 1, 2))) +void kprintf(const char *format, ...); diff --git a/include/serial.h b/include/serial.h index a7da91c..7587d74 100644 --- a/include/serial.h +++ b/include/serial.h @@ -5,4 +5,4 @@ int serial_init(void); uint8_t serial_in(void); void serial_out(uint8_t ch); -void serial_out_str(char *str); +void serial_out_str(const char *str); diff --git a/include/shim.h b/include/shim.h index dc8c19c..7178a0f 100644 --- a/include/shim.h +++ b/include/shim.h @@ -2,7 +2,8 @@ #include -#define CMDLINE_MAX 32 +#define CMDLINE_MAX 32 +#define MMAP_MAX_ENTRY 64 struct memory_segment { uint64_t addr; @@ -12,8 +13,7 @@ struct memory_segment { struct memory_map { uint32_t entry_count; - uint32_t entry_length; - struct memory_segment *entries; + struct memory_segment entries[MMAP_MAX_ENTRY]; }; struct boot_info { diff --git a/src/arch/amd64/acpi.c b/src/arch/amd64/acpi.c index 83f2014..70c2f38 100644 --- a/src/arch/amd64/acpi.c +++ b/src/arch/amd64/acpi.c @@ -31,7 +31,7 @@ struct rsdp { char oemid[6]; uint8_t revision; uint32_t rsdt_addr; -} __attribute__((packed)); +}; // eXtended system descriptor pointer // ACPI 2.0 @@ -46,7 +46,7 @@ struct xsdp { uint64_t xsdt_addr; uint8_t extendeid_checksum; uint8_t reserved[3]; -} __attribute__((packed)); +}; // root system descriptor table // ACPI 1.0 @@ -161,10 +161,8 @@ static bool checksum(uint8_t *data, size_t len) { } static int read_s5_addr(struct acpi_state *state) { - serial_out_str("a"); uintptr_t ptr = state->fadt.dsdt; char *s5_addr = (void*) (ptr + 36); - serial_out_str("a"); int dsdt_len = *((int*) (ptr+1)) - 36; while (0 < dsdt_len--) { @@ -256,6 +254,7 @@ int acpi_init_rsdt(struct rsdt *rsdt) { int acpi_init_xsdt(struct xsdt *xsdt) { xsdt = mmap(xsdt, sizeof(struct xsdt)); + return -1; state.dst.xsdt = xsdt; state.version = 2; diff --git a/src/arch/amd64/boot.S b/src/arch/amd64/boot.S index 55d942b..455b68b 100644 --- a/src/arch/amd64/boot.S +++ b/src/arch/amd64/boot.S @@ -90,6 +90,8 @@ start: push DWORD 0 push ebx + push DWORD 0 + push eax mov edi, 0x1000 mov cr3, edi @@ -143,8 +145,10 @@ code64: xor rbp, rbp ; set ebp to 0 so we know where to end stack traces pop rdi + pop rsi call amd64_shim mov rdi, rax + xor rsi, rsi sti call kmain diff --git a/src/arch/amd64/linker.ld b/src/arch/amd64/linker.ld new file mode 100644 index 0000000..0032765 --- /dev/null +++ b/src/arch/amd64/linker.ld @@ -0,0 +1,38 @@ +ENTRY(start) + +SECTIONS { + . = 1M; + + kernel_start = .; + + .boot BLOCK(4K) : ALIGN(4K) + { + *(.multiboot) + } + + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + text_start = .; + + .text BLOCK(4K) : ALIGN(4K) + { + *(.text) + } + + text_end = .; + + .bss BLOCK(4K) : ALIGN(4K) + { + *(.bss) + } + + kernel_end = .; +} diff --git a/src/arch/amd64/mboot.c b/src/arch/amd64/mboot.c index 6c3c413..b7124df 100644 --- a/src/arch/amd64/mboot.c +++ b/src/arch/amd64/mboot.c @@ -1,17 +1,25 @@ -#include "mboot.h" -#include "serial.h" -#include "shim.h" - +#include #include #include +#include + +#include "mboot.h" + +#define MBOOT_HEADER_MAGIC 0x36D76289 + +#define MBOOT_CMDLINE 1 +#define MBOOT_MEMORY_MAP 6 +#define MBOOT_ELF_SYMBOLS 9 +#define MBOOT_OLD_RSDP 14 +#define MBOOT_NEW_RSDP 15 extern char symtab; #define kaddr(addr) ((uintptr_t)(&addr)) -typedef unsigned char mboot_uint8_t; -typedef unsigned short mboot_uint16_t; -typedef unsigned int mboot_uint32_t; -typedef unsigned long long mboot_uint64_t; +typedef uint8_t mboot_uint8_t; +typedef uint16_t mboot_uint16_t; +typedef uint32_t mboot_uint32_t; +typedef uint64_t mboot_uint64_t; struct mboot_info { mboot_uint32_t total_size; @@ -25,24 +33,17 @@ struct mboot_tag { char data[]; }; -enum mboot_tag_type { - MBOOT_CMDLINE = 0, - MBOOT_MEMORYMAP = 6, - MBOOT_SYMBOLS = 9, - MBOOT_RSDP = 14, - MBOOT_XSDP = 15, -}; - -struct mboot_elf_header_layout { +struct mboot_tag_elf_sections { mboot_uint32_t type; mboot_uint32_t size; - mboot_uint32_t num; - mboot_uint32_t entsize; - mboot_uint32_t shndx; - char elf_section_headers[]; + mboot_uint16_t num; + mboot_uint16_t entsize; + mboot_uint16_t shndx; + mboot_uint16_t reserved; + char sections[]; }; -struct mboot_elf_section_header { +struct mboot_tag_elf_sections_entry { mboot_uint32_t sh_name; mboot_uint32_t sh_type; mboot_uint64_t sh_flags; @@ -55,45 +56,46 @@ struct mboot_elf_section_header { mboot_uint64_t sh_entsize; }; -struct mboot_memory_segment { +struct mboot_mmap_entry { mboot_uint64_t addr; mboot_uint64_t len; mboot_uint32_t type; - mboot_uint32_t reserved; + mboot_uint32_t zero; }; -struct mboot_memory_map { - mboot_uint32_t tag; +struct mboot_tag_mmap { + mboot_uint32_t type; mboot_uint32_t size; mboot_uint32_t entry_size; mboot_uint32_t entry_version; - struct memory_segment entries[]; + struct mboot_mmap_entry entries[]; }; -struct mboot_rsdp { - mboot_uint32_t tag; + +struct mboot_tag_old_rsdp { + mboot_uint32_t type; mboot_uint32_t size; mboot_uint8_t rsdp[]; }; -struct mboot_xsdp { - mboot_uint32_t tag; +struct mboot_tag_new_rsdp { + mboot_uint32_t type; mboot_uint32_t size; - mboot_uint8_t xsdp[]; + mboot_uint8_t rsdp[]; }; -struct mboot_cmdline { - mboot_uint32_t tag; +struct mboot_tag_cmdline { + mboot_uint32_t type; mboot_uint32_t size; - char cmdline[]; + mboot_uint8_t cmdline[]; }; static void read_symbols( struct boot_info *shim_info, - struct mboot_elf_header_layout *layout + struct mboot_tag_elf_sections *sections ) { - shim_info->symbol_table = layout->elf_section_headers; + shim_info->symbol_table = sections->sections; // struct mboot_elf_section_header *section = // (struct mboot_elf_section_header *) (layout->elf_section_headers); @@ -130,7 +132,7 @@ static void read_symbols( static void read_cmdline( struct boot_info *shim_info, - struct mboot_cmdline *cmdline + struct mboot_tag_cmdline *cmdline ) { mboot_uint32_t size = cmdline->size - 8; if (size >= CMDLINE_MAX) @@ -139,39 +141,49 @@ static void read_cmdline( shim_info->cmdline[size] = '\0'; } -static void read_memorymap( +static void read_memory_map( struct boot_info *shim_info, - struct mboot_memory_map *map + struct mboot_tag_mmap *map ) { - int size = map->size - sizeof(mboot_uint32_t) * 4; - int count = size / map->entry_size; - - shim_info->map.entry_count = count; - shim_info->map.entry_length = map->entry_size; - shim_info->map.entries = map->entries; + int idx = 0; + uintptr_t i = (uintptr_t)map->entries; + for ( ; + i < (uintptr_t)map->entries + map->size; + i += map->entry_size, idx++ + ) { + struct mboot_mmap_entry *seg = (struct mboot_mmap_entry *) i; + shim_info->map.entries[idx].addr = seg->addr; + shim_info->map.entries[idx].type = seg->type; + shim_info->map.entries[idx].len = seg->len; + } + shim_info->map.entry_count = idx; } -static void read_rsdp( +static void read_old_rsdp( struct boot_info *shim_info, - struct mboot_rsdp *rsdp + struct mboot_tag_old_rsdp *rsdp ) { if (shim_info->acpi_table != NULL) return; // xsdp is newer and has been loaded shim_info->acpi_table = rsdp->rsdp; } -static void read_xsdp( +static void read_new_rsdp( struct boot_info *shim_info, - struct mboot_xsdp *xsdp + struct mboot_tag_new_rsdp *rsdp ) { - shim_info->acpi_table = xsdp->xsdp; + shim_info->acpi_table = rsdp->rsdp; } void mboot_load_info( + long mboot_magic, const void *mboot_data_ptr, struct boot_info *shim_info ) { + if (mboot_magic != MBOOT_HEADER_MAGIC) + panic("invalid multiboot magic"); + memset(shim_info, 0, sizeof(struct boot_info)); struct mboot_info *mboot_info = (struct mboot_info *) mboot_data_ptr; @@ -186,31 +198,31 @@ void mboot_load_info( case MBOOT_CMDLINE: read_cmdline( shim_info, - (struct mboot_cmdline *) tag + (struct mboot_tag_cmdline *) tag ); break; - case MBOOT_MEMORYMAP: - read_memorymap( + case MBOOT_MEMORY_MAP: + read_memory_map( shim_info, - (struct mboot_memory_map *) tag + (struct mboot_tag_mmap *) tag ); break; - case MBOOT_SYMBOLS: + case MBOOT_ELF_SYMBOLS: read_symbols( shim_info, - (struct mboot_elf_header_layout *) tag + (struct mboot_tag_elf_sections *) tag ); break; - case MBOOT_RSDP: - read_rsdp( + case MBOOT_OLD_RSDP: + read_old_rsdp( shim_info, - (struct mboot_rsdp *) tag + (struct mboot_tag_old_rsdp *) tag ); break; - case MBOOT_XSDP: - read_xsdp( + case MBOOT_NEW_RSDP: + read_new_rsdp( shim_info, - (struct mboot_xsdp *) tag + (struct mboot_tag_new_rsdp *) tag ); break; default: diff --git a/src/arch/amd64/mboot.h b/src/arch/amd64/mboot.h index 90ed75c..b9c647b 100644 --- a/src/arch/amd64/mboot.h +++ b/src/arch/amd64/mboot.h @@ -8,4 +8,4 @@ * @param mboot_info - the pointer passed from multiboot2 * @param shim_info - the info to be collected by shim */ -void mboot_load_info(const void *mboot_info, struct boot_info *shim_info); +void mboot_load_info(long mboot_magic, const void *mboot_info, struct boot_info *shim_info); diff --git a/src/arch/amd64/serial.c b/src/arch/amd64/serial.c index 85cd408..d63d9dd 100644 --- a/src/arch/amd64/serial.c +++ b/src/arch/amd64/serial.c @@ -16,7 +16,7 @@ int serial_init(void) { // outb(port + 4, 0x0B); // TODO copied this from osdev wiki but i don't think you need it here outb(PORT + 4, 0x1E); // set in loopback mode for test outb(PORT + 0, 0xAE); // test by sending 0xAE - + uint8_t response = inb(PORT + 0); if(response != 0xAE) { // TODO panic here? @@ -40,7 +40,7 @@ void serial_out(uint8_t ch) { outb(PORT, ch); } -void serial_out_str(char *str) { +void serial_out_str(const char *str) { for(; *str != '\0'; str++) { serial_out(*str); } diff --git a/src/arch/amd64/shim.c b/src/arch/amd64/shim.c index 7332994..3c0bd72 100644 --- a/src/arch/amd64/shim.c +++ b/src/arch/amd64/shim.c @@ -11,14 +11,13 @@ static struct boot_info boot_info; -void* amd64_shim(void *mboot_data_ptr) { - +void* amd64_shim(long mboot_magic, void *mboot_data_ptr) { serial_init(); paging_init(); pic_remap(); idt_init(); - mboot_load_info(mboot_data_ptr, &boot_info); + mboot_load_info(mboot_magic, mboot_data_ptr, &boot_info); return &boot_info; } diff --git a/src/kmain.c b/src/kmain.c index 54ed506..057620d 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -10,11 +10,13 @@ void kmain(struct boot_info *info) { //acpi_init(info->acpi_table); //fb_init(1024, 768); - serial_out_str("entered kmain\n"); + kprintf("enterd kmain\n"); + *(char*)(0xB8000 + 0x144) = 'h'; *(char*)(0xB8000 + 0x146) = 'i'; while (1) { + //kprintf("ret: 0x%p\n", kalloc(2)); // loop so we dont halt // this allows interrupts to fire } diff --git a/src/lib.c b/src/lib.c index db09dda..7f3d79f 100644 --- a/src/lib.c +++ b/src/lib.c @@ -1,5 +1,5 @@ +#include "memory.h" #include - #include int memcmp(const void *restrict vl, const void *restrict vr, unsigned long n) { @@ -31,6 +31,7 @@ void *memmove(void *dest, const void *src, unsigned long n) { } void *memset(void *restrict dest, int c, unsigned long n) { + unsigned char *d = dest; for (; n; n--) *d++ = c; return dest; @@ -149,6 +150,7 @@ int ctoi(char c) { UXTOA(int, utoa) UXTOA(long int, ultoa) +UXTOA(long long int, ulltoa) #define XTOA(type, name) \ char *name(type n, char* buffer, int radix) { \ @@ -176,6 +178,7 @@ UXTOA(long int, ultoa) XTOA(int, itoa) XTOA(long int, ltoa) +XTOA(long long int, lltoa) #define STRTOX(name, type) \ type name(const char *s, char **endptr, int radix) { \ diff --git a/src/memory/memory.c b/src/memory/memory.c index 1c69bae..af63865 100644 --- a/src/memory/memory.c +++ b/src/memory/memory.c @@ -1,10 +1,8 @@ +#include "serial.h" #include #include #include - -#ifdef MEMORY_PANIC #include -#endif #define MAGIC 0xBEEFCAFE @@ -18,8 +16,8 @@ struct page_header { }; static const size_t header_len = sizeof(struct page_header); -struct page_header *start_header = NULL; -struct page_header *end_header = NULL; +static struct page_header *start_header = NULL; +static struct page_header *end_header = NULL; struct page_header* get_header(void *ptr) { struct page_header *header = @@ -36,6 +34,7 @@ struct page_header* get_header(void *ptr) { void *kalloc_new(size_t size) { size_t pages = ((size + header_len) / PAGE_SIZE) + 1; + void *addr = alloc_pages(pages); void *mem = (char *)addr + header_len; @@ -54,20 +53,20 @@ void *kalloc_new(size_t size) { } struct page_header *header = addr; - header->magic = MAGIC; + header->magic = 0xBEEFCAFE; header->used = size; header->free = free; header->prev = end_header; header->next = NULL; header->node_number = node; - if (end_header == NULL) { + if (start_header == NULL) { start_header = header; - } else { - end_header->next = header; } - end_header = header; + if (end_header != NULL) { + end_header->next = header; + } return mem; } @@ -97,6 +96,9 @@ void *kalloc(size_t size) { for (; header != NULL; header = header->next) { size_t free = header->free; + if (free < header_len) { + continue; + } if (size <= (free - header_len)) { // we must be able to fit data + header break; } @@ -129,21 +131,13 @@ void *krealloc(void *src, size_t dst_len) { header = get_header(src); if (header == NULL) { -#ifdef MEMORY_PANIC panic("attempted to realloc on a invalid ptr"); -#else - return NULL; // invalid pointer passed -#endif } src_len = header->used; if (src_len == 0) { -#ifdef MEMORY_PANIC panic("attempted to realloc on an empty ptr"); -#else - return NULL; // likely double free :( -#endif } dst = kalloc(dst_len); @@ -166,11 +160,7 @@ void kfree(void *ptr) { header = get_header(ptr); if (header == NULL || header->used == 0) { -#ifdef MEMORY_PANIC panic("attempted to kfree invalid pointer"); -#else - return; -#endif } header->free += header->used; diff --git a/src/memory/physalloc.c b/src/memory/physalloc.c index 1140258..bcbc66d 100644 --- a/src/memory/physalloc.c +++ b/src/memory/physalloc.c @@ -1,3 +1,4 @@ +#include "serial.h" #include #include #include @@ -63,6 +64,10 @@ static inline bool bitmap_get(int i) { } static inline void bitmap_set(int i, bool v) { + if (v) + free_memory -= PAGE_SIZE; + else + free_memory += PAGE_SIZE; int idx = i / 64; bitmap[idx] &= ~(1 << i % 64); bitmap[idx] |= (v << i % 64); @@ -115,11 +120,11 @@ void free_phys_pages(void *ptr, int pages) { } static bool segment_invalid(const struct memory_segment *segment) { - if (segment->type != 1) return false; - if (segment->addr < kaddr(kernel_start)) return false; - if (segment->addr + segment->len < memory_start) return false; - if (segment->addr + segment->len < kaddr(kernel_start)) return false; - return true; + if (segment->type != 1) return true; + if (segment->addr < kaddr(kernel_start)) return true; + if (segment->addr + segment->len < memory_start) return true; + if (segment->addr + segment->len < kaddr(kernel_start)) return true; + return false; } static struct memory_area segment_to_area(const struct memory_segment *segment) { @@ -195,18 +200,28 @@ void memory_init(struct memory_map *map) { struct memory_area *area = page_start; + kprintf("MEMORY MAP\n"); for(uint32_t i = 0; i < map->entry_count; i++) { struct memory_segment *segment = &map->entries[i]; if (segment_invalid(segment)) continue; + kprintf("addr: 0x%16p\tlen: %ld\n", (void *)segment->addr, segment->len); + struct memory_area temp = segment_to_area(segment); *area = temp; area++; } + total_memory = page_count * PAGE_SIZE; page_count -= bitmap_pages; + free_memory = page_count * PAGE_SIZE; + + kprintf("\nMEMORY USAGE\n"); + kprintf("mem total: %ld\n", memory_total()); + kprintf("mem free: %ld\n", memory_free()); + kprintf("mem used: %ld\n\n", memory_used()); memory_unlock(); diff --git a/src/memory/virtalloc.c b/src/memory/virtalloc.c index 781fc9b..2ab9fc2 100644 --- a/src/memory/virtalloc.c +++ b/src/memory/virtalloc.c @@ -1,6 +1,9 @@ +#include "lib.h" +#include "panic.h" #include #include #include +#include #define MEMORY_INTERNAL #include @@ -10,34 +13,60 @@ struct addr_node { uintptr_t end; struct addr_node *next; struct addr_node *prev; - uint8_t is_alloc; - uint8_t is_bss; + uint8_t is_alloc; // if node is storing allocated data + uint8_t is_used; // if node is in use by virtalloc }; -#define BOOTSTRAP_BSS_NODES 16 -static uint8_t bss_nodes = 0; -static struct addr_node nodes[BOOTSTRAP_BSS_NODES]; +#define BSS_NODES 64 +static struct addr_node bootstrap_nodes[BSS_NODES]; +static struct addr_node *alloc_nodes = NULL; +static size_t free_node_start = 0; +static size_t alloc_node_count = 0; +static size_t used_node_count = 0; +static bool is_allocating = false; -static struct addr_node *start_node; +static struct addr_node *start_node = NULL; -static struct addr_node *alloc_node(void) { - struct addr_node *node = NULL; - if (bss_nodes >= BOOTSTRAP_BSS_NODES) { - node = kalloc(sizeof(struct addr_node)); - if (node == NULL) - return NULL; - node->is_bss = false; +static struct addr_node *get_node_idx(int idx) { + if (idx < BSS_NODES) { + return &bootstrap_nodes[idx]; } else { - node = &nodes[bss_nodes]; - bss_nodes += 1; - node->is_bss = true; + return &alloc_nodes[idx - BSS_NODES]; } - return node; +} + +static struct addr_node *get_node(void) { + size_t count = BSS_NODES + alloc_node_count; + + if (!is_allocating && used_node_count + 16 >= count) { + is_allocating = true; + int new_alloc = alloc_node_count * 2; + if (new_alloc < 8) + new_alloc = 8; + int allocated = new_alloc - alloc_node_count; + int old = new_alloc - allocated; + alloc_nodes = krealloc(alloc_nodes, sizeof(struct addr_node) * new_alloc); + memset(alloc_nodes + old, 0, sizeof(struct addr_node) + allocated);; + alloc_node_count = new_alloc; + is_allocating = false; + count = BSS_NODES + alloc_node_count; + } + + size_t idx = free_node_start; + for (; idx < count; idx++) { + struct addr_node *node = get_node_idx(idx); + if (!node->is_used) { + used_node_count++; + return node; + } + } + + panic("could not get virtaddr node"); } static void free_node(struct addr_node *node) { - if (!node->is_bss) - kfree(node); + node->is_used = false; + used_node_count--; } void virtaddr_init(void) { @@ -47,11 +76,11 @@ void virtaddr_init(void) { .next = NULL, .prev = NULL, .is_alloc = false, - .is_bss = true, + .is_used = true, }; - nodes[0] = init; - start_node = &nodes[0]; - bss_nodes++; + memset(bootstrap_nodes, 0, sizeof(bootstrap_nodes)); + bootstrap_nodes[0] = init; + start_node = &bootstrap_nodes[0]; } void *virtaddr_alloc(int n_pages) { @@ -69,10 +98,7 @@ void *virtaddr_alloc(int n_pages) { long length = node->end - node->start; if (length >= n_length) { - struct addr_node *new = alloc_node(); - if (node == NULL) { - return NULL; - } + struct addr_node *new = get_node(); if (node->prev != NULL) { node->prev->next = new; } @@ -82,6 +108,7 @@ void *virtaddr_alloc(int n_pages) { new->end = new->start + n_length; node->start = new->end; new->is_alloc = true; + new->is_used = true; new->next = node; return (void *) new->start; } diff --git a/src/print.c b/src/print.c new file mode 100644 index 0000000..f158985 --- /dev/null +++ b/src/print.c @@ -0,0 +1,564 @@ +#include +#include +#include + +void kputc(char c) { + serial_out(c); +} + +void kputs(const char *s) { + serial_out_str(s); +} + +enum format_flag { + FLG_NONE = 0x00, + FLG_ALTERNATE = 0x01, + FLG_ZERO = 0x02, + FLG_LEFT_ALIGN = 0x04, + FLG_ADD_SIGN = 0x08 +}; + +struct format_width { + bool defined; + bool varys; + int value; +}; + +struct format_precision { + bool defined; + bool varys; + int value; +}; + +enum format_modifier { + MOD_NONE, + MOD_INVALID, + MOD_HALF_HALF, + MOD_HALF, + MOD_LONG_LONG, + MOD_LONG, +}; + +enum format_conversion { + FMT_INT, + FMT_UINT, + FMT_OCT, + FMT_HEX, + FMT_HEX_UPPER, + FMT_CHAR, + FMT_STR, + FMT_PTR, + FMT_PTR_UPPER, + FMT_PERCENT, + FMT_INVALID +}; + +static enum format_flag read_flag(const char *format, const char **end) { + + enum format_flag flag = FLG_NONE; + + for (; *format != '\0'; format++) { + switch (*format) { + case '#': + flag |= FLG_ALTERNATE; + break; + case '0': + flag |= FLG_ZERO; + break; + case '-': + flag |= FLG_LEFT_ALIGN; + break; + case '+': + flag |= FLG_ADD_SIGN; + break; + default: + *end = format; + return flag; + } + } + + *end = format; + return flag; +} + +static struct format_width read_width(const char *format, const char **end) { + + struct format_width width; + width.defined = false; + width.varys = false; + width.value = 0; + + int value = 0; + + for (; *format != '\0'; format++) { + char c = *format; + + if (c == '*' && width.defined == false) { + width.defined = true; + width.varys = true; + break; + } + + if (!isdigit(c)) + break; + + int i = c - '0'; + value *= 10; + value += i; + + width.value = value; + width.defined = true; + width.varys = false; + } + + *end = format; + return width; + +} + +static struct format_precision read_precision(const char *format, const char **end) { + + struct format_precision precision; + precision.varys = false; + precision.defined = false; + precision.value = 0; + + if (*format != '.') { + *end = format; + return precision; + } + + format++; + + int value = 0; + + for (; *format != '\0'; format++) { + char c = *format; + + if (c == '*' && precision.defined == false) { + precision.defined = true; + precision.varys = true; + break; + } + + if (!isdigit(c)) + break; + + int i = c - '0'; + value *= 10; + value += i; + + precision.value = value; + precision.defined = true; + precision.varys = false; + } + + *end = format; + return precision; +} + +static enum format_modifier read_modifier(const char *format, const char **end) { + + enum format_modifier mod = MOD_NONE; + + for (; *format != '\0'; format++) { + *end = format; + switch (*format) { + case 'l': + if (mod == MOD_NONE) + mod = MOD_LONG; + else if (mod == MOD_LONG) + return MOD_LONG_LONG; + else + return MOD_INVALID; + break; + case 'L': + if (mod == MOD_NONE) + return MOD_LONG_LONG; + else + return MOD_INVALID; + break; + case 'h': + if (mod == MOD_NONE) + mod = MOD_HALF; + else if (mod == MOD_HALF) + return MOD_HALF_HALF; + else + return MOD_INVALID; + break; + case 'H': + if (mod == MOD_NONE) + return MOD_HALF_HALF; + else + return MOD_INVALID; + break; + default: + return mod; + } + } + + return MOD_INVALID; +} + +static enum format_conversion read_conversion(const char *format, const char **end) { + *end = format + 1; + switch (*format) { + case 'd': + case 'i': + return FMT_INT; + case 'o': + return FMT_OCT; + case 'u': + return FMT_UINT; + case 'x': + return FMT_HEX; + case 'X': + return FMT_HEX_UPPER; + case 'c': + return FMT_CHAR; + case 's': + return FMT_STR; + case 'p': + return FMT_PTR; + case 'P': + return FMT_PTR_UPPER; + case '%': + return FMT_PERCENT; + default: + return FMT_INVALID; + } +} + +static void print_string( + const char *str, + enum format_flag flag, + struct format_width width, + struct format_precision precision +) { + + size_t max_len = 0; + size_t min_len = 0; + size_t len = 0; + + if (width.defined) + min_len = width.value; + + if (precision.defined) { + max_len = precision.value; + len = max_len; + if (max_len < min_len) + min_len = max_len; + } else { + len = strlen(str); + } + + if (!(flag & FLG_LEFT_ALIGN) && len < min_len) { + for (size_t i = 0; i < (min_len - len); i++) { + kputc(' '); + } + } + + for (size_t i = 0; i < len; i++) { + kputc(str[i]); + } + + if ((flag & FLG_LEFT_ALIGN) && len < min_len) { + for (size_t i = 0; i < (min_len - len); i++) { + kputc(' '); + } + } +} + +static char get_letter( + char c, + char base +) { + if (c >= 0 && c <= 9) + return c + '0'; + c -= 10; + return c + base; +} + +static char *get_decimal( + long long num, + char *buf, + char sign, + int radix, + char base +) { + + *buf = '\0'; + buf--; + + if (num == 0) { + *buf = '0'; + buf--; + } + + while (num != 0) { + char i = num % radix; + char c = get_letter(i, base); + *buf = c; + buf--; + num /= radix; + } + + if (sign) { + *buf = sign; + buf--; + } + + buf++; + + return buf; +} + +static void print_unum( + unsigned long long num, + enum format_flag flag, + struct format_width width, + struct format_precision precision, + bool isneg, + int radix, + char base +) { + + size_t max_len = 0; + size_t min_len = 0; + size_t len = 0; + + char sign = 0; + if (isneg) + sign = '-'; + else if (flag & FLG_ADD_SIGN) + sign = '+'; + + char buf[1024]; + char *str = get_decimal( + num, + buf, + sign, + radix, + base + ); + + bool space_pre = (flag & FLG_LEFT_ALIGN) || !(flag & FLG_ZERO); + + if (space_pre && radix == 16 && flag & FLG_ALTERNATE) { + char x = base + ('x' - 'a'); + serial_out('0'); + serial_out(x); + } + + if (width.defined) + min_len = width.value; + + if (precision.defined) { + max_len = precision.value; + len = max_len; + if (max_len < min_len) + min_len = max_len; + } else { + len = strlen(str); + } + + bool zero_padded = false; + + if (!(flag & FLG_LEFT_ALIGN) && len < min_len) { + for (size_t i = 0; i < (min_len - len); i++) { + (flag & FLG_ZERO) ? kputc('0') : kputc(' '); + } + if (flag & FLG_ZERO) + zero_padded = true; + } + + kputs(str); + + if (!zero_padded && (flag & FLG_ALTERNATE) && radix == 8) + kputc('0'); + + if ((flag & FLG_LEFT_ALIGN) && len < min_len) { + for (size_t i = 0; i < (min_len - len); i++) { + (flag & FLG_ZERO) ? kputc('0') : kputc(' '); + } + } +} + +static void print_num( + long long num, + enum format_flag flag, + struct format_width width, + struct format_precision precision, + int radix, + char base +) { + bool isneg = false; + + if (num < 0) { + num = ~num; + isneg = true; + } + + print_unum( + num, + flag, + width, + precision, + isneg, + radix, + base + ); +} + +void kvprintf(const char *format, va_list args) { + for (; *format != '\0'; format++) { + char c = *format; + if (c == '%') { + enum format_flag flag; + struct format_width width; + struct format_precision precision; + enum format_modifier modifier; + enum format_conversion conversion; + + const char *ptr = format + 1; + + flag = read_flag(ptr, &ptr); + width = read_width(ptr, &ptr); + precision = read_precision(ptr, &ptr); + modifier = read_modifier(ptr, &ptr); + + if (modifier == MOD_INVALID) { + kputc('%'); + continue; + } + + conversion = read_conversion(ptr, &ptr); + + if (conversion == FMT_INVALID) { + kputc('%'); + continue; + } + + union { + unsigned long long u; + long long l; + char c; + const char *str; + void *ptr; + } data; + + int radix = 0; + char base = 0; + + switch (conversion) { + case FMT_INT: + if (modifier == MOD_NONE) + data.l = va_arg(args, int); + else if (modifier == MOD_HALF) + data.l = (short) va_arg(args, int); + else if (modifier == MOD_HALF_HALF) + data.l = (char) va_arg(args, int); + else if (modifier == MOD_LONG) + data.l = va_arg(args, long); + else if (modifier == MOD_LONG_LONG) + data.l = va_arg(args, long long); + radix = 10; + goto printnum; + case FMT_UINT: + case FMT_OCT: + case FMT_HEX_UPPER: + case FMT_HEX: + if (modifier == MOD_NONE) + data.u = va_arg(args, unsigned int); + else if (modifier == MOD_HALF) + data.u = (unsigned short) va_arg(args, unsigned int); + else if (modifier == MOD_HALF_HALF) + data.u = (unsigned char) va_arg(args, unsigned int); + else if (modifier == MOD_LONG) + data.u = va_arg(args, unsigned long); + else if (modifier == MOD_LONG_LONG) + data.u = va_arg(args, unsigned long long); + + if (conversion == FMT_UINT) { + radix = 10; + } else if (conversion == FMT_OCT) { + radix = 8; + } else if (conversion == FMT_HEX) { + radix = 16; + base = 'a'; + } else if (conversion == FMT_HEX_UPPER) { + radix = 16; + base = 'A'; + } + goto printunum; + case FMT_PTR: + case FMT_PTR_UPPER: + flag |= FLG_ZERO; + data.u = va_arg(args, size_t); + radix = 16; + if (conversion == FMT_PTR) + base = 'a'; + else + base = 'A'; + goto printunum; + printnum: + print_num( + data.l, + flag, + width, + precision, + radix, + base + ); + break; + printunum: + print_unum( + data.u, + flag, + width, + precision, + false, + radix, + base + ); + break; + case FMT_CHAR: { + char buf[2]; + buf[0] = (char) va_arg(args, int); + buf[1] = '\0'; + print_string( + buf, + flag, + width, + precision + ); + break; + } + case FMT_STR: + data.str = va_arg(args, const char*); + print_string( + data.str, + flag, + width, + precision + ); + break; + case FMT_PERCENT: + kputc('%'); + break; + case FMT_INVALID: + break; + } + format = ptr - 1; + } else { + kputc(c); + } + } +} + +void kprintf(const char *format, ...) { + va_list args; + va_start(args, format); + kvprintf(format, args); + va_end(args); +}