From ffb2c4adfb8e65e355b39abd39d994eebc649c98 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 3 Jan 2020 04:53:01 +0100 Subject: add (not yet fully working - it can only send through uart now) interrupt-driven uart together with "scheduler" --- scheduler.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 scheduler.c (limited to 'scheduler.c') diff --git a/scheduler.c b/scheduler.c new file mode 100644 index 0000000..3399bf4 --- /dev/null +++ b/scheduler.c @@ -0,0 +1,158 @@ +#include "scheduler.h" +#include "uart.h" +#include "strings.h" +#include "armclock.h" +#include "memory.h" +#include "io.h" + +// for now we only have 1 process in "queue" +// later there is going to be an actual queue +uint32_t PL0_regs[14] = {0}; // contains r0-r12, pc +uint32_t PL0_sp; +uint32_t PL0_lr; + +PSR_t PL0_PSR; // to be put into spsr when jumping to user mode + +PSR_t PL1_PSR; + +// when set, it means process used GETCHAR system call and once we get +// a char, we have to return it +_Bool waiting_for_input = 0; + +// when set, it means process used PUTCHAR system call and once we +// manage to put the char, we can return to process +_Bool waiting_for_output = 0; +char waiting_output; + +// 0 is kernel code in system mode is being run +// 1 if our process is being run +// later when we have many processes and this will hold process id +uint32_t current_process; + +void setup_scheduler_structures(void) +{ + PL1_PSR = read_CPSR(); +} + +void scheduler_try_output(void) +{ + if (waiting_for_output) + if (!putchar_non_blocking(waiting_output)) + { + waiting_for_output = 0; + uart_send_irq_disable(); + } +} + +void scheduler_try_input(void) +{ + if (waiting_for_input) + if ((PL0_regs[0] = getchar_non_blocking()) != (uint32_t) (-1)) + { + waiting_for_input = 0; + uart_recv_irq_disable(); + } +} + +void __attribute__((noreturn)) +schedule_new(uint32_t pc, uint32_t sp) +{ + PL0_regs[13] = pc; + PL0_sp = sp; + PL0_lr = 0; + + PL0_PSR = read_CPSR(); + PL0_PSR.fields.PSR_MODE_4_0 = MODE_USER; + PL0_PSR.fields.PSR_IRQ_MASK_BIT = 0; + + schedule(); +} + +void __attribute__((noreturn)) +schedule_wait_for_output(uint32_t regs[14], char c) +{ + if (current_process == 0) + error("SYSTEM tried waiting for output!"); + + waiting_for_output = 1; + waiting_output = c; + uart_send_irq_enable(); + + schedule_save_context(regs); +} + +void __attribute__((noreturn)) +schedule_wait_for_input(uint32_t regs[14]) +{ + if (current_process == 0) + error("SYSTEM tried waiting for input!"); + + waiting_for_input = 1; + uart_recv_irq_enable(); + + schedule_save_context(regs); +} + +void __attribute__((noreturn)) +schedule_save_context(uint32_t regs[14]) +{ + memcpy(PL0_regs, regs, sizeof(PL0_regs)); + + PL0_PSR = read_SPSR(); + + asm volatile("cps %[sysmode]\n\r" + "isb\n\r" + "mov %[sp_transfer], sp\n\r" + "mov %[lr_transfer], lr\n\r" + "cps %[supmode]\n\r" + "isb\n\r" : + [sp_transfer]"=r" (PL0_sp), + [lr_transfer]"=r" (PL0_lr): + [sysmode]"I" (MODE_SYSTEM), + [supmode]"I" (MODE_SUPERVISOR) : "memory"); + + schedule(); +} +extern _Bool flag; + +void __attribute__((noreturn)) schedule(void) +{ + current_process = 0; + armclk_disable_timer_irq(); + + if (waiting_for_input || waiting_for_output) + { + PSR_t new_CPSR = PL1_PSR; + new_CPSR.fields.PSR_IRQ_MASK_BIT = 0; + + write_CPSR(new_CPSR); + if (flag) putchar('l'); + + asm volatile("wfi"); + + __builtin_unreachable(); + } + + current_process = 1; + + asm volatile("cps %[sysmode]\n\r" + "isb\n\r" + "mov sp, %[stackaddr]\n\r" + "mov lr, %[linkaddr]\n\r" + "cps %[supmode]\n\r" + "isb" :: + [sysmode]"I" (MODE_SYSTEM), + [supmode]"I" (MODE_SUPERVISOR), + [stackaddr]"r" (PL0_sp), + [linkaddr]"r" (PL0_lr) : "memory"); + + armclk_enable_timer_irq(); + armclk_irq_settimeout(0x00100000); + + write_SPSR(PL0_PSR); + + asm volatile("ldm %0, {r0 - r12, pc} ^" :: + "r" (PL0_regs) : "memory"); + + __builtin_unreachable(); +} -- cgit v1.2.3 From 06991bb6572c1eb814ee35256b3c2bd06519acd2 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 3 Jan 2020 16:41:41 +0100 Subject: fix interrupt enabling/disabling/polling and uart fifo setting to make the io work properly --- PL0_test.c | 2 -- armclock.h | 12 +++++++++++- interrupts.c | 11 +---------- scheduler.c | 4 +--- uart.c | 11 +++++++++-- uart.h | 4 ++-- 6 files changed, 24 insertions(+), 20 deletions(-) (limited to 'scheduler.c') diff --git a/PL0_test.c b/PL0_test.c index fed62a2..0bfebc7 100644 --- a/PL0_test.c +++ b/PL0_test.c @@ -8,8 +8,6 @@ void PL0_main(void) puts("Hello userspace! Type 'f' if you want me to try accessing " "kernel memory!"); - - asm volatile("mov r0, #17\n\rsvc #0" ::: "r0"); while (1) { char c = getchar(); diff --git a/armclock.h b/armclock.h index 2b2aec9..f81f363 100644 --- a/armclock.h +++ b/armclock.h @@ -46,11 +46,21 @@ static inline void armclk_init(void) static inline void armclk_enable_timer_irq(void) { + armclk_control_t ctrl = + (armclk_control_t) *(uint32_t volatile*) ARMCLK_CONTROL; + ctrl.fields.interrupt_enable = 1; + *(uint32_t volatile*) ARMCLK_CONTROL = ctrl.raw; + *(uint32_t volatile*) ARM_ENABLE_BASIC_IRQS = 1; } static inline void armclk_disable_timer_irq(void) { + armclk_control_t ctrl = + (armclk_control_t) *(uint32_t volatile*) ARMCLK_CONTROL; + ctrl.fields.interrupt_enable = 0; + *(uint32_t volatile*) ARMCLK_CONTROL = ctrl.raw; + *(uint32_t volatile*) ARM_DISABLE_BASIC_IRQS = 1; } @@ -62,7 +72,7 @@ static inline void armclk_irq_settimeout(uint32_t timeout) static inline _Bool armclk_irq_pending(void) { - return *(uint32_t volatile*) ARMCLK_RAW_IRQ; + return *(uint32_t volatile*) ARM_IRQ_BASIC_PENDING & 1; } #endif // ARMCLOCK_H diff --git a/interrupts.c b/interrupts.c index 9beee0a..bf7ed02 100644 --- a/interrupts.c +++ b/interrupts.c @@ -18,7 +18,7 @@ void undefined_instruction_vector(void) { error("Undefined instruction occured"); } -_Bool flag = 0; + uint32_t supervisor_call_handler(uint32_t regs[14]) { switch(regs[0]) { @@ -38,15 +38,6 @@ uint32_t supervisor_call_handler(uint32_t regs[14]) case UART_WRITE: error("UART_WRITE not implemented!!!!!"); break; - case 17: - { - flag = 1; - /* while (1) */ - /* { */ - /* printbin(*(uint32_t volatile*) PL011_UART_MIS); puts(""); */ - /* } */ - break; - } default: // perhaps we should kill the process now? error("unknown supervisor call type!!!!!"); diff --git a/scheduler.c b/scheduler.c index 3399bf4..141ba1d 100644 --- a/scheduler.c +++ b/scheduler.c @@ -113,7 +113,6 @@ schedule_save_context(uint32_t regs[14]) schedule(); } -extern _Bool flag; void __attribute__((noreturn)) schedule(void) { @@ -126,7 +125,6 @@ void __attribute__((noreturn)) schedule(void) new_CPSR.fields.PSR_IRQ_MASK_BIT = 0; write_CPSR(new_CPSR); - if (flag) putchar('l'); asm volatile("wfi"); @@ -146,8 +144,8 @@ void __attribute__((noreturn)) schedule(void) [stackaddr]"r" (PL0_sp), [linkaddr]"r" (PL0_lr) : "memory"); - armclk_enable_timer_irq(); armclk_irq_settimeout(0x00100000); + armclk_enable_timer_irq(); write_SPSR(PL0_PSR); diff --git a/uart.c b/uart.c index c9fcd35..c4ae445 100644 --- a/uart.c +++ b/uart.c @@ -52,11 +52,14 @@ void uart_init() // Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40. mmio_write(PL011_UART_FBRD, 40); - // Enable FIFO & 8 bit data transmission (1 stop bit, no parity). - mmio_write(PL011_UART_LCRH, (1 << 4) | (1 << 5) | (1 << 6)); + // Set 8 bit data transmission (1 stop bit, no parity) + // and disable FIFO to be able to receive interrupt every received + // char, not every 2 chars + mmio_write(PL011_UART_LCRH, (1 << 5) | (1 << 6)); // set interrupt to come when transmit FIFO becomes ≤ 1/8 full // or receive FIFO becomes ≥ 1/8 full + // (not really matters, since we disabled FIFOs) mmio_write(PL011_UART_IFLS, 0); // Enable PL011_UART, receive & transfer part of UART.2 @@ -64,6 +67,10 @@ void uart_init() // At first, it's probably safer to disable interrupts :) uart_irq_disable(); + + // That disables the entire uart irq; also disable single sources + // within it + *(uint32_t volatile*) PL011_UART_IMSC = 0; } inline static _Bool can_transmit(void) diff --git a/uart.h b/uart.h index ce27d4e..eba292a 100644 --- a/uart.h +++ b/uart.h @@ -61,7 +61,7 @@ static inline void uart_irq_enable(void) static inline _Bool uart_recv_irq_pending(void) { - return ((uint32_t) 1 << 4) & *(uint32_t volatile*) PL011_UART_RIS; + return ((uint32_t) 1 << 4) & *(uint32_t volatile*) PL011_UART_MIS; } static inline void uart_recv_irq_disable(void) @@ -81,7 +81,7 @@ static inline void uart_clear_recv_irq(void) static inline _Bool uart_send_irq_pending(void) { - return ((uint32_t) 1 << 5) & *(uint32_t volatile*) PL011_UART_RIS; + return ((uint32_t) 1 << 5) & *(uint32_t volatile*) PL011_UART_MIS; } static inline void uart_send_irq_disable(void) -- cgit v1.2.3