diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h new file mode 100644 index 0000000..a0764de --- /dev/null +++ b/src/userland/hlib/include/syscalls.h @@ -0,0 +1,19 @@ +#ifndef SYSCALLS_H +#define SYSCALLS_H + +#include +#include + +typedef enum { + SYS_RUN = 0, + SYS_REGISTER_FUNCTION = 1, + SYS_REQUEST = 2, + SYS_IO_IN = 3, + SYS_IO_OUT = 4, + SYS_LOAD_INITRD = 5, + SYS_GET_SERVICE = 6, + SYS_GET_PROVIDER = 7, + SYS_SUBSCRIBE_INTERRUPT = 8, +} SyscallIds; + +#endif diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h new file mode 100644 index 0000000..a0764de --- /dev/null +++ b/src/userland/hlib/include/syscalls.h @@ -0,0 +1,19 @@ +#ifndef SYSCALLS_H +#define SYSCALLS_H + +#include +#include + +typedef enum { + SYS_RUN = 0, + SYS_REGISTER_FUNCTION = 1, + SYS_REQUEST = 2, + SYS_IO_IN = 3, + SYS_IO_OUT = 4, + SYS_LOAD_INITRD = 5, + SYS_GET_SERVICE = 6, + SYS_GET_PROVIDER = 7, + SYS_SUBSCRIBE_INTERRUPT = 8, +} SyscallIds; + +#endif diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld new file mode 100644 index 0000000..3ff2142 --- /dev/null +++ b/src/userland/hlib/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0xFF000000; + + .hlib : { + *(.text) + *(.rodata) + *(.data) + *(.bss) + } +} diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h new file mode 100644 index 0000000..a0764de --- /dev/null +++ b/src/userland/hlib/include/syscalls.h @@ -0,0 +1,19 @@ +#ifndef SYSCALLS_H +#define SYSCALLS_H + +#include +#include + +typedef enum { + SYS_RUN = 0, + SYS_REGISTER_FUNCTION = 1, + SYS_REQUEST = 2, + SYS_IO_IN = 3, + SYS_IO_OUT = 4, + SYS_LOAD_INITRD = 5, + SYS_GET_SERVICE = 6, + SYS_GET_PROVIDER = 7, + SYS_SUBSCRIBE_INTERRUPT = 8, +} SyscallIds; + +#endif diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld new file mode 100644 index 0000000..3ff2142 --- /dev/null +++ b/src/userland/hlib/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0xFF000000; + + .hlib : { + *(.text) + *(.rodata) + *(.data) + *(.bss) + } +} diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c new file mode 100644 index 0000000..1404907 --- /dev/null +++ b/src/userland/hlib/main.c @@ -0,0 +1,76 @@ +#include "include/syscalls.h" +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, + uint32_t parameter2, uint32_t parameter3) { + uint32_t esp; + asm("push %%eax" ::"a"(&&end)); + asm("mov %%esp, %%eax" : "=a"(esp)); + asm("sysenter\n" + : + : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), + "S"(parameter3), "D"(esp)); +// eax is set by the kernel as the return value +end: + // the 0x1C comes from the number of parameters / local variables do handle + // this function with care or it will break everything + asm("add $0x1C, %%esp\n" + "pop %%ebp\n" + "ret" ::); + // don't go here! ret returns with the correct value + return 0; +} + +void request(uint32_t module, uint32_t function, void *data, uint32_t size) { + syscall(SYS_REQUEST, module, function, U32(data), size); +} + +void installServiceProvider(char *name, void(provider)(void *)) { + syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); +} + +uint32_t strlen(char *string) { + uint32_t size = 0; + while (*string) { + string++; + size++; + } + return size; +} + +uint32_t getModule(char *name) { + return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); +} + +uint32_t getProvider(uint32_t module, char *name) { + return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); +} + +void loadFromInitrd(char *name) { + syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); +} + +uint32_t logModule = 0, logProvider; + +void log(char *message) { + if (logModule == 0) { + logModule = getModule("log"); + logProvider = getProvider(logModule, "log"); + } + request(logModule, logProvider, message, strlen(message)); +} + +uint32_t ioIn(uint16_t port, uint8_t size) { + return syscall(SYS_IO_IN, size, port, 0, 0); +} + +void ioOut(uint16_t port, uint32_t value, uint8_t size) { + syscall(SYS_IO_OUT, size, port, value, 0); +} + +void subscribeInterrupt(uint32_t intNo, void *handler) { + syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0); +} diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h new file mode 100644 index 0000000..a0764de --- /dev/null +++ b/src/userland/hlib/include/syscalls.h @@ -0,0 +1,19 @@ +#ifndef SYSCALLS_H +#define SYSCALLS_H + +#include +#include + +typedef enum { + SYS_RUN = 0, + SYS_REGISTER_FUNCTION = 1, + SYS_REQUEST = 2, + SYS_IO_IN = 3, + SYS_IO_OUT = 4, + SYS_LOAD_INITRD = 5, + SYS_GET_SERVICE = 6, + SYS_GET_PROVIDER = 7, + SYS_SUBSCRIBE_INTERRUPT = 8, +} SyscallIds; + +#endif diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld new file mode 100644 index 0000000..3ff2142 --- /dev/null +++ b/src/userland/hlib/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0xFF000000; + + .hlib : { + *(.text) + *(.rodata) + *(.data) + *(.bss) + } +} diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c new file mode 100644 index 0000000..1404907 --- /dev/null +++ b/src/userland/hlib/main.c @@ -0,0 +1,76 @@ +#include "include/syscalls.h" +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, + uint32_t parameter2, uint32_t parameter3) { + uint32_t esp; + asm("push %%eax" ::"a"(&&end)); + asm("mov %%esp, %%eax" : "=a"(esp)); + asm("sysenter\n" + : + : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), + "S"(parameter3), "D"(esp)); +// eax is set by the kernel as the return value +end: + // the 0x1C comes from the number of parameters / local variables do handle + // this function with care or it will break everything + asm("add $0x1C, %%esp\n" + "pop %%ebp\n" + "ret" ::); + // don't go here! ret returns with the correct value + return 0; +} + +void request(uint32_t module, uint32_t function, void *data, uint32_t size) { + syscall(SYS_REQUEST, module, function, U32(data), size); +} + +void installServiceProvider(char *name, void(provider)(void *)) { + syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); +} + +uint32_t strlen(char *string) { + uint32_t size = 0; + while (*string) { + string++; + size++; + } + return size; +} + +uint32_t getModule(char *name) { + return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); +} + +uint32_t getProvider(uint32_t module, char *name) { + return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); +} + +void loadFromInitrd(char *name) { + syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); +} + +uint32_t logModule = 0, logProvider; + +void log(char *message) { + if (logModule == 0) { + logModule = getModule("log"); + logProvider = getProvider(logModule, "log"); + } + request(logModule, logProvider, message, strlen(message)); +} + +uint32_t ioIn(uint16_t port, uint8_t size) { + return syscall(SYS_IO_IN, size, port, 0, 0); +} + +void ioOut(uint16_t port, uint32_t value, uint8_t size) { + syscall(SYS_IO_OUT, size, port, value, 0); +} + +void subscribeInterrupt(uint32_t intNo, void *handler) { + syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0); +} diff --git a/src/userland/link.ld b/src/userland/link.ld new file mode 100644 index 0000000..d0fdcd5 --- /dev/null +++ b/src/userland/link.ld @@ -0,0 +1,28 @@ +OUTPUT_ARCH(i386) +ENTRY(main) + +INPUT( ../../../build/hlib.o) + +SECTIONS { + . = 0x80000000; + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.data) + } + + .bss : { + *(.bss) + } + + . = 0xFF000000; + .hlib (NOLOAD) : { + *(.hlib) + } +} diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h new file mode 100644 index 0000000..a0764de --- /dev/null +++ b/src/userland/hlib/include/syscalls.h @@ -0,0 +1,19 @@ +#ifndef SYSCALLS_H +#define SYSCALLS_H + +#include +#include + +typedef enum { + SYS_RUN = 0, + SYS_REGISTER_FUNCTION = 1, + SYS_REQUEST = 2, + SYS_IO_IN = 3, + SYS_IO_OUT = 4, + SYS_LOAD_INITRD = 5, + SYS_GET_SERVICE = 6, + SYS_GET_PROVIDER = 7, + SYS_SUBSCRIBE_INTERRUPT = 8, +} SyscallIds; + +#endif diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld new file mode 100644 index 0000000..3ff2142 --- /dev/null +++ b/src/userland/hlib/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0xFF000000; + + .hlib : { + *(.text) + *(.rodata) + *(.data) + *(.bss) + } +} diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c new file mode 100644 index 0000000..1404907 --- /dev/null +++ b/src/userland/hlib/main.c @@ -0,0 +1,76 @@ +#include "include/syscalls.h" +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, + uint32_t parameter2, uint32_t parameter3) { + uint32_t esp; + asm("push %%eax" ::"a"(&&end)); + asm("mov %%esp, %%eax" : "=a"(esp)); + asm("sysenter\n" + : + : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), + "S"(parameter3), "D"(esp)); +// eax is set by the kernel as the return value +end: + // the 0x1C comes from the number of parameters / local variables do handle + // this function with care or it will break everything + asm("add $0x1C, %%esp\n" + "pop %%ebp\n" + "ret" ::); + // don't go here! ret returns with the correct value + return 0; +} + +void request(uint32_t module, uint32_t function, void *data, uint32_t size) { + syscall(SYS_REQUEST, module, function, U32(data), size); +} + +void installServiceProvider(char *name, void(provider)(void *)) { + syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); +} + +uint32_t strlen(char *string) { + uint32_t size = 0; + while (*string) { + string++; + size++; + } + return size; +} + +uint32_t getModule(char *name) { + return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); +} + +uint32_t getProvider(uint32_t module, char *name) { + return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); +} + +void loadFromInitrd(char *name) { + syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); +} + +uint32_t logModule = 0, logProvider; + +void log(char *message) { + if (logModule == 0) { + logModule = getModule("log"); + logProvider = getProvider(logModule, "log"); + } + request(logModule, logProvider, message, strlen(message)); +} + +uint32_t ioIn(uint16_t port, uint8_t size) { + return syscall(SYS_IO_IN, size, port, 0, 0); +} + +void ioOut(uint16_t port, uint32_t value, uint8_t size) { + syscall(SYS_IO_OUT, size, port, value, 0); +} + +void subscribeInterrupt(uint32_t intNo, void *handler) { + syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0); +} diff --git a/src/userland/link.ld b/src/userland/link.ld new file mode 100644 index 0000000..d0fdcd5 --- /dev/null +++ b/src/userland/link.ld @@ -0,0 +1,28 @@ +OUTPUT_ARCH(i386) +ENTRY(main) + +INPUT( ../../../build/hlib.o) + +SECTIONS { + . = 0x80000000; + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.data) + } + + .bss : { + *(.bss) + } + + . = 0xFF000000; + .hlib (NOLOAD) : { + *(.hlib) + } +} diff --git a/src/userland/loader/Makefile b/src/userland/loader/Makefile index c0d9686..f55080e 100644 --- a/src/userland/loader/Makefile +++ b/src/userland/loader/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h new file mode 100644 index 0000000..a0764de --- /dev/null +++ b/src/userland/hlib/include/syscalls.h @@ -0,0 +1,19 @@ +#ifndef SYSCALLS_H +#define SYSCALLS_H + +#include +#include + +typedef enum { + SYS_RUN = 0, + SYS_REGISTER_FUNCTION = 1, + SYS_REQUEST = 2, + SYS_IO_IN = 3, + SYS_IO_OUT = 4, + SYS_LOAD_INITRD = 5, + SYS_GET_SERVICE = 6, + SYS_GET_PROVIDER = 7, + SYS_SUBSCRIBE_INTERRUPT = 8, +} SyscallIds; + +#endif diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld new file mode 100644 index 0000000..3ff2142 --- /dev/null +++ b/src/userland/hlib/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0xFF000000; + + .hlib : { + *(.text) + *(.rodata) + *(.data) + *(.bss) + } +} diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c new file mode 100644 index 0000000..1404907 --- /dev/null +++ b/src/userland/hlib/main.c @@ -0,0 +1,76 @@ +#include "include/syscalls.h" +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, + uint32_t parameter2, uint32_t parameter3) { + uint32_t esp; + asm("push %%eax" ::"a"(&&end)); + asm("mov %%esp, %%eax" : "=a"(esp)); + asm("sysenter\n" + : + : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), + "S"(parameter3), "D"(esp)); +// eax is set by the kernel as the return value +end: + // the 0x1C comes from the number of parameters / local variables do handle + // this function with care or it will break everything + asm("add $0x1C, %%esp\n" + "pop %%ebp\n" + "ret" ::); + // don't go here! ret returns with the correct value + return 0; +} + +void request(uint32_t module, uint32_t function, void *data, uint32_t size) { + syscall(SYS_REQUEST, module, function, U32(data), size); +} + +void installServiceProvider(char *name, void(provider)(void *)) { + syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); +} + +uint32_t strlen(char *string) { + uint32_t size = 0; + while (*string) { + string++; + size++; + } + return size; +} + +uint32_t getModule(char *name) { + return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); +} + +uint32_t getProvider(uint32_t module, char *name) { + return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); +} + +void loadFromInitrd(char *name) { + syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); +} + +uint32_t logModule = 0, logProvider; + +void log(char *message) { + if (logModule == 0) { + logModule = getModule("log"); + logProvider = getProvider(logModule, "log"); + } + request(logModule, logProvider, message, strlen(message)); +} + +uint32_t ioIn(uint16_t port, uint8_t size) { + return syscall(SYS_IO_IN, size, port, 0, 0); +} + +void ioOut(uint16_t port, uint32_t value, uint8_t size) { + syscall(SYS_IO_OUT, size, port, value, 0); +} + +void subscribeInterrupt(uint32_t intNo, void *handler) { + syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0); +} diff --git a/src/userland/link.ld b/src/userland/link.ld new file mode 100644 index 0000000..d0fdcd5 --- /dev/null +++ b/src/userland/link.ld @@ -0,0 +1,28 @@ +OUTPUT_ARCH(i386) +ENTRY(main) + +INPUT( ../../../build/hlib.o) + +SECTIONS { + . = 0x80000000; + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.data) + } + + .bss : { + *(.bss) + } + + . = 0xFF000000; + .hlib (NOLOAD) : { + *(.hlib) + } +} diff --git a/src/userland/loader/Makefile b/src/userland/loader/Makefile index c0d9686..f55080e 100644 --- a/src/userland/loader/Makefile +++ b/src/userland/loader/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/src/userland/loader/main.c b/src/userland/loader/main.c index d6cb880..422d034 100644 --- a/src/userland/loader/main.c +++ b/src/userland/loader/main.c @@ -1,63 +1,5 @@ +#include #include -#include - -#define PTR(x) ((void *)(uintptr_t)x) -#define U32(x) ((uint32_t)(uintptr_t)x) - -uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, - uint32_t parameter2, uint32_t parameter3) { - uint32_t esp; - asm("push %%eax" ::"a"(&&end)); - asm("mov %%esp, %%eax" : "=a"(esp)); - asm("sysenter\n" - : - : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), - "S"(parameter3), "D"(esp)); -// eax is set by the kernel as the return value -end: - // the 0x1C comes from the number of parameters / local variables do handle - // this function with care or it will break everything - asm("add $0x1C, %%esp\n" - "pop %%ebp\n" - "ret" ::); - // don't go here! ret returns with the correct value - return 0; -} - -void request(uint32_t module, uint32_t function, void *data, uint32_t size) { - syscall(SYS_REQUEST, module, function, U32(data), size); -} - -void installServiceProvider(char *name, void(provider)(void *)) { - syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); -} - -uint32_t strlen(char *string) { - uint32_t size = 0; - while (*string) { - string++; - size++; - } - return size; -} - -uint32_t getModule(char *name) { - return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); -} - -uint32_t getProvider(uint32_t module, char *name) { - return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); -} - -void loadFromInitrd(char *name) { - syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); -} - -void log(char *message) { - uint32_t module = getModule("log"); - uint32_t provider = getProvider(module, "log"); - request(module, provider, message, strlen(message)); -} int32_t main() { loadFromInitrd("log"); diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h new file mode 100644 index 0000000..a0764de --- /dev/null +++ b/src/userland/hlib/include/syscalls.h @@ -0,0 +1,19 @@ +#ifndef SYSCALLS_H +#define SYSCALLS_H + +#include +#include + +typedef enum { + SYS_RUN = 0, + SYS_REGISTER_FUNCTION = 1, + SYS_REQUEST = 2, + SYS_IO_IN = 3, + SYS_IO_OUT = 4, + SYS_LOAD_INITRD = 5, + SYS_GET_SERVICE = 6, + SYS_GET_PROVIDER = 7, + SYS_SUBSCRIBE_INTERRUPT = 8, +} SyscallIds; + +#endif diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld new file mode 100644 index 0000000..3ff2142 --- /dev/null +++ b/src/userland/hlib/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0xFF000000; + + .hlib : { + *(.text) + *(.rodata) + *(.data) + *(.bss) + } +} diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c new file mode 100644 index 0000000..1404907 --- /dev/null +++ b/src/userland/hlib/main.c @@ -0,0 +1,76 @@ +#include "include/syscalls.h" +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, + uint32_t parameter2, uint32_t parameter3) { + uint32_t esp; + asm("push %%eax" ::"a"(&&end)); + asm("mov %%esp, %%eax" : "=a"(esp)); + asm("sysenter\n" + : + : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), + "S"(parameter3), "D"(esp)); +// eax is set by the kernel as the return value +end: + // the 0x1C comes from the number of parameters / local variables do handle + // this function with care or it will break everything + asm("add $0x1C, %%esp\n" + "pop %%ebp\n" + "ret" ::); + // don't go here! ret returns with the correct value + return 0; +} + +void request(uint32_t module, uint32_t function, void *data, uint32_t size) { + syscall(SYS_REQUEST, module, function, U32(data), size); +} + +void installServiceProvider(char *name, void(provider)(void *)) { + syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); +} + +uint32_t strlen(char *string) { + uint32_t size = 0; + while (*string) { + string++; + size++; + } + return size; +} + +uint32_t getModule(char *name) { + return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); +} + +uint32_t getProvider(uint32_t module, char *name) { + return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); +} + +void loadFromInitrd(char *name) { + syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); +} + +uint32_t logModule = 0, logProvider; + +void log(char *message) { + if (logModule == 0) { + logModule = getModule("log"); + logProvider = getProvider(logModule, "log"); + } + request(logModule, logProvider, message, strlen(message)); +} + +uint32_t ioIn(uint16_t port, uint8_t size) { + return syscall(SYS_IO_IN, size, port, 0, 0); +} + +void ioOut(uint16_t port, uint32_t value, uint8_t size) { + syscall(SYS_IO_OUT, size, port, value, 0); +} + +void subscribeInterrupt(uint32_t intNo, void *handler) { + syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0); +} diff --git a/src/userland/link.ld b/src/userland/link.ld new file mode 100644 index 0000000..d0fdcd5 --- /dev/null +++ b/src/userland/link.ld @@ -0,0 +1,28 @@ +OUTPUT_ARCH(i386) +ENTRY(main) + +INPUT( ../../../build/hlib.o) + +SECTIONS { + . = 0x80000000; + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.data) + } + + .bss : { + *(.bss) + } + + . = 0xFF000000; + .hlib (NOLOAD) : { + *(.hlib) + } +} diff --git a/src/userland/loader/Makefile b/src/userland/loader/Makefile index c0d9686..f55080e 100644 --- a/src/userland/loader/Makefile +++ b/src/userland/loader/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/src/userland/loader/main.c b/src/userland/loader/main.c index d6cb880..422d034 100644 --- a/src/userland/loader/main.c +++ b/src/userland/loader/main.c @@ -1,63 +1,5 @@ +#include #include -#include - -#define PTR(x) ((void *)(uintptr_t)x) -#define U32(x) ((uint32_t)(uintptr_t)x) - -uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, - uint32_t parameter2, uint32_t parameter3) { - uint32_t esp; - asm("push %%eax" ::"a"(&&end)); - asm("mov %%esp, %%eax" : "=a"(esp)); - asm("sysenter\n" - : - : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), - "S"(parameter3), "D"(esp)); -// eax is set by the kernel as the return value -end: - // the 0x1C comes from the number of parameters / local variables do handle - // this function with care or it will break everything - asm("add $0x1C, %%esp\n" - "pop %%ebp\n" - "ret" ::); - // don't go here! ret returns with the correct value - return 0; -} - -void request(uint32_t module, uint32_t function, void *data, uint32_t size) { - syscall(SYS_REQUEST, module, function, U32(data), size); -} - -void installServiceProvider(char *name, void(provider)(void *)) { - syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); -} - -uint32_t strlen(char *string) { - uint32_t size = 0; - while (*string) { - string++; - size++; - } - return size; -} - -uint32_t getModule(char *name) { - return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); -} - -uint32_t getProvider(uint32_t module, char *name) { - return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); -} - -void loadFromInitrd(char *name) { - syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); -} - -void log(char *message) { - uint32_t module = getModule("log"); - uint32_t provider = getProvider(module, "log"); - request(module, provider, message, strlen(message)); -} int32_t main() { loadFromInitrd("log"); diff --git a/src/userland/log/Makefile b/src/userland/log/Makefile index 5b974b2..749b70a 100644 --- a/src/userland/log/Makefile +++ b/src/userland/log/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h new file mode 100644 index 0000000..a0764de --- /dev/null +++ b/src/userland/hlib/include/syscalls.h @@ -0,0 +1,19 @@ +#ifndef SYSCALLS_H +#define SYSCALLS_H + +#include +#include + +typedef enum { + SYS_RUN = 0, + SYS_REGISTER_FUNCTION = 1, + SYS_REQUEST = 2, + SYS_IO_IN = 3, + SYS_IO_OUT = 4, + SYS_LOAD_INITRD = 5, + SYS_GET_SERVICE = 6, + SYS_GET_PROVIDER = 7, + SYS_SUBSCRIBE_INTERRUPT = 8, +} SyscallIds; + +#endif diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld new file mode 100644 index 0000000..3ff2142 --- /dev/null +++ b/src/userland/hlib/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0xFF000000; + + .hlib : { + *(.text) + *(.rodata) + *(.data) + *(.bss) + } +} diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c new file mode 100644 index 0000000..1404907 --- /dev/null +++ b/src/userland/hlib/main.c @@ -0,0 +1,76 @@ +#include "include/syscalls.h" +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, + uint32_t parameter2, uint32_t parameter3) { + uint32_t esp; + asm("push %%eax" ::"a"(&&end)); + asm("mov %%esp, %%eax" : "=a"(esp)); + asm("sysenter\n" + : + : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), + "S"(parameter3), "D"(esp)); +// eax is set by the kernel as the return value +end: + // the 0x1C comes from the number of parameters / local variables do handle + // this function with care or it will break everything + asm("add $0x1C, %%esp\n" + "pop %%ebp\n" + "ret" ::); + // don't go here! ret returns with the correct value + return 0; +} + +void request(uint32_t module, uint32_t function, void *data, uint32_t size) { + syscall(SYS_REQUEST, module, function, U32(data), size); +} + +void installServiceProvider(char *name, void(provider)(void *)) { + syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); +} + +uint32_t strlen(char *string) { + uint32_t size = 0; + while (*string) { + string++; + size++; + } + return size; +} + +uint32_t getModule(char *name) { + return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); +} + +uint32_t getProvider(uint32_t module, char *name) { + return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); +} + +void loadFromInitrd(char *name) { + syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); +} + +uint32_t logModule = 0, logProvider; + +void log(char *message) { + if (logModule == 0) { + logModule = getModule("log"); + logProvider = getProvider(logModule, "log"); + } + request(logModule, logProvider, message, strlen(message)); +} + +uint32_t ioIn(uint16_t port, uint8_t size) { + return syscall(SYS_IO_IN, size, port, 0, 0); +} + +void ioOut(uint16_t port, uint32_t value, uint8_t size) { + syscall(SYS_IO_OUT, size, port, value, 0); +} + +void subscribeInterrupt(uint32_t intNo, void *handler) { + syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0); +} diff --git a/src/userland/link.ld b/src/userland/link.ld new file mode 100644 index 0000000..d0fdcd5 --- /dev/null +++ b/src/userland/link.ld @@ -0,0 +1,28 @@ +OUTPUT_ARCH(i386) +ENTRY(main) + +INPUT( ../../../build/hlib.o) + +SECTIONS { + . = 0x80000000; + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.data) + } + + .bss : { + *(.bss) + } + + . = 0xFF000000; + .hlib (NOLOAD) : { + *(.hlib) + } +} diff --git a/src/userland/loader/Makefile b/src/userland/loader/Makefile index c0d9686..f55080e 100644 --- a/src/userland/loader/Makefile +++ b/src/userland/loader/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/src/userland/loader/main.c b/src/userland/loader/main.c index d6cb880..422d034 100644 --- a/src/userland/loader/main.c +++ b/src/userland/loader/main.c @@ -1,63 +1,5 @@ +#include #include -#include - -#define PTR(x) ((void *)(uintptr_t)x) -#define U32(x) ((uint32_t)(uintptr_t)x) - -uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, - uint32_t parameter2, uint32_t parameter3) { - uint32_t esp; - asm("push %%eax" ::"a"(&&end)); - asm("mov %%esp, %%eax" : "=a"(esp)); - asm("sysenter\n" - : - : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), - "S"(parameter3), "D"(esp)); -// eax is set by the kernel as the return value -end: - // the 0x1C comes from the number of parameters / local variables do handle - // this function with care or it will break everything - asm("add $0x1C, %%esp\n" - "pop %%ebp\n" - "ret" ::); - // don't go here! ret returns with the correct value - return 0; -} - -void request(uint32_t module, uint32_t function, void *data, uint32_t size) { - syscall(SYS_REQUEST, module, function, U32(data), size); -} - -void installServiceProvider(char *name, void(provider)(void *)) { - syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); -} - -uint32_t strlen(char *string) { - uint32_t size = 0; - while (*string) { - string++; - size++; - } - return size; -} - -uint32_t getModule(char *name) { - return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); -} - -uint32_t getProvider(uint32_t module, char *name) { - return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); -} - -void loadFromInitrd(char *name) { - syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); -} - -void log(char *message) { - uint32_t module = getModule("log"); - uint32_t provider = getProvider(module, "log"); - request(module, provider, message, strlen(message)); -} int32_t main() { loadFromInitrd("log"); diff --git a/src/userland/log/Makefile b/src/userland/log/Makefile index 5b974b2..749b70a 100644 --- a/src/userland/log/Makefile +++ b/src/userland/log/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/src/userland/log/main.c b/src/userland/log/main.c index 054223a..c03e8fd 100644 --- a/src/userland/log/main.c +++ b/src/userland/log/main.c @@ -1,49 +1,5 @@ +#include #include -#include - -#define PTR(x) ((void *)(uintptr_t)x) -#define U32(x) ((uint32_t)(uintptr_t)x) - -uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, - uint32_t parameter2, uint32_t parameter3) { - uint32_t esp; - asm("push %%eax" ::"a"(&&end)); - asm("mov %%esp, %%eax" : "=a"(esp)); - asm("sysenter\n" - : - : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), - "S"(parameter3), "D"(esp)); -// eax is set by the kernel as the return value -end: - // the 0x1C comes from the number of parameters / local variables do handle - // this function with care or it will break everything - asm("add $0x1C, %%esp\n" - "pop %%ebp\n" - "ret" ::); - // don't go here! ret returns with the correct value - return 0; -} - -void installServiceProvider(char *name, void(provider)(void *, uint32_t)) { - syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); -} - -uint32_t strlen(char *string) { - uint32_t size = 0; - while (*string) { - string++; - size++; - } - return size; -} - -uint32_t ioIn(uint16_t port, uint8_t size) { - return syscall(SYS_IO_IN, size, port, 0, 0); -} - -void ioOut(uint16_t port, uint32_t value, uint8_t size) { - syscall(SYS_IO_OUT, size, port, value, 0); -} void writeParallel(uint8_t data) { uint8_t control; @@ -58,7 +14,7 @@ } } -void log(void *data, uint32_t dataLength) { +void handleLog(void *data, uint32_t dataLength) { char *string = data, dump; for (uint32_t i = 0; i < dataLength; i++) { writeParallel(string[i]); @@ -68,12 +24,8 @@ } int32_t main() { - installServiceProvider("log", log); - writeParallel('m'); - writeParallel('a'); - writeParallel('i'); - writeParallel('n'); - writeParallel('\r'); - writeParallel('\n'); + installServiceProvider("log", handleLog); + char *message = "logger initialized"; + handleLog(message, strlen(message)); return 0; } diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h new file mode 100644 index 0000000..a0764de --- /dev/null +++ b/src/userland/hlib/include/syscalls.h @@ -0,0 +1,19 @@ +#ifndef SYSCALLS_H +#define SYSCALLS_H + +#include +#include + +typedef enum { + SYS_RUN = 0, + SYS_REGISTER_FUNCTION = 1, + SYS_REQUEST = 2, + SYS_IO_IN = 3, + SYS_IO_OUT = 4, + SYS_LOAD_INITRD = 5, + SYS_GET_SERVICE = 6, + SYS_GET_PROVIDER = 7, + SYS_SUBSCRIBE_INTERRUPT = 8, +} SyscallIds; + +#endif diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld new file mode 100644 index 0000000..3ff2142 --- /dev/null +++ b/src/userland/hlib/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0xFF000000; + + .hlib : { + *(.text) + *(.rodata) + *(.data) + *(.bss) + } +} diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c new file mode 100644 index 0000000..1404907 --- /dev/null +++ b/src/userland/hlib/main.c @@ -0,0 +1,76 @@ +#include "include/syscalls.h" +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, + uint32_t parameter2, uint32_t parameter3) { + uint32_t esp; + asm("push %%eax" ::"a"(&&end)); + asm("mov %%esp, %%eax" : "=a"(esp)); + asm("sysenter\n" + : + : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), + "S"(parameter3), "D"(esp)); +// eax is set by the kernel as the return value +end: + // the 0x1C comes from the number of parameters / local variables do handle + // this function with care or it will break everything + asm("add $0x1C, %%esp\n" + "pop %%ebp\n" + "ret" ::); + // don't go here! ret returns with the correct value + return 0; +} + +void request(uint32_t module, uint32_t function, void *data, uint32_t size) { + syscall(SYS_REQUEST, module, function, U32(data), size); +} + +void installServiceProvider(char *name, void(provider)(void *)) { + syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); +} + +uint32_t strlen(char *string) { + uint32_t size = 0; + while (*string) { + string++; + size++; + } + return size; +} + +uint32_t getModule(char *name) { + return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); +} + +uint32_t getProvider(uint32_t module, char *name) { + return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); +} + +void loadFromInitrd(char *name) { + syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); +} + +uint32_t logModule = 0, logProvider; + +void log(char *message) { + if (logModule == 0) { + logModule = getModule("log"); + logProvider = getProvider(logModule, "log"); + } + request(logModule, logProvider, message, strlen(message)); +} + +uint32_t ioIn(uint16_t port, uint8_t size) { + return syscall(SYS_IO_IN, size, port, 0, 0); +} + +void ioOut(uint16_t port, uint32_t value, uint8_t size) { + syscall(SYS_IO_OUT, size, port, value, 0); +} + +void subscribeInterrupt(uint32_t intNo, void *handler) { + syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0); +} diff --git a/src/userland/link.ld b/src/userland/link.ld new file mode 100644 index 0000000..d0fdcd5 --- /dev/null +++ b/src/userland/link.ld @@ -0,0 +1,28 @@ +OUTPUT_ARCH(i386) +ENTRY(main) + +INPUT( ../../../build/hlib.o) + +SECTIONS { + . = 0x80000000; + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.data) + } + + .bss : { + *(.bss) + } + + . = 0xFF000000; + .hlib (NOLOAD) : { + *(.hlib) + } +} diff --git a/src/userland/loader/Makefile b/src/userland/loader/Makefile index c0d9686..f55080e 100644 --- a/src/userland/loader/Makefile +++ b/src/userland/loader/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/src/userland/loader/main.c b/src/userland/loader/main.c index d6cb880..422d034 100644 --- a/src/userland/loader/main.c +++ b/src/userland/loader/main.c @@ -1,63 +1,5 @@ +#include #include -#include - -#define PTR(x) ((void *)(uintptr_t)x) -#define U32(x) ((uint32_t)(uintptr_t)x) - -uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, - uint32_t parameter2, uint32_t parameter3) { - uint32_t esp; - asm("push %%eax" ::"a"(&&end)); - asm("mov %%esp, %%eax" : "=a"(esp)); - asm("sysenter\n" - : - : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), - "S"(parameter3), "D"(esp)); -// eax is set by the kernel as the return value -end: - // the 0x1C comes from the number of parameters / local variables do handle - // this function with care or it will break everything - asm("add $0x1C, %%esp\n" - "pop %%ebp\n" - "ret" ::); - // don't go here! ret returns with the correct value - return 0; -} - -void request(uint32_t module, uint32_t function, void *data, uint32_t size) { - syscall(SYS_REQUEST, module, function, U32(data), size); -} - -void installServiceProvider(char *name, void(provider)(void *)) { - syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); -} - -uint32_t strlen(char *string) { - uint32_t size = 0; - while (*string) { - string++; - size++; - } - return size; -} - -uint32_t getModule(char *name) { - return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); -} - -uint32_t getProvider(uint32_t module, char *name) { - return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); -} - -void loadFromInitrd(char *name) { - syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); -} - -void log(char *message) { - uint32_t module = getModule("log"); - uint32_t provider = getProvider(module, "log"); - request(module, provider, message, strlen(message)); -} int32_t main() { loadFromInitrd("log"); diff --git a/src/userland/log/Makefile b/src/userland/log/Makefile index 5b974b2..749b70a 100644 --- a/src/userland/log/Makefile +++ b/src/userland/log/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/src/userland/log/main.c b/src/userland/log/main.c index 054223a..c03e8fd 100644 --- a/src/userland/log/main.c +++ b/src/userland/log/main.c @@ -1,49 +1,5 @@ +#include #include -#include - -#define PTR(x) ((void *)(uintptr_t)x) -#define U32(x) ((uint32_t)(uintptr_t)x) - -uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, - uint32_t parameter2, uint32_t parameter3) { - uint32_t esp; - asm("push %%eax" ::"a"(&&end)); - asm("mov %%esp, %%eax" : "=a"(esp)); - asm("sysenter\n" - : - : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), - "S"(parameter3), "D"(esp)); -// eax is set by the kernel as the return value -end: - // the 0x1C comes from the number of parameters / local variables do handle - // this function with care or it will break everything - asm("add $0x1C, %%esp\n" - "pop %%ebp\n" - "ret" ::); - // don't go here! ret returns with the correct value - return 0; -} - -void installServiceProvider(char *name, void(provider)(void *, uint32_t)) { - syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); -} - -uint32_t strlen(char *string) { - uint32_t size = 0; - while (*string) { - string++; - size++; - } - return size; -} - -uint32_t ioIn(uint16_t port, uint8_t size) { - return syscall(SYS_IO_IN, size, port, 0, 0); -} - -void ioOut(uint16_t port, uint32_t value, uint8_t size) { - syscall(SYS_IO_OUT, size, port, value, 0); -} void writeParallel(uint8_t data) { uint8_t control; @@ -58,7 +14,7 @@ } } -void log(void *data, uint32_t dataLength) { +void handleLog(void *data, uint32_t dataLength) { char *string = data, dump; for (uint32_t i = 0; i < dataLength; i++) { writeParallel(string[i]); @@ -68,12 +24,8 @@ } int32_t main() { - installServiceProvider("log", log); - writeParallel('m'); - writeParallel('a'); - writeParallel('i'); - writeParallel('n'); - writeParallel('\r'); - writeParallel('\n'); + installServiceProvider("log", handleLog); + char *message = "logger initialized"; + handleLog(message, strlen(message)); return 0; } diff --git a/src/userland/pic/Makefile b/src/userland/pic/Makefile index 1769890..2f7a767 100644 --- a/src/userland/pic/Makefile +++ b/src/userland/pic/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/Makefile b/Makefile index 35e0643..7ee17e3 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ SOURCE_FILES := $(shell find src/kernel -name *.c -or -name *.asm -or -name *.s) OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) -USER_PROGRAMS := $(shell ls src/userland) +USER_PROGRAMS := $(shell tree -d -L 1 -i --noreport src/userland/ | tail -n+2) USER_PROGRAM_NAMES := $(USER_PROGRAMS:%=user/%) USER_PROGRAM_FILES := $(USER_PROGRAMS:%=initrd/%) diff --git a/src/include/hlib.h b/src/include/hlib.h new file mode 100644 index 0000000..c7c8b2d --- /dev/null +++ b/src/include/hlib.h @@ -0,0 +1,19 @@ +#ifndef HLIB_H +#define HLIB_H + +#include +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +extern void installServiceProvider(char *name, + void(provider)(void *, uint32_t)); +extern uint32_t strlen(char *string); +extern uint32_t ioIn(uint16_t port, uint8_t size); +extern void ioOut(uint16_t port, uint32_t value, uint8_t size); +extern void log(char *); +extern void subscribeInterrupt(uint32_t intNo, void *handler); +extern void loadFromInitrd(char *name); + +#endif diff --git a/src/include/syscalls.h b/src/include/syscalls.h deleted file mode 100644 index a0764de..0000000 --- a/src/include/syscalls.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef SYSCALLS_H -#define SYSCALLS_H - -#include -#include - -typedef enum { - SYS_RUN = 0, - SYS_REGISTER_FUNCTION = 1, - SYS_REQUEST = 2, - SYS_IO_IN = 3, - SYS_IO_OUT = 4, - SYS_LOAD_INITRD = 5, - SYS_GET_SERVICE = 6, - SYS_GET_PROVIDER = 7, - SYS_SUBSCRIBE_INTERRUPT = 8, -} SyscallIds; - -#endif diff --git a/src/kernel/include/service.h b/src/kernel/include/service.h index 6e973c9..0006b10 100644 --- a/src/kernel/include/service.h +++ b/src/kernel/include/service.h @@ -18,7 +18,7 @@ Service *service; } Provider; -extern void loadElf(void *fileData, char *serviceName); +extern Service *loadElf(void *fileData, char *serviceName); extern void resume(Syscall *syscall); extern void *runEnd; diff --git a/src/kernel/include/syscall.h b/src/kernel/include/syscall.h index e7ced85..ff27850 100644 --- a/src/kernel/include/syscall.h +++ b/src/kernel/include/syscall.h @@ -1,7 +1,8 @@ #ifndef SYSCALL_H #define SYSCALL_H -#include +#include +#include typedef struct Syscall { uint32_t function; diff --git a/src/kernel/interrupts/interruptDescriptors.asm b/src/kernel/interrupts/interruptDescriptors.asm index 0144759..094e43d 100644 --- a/src/kernel/interrupts/interruptDescriptors.asm +++ b/src/kernel/interrupts/interruptDescriptors.asm @@ -1,20 +1,74 @@ section .sharedFunctions extern onInterrupt +extern temporaryESP global interruptStack interruptStack: resb 1024 -handleInterrupt: +interruptReturn: + pop eax + pop ebx + pop ecx + pop edx + ret + +exceptionAbort: mov eax, cr3 + cmp eax, 0x500000 + je $ + mov eax, 0x500000 + mov cr3, eax + mov eax, [temporaryESP] + mov esp, eax + pop ebp + ret + +handleInterrupt: +.saveRegisters: + push eax + push ebx + push ecx + push edx + mov eax, cr3 + push eax +.checkException: + mov eax, [esp+20] + cmp eax, 31 + jng exceptionAbort +.normalInterrupt: + push eax +.checkUsermode: + mov eax, cr3 + cmp eax, 0x500000 + je .kernelPages +.saveRegistersToOldStack: + mov eax, [esp+44] ; eax = old esp + mov ebx, [esp+32] ; ebx = old eip + mov [eax], ebx ; virtual push + add eax, 4 +.pushRegisters: + mov ebx, [esp+4] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+8] ; ebx = old ecx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+12] ; ebx = old ebx + mov [eax], ebx ; virtual push ebx + add eax, 4 + mov ebx, [esp+16] ; ebx = old edx + mov [eax], ebx ; virtual push ebx + add eax, 4 +.kernelPages: push eax mov eax, 0x500000 mov cr3, eax +.callHandler: + push interruptReturn call onInterrupt - pop eax - mov cr3, eax - pop eax - pop eax +.iretNow: + add esp, 40 iret %macro interruptHandler 1 diff --git a/src/kernel/interrupts/interrupts.c b/src/kernel/interrupts/interrupts.c index 73aa208..368b43f 100644 --- a/src/kernel/interrupts/interrupts.c +++ b/src/kernel/interrupts/interrupts.c @@ -12,29 +12,31 @@ extern GDTEntry newGDT; extern TSS tss; +extern Syscall *currentSyscall; +extern ListElement *callsToProcess; ListElement *interruptSubscriptions[255]; -__attribute__((section(".sharedFunction"))) __attribute__((aligned(0x10))) +__attribute__((section(".sharedFunctions"))) __attribute__((aligned(0x10))) IdtEntry idtEntries[256] = {}; -void onInterrupt(uint32_t cr3, uint32_t intNo, uint32_t errorCode) { - if (intNo > 31) { - // an external interrupt was triggered - foreach (interruptSubscriptions[intNo], Provider *, provider, - { scheduleProvider(provider, PTR(intNo), 0, NULL); }) - ; - } else if (intNo <= 31 && cr3 != 0x500000) { - // a task encountered an exception, end it - // todo: free syscall structure and handle the respondingTo one - // appropriately - asm(".intel_syntax noprefix\n" - "mov eax, [temporaryESP]\n" - "mov esp, eax\n" - "pop ebp\n" - "ret\n" - ".att_syntax"); +void onInterrupt(void *eip, void *esp, uint32_t intNo, void *cr3) { + // an external interrupt was triggered + foreach (interruptSubscriptions[intNo], Provider *, provider, + { scheduleProvider(provider, PTR(intNo), 0, NULL); }) + ; + if (cr3 == PTR(0x500000)) { + return; } + Syscall *call = malloc(sizeof(Syscall)); + call->function = 0; + call->service = currentSyscall->service; + call->esp = esp; + call->respondingTo = currentSyscall->respondingTo; + Service *currentService = currentSyscall->service; + call->cr3 = cr3; + listAdd(&callsToProcess, call); + asm("jmp handleSyscallEnd"); } extern void *interruptStack; @@ -42,6 +44,7 @@ void setupPic(); void registerInterrupts() { + setupPic(); GDTEntry *currentGdt = &newGDT; currentGdt[5].limit = sizeof(TSS); currentGdt[5].baseLow = U32(&tss); @@ -64,7 +67,6 @@ .limit = sizeof(idtEntries) - 1, }; asm("lidt %0" ::"m"(pointer)); - setupPic(); asm("sti"); } @@ -72,8 +74,8 @@ asm("outb %0, %1" : : "a"((uint8_t)value), "Nd"(port)); void setupPic() { - // sadly I have to do this here, because the PIC will trigger before the PIC - // driver has a chance to set it up + // sadly I have to do this here, because the PIC will trigger before the + // PIC driver has a chance to set it up outb(0x20, 0x11); outb(0xA0, 0x11); outb(0xA1, 32); @@ -82,4 +84,6 @@ outb(0x21, 0x02); outb(0x21, 0x1); outb(0xA1, 0x1); + outb(0x21, 0xFF); + outb(0xA1, 0xFF); } diff --git a/src/kernel/main.c b/src/kernel/main.c index 7a9b9c3..52a29f6 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -4,7 +4,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -12,29 +11,32 @@ void *initrd; uint32_t initrdSize; +Service *hlib; -void loadInitrdProgram(char *name, Syscall *respondingTo) { +Service *readInitrdProgram(char *name) { char *fileName = combineStrings("initrd/", name); void *elfData = findTarFile(initrd, initrdSize, fileName); free(fileName); - loadElf(elfData, name); - - Service *service = findService(name); - Provider *provider = findProvider(service, "main"); - scheduleProvider(provider, 0, 0, 0); + return loadElf(elfData, name); } -void loadAndScheduleLoader(void *multibootInfo) { +Service *loadProgram(char *name, Syscall *respondingTo) { + Service *service = readInitrdProgram(name); + Provider *provider = findProvider(service, "main"); + scheduleProvider(provider, 0, 0, respondingTo); + return service; +} + +void loadAndScheduleSystemServices(void *multibootInfo) { void *address = kernelMapPhysicalCount(multibootInfo, 4); initrd = findInitrd(address, &initrdSize); - loadInitrdProgram("loader", NULL); + hlib = readInitrdProgram("hlib"); + loadProgram("loader", NULL); } void kernelMain(void *multibootInfo) { setupMemory(); - // loading the loader also reserves the needed space for the - // multiboot-loaded stuff - loadAndScheduleLoader(multibootInfo); + loadAndScheduleSystemServices(multibootInfo); setupSyscalls(); registerInterrupts(); while (1) { diff --git a/src/kernel/service/service.asm b/src/kernel/service/service.asm index 1d8ad27..8ec8d44 100644 --- a/src/kernel/service/service.asm +++ b/src/kernel/service/service.asm @@ -19,6 +19,7 @@ mov ebx, [ebx + 20] mov cr3, eax mov eax, ebx + sti sysexit runEnd: mov eax, 0 diff --git a/src/kernel/service/services.c b/src/kernel/service/services.c index 130f3ce..7ac6bd6 100644 --- a/src/kernel/service/services.c +++ b/src/kernel/service/services.c @@ -2,7 +2,6 @@ #include "service.h" #include #include -#include #include extern void *functionsStart; @@ -11,6 +10,7 @@ ListElement *services, *callsToProcess; Syscall *currentSyscall; +extern Service *hlib; void resume(Syscall *syscall) { if (U32(syscall) < 0x1000) { @@ -20,7 +20,7 @@ runFunction(); } -void loadElf(void *elfStart, char *serviceName) { +Service *loadElf(void *elfStart, char *serviceName) { // use this function ONLY to load the initrd/loader program(maybe also the // ELF loader service)! ElfHeader *header = elfStart; @@ -31,12 +31,22 @@ service->pagingInfo.pageDirectory = malloc(0x1000); service->name = serviceName; void *current = &functionsStart; + if (hlib) { + service->pagingInfo.pageDirectory[0x3FC].pageTableID = + hlib->pagingInfo.pageDirectory[0x3FC].pageTableID; + service->pagingInfo.pageDirectory[0x3FC].belongsToUserProcess = 1; + service->pagingInfo.pageDirectory[0x3FC].present = 1; + service->pagingInfo.pageDirectory[0x3FC].writable = 1; + } for (uint32_t i = 0; i < 3; i++) { // todo: make this unwritable! sharePage(&(service->pagingInfo), current, current); current += 0x1000; } for (uint32_t i = 0; i < header->programHeaderEntryCount; i++) { + if (hlib && programHeader->virtualAddress >= 0xF0000000) { + goto end; + } for (uint32_t page = 0; page < programHeader->segmentMemorySize; page += 0x1000) { void *data = malloc(0x1000); @@ -46,6 +56,7 @@ sharePage(&service->pagingInfo, data, PTR(programHeader->virtualAddress + page)); } + end: programHeader = (void *)programHeader + header->programHeaderEntrySize; } Provider *main = malloc(sizeof(Provider)); @@ -54,6 +65,7 @@ main->address = PTR(header->entryPosition); listAdd(&services, service); listAdd(&service->providers, main); + return service; } Service *findService(char *name) { @@ -80,7 +92,7 @@ Syscall *respondingTo) { sharePage(&provider->service->pagingInfo, data, data); Syscall *runCall = malloc(sizeof(Syscall)); - runCall->function = SYS_RUN; + runCall->function = 0; runCall->esp = malloc(0x1000); runCall->respondingTo = respondingTo; runCall->cr3 = diff --git a/src/kernel/syscalls/syscall.c b/src/kernel/syscalls/syscall.c index b4353a8..d992a2f 100644 --- a/src/kernel/syscalls/syscall.c +++ b/src/kernel/syscalls/syscall.c @@ -2,7 +2,6 @@ #include #include #include -#include #include extern ListElement *callsToProcess; @@ -123,13 +122,13 @@ } } -extern void loadInitrdProgram(char *name, Syscall *respondingTo); +extern void loadProgram(char *name, Syscall *respondingTo); void handleLoadFromInitrdSyscall(Syscall *call) { Service *service = call->service; char *programName = kernelMapPhysical(getPhysicalAddress( service->pagingInfo.pageDirectory, PTR(call->parameters[0]))); - loadInitrdProgram(programName, (void *)call); + loadProgram(programName, (void *)call); call->avoidReschedule = true; } diff --git a/src/kernel/syscalls/syscallStub.asm b/src/kernel/syscalls/syscallStub.asm index f8213a8..ff5358d 100644 --- a/src/kernel/syscalls/syscallStub.asm +++ b/src/kernel/syscalls/syscallStub.asm @@ -2,6 +2,7 @@ bits 32 global syscallStub +global handleSyscallEnd extern handleSyscall extern temporaryESP @@ -19,6 +20,7 @@ push eax push edi call handleSyscall +handleSyscallEnd: mov eax, [temporaryESP] mov esp, eax pop ebp diff --git a/src/userland/hlib/Makefile b/src/userland/hlib/Makefile new file mode 100644 index 0000000..0bc3580 --- /dev/null +++ b/src/userland/hlib/Makefile @@ -0,0 +1,30 @@ +CC = i686-elf-gcc +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 +LD = i686-elf-ld +LD_FLAGS = -z max-page-size=0x1000 -e main +AS = nasm +ASFlAGS = -felf32 + +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find . -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +../../../initrd/hlib: $(OBJS) + @echo "linking the honey OS c libary" + @$(LD) $(LD_FLAGS) -o ../../../build/hlib.o $(OBJS) -T link.ld -r + @$(LD) $(LD_FLAGS) -o ../../../initrd/hlib $(OBJS) -T link.ld + +$(BUILD_FOLDER)/%.asm.o: %.asm + @echo "asembling $<" + @mkdir -p $(dir $@) + @$(AS) $(ASFlAGS) $< -o $@ + +$(BUILD_FOLDER)/%.c.o: %.c + @echo "compiling $<" + @mkdir -p $(dir $@) + @$(CC) $(CCFLAGS) -r $< -o $@ + +clean: + @echo "clearing build folder" + @rm -r $(BUILD_FOLDER) diff --git a/src/userland/hlib/include/syscalls.h b/src/userland/hlib/include/syscalls.h new file mode 100644 index 0000000..a0764de --- /dev/null +++ b/src/userland/hlib/include/syscalls.h @@ -0,0 +1,19 @@ +#ifndef SYSCALLS_H +#define SYSCALLS_H + +#include +#include + +typedef enum { + SYS_RUN = 0, + SYS_REGISTER_FUNCTION = 1, + SYS_REQUEST = 2, + SYS_IO_IN = 3, + SYS_IO_OUT = 4, + SYS_LOAD_INITRD = 5, + SYS_GET_SERVICE = 6, + SYS_GET_PROVIDER = 7, + SYS_SUBSCRIBE_INTERRUPT = 8, +} SyscallIds; + +#endif diff --git a/src/userland/hlib/link.ld b/src/userland/hlib/link.ld new file mode 100644 index 0000000..3ff2142 --- /dev/null +++ b/src/userland/hlib/link.ld @@ -0,0 +1,12 @@ +OUTPUT_ARCH(i386) + +SECTIONS { + . = 0xFF000000; + + .hlib : { + *(.text) + *(.rodata) + *(.data) + *(.bss) + } +} diff --git a/src/userland/hlib/main.c b/src/userland/hlib/main.c new file mode 100644 index 0000000..1404907 --- /dev/null +++ b/src/userland/hlib/main.c @@ -0,0 +1,76 @@ +#include "include/syscalls.h" +#include + +#define PTR(x) ((void *)(uintptr_t)x) +#define U32(x) ((uint32_t)(uintptr_t)x) + +uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, + uint32_t parameter2, uint32_t parameter3) { + uint32_t esp; + asm("push %%eax" ::"a"(&&end)); + asm("mov %%esp, %%eax" : "=a"(esp)); + asm("sysenter\n" + : + : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), + "S"(parameter3), "D"(esp)); +// eax is set by the kernel as the return value +end: + // the 0x1C comes from the number of parameters / local variables do handle + // this function with care or it will break everything + asm("add $0x1C, %%esp\n" + "pop %%ebp\n" + "ret" ::); + // don't go here! ret returns with the correct value + return 0; +} + +void request(uint32_t module, uint32_t function, void *data, uint32_t size) { + syscall(SYS_REQUEST, module, function, U32(data), size); +} + +void installServiceProvider(char *name, void(provider)(void *)) { + syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); +} + +uint32_t strlen(char *string) { + uint32_t size = 0; + while (*string) { + string++; + size++; + } + return size; +} + +uint32_t getModule(char *name) { + return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); +} + +uint32_t getProvider(uint32_t module, char *name) { + return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); +} + +void loadFromInitrd(char *name) { + syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); +} + +uint32_t logModule = 0, logProvider; + +void log(char *message) { + if (logModule == 0) { + logModule = getModule("log"); + logProvider = getProvider(logModule, "log"); + } + request(logModule, logProvider, message, strlen(message)); +} + +uint32_t ioIn(uint16_t port, uint8_t size) { + return syscall(SYS_IO_IN, size, port, 0, 0); +} + +void ioOut(uint16_t port, uint32_t value, uint8_t size) { + syscall(SYS_IO_OUT, size, port, value, 0); +} + +void subscribeInterrupt(uint32_t intNo, void *handler) { + syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0); +} diff --git a/src/userland/link.ld b/src/userland/link.ld new file mode 100644 index 0000000..d0fdcd5 --- /dev/null +++ b/src/userland/link.ld @@ -0,0 +1,28 @@ +OUTPUT_ARCH(i386) +ENTRY(main) + +INPUT( ../../../build/hlib.o) + +SECTIONS { + . = 0x80000000; + .text : { + *(.text) + } + + .rodata : { + *(.rodata) + } + + .data : { + *(.data) + } + + .bss : { + *(.bss) + } + + . = 0xFF000000; + .hlib (NOLOAD) : { + *(.hlib) + } +} diff --git a/src/userland/loader/Makefile b/src/userland/loader/Makefile index c0d9686..f55080e 100644 --- a/src/userland/loader/Makefile +++ b/src/userland/loader/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/src/userland/loader/main.c b/src/userland/loader/main.c index d6cb880..422d034 100644 --- a/src/userland/loader/main.c +++ b/src/userland/loader/main.c @@ -1,63 +1,5 @@ +#include #include -#include - -#define PTR(x) ((void *)(uintptr_t)x) -#define U32(x) ((uint32_t)(uintptr_t)x) - -uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, - uint32_t parameter2, uint32_t parameter3) { - uint32_t esp; - asm("push %%eax" ::"a"(&&end)); - asm("mov %%esp, %%eax" : "=a"(esp)); - asm("sysenter\n" - : - : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), - "S"(parameter3), "D"(esp)); -// eax is set by the kernel as the return value -end: - // the 0x1C comes from the number of parameters / local variables do handle - // this function with care or it will break everything - asm("add $0x1C, %%esp\n" - "pop %%ebp\n" - "ret" ::); - // don't go here! ret returns with the correct value - return 0; -} - -void request(uint32_t module, uint32_t function, void *data, uint32_t size) { - syscall(SYS_REQUEST, module, function, U32(data), size); -} - -void installServiceProvider(char *name, void(provider)(void *)) { - syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); -} - -uint32_t strlen(char *string) { - uint32_t size = 0; - while (*string) { - string++; - size++; - } - return size; -} - -uint32_t getModule(char *name) { - return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); -} - -uint32_t getProvider(uint32_t module, char *name) { - return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); -} - -void loadFromInitrd(char *name) { - syscall(SYS_LOAD_INITRD, U32(name), strlen(name), 0, 0); -} - -void log(char *message) { - uint32_t module = getModule("log"); - uint32_t provider = getProvider(module, "log"); - request(module, provider, message, strlen(message)); -} int32_t main() { loadFromInitrd("log"); diff --git a/src/userland/log/Makefile b/src/userland/log/Makefile index 5b974b2..749b70a 100644 --- a/src/userland/log/Makefile +++ b/src/userland/log/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/src/userland/log/main.c b/src/userland/log/main.c index 054223a..c03e8fd 100644 --- a/src/userland/log/main.c +++ b/src/userland/log/main.c @@ -1,49 +1,5 @@ +#include #include -#include - -#define PTR(x) ((void *)(uintptr_t)x) -#define U32(x) ((uint32_t)(uintptr_t)x) - -uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, - uint32_t parameter2, uint32_t parameter3) { - uint32_t esp; - asm("push %%eax" ::"a"(&&end)); - asm("mov %%esp, %%eax" : "=a"(esp)); - asm("sysenter\n" - : - : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), - "S"(parameter3), "D"(esp)); -// eax is set by the kernel as the return value -end: - // the 0x1C comes from the number of parameters / local variables do handle - // this function with care or it will break everything - asm("add $0x1C, %%esp\n" - "pop %%ebp\n" - "ret" ::); - // don't go here! ret returns with the correct value - return 0; -} - -void installServiceProvider(char *name, void(provider)(void *, uint32_t)) { - syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); -} - -uint32_t strlen(char *string) { - uint32_t size = 0; - while (*string) { - string++; - size++; - } - return size; -} - -uint32_t ioIn(uint16_t port, uint8_t size) { - return syscall(SYS_IO_IN, size, port, 0, 0); -} - -void ioOut(uint16_t port, uint32_t value, uint8_t size) { - syscall(SYS_IO_OUT, size, port, value, 0); -} void writeParallel(uint8_t data) { uint8_t control; @@ -58,7 +14,7 @@ } } -void log(void *data, uint32_t dataLength) { +void handleLog(void *data, uint32_t dataLength) { char *string = data, dump; for (uint32_t i = 0; i < dataLength; i++) { writeParallel(string[i]); @@ -68,12 +24,8 @@ } int32_t main() { - installServiceProvider("log", log); - writeParallel('m'); - writeParallel('a'); - writeParallel('i'); - writeParallel('n'); - writeParallel('\r'); - writeParallel('\n'); + installServiceProvider("log", handleLog); + char *message = "logger initialized"; + handleLog(message, strlen(message)); return 0; } diff --git a/src/userland/pic/Makefile b/src/userland/pic/Makefile index 1769890..2f7a767 100644 --- a/src/userland/pic/Makefile +++ b/src/userland/pic/Makefile @@ -1,7 +1,7 @@ CC = i686-elf-gcc CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../../include -I include -Wno-discarded-qualifiers -fms-extensions -Wno-shift-count-overflow -O0 LD = i686-elf-ld -LD_FLAGS = -z max-page-size=0x1000 -e main +LD_FLAGS = -z max-page-size=0x1000 -T ../link.ld AS = nasm ASFlAGS = -felf32 diff --git a/src/userland/pic/main.c b/src/userland/pic/main.c index 5fd3227..cf62164 100644 --- a/src/userland/pic/main.c +++ b/src/userland/pic/main.c @@ -1,66 +1,6 @@ +#include +#include #include -#include - -#define PTR(x) ((void *)(uintptr_t)x) -#define U32(x) ((uint32_t)(uintptr_t)x) - -uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1, - uint32_t parameter2, uint32_t parameter3) { - uint32_t esp; - asm("push %%eax" ::"a"(&&end)); - asm("mov %%esp, %%eax" : "=a"(esp)); - asm("sysenter\n" - : - : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2), - "S"(parameter3), "D"(esp)); -end: - // the 0x1C comes from the number of parameters / local variables do handle - // this function with care or it will break everything - asm("add $0x1C, %%esp\n" - "pop %%ebp\n" - "ret" ::); - // don't go here! ret returns with the correct value - return 0; -} - -void installServiceProvider(char *name, void(provider)(void *, uint32_t)) { - syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0); -} - -uint32_t strlen(char *string) { - uint32_t size = 0; - while (*string) { - string++; - size++; - } - return size; -} - -uint32_t ioIn(uint16_t port, uint8_t size) { - return syscall(SYS_IO_IN, size, port, 0, 0); -} - -void ioOut(uint16_t port, uint32_t value, uint8_t size) { - syscall(SYS_IO_OUT, size, port, value, 0); -} - -uint32_t getModule(char *name) { - return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0); -} - -uint32_t getProvider(uint32_t module, char *name) { - return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0); -} - -void request(uint32_t module, uint32_t function, void *data, uint32_t size) { - syscall(SYS_REQUEST, module, function, U32(data), size); -} - -void log(char *message) { - uint32_t module = getModule("log"); - uint32_t provider = getProvider(module, "log"); - request(module, provider, message, strlen(message)); -} #define PIC1 0x20 #define PIC2 0xA0 @@ -113,8 +53,11 @@ } } -void subscribeInterrupt(uint32_t intNo, void *handler) { - syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0); +uint32_t x = 1; + +void loop() { + while (x > 0) + ; } int32_t main() { @@ -122,4 +65,8 @@ for (uint32_t i = 32; i < 48; i++) { subscribeInterrupt(i, irqMaster); } + ioOut(0x21, 0x1, 1); + ioOut(0xA1, 0x1, 1); + ioOut(0x70, ioIn(0x70, 1) | 0x80, 1); + ioIn(0x71, 1); }