This commit is contained in:
2023-11-27 18:59:13 +01:00
parent 4749bb5c09
commit a20514ef9d
19 changed files with 275 additions and 28 deletions

View File

@@ -4,6 +4,10 @@
#include "SerialTty.hpp"
#include "LockGuard.hpp"
#include "idt.hpp"
#include "io.hpp"
#define PORT 0x3f8// COM1
void SerialTty::putchar(char c) {
LockGuard guard(mutex);
@@ -14,3 +18,57 @@ void SerialTty::putstr(const char *str) {
LockGuard guard(mutex);
writestr(str);
}
static int read() {
if (!(inb(PORT + 5) & 1)) return -1;
return inb(PORT);
}
void SerialTty::this_pooler() {
while (true) {
sleep_self(10000);
if (intflag != 0) {
if (mutex.try_lock()) {
intflag = 0;
int r = read();
while (r != -1) {
buf.push_back((char) r);
r = read();
}
cv.notify_one();
mutex.unlock();
}
}
}
}
SerialTty::SerialTty() : Tty() {
outb(PORT + 3, 0x00);// Disable DLAB
outb(PORT + 1, 0x01);// Enable data available interrupt
Task *task = new_ktask((void (*)(void))(&SerialTty::this_pooler), "serialpooler", false);
task->frame.rdi = reinterpret_cast<uint64_t>(this);
start_task(task);
attach_interrupt(4, &SerialTty::isr, this);
IRQ_clear_mask(4);
}
void SerialTty::isr(void *tty) {
((SerialTty *) tty)->this_isr();
}
void SerialTty::this_isr() {
intflag.fetch_add(1);
}
char SerialTty::readchar() {
mutex.lock();
if (buf.empty()) {
cv.wait(mutex);
}
assert(!buf.empty());
char ret = buf.pop_back();
mutex.unlock();
return ret;
}

View File

@@ -5,14 +5,25 @@
#ifndef OS2_SERIALTTY_HPP
#define OS2_SERIALTTY_HPP
#include "CircularBuffer.hpp"
#include "Tty.hpp"
#include "cv.hpp"
class SerialTty : public Tty {
Mutex mutex;
CV cv;
static void isr(void *tty);
void this_isr();
void this_pooler();
std::atomic<int> intflag = 0;
CircularBuffer<char, 512> buf;
public:
SerialTty();
void putchar(char c) override;
void putstr(const char *str) override;
char readchar() override;
};

View File

@@ -163,6 +163,9 @@ uint16_t pic_get_isr(void) {
return __pic_get_irq_reg(PIC_READ_ISR);
}
static int_handler_t handlers[256];
static void *handlers_args[256];
extern "C" void pic1_irq_real_0(struct task_frame *frame) {
timer_tick();
switch_task(frame);
@@ -179,6 +182,9 @@ extern "C" void pic1_irq_real_3() {
PIC_sendEOI(3);
}
extern "C" void pic1_irq_real_4() {
if (handlers[4] != nullptr) {
handlers[4](handlers_args[4]);
}
PIC_sendEOI(4);
}
extern "C" void pic1_irq_real_5() {
@@ -224,3 +230,8 @@ extern "C" void pic2_irq_real_7() {
PIC_sendEOI(15);
}
void attach_interrupt(unsigned num, int_handler_t handler, void *firstarg) {
handlers[num] = handler;
handlers_args[num] = firstarg;
}

View File

@@ -92,4 +92,8 @@ void idt_init(void);
extern void (*isr_stub_table[])();
using int_handler_t = void (*)(void *);
void attach_interrupt(unsigned num, int_handler_t handler, void *arg);
#endif

View File

@@ -224,7 +224,7 @@ void ktask_main() {
assert(saved_modules_size > 0);
utask->vma->mmap_phys((void *) 0x00020000, (void *) KERN_V2P(saved_modules_data[i]),
max_saved_module_file_size, PAGE_USER | PAGE_RW);
start_utask(utask);
start_task(utask);
}
remove_self();

View File

@@ -6,17 +6,17 @@ section .text
global _syscall_entrypoint:function (_syscall_entrypoint.end - _syscall_entrypoint)
_syscall_entrypoint:
; TODO: make it synced somehow
mov r11, 0x10016 ; TASK_POINTER->ret_sp_val
mov [r11], rsp
mov r11, 0x10008 ; TASK_POINTER->entry_ksp_val
mov rsp, [r11]
mov r15, rcx
mov [0x10016], rsp ; TASK_POINTER->ret_sp_val
mov [0x10024], r11 ; TASK_POINTER->ret_flags
mov rsp, [0x10008] ; TASK_POINTER->entry_ksp_val
mov r15, rcx ; This seems like a hack
sti
; Do very complicated stuff here
call syscall_impl
mov r11, 0x10016 ; TASK_POINTER->ret_sp_val
mov rsp, [r11]
cli
mov rcx, r15
mov r11, [0x10024] ; TASK_POINTER->ret_flags
o64 sysret
.end:

View File

@@ -40,7 +40,7 @@ void setup_syscalls() {
wrmsr(0xc0000081, newstar.bytes);
wrmsr(0xc0000082, reinterpret_cast<uint64_t>(&_syscall_entrypoint));
wrmsr(0xc0000084, 0);
wrmsr(0xc0000084, (1 << 9));// IA32_FMASK, mask interrupts
wrmsr(0xC0000080, rdmsr(0xC0000080) | 0b1);
}
@@ -55,12 +55,21 @@ uint64_t syscall_sleep(uint64_t micros) {
return 0;
}
uint64_t syscall_readchar() {
Tty *tty = GlobalTtyManager.get_tty(0);
return tty->readchar();
}
extern "C" uint64_t syscall_impl(uint64_t id_rdi, uint64_t a1_rsi, uint64_t a2_rdx, uint64_t a3_rcx) {
assert2(are_interrupts_enabled(), "why wouldn't they be?");
switch (id_rdi) {
case SYSCALL_PUTCHAR_ID:
return syscall_putchar(a1_rsi);
case SYSCALL_SLEEP_ID:
return syscall_sleep(a1_rsi);
case SYSCALL_READCHAR_ID:
assert(a1_rsi == NULL);
return syscall_readchar();
default:
return -1;
}

View File

@@ -90,7 +90,7 @@ static void task_freer() {
}
}
struct Task *new_ktask(void (*fn)(), const char *name) {
struct Task *new_ktask(void (*fn)(), const char *name, bool start) {
struct Task *newt = static_cast<Task *>(kmalloc(sizeof(struct Task)));
newt->kstack = static_cast<uint64_t *>(kmalloc(TASK_SS));
newt->name = static_cast<char *>(kmalloc(strlen(name) + 1));
@@ -110,18 +110,19 @@ struct Task *new_ktask(void (*fn)(), const char *name) {
newt->frame.flags = flags();
newt->frame.guard = IDT_GUARD;
newt->addressSpace = KERN_AddressSpace;
newt->state = TS_RUNNING;
newt->state = start ? TS_RUNNING : TS_BLOCKED;
newt->mode = TASKMODE_KERN;
newt->pid = max_pid.fetch_add(1);
newt->used_time = 0;
sanity_check_frame(&newt->frame);
if (start) {
auto new_node = NextTasks.create_node(newt);
auto new_node = NextTasks.create_node(newt);
{
LockGuard l(NextTasks_lock);
NextTasks.emplace_front(new_node);
{
LockGuard l(NextTasks_lock);
NextTasks.emplace_front(new_node);
}
}
{
@@ -152,7 +153,9 @@ struct Task *new_utask(void (*entrypoint)(), const char *name) {
newt->pid = max_pid.fetch_add(1);
newt->used_time = 0;
task_pointer *taskptr = static_cast<task_pointer *>(newt->vma->mmap_mem(reinterpret_cast<void *>(TASK_POINTER), sizeof(task_pointer), 0, PAGE_RW));
task_pointer *taskptr = static_cast<task_pointer *>(
newt->vma->mmap_mem(reinterpret_cast<void *>(TASK_POINTER),
sizeof(task_pointer), 0, PAGE_RW | PAGE_USER));// FIXME: this is probably unsafe
assert((uintptr_t) taskptr == TASK_POINTER);
task_pointer *taskptr_real = reinterpret_cast<task_pointer *>(HHDM_P2V(newt->addressSpace->virt2real(taskptr)));
@@ -182,7 +185,8 @@ struct Task *new_utask(void (*entrypoint)(), const char *name) {
return newt;
}
void start_utask(struct Task *task) {
void start_task(struct Task *task) {
assert(task->state != TS_RUNNING);
task->state = TS_RUNNING;
auto new_node = NextTasks.create_node(task);
{
@@ -340,18 +344,24 @@ void self_block(Spinlock &to_unlock) {
}
void unblock(Task *what) {
what->state = TS_RUNNING;
assert(what != nullptr);
assert(what->state != TS_RUNNING);
sanity_check_frame(&what->frame);
auto new_node = NextTasks.create_node(what);
{
LockGuard l(NextTasks_lock);
what->state = TS_RUNNING;
NextTasks.emplace_front(new_node);
}
};
void unblock(List<Task *>::Node *what) {
what->val->state = TS_RUNNING;
assert(what != nullptr);
assert(what->val->state != TS_RUNNING);
sanity_check_frame(&what->val->frame);
{
LockGuard l(NextTasks_lock);
what->val->state = TS_RUNNING;
NextTasks.emplace_front(what);
}
};

View File

@@ -46,15 +46,16 @@ struct task_pointer {
Task *taskptr;
uint64_t entry_ksp_val;
uint64_t ret_sp;
uint64_t ret_flags;
} __attribute__((packed));
struct Task *cur_task();
List<Task *>::Node *extract_running_task_node();
void init_tasks();
struct Task *new_ktask(void (*fn)(), const char *name);
struct Task *new_ktask(void (*fn)(), const char *name, bool start = true);
struct Task *new_utask(void (*entrypoint)(), const char *name);
void start_utask(struct Task *task);
void start_task(struct Task *task);
void remove_self();
void sleep_self(uint64_t diff);

View File

@@ -1,5 +1,5 @@
target_include_directories(kernel.elf PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_sources(kernel.elf PRIVATE mutex.cpp cppsupport.cpp Spinlock.cpp LockGuard.cpp rand.cpp VMA.cpp asserts.cpp TtyManager.cpp Tty.cpp)
target_sources(kernel.elf PRIVATE mutex.cpp cppsupport.cpp Spinlock.cpp LockGuard.cpp rand.cpp VMA.cpp asserts.cpp TtyManager.cpp Tty.cpp cv.cpp)
add_subdirectory(templates)

View File

@@ -5,10 +5,13 @@
#ifndef OS2_LOCKGUARD_H
#define OS2_LOCKGUARD_H
#include "asserts.hpp"
template<typename T>
class LockGuard {
public:
LockGuard(T &lock) : lock(&lock) {
assert2(are_interrupts_enabled(), "Trying to lock with disabled interrupts!");
this->lock->lock();
}
~LockGuard() {

View File

@@ -11,6 +11,7 @@ class Tty {
public:
virtual void putchar(char c) = 0;
virtual void putstr(const char *str) = 0;
virtual char readchar() = 0;
};

5
src/kernel/cv.cpp Normal file
View File

@@ -0,0 +1,5 @@
//
// Created by Stepan Usatiuk on 26.11.2023.
//
#include "cv.hpp"

59
src/kernel/cv.hpp Normal file
View File

@@ -0,0 +1,59 @@
//
// Created by Stepan Usatiuk on 26.11.2023.
//
#ifndef OS2_CV_HPP
#define OS2_CV_HPP
#include <atomic>
#include <cstddef>
#include <cstdint>
#include "List.hpp"
#include "LockGuard.hpp"
#include "Spinlock.hpp"
struct Task;
// This is probably broken in some way
class CV {
List<List<Task *>::Node *> waiters;
Spinlock waiters_lock;
public:
template<typename Lockable>
void wait(Lockable &l) {
l.unlock();
waiters_lock.lock();
waiters.emplace_front(extract_running_task_node());
self_block(waiters_lock);
l.lock();
}
void notify_one() {
List<Task *>::Node *t = nullptr;
{
LockGuard l(waiters_lock);
if (!waiters.empty()) {
t = waiters.back();
waiters.pop_back();
}
}
if (t) unblock(t);
}
void notify_all() {
assert(false);
List<List<Task *>::Node *> waiters_new;
{
LockGuard l(waiters_lock);
std::swap(waiters_new, waiters);
}
while (!waiters_new.empty()) {
auto t = waiters_new.back();
waiters_new.pop_back();
unblock(t);
}
}
};
#endif//OS2_CV_HPP

View File

@@ -0,0 +1,65 @@
//
// Created by Stepan Usatiuk on 26.11.2023.
//
#ifndef OS2_CIRCULARBUFFER_HPP
#define OS2_CIRCULARBUFFER_HPP
#include "asserts.hpp"
// FIXME
template<typename T, auto S>
class CircularBuffer {
T data[S];
int front, back;
public:
CircularBuffer() {
front = -1;
back = -1;
}
bool full() {
if (front == 0 && back == S - 1) {
return true;
}
if (front == back + 1) {
return true;
}
return false;
}
bool empty() {
if (front == -1)
return true;
else
return false;
}
void push_back(T what) {
if (full()) {
assert(false);
} else {
if (front == -1) front = 0;
back = (back + 1) % S;
data[back] = what;
}
}
T pop_back() {
if (empty()) {
assert(false);
} else {
T ret = data[front];
if (front == back) {
front = -1;
back = -1;
} else {
front = (front + 1) % S;
}
return ret;
}
}
};
#endif//OS2_CIRCULARBUFFER_HPP

View File

@@ -1,10 +1,14 @@
#include "syscalls_interface.h"
void _start() {
// putchar('h');
// putchar('i');
// putchar('\n');
while (true) {
putchar('h');
putchar('i');
putchar('\n');
sleep(100000);
// putchar('h');
// putchar('i');
// putchar('\n');
putchar(readchar());
// sleep(100000);
}
}

View File

@@ -14,6 +14,7 @@ extern "C" {
#define SYSCALL_PUTCHAR_ID 1
#define SYSCALL_SLEEP_ID 2
#define SYSCALL_READCHAR_ID 3
#ifdef __cplusplus
}

View File

@@ -7,7 +7,7 @@
uint64_t do_syscall(uint64_t num, uint64_t a1_rsi) {
uint64_t res;
asm volatile("syscall"
asm volatile("syscall; mov (0x10016), %%rsp"// TASK_POINTER->ret_sp_val
: "=r"(res)
: "D"(num), "S"(a1_rsi)
: "cc", "rdx", "rcx", "r8",
@@ -15,6 +15,10 @@ uint64_t do_syscall(uint64_t num, uint64_t a1_rsi) {
return res;
}
uint64_t readchar() {
return do_syscall(SYSCALL_READCHAR_ID, 0);
}
uint64_t putchar(char c) {
return do_syscall(SYSCALL_PUTCHAR_ID, c);
}

View File

@@ -13,6 +13,7 @@ extern "C" {
#endif
uint64_t putchar(char c);
uint64_t readchar();
uint64_t sleep(uint64_t micros);
#ifdef __cplusplus