aboutsummaryrefslogtreecommitdiffstats
path: root/tasking.cpp
blob: 1b78011705bb65f48fdfccf6a61279b113f9c764 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include "tasking.hpp"

#include <array>

struct Task
{
    enum class State {
        Invalid,
        Staging,
        Staged,
        Running
    };

    using enum State;

    std::uint32_t esp;
    std::uint32_t ebp;
    State state = State::Invalid;
};

static std::array<Task, 4> tasks;
static int current = -1;

void schedule(const Registers&)
{
    if (current < 0)
        return;

    asm volatile(R"(
        mov %%esp, %0
        mov %%ebp, %1
    )" : "=m" (tasks[current].esp), "=m" (tasks[current].ebp));

    do {
        if (++current >= static_cast<int>(tasks.size()))
            current = 0;
    } while (tasks[current].state == Task::Invalid || tasks[current].state == Task::Staging);

    asm volatile(R"(
        mov %0, %%esp
        mov %1, %%ebp
    )" :: "m" (tasks[current].esp), "m" (tasks[current].ebp));

    if (tasks[current].state == Task::Staged) {
        tasks[current].state = Task::Running;
        asm volatile(R"(
            pop %eax
            popa
            add $0x4, %esp
            iret
        )");
    }
}

void tasking_initialize()
{
    tasks[0].state = Task::Running;
    current = 0;
    asm volatile("int $0x20");
}

bool tasking_spawn(void (*entry)(), unsigned ssize)
{
    unsigned i;
    for (i = 0; i < tasks.size(); ++i) {
        if (tasks[i].state == Task::Invalid)
            break;
    }

    if (i >= tasks.size())
        return false;

    tasks[i].state = Task::Staging;

    auto stack = reinterpret_cast<std::uint32_t>(new std::uint8_t[ssize]);
    const auto stackend = stack + ssize;
    const auto regbase = stackend - sizeof(Registers);
    auto r = reinterpret_cast<Registers *>(regbase);
    r->ebp = stackend;
    r->esp = stackend;
    r->eip = reinterpret_cast<std::uint32_t>(entry);
    r->cs = 0x8;
    asm volatile("pushfl; pop %%eax" : "=a"(r->eflags));

    tasks[i] = Task {
        .esp = regbase,
        .ebp = stackend,
        .state = Task::Staged
    };
    return true;
}