Fixes nasty memory leaks. Adds memory tracing. Adds serial console for advanced debugging. Implements malloc correctly.

This commit is contained in:
Felix Queissner 2015-08-17 15:38:19 +02:00
parent 5002d8728c
commit e69a342b29
18 changed files with 516 additions and 117 deletions

View file

@ -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

View file

@ -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

View file

@ -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`

View file

@ -3,3 +3,11 @@
/*
#define USE_VIRTUAL_MEMORY_MANAGEMENT
//*/
/*
#define USE_VERBOSE_MALLOC
//*/
/*
#define USE_VERBOSE_FREE
//*/

View file

@ -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

View file

@ -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);

51
include/serial.h Normal file
View file

@ -0,0 +1,51 @@
#pragma once
#include <stddef.h>
#include <inttypes.h>
#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

View file

@ -3,6 +3,7 @@
#include <stddef.h>
#include <inttypes.h>
#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

View file

@ -5,7 +5,7 @@ BEGIN
0 -> i;
WHILE ((i + 1) -> i) <= 50 DO
BEGIN
printInt(i);
print2Int(50 - i, i);
sleep(2);
END
END

View file

@ -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);
}

View file

@ -6,6 +6,7 @@
#include <vmm.h>
#include <timer.h>
#include <config.h>
#include <serial.h>
void die(const char *msg)
{
@ -160,6 +161,9 @@ 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: ");

View file

@ -1,37 +1,194 @@
#include <kernel.h>
#include <stdlib.h>
#include <stdint.h>
#include <console.h>
#include <serial.h>
#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)
{
// 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 *ptr = current;
current += len;
if((uintptr_t)current >= (uintptr_t)malloc_heap_end) {
die("malloc.OutOfMemory");
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));
}
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);
}

85
src/serial.c Normal file
View file

@ -0,0 +1,85 @@
#include <io.h>
#include <serial.h>
#include <stdlib.h>
#include <varargs.h>
// 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);
}

View file

@ -1,14 +1,6 @@
#include <stdlib.h>
#include <kernel.h>
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;
}

View file

@ -93,24 +93,25 @@ Variable NativeMethod::invoke(Vector<Variable> 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<Int*>(stack) = arguments[i].boolean ? 1 : 0;
stack += sizeof(Int);
*reinterpret_cast<Int*>(stackPtr) = arguments[i].boolean ? 1 : 0;
stackPtr += sizeof(Int);
break;
case TypeID::Int:
*reinterpret_cast<Int*>(stack) = arguments[i].integer;
stack += sizeof(Int);
*reinterpret_cast<Int*>(stackPtr) = arguments[i].integer;
stackPtr += sizeof(Int);
break;
case TypeID::Real:
*reinterpret_cast<Real*>(stack) = arguments[i].real;
stack += sizeof(Real);
*reinterpret_cast<Real*>(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 }
};

View file

@ -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 \

View file

@ -1,7 +1,5 @@
extern "C" {
#include <stdlib.h>
#include <console.h>
}
#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<char*>(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++) {