From 0cfd3b4bae21dc79a4074cfd5dfe5fd9d82a99db Mon Sep 17 00:00:00 2001 From: Roberto Valenzuela Date: Mon, 8 Apr 2024 02:48:47 -0400 Subject: [PATCH] user: create first demo that display ascii art --- include/peripherals/irq.h | 74 +++++++------------------------ include/peripherals/timer.h | 15 ++++--- include/sched.h | 87 +++++++++++++++++++------------------ include/user/demo1.h | 7 +++ src/armv8.S | 22 +++++++--- src/demo1.c | 25 +++++++++++ src/irq.c | 11 +++-- src/main.c | 31 +++++++++---- src/timer.c | 20 ++++++++- 9 files changed, 164 insertions(+), 128 deletions(-) create mode 100644 include/user/demo1.h create mode 100644 src/demo1.c diff --git a/include/peripherals/irq.h b/include/peripherals/irq.h index 4acb560..70a2875 100644 --- a/include/peripherals/irq.h +++ b/include/peripherals/irq.h @@ -3,73 +3,31 @@ #include "base.h" -// struct arm_irq_regs_2711 { -// volatile unsigned int irq0_pending0; -// volatile unsigned int irq0_pending1; -// volatile unsigned int irq0_pending2; -// volatile unsigned int irq0_set_en_0; -// volatile unsigned int irq0_set_en_1; -// volatile unsigned int irq0_set_en_2; -// volatile unsigned int irq_clr_en_0; -// volatile unsigned int irq_clr_en_1; -// volatile unsigned int irq_clr_en_2; -// volatile unsigned int irq_status0; -// volatile unsigned int irq_status1; -// volatile unsigned int irq_status2; -// }; - -// typedef struct arm_irq_regs_2711 arm_irq_regs; - -// #define GIC_BASE 0xFF840000 -// #define GICD_DIST_BASE (GIC_BASE + 0x00001000) -// #define GICC_CPU_BASE (GIC_BASE + 0x00002000) - -// #define GICD_ENABLE_IRQ_BASE (GICD_DIST_BASE + 0x00000100) - -// #define GICC_IAR (GICC_CPU_BASE + 0x0000000C) -// #define GICC_EOIR (GICC_CPU_BASE + 0x00000010) - -// #define GIC_IRQ_TARGET_BASE (GICD_DIST_BASE+0x00000800) - -// //VC (=VideoCore) starts at 96 -// #define SYSTEM_TIMER_IRQ_0 (0x60) //96 -// #define SYSTEM_TIMER_IRQ_1 (0x61) //97 -// #define SYSTEM_TIMER_IRQ_2 (0x62) //98 -// #define SYSTEM_TIMER_IRQ_3 (0x63) //99 - -// // #define REGS_IRQ ((arm_irq_regs *)(GIC_BASE + 0x0000B200)) -// #define REGS_IRQ ((arm_irq_regs *)(0xFF00B200)) - -// enum vc_irqs { -// SYS_TIMER_IRQ_0 = 1, -// SYS_TIMER_IRQ_1 = 2, -// SYS_TIMER_IRQ_2 = 4, -// SYS_TIMER_IRQ_3 = 8, -// AUX_IRQ = (1 << 29) -// }; - #define GIC_BASE 0xFF840000 -#define GICD_DIST_BASE (GIC_BASE+0x00001000) -#define GICC_CPU_BASE (GIC_BASE+0x00002000) +#define GICD_DIST_BASE (GIC_BASE + 0x00001000) +#define GICC_CPU_BASE (GIC_BASE + 0x00002000) -#define GICD_ENABLE_IRQ_BASE (GICD_DIST_BASE+0x00000100) +#define GICD_ENABLE_IRQ_BASE (GICD_DIST_BASE + 0x00000100) -#define GICC_IAR (GICC_CPU_BASE+0x0000000C) -#define GICC_EOIR (GICC_CPU_BASE+0x00000010) +#define GICC_IAR (GICC_CPU_BASE + 0x0000000C) +#define GICC_EOIR (GICC_CPU_BASE + 0x00000010) -#define GIC_IRQ_TARGET_BASE (GICD_DIST_BASE+0x00000800) +#define GIC_IRQ_TARGET_BASE (GICD_DIST_BASE + 0x00000800) -//VC (=VideoCore) starts at 96 -#define SYSTEM_TIMER_IRQ_0 (0x60) //96 -#define SYSTEM_TIMER_IRQ_1 (0x61) //97 -#define SYSTEM_TIMER_IRQ_2 (0x62) //98 -#define SYSTEM_TIMER_IRQ_3 (0x63) //99 +/* VideoCore interrupts + * + * VC (=VideoCore) starts at 96 + * BCM2711 ARM Peripherals, p.87/166 + */ +#define SYSTEM_TIMER_IRQ_0 (0x60) // 96 +#define SYSTEM_TIMER_IRQ_1 (0x61) // 97 +#define SYSTEM_TIMER_IRQ_2 (0x62) // 98 +#define SYSTEM_TIMER_IRQ_3 (0x63) // 99 void enable_interrupt_controller(void); -void disable_interrupt_controller(void); void handle_irq(void); -// In assembly file +/* In irq.S assembly file */ extern void exception_vectors_init(void); extern void irq_enable(void); extern void irq_disable(void); diff --git a/include/peripherals/timer.h b/include/peripherals/timer.h index fff9463..0dd060d 100644 --- a/include/peripherals/timer.h +++ b/include/peripherals/timer.h @@ -20,13 +20,13 @@ // static char* const SYS_TIMER_BASE = (char*)(PERIPHERALS_BASE + 0x3000); -#define TIMER_CS (PERIPHERALS_BASE+0x00003000) -#define TIMER_CLO (PERIPHERALS_BASE+0x00003004) -#define TIMER_CHI (PERIPHERALS_BASE+0x00003008) -#define TIMER_C0 (PERIPHERALS_BASE+0x0000300C) -#define TIMER_C1 (PERIPHERALS_BASE+0x00003010) -#define TIMER_C2 (PERIPHERALS_BASE+0x00003014) -#define TIMER_C3 (PERIPHERALS_BASE+0x00003018) +#define TIMER_CS (PERIPHERALS_BASE + 0x00003000) +#define TIMER_CLO (PERIPHERALS_BASE + 0x00003004) +#define TIMER_CHI (PERIPHERALS_BASE + 0x00003008) +#define TIMER_C0 (PERIPHERALS_BASE + 0x0000300C) +#define TIMER_C1 (PERIPHERALS_BASE + 0x00003010) +#define TIMER_C2 (PERIPHERALS_BASE + 0x00003014) +#define TIMER_C3 (PERIPHERALS_BASE + 0x00003018) #define TIMER_CS_M0 (1 << 0) #define TIMER_CS_M1 (1 << 1) @@ -47,5 +47,6 @@ struct timer_regs uint32_t sys_timer_get_count(void); void sys_timer_init(void); void handle_timer_1_irq(void); +void handle_timer_3_irq(void); #endif /* PERIPHERALS_TIMER_H_ */ diff --git a/include/sched.h b/include/sched.h index 2441467..11a0265 100644 --- a/include/sched.h +++ b/include/sched.h @@ -48,56 +48,59 @@ typedef enum /* CPUContext_t * */ -// typedef struct _cpu_context -// { -// unsigned long x0; -// unsigned long x1; -// unsigned long x2; -// unsigned long x3; -// unsigned long x4; -// unsigned long x5; -// unsigned long x6; -// unsigned long x7; -// unsigned long x8; -// unsigned long x9; -// unsigned long x10; -// unsigned long x11; -// unsigned long x12; -// unsigned long x13; -// unsigned long x14; -// unsigned long x15; -// unsigned long x16; -// unsigned long x17; -// unsigned long x18; -// unsigned long x19; -// unsigned long x20; -// unsigned long x21; -// unsigned long x22; -// unsigned long x23; -// unsigned long x24; -// unsigned long x25; -// unsigned long x26; -// unsigned long x27; -// unsigned long x28; -// unsigned long x29; -// unsigned long x30; -// unsigned long elr_el1; -// unsigned long spsr_el1; -// unsigned long sp_el0; -// } CPUContext_t; +typedef struct _cpu_context +{ + // unsigned long x0; + // unsigned long x1; + // unsigned long x2; + // unsigned long x3; + // unsigned long x4; + // unsigned long x5; + // unsigned long x6; + // unsigned long x7; + // unsigned long x8; + // unsigned long x9; + // unsigned long x10; + // unsigned long x11; + // unsigned long x12; + // unsigned long x13; + // unsigned long x14; + // unsigned long x15; + // unsigned long x16; + // unsigned long x17; + // unsigned long x18; + unsigned long x19; + unsigned long x20; + unsigned long x21; + unsigned long x22; + unsigned long x23; + unsigned long x24; + unsigned long x25; + unsigned long x26; + unsigned long x27; + unsigned long x28; + // unsigned long x29; + // unsigned long x30; + // unsigned long elr_el1; + // unsigned long spsr_el1; + // unsigned long sp_el0; + unsigned long fp; + unsigned long sp; + unsigned long pc; +} CPUContext_t; /* TaskDescriptor_t */ typedef struct _task_descriptor { - int tid; /* Task identifier (tid), which is unique among all active tasks */ - int priority; /* The task's priority */ - TaskDescriptor_t *parent_td; /* A pointer to the TaskDescriptor of the task that created it, its parent */ + int tid; /* Task identifier (tid), which is unique among all active tasks */ + int priority; /* The task's priority */ + TaskDescriptor_t *parent_td; /* A pointer to the TaskDescriptor of the task that created it, its parent */ // TaskDescriptor_t *next_task_ready_queue; /* Pointer to TaskDescriptor of the next ready task (schedule) */ // TaskDescriptor_t *next_task_send_queue; /* Pointer to TaskDescriptor of the next ready task (send queue) */ TaskState_t state; /* The task's current run state */ - /* TODO */ /* The task's current stack pointer */ - /* TODO - CPU Context CPUContext_t *context; This is the context, includes the tasks's SPSR */ + /* TODO */ /* The task's current stack pointer */ + CPUContext_t cpu_context; /* This is the context, includes the tasks's SPSR */ entry_point function; } TaskDescriptor_t; diff --git a/include/user/demo1.h b/include/user/demo1.h new file mode 100644 index 0000000..d29454f --- /dev/null +++ b/include/user/demo1.h @@ -0,0 +1,7 @@ +#ifndef USER_DEMO1_H_ +#define USER_DEMO1_H_ + +void user_task(void); +void display_ascii_art(void); + +#endif /* USER_DEMO1_H_ */ diff --git a/src/armv8.S b/src/armv8.S index 7a51402..f723f7f 100644 --- a/src/armv8.S +++ b/src/armv8.S @@ -18,8 +18,8 @@ #define FIQ_INVALID_EL0_32 14 #define ERROR_INVALID_EL0_32 15 -// Stack frame size -#define S_FRAME_SIZE 256 // Size of all saved registers +/* Stack frame size - size of all stored registers */ +#define S_FRAME_SIZE 256 /* Kernel entry */ .macro kernel_entry @@ -42,8 +42,7 @@ str x30, [sp, #16 * 15] .endm -// Kernel exit -// .macro kernel_exit, el +/* Kernel exit */ .macro kernel_exit ldp x0, x1, [sp, #16 * 0] ldp x2, x3, [sp, #16 * 1] @@ -65,7 +64,7 @@ eret .endm -// .macro handle_invalid_entry el, type +/* Handle invalid entry */ .macro handle_invalid_entry type kernel_entry mov x0, #\type @@ -75,6 +74,7 @@ b err_hang .endm +/* `ventry` is used to create entries in the vector table */ .macro ventry label .balign 0x80 b \label @@ -154,7 +154,11 @@ fiq_invalid_el0_32: error_invalid_el0_32: handle_invalid_entry ERROR_INVALID_EL0_32 -/* IRQ handler */ +/* IRQ handler + * + * Note: Whenever an exception handler is executed, the processor + * automatically disables all types of interrupts (masking). + */ .align 8 handle_el1_irq: kernel_entry @@ -196,7 +200,11 @@ exception_vectors_init: isb sy ret -/* Enable IRQ */ +/* Enable IRQ + * + * We use the value of 2 because we only want to set (in irq_enable) and + * clear (in irq_disable) second bit that corresponds to the I Mask (IRQs). + */ .align 8 .global irq_enable irq_enable: diff --git a/src/demo1.c b/src/demo1.c new file mode 100644 index 0000000..0853b96 --- /dev/null +++ b/src/demo1.c @@ -0,0 +1,25 @@ +#include "user/demo1.h" + +#include "peripherals/uart.h" + +void user_task(void) +{ + while (1) { + for (int i = 0; i < 50; i++) { + uart_printf(CONSOLE, "first_task (user): %d\r\n", i); + } + } +} + +/* ASCII art + * https://www.asciiart.eu/vehicles/trains + */ +void display_ascii_art(void) +{ + uart_printf(CONSOLE, " _____ . . . . . o o o o o\n"); + uart_printf(CONSOLE, " __|[_]|__ ___________ _______ ____ o\n"); + uart_printf(CONSOLE, " |[] [] []| [] [] [] [] [_____(__ ][]]_n_n__][.\n"); + uart_printf(CONSOLE, "_|________|_[_________]_[________]_|__|________)<\n"); + uart_printf(CONSOLE, " oo oo 'oo oo ' oo oo 'oo 0000---oo\\_\n"); + uart_printf(CONSOLE, " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); +} diff --git a/src/irq.c b/src/irq.c index e45120a..20ae534 100644 --- a/src/irq.c +++ b/src/irq.c @@ -6,11 +6,11 @@ void enable_interrupt(unsigned int irq) { - uart_printf(CONSOLE, "%x\r\n", irq); + uart_printf(CONSOLE, "irq: %x\r\n", irq); unsigned int n = irq / 32; unsigned int offset = irq % 32; unsigned int enableRegister = GICD_ENABLE_IRQ_BASE + (4*n); - uart_printf(CONSOLE, "EnableRegister: %x\r\n", enableRegister); + uart_printf(CONSOLE, "irq: EnableRegister: %x\r\n", enableRegister); put32(enableRegister, 1 << offset); } @@ -32,12 +32,17 @@ void enable_interrupt_controller() void handle_irq(void) { unsigned int irq_ack_reg = get32(GICC_IAR); - unsigned int irq = irq_ack_reg & 0x2FF; + unsigned int irq = irq_ack_reg & 0x2FF; switch (irq) { case (SYSTEM_TIMER_IRQ_1): + put32(GICC_EOIR, irq_ack_reg); handle_timer_1_irq(); break; + // case (SYSTEM_TIMER_IRQ_3): + // put32(GICC_EOIR, irq_ack_reg); + // handle_timer_3_irq(); + // break; default: uart_printf(CONSOLE, "irq: Unknown pending irq: %x\r\n", irq); } diff --git a/src/main.c b/src/main.c index 08334e0..b882648 100644 --- a/src/main.c +++ b/src/main.c @@ -4,15 +4,7 @@ #include "peripherals/uart.h" #include "sched.h" #include "task.h" - -void user_task(void) -{ - while (1) { - for (int i = 0; i < 50; i++) { - uart_printf(CONSOLE, "first_task (user): %d\r\n", i); - } - } -} +#include "user/demo1.h" /* start_kernel * @@ -66,9 +58,22 @@ int kmain(void) // return first_task; // } + // int second_task = task_create(0, &user_art); + // if (first_task < 0) { + // uart_printf(CONSOLE, "Error creating first task: %d\r\n", first_task); + // return first_task; + // } + char input; uint32_t count; + uart_printf(CONSOLE, " _____ . . . . . o o o o o\r\n"); + uart_printf(CONSOLE, " __|[_]|__ ___________ _______ ____ o\r\n"); + uart_printf(CONSOLE, " |[] [] []| [] [] [] [] [_____(__ ][]]_n_n__][.\r\n"); + uart_printf(CONSOLE, "_|________|_[_________]_[________]_|__|________)<\r\n"); + uart_printf(CONSOLE, " oo oo 'oo oo ' oo oo 'oo 0000---oo\\_\r\n"); + uart_printf(CONSOLE, " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n"); + while (1) { input = uart_getc(CONSOLE); @@ -80,6 +85,14 @@ int kmain(void) } else { uart_putc(CONSOLE, input); } + + display_ascii_art(); + + for (int i = 0; i < 10; i++) { + uart_printf(CONSOLE, "Delay [%d]...\r\n", i); + delay(1000000); + } + } // while (1) { diff --git a/src/timer.c b/src/timer.c index e345ccb..9c3951e 100644 --- a/src/timer.c +++ b/src/timer.c @@ -10,23 +10,39 @@ */ const unsigned int timer1_interval = 200000; +const unsigned int timer3_interval = 200000 / 4; unsigned int timer1_val = 0; +unsigned int timer3_val = 0; void sys_timer_init(void) { timer1_val = get32(TIMER_CLO); timer1_val += timer1_interval; put32(TIMER_C1, timer1_val); + + timer1_val = get32(TIMER_CLO); + timer1_val += timer1_interval; + put32(TIMER_C3, timer1_val); } void handle_timer_1_irq(void) { timer1_val += timer1_interval; put32(TIMER_C1, timer1_val); - /* TODO: What are we setting here? */ + /* TODO: What are we setting here? + * https://github.com/s-matyukevich/raspberry-pi-os/blob/master/docs/lesson03/rpi-os.md + */ put32(TIMER_CS, TIMER_CS_M1); - uart_printf(CONSOLE, "[irq] Timer interrupt received\r\n..."); + uart_printf(CONSOLE, "[irq] Timer 1 interrupt received.\r\n"); +} +void handle_timer_3_irq(void) +{ + timer3_val += timer3_interval; + put32(TIMER_C3, timer3_val); + /* TODO: What are we setting here? */ + put32(TIMER_CS, TIMER_CS_M3); + uart_printf(CONSOLE, "[irq] Timer 3 interrupt received\r\n..."); } uint32_t sys_timer_get_count(void)