mirror of
https://github.com/usatiuk/ficus.git
synced 2025-10-29 00:27:52 +01:00
readchar
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
5
src/kernel/cv.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by Stepan Usatiuk on 26.11.2023.
|
||||
//
|
||||
|
||||
#include "cv.hpp"
|
||||
59
src/kernel/cv.hpp
Normal file
59
src/kernel/cv.hpp
Normal 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
|
||||
65
src/kernel/templates/CircularBuffer.hpp
Normal file
65
src/kernel/templates/CircularBuffer.hpp
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ extern "C" {
|
||||
|
||||
#define SYSCALL_PUTCHAR_ID 1
|
||||
#define SYSCALL_SLEEP_ID 2
|
||||
#define SYSCALL_READCHAR_ID 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
uint64_t putchar(char c);
|
||||
uint64_t readchar();
|
||||
uint64_t sleep(uint64_t micros);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Reference in New Issue
Block a user