From e69a342b29ec483db9649f40cd22486800527ace Mon Sep 17 00:00:00 2001 From: Felix Queissner Date: Mon, 17 Aug 2015 15:38:19 +0200 Subject: [PATCH] Fixes nasty memory leaks. Adds memory tracing. Adds serial console for advanced debugging. Implements malloc correctly. --- Depfile | 2 +- Makefile | 70 ++++++++------- README.md | 2 + include/config.h | 8 ++ include/io.h | 7 ++ include/ker/string.hpp | 4 +- include/ker/vector.hpp | 2 +- include/serial.h | 51 +++++++++++ include/stdlib.h | 23 +++++ scripts/main.ts | 2 +- src/console.c | 48 ++--------- src/init.c | 6 +- src/malloc.c | 187 +++++++++++++++++++++++++++++++++++++---- src/serial.c | 85 +++++++++++++++++++ src/stdlib.c | 101 ++++++++++++++++++++-- src/vm.cpp | 20 +++-- trainOS.pro | 6 +- trainscript/tsvm.cpp | 9 +- 18 files changed, 516 insertions(+), 117 deletions(-) create mode 100644 include/serial.h create mode 100644 src/serial.c diff --git a/Depfile b/Depfile index 28dadb8..2f83128 100644 --- a/Depfile +++ b/Depfile @@ -36,4 +36,4 @@ obj/main.o: scripts/main.ts .PHONY: run run: - qemu-system-i386 -kernel kernel kernel + qemu-system-i386 -serial stdio -kernel kernel diff --git a/Makefile b/Makefile index 12adafb..1760a36 100644 --- a/Makefile +++ b/Makefile @@ -11,9 +11,9 @@ YACC = bison # File Lists SRCS_AS = asm/dynamic.S asm/intr_common_handler.S asm/multiboot.S asm/start.S -SRCS_CC = src/console.c src/init.c src/interrupts.c src/malloc.c src/pmm.c src/stdlib.c src/timer.c src/vmm.c +SRCS_CC = src/console.c src/init.c src/interrupts.c src/malloc.c src/pmm.c src/serial.c src/stdlib.c src/timer.c src/vmm.c SRCS_CXX = trainscript/tsvm.cpp src/cplusplus.cpp src/vm.cpp obj/trainscript.yy.cpp obj/trainscript.tab.cpp -OBJS = obj/tsvm.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/main.o +OBJS = obj/tsvm.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/main.o # Flags FLAGS = -m32 -Dnullptr=0 -D__cdecl="__attribute__((cdecl))" -mno-sse -mno-sse2 -mno-mmx @@ -27,40 +27,47 @@ all: kernel .PHONY: clean clean: - $(RM) obj/trainscript.yy.cpp obj/trainscript.tab.cpp obj/tsvm.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/main.o + $(RM) obj/trainscript.yy.cpp obj/trainscript.tab.cpp obj/tsvm.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/main.o -kernel: obj/tsvm.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/main.o - $(LD) $(FLAGS) $(LDFLAGS) -o $@ obj/tsvm.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/main.o +kernel: obj/tsvm.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/main.o + $(LD) $(FLAGS) $(LDFLAGS) -o $@ obj/tsvm.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/start.o obj/console.o obj/init.o obj/interrupts.o obj/malloc.o obj/pmm.o obj/serial.o obj/stdlib.o obj/timer.o obj/vmm.o obj/cplusplus.o obj/vm.o obj/trainscript.yy.o obj/trainscript.tab.o obj/main.o # src/console.c obj/console.o: src/console.c include/console.h include/stdlib.h \ - include/varargs.h + include/varargs.h include/config.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/console.c # src/init.c obj/init.o: src/init.c include/kernel.h include/stdlib.h include/varargs.h \ - include/console.h include/interrupts.h include/cpustate.h include/pmm.h \ - include/multiboot.h include/vmm.h include/config.h include/timer.h + include/config.h include/console.h include/interrupts.h \ + include/cpustate.h include/pmm.h include/multiboot.h include/vmm.h \ + include/timer.h include/serial.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/init.c # src/interrupts.c obj/interrupts.o: src/interrupts.c include/interrupts.h include/cpustate.h \ - include/console.h include/stdlib.h include/varargs.h include/io.h \ - src/intr_stubs.h + include/console.h include/stdlib.h include/varargs.h include/config.h \ + include/io.h src/intr_stubs.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/interrupts.c # src/malloc.c -obj/malloc.o: src/malloc.c include/stdlib.h include/varargs.h +obj/malloc.o: src/malloc.c include/kernel.h include/stdlib.h \ + include/varargs.h include/config.h include/console.h include/serial.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/malloc.c # src/pmm.c obj/pmm.o: src/pmm.c include/pmm.h include/multiboot.h include/kernel.h \ - include/stdlib.h include/varargs.h include/console.h + include/stdlib.h include/varargs.h include/config.h include/console.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/pmm.c +# src/serial.c +obj/serial.o: src/serial.c include/io.h include/serial.h include/stdlib.h \ + include/varargs.h include/config.h + $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/serial.c + # src/stdlib.c obj/stdlib.o: src/stdlib.c include/stdlib.h include/varargs.h \ - include/kernel.h + include/config.h include/kernel.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/stdlib.c # src/timer.c @@ -76,29 +83,30 @@ obj/vmm.o: src/vmm.c include/config.h include/vmm.h include/pmm.h \ # trainscript/tsvm.cpp obj/tsvm.o: trainscript/tsvm.cpp include/stdlib.h include/varargs.h \ - include/console.h trainscript/common.h trainscript/tsvm.hpp \ - include/ker/string.hpp include/ker/vector.hpp include/ker/new.hpp \ - include/ker/dictionary.hpp include/kernel.h include/ker/pair.hpp \ - trainscript/typeid.hpp trainscript/trainscript.tab.hpp \ - trainscript/trainscript.l.h include/string.h + include/config.h include/console.h trainscript/common.h \ + trainscript/tsvm.hpp include/ker/string.hpp include/ker/vector.hpp \ + include/ker/new.hpp include/ker/dictionary.hpp include/kernel.h \ + include/ker/pair.hpp trainscript/typeid.hpp \ + trainscript/trainscript.tab.hpp trainscript/trainscript.l.h \ + include/string.h $(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c trainscript/tsvm.cpp # src/cplusplus.cpp obj/cplusplus.o: src/cplusplus.cpp include/stdlib.h include/varargs.h \ - include/console.h include/ker/new.hpp + include/config.h include/console.h include/ker/new.hpp $(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/cplusplus.cpp # src/vm.cpp -obj/vm.o: src/vm.cpp include/stdlib.h include/varargs.h include/timer.h \ - include/dynamic.h src/../trainscript/tsvm.hpp include/console.h \ - include/ker/string.hpp include/ker/vector.hpp include/ker/new.hpp \ - include/ker/dictionary.hpp include/kernel.h include/ker/pair.hpp \ - src/../trainscript/typeid.hpp +obj/vm.o: src/vm.cpp include/stdlib.h include/varargs.h include/config.h \ + include/timer.h include/dynamic.h src/../trainscript/tsvm.hpp \ + include/console.h include/ker/string.hpp include/ker/vector.hpp \ + include/ker/new.hpp include/ker/dictionary.hpp include/kernel.h \ + include/ker/pair.hpp src/../trainscript/typeid.hpp $(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/vm.cpp # obj/trainscript.yy.cpp obj/trainscript.yy.o: obj/trainscript.yy.cpp include/string.h \ - include/stdlib.h include/varargs.h trainscript/common.h \ + include/stdlib.h include/varargs.h include/config.h trainscript/common.h \ trainscript/tsvm.hpp include/console.h include/ker/string.hpp \ include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \ include/kernel.h include/ker/pair.hpp trainscript/typeid.hpp \ @@ -107,11 +115,11 @@ obj/trainscript.yy.o: obj/trainscript.yy.cpp include/string.h \ # obj/trainscript.tab.cpp obj/trainscript.tab.o: obj/trainscript.tab.cpp include/stdlib.h \ - include/varargs.h trainscript/common.h trainscript/tsvm.hpp \ - include/console.h include/ker/string.hpp include/ker/vector.hpp \ - include/ker/new.hpp include/ker/dictionary.hpp include/kernel.h \ - include/ker/pair.hpp trainscript/typeid.hpp trainscript/trainscript.l.h \ - include/string.h + include/varargs.h include/config.h trainscript/common.h \ + trainscript/tsvm.hpp include/console.h include/ker/string.hpp \ + include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \ + include/kernel.h include/ker/pair.hpp trainscript/typeid.hpp \ + trainscript/trainscript.l.h include/string.h $(CXX) -iquotetrainscript $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.tab.cpp # asm/dynamic.S @@ -149,4 +157,4 @@ obj/main.o: scripts/main.ts .PHONY: run run: - qemu-system-i386 -kernel kernel kernel + qemu-system-i386 -serial stdio -kernel kernel diff --git a/README.md b/README.md index 7cff472..bf2d51c 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,5 @@ Also it leaks memory. A lot of memory. - Adding support for String Type - Implement custom malloc that does what it should +## Guidlines +- Calls to `die` or `die_extra` should follow the following scheme: `ContextName.ErrorName` diff --git a/include/config.h b/include/config.h index 9ce3eef..f428c54 100644 --- a/include/config.h +++ b/include/config.h @@ -3,3 +3,11 @@ /* #define USE_VIRTUAL_MEMORY_MANAGEMENT //*/ + +/* +#define USE_VERBOSE_MALLOC +//*/ + +/* +#define USE_VERBOSE_FREE +//*/ diff --git a/include/io.h b/include/io.h index ab9dec6..f30dccd 100644 --- a/include/io.h +++ b/include/io.h @@ -17,6 +17,13 @@ static inline void outb(uint16_t port, uint8_t data) __asm__ volatile ("outb %0, %1" : : "a" (data), "Nd" (port)); } +static inline uint8_t inb(uint16_t port) +{ + uint8_t data; + __asm__ volatile ("inb %1, %0" : "=a" (data) : "d" (port)); + return data; +} + #if defined(__cplusplus) } #endif diff --git a/include/ker/string.hpp b/include/ker/string.hpp index d097e09..a25c313 100644 --- a/include/ker/string.hpp +++ b/include/ker/string.hpp @@ -49,7 +49,7 @@ namespace ker ~String() { if(this->mText != nullptr) { - free(this->mText); + free(this->mText); } } @@ -136,7 +136,7 @@ namespace ker void copyFrom(const uint8_t *bytes, size_t length) { if(this->mText != nullptr) { - free(this->mText); + // free(this->mText); } this->mText = (uint8_t*)malloc(length + 1); memcpy(this->mText, bytes, length); diff --git a/include/ker/vector.hpp b/include/ker/vector.hpp index 0b40326..b4c67a1 100644 --- a/include/ker/vector.hpp +++ b/include/ker/vector.hpp @@ -66,7 +66,7 @@ namespace ker ~Vector() { if(this->mData != nullptr) { - free(this->mData); + free(this->mData); } } diff --git a/include/serial.h b/include/serial.h new file mode 100644 index 0000000..4afe564 --- /dev/null +++ b/include/serial.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +#define SERIAL_IER 1 +#define SERIAL_IIR 2 +#define SERIAL_FCR 2 +#define SERIAL_LCR 3 +#define SERIAL_MCR 4 +#define SERIAL_LSR 5 +#define SERIAL_MSR 6 + +#define SERIAL_COM1 0x3F8 +#define SERIAL_COM2 0x2F8 +#define SERIAL_COM3 0x3E8 +#define SERIAL_COM4 0x2E8 + +#define SERIAL_PARITY_NONE 0b000 +#define SERIAL_PARITY_ODD 0b100 +#define SERIAL_PARITY_EVEN 0b110 +#define SERIAL_PARITY_HIGH 0b101 +#define SERIAL_PARITY_LOW 0b111 + +#if defined(__cplusplus) +extern "C" { +#endif + +void serial_init(uint16_t port, uint32_t baud, uint8_t parity, uint8_t bits); + +int serial_can_read(uint16_t port); + +int serial_can_write(uint16_t port); + +void serial_write(uint16_t port, const uint8_t *data, size_t length); + +void serial_read(uint16_t port, uint8_t *data, size_t length); + +void serial_printf(uint16_t port, const char *format, ...); + +static inline void serial_write_str(uint16_t port, const char *text) +{ + while(*text) { + serial_write(port, (uint8_t*)text, 1); + text++; + } +} + +#if defined(__cplusplus) +} +#endif diff --git a/include/stdlib.h b/include/stdlib.h index f3327a9..a898a5e 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -3,6 +3,7 @@ #include #include #include "varargs.h" +#include "config.h" #if defined(__cplusplus) extern "C" { @@ -12,6 +13,14 @@ char *itoa(int value, char *str, int base); int atoi(const char *str); float atof(const char *str); +#if defined(USE_VERBOSE_MALLOC) +void *malloc_d(size_t,const char *,int); +#endif + +#if defined(USE_VERBOSE_FREE) +void free_d(void *,const char*, int); +#endif + /** * Allocates a block of memory * @param size Minimum size of the memory block @@ -132,6 +141,20 @@ static inline char * strdup(const char *str) return n; } +int sprintf(char *target, const char *format, ...); + +int vsprintf(char *target, const char *format, va_list vl); + #if defined(__cplusplus) } #endif + + + +#if defined(USE_VERBOSE_MALLOC) +#define malloc(size) malloc_d((size), __FILE__, __LINE__) +#endif + +#if defined(USE_VERBOSE_FREE) +#define free(ptr) free_d((ptr), __FILE__, __LINE__) +#endif diff --git a/scripts/main.ts b/scripts/main.ts index eca5b04..0fd6fa8 100644 --- a/scripts/main.ts +++ b/scripts/main.ts @@ -5,7 +5,7 @@ BEGIN 0 -> i; WHILE ((i + 1) -> i) <= 50 DO BEGIN - printInt(i); + print2Int(50 - i, i); sleep(2); END END diff --git a/src/console.c b/src/console.c index 1881544..5b3562c 100644 --- a/src/console.c +++ b/src/console.c @@ -188,50 +188,12 @@ void kputs(const char *str) void kprintf(const char *format, ...) { - char buffer[32]; + static char buffer[1024]; + memset(buffer, 0, sizeof(buffer)); + va_list vl; va_start(vl, format); - while(*format != 0) - { - char c = *(format++); - if(c == '%') - { - c = *(format++); - int i; - char *str; - switch(c) - { - case 'd': - case 'i': - i = va_arg(vl, int); - kputs(itoa(i, buffer, 10)); - break; - case 'b': - i = va_arg(vl, int); - kputs(itoa(i, buffer, 2)); - break; - case 'x': - case 'X': - i = va_arg(vl, int); - kputs(itoa(i, buffer, 16)); - break; - case 'c': - c = va_arg(vl, int); - kputc(c); - break; - case 's': - str = va_arg(vl, char*); - kputs(str); - break; - default: - kputc(c); - break; - } - } - else - { - kputc(c); - } - } + vsprintf(buffer, format, vl); va_end(vl); + kputs(buffer); } diff --git a/src/init.c b/src/init.c index fa112dc..45f33c4 100644 --- a/src/init.c +++ b/src/init.c @@ -6,6 +6,7 @@ #include #include #include +#include void die(const char *msg) { @@ -160,13 +161,16 @@ void init(const MultibootStructure *mbHeader) kclear(); kputs("Welcome to \x12\x05trainOS\x12\x07!\n"); + serial_init(SERIAL_COM1, 9600, SERIAL_PARITY_NONE, 8); + serial_write_str(SERIAL_COM1, "Debug Console Ready\n"); + //dumpMB(mbHeader); kputs("Initialize physical memory management: "); pmm_init(mbHeader); putsuccess(); - uint32_t freeMem = pmm_calc_free(); + uint32_t freeMem = pmm_calc_free(); kprintf("Free memory: %d B, %d kB, %d MB\n", freeMem, freeMem >> 10, freeMem >> 20); #if defined(USE_VIRTUAL_MEMORY_MANAGEMENT) diff --git a/src/malloc.c b/src/malloc.c index a07c466..0de1de8 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -1,37 +1,194 @@ +#include #include #include +#include +#include + +#undef malloc +#undef free + +typedef struct List +{ + size_t magic; + size_t length; + size_t used; + struct List *next; +} List; size_t mallocCount = 0, freeCount = 0; size_t allocatedMemory = 0; +static const size_t minimumAllocSize = 2 * sizeof(List); static char * const malloc_heap_start = (char *)0x400000; -static char * const malloc_heap_end = (char *)0x800000; +static char * const malloc_heap_end = (char *)0x10000000; -static char * current = nullptr; +List *listBegin = nullptr; + +static void print_list() +{ + List *list = listBegin; + serial_printf(SERIAL_COM1, "malloc list: \n"); + while(list != nullptr) + { + if(list->magic != 0xDEADBEEF) { + die("malloc::print_list.InvalidMagicNumber"); + } + serial_printf(SERIAL_COM1, "[%x -> %x] %d %d\n", list, list->next, list->used, list->length); + list = list->next; + } +} + +static void defragment() +{ + List *list = listBegin; + if(list == nullptr) { + return; + } + for(; list->next != nullptr; list = list->next) + { + if(list->used != 0) { + continue; + } + while(list->next->used == 0) { + List *n = list->next->next; + list->length += list->next->length + sizeof(List); + list->next = n; + } + } +} void *malloc(size_t len) { - allocatedMemory += len; + // Prevent fragmentation, sacrifice memory + if(len < minimumAllocSize) { + len = minimumAllocSize; + } + + if(listBegin == nullptr) { + listBegin = (List*)malloc_heap_start; + listBegin->length = (intptr_t)malloc_heap_end - (intptr_t)malloc_heap_start - sizeof(List); + listBegin->used = 0; + listBegin->next = nullptr; + listBegin->magic = 0xDEADBEEF; + + print_list(); + } + + List *cursor = listBegin; + + // Find the first non-used List entry + while((cursor != nullptr) && ((cursor->used != 0) || (cursor->length < (len + sizeof(List))))) { + cursor = cursor->next; + } + if(cursor == nullptr) { + print_list(); + die_extra("malloc.OutOfMemory", itoa(len, nullptr, 10)); + } + + if(cursor->length < (sizeof(List) + len)) { + die("malloc.FragmentationFailure"); + } + + if(cursor->length == len) + { + cursor->used = 1; + } + else + { + // Store total length + size_t newLength = cursor->length - sizeof(List) - len; + + // Allocate the memory + cursor->used = 1; + cursor->length = len; + + // Fragment list + List *newl = (List*)((char*)cursor + (sizeof(List) + cursor->length)); + newl->length = newLength; + newl->used = 0; + newl->next = cursor->next; + newl->magic = 0xDEADBEEF; + + cursor->next = newl; + } + + allocatedMemory += len; mallocCount++; - if(current == nullptr) { - current = malloc_heap_start; + return (void*)((char*)cursor + sizeof(List)); +} + +void* realloc (void* ptr, size_t size) +{ + void *n = malloc(size); + memcpy(n, ptr, size); + free(ptr); + return n; +} + +void free(void *ptr) +{ + if(ptr == nullptr) { + // Valid behaviour! + return; + } + if((uintptr_t)ptr < (uintptr_t)malloc_heap_start) { + die_extra("free.InvalidFree", itoa(ptr, nullptr, 16)); + } + freeCount++; + + List *entry = (List*)((char*)ptr - sizeof(List)); + if(entry->used == 0) { + die_extra("free.InvalidBlock", itoa(ptr, nullptr, 16)); + } + if(entry->magic != 0xDEADBEEF) { + die_extra("free.InvalidBlockMagic: ", itoa(entry->magic, nullptr, 16)); } - void *ptr = current; - current += len; - - if((uintptr_t)current >= (uintptr_t)malloc_heap_end) { - die("malloc.OutOfMemory"); + if(entry->length > 0x5000) { + die_extra("free.InvalidSizedBlock: ", itoa(entry->length, nullptr, 10)); } + allocatedMemory -= entry->length; + entry->used = 0; + + defragment(); +} + + + +void *malloc_d(size_t len, const char *file, int line) +{ + serial_write_str(SERIAL_COM1, "Allocate "); + serial_write_str(SERIAL_COM1, itoa(len, nullptr, 10)); + serial_write_str(SERIAL_COM1, " bytes at "); + serial_write_str(SERIAL_COM1, file); + serial_write_str(SERIAL_COM1, ":"); + serial_write_str(SERIAL_COM1, itoa(line, nullptr, 10)); + serial_write_str(SERIAL_COM1, ": "); + + void *ptr = malloc(len); + serial_write_str(SERIAL_COM1, itoa(ptr, nullptr, 16)); + serial_write_str(SERIAL_COM1, "\n"); + return ptr; } - - - -void free(void *__ptr) +void free_d(void *ptr, const char *file, int line) { - freeCount++; + if(ptr == nullptr) { + return; + } + List *entry = (List*)((char*)ptr - sizeof(List)); + + serial_write_str(SERIAL_COM1, "Free "); + serial_write_str(SERIAL_COM1, itoa(entry->length, nullptr, 10)); + serial_write_str(SERIAL_COM1, " bytes at "); + serial_write_str(SERIAL_COM1, itoa(ptr, nullptr, 16)); + serial_write_str(SERIAL_COM1, " in "); + serial_write_str(SERIAL_COM1, file); + serial_write_str(SERIAL_COM1, ":"); + serial_write_str(SERIAL_COM1, itoa(line, nullptr, 10)); + serial_write_str(SERIAL_COM1, ".\n"); + free(ptr); } diff --git a/src/serial.c b/src/serial.c new file mode 100644 index 0000000..f18f095 --- /dev/null +++ b/src/serial.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +// Funktion zum initialisieren eines COM-Ports +void serial_init(uint16_t base, uint32_t baud, uint8_t parity, uint8_t bits) +{ + // Teiler berechnen + union { + uint8_t b[2]; + uint16_t w; + } divisor; + divisor.w = 115200/baud; + + // Interrupt ausschalten + outb(base+SERIAL_IER,0x00); + + // DLAB-Bit setzen + outb(base+SERIAL_LCR,0x80); + + // Teiler (low) setzen + outb(base+0,divisor.b[0]); + + // Teiler (high) setzen + outb(base+1,divisor.b[1]); + + // Anzahl Bits, Parität, usw setzen (DLAB zurücksetzen) + outb(base+SERIAL_LCR,((parity&0x7)<<3)|((bits-5)&0x3)); + + // Initialisierung abschließen + outb(base+SERIAL_FCR,0xC7); + outb(base+SERIAL_MCR,0x0B); +} + +int serial_can_write(uint16_t base) +{ + return inb(base+SERIAL_LSR)&0x20; +} + +// Byte senden +void write_com(uint16_t base, uint8_t chr) { + while (serial_can_write(base)==0); + outb(base,chr); +} + +void serial_write(uint16_t port, const uint8_t *data, size_t length) +{ + while(length--) { + write_com(port, *data++); + } +} + +// Prüft, ob man bereits lesen kann +int serial_can_read(uint16_t base) +{ + return inb(base+SERIAL_LSR)&1; +} + +// Byte empfangen +static uint8_t read_serial(uint16_t base) +{ + while (!serial_can_read(base)); + return inb(base); +} + +void serial_read(uint16_t port, uint8_t *data, size_t length) +{ + while(length--) { + *data++ = read_serial(port); + } +} + +void serial_printf(uint16_t port, const char *format, ...) +{ + static char buffer[1024]; + memset(buffer, 0, sizeof(buffer)); + + va_list vl; + va_start(vl, format); + vsprintf(buffer, format, vl); + va_end(vl); + + serial_write_str(port, buffer); +} diff --git a/src/stdlib.c b/src/stdlib.c index f141048..143f230 100644 --- a/src/stdlib.c +++ b/src/stdlib.c @@ -1,14 +1,6 @@ #include #include -void* realloc (void* ptr, size_t size) -{ - void *n = malloc(size); - memcpy(n, ptr, size); - free(ptr); - return n; -} - void exit(int errorCode) { static char buffer[128]; @@ -38,6 +30,11 @@ char *itoa(int num, char *str, int base) int i = 0; int isNegative = 0; + if(str == nullptr) { + static char tmp[64]; + str = tmp; + } + /* Handle 0 explicitely, otherwise empty string is printed for 0 */ if (num == 0) { @@ -102,3 +99,91 @@ void *memmove( void *destination, const void *source, size_t num) // TODO: Implement memmove return nullptr; } + +int sprintf(char *target, const char *format, ...) +{ + va_list vl; + va_start(vl, format); + int len = vsprintf(target, format, vl); + va_end(vl); + + return len; +} + +int vsprintf(char *target, const char *format, va_list vl) +{ + int length = 0; + char buffer[32]; + while(*format != 0) + { + char c = *(format++); + if(c == '%') + { + c = *(format++); + int i; + char *tmp; + size_t len; + switch(c) + { + case 'd': + case 'i': + i = va_arg(vl, int); + tmp = itoa(i, buffer, 10); + len = strlen(tmp); + if(target != nullptr) { + strcat(target, tmp); + target += len; + } + length += len; + break; + case 'b': + i = va_arg(vl, int); + tmp = itoa(i, buffer, 2); + len = strlen(tmp); + if(target != nullptr) { + strcat(target, tmp); + target += len; + } + length += len; + break; + case 'x': + case 'X': + i = va_arg(vl, int); + tmp = itoa(i, buffer, 16); + len = strlen(tmp); + if(target != nullptr) { + strcat(target, tmp); + target += len; + } + length += len; + break; + case 's': + tmp = va_arg(vl, char*); + len = strlen(tmp); + if(target != nullptr) { + strcat(target, tmp); + target += len; + } + length += len; + break; + case 'c': + c = va_arg(vl, int); + default: + if(target != nullptr) { + *target++ = c; + } + length += 1; + break; + } + } + else + { + if(target != nullptr) *target++ = c; + length += 1; + } + } + if(target != nullptr) { + target[length] = 0; + } + return length; +} diff --git a/src/vm.cpp b/src/vm.cpp index d1a50a7..e33a6d6 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -93,24 +93,25 @@ Variable NativeMethod::invoke(Vector arguments) } uint8_t *stack = (uint8_t*)malloc(stackSize); + uint8_t *stackPtr = stack; for(int i = arguments.length() - 1; i >= 0; i--) { switch(arguments[i].type.id) { case TypeID::Bool: - *reinterpret_cast(stack) = arguments[i].boolean ? 1 : 0; - stack += sizeof(Int); + *reinterpret_cast(stackPtr) = arguments[i].boolean ? 1 : 0; + stackPtr += sizeof(Int); break; case TypeID::Int: - *reinterpret_cast(stack) = arguments[i].integer; - stack += sizeof(Int); + *reinterpret_cast(stackPtr) = arguments[i].integer; + stackPtr += sizeof(Int); break; case TypeID::Real: - *reinterpret_cast(stack) = arguments[i].real; - stack += sizeof(Real); + *reinterpret_cast(stackPtr) = arguments[i].real; + stackPtr += sizeof(Real); break; } } - dynamic_call(this->function, stack-stackSize, stackSize); + dynamic_call(this->function, stack, stackSize); free(stack); @@ -121,6 +122,10 @@ extern "C" void __cdecl printInt(int i) { kprintf("{%d}\n", i); } +extern "C" void __cdecl print2Int(int a, int b) { + kprintf("{%d;%d}\n", a, b); +} + struct NativeModuleDef { const char *name; @@ -133,6 +138,7 @@ NativeModuleDef methods[] = { { "timer_get", "", (void*)timer_get }, { "timer_set", "i", (void*)timer_set }, { "printInt", "i", (void*)printInt }, + { "print2Int", "ii", (void*)print2Int }, { nullptr, nullptr, 0 } }; diff --git a/trainOS.pro b/trainOS.pro index 031b6e3..c87c181 100644 --- a/trainOS.pro +++ b/trainOS.pro @@ -15,7 +15,8 @@ SOURCES += \ trainscript/main.cpp \ src/timer.c \ src/cplusplus.cpp \ - src/vm.cpp + src/vm.cpp \ + src/serial.c HEADERS += \ include/console.h \ @@ -40,7 +41,8 @@ HEADERS += \ include/string.h \ include/ker/new.hpp \ include/dynamic.h \ - include/config.h + include/config.h \ + include/serial.h DISTFILES += \ asm/intr_common_handler.S \ diff --git a/trainscript/tsvm.cpp b/trainscript/tsvm.cpp index 6fef3a8..a792eb6 100644 --- a/trainscript/tsvm.cpp +++ b/trainscript/tsvm.cpp @@ -1,7 +1,5 @@ -extern "C" { #include #include -} #include "common.h" @@ -41,21 +39,22 @@ namespace trainscript Module *VM::load(const void *buffer, size_t length) { - void *internalStorage = malloc(length); + char *internalStorage = (char*)malloc(length); memcpy(internalStorage, buffer, length); Module *module = new Module(); ParserData data; + memset(&data, 0, sizeof(data)); data.buffer = reinterpret_cast(internalStorage); data.index = 0; data.length = length; data.module = module; + yylex_init_extra(&data, &data.scanner); - bool valid = yyparse(&data) == 0; - yylex_destroy(data.scanner); + free(internalStorage); for(size_t i = 0; i < 256; i++) {