Newer
Older
honey-os / src / kernel / main.c
#include <memory.h>
#include <multiboot.h>
#include <service.h>
#include <stdint.h>
#include <syscall.h>
#include <syscalls.h>
#include <util.h>

// todo: use data structures more suited to the job
ListElement *services, *callsToProcess;

Service *findService(char *name) {
    foreach (services, Service *, service, {
        if (stringEquals(service->name, name)) {
            return service;
        }
    })
        ;
    return NULL;
}

Service *findServiceByCR3(uint32_t cr3) {
    foreach (services, Service *, service, {
        if (getPhysicalAddressKernel(service->pagingInfo.pageDirectory) ==
            PTR(cr3)) {
            return service;
        }
    })
        ;
    return NULL;
}

Provider *findProvider(Service *service, char *name) {
    foreach (service->providers, Provider *, provider, {
        if (stringEquals(provider->name, name)) {
            return provider;
        }
    })
        ;
    return NULL;
}

void runRequest(Provider *provider, void *parameter) {
    run(provider->service, provider->address);
}

void handleInstallSyscall(Syscall *call, Service *service) {
    Provider *provider = malloc(sizeof(Provider));
    RegisterServiceProviderSyscall *registerCall = (void *)call;
    char *providerName = kernelMapPhysical(
        getPhysicalAddress(registerCall->pageDirectory, registerCall->name));
    provider->name = providerName;
    provider->address = registerCall->handler;
    provider->service = service;
    listAdd(&service->providers, provider);
    call->resume = true;
    listAdd(&callsToProcess, call);
}

extern void *runEnd;

void handleRequestSyscall(Syscall *call, Service *service) {
    RequestSyscall *request = (void *)call;
    char *serviceName = kernelMapPhysical(
        getPhysicalAddress(request->pageDirectory, request->service));
    Service *providerService = findService(serviceName);
    char *providerName = kernelMapPhysical(
        getPhysicalAddress(request->pageDirectory, request->request));
    Provider *callProvider = findProvider(providerService, providerName);
    Syscall *runCall = malloc(sizeof(Syscall));
    runCall->id = 0;
    runCall->resume = true;
    runCall->respondingTo = call;
    runCall->pageDirectory = providerService->pagingInfo.pageDirectory;
    runCall->cr3 = U32(getPhysicalAddressKernel(runCall->pageDirectory));
    runCall->returnEsp = malloc(0x1000);
    runCall->returnAddress = callProvider->address;
    runCall->resume = true;
    sharePage(&providerService->pagingInfo, runCall->returnEsp,
              runCall->returnEsp);
    runCall->returnEsp += 0xFFC;
    *(void **)runCall->returnEsp = runEnd;
    listAdd(&callsToProcess, runCall);
}

void kernelMain(void *multibootInfo) {
    setupMemory();
    void *address = kernelMapMultiplePhysicalPages(multibootInfo, 4);
    uint32_t tarSize = 0;
    void *initrd = findInitrd(address, &tarSize);
    setupSyscalls();
    void *loaderProgram = findTarFile(initrd, tarSize, "initrd/loader");
    loadElf(loaderProgram, "loader", &services);
    Service *loader = findService("loader");
    Provider *provider = findProvider(loader, "main");
    runRequest(provider, NULL);
    while (1) {
        Syscall *call = listPopFirst(&callsToProcess);
        if (!call) {
            asm("hlt");
            continue;
        }
        Service *service = findServiceByCR3(call->cr3);
        if (call->resume) {
            resume(call);
            continue;
        }
        switch (call->id) {
        case SYS_REGISTER_FUNCTION:
            handleInstallSyscall(call, service);
            break;
        case SYS_REQUEST:
            handleRequestSyscall(call, service);
            break;
        }
    }
}