feat: added support for waiting on an irq
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
#include <drivers/ports.h>
|
#include <drivers/ports.h>
|
||||||
#include <libc/kprintf.h>
|
#include <libc/kprintf.h>
|
||||||
#include <libk/libk.h>
|
#include <libk/libk.h>
|
||||||
|
#include <tasks/task.h>
|
||||||
|
|
||||||
#define PIC_END_OF_INTERRUPT 0x20
|
#define PIC_END_OF_INTERRUPT 0x20
|
||||||
|
|
||||||
@@ -142,6 +143,9 @@ void irq_handler(isr_registers_t r) {
|
|||||||
if (r.int_no >= 40) port_byte_out(PORT_PIC_SLAVE_COMMAND, PIC_END_OF_INTERRUPT); /* slave */
|
if (r.int_no >= 40) port_byte_out(PORT_PIC_SLAVE_COMMAND, PIC_END_OF_INTERRUPT); /* slave */
|
||||||
port_byte_out(PORT_PIC_MASTER_COMMAND, PIC_END_OF_INTERRUPT); /* master */
|
port_byte_out(PORT_PIC_MASTER_COMMAND, PIC_END_OF_INTERRUPT); /* master */
|
||||||
|
|
||||||
|
if (r.int_no >= IRQ0 && r.int_no < IRQ15) {
|
||||||
|
task_notify_irq(r.int_no - IRQ0);
|
||||||
|
}
|
||||||
/* Handle the interrupt in a more modular way */
|
/* Handle the interrupt in a more modular way */
|
||||||
if (interrupt_handlers[r.int_no] != NULL) {
|
if (interrupt_handlers[r.int_no] != NULL) {
|
||||||
isr_t handler = interrupt_handlers[r.int_no];
|
isr_t handler = interrupt_handlers[r.int_no];
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ void syscall_handle(isr_registers_t *registers) {
|
|||||||
case SYSCALL_YIELD_JOB:
|
case SYSCALL_YIELD_JOB:
|
||||||
task_switch_next();
|
task_switch_next();
|
||||||
break;
|
break;
|
||||||
|
case SYSCALL_YIELD_IRQ:
|
||||||
|
task_wait_irq(registers->ebx);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <libc/ringqueue.h>
|
#include <libc/ringqueue.h>
|
||||||
#include <libk/libk.h>
|
#include <libk/libk.h>
|
||||||
#include <mem/malloc.h>
|
#include <mem/malloc.h>
|
||||||
|
#include <libk/syscall.h>
|
||||||
|
|
||||||
|
|
||||||
const char scancode_map_lowercase[] = {
|
const char scancode_map_lowercase[] = {
|
||||||
@@ -63,7 +64,8 @@ char getc() {
|
|||||||
KeyEvent *get_next_event() {
|
KeyEvent *get_next_event() {
|
||||||
KeyEvent *target = malloc(sizeof(KeyEvent));
|
KeyEvent *target = malloc(sizeof(KeyEvent));
|
||||||
if (!ring_buffer_get(keyboard_event_buffer, target)) {
|
if (!ring_buffer_get(keyboard_event_buffer, target)) {
|
||||||
k_wait_for_interrupt();
|
syscall_yield_irq(1 << 1);
|
||||||
|
// k_wait_for_interrupt();
|
||||||
free(target);
|
free(target);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ void noreturn kmain(multiboot_info_t *multiboot_info) {
|
|||||||
|
|
||||||
printf("Booted successfully v%d.%d.%d\n", version_major, version_minor, version_patch);
|
printf("Booted successfully v%d.%d.%d\n", version_major, version_minor, version_patch);
|
||||||
|
|
||||||
|
task_init();
|
||||||
task_spawn(main_loop, NULL);
|
task_spawn(main_loop, NULL);
|
||||||
syscall_start_scheduler();
|
syscall_start_scheduler();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,21 @@ void syscall1(uint32_t arg1) {
|
|||||||
: "a"(arg1));
|
: "a"(arg1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void syscall_yield_job() {
|
void syscall2(uint32_t arg1, uint32_t arg2) {
|
||||||
syscall1(SYSCALL_YIELD_JOB);
|
__asm__("int $0x80"
|
||||||
|
:
|
||||||
|
: "a"(arg1), "b"(arg2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void noreturn syscall_start_scheduler() {
|
void noreturn syscall_start_scheduler() {
|
||||||
syscall1(SYSCALL_START_SCHEDULER);
|
syscall1(SYSCALL_START_SCHEDULER);
|
||||||
while (1) { __asm__("hlt"); };
|
while (1) { __asm__("hlt"); };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void syscall_yield_job() {
|
||||||
|
syscall1(SYSCALL_YIELD_JOB);
|
||||||
|
}
|
||||||
|
|
||||||
|
void syscall_yield_irq(uint16_t irq) {
|
||||||
|
syscall2(SYSCALL_YIELD_IRQ, irq );
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,14 +4,17 @@
|
|||||||
|
|
||||||
#ifndef NEW_KERNEL_SYSCALL_H
|
#ifndef NEW_KERNEL_SYSCALL_H
|
||||||
#define NEW_KERNEL_SYSCALL_H
|
#define NEW_KERNEL_SYSCALL_H
|
||||||
|
#include <types.h>
|
||||||
#include <attributes.h>
|
#include <attributes.h>
|
||||||
|
|
||||||
#define SYSCALL_START_SCHEDULER 0x01
|
#define SYSCALL_START_SCHEDULER 0x01
|
||||||
#define SYSCALL_YIELD_JOB 0x02
|
#define SYSCALL_YIELD_JOB 0x02
|
||||||
|
#define SYSCALL_YIELD_IRQ 0x03
|
||||||
void syscall_yield_job();
|
|
||||||
|
|
||||||
void noreturn syscall_start_scheduler();
|
void noreturn syscall_start_scheduler();
|
||||||
|
|
||||||
|
void syscall_yield_job();
|
||||||
|
|
||||||
|
void syscall_yield_irq(uint16_t irq);
|
||||||
|
|
||||||
#endif //NEW_KERNEL_SYSCALL_H
|
#endif //NEW_KERNEL_SYSCALL_H
|
||||||
|
|||||||
@@ -13,15 +13,24 @@
|
|||||||
|
|
||||||
#define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE))
|
#define stack_end(task) ((task)->stack + ((task)->stack_page_count * PAGE_SIZE))
|
||||||
|
|
||||||
|
#define TASK_STATE_UNKNOWN (0)
|
||||||
|
#define TASK_STATE_RUNNABLE (1 << 0)
|
||||||
|
#define TASK_STATE_RUNNING (1 << 1)
|
||||||
|
#define TASK_STATE_WAIT_IRQ (1 << 2)
|
||||||
|
|
||||||
|
#define TASK_STATE_ERROR (1 << 7)
|
||||||
|
|
||||||
|
|
||||||
typedef struct task {
|
typedef struct task {
|
||||||
bool present: 1;
|
bool present: 1;
|
||||||
uint8_t wait_irq: 4;
|
uint8_t state;
|
||||||
|
uint16_t wait_irq;
|
||||||
|
|
||||||
uint32_t tid;
|
uint32_t tid;
|
||||||
|
|
||||||
struct task *next;
|
struct task *next;
|
||||||
|
|
||||||
void* stack;
|
void *stack;
|
||||||
uint32_t stack_page_count;
|
uint32_t stack_page_count;
|
||||||
|
|
||||||
task_registers_t *task_registers;
|
task_registers_t *task_registers;
|
||||||
@@ -37,15 +46,20 @@ typedef struct {
|
|||||||
|
|
||||||
bool task_locked = false;
|
bool task_locked = false;
|
||||||
|
|
||||||
|
task_t *idle_task = NULL;
|
||||||
task_t *first_task = NULL;
|
task_t *first_task = NULL;
|
||||||
task_t *last_task = NULL;
|
task_t *last_task = NULL;
|
||||||
task_t *current_task = NULL;
|
task_t *current_task = NULL;
|
||||||
|
|
||||||
uint32_t last_tid = 0;
|
uint32_t last_tid = 0;
|
||||||
|
|
||||||
extern switch_task(task_registers_t**, task_registers_t*);
|
extern switch_task(task_registers_t
|
||||||
|
**, task_registers_t*);
|
||||||
|
|
||||||
extern cdecl noreturn void __task_entry_point();
|
extern cdecl noreturn void __task_entry_point();
|
||||||
|
|
||||||
extern noreturn void __task_entry_point_inner();
|
extern noreturn void __task_entry_point_inner();
|
||||||
|
|
||||||
// explicit cdecl calling convention
|
// explicit cdecl calling convention
|
||||||
void cdecl noreturn task_entry_point(task_entrypoint entrypoint, void *entry_data) {
|
void cdecl noreturn task_entry_point(task_entrypoint entrypoint, void *entry_data) {
|
||||||
entrypoint(entry_data);
|
entrypoint(entry_data);
|
||||||
@@ -61,6 +75,28 @@ void task_lock_free() {
|
|||||||
task_locked = false;
|
task_locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void noreturn task_idle(void *data) {
|
||||||
|
while (true) __asm__("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_notify_irq(uint8_t irq_no) {
|
||||||
|
uint16_t irq__bit = 1 << irq_no;
|
||||||
|
task_t *t = first_task;
|
||||||
|
while (t != NULL) {
|
||||||
|
if (t->state == TASK_STATE_WAIT_IRQ && (t->wait_irq & irq__bit) != 0) {
|
||||||
|
t->wait_irq = 0;
|
||||||
|
t->state = TASK_STATE_RUNNABLE;
|
||||||
|
}
|
||||||
|
t = t->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_wait_irq(uint16_t irq_bits) {
|
||||||
|
current_task->wait_irq = irq_bits;
|
||||||
|
current_task->state = TASK_STATE_WAIT_IRQ;
|
||||||
|
task_switch_next();
|
||||||
|
}
|
||||||
|
|
||||||
void task_switch_next_inner(task_t *next_task) {
|
void task_switch_next_inner(task_t *next_task) {
|
||||||
if (task_locked) {
|
if (task_locked) {
|
||||||
return; // don't switch while the task is locked
|
return; // don't switch while the task is locked
|
||||||
@@ -70,6 +106,10 @@ void task_switch_next_inner(task_t *next_task) {
|
|||||||
}
|
}
|
||||||
task_t *previous_task = current_task;
|
task_t *previous_task = current_task;
|
||||||
current_task = next_task;
|
current_task = next_task;
|
||||||
|
if (previous_task->state == TASK_STATE_RUNNING) {
|
||||||
|
previous_task->state = TASK_STATE_RUNNABLE;
|
||||||
|
}
|
||||||
|
current_task->state = TASK_STATE_RUNNING;
|
||||||
// switch task
|
// switch task
|
||||||
switch_task(previous_task == NULL ? NULL : &previous_task->task_registers, current_task->task_registers);
|
switch_task(previous_task == NULL ? NULL : &previous_task->task_registers, current_task->task_registers);
|
||||||
}
|
}
|
||||||
@@ -78,34 +118,53 @@ void task_start_first() {
|
|||||||
task_switch_next_inner(first_task);
|
task_switch_next_inner(first_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task_t *task_first_runnable() {
|
||||||
|
task_t *next_task = current_task;
|
||||||
|
bool looped = false;
|
||||||
|
if (next_task == idle_task || next_task->next == NULL) {
|
||||||
|
looped = true;
|
||||||
|
next_task = first_task;
|
||||||
|
} else {
|
||||||
|
next_task = current_task->next;
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
if (!looped && next_task == NULL) {
|
||||||
|
looped = true;
|
||||||
|
next_task = first_task;
|
||||||
|
}
|
||||||
|
if (next_task == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (next_task->state == TASK_STATE_RUNNABLE) {
|
||||||
|
return next_task;
|
||||||
|
}
|
||||||
|
next_task = next_task->next;
|
||||||
|
} while (next_task != current_task);
|
||||||
|
if (current_task->state == TASK_STATE_RUNNING)
|
||||||
|
return current_task;
|
||||||
|
return idle_task;
|
||||||
|
}
|
||||||
|
|
||||||
void task_switch_next() {
|
void task_switch_next() {
|
||||||
if (current_task == NULL) {
|
if (current_task == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
task_switch_next_inner(current_task->next == NULL ? first_task : current_task->next);
|
task_switch_next_inner(task_first_runnable());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) {
|
task_t *task_create(task_entrypoint entrypoint, void *entry_data) {
|
||||||
task_t *new_task = malloc(sizeof(task_t));
|
task_t *new_task = malloc(sizeof(task_t));
|
||||||
memset((uint8_t *) new_task, 0, sizeof(task_t));
|
memset((uint8_t *) new_task, 0, sizeof(task_t));
|
||||||
new_task->tid = last_tid++;
|
new_task->tid = last_tid++;
|
||||||
|
new_task->state = TASK_STATE_RUNNABLE;
|
||||||
|
|
||||||
new_task->stack = pmm_get_pages(16);
|
new_task->stack = pmm_get_pages(16);
|
||||||
new_task->stack_page_count = 16;
|
new_task->stack_page_count = 16;
|
||||||
// todo check for null
|
// todo check for null
|
||||||
|
|
||||||
|
|
||||||
if (first_task == NULL) {
|
|
||||||
// first task
|
|
||||||
first_task = new_task;
|
|
||||||
} else {
|
|
||||||
last_task->next = new_task;
|
|
||||||
}
|
|
||||||
last_task = new_task;
|
|
||||||
|
|
||||||
// prepare stack
|
// prepare stack
|
||||||
// cdecl format
|
// cdecl format
|
||||||
task_stack_start* stack = (task_stack_start *) (stack_end(new_task) - sizeof(task_stack_start));
|
task_stack_start *stack = (task_stack_start *) (stack_end(new_task) - sizeof(task_stack_start));
|
||||||
memset((uint8_t *) stack, 0, sizeof(task_stack_start));
|
memset((uint8_t *) stack, 0, sizeof(task_stack_start));
|
||||||
// setup isr return frame
|
// setup isr return frame
|
||||||
stack->isr_registers.cs = 0x08; // todo proper gdt setup
|
stack->isr_registers.cs = 0x08; // todo proper gdt setup
|
||||||
@@ -124,6 +183,23 @@ uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) {
|
|||||||
new_task->task_registers = &stack->task_registers;
|
new_task->task_registers = &stack->task_registers;
|
||||||
|
|
||||||
new_task->present = true;
|
new_task->present = true;
|
||||||
|
return new_task;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void task_init() {
|
||||||
|
idle_task = task_create(task_idle, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t task_spawn(task_entrypoint entrypoint, void *entry_data) {
|
||||||
|
task_t *new_task = task_create(entrypoint, entry_data);
|
||||||
|
if (first_task == NULL) {
|
||||||
|
// first task
|
||||||
|
first_task = new_task;
|
||||||
|
} else {
|
||||||
|
last_task->next = new_task;
|
||||||
|
}
|
||||||
|
last_task = new_task;
|
||||||
return new_task->tid;
|
return new_task->tid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,12 @@
|
|||||||
|
|
||||||
typedef void (*task_entrypoint)(void *entry_data);
|
typedef void (*task_entrypoint)(void *entry_data);
|
||||||
|
|
||||||
|
void task_notify_irq(uint8_t irq_no);
|
||||||
|
|
||||||
|
void task_wait_irq(uint16_t irq_bits);
|
||||||
|
|
||||||
|
void task_init();
|
||||||
|
|
||||||
void task_start_first();
|
void task_start_first();
|
||||||
|
|
||||||
void task_switch_next();
|
void task_switch_next();
|
||||||
|
|||||||
Reference in New Issue
Block a user