diff options
-rw-r--r-- | PL0_test.ld | 5 | ||||
-rw-r--r-- | demo_functionality.c | 96 | ||||
-rw-r--r-- | demo_functionality.h | 4 | ||||
-rw-r--r-- | interrupts.h | 128 | ||||
-rw-r--r-- | kernel.c | 28 | ||||
-rw-r--r-- | memory.h | 28 |
6 files changed, 182 insertions, 107 deletions
diff --git a/PL0_test.ld b/PL0_test.ld index 45bee5e..430e098 100644 --- a/PL0_test.ld +++ b/PL0_test.ld @@ -4,11 +4,6 @@ SECTIONS { /* 0b10101010101000000000000000000000 */ . = 0xaaa00000; - - /* For some reason ld warns when _start is not defined. */ - /* Other .elf files link ok - only PL0_test.elf seems to */ - /* expect _start to be deifned. */ - _start = .; __start = .; __text_start = .; .text : diff --git a/demo_functionality.c b/demo_functionality.c index 3375550..691cdb1 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -2,7 +2,6 @@ #include "psr.h" #include "memory.h" #include "translation_table_descriptors.h" -#include "libkernel.h" void demo_paging_support(void) { @@ -53,73 +52,35 @@ void demo_current_mode(void) uart_puts(mode_name); } -#define TRANSLATION_TABLE \ - ((short_section_descriptor_t volatile*) TRANSLATION_TABLE_BASE) - -extern char - __renamed_start, - __renamed_end, - __renamed_size; - -void demo_setup_libkernel(void) { - short_section_descriptor_t volatile *libkernel_section_entry = - &TRANSLATION_TABLE[LIBKERNEL_SECTION_NUMBER]; - - short_section_descriptor_t - libkernel_section = *libkernel_section_entry; - - // make libkernel section executable and read-only for - // unprivileged code - libkernel_section.ACCESS_PERMISSIONS_2 = - AP_2_0_MODEL_RW_PL1_RO_PL0 >> 2; - libkernel_section.ACCESS_PERMISSIONS_1_0 = - AP_2_0_MODEL_RW_PL1_RO_PL0 & 0b011; - - *libkernel_section_entry = libkernel_section; - - // invalidate main Translation Lookup Buffer (just in case) - asm("mcr p15, 0, %0, c8, c7, 0\n\r" - "isb" :: "r" (0) : "memory"); - - // copy libkernel code to libkernel section - for (size_t i = 0; i < (size_t) &__renamed_size; i++) - ((volatile char*) LIBKERNEL_SECTION_START)[i] = - (&__renamed_start)[i]; -} - extern char _binary_PL_0_test_img_start, _binary_PL_0_test_img_end, _binary_PL_0_test_img_size; -void demo_setup_PL0(void) +void demo_go_unprivileged(void) { - short_section_descriptor_t volatile *PL0_section_entry = - &TRANSLATION_TABLE[PL0_SECTION_NUMBER]; - short_section_descriptor_t volatile *UART_memory_section_entry = - &TRANSLATION_TABLE[((uint32_t) GPIO_BASE) >> 20]; + short_section_descriptor_t *translation_table = + (short_section_descriptor_t*) TRANSLATION_TABLE_BASE; - short_section_descriptor_t - PL0_section = *PL0_section_entry, - UART_memory_section = *UART_memory_section_entry; + volatile short_section_descriptor_t *PL0_section = + &translation_table[PL0_SECTION_NUMBER]; + volatile short_section_descriptor_t *UART_memory_section = + &translation_table[((uint32_t) GPIO_BASE) >> 20]; - // set up address of PL0 section - PL0_section.SECTION_BASE_ADDRESS_31_20 = + PL0_section->SECTION_BASE_ADDRESS_31_20 = UNPRIVILEGED_MEMORY_START >> 20; // make the selected section and uart section available for PL0 - PL0_section.ACCESS_PERMISSIONS_2 = + PL0_section->ACCESS_PERMISSIONS_2 = AP_2_0_MODEL_RW_ALL >> 2; - PL0_section.ACCESS_PERMISSIONS_1_0 = + PL0_section->ACCESS_PERMISSIONS_1_0 = AP_2_0_MODEL_RW_ALL & 0b011; - UART_memory_section.ACCESS_PERMISSIONS_2 = + UART_memory_section->ACCESS_PERMISSIONS_2 = AP_2_0_MODEL_RW_ALL >> 2; - UART_memory_section.ACCESS_PERMISSIONS_1_0 = + UART_memory_section->ACCESS_PERMISSIONS_1_0 = AP_2_0_MODEL_RW_ALL & 0b011; - - *PL0_section_entry = PL0_section; - *UART_memory_section_entry = UART_memory_section; + // invalidate main Translation Lookup Buffer (just in case) asm("mcr p15, 0, %0, c8, c7, 0\n\r" @@ -135,32 +96,19 @@ void demo_setup_PL0(void) uart_puts((char*) VIRTUAL_PL0_MEMORY_START); - // now paste a userspace program to that section + // now paste a userspace program to that section, jump to it and + // switch to PL0 for (size_t i = 0; i < (size_t) &_binary_PL_0_test_img_size; i++) ((volatile char*) VIRTUAL_PL0_MEMORY_START)[i] = (&_binary_PL_0_test_img_start)[i]; - uart_puts("copied PL0 and libkernel code to their sections"); -} - -void demo_go_unprivileged(void) -{ - size_t call_unprivileged_offset = - (size_t) &call_unprivileged - (size_t) &__renamed_start; - - void *call_unprivileged_new_location = - (void*) (LIBKERNEL_SECTION_START + call_unprivileged_offset); - - // call call_unprivileged from libkernel - asm volatile("mov r5, %0\n\r" - "mov r0, %1\n\r" - "mov r4, #0\n\r" - "movt r4, #"PL0_SECTION_NUMBER_STR"1111\n\r" - "mov sp, r4\n\r" // setting stack is important :D - "blx r5\n\r" :: - "r" (call_unprivileged_new_location), - "r" (VIRTUAL_PL0_MEMORY_START) - : "memory", "r4", "r5", "r0"); + // jump to that copied code (switch to PL0 is done by that code) + asm volatile("mov r5, #0\n\r" + "movt r5, #"PL0_SECTION_NUMBER_STR"1111\n\r" + "mov sp, r5\n\r" // setting stack is important :D + "mov r5, #0\n\r" + "movt r5, #"PL0_SECTION_NUMBER_STR"0000\n\r" + "blx r5\n\r"); } extern char diff --git a/demo_functionality.h b/demo_functionality.h index 12f5807..57fd6f0 100644 --- a/demo_functionality.h +++ b/demo_functionality.h @@ -5,10 +5,6 @@ void demo_paging_support(void); void demo_current_mode(void); -void demo_setup_libkernel(void); - -void demo_setup_PL0(void); - void demo_go_unprivileged(void); void demo_setup_interrupts(void); diff --git a/interrupts.h b/interrupts.h new file mode 100644 index 0000000..9f80668 --- /dev/null +++ b/interrupts.h @@ -0,0 +1,128 @@ +#ifndef RPI_MMU_EXAMPLE_INTERRUPTS_H +#define RPI_MMU_EXAMPLE_INTERRUPTS_H + +#include <stdint.h> + + //offset of peripherals+ offset for first addresable register for interupt controller +#define RPI_INTERRUPT_CONTROLLER_BASE ( 0x3F000000UL + 0xB200 ) + +// Bits in the Enable_Basic_IRQs register to enable various interrupts. +// According to the BCM2835 ARM Peripherals manual, section 7.5 */ + +#define RPI_BASIC_ARM_TIMER_IRQ (1 << 0) +#define RPI_BASIC_ARM_MAILBOX_IRQ (1 << 1) +#define RPI_BASIC_ARM_DOORBELL_0_IRQ (1 << 2) +#define RPI_BASIC_ARM_DOORBELL_1_IRQ (1 << 3) +#define RPI_BASIC_GPU_0_HALTED_IRQ (1 << 4) +#define RPI_BASIC_GPU_1_HALTED_IRQ (1 << 5) +#define RPI_BASIC_ACCESS_ERROR_1_IRQ (1 << 6) +#define RPI_BASIC_ACCESS_ERROR_0_IRQ (1 << 7) + +// @brief The interrupt controller memory mapped register set +typedef struct { + volatile uint32_t IRQ_basic_pending; + volatile uint32_t IRQ_pending_1; + volatile uint32_t IRQ_pending_2; + volatile uint32_t FIQ_control; + volatile uint32_t Enable_IRQs_1; + volatile uint32_t Enable_IRQs_2; + volatile uint32_t Enable_Basic_IRQs; + volatile uint32_t Disable_IRQs_1; + volatile uint32_t Disable_IRQs_2; + volatile uint32_t Disable_Basic_IRQs; +} rpi_irq_controller_t; + +extern rpi_irq_controller_t* RPI_GetIrqController(void); + +//TIMER + +/*--------------------------------------------------------------------------} +{ LOCAL TIMER INTERRUPT ROUTING REGISTER - QA7_rev3.4.pdf page 18 } +{--------------------------------------------------------------------------*/ +typedef union +{ + struct + { + enum { + LOCALTIMER_TO_CORE0_IRQ = 0, + LOCALTIMER_TO_CORE1_IRQ = 1, + LOCALTIMER_TO_CORE2_IRQ = 2, + LOCALTIMER_TO_CORE3_IRQ = 3, + LOCALTIMER_TO_CORE0_FIQ = 4, + LOCALTIMER_TO_CORE1_FIQ = 5, + LOCALTIMER_TO_CORE2_FIQ = 6, + LOCALTIMER_TO_CORE3_FIQ = 7, + } Routing: 3; // @0-2 Local Timer routing + unsigned unused : 29; // @3-31 + }; + uint32_t Raw32; // Union to access all 32 bits as a uint32_t +} local_timer_int_route_reg_t; + +/*--------------------------------------------------------------------------} +{ LOCAL TIMER CONTROL AND STATUS REGISTER - QA7_rev3.4.pdf page 17 } +{--------------------------------------------------------------------------*/ +typedef union +{ + struct + { + unsigned ReloadValue : 28; // @0-27 Reload value + unsigned TimerEnable : 1; // @28 Timer enable (1 = enabled) + unsigned IntEnable : 1; // @29 Interrupt enable (1= enabled) + unsigned unused : 1; // @30 Unused + unsigned IntPending : 1; // @31 Timer Interrupt flag (Read-Only) + }; + uint32_t Raw32; // Union to access all 32 bits as a uint32_t +} local_timer_ctrl_status_reg_t; + +/*--------------------------------------------------------------------------} +{ LOCAL TIMER CLEAR AND RELOAD REGISTER - QA7_rev3.4.pdf page 18 } +{--------------------------------------------------------------------------*/ +typedef union +{ + struct + { + unsigned unused : 30; // @0-29 unused + unsigned Reload : 1; // @30 Local timer-reloaded when written as 1 + unsigned IntClear : 1; // @31 Interrupt flag clear when written as 1 + }; + uint32_t Raw32; // Union to access all 32 bits as a uint32_t +} local_timer_clr_reload_reg_t; + +/*--------------------------------------------------------------------------} +{ GENERIC TIMER INTERRUPT CONTROL REGISTER - QA7_rev3.4.pdf page 13 } +{--------------------------------------------------------------------------*/ +typedef union +{ + struct + { + unsigned nCNTPSIRQ_IRQ : 1; // @0 Secure physical timer event IRQ enabled, This bit is only valid if bit 4 is clear otherwise it is ignored. + unsigned nCNTPNSIRQ_IRQ : 1; // @1 Non-secure physical timer event IRQ enabled, This bit is only valid if bit 5 is clear otherwise it is ignored + unsigned nCNTHPIRQ_IRQ : 1; // @2 Hypervisor physical timer event IRQ enabled, This bit is only valid if bit 6 is clear otherwise it is ignored + unsigned nCNTVIRQ_IRQ : 1; // @3 Virtual physical timer event IRQ enabled, This bit is only valid if bit 7 is clear otherwise it is ignored + unsigned nCNTPSIRQ_FIQ : 1; // @4 Secure physical timer event FIQ enabled, If set, this bit overrides the IRQ bit (0) + unsigned nCNTPNSIRQ_FIQ : 1; // @5 Non-secure physical timer event FIQ enabled, If set, this bit overrides the IRQ bit (1) + unsigned nCNTHPIRQ_FIQ : 1; // @6 Hypervisor physical timer event FIQ enabled, If set, this bit overrides the IRQ bit (2) + unsigned nCNTVIRQ_FIQ : 1; // @7 Virtual physical timer event FIQ enabled, If set, this bit overrides the IRQ bit (3) + unsigned reserved : 24; // @8-31 reserved + }; + uint32_t Raw32; // Union to access all 32 bits as a uint32_t +} generic_timer_int_ctrl_reg_t; + +struct __attribute__((__packed__, aligned(4))) QA7Registers { + local_timer_int_route_reg_t TimerRouting; // 0x24 + uint32_t GPIORouting; // 0x28 + uint32_t AXIOutstandingCounters; // 0x2C + uint32_t AXIOutstandingIrq; // 0x30 + local_timer_ctrl_status_reg_t TimerControlStatus; // 0x34 + local_timer_clr_reload_reg_t TimerClearReload; // 0x38 + uint32_t unused; // 0x3C + generic_timer_int_ctrl_reg_t Core0TimerIntControl; // 0x40 + generic_timer_int_ctrl_reg_t Core1TimerIntControl; // 0x44 + generic_timer_int_ctrl_reg_t Core2TimerIntControl; // 0x48 + generic_timer_int_ctrl_reg_t Core3TimerIntControl; // 0x4C +}; +#define QA7 ((volatile __attribute__((aligned(4))) struct QA7Registers*)(uintptr_t)(0x40000040)) +//40000040 + +int enable_timer(void); +#endif //RPI_MMU_EXAMPLE_INTERRUPTS_H @@ -1,6 +1,7 @@ #include "uart.h" #include "demo_functionality.h" #include "paging.h" +#include "interrupts.h" void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) { @@ -21,6 +22,10 @@ void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) // prints some info demo_paging_support(); + + + // prints some info and switches to system mode + demo_mode_to_system(); // prints some info demo_current_mode(); @@ -30,13 +35,30 @@ void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) demo_setup_libkernel(); demo_setup_PL0(); + enable_timer(); + // enable interrupts demo_setup_interrupts(); - - // prints some info and sets up a section for PL0 code, loads a blob + + *(int *)(0x3000B210) = 1; + *(int *)(0x3000B204) = 1; + + + asm("LDR r0, =0x3F00B200\n\r" + "MOV r1, #2\n\r" + "STR r1, [r0, #0x00]\n\r"); + + *(int *)(0x7E00B210) = 1; + *(int *)(0x7E00B214) = 1; + *(int *)(0x7E00B218) = 1; + uart_putc(*(int*)(0x40000034) ); + *(int *)(0x40000034) = 1; + + + // prints some info and sets up a section for PL0 code, loads a blob // there and jumps to it... never, ever, ever returns demo_go_unprivileged(); - + while(1); while (1) @@ -1,17 +1,13 @@ #ifndef MEMORY_H #define MEMORY_H -#include "paging.h" - -#define SECTION_SIZE (((uint32_t) 1) << 20) - #define INTERRUPT_VECTOR_TABLE_START ((uint32_t) 0x0) #define STACK_START ((uint32_t) 0x4000) #define STACK_END ((uint32_t) 0x8000) -extern const char __end; -extern const char __start; +extern char __end; +extern char __start; #define KERNEL_START ((uint32_t) &__start) #define KERNEL_END ((uint32_t) &__end) @@ -24,21 +20,11 @@ extern const char __start; #define TRANSLATION_TABLE_END \ (TRANSLATION_TABLE_BASE + (uint32_t) (4096 * 4)) -#define LIBKERNEL_SECTION_START \ - (((TRANSLATION_TABLE_END - (uint32_t) 1) & ~((uint32_t) 0xfffff)) \ - + SECTION_SIZE) - -#define LIBKERNEL_SECTION_END \ - (LIBKERNEL_SECTION_START + SECTION_SIZE) +#define PRIVILEGED_MEMORY_END TRANSLATION_TABLE_END -// section for libkernel is flat-mapped -#define LIBKERNEL_SECTION_NUMBER (LIBKERNEL_SECTION_START >> 20) - -#define PRIVILEGED_MEMORY_END LIBKERNEL_SECTION_END - -#define UNPRIVILEGED_MEMORY_START PRIVILEGED_MEMORY_END -#define UNPRIVILEGED_MEMORY_END \ - (UNPRIVILEGED_MEMORY_START + SECTION_SIZE) +#define UNPRIVILEGED_MEMORY_START \ + (((PRIVILEGED_MEMORY_END - (uint32_t) 1) & ~((uint32_t) 0xfffff)) \ + + (uint32_t) 0x100000) #define PL0_SECTION_NUMBER ((uint32_t) 0b101010101010) #define PL0_SECTION_NUMBER_STR "0b101010101010" @@ -46,4 +32,4 @@ extern const char __start; #define VIRTUAL_PL0_MEMORY_START (PL0_SECTION_NUMBER << 20) #endif // MEMORY_H - + |