aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojtek Kosior <kwojtus@protonmail.com>2020-01-02 13:24:29 +0100
committerWojtek Kosior <kwojtus@protonmail.com>2020-01-02 13:24:29 +0100
commit3941fe97783c7a31ab04fbfb127f5026dd31ef78 (patch)
tree523b0b1d626969c3eb52545b672ca909dd5ae31b
parentea465f85cf7a47f488332509a2f6d7ae5c88057c (diff)
downloadrpi-MMU-example-3941fe97783c7a31ab04fbfb127f5026dd31ef78.tar.gz
rpi-MMU-example-3941fe97783c7a31ab04fbfb127f5026dd31ef78.zip
demo of arm timer irq
-rw-r--r--PL0_test.c29
-rw-r--r--armclock.h53
-rw-r--r--demo_functionality.c4
-rw-r--r--interrupts.c14
-rw-r--r--setup.c9
5 files changed, 78 insertions, 31 deletions
diff --git a/PL0_test.c b/PL0_test.c
index ac74ad4..c6cbe18 100644
--- a/PL0_test.c
+++ b/PL0_test.c
@@ -5,25 +5,30 @@ void PL0_main(void)
{
// If loading program to userspace and handling of svc are
// implemented correctly, this shall get printed
- puts("Hello userspace!");
+ puts("Hello userspace! Type 'f' if you want me to try accessing "
+ "kernel memory!");
- // if we're indeed in PL0, we should trigger the abort handler now,
- // when trying to access memory we're not allowed to
- puts("Attempting to meddle with kernel memory from userspace :d");
- char first_kernel_byte[2];
-
- first_kernel_byte[0] = *(char*) 0x0;
- first_kernel_byte[1] = '\0';
-
- puts(first_kernel_byte);
-
while (1)
{
char c = getchar();
if (c == '\r')
putchar('\n');
-
+
putchar(c);
+
+ if (c == 'f')
+ {
+ // if we're indeed in PL0, we should trigger the abort
+ // handler now, when trying to access memory we're not
+ // allowed to
+ puts("Attempting to read kernel memory from userspace :d");
+ char first_kernel_byte[2];
+
+ first_kernel_byte[0] = *(char*) 0x0;
+ first_kernel_byte[1] = '\0';
+
+ puts(first_kernel_byte);
+ }
}
}
diff --git a/armclock.h b/armclock.h
index 67a4ab8..700879a 100644
--- a/armclock.h
+++ b/armclock.h
@@ -1,6 +1,8 @@
#ifndef ARMCLOCK_H
#define ARMCLOCK_H
+#include <stdint.h>
+
#include "global.h"
#define ARMCLK_LOAD (ARM_BASE + 0x400)
@@ -15,35 +17,56 @@
#define ARMCLK_LOAD_FREE_RUNNING_COUNTER (ARM_BASE + 0x420)
#define BCMCLK_ENABLE_BASIC_IRQS (ARM_BASE + 0x218)
+#define BCMCLK_DISABLE_BASIC_IRQS (ARM_BASE + 0x224)
-static inline void armclk_enable_timer_irq(void)
+typedef union armclk_control
{
- // uint32_t control_reg = *(uint32_t volatile*) ARMCLK_CONTROL;
- // control_reg |= 1 << 5;
- // *(uint32_t volatile*) ARMCLK_CONTROL = control_reg;
- *(uint32_t volatile*) ARMCLK_CONTROL = 0x00000000;
- *(uint32_t volatile*) ARMCLK_LOAD_PRE_DRIVER = 0x000000f9;
- *(uint32_t volatile*) ARMCLK_LOAD_RELOAD = 0x4C4B40; //50 times a Sec by 250Mhz
- *(uint32_t volatile*) ARMCLK_LOAD = 0x4C4B40;//50 times a Sec by 250Mhz
- *(uint32_t volatile*) ARMCLK_IRQ_CLR_ACK = 0x00000000;
- *(uint32_t volatile*) ARMCLK_CONTROL = 0x000000a2;
-
+ uint32_t raw;
+ struct
+ {
+ uint32_t one_shot_mode : 1; // bit 0; unused in RPi
+ uint32_t counter_23bit : 1; // bit 1
+ uint32_t pre_scale : 2; // bits 3:2
+ uint32_t bit_4 : 1; // bit 4
+ uint32_t interrupt_enable : 1; // bit 5
+ uint32_t periodic_mode : 1; // bit 6; unused in RPi
+ uint32_t timer_enable : 1; // bit 7
+ uint32_t halt_in_debug : 1; // bit 8
+ uint32_t free_running_enable : 1; // bit 9
+ uint32_t bits_15_10 : 6; // bits 15:10
+ uint32_t free_running_pre_scaler : 8; // bits 23:16
+ uint32_t bits_31_24 : 8; // bits 31:24
+ } fields;
+} armclk_control_t;
+static inline void armclk_init(void)
+{
+ armclk_control_t ctrl = (armclk_control_t) (uint32_t) 0;
+ ctrl.fields.timer_enable = 1;
+ ctrl.fields.interrupt_enable = 1;
+ ctrl.fields.counter_23bit = 1;
+ *(uint32_t volatile*) ARMCLK_CONTROL = ctrl.raw;
+}
-
+static inline void armclk_enable_timer_irq(void)
+{
*(uint32_t volatile*) BCMCLK_ENABLE_BASIC_IRQS = 1;
}
static inline void armclk_disable_timer_irq(void)
{
- uint32_t control_reg = *(uint32_t volatile*) ARMCLK_CONTROL;
- control_reg &= ~((uint32_t) 1 << 5);
- *(uint32_t volatile*) ARMCLK_CONTROL = control_reg;
+ *(uint32_t volatile*) BCMCLK_DISABLE_BASIC_IRQS = 1;
}
static inline void armclk_set_timer_match_timeout(uint32_t timeout)
{
+ *(uint32_t volatile*) ARMCLK_IRQ_CLR_ACK = 0;
*(uint32_t volatile*) ARMCLK_LOAD = timeout;
}
+static inline _Bool armclk_irq_pending(void)
+{
+ return *(uint32_t volatile*) ARMCLK_LOAD_RAW_IRQ;
+}
+
#endif // ARMCLOCK_H
diff --git a/demo_functionality.c b/demo_functionality.c
index 3cf5b8f..a2d8550 100644
--- a/demo_functionality.c
+++ b/demo_functionality.c
@@ -5,6 +5,7 @@
#include "ramfs.h"
#include "strings.h"
#include "paging.h"
+#include "armclock.h"
void demo_paging_support(void)
{
@@ -120,10 +121,13 @@ void demo_go_unprivileged(void)
PSR_t new_SPSR = read_CPSR();
new_SPSR.fields.PSR_MODE_4_0 = MODE_USER;
+ new_SPSR.fields.PSR_IRQ_MASK_BIT = 0;
write_SPSR(new_SPSR);
puts("All ready, jumping to PL0 code");
+ armclk_set_timer_match_timeout(0x00100000);
+
asm volatile("cps %[sysmode]\n\r"
"mov sp, %[stackaddr]\n\r"
"cps %[supmode]\n\r"
diff --git a/interrupts.c b/interrupts.c
index c6e3f17..62c644b 100644
--- a/interrupts.c
+++ b/interrupts.c
@@ -1,5 +1,6 @@
#include "io.h"
#include "svc_interface.h"
+#include "armclock.h"
void __attribute__((noreturn)) setup(void);
@@ -58,9 +59,16 @@ void generic_handler(void)
void irq_handler(void)
{
- puts("irq happened");
-
- while(1);
+ if (armclk_irq_pending())
+ {
+ puts("<<irq from timer>>");
+ armclk_set_timer_match_timeout(0x00100000);
+ }
+ else
+ {
+ puts("unknown irq");
+ while(1);
+ }
}
void fiq_handler(void)
diff --git a/setup.c b/setup.c
index 63ca054..ad01720 100644
--- a/setup.c
+++ b/setup.c
@@ -5,6 +5,7 @@
#include "atags.h"
// for POWER_OF_2() macro... perhaps the macro should be moved
#include "memory.h"
+#include "armclock.h"
void setup(uint32_t r0, uint32_t machine_type,
struct atag_header *atags)
@@ -14,7 +15,7 @@ void setup(uint32_t r0, uint32_t machine_type,
// When we attach screen session after loading kernel with socat
// we miss kernel's greeting... So we'll make the kernel wait for
// one char we're going to send from within screen
- //getchar();
+ getchar();
puts("Hello, kernel World!");
@@ -97,6 +98,12 @@ void setup(uint32_t r0, uint32_t machine_type,
// loads a blob there
demo_setup_PL0();
+ // sets some general settings for arm timer
+ armclk_init();
+
+ // turns on irq from arm timer
+ armclk_enable_timer_irq();
+
// jumps to unprivileged code... never, ever, ever returns
demo_go_unprivileged();