From b26d2337f46aace9f735794dfdec3fdf22f55606 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 17 Dec 2019 17:03:26 +0100 Subject: add missing newline in output --- demo_functionality.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo_functionality.c b/demo_functionality.c index 3375550..19a5c38 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -140,7 +140,7 @@ void demo_setup_PL0(void) ((volatile char*) VIRTUAL_PL0_MEMORY_START)[i] = (&_binary_PL_0_test_img_start)[i]; - uart_puts("copied PL0 and libkernel code to their sections"); + uart_puts("copied PL0 and libkernel code to their sections\n\r"); } void demo_go_unprivileged(void) -- cgit v1.2.3 From 2d91eebbf1fc9335269207602b360ec485aaf7bb Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 17 Dec 2019 17:39:03 +0100 Subject: don't embed stage2 of bootloader as binary blob - use smart section naming --- Makefile | 11 ++++----- loader_linker.ld | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ loader_stage1.c | 21 +++++++++-------- loader_stage1.ld | 56 --------------------------------------------- loader_stage2.c | 2 -- loader_stage2.ld | 44 ----------------------------------- 6 files changed, 85 insertions(+), 119 deletions(-) create mode 100644 loader_linker.ld delete mode 100644 loader_stage1.ld delete mode 100644 loader_stage2.ld diff --git a/Makefile b/Makefile index d1d66fa..35cc48c 100644 --- a/Makefile +++ b/Makefile @@ -30,17 +30,14 @@ PL_0_test.elf : PL0_test.o uart.o kernel.elf : boot.o kernel.o uart.o PL_0_test_embeddable.o demo_functionality.o paging.o libkernel_renamed.o interrupt_vector.o interrupts.o arm-none-eabi-gcc -T linker.ld -o $@ $(ELFFLAGS) $^ -loader_stage2.elf : loader_stage2.o uart.o - arm-none-eabi-gcc -T loader_stage2.ld -o $@ $(ELFFLAGS) $^ +loader.elf : boot.o loader_stage1.o loader_stage2.o uart.o + arm-none-eabi-gcc -T loader_linker.ld -o $@ $(ELFFLAGS) $^ -loader_stage2.img : loader_stage2.elf +loader.img : loader.elf arm-none-eabi-objcopy $^ -O binary $@ +# check if the resulting image is not too big test -n "$$(find $@ -size -16384c)" || exit -1 -loader.elf : boot.o loader_stage1.o loader_stage2_embeddable.o - arm-none-eabi-gcc -T loader_stage1.ld -o $@ $(ELFFLAGS) $^ - - qemu-elf : kernel.elf qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $^ diff --git a/loader_linker.ld b/loader_linker.ld new file mode 100644 index 0000000..a8942f6 --- /dev/null +++ b/loader_linker.ld @@ -0,0 +1,70 @@ +ENTRY(_start) + +SECTIONS +{ + /* Starts at LOADER_ADDR. */ + /* Warning! Internet says RPis in 32-bit mode load binary at 0x8000! */ + /* My experiments do, however, show, that qemu emulating RPi2 */ + /* loads it at 0x10000! (took some pain to find out) */ + + /* . = 0x10000; */ + + /* rpi-open-firmware, on the other hand, loads it at 0x2000000 */ + /* (and this should be not-so-hard to change by modifying the */ + /* firmware) */ + + . = 0x2000000; + + /* For AArch64, use . = 0x80000; Unless this too is wrong */ + + __start = .; + __text_stage1_start = .; + .text_stage1 : + { + KEEP(*(.text.boot)) + *(.text.boot) + *(.text.stage1main) + } + . = ALIGN(4096); /* align to page size */ + __text_stage1_end = .; + + __stage2_start = .; + __text_start = .; + .text : + { + KEEP(*(.text.stage2main)) + *(.text.boot) + } + . = ALIGN(4096); /* align to page size */ + __text_end = .; + + __rodata_start = .; + .rodata : + { + *(.rodata) + } + . = ALIGN(4096); /* align to page size */ + __rodata_end = .; + + __data_start = .; + .data : + { + *(.data) + } + . = ALIGN(4096); /* align to page size */ + __data_end = .; + + __bss_start = .; + .bss : + { + bss = .; + *(.bss) + } + . = ALIGN(4096); /* align to page size */ + __bss_end = .; + __bss_size = __bss_end - __bss_start; + + __stage2_end = .; + __stage2_size = __stage2_end - __stage2_start; + __end = .; +} diff --git a/loader_stage1.c b/loader_stage1.c index d209c15..aca439c 100644 --- a/loader_stage1.c +++ b/loader_stage1.c @@ -2,24 +2,25 @@ #include #include -char *const stage2_addr = ((void*) 0x4000); +#define STAGE2_ADDR ((volatile char*) 0x4000) -// there's one tricky thing about embedding file in executable; -// mainly, symbols are visible to c code as extern chars, but the actual +// There's one tricky thing about managing executable's own code. +// Mainly, symbols are visible to c code as extern chars, but the actual // values are their adresses... see the code below extern char - _binary_loader_stage2_img_start, - _binary_loader_stage2_img_end, - _binary_loader_stage2_img_size; + __stage2_start, + __stage2_end, + __stage2_size; +__attribute__((section(".text.stage1main"))) void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) { - // stage2 of the bootloader is a blob embedded in executable; + // stage2 of the bootloader is part of executable; // copy it over to it's destination place // TODO implement a memcpy() somewhere and use it instead of loops - for (size_t i = 0; i < (size_t) &_binary_loader_stage2_img_size; i++) - stage2_addr[i] = (&_binary_loader_stage2_img_start)[i]; + for (size_t i = 0; i < (size_t) &__stage2_size; i++) + STAGE2_ADDR[i] = (&__stage2_start)[i]; // jump to stage2 - ((void(*)(uint32_t, uint32_t, uint32_t))stage2_addr)(r0, r1, atags); + ((void(*)(uint32_t, uint32_t, uint32_t))STAGE2_ADDR)(r0, r1, atags); } diff --git a/loader_stage1.ld b/loader_stage1.ld deleted file mode 100644 index 18fe477..0000000 --- a/loader_stage1.ld +++ /dev/null @@ -1,56 +0,0 @@ -ENTRY(_start) - -SECTIONS -{ - /* Starts at LOADER_ADDR. */ - /* Warning! Internet says RPis in 32-bit mode load binary at 0x8000! */ - /* My experiments do, however, show, that qemu emulating RPi2 */ - /* loads it at 0x10000! (took some pain to find out) */ - - /* . = 0x10000; */ - - /* rpi-open-firmware, on the other hand, loads it at 0x2000000 */ - /* (and this should be not-so-hard to change by modifying the */ - /* firmware) */ - - . = 0x2000000; - - /* For AArch64, use . = 0x80000; Unless this too is wrong */ - - __start = .; - __text_start = .; - .text : - { - KEEP(*(.text.boot)) - *(.text) - } - . = ALIGN(4096); /* align to page size */ - __text_end = .; - - __rodata_start = .; - .rodata : - { - *(.rodata) - } - . = ALIGN(4096); /* align to page size */ - __rodata_end = .; - - __data_start = .; - .data : - { - *(.data) - } - . = ALIGN(4096); /* align to page size */ - __data_end = .; - - __bss_start = .; - .bss : - { - bss = .; - *(.bss) - } - . = ALIGN(4096); /* align to page size */ - __bss_end = .; - __bss_size = __bss_end - __bss_start; - __end = .; -} diff --git a/loader_stage2.c b/loader_stage2.c index e221dda..7b5087a 100644 --- a/loader_stage2.c +++ b/loader_stage2.c @@ -36,5 +36,3 @@ stage2(uint32_t r0, uint32_t r1, uint32_t atags) asm volatile("bx %0" :: "r" (kernel_load_addr) : "memory"); } -void *const _start = ((void*) stage2); // for linker script - diff --git a/loader_stage2.ld b/loader_stage2.ld deleted file mode 100644 index 8f215e9..0000000 --- a/loader_stage2.ld +++ /dev/null @@ -1,44 +0,0 @@ -ENTRY(_start) - -SECTIONS -{ - /* stage2 bootloader gets loaded at 0x4000 */ - . = 0x4000; - __start = .; - __text_start = .; - .text : - { - /* have entry point at the beginning */ - KEEP(*(.text.stage2main)) - *(.text) - } - . = ALIGN(4096); /* align to page size */ - __text_end = .; - - __rodata_start = .; - .rodata : - { - *(.rodata) - } - . = ALIGN(4096); /* align to page size */ - __rodata_end = .; - - __data_start = .; - .data : - { - *(.data) - } - . = ALIGN(4096); /* align to page size */ - __data_end = .; - - __bss_start = .; - .bss : - { - bss = .; - *(.bss) - } - . = ALIGN(4096); /* align to page size */ - __bss_end = .; - __bss_size = __bss_end - __bss_start; - __end = .; -} -- cgit v1.2.3 From 4c110d2802742fe1d37ba7280f374174fc45cbe1 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 24 Dec 2019 22:43:07 +0100 Subject: simplify linking of libkernel --- Makefile | 7 +----- demo_functionality.c | 12 +++++----- linker.ld | 63 +++++++++++++++------------------------------------- 3 files changed, 25 insertions(+), 57 deletions(-) diff --git a/Makefile b/Makefile index 35cc48c..d782eda 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,6 @@ ARM_OBJECTS=kernel.o paging.o demo_functionality.o PL0_test.o uart.o loader_stag EMBEDDABLE_OBJECTS=PL_0_test_embeddable.o loader_stage2_embeddable.o -RENAME_FLAGS=--rename-section .data=.renamed_data --rename-section .rodata=.renamed_rodata --rename-section .text=.renamed_text --rename-section .bss=.renamed_bss - all : kernel7.img %.o : %.c @@ -21,13 +19,10 @@ all : kernel7.img %_embeddable.o : %.img arm-none-eabi-objcopy -I binary -O elf32-littlearm -B arm --rename-section .data=.rodata $^ $@ -libkernel_renamed.o : libkernel.o - arm-none-eabi-objcopy $(RENAME_FLAGS) $^ $@ - PL_0_test.elf : PL0_test.o uart.o arm-none-eabi-gcc -T PL0_test.ld -o $@ $(ELFFLAGS) $^ -kernel.elf : boot.o kernel.o uart.o PL_0_test_embeddable.o demo_functionality.o paging.o libkernel_renamed.o interrupt_vector.o interrupts.o +kernel.elf : boot.o kernel.o uart.o PL_0_test_embeddable.o demo_functionality.o paging.o libkernel.o interrupt_vector.o interrupts.o arm-none-eabi-gcc -T linker.ld -o $@ $(ELFFLAGS) $^ loader.elf : boot.o loader_stage1.o loader_stage2.o uart.o diff --git a/demo_functionality.c b/demo_functionality.c index 19a5c38..aedab08 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -57,9 +57,9 @@ void demo_current_mode(void) ((short_section_descriptor_t volatile*) TRANSLATION_TABLE_BASE) extern char - __renamed_start, - __renamed_end, - __renamed_size; + __libkernel_start, + __libkernel_end, + __libkernel_size; void demo_setup_libkernel(void) { short_section_descriptor_t volatile *libkernel_section_entry = @@ -82,9 +82,9 @@ void demo_setup_libkernel(void) { "isb" :: "r" (0) : "memory"); // copy libkernel code to libkernel section - for (size_t i = 0; i < (size_t) &__renamed_size; i++) + for (size_t i = 0; i < (size_t) &__libkernel_size; i++) ((volatile char*) LIBKERNEL_SECTION_START)[i] = - (&__renamed_start)[i]; + (&__libkernel_start)[i]; } extern char @@ -146,7 +146,7 @@ void demo_setup_PL0(void) void demo_go_unprivileged(void) { size_t call_unprivileged_offset = - (size_t) &call_unprivileged - (size_t) &__renamed_start; + (size_t) &call_unprivileged - (size_t) &__libkernel_start; void *call_unprivileged_new_location = (void*) (LIBKERNEL_SECTION_START + call_unprivileged_offset); diff --git a/linker.ld b/linker.ld index 01eda35..387e7c7 100644 --- a/linker.ld +++ b/linker.ld @@ -1,18 +1,21 @@ -ENTRY(_start) +ENTRY(_start) /* defined in boot.S */ SECTIONS { - /* Starts at LOADER_ADDR, which is 0x8000 - that's where RPis in */ - /* 32-bit mode load kernel at. */ + /* Starts at 0x8000 - that's where RPis in 32-bit mode load kernel at. */ /* My experiments do, however, show, that qemu emulating RPi2 */ /* loads the kernel at 0x10000! (took some pain to find out). */ - /* Since we're using a bootloader now, we can compile the kernel */ - /* for 0x8000 and bootloader will load it properly (although it */ - /* itself still has to be compiled for 0x10000) */ - /* rpi-open-firmware, ont he other hand, loads kernel at 0x2000000 */ - /* This issue is also to be avoided by the use of bootloader */ + /* rpi-open-firmware, on the other hand, loads kernel at 0x2000000! */ + /* This is not really a problem, since: */ + /* 1. We can use out bootloader to load the kernel at 0x8000 */ + /* 2. We compile kernel with -fPIC, so it should be able to work with */ + /* any load addr. + /* 3. In qemu, we can load kernel.elf instead of raw binary */ + /* (qemu will do the loading then) */ + . = 0x8000; - /* For AArch64, use . = 0x80000; Unless this too is wrong in qemu… */ + + /* For AArch64, use . = 0x80000 */ __start = .; __text_start = .; @@ -51,44 +54,14 @@ SECTIONS __bss_size = __bss_end - __bss_start; - - /* Here come the definitions for renamed sections */ - __renamed_start = .; - __renamed_text_start = .; - .renamed_text : - { - *(.renamed_text) - } - . = ALIGN(4096); /* align to page size */ - __renamed_text_end = .; - - __renamed_rodata_start = .; - .renamed_rodata : - { - *(.renamed_rodata) - } - . = ALIGN(4096); /* align to page size */ - __renamed_rodata_end = .; - - __renamed_data_start = .; - .renamed_data : - { - *(.renamed_data) - } - . = ALIGN(4096); /* align to page size */ - __renamed_data_end = .; - - __renamed_bss_start = .; - .renamed_bss : + /* libkernel */ + .libkernel : { - renamed_bss = .; - *(.renamed_bss) + __libkernel_start = .; + libkernel.o + __libkernel_end = .; } - . = ALIGN(4096); /* align to page size */ - __renamed_bss_end = .; - __renamed_bss_size = __renamed_bss_end - __renamed_bss_start; - __renamed_end = .; - __renamed_size = __renamed_end - __renamed_start; + __libkernel_size = __libkernel_end - __libkernel_start; . = ALIGN(4096); /* align to page size */ -- cgit v1.2.3 From 32ab77e291eca37677c416ca69fe3fd93e224464 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 26 Dec 2019 17:21:03 +0100 Subject: add gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..db6eb43 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*.elf +*.img +pipe_image -- cgit v1.2.3 From 6a5684927d5a6d201b407ff30340307fe9813677 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 26 Dec 2019 17:55:15 +0100 Subject: fix linking of libkernel --- linker.ld | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linker.ld b/linker.ld index 387e7c7..60387bf 100644 --- a/linker.ld +++ b/linker.ld @@ -22,7 +22,7 @@ SECTIONS .text : { KEEP(*(.text.boot)) - *(.text) + *(EXCLUDE_FILE (libkernel.o) .text) } . = ALIGN(4096); /* align to page size */ __text_end = .; @@ -30,7 +30,7 @@ SECTIONS __rodata_start = .; .rodata : { - *(.rodata) + *(EXCLUDE_FILE (libkernel.o) .rodata) } . = ALIGN(4096); /* align to page size */ __rodata_end = .; @@ -38,7 +38,7 @@ SECTIONS __data_start = .; .data : { - *(.data) + *(EXCLUDE_FILE (libkernel.o) .data) } . = ALIGN(4096); /* align to page size */ __data_end = .; @@ -47,7 +47,7 @@ SECTIONS .bss : { bss = .; - *(.bss) + *(EXCLUDE_FILE (libkernel.o) .bss) } . = ALIGN(4096); /* align to page size */ __bss_end = .; -- cgit v1.2.3 From 93a1c704c99a48803d118f66ac4fe08510fb4b89 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 26 Dec 2019 18:21:29 +0100 Subject: simplify linker script; rely on initially-zero memory to be included in binary image (no bss zeroing in assembly code) --- boot.S | 20 +------------------- linker.ld | 36 +++++++----------------------------- 2 files changed, 8 insertions(+), 48 deletions(-) diff --git a/boot.S b/boot.S index 5e510f8..a792c94 100644 --- a/boot.S +++ b/boot.S @@ -1,7 +1,7 @@ // armv7 mode // To keep this in the first portion of the binary. -.section ".text.boot" +.section ".boot" //.org 0x8000 @@ -30,24 +30,6 @@ _start: ldr r5, =__start mov sp, r5 - // Clear out bss. - ldr r4, =__bss_start - ldr r9, =__bss_end - mov r5, #0 - mov r6, #0 - mov r7, #0 - mov r8, #0 - b 2f - -1: - // store multiple at r4. - stmia r4!, {r5-r8} - - // If we are still below bss_end, loop. -2: - cmp r4, r9 - blo 1b - // Call kernel_main ldr r3, =kernel_main bx r3 diff --git a/linker.ld b/linker.ld index 60387bf..ed40054 100644 --- a/linker.ld +++ b/linker.ld @@ -18,40 +18,18 @@ SECTIONS /* For AArch64, use . = 0x80000 */ __start = .; - __text_start = .; - .text : + .boot : { - KEEP(*(.text.boot)) - *(EXCLUDE_FILE (libkernel.o) .text) + boot.o } - . = ALIGN(4096); /* align to page size */ - __text_end = .; - - __rodata_start = .; - .rodata : - { - *(EXCLUDE_FILE (libkernel.o) .rodata) - } - . = ALIGN(4096); /* align to page size */ - __rodata_end = .; - - __data_start = .; - .data : - { - *(EXCLUDE_FILE (libkernel.o) .data) - } - . = ALIGN(4096); /* align to page size */ - __data_end = .; - - __bss_start = .; - .bss : + __kernel_start = .; + .kernel : { - bss = .; - *(EXCLUDE_FILE (libkernel.o) .bss) + *(EXCLUDE_FILE (libkernel.o interrupt_vector.o interrupts.o) *) } . = ALIGN(4096); /* align to page size */ - __bss_end = .; - __bss_size = __bss_end - __bss_start; + __kernel_end = .; + __kernel_size = __kernel_end - __kernel_start; /* libkernel */ -- cgit v1.2.3 From 9d587f9f750253461314757f2f861c5214563120 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 26 Dec 2019 18:48:38 +0100 Subject: improve linking of interrupts --- demo_functionality.c | 10 +++++----- interrupt_vector.S | 4 +++- interrupts.c | 9 ++++++--- linker.ld | 18 +++++++++--------- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/demo_functionality.c b/demo_functionality.c index aedab08..c6f7e5c 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -164,9 +164,9 @@ void demo_go_unprivileged(void) } extern char - __interrupt_vectors_start, - __interrupt_vectors_end, - __interrupt_vectors_size; + __interrupts_start, + __interrupts_end, + __interrupts_size; extern void (*volatile system_reentry_point)(void); @@ -180,7 +180,7 @@ void demo_setup_interrupts(void) { system_reentry_point = system_reentry; - for (size_t i = 0; i < (size_t) &__interrupt_vectors_size; i++) + for (size_t i = 0; i < (size_t) &__interrupts_size; i++) ((volatile char*) 0)[i] = - (&__interrupt_vectors_start)[i]; + (&__interrupts_start)[i]; } diff --git a/interrupt_vector.S b/interrupt_vector.S index f71330b..d20bf6d 100644 --- a/interrupt_vector.S +++ b/interrupt_vector.S @@ -1,4 +1,4 @@ -.section ".interrupt_vectors.text" +.section ".interrupts.vector" .global abort_handler .local generic_handler @@ -12,6 +12,8 @@ _interrupt_vectors: b generic_handler b generic_handler +.section ".interrupts.text" + generic_handler: b generic_handler abort_handler_caller: diff --git a/interrupts.c b/interrupts.c index 191ce40..6952f89 100644 --- a/interrupts.c +++ b/interrupts.c @@ -5,7 +5,10 @@ If an undefined instruction is encountered, the CPU will start executing this function. Just trap here as a debug solution. */ -void __attribute__((interrupt("UNDEF"))) undefined_instruction_vector(void) +void +__attribute__((interrupt("UNDEF"))) +__attribute__((section(".interrupts.text"))) +undefined_instruction_vector(void) { uart_puts("Undefined instruction occured"); while( 1 ) @@ -14,12 +17,12 @@ void __attribute__((interrupt("UNDEF"))) undefined_instruction_vector(void) } } -void __attribute__((section(".interrupt_vectors.data"))) +void __attribute__((section(".interrupts.data"))) (*system_reentry_point) (void); void __attribute__((interrupt("ABORT"))) -__attribute__((section(".interrupt_vectors.text"))) +__attribute__((section(".interrupts.text"))) abort_handler(void) { system_reentry_point(); diff --git a/linker.ld b/linker.ld index ed40054..5bdbfd2 100644 --- a/linker.ld +++ b/linker.ld @@ -42,17 +42,17 @@ SECTIONS __libkernel_size = __libkernel_end - __libkernel_start; - . = ALIGN(4096); /* align to page size */ - __interrupt_vectors_start = .; - .interrupt_vectors : + + .interrupts : { - interrupt_vectors = .; - *(.interrupt_vectors.text) - *(.interrupt_vectors.data) + __interrupts_start = .; + KEEP(*(.interrupts.vector)) + interrupt_vector.o + interrupts.o + __interrupts_end = .; } - . = ALIGN(4096); /* align to page size */ - __interrupt_vectors_end = .; - __interrupt_vectors_size = __interrupt_vectors_end - __interrupt_vectors_start; + + __interrupts_size = __interrupts_end - __interrupts_start; __end = .; } -- cgit v1.2.3 From 4d3cd9bd400b3d07d752d60ce2b3c425a53b72d6 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 26 Dec 2019 19:02:32 +0100 Subject: improve linking of initial boot code --- boot.S | 12 +++--------- linker.ld | 14 +++++--------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/boot.S b/boot.S index a792c94..ae56387 100644 --- a/boot.S +++ b/boot.S @@ -1,20 +1,14 @@ // armv7 mode -// To keep this in the first portion of the binary. -.section ".boot" - -//.org 0x8000 - -// Make _start global. -.globl _start - // Entry point for the kernel. // r15 -> should begin execution at 0x8000. // r0 -> 0x00000000 // r1 -> 0x00000C42 // r2 -> 0x00000100 - start of ATAGS // preserve these registers as argument for kernel_main -_start: + +.globl _boot // make entry point label global +_boot: // Shut off extra cores mrc p15, 0, r5, c0, c0, 5 and r5, r5, #3 diff --git a/linker.ld b/linker.ld index 5bdbfd2..a0ad1ae 100644 --- a/linker.ld +++ b/linker.ld @@ -1,4 +1,4 @@ -ENTRY(_start) /* defined in boot.S */ +ENTRY(_boot) /* defined in boot.S; qemu needs it to run elf file */ SECTIONS { @@ -15,20 +15,16 @@ SECTIONS . = 0x8000; - /* For AArch64, use . = 0x80000 */ + /* RPi in 64-bit mode uses address 0x80000 instead */ __start = .; - .boot : - { - boot.o - } - __kernel_start = .; .kernel : { + __kernel_start = .; + KEEP(boot.o) *(EXCLUDE_FILE (libkernel.o interrupt_vector.o interrupts.o) *) + __kernel_end = .; } - . = ALIGN(4096); /* align to page size */ - __kernel_end = .; __kernel_size = __kernel_end - __kernel_start; -- cgit v1.2.3 From d9ac897bd8aa7a8b6471bca1eb8a2bd314fdb133 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 26 Dec 2019 19:06:18 +0100 Subject: minor changes (comments, whitespace) --- linker.ld | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/linker.ld b/linker.ld index a0ad1ae..33ac68c 100644 --- a/linker.ld +++ b/linker.ld @@ -2,16 +2,17 @@ ENTRY(_boot) /* defined in boot.S; qemu needs it to run elf file */ SECTIONS { - /* Starts at 0x8000 - that's where RPis in 32-bit mode load kernel at. */ - /* My experiments do, however, show, that qemu emulating RPi2 */ - /* loads the kernel at 0x10000! (took some pain to find out). */ - /* rpi-open-firmware, on the other hand, loads kernel at 0x2000000! */ + /* Starts at 0x8000 - that's where RPis in 32-bit mode load */ + /* kernel at. My experiments do, however, show, that qemu */ + /* emulating RPi2 loads the kernel at 0x10000! (took some pain */ + /* to find out). rpi-open-firmware, on the other hand, loads */ + /* kernel at 0x2000000! */ /* This is not really a problem, since: */ - /* 1. We can use out bootloader to load the kernel at 0x8000 */ - /* 2. We compile kernel with -fPIC, so it should be able to work with */ - /* any load addr. + /* 1. We can use our bootloader to load the kernel at 0x8000 */ + /* 2. We compile kernel with -fPIC, so it should be able to */ + /* work with any load addr. */ /* 3. In qemu, we can load kernel.elf instead of raw binary */ - /* (qemu will do the loading then) */ + /* (qemu will do the right thing then) */ . = 0x8000; @@ -38,7 +39,6 @@ SECTIONS __libkernel_size = __libkernel_end - __libkernel_start; - .interrupts : { __interrupts_start = .; @@ -47,7 +47,6 @@ SECTIONS interrupts.o __interrupts_end = .; } - __interrupts_size = __interrupts_end - __interrupts_start; __end = .; -- cgit v1.2.3 From 31806d249fe6e57efee0531bb082f836e5b35a3d Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 26 Dec 2019 19:15:08 +0100 Subject: remove halt loop (not really needed + we want to get rid of pieces of code copy-pasted from wiki osdev) --- boot.S | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/boot.S b/boot.S index ae56387..be858ee 100644 --- a/boot.S +++ b/boot.S @@ -13,8 +13,12 @@ _boot: mrc p15, 0, r5, c0, c0, 5 and r5, r5, #3 cmp r5, #0 - bne halt + beq proceed + // this is a kind of blef - races can theoretically still occur + // when the main core overwrites this part of memory + wfe +proceed: // go to system mode cps #0b11111 isb @@ -27,8 +31,3 @@ _boot: // Call kernel_main ldr r3, =kernel_main bx r3 - - // halt -halt: - wfe - b halt -- cgit v1.2.3 From 19efd77944dd42c3451a19e60a6948a52bc9ccad Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 26 Dec 2019 19:22:24 +0100 Subject: minor changes to boot code --- boot.S | 18 ++++++++---------- linker.ld | 2 ++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/boot.S b/boot.S index be858ee..0cd0339 100644 --- a/boot.S +++ b/boot.S @@ -7,26 +7,24 @@ // r2 -> 0x00000100 - start of ATAGS // preserve these registers as argument for kernel_main -.globl _boot // make entry point label global +.global _boot // make entry point label global _boot: - // Shut off extra cores - mrc p15, 0, r5, c0, c0, 5 - and r5, r5, #3 - cmp r5, #0 + // Only let the first core execute + mrc p15, 0, r3, c0, c0, 5 + and r3, r3, #3 + cmp r3, #0 beq proceed // this is a kind of blef - races can theoretically still occur // when the main core overwrites this part of memory wfe proceed: - // go to system mode + // go to system mode (we had problems doing this later) cps #0b11111 isb - // Setup the stack. - // It shall be directly below our kernel image - ldr r5, =__start - mov sp, r5 + // Initialize the stack (_stack_top is defined in linker.ld) + ldr sp, =_stack_top // Call kernel_main ldr r3, =kernel_main diff --git a/linker.ld b/linker.ld index 33ac68c..e0e72b2 100644 --- a/linker.ld +++ b/linker.ld @@ -50,4 +50,6 @@ SECTIONS __interrupts_size = __interrupts_end - __interrupts_start; __end = .; + + _stack_top = __start; } -- cgit v1.2.3 From 6bdfd7c992b2345f964dc6bc5dbb4189e36a5e99 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 27 Dec 2019 22:09:21 +0100 Subject: add userspace tool for creating ramfs image --- .gitignore | 1 + Makefile | 3 +++ makefs.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 makefs.c diff --git a/.gitignore b/.gitignore index db6eb43..480597b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.elf *.img pipe_image +makefs diff --git a/Makefile b/Makefile index d782eda..3d6b095 100644 --- a/Makefile +++ b/Makefile @@ -46,6 +46,9 @@ run-on-rpi : kernel.img pipe_image pipe_image : pipe_image.c lib/rs232/rs232.c gcc -Wall -std=gnu99 -O3 $^ -o $@ +makefs : makefs.c + gcc -Wall -std=gnu99 -O3 $^ -o $@ + clean : -rm *.img *.elf *.o pipe_image diff --git a/makefs.c b/makefs.c new file mode 100644 index 0000000..7d5b148 --- /dev/null +++ b/makefs.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ANSI_FG_RED "\033[0;31m" +#define ANSI_FG_DEFAULT "\033[0;39m" + +int main(int argc, char **argv) +{ + for (int i = 1; i < argc; i++) + { + struct stat fileinfo; + + if (stat(argv[i], &fileinfo)) + err(-1, "couldn't stat " ANSI_FG_RED "%s" ANSI_FG_DEFAULT, + argv[i]); + + if (!S_ISREG(fileinfo.st_mode)) + errx(-1, ANSI_FG_RED "%s" ANSI_FG_DEFAULT + " is not a regular file.", argv[i]); + + if (fileinfo.st_size > UINT32_MAX) + errx(-1, ANSI_FG_RED "%s" ANSI_FG_DEFAULT + " is too big.", argv[i]); + + uint32_t file_size = fileinfo.st_size; + uint32_t name_size = strlen(argv[i]); + + if (fwrite(&name_size, 4, 1, stdout) != 1) + errx(-1, "error writing to stdout"); + + if (printf("%s", argv[i]) != name_size) + errx(-1, "error writing to stdout"); + + if (fwrite(&file_size, 4, 1, stdout) != 1) + errx(-1, "error writing to stdout"); + + if (fflush(stdout)) + err(-1, "couldn't flush stdout"); + + pid_t pid; + int wstatus; + switch (pid = fork()) + { + case -1: + err(-1, "couldn't fork"); + case 0: + if (execlp("cat", "cat", argv[i], NULL)) + err(-1, "couldn't execute cat"); + default: + if (wait(&wstatus) == -1) + err(-1, "error waiting for child"); + + if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) + exit(-1); + } + } + + return 0; +} + -- cgit v1.2.3 From 2f037d0ced1f9a357063667530931566e53e743c Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 27 Dec 2019 22:10:35 +0100 Subject: adjust bootloader's linker script use with newest version of boot.S --- loader_linker.ld | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/loader_linker.ld b/loader_linker.ld index a8942f6..45c88ff 100644 --- a/loader_linker.ld +++ b/loader_linker.ld @@ -1,4 +1,4 @@ -ENTRY(_start) +ENTRY(_boot) SECTIONS { @@ -67,4 +67,6 @@ SECTIONS __stage2_end = .; __stage2_size = __stage2_end - __stage2_start; __end = .; + + _stack_top = 0x4000; } -- cgit v1.2.3 From 6c6156c87c08ec06ccaf44ce391a8e25dbf77ea6 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 27 Dec 2019 22:30:53 +0100 Subject: make int values always 4-aligned in fs image --- makefs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/makefs.c b/makefs.c index 7d5b148..24d8f6c 100644 --- a/makefs.c +++ b/makefs.c @@ -38,6 +38,10 @@ int main(int argc, char **argv) if (printf("%s", argv[i]) != name_size) errx(-1, "error writing to stdout"); + for (int j = 0; (j + (name_size & 0b11)) & 0b11; j++) + if (putchar('\0')) + errx(-1, "error writing to stdout"); + if (fwrite(&file_size, 4, 1, stdout) != 1) errx(-1, "error writing to stdout"); @@ -60,6 +64,10 @@ int main(int argc, char **argv) if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) exit(-1); } + + for (int j = 0; (j + (file_size & 0b11)) & 0b11; j++) + if (putchar('\0')) + errx(-1, "error writing to stdout"); } return 0; -- cgit v1.2.3 From b2dd2b0507571399723b3fe74bb469bc7e24f8a0 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 12:13:22 +0100 Subject: another (hopefully last) change to our fs format - use C-style NULL-terminated strings instead of length-padded --- makefs.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/makefs.c b/makefs.c index 24d8f6c..31831a3 100644 --- a/makefs.c +++ b/makefs.c @@ -30,12 +30,9 @@ int main(int argc, char **argv) " is too big.", argv[i]); uint32_t file_size = fileinfo.st_size; - uint32_t name_size = strlen(argv[i]); + uint32_t name_size = strlen(argv[i]) + 1; - if (fwrite(&name_size, 4, 1, stdout) != 1) - errx(-1, "error writing to stdout"); - - if (printf("%s", argv[i]) != name_size) + if (fwrite(argv[i], 1, name_size, stdout) != name_size) errx(-1, "error writing to stdout"); for (int j = 0; (j + (name_size & 0b11)) & 0b11; j++) -- cgit v1.2.3 From 1168c080af2f2f901a08886b670228a05ce74b77 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 12:29:08 +0100 Subject: add comments in makefs.c --- makefs.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/makefs.c b/makefs.c index 31831a3..c122267 100644 --- a/makefs.c +++ b/makefs.c @@ -1,3 +1,12 @@ +// Take files given on stdin and make them into a ramfs image of our +// own, (stupid) simple format. +// In the format: for each file comes the null-terminated string +// with filename, then null-padding until a 4-aligned offset, then +// 4-byte little-endian size of the file and then the contents +// of the file and then another null-padding until a 4-aligned offset. +// Files encoded this way go one after another (so it's easy to add +// something at the end or at the beginning). + #include #include #include @@ -13,6 +22,7 @@ int main(int argc, char **argv) { + // process files in the order they are provided on the command line for (int i = 1; i < argc; i++) { struct stat fileinfo; @@ -25,26 +35,35 @@ int main(int argc, char **argv) errx(-1, ANSI_FG_RED "%s" ANSI_FG_DEFAULT " is not a regular file.", argv[i]); + // don't allow files with size so big, that it can't be encoded + // in a 4-byte unsigned int... In practice even smaller files + // won't fit on the rpi. if (fileinfo.st_size > UINT32_MAX) errx(-1, ANSI_FG_RED "%s" ANSI_FG_DEFAULT " is too big.", argv[i]); uint32_t file_size = fileinfo.st_size; - uint32_t name_size = strlen(argv[i]) + 1; + uint32_t name_size = strlen(argv[i]) + 1; // 1 for null-byte if (fwrite(argv[i], 1, name_size, stdout) != name_size) errx(-1, "error writing to stdout"); - for (int j = 0; (j + (name_size & 0b11)) & 0b11; j++) + // pad with null-bytes until a 4-aligned offset + for (unsigned int j = 0; (j + (name_size & 0b11)) & 0b11; j++) if (putchar('\0')) errx(-1, "error writing to stdout"); - + + // TODO convert file_size to little endian first (in case our + // host is be). if (fwrite(&file_size, 4, 1, stdout) != 1) errx(-1, "error writing to stdout"); + // flush b4 running cat, so that stuff we've written comes + // b4 the actual file contents in the output if (fflush(stdout)) err(-1, "couldn't flush stdout"); - + + // we don't copy the actual file ourselves - we run cat for that pid_t pid; int wstatus; switch (pid = fork()) @@ -62,9 +81,10 @@ int main(int argc, char **argv) exit(-1); } + // again, pad with null-bytes until a 4-aligned offset for (int j = 0; (j + (file_size & 0b11)) & 0b11; j++) if (putchar('\0')) - errx(-1, "error writing to stdout"); + errx(-1, "error writing to stdout"); } return 0; -- cgit v1.2.3 From 8b80b2a919012560b72405e3e34993b8ad35b82c Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 12:30:48 +0100 Subject: write the same null-padding loop a saner way --- makefs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/makefs.c b/makefs.c index c122267..90e731c 100644 --- a/makefs.c +++ b/makefs.c @@ -49,7 +49,7 @@ int main(int argc, char **argv) errx(-1, "error writing to stdout"); // pad with null-bytes until a 4-aligned offset - for (unsigned int j = 0; (j + (name_size & 0b11)) & 0b11; j++) + for (uint32_t j = 0; (j + name_size) & 0b11; j++) if (putchar('\0')) errx(-1, "error writing to stdout"); @@ -82,7 +82,7 @@ int main(int argc, char **argv) } // again, pad with null-bytes until a 4-aligned offset - for (int j = 0; (j + (file_size & 0b11)) & 0b11; j++) + for (uint32_t j = 0; (j + file_size) & 0b11; j++) if (putchar('\0')) errx(-1, "error writing to stdout"); } -- cgit v1.2.3 From 311ddd85042170f35736b9491ce952ee51e21db1 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 12:37:47 +0100 Subject: another hopefully last change to the format - add terminating null-byte at the end of the entire ramfs --- makefs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/makefs.c b/makefs.c index 90e731c..379e8c5 100644 --- a/makefs.c +++ b/makefs.c @@ -5,7 +5,9 @@ // 4-byte little-endian size of the file and then the contents // of the file and then another null-padding until a 4-aligned offset. // Files encoded this way go one after another (so it's easy to add -// something at the end or at the beginning). +// something at the beginning). +// At the and comes one null-byte (as if a file with empty name +// was there). #include #include @@ -87,6 +89,9 @@ int main(int argc, char **argv) errx(-1, "error writing to stdout"); } + if (putchar('\0')) + errx(-1, "error writing to stdout"); + return 0; } -- cgit v1.2.3 From 5b5ed23b44ae9eb845ebbac284e0b27822e45ed1 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 13:14:33 +0100 Subject: add ramfs driver --- ramfs.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ramfs.h | 16 ++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 ramfs.c create mode 100644 ramfs.h diff --git a/ramfs.c b/ramfs.c new file mode 100644 index 0000000..cc66b4c --- /dev/null +++ b/ramfs.c @@ -0,0 +1,65 @@ +// driver for the read-only ramfs +// see makefs.c for details + +#include +#include "ramfs.h" + +static int strcmp(char const *str1, char const *str2) +{ + while (1) + { + int c1 = (unsigned char) *str1, c2 = (unsigned char) *str2; + + if (!c1 && !c2) + return 0; + + if (c1 != c2) + return c1 - c2; + + str1++; str2++; + } +} + +static uint32_t strlen(char const *str1) +{ + uint32_t len = 0; + + while (str1[len]) + len++; + + return len; +} + +static inline char *align4(char *addr) +{ + return (char*) (((uint32_t) addr - 1) & ~0b11) + 4; +} + +int find_file(void *ramfs, char *filename, struct ramfile *buf) +{ + char *fs_file = ramfs; + + while (*fs_file) + { + uint32_t *fs_file_size = (uint32_t*) + align4(fs_file + strlen(fs_file) + 1); + + char *fs_file_contents = (char*) (fs_file_size + 1); + + if (!strcmp(fs_file, filename)) + { + buf->file_size = *fs_file_size; + + buf->file_name = fs_file; + + buf->file_contents = fs_file_contents; + + return 0; + } + + // move to the next file in ramfs + fs_file = align4(fs_file_contents + *fs_file_size); + } + + return -1; // reached end of ramfs; file not found +} diff --git a/ramfs.h b/ramfs.h new file mode 100644 index 0000000..cf45736 --- /dev/null +++ b/ramfs.h @@ -0,0 +1,16 @@ +#ifndef RAMFS_H +#define RAMFS_H + +struct ramfile +{ + char *file_name; + uint32_t file_size; + char *file_contents; +}; + +// search for file named filename in ramfs; +// If found - return 0 and fill buf fields with file's info. +// Otherwise return a non-zero value. +int find_file(void *ramfs, char *filename, struct ramfile *buf); + +#endif // RAMFS_H -- cgit v1.2.3 From 826d5b3ba04a8b830c8a92a6f69ca4e223257c5b Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 14:01:14 +0100 Subject: place PL_0_test.img in ramfs instead of embedding it directly --- Makefile | 7 ++++++- demo_functionality.c | 21 ++++++++++++++++----- linker.ld | 4 +++- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 3d6b095..b8800cc 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,8 @@ ARM_OBJECTS=kernel.o paging.o demo_functionality.o PL0_test.o uart.o loader_stag EMBEDDABLE_OBJECTS=PL_0_test_embeddable.o loader_stage2_embeddable.o +RAMFS_FILES=PL_0_test.img + all : kernel7.img %.o : %.c @@ -22,7 +24,7 @@ all : kernel7.img PL_0_test.elf : PL0_test.o uart.o arm-none-eabi-gcc -T PL0_test.ld -o $@ $(ELFFLAGS) $^ -kernel.elf : boot.o kernel.o uart.o PL_0_test_embeddable.o demo_functionality.o paging.o libkernel.o interrupt_vector.o interrupts.o +kernel.elf : boot.o kernel.o uart.o demo_functionality.o paging.o libkernel.o interrupt_vector.o interrupts.o ramfs_embeddable.o ramfs.o arm-none-eabi-gcc -T linker.ld -o $@ $(ELFFLAGS) $^ loader.elf : boot.o loader_stage1.o loader_stage2.o uart.o @@ -49,6 +51,9 @@ pipe_image : pipe_image.c lib/rs232/rs232.c makefs : makefs.c gcc -Wall -std=gnu99 -O3 $^ -o $@ +ramfs.img : makefs $(RAMFS_FILES) + ./makefs $(RAMFS_FILES) > $@ + clean : -rm *.img *.elf *.o pipe_image diff --git a/demo_functionality.c b/demo_functionality.c index c6f7e5c..206dd2b 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -3,6 +3,7 @@ #include "memory.h" #include "translation_table_descriptors.h" #include "libkernel.h" +#include "ramfs.h" void demo_paging_support(void) { @@ -88,12 +89,22 @@ void demo_setup_libkernel(void) { } extern char - _binary_PL_0_test_img_start, - _binary_PL_0_test_img_end, - _binary_PL_0_test_img_size; + _binary_ramfs_img_start, + _binary_ramfs_img_end, + _binary_ramfs_img_size; void demo_setup_PL0(void) { + // find PL_0_test.img im ramfs + struct ramfile PL_0_test_img; + + if (find_file(&_binary_ramfs_img_start, "PL_0_test.img", + &PL_0_test_img)) + { + uart_puts("PL_0_test.img not found :(\r\n"); + asm volatile ("wfi"); + } + short_section_descriptor_t volatile *PL0_section_entry = &TRANSLATION_TABLE[PL0_SECTION_NUMBER]; short_section_descriptor_t volatile *UART_memory_section_entry = @@ -136,9 +147,9 @@ void demo_setup_PL0(void) uart_puts((char*) VIRTUAL_PL0_MEMORY_START); // now paste a userspace program to that section - for (size_t i = 0; i < (size_t) &_binary_PL_0_test_img_size; i++) + for (uint32_t i = 0; i < PL_0_test_img.file_size; i++) ((volatile char*) VIRTUAL_PL0_MEMORY_START)[i] = - (&_binary_PL_0_test_img_start)[i]; + PL_0_test_img.file_contents[i]; uart_puts("copied PL0 and libkernel code to their sections\n\r"); } diff --git a/linker.ld b/linker.ld index e0e72b2..7b585dc 100644 --- a/linker.ld +++ b/linker.ld @@ -23,7 +23,9 @@ SECTIONS { __kernel_start = .; KEEP(boot.o) - *(EXCLUDE_FILE (libkernel.o interrupt_vector.o interrupts.o) *) + *(EXCLUDE_FILE (ramfs_embeddable.o libkernel.o interrupt_vector.o interrupts.o) *) + . = ALIGN(4); + ramfs_embeddable.o __kernel_end = .; } __kernel_size = __kernel_end - __kernel_start; -- cgit v1.2.3 From f8c683a73dee4a7215a0cac31b3007723d07187a Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 14:01:48 +0100 Subject: make uint32_to_bits() inline --- strings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings.h b/strings.h index 2ceade8..8d4b511 100644 --- a/strings.h +++ b/strings.h @@ -3,7 +3,7 @@ #include -void uint32_to_bits(uint32_t number, char *buf) +static inline void uint32_to_bits(uint32_t number, char *buf) { for (int i = 0; i < 32; i++) buf[i] = ((number >> (32 - i - 1)) & 1) ? '1' : '0'; -- cgit v1.2.3 From 7062b101197c03c7f4806d83b8d79cf34d3b6a42 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 14:51:27 +0100 Subject: remain in supervisor mode --- boot.S | 4 ---- 1 file changed, 4 deletions(-) diff --git a/boot.S b/boot.S index 0cd0339..593ed11 100644 --- a/boot.S +++ b/boot.S @@ -19,10 +19,6 @@ _boot: wfe proceed: - // go to system mode (we had problems doing this later) - cps #0b11111 - isb - // Initialize the stack (_stack_top is defined in linker.ld) ldr sp, =_stack_top -- cgit v1.2.3 From c374eaacbc0d16983bbd1112fefa74dbe88e1e53 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 15:55:29 +0100 Subject: use ldm instruction instead of libkernel for entering user mode; get rid of libkernel (no longer needed) --- Makefile | 2 +- demo_functionality.c | 69 +++++++++++++++++----------------------------------- kernel.c | 2 -- libkernel.c | 12 --------- libkernel.h | 6 ----- linker.ld | 11 --------- memory.h | 13 ++-------- psr.h | 15 ++++++++++++ 8 files changed, 40 insertions(+), 90 deletions(-) delete mode 100644 libkernel.c delete mode 100644 libkernel.h diff --git a/Makefile b/Makefile index b8800cc..55d0d1b 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ all : kernel7.img PL_0_test.elf : PL0_test.o uart.o arm-none-eabi-gcc -T PL0_test.ld -o $@ $(ELFFLAGS) $^ -kernel.elf : boot.o kernel.o uart.o demo_functionality.o paging.o libkernel.o interrupt_vector.o interrupts.o ramfs_embeddable.o ramfs.o +kernel.elf : boot.o kernel.o uart.o demo_functionality.o paging.o interrupt_vector.o interrupts.o ramfs_embeddable.o ramfs.o arm-none-eabi-gcc -T linker.ld -o $@ $(ELFFLAGS) $^ loader.elf : boot.o loader_stage1.o loader_stage2.o uart.o diff --git a/demo_functionality.c b/demo_functionality.c index 206dd2b..4b002d6 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" #include "ramfs.h" void demo_paging_support(void) @@ -57,37 +56,6 @@ void demo_current_mode(void) #define TRANSLATION_TABLE \ ((short_section_descriptor_t volatile*) TRANSLATION_TABLE_BASE) -extern char - __libkernel_start, - __libkernel_end, - __libkernel_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) &__libkernel_size; i++) - ((volatile char*) LIBKERNEL_SECTION_START)[i] = - (&__libkernel_start)[i]; -} - extern char _binary_ramfs_img_start, _binary_ramfs_img_end, @@ -151,27 +119,34 @@ void demo_setup_PL0(void) ((volatile char*) VIRTUAL_PL0_MEMORY_START)[i] = PL_0_test_img.file_contents[i]; - uart_puts("copied PL0 and libkernel code to their sections\n\r"); + uart_puts("copied PL0 code to it's section\n\r"); +} + +// needed for array initialization in demo_go_unprivileged() +void *memset(void *s, int c, size_t n) +{ + char *mem = s; + + for (size_t i = 0; i < n; i++) + mem[i] = c; + + return s; } void demo_go_unprivileged(void) { - size_t call_unprivileged_offset = - (size_t) &call_unprivileged - (size_t) &__libkernel_start; + uint32_t PL0_regs[16] = {0}; + PL0_regs[15] = VIRTUAL_PL0_MEMORY_START; // the new pc + PL0_regs[13] = (PL0_SECTION_NUMBER + 1) << 20; // the new sp + + PSR_t new_SPSR = read_CPSR(); + new_SPSR.fields.PSR_MODE_4_0 = MODE_USER; + write_SPSR(new_SPSR); - void *call_unprivileged_new_location = - (void*) (LIBKERNEL_SECTION_START + call_unprivileged_offset); + uart_puts("All ready, jumping to PL0 code\n\r"); - // 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"); + asm volatile("ldm %0, {r0 - r15} ^" :: + "r" (PL0_regs)); } extern char diff --git a/kernel.c b/kernel.c index fc629e1..9cdb82a 100644 --- a/kernel.c +++ b/kernel.c @@ -27,8 +27,6 @@ void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) // prints some info and sets upp translation table, turns on MMU setup_flat_map(); - demo_setup_libkernel(); - demo_setup_PL0(); demo_setup_interrupts(); diff --git a/libkernel.c b/libkernel.c deleted file mode 100644 index 0955e0e..0000000 --- a/libkernel.c +++ /dev/null @@ -1,12 +0,0 @@ -// This is the privileged code, that gets placed somewhere in -// unprivileged process' address space. It's compiled as relocatable, -// so it can be loaded at different address for different processes. - -void call_unprivileged(void (*address) (void)) { - // switch to PL0 - asm("cps #0b10000\n\r" - "isb" ::: "memory"); - - // jump to that unprivileged code - address(); -} diff --git a/libkernel.h b/libkernel.h deleted file mode 100644 index a8af348..0000000 --- a/libkernel.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef LIBKERNEL_H -#define LIBKERNEL_H - -void call_unprivileged(void (*address) (void)); - -#endif // LIBKERNEL_H diff --git a/linker.ld b/linker.ld index 7b585dc..673d7e2 100644 --- a/linker.ld +++ b/linker.ld @@ -30,17 +30,6 @@ SECTIONS } __kernel_size = __kernel_end - __kernel_start; - - /* libkernel */ - .libkernel : - { - __libkernel_start = .; - libkernel.o - __libkernel_end = .; - } - __libkernel_size = __libkernel_end - __libkernel_start; - - .interrupts : { __interrupts_start = .; diff --git a/memory.h b/memory.h index 1c9ae35..d369694 100644 --- a/memory.h +++ b/memory.h @@ -24,24 +24,15 @@ 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)) \ +#define PRIVILEGED_MEMORY_END \ + (((TRANSLATION_TABLE_END - (uint32_t) 1) & ~((uint32_t) 0xfffff)) \ + SECTION_SIZE) -#define LIBKERNEL_SECTION_END \ - (LIBKERNEL_SECTION_START + SECTION_SIZE) - -// 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 PL0_SECTION_NUMBER ((uint32_t) 0b101010101010) -#define PL0_SECTION_NUMBER_STR "0b101010101010" #define VIRTUAL_PL0_MEMORY_START (PL0_SECTION_NUMBER << 20) diff --git a/psr.h b/psr.h index 9809fc4..b2adafb 100644 --- a/psr.h +++ b/psr.h @@ -64,4 +64,19 @@ inline static PSR_t read_CPSR(void) return CPSR; } +inline static PSR_t read_SPSR(void) +{ + PSR_t SPSR; + // get content of saved program status register + asm("mrs %0, spsr" : "=r" (SPSR.raw) :: "memory"); + + return SPSR; +} + +inline static void write_SPSR(PSR_t SPSR) +{ + // set content of saved program status register + asm("msr spsr, %0" :: "r" (SPSR.raw)); +} + #endif // PSR_H -- cgit v1.2.3 From dea4cc9a00cd98f2749e9b658589a03addc6143b Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 16:46:08 +0100 Subject: clean-up memory.h --- memory.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/memory.h b/memory.h index d369694..e4493e2 100644 --- a/memory.h +++ b/memory.h @@ -1,9 +1,14 @@ #ifndef MEMORY_H #define MEMORY_H -#include "paging.h" +#define POWER_OF_2(EXP) (((uint32_t) 1) << EXP) -#define SECTION_SIZE (((uint32_t) 1) << 20) +#define ALIGN_POWER_OF_2(ADDR, EXP) \ + (((ADDR - 1) & ~(POWER_OF_2(EXP) - 1)) + POWER_OF_2(EXP)) + +#define SECTION_SIZE POWER_OF_2(20) + +#define ALIGN_SECTION(ADDR) ALIGN_POWER_OF_2(ADDR, 20) #define INTERRUPT_VECTOR_TABLE_START ((uint32_t) 0x0) @@ -13,26 +18,23 @@ extern const char __end; extern const char __start; -#define KERNEL_START ((uint32_t) &__start) +#define KERNEL_START ((uint32_t) &__start) // this is 0x8000 #define KERNEL_END ((uint32_t) &__end) // first 2^14 aligned address after the kernel -#define TRANSLATION_TABLE_BASE \ - (((KERNEL_END - (uint32_t) 1) & ~((uint32_t) 0x3fff)) \ - + (uint32_t) 0x4000) +#define TRANSLATION_TABLE_BASE ALIGN_POWER_OF_2(KERNEL_END, 14) #define TRANSLATION_TABLE_END \ (TRANSLATION_TABLE_BASE + (uint32_t) (4096 * 4)) -#define PRIVILEGED_MEMORY_END \ - (((TRANSLATION_TABLE_END - (uint32_t) 1) & ~((uint32_t) 0xfffff)) \ - + SECTION_SIZE) +#define PRIVILEGED_MEMORY_END ALIGN_SECTION(TRANSLATION_TABLE_END) #define UNPRIVILEGED_MEMORY_START PRIVILEGED_MEMORY_END + #define UNPRIVILEGED_MEMORY_END \ (UNPRIVILEGED_MEMORY_START + SECTION_SIZE) -#define PL0_SECTION_NUMBER ((uint32_t) 0b101010101010) +#define PL0_SECTION_NUMBER ((uint32_t) 0b101010101010) #define VIRTUAL_PL0_MEMORY_START (PL0_SECTION_NUMBER << 20) -- cgit v1.2.3 From f05be08f8ef6c9f0f698c14a93559968044c987c Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 16:48:25 +0100 Subject: remove makefs executable when running `make clean` --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 55d0d1b..1311773 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,6 @@ ramfs.img : makefs $(RAMFS_FILES) ./makefs $(RAMFS_FILES) > $@ clean : - -rm *.img *.elf *.o pipe_image + -rm *.img *.elf *.o pipe_image makefs .PHONY: all qemu-elf qemu-bin clean -- cgit v1.2.3 From 6321cd922cb665ca5bfb9bc2025701b07c076894 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 16:51:03 +0100 Subject: minor changes to Makefile --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 1311773..92d200f 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,9 @@ ELFFLAGS=-nostdlib -lgcc ARM_OBJECTS=kernel.o paging.o demo_functionality.o PL0_test.o uart.o loader_stage1.o loader_stage2.o -EMBEDDABLE_OBJECTS=PL_0_test_embeddable.o loader_stage2_embeddable.o - RAMFS_FILES=PL_0_test.img -all : kernel7.img +all : kernel.img %.o : %.c arm-none-eabi-gcc $(CFLAGS) -c $^ -o $@ -- cgit v1.2.3 From f7ddd1a356f58298d703b11e862d3d6127e67080 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 18:09:09 +0100 Subject: rewrite the stage 1 of bootloader in a more compact and (mostly) load-addr-independent way --- Makefile | 12 ++++++--- loader_linker.ld | 72 ------------------------------------------------- loader_stage1.S | 55 +++++++++++++++++++++++++++++++++++++ loader_stage1.c | 26 ------------------ loader_stage1_linker.ld | 16 +++++++++++ loader_stage2.c | 3 +-- loader_stage2_linker.ld | 16 +++++++++++ 7 files changed, 97 insertions(+), 103 deletions(-) delete mode 100644 loader_linker.ld create mode 100644 loader_stage1.S delete mode 100644 loader_stage1.c create mode 100644 loader_stage1_linker.ld create mode 100644 loader_stage2_linker.ld diff --git a/Makefile b/Makefile index 92d200f..29efa86 100644 --- a/Makefile +++ b/Makefile @@ -25,8 +25,14 @@ PL_0_test.elf : PL0_test.o uart.o kernel.elf : boot.o kernel.o uart.o demo_functionality.o paging.o interrupt_vector.o interrupts.o ramfs_embeddable.o ramfs.o arm-none-eabi-gcc -T linker.ld -o $@ $(ELFFLAGS) $^ -loader.elf : boot.o loader_stage1.o loader_stage2.o uart.o - arm-none-eabi-gcc -T loader_linker.ld -o $@ $(ELFFLAGS) $^ +loader_stage2.elf : loader_stage2.o uart.o + arm-none-eabi-gcc -T loader_stage2_linker.ld -o $@ $(ELFFLAGS) $^ + +loader_stage1.o : loader_stage1.S loader_stage2.img + arm-none-eabi-as -mcpu=cortex-a7 $< -o $@ + +loader.elf : loader_stage1.o + arm-none-eabi-gcc -T loader_stage1_linker.ld -o $@ $(ELFFLAGS) $^ loader.img : loader.elf arm-none-eabi-objcopy $^ -O binary $@ @@ -36,7 +42,7 @@ loader.img : loader.elf qemu-elf : kernel.elf qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $^ -qemu-bin : loader.elf kernel.img pipe_image +qemu-bin : loader.img kernel.img pipe_image ./pipe_image --stdout | qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $< run-on-rpi : kernel.img pipe_image diff --git a/loader_linker.ld b/loader_linker.ld deleted file mode 100644 index 45c88ff..0000000 --- a/loader_linker.ld +++ /dev/null @@ -1,72 +0,0 @@ -ENTRY(_boot) - -SECTIONS -{ - /* Starts at LOADER_ADDR. */ - /* Warning! Internet says RPis in 32-bit mode load binary at 0x8000! */ - /* My experiments do, however, show, that qemu emulating RPi2 */ - /* loads it at 0x10000! (took some pain to find out) */ - - /* . = 0x10000; */ - - /* rpi-open-firmware, on the other hand, loads it at 0x2000000 */ - /* (and this should be not-so-hard to change by modifying the */ - /* firmware) */ - - . = 0x2000000; - - /* For AArch64, use . = 0x80000; Unless this too is wrong */ - - __start = .; - __text_stage1_start = .; - .text_stage1 : - { - KEEP(*(.text.boot)) - *(.text.boot) - *(.text.stage1main) - } - . = ALIGN(4096); /* align to page size */ - __text_stage1_end = .; - - __stage2_start = .; - __text_start = .; - .text : - { - KEEP(*(.text.stage2main)) - *(.text.boot) - } - . = ALIGN(4096); /* align to page size */ - __text_end = .; - - __rodata_start = .; - .rodata : - { - *(.rodata) - } - . = ALIGN(4096); /* align to page size */ - __rodata_end = .; - - __data_start = .; - .data : - { - *(.data) - } - . = ALIGN(4096); /* align to page size */ - __data_end = .; - - __bss_start = .; - .bss : - { - bss = .; - *(.bss) - } - . = ALIGN(4096); /* align to page size */ - __bss_end = .; - __bss_size = __bss_end - __bss_start; - - __stage2_end = .; - __stage2_size = __stage2_end - __stage2_start; - __end = .; - - _stack_top = 0x4000; -} diff --git a/loader_stage1.S b/loader_stage1.S new file mode 100644 index 0000000..adf2e12 --- /dev/null +++ b/loader_stage1.S @@ -0,0 +1,55 @@ +// armv7 mode + +// Entry point for the kernel. +// r15 -> should begin execution at 0x8000. +// r0 -> 0x00000000 +// r1 -> 0x00000C42 +// r2 -> 0x00000100 - start of ATAGS +// preserve these registers as argument for kernel + +.global _boot +_boot: + // Only let the first core execute + mrc p15, 0, r3, c0, c0, 5 + and r3, r3, #3 + cmp r3, #0 + beq proceed + // this is a kind of blef - races can theoretically still occur + // when the main core overwrites this part of memory + wfe + +proceed: + // copy stage2 of the loader to address 0x4000 + + // first, load address of stage2_start to r3 (a PIC way) + adr r3, stage2_start + + // load destination address for stage2 code to r4 + mov r4, #0x4000 + + // load blob size to r5 + mov r5, #(stage2_end - stage2_start) + + // r6 is the counter - counts the bytes copied + mov r6, #0 + + // each word of the blob is loaded to r7 and stored + // from r7 to it's destination in a loop +loop: + ldr r7, [r3, r6] + str r7, [r4, r6] + add r6, r6, #4 + cmp r6, r5 + blo loop + + // Initialize the stack + // _stack_top is defined in loader_stage1_linker.ld + ldr sp, =_stack_top + + // Call stage2 of the loader (branch to 0x4000) + bx r4 + +.align 4 +stage2_start: + .incbin "loader_stage2.img" +stage2_end: diff --git a/loader_stage1.c b/loader_stage1.c deleted file mode 100644 index aca439c..0000000 --- a/loader_stage1.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include - -#define STAGE2_ADDR ((volatile char*) 0x4000) - -// There's one tricky thing about managing executable's own code. -// Mainly, symbols are visible to c code as extern chars, but the actual -// values are their adresses... see the code below -extern char - __stage2_start, - __stage2_end, - __stage2_size; - -__attribute__((section(".text.stage1main"))) -void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) -{ - // stage2 of the bootloader is part of executable; - // copy it over to it's destination place - // TODO implement a memcpy() somewhere and use it instead of loops - for (size_t i = 0; i < (size_t) &__stage2_size; i++) - STAGE2_ADDR[i] = (&__stage2_start)[i]; - - // jump to stage2 - ((void(*)(uint32_t, uint32_t, uint32_t))STAGE2_ADDR)(r0, r1, atags); -} diff --git a/loader_stage1_linker.ld b/loader_stage1_linker.ld new file mode 100644 index 0000000..711fcbf --- /dev/null +++ b/loader_stage1_linker.ld @@ -0,0 +1,16 @@ +ENTRY(_boot) + +SECTIONS +{ + /* see linker.ld for details */ + . = 0x2000000; + + __start = .; + loader_stage1 : + { + KEEP(loader_stage1.o) + } + __end = .; + + _stack_top = 0x8000; +} diff --git a/loader_stage2.c b/loader_stage2.c index 7b5087a..65dda0a 100644 --- a/loader_stage2.c +++ b/loader_stage2.c @@ -5,8 +5,7 @@ void *const kernel_load_addr = ((void*) 0x8000); -void __attribute__((section(".text.stage2main"))) -stage2(uint32_t r0, uint32_t r1, uint32_t atags) +void _stage2_main(uint32_t r0, uint32_t r1, uint32_t atags) { // Declare as unused (void) r0; diff --git a/loader_stage2_linker.ld b/loader_stage2_linker.ld new file mode 100644 index 0000000..33e79e9 --- /dev/null +++ b/loader_stage2_linker.ld @@ -0,0 +1,16 @@ +ENTRY(_stage2_main) + +SECTIONS +{ + /* see loader_stage1.S for details */ + . = 0x4000; + + __start = .; + loader_stage2 : + { + KEEP(loader_stage2.o(.text)) + loader_stage2.o + uart.o + } + __end = .; +} -- cgit v1.2.3 From d357eefbfb7392e9313ac7d4b8f819e7a08f886a Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 18:29:22 +0100 Subject: forward arguments from the loader --- loader_stage2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loader_stage2.c b/loader_stage2.c index 65dda0a..f49d94c 100644 --- a/loader_stage2.c +++ b/loader_stage2.c @@ -31,7 +31,7 @@ void _stage2_main(uint32_t r0, uint32_t r1, uint32_t atags) *(dst++) = uart_getc(); // jump to kernel - // TODO also forward arguments (r0, r1, atags) - asm volatile("bx %0" :: "r" (kernel_load_addr) : "memory"); + ((void(*)(uint32_t, uint32_t, uint32_t)) kernel_load_addr) + (r0, r1, atags); } -- cgit v1.2.3 From 7d5496d130100e621d6f192815ac67a5cad37f37 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 18:35:11 +0100 Subject: don't take kernel arguments (as we're making no use of them for now, anyway) --- kernel.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/kernel.c b/kernel.c index 9cdb82a..719ceff 100644 --- a/kernel.c +++ b/kernel.c @@ -2,13 +2,8 @@ #include "demo_functionality.h" #include "paging.h" -void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) +void kernel_main(void) { - // Declare as unused - (void) r0; - (void) r1; - (void) atags; - uart_init(); // When we attach screen session after loading kernel with socat -- cgit v1.2.3 From 38afee0bfe051f1c1e5b9426395eb50b9d8a7bc2 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 18:53:16 +0100 Subject: correct the notion of PIC in the comment --- linker.ld | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/linker.ld b/linker.ld index 673d7e2..444bbf6 100644 --- a/linker.ld +++ b/linker.ld @@ -9,8 +9,9 @@ SECTIONS /* kernel at 0x2000000! */ /* This is not really a problem, since: */ /* 1. We can use our bootloader to load the kernel at 0x8000 */ - /* 2. We compile kernel with -fPIC, so it should be able to */ - /* work with any load addr. */ + /* 2. Stage 1 of the bootloader is written in careful */ + /* assembly, so that the loader itself should work */ + /* regardless of where it is loaded. */ /* 3. In qemu, we can load kernel.elf instead of raw binary */ /* (qemu will do the right thing then) */ @@ -23,9 +24,9 @@ SECTIONS { __kernel_start = .; KEEP(boot.o) - *(EXCLUDE_FILE (ramfs_embeddable.o libkernel.o interrupt_vector.o interrupts.o) *) . = ALIGN(4); ramfs_embeddable.o + *(EXCLUDE_FILE (libkernel.o interrupt_vector.o interrupts.o) *) __kernel_end = .; } __kernel_size = __kernel_end - __kernel_start; -- cgit v1.2.3 From 80c9af17330ac442a4c3d6d55b4041cbe923e9b4 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 19:09:47 +0100 Subject: modify comment in the top of loader_stage1.S --- loader_stage1.S | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/loader_stage1.S b/loader_stage1.S index adf2e12..9326360 100644 --- a/loader_stage1.S +++ b/loader_stage1.S @@ -1,12 +1,12 @@ -// armv7 mode - -// Entry point for the kernel. -// r15 -> should begin execution at 0x8000. -// r0 -> 0x00000000 -// r1 -> 0x00000C42 -// r2 -> 0x00000100 - start of ATAGS -// preserve these registers as argument for kernel - +/* arm mode, cortex-a7 compatibility + * + * _boot is entry point for the loader. + * + * Loader copies it's embedded stage 2 to address 0x4000 + * and jumps to it. Registers r0 - r2 are arguments for the kernel + * and should be left intact. + */ + .global _boot _boot: // Only let the first core execute -- cgit v1.2.3 From 700f4c412d42c9b9811269045c0e363a0331bba9 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 21:54:42 +0100 Subject: split kernel into 2 stages; second stage gets copied to 0x0 and runs from there --- Makefile | 29 ++++++++++++++++++----- boot.S | 27 --------------------- demo_functionality.c | 26 ++------------------ interrupt_vector.S | 53 +++++++++++++++++++++++++++++------------ interrupts.c | 55 +++++++++++++++++++++++++++++++++++------- kernel.c | 44 ---------------------------------- kernel_stage1.S | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel_stage1.ld | 27 +++++++++++++++++++++ kernel_stage2.ld | 52 ++++++++++++++++++++++++++++++++++++++++ linker.ld | 47 ------------------------------------ memory.h | 43 ++++++++++++++++++++++----------- setup.c | 41 ++++++++++++++++++++++++++++++++ 12 files changed, 325 insertions(+), 186 deletions(-) delete mode 100644 boot.S delete mode 100644 kernel.c create mode 100644 kernel_stage1.S create mode 100644 kernel_stage1.ld create mode 100644 kernel_stage2.ld delete mode 100644 linker.ld create mode 100644 setup.c diff --git a/Makefile b/Makefile index 29efa86..68368a5 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,10 @@ -CFLAGS=-mcpu=cortex-a7 -ffreestanding -std=gnu11 -Wall -Wextra -O2 -fPIC -I. +CFLAGS=-mcpu=cortex-a7 -ffreestanding -std=gnu11 -Wall -Wextra -O2 -I. ELFFLAGS=-nostdlib -lgcc ARM_OBJECTS=kernel.o paging.o demo_functionality.o PL0_test.o uart.o loader_stage1.o loader_stage2.o +KERNEL_STAGE2_OBJECTS=setup.o interrupt_vector.o interrupts.o uart.o demo_functionality.o paging.o ramfs_embeddable.o ramfs.o + RAMFS_FILES=PL_0_test.img all : kernel.img @@ -10,20 +12,32 @@ all : kernel.img %.o : %.c arm-none-eabi-gcc $(CFLAGS) -c $^ -o $@ -%.o : %.S - arm-none-eabi-as -mcpu=cortex-a7 $^ -o $@ - %.img : %.elf arm-none-eabi-objcopy $^ -O binary $@ +%.o : %.S + arm-none-eabi-as -mcpu=cortex-a7 $^ -o $@ + %_embeddable.o : %.img arm-none-eabi-objcopy -I binary -O elf32-littlearm -B arm --rename-section .data=.rodata $^ $@ PL_0_test.elf : PL0_test.o uart.o arm-none-eabi-gcc -T PL0_test.ld -o $@ $(ELFFLAGS) $^ -kernel.elf : boot.o kernel.o uart.o demo_functionality.o paging.o interrupt_vector.o interrupts.o ramfs_embeddable.o ramfs.o - arm-none-eabi-gcc -T linker.ld -o $@ $(ELFFLAGS) $^ +kernel_stage1.o : kernel_stage1.S kernel_stage2.img + arm-none-eabi-as -mcpu=cortex-a7 $< -o $@ + +kernel.elf : kernel_stage1.ld kernel_stage1.o + arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) kernel_stage1.o + +kernel.img : kernel.elf + arm-none-eabi-objcopy $^ -O binary $@ + +kernel_stage2.elf : kernel_stage2.ld $(KERNEL_STAGE2_OBJECTS) + arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) $(KERNEL_STAGE2_OBJECTS) + +#kernel.elf : boot.o kernel.o uart.o demo_functionality.o paging.o interrupt_vector.o interrupts.o ramfs_embeddable.o ramfs.o +# arm-none-eabi-gcc -T linker.ld -o $@ $(ELFFLAGS) $^ loader_stage2.elf : loader_stage2.o uart.o arm-none-eabi-gcc -T loader_stage2_linker.ld -o $@ $(ELFFLAGS) $^ @@ -42,6 +56,9 @@ loader.img : loader.elf qemu-elf : kernel.elf qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $^ +qemu-img : kernel.img + qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $^ + qemu-bin : loader.img kernel.img pipe_image ./pipe_image --stdout | qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $< diff --git a/boot.S b/boot.S deleted file mode 100644 index 593ed11..0000000 --- a/boot.S +++ /dev/null @@ -1,27 +0,0 @@ -// armv7 mode - -// Entry point for the kernel. -// r15 -> should begin execution at 0x8000. -// r0 -> 0x00000000 -// r1 -> 0x00000C42 -// r2 -> 0x00000100 - start of ATAGS -// preserve these registers as argument for kernel_main - -.global _boot // make entry point label global -_boot: - // Only let the first core execute - mrc p15, 0, r3, c0, c0, 5 - and r3, r3, #3 - cmp r3, #0 - beq proceed - // this is a kind of blef - races can theoretically still occur - // when the main core overwrites this part of memory - wfe - -proceed: - // Initialize the stack (_stack_top is defined in linker.ld) - ldr sp, =_stack_top - - // Call kernel_main - ldr r3, =kernel_main - bx r3 diff --git a/demo_functionality.c b/demo_functionality.c index 4b002d6..420639b 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -53,7 +53,7 @@ void demo_current_mode(void) uart_puts(mode_name); } -#define TRANSLATION_TABLE \ +#define TRANSLATION_TABLE \ ((short_section_descriptor_t volatile*) TRANSLATION_TABLE_BASE) extern char @@ -144,29 +144,7 @@ void demo_go_unprivileged(void) write_SPSR(new_SPSR); uart_puts("All ready, jumping to PL0 code\n\r"); - + asm volatile("ldm %0, {r0 - r15} ^" :: "r" (PL0_regs)); } - -extern char - __interrupts_start, - __interrupts_end, - __interrupts_size; - -extern void (*volatile system_reentry_point)(void); - -void system_reentry(void) -{ - uart_puts("re-entered system"); - while(1); -} - -void demo_setup_interrupts(void) -{ - system_reentry_point = system_reentry; - - for (size_t i = 0; i < (size_t) &__interrupts_size; i++) - ((volatile char*) 0)[i] = - (&__interrupts_start)[i]; -} diff --git a/interrupt_vector.S b/interrupt_vector.S index d20bf6d..6037b7c 100644 --- a/interrupt_vector.S +++ b/interrupt_vector.S @@ -1,22 +1,45 @@ -.section ".interrupts.vector" - -.global abort_handler -.local generic_handler -.global _interrupt_vectors _interrupt_vectors: - b generic_handler - b generic_handler - b generic_handler + b reset_handler_caller + b undef_handler_caller + b svc_handler_caller b abort_handler_caller b abort_handler_caller - b generic_handler - b generic_handler - -.section ".interrupts.text" + b generic_handler_caller + b irq_handler_caller + b fiq_handler_caller + +reset_handler_caller: + ldr sp, =_stack_top + ldr r5, =reset_handler + bx r5 + +undef_handler_caller: + ldr sp, =_stack_top + ldr r5, =undefined_instruction_vector + bx r5 -generic_handler: - b generic_handler +svc_handler_caller: + ldr sp, =_stack_top + ldr r5, =supervisor_call_handler + bx r5 + abort_handler_caller: - mov sp, #0x8000 + ldr sp, =_stack_top ldr r5, =abort_handler bx r5 + +generic_handler_caller: + ldr sp, =_stack_top + ldr r5, =generic_handler + bx r5 + +irq_handler_caller: + ldr sp, =_stack_top + ldr r5, =irq_handler + bx r5 + +fiq_handler_caller: + ldr sp, =_stack_top + ldr r5, =fiq_handler + bx r5 + diff --git a/interrupts.c b/interrupts.c index 6952f89..1b0590a 100644 --- a/interrupts.c +++ b/interrupts.c @@ -1,10 +1,20 @@ #include "uart.h" -/** - @brief The undefined instruction interrupt handler - If an undefined instruction is encountered, the CPU will start - executing this function. Just trap here as a debug solution. -*/ +void setup(void); + +void reset_handler(void) +{ + static _Bool setup_done; + + if (!setup_done) + setup(); + + setup_done = 1; + + // TODO do something here + while(1); +} + void __attribute__((interrupt("UNDEF"))) __attribute__((section(".interrupts.text"))) @@ -17,13 +27,40 @@ undefined_instruction_vector(void) } } -void __attribute__((section(".interrupts.data"))) -(*system_reentry_point) (void); +void supervisor_call_handler(void) +{ + uart_puts("something svc happened\n\r"); + + while(1); +} void __attribute__((interrupt("ABORT"))) -__attribute__((section(".interrupts.text"))) abort_handler(void) { - system_reentry_point(); + uart_puts("re-entered system\n\r"); + + while(1); +} + +void generic_handler(void) +{ + uart_puts("something weird happened\n\r"); + + while(1); +} + +void irq_handler(void) +{ + uart_puts("irq happened\n\r"); + + while(1); +} + +void fiq_handler(void) +{ + uart_puts("fiq happened\n\r"); + + while(1); } + diff --git a/kernel.c b/kernel.c deleted file mode 100644 index 719ceff..0000000 --- a/kernel.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "uart.h" -#include "demo_functionality.h" -#include "paging.h" - -void kernel_main(void) -{ - uart_init(); - - // 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 - uart_getc(); - - uart_puts("Hello, kernel World!\r\n"); - - // prints some info - demo_paging_support(); - - // prints some info - demo_current_mode(); - - // prints some info and sets upp translation table, turns on MMU - setup_flat_map(); - - demo_setup_PL0(); - - demo_setup_interrupts(); - - // 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) - { - char c = uart_getc(); - - uart_putc(c); - - if (c == '\r') - uart_putc('\n'); - } -} diff --git a/kernel_stage1.S b/kernel_stage1.S new file mode 100644 index 0000000..1e0f614 --- /dev/null +++ b/kernel_stage1.S @@ -0,0 +1,67 @@ +/* arm mode, cortex-a7 compatibility + * + * _boot is entry point for the kernel. + * + * Kernel copies it's embedded stage 2 to address 0x0 and jumps to + * it (to the reset handler). Registers r0 - r2 are arguments for + * the kernel, but we're not using them for now. + * + * This file is based on (and almost identical with) loader_stage1.S + */ + +.global _boot +_boot: + // Only let the first core execute + mrc p15, 0, r3, c0, c0, 5 + and r3, r3, #3 + cmp r3, #0 + beq proceed + // this is a kind of blef - races can theoretically still + // occur when the main core overwrites this part of memory + wfe + +proceed: + // copy stage2 of the kernel to address 0x0 + + // first, load address of stage2_start to r3 (a PIC way) + adr r3, stage2_start + + // load destination address for stage2 code to r4 + mov r4, #0 + + // load blob size to r5 + // The size might get too big for an immediate value, so + // we load it from memory. + adr r5, blob_size + ldr r5, [r5] + + // r6 is the counter - counts the bytes copied + mov r6, #0 + + // This initial piece of code might get overwritten when we + // copy stage2, so the actual copying loop shall be after + // stage2 blob. We want this asm code to be PIC, so we're + // computing address of stage2_end into r7. + add r7, r3, r5 + bx r7 + +blob_size: + .word stage2_end - stage2_start + +.align 4 +stage2_start: + .incbin "kernel_stage2.img" +stage2_end: + + // each word of the blob is loaded to r7 and stored + // from r7 to it's destination in a loop +loop: + ldr r7, [r3, r6] + str r7, [r4, r6] + add r6, r6, #4 + cmp r6, r5 + blo loop + + // Call stage2 of the kernel (branch to 0x0, + // which is the reset handler). + bx r4 diff --git a/kernel_stage1.ld b/kernel_stage1.ld new file mode 100644 index 0000000..3130634 --- /dev/null +++ b/kernel_stage1.ld @@ -0,0 +1,27 @@ +ENTRY(_boot) /* defined in boot.S; qemu needs it to run elf file */ + +/* Code starts at 0x8000 - that's where RPis in 32-bit mode load + * kernel at. My experiments do, however, show, that qemu emulating + * RPi2 loads the kernel at 0x10000! (took some pain to find out). + * rpi-open-firmware, on the other hand, loads kernel at 0x2000000! + * This is not really a problem, since: + * 1. We can use our bootloader to load the kernel at 0x8000 + * 2. We've rewritten stage 1 of both bootloader and kernel in + * careful assembly, so that they should work regardless of + * where they are loaded. + * 3. In qemu, we can load kernel.elf instead of raw binary + * (qemu will do the right thing then) + */ + +SECTIONS +{ + + . = 0x8000; + + __start = .; + .kernel_stage1 : + { + KEEP(kernel_stage1.o) + } + __end = .; +} diff --git a/kernel_stage2.ld b/kernel_stage2.ld new file mode 100644 index 0000000..d3a23bf --- /dev/null +++ b/kernel_stage2.ld @@ -0,0 +1,52 @@ +/* This sesond stage of the kernel is run from address 0x0 */ + +TRANSLATION_TABLE_SIZE = 4096 * 4; +MMU_SECTION_SIZE = 1 << 20; + +SECTIONS +{ + + . = 0x0; + + __start = .; + .kernel_stage2 : + { + KEEP(interrupt_vector.o) + . = ALIGN(4); + ramfs_embeddable.o + (*) + } + __end = .; + + . = ALIGN(1 << 14); + + .translation_table (NOLOAD) : + { + _translation_table_start = .; + + . = . + TRANSLATION_TABLE_SIZE; + + _translation_table_end = .; + } + + . = ALIGN(1 << 20); + . = . + MMU_SECTION_SIZE; + + .stack (NOLOAD) : + { + _stack_start = .; + + . = . + MMU_SECTION_SIZE; + + _stack_top = .; + } + + .unprivileged_memory (NOLOAD) : + { + _unprivileged_memory_start = .; + + . = . + MMU_SECTION_SIZE; + + _unprivileged_memory_end = .; + } +} diff --git a/linker.ld b/linker.ld deleted file mode 100644 index 444bbf6..0000000 --- a/linker.ld +++ /dev/null @@ -1,47 +0,0 @@ -ENTRY(_boot) /* defined in boot.S; qemu needs it to run elf file */ - -SECTIONS -{ - /* Starts at 0x8000 - that's where RPis in 32-bit mode load */ - /* kernel at. My experiments do, however, show, that qemu */ - /* emulating RPi2 loads the kernel at 0x10000! (took some pain */ - /* to find out). rpi-open-firmware, on the other hand, loads */ - /* kernel at 0x2000000! */ - /* This is not really a problem, since: */ - /* 1. We can use our bootloader to load the kernel at 0x8000 */ - /* 2. Stage 1 of the bootloader is written in careful */ - /* assembly, so that the loader itself should work */ - /* regardless of where it is loaded. */ - /* 3. In qemu, we can load kernel.elf instead of raw binary */ - /* (qemu will do the right thing then) */ - - . = 0x8000; - - /* RPi in 64-bit mode uses address 0x80000 instead */ - - __start = .; - .kernel : - { - __kernel_start = .; - KEEP(boot.o) - . = ALIGN(4); - ramfs_embeddable.o - *(EXCLUDE_FILE (libkernel.o interrupt_vector.o interrupts.o) *) - __kernel_end = .; - } - __kernel_size = __kernel_end - __kernel_start; - - .interrupts : - { - __interrupts_start = .; - KEEP(*(.interrupts.vector)) - interrupt_vector.o - interrupts.o - __interrupts_end = .; - } - __interrupts_size = __interrupts_end - __interrupts_start; - - __end = .; - - _stack_top = __start; -} diff --git a/memory.h b/memory.h index e4493e2..adc3bc0 100644 --- a/memory.h +++ b/memory.h @@ -1,7 +1,10 @@ #ifndef MEMORY_H #define MEMORY_H -#define POWER_OF_2(EXP) (((uint32_t) 1) << EXP) +// These macros were heavily used b4 I moved all the address +// computation to the linker script. Now I'm just keeping them +// in case they're needed for something else :) +#define POWER_OF_2(EXP) (((size_t) 1) << EXP) #define ALIGN_POWER_OF_2(ADDR, EXP) \ (((ADDR - 1) & ~(POWER_OF_2(EXP) - 1)) + POWER_OF_2(EXP)) @@ -10,33 +13,45 @@ #define ALIGN_SECTION(ADDR) ALIGN_POWER_OF_2(ADDR, 20) -#define INTERRUPT_VECTOR_TABLE_START ((uint32_t) 0x0) -#define STACK_START ((uint32_t) 0x4000) -#define STACK_END ((uint32_t) 0x8000) +// memory layout + +#define INTERRUPT_VECTOR_TABLE_START ((uint32_t) 0x0) +// all those symbols are defined in the linker script extern const char __end; extern const char __start; +extern const char _translation_table_start; +extern const char _translation_table_end; +extern const char _stack_start; +extern const char _stack_top; +extern const char _unprivileged_memory_start; +extern const char _unprivileged_memory_end; -#define KERNEL_START ((uint32_t) &__start) // this is 0x8000 -#define KERNEL_END ((uint32_t) &__end) +#define KERNEL_START ((size_t) &__start) // this is 0x0 +#define KERNEL_END ((size_t) &__end) // first 2^14 aligned address after the kernel -#define TRANSLATION_TABLE_BASE ALIGN_POWER_OF_2(KERNEL_END, 14) - -#define TRANSLATION_TABLE_END \ - (TRANSLATION_TABLE_BASE + (uint32_t) (4096 * 4)) +#define TRANSLATION_TABLE_BASE ((size_t) &_translation_table_start) +#define TRANSLATION_TABLE_END ((size_t) &_translation_table_end) -#define PRIVILEGED_MEMORY_END ALIGN_SECTION(TRANSLATION_TABLE_END) +// first section after the translation table is left unused; +// the next section is used as the stack +#define STACK_START ((size_t) &_stack_start) +#define STACK_END ((size_t) &_stack_top) -#define UNPRIVILEGED_MEMORY_START PRIVILEGED_MEMORY_END +#define PRIVILEGED_MEMORY_END STACK_END +#define UNPRIVILEGED_MEMORY_START \ + ((size_t) &_unprivileged_memory_start) // equal to STACK_END #define UNPRIVILEGED_MEMORY_END \ - (UNPRIVILEGED_MEMORY_START + SECTION_SIZE) + ((size_t) &_unprivileged_memory_end) -#define PL0_SECTION_NUMBER ((uint32_t) 0b101010101010) +#define PL0_SECTION_NUMBER ((size_t) 0xaaa) #define VIRTUAL_PL0_MEMORY_START (PL0_SECTION_NUMBER << 20) +#define VIRTUAL_PL0_MEMORY_END \ + (VIRTUAL_PL0_MEMORY_START + SECTION_SIZE) #endif // MEMORY_H diff --git a/setup.c b/setup.c new file mode 100644 index 0000000..48df825 --- /dev/null +++ b/setup.c @@ -0,0 +1,41 @@ +#include "uart.h" +#include "demo_functionality.h" +#include "paging.h" + +void setup(void) +{ + uart_init(); + + // 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 + uart_getc(); + + uart_puts("Hello, kernel World!\r\n"); + + // prints some info + demo_paging_support(); + + // prints some info + demo_current_mode(); + + // prints some info and sets upp translation table, turns on MMU + setup_flat_map(); + + // prints some info and sets up a section for PL0 code, + // loads a blob there + demo_setup_PL0(); + + // jumps to unprivileged code... never, ever, ever returns + demo_go_unprivileged(); + + while (1) + { + char c = uart_getc(); + + uart_putc(c); + + if (c == '\r') + uart_putc('\n'); + } +} -- cgit v1.2.3 From 68478311d11406e9452ae7fc2cf6e7405fb9c4d6 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 21:57:00 +0100 Subject: simple interrupt handling functions declarations, without attributes --- interrupts.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/interrupts.c b/interrupts.c index 1b0590a..1a0150e 100644 --- a/interrupts.c +++ b/interrupts.c @@ -15,10 +15,7 @@ void reset_handler(void) while(1); } -void -__attribute__((interrupt("UNDEF"))) -__attribute__((section(".interrupts.text"))) -undefined_instruction_vector(void) +void undefined_instruction_vector(void) { uart_puts("Undefined instruction occured"); while( 1 ) @@ -34,9 +31,7 @@ void supervisor_call_handler(void) while(1); } -void -__attribute__((interrupt("ABORT"))) -abort_handler(void) +void abort_handler(void) { uart_puts("re-entered system\n\r"); -- cgit v1.2.3 From a910d10349593fce9f5f28f0de4f27ba85cd7df2 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 23:25:05 +0100 Subject: enter and exit supervisor call (+ fixed jumping to PL0 for the first time - setting sp was broken there) --- PL0_test.c | 15 +++++++++++---- demo_functionality.c | 17 ++++++++++++----- interrupt_vector.S | 4 +++- interrupts.c | 2 -- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/PL0_test.c b/PL0_test.c index 32addf8..2e008a2 100644 --- a/PL0_test.c +++ b/PL0_test.c @@ -1,18 +1,25 @@ #include "uart.h" #include "psr.h" +// entry point - must remain the only function in the file! void PL0_main(void) { - // if all went correct, Success! gets printed + // If all went correct, Success! gets printed uart_puts("Success!\n\r"); - // if we're indeed i PL0, we should crash now, when trying to access + uart_puts("calling supervisor\n\r"); + + asm volatile("svc #0"); + + uart_puts("back from supervisor call\n\r"); + + // if we're indeed in PL0, we should crash now, when trying to access // memory we're not allowed to char first_kernel_byte[2]; - first_kernel_byte[0] = *(char*) ((uint32_t) 0x8000); + first_kernel_byte[0] = *(char*) ((uint32_t) 0x0); first_kernel_byte[1] = '\0'; - + uart_puts(first_kernel_byte); while (1) diff --git a/demo_functionality.c b/demo_functionality.c index 420639b..12bba9b 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -135,9 +135,8 @@ void *memset(void *s, int c, size_t n) void demo_go_unprivileged(void) { - uint32_t PL0_regs[16] = {0}; - PL0_regs[15] = VIRTUAL_PL0_MEMORY_START; // the new pc - PL0_regs[13] = (PL0_SECTION_NUMBER + 1) << 20; // the new sp + uint32_t PL0_regs[14] = {0}; + PL0_regs[13] = VIRTUAL_PL0_MEMORY_START; // the new pc PSR_t new_SPSR = read_CPSR(); new_SPSR.fields.PSR_MODE_4_0 = MODE_USER; @@ -145,6 +144,14 @@ void demo_go_unprivileged(void) uart_puts("All ready, jumping to PL0 code\n\r"); - asm volatile("ldm %0, {r0 - r15} ^" :: - "r" (PL0_regs)); + asm volatile("cps %[sysmode]\n\r" + "mov sp, %[stackaddr]\n\r" + "cps %[supmode]\n\r" + "ldm %[contextaddr], {r0 - r12, pc} ^" :: + [sysmode]"I" (MODE_SYSTEM), + [supmode]"I" (MODE_SUPERVISOR), + [stackaddr]"r" ((PL0_SECTION_NUMBER + 1) << 20), + [contextaddr]"r" (PL0_regs) : "memory"); + + __builtin_unreachable(); } diff --git a/interrupt_vector.S b/interrupt_vector.S index 6037b7c..88b32bf 100644 --- a/interrupt_vector.S +++ b/interrupt_vector.S @@ -21,7 +21,9 @@ undef_handler_caller: svc_handler_caller: ldr sp, =_stack_top ldr r5, =supervisor_call_handler - bx r5 + push {lr} + blx r5 + ldm sp!, {pc} ^ abort_handler_caller: ldr sp, =_stack_top diff --git a/interrupts.c b/interrupts.c index 1a0150e..7932d23 100644 --- a/interrupts.c +++ b/interrupts.c @@ -27,8 +27,6 @@ void undefined_instruction_vector(void) void supervisor_call_handler(void) { uart_puts("something svc happened\n\r"); - - while(1); } void abort_handler(void) -- cgit v1.2.3 From dab51b1932cb82af152b0b6cbdb687083f79a290 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 28 Dec 2019 23:37:17 +0100 Subject: improve linking of PL0_test --- Makefile | 4 ++-- PL0_test.ld | 48 +++++++++--------------------------------------- 2 files changed, 11 insertions(+), 41 deletions(-) diff --git a/Makefile b/Makefile index 68368a5..e48dd2d 100644 --- a/Makefile +++ b/Makefile @@ -21,8 +21,8 @@ all : kernel.img %_embeddable.o : %.img arm-none-eabi-objcopy -I binary -O elf32-littlearm -B arm --rename-section .data=.rodata $^ $@ -PL_0_test.elf : PL0_test.o uart.o - arm-none-eabi-gcc -T PL0_test.ld -o $@ $(ELFFLAGS) $^ +PL_0_test.elf : PL0_test.ld PL0_test.o uart.o + arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) PL0_test.o uart.o kernel_stage1.o : kernel_stage1.S kernel_stage2.img arm-none-eabi-as -mcpu=cortex-a7 $< -o $@ diff --git a/PL0_test.ld b/PL0_test.ld index 45bee5e..b1d06f4 100644 --- a/PL0_test.ld +++ b/PL0_test.ld @@ -1,49 +1,19 @@ -ENTRY(_start) - +/* linker script for creating the example userspace program PL0_test + */ + +/* no ENTRY() statement - this executable is run by jumping to it */ + SECTIONS { - /* 0b10101010101000000000000000000000 */ + /* my thought up address userspace programs should run from */ . = 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 : + .another_weird_section_name_that_doesnt_matter : { /* have entry point at the beginning */ - KEEP(*(.text.PL0main)) - *(.text) + KEEP(PL0_test.o) + *(*) } - . = ALIGN(4096); /* align to page size */ - __text_end = .; - - __rodata_start = .; - .rodata : - { - *(.rodata) - } - . = ALIGN(4096); /* align to page size */ - __rodata_end = .; - - __data_start = .; - .data : - { - *(.data) - } - . = ALIGN(4096); /* align to page size */ - __data_end = .; - - __bss_start = .; - .bss : - { - bss = .; - *(.bss) - } - . = ALIGN(4096); /* align to page size */ - __bss_end = .; - __bss_size = __bss_end - __bss_start; __end = .; } -- cgit v1.2.3 From 48a3742d8f453f46da9ed5f375777788ca4d87a7 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 13:27:52 +0100 Subject: don't perform unneeded section renaming for embedded files --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e48dd2d..d44fc2b 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ all : kernel.img arm-none-eabi-as -mcpu=cortex-a7 $^ -o $@ %_embeddable.o : %.img - arm-none-eabi-objcopy -I binary -O elf32-littlearm -B arm --rename-section .data=.rodata $^ $@ + arm-none-eabi-objcopy -I binary -O elf32-littlearm -B arm $^ $@ PL_0_test.elf : PL0_test.ld PL0_test.o uart.o arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) PL0_test.o uart.o -- cgit v1.2.3 From ee8668f9fcd952e4952706789bdde7fd223dacb5 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 13:29:04 +0100 Subject: fix the linking of embedded ramfs --- kernel_stage2.ld | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/kernel_stage2.ld b/kernel_stage2.ld index d3a23bf..dce2d1f 100644 --- a/kernel_stage2.ld +++ b/kernel_stage2.ld @@ -9,12 +9,22 @@ SECTIONS . = 0x0; __start = .; - .kernel_stage2 : + .interrupt_vector : { KEEP(interrupt_vector.o) - . = ALIGN(4); + } + . = ALIGN(4); + .embedded_ramfs : + { ramfs_embeddable.o - (*) + } + .rest_of_kernel : + { + *(.text) + *(.data) + *(.rodata) + *(.bss) + *(/COMMON/) } __end = .; -- cgit v1.2.3 From 26685f5203bc38cfa082b96182a406f4f7e6435a Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 14:36:31 +0100 Subject: implement getchar() and putchar() in terms of supervisor call --- Makefile | 6 ++++-- PL0_test.c | 27 +++++++++++---------------- PL0_utils.c | 27 +++++++++++++++++++++++++++ PL0_utils.h | 10 ++++++++++ interrupts.c | 22 ++++++++++++++++++++-- svc.S | 5 +++++ svc_interface.h | 11 +++++++++++ 7 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 PL0_utils.c create mode 100644 PL0_utils.h create mode 100644 svc.S create mode 100644 svc_interface.h diff --git a/Makefile b/Makefile index d44fc2b..48bbd14 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,8 @@ ARM_OBJECTS=kernel.o paging.o demo_functionality.o PL0_test.o uart.o loader_stag KERNEL_STAGE2_OBJECTS=setup.o interrupt_vector.o interrupts.o uart.o demo_functionality.o paging.o ramfs_embeddable.o ramfs.o +PL_0_TEST_OBJECTS=PL0_utils.o svc.o PL0_test.o uart.o + RAMFS_FILES=PL_0_test.img all : kernel.img @@ -21,8 +23,8 @@ all : kernel.img %_embeddable.o : %.img arm-none-eabi-objcopy -I binary -O elf32-littlearm -B arm $^ $@ -PL_0_test.elf : PL0_test.ld PL0_test.o uart.o - arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) PL0_test.o uart.o +PL_0_test.elf : PL0_test.ld $(PL_0_TEST_OBJECTS) + arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) $(PL_0_TEST_OBJECTS) kernel_stage1.o : kernel_stage1.S kernel_stage2.img arm-none-eabi-as -mcpu=cortex-a7 $< -o $@ diff --git a/PL0_test.c b/PL0_test.c index 2e008a2..f476eb7 100644 --- a/PL0_test.c +++ b/PL0_test.c @@ -1,34 +1,29 @@ -#include "uart.h" -#include "psr.h" +#include "PL0_utils.h" // entry point - must remain the only function in the file! void PL0_main(void) { - // If all went correct, Success! gets printed - uart_puts("Success!\n\r"); - - uart_puts("calling supervisor\n\r"); - - asm volatile("svc #0"); - - uart_puts("back from supervisor call\n\r"); + // If loading program to userspace and handling of svc are + // implemented correctly, this shall get printed + puts("Hello userspace!"); - // if we're indeed in PL0, we should crash now, when trying to access - // memory we're not allowed to + // 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*) ((uint32_t) 0x0); + first_kernel_byte[0] = *(char*) 0x0; first_kernel_byte[1] = '\0'; uart_puts(first_kernel_byte); while (1) { - char c = uart_getc(); + char c = getchar(); - uart_putc(c); + putchar(c); if (c == '\r') - uart_putc('\n'); + putchar('\n'); } } diff --git a/PL0_utils.c b/PL0_utils.c new file mode 100644 index 0000000..2cede90 --- /dev/null +++ b/PL0_utils.c @@ -0,0 +1,27 @@ +#include +#include + +#include "svc_interface.h" + +// most generic definition possible +// the actual function defined in svc.S +uint32_t svc(enum svc_type, ...); + +void putchar(int character) +{ + svc(UART_PUTCHAR, character); +} + +int getchar(void) +{ + return svc(UART_GETCHAR); +} + +void puts(char *string) +{ + for (size_t i = 0; string[i]; i++) + putchar(string[i]); + + putchar('\n'); + putchar('\r'); +} diff --git a/PL0_utils.h b/PL0_utils.h new file mode 100644 index 0000000..ba72fd3 --- /dev/null +++ b/PL0_utils.h @@ -0,0 +1,10 @@ +#ifndef PL0_UTILS_H +#define PL0_UTILS_H + +void putchar(int character); + +int getchar(void); + +void puts(char *string); + +#endif // PL0_UTILS_H diff --git a/interrupts.c b/interrupts.c index 7932d23..f47bc1d 100644 --- a/interrupts.c +++ b/interrupts.c @@ -1,4 +1,5 @@ #include "uart.h" +#include "svc_interface.h" void setup(void); @@ -24,9 +25,26 @@ void undefined_instruction_vector(void) } } -void supervisor_call_handler(void) +uint32_t supervisor_call_handler(enum svc_type request, uint32_t arg1, + uint32_t arg2, uint32_t arg3) { - uart_puts("something svc happened\n\r"); + (void) arg2; (void) arg3; // unused for now + + switch(request) { + case UART_PUTCHAR: + uart_putc(arg1); + break; + case UART_GETCHAR: + return uart_getc(); + case UART_WRITE: + uart_puts("UART_WRITE not implemented!!!!!\n\r"); + break; + default: + // perhaps we should kill the process now? + uart_puts("unknown supervisor call type!!!!!\n\r"); + } + + return 0; // a dummy value } void abort_handler(void) diff --git a/svc.S b/svc.S new file mode 100644 index 0000000..65200d8 --- /dev/null +++ b/svc.S @@ -0,0 +1,5 @@ +.global svc + +svc: + svc #0 + mov pc, lr diff --git a/svc_interface.h b/svc_interface.h new file mode 100644 index 0000000..aa478ce --- /dev/null +++ b/svc_interface.h @@ -0,0 +1,11 @@ +#ifndef SVC_INTERFACE_H +#define SVC_INTERFACE_H + +enum svc_type + { + UART_PUTCHAR, + UART_GETCHAR, + UART_WRITE + }; + +#endif // SVC_INTERFACE_H -- cgit v1.2.3 From eae54c24e2e2b89f399bc2d3be195468c2e462a5 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 14:40:26 +0100 Subject: stop direct uart usage from PL0 --- Makefile | 2 +- demo_functionality.c | 14 ++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 48bbd14..c3fc2f1 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ ARM_OBJECTS=kernel.o paging.o demo_functionality.o PL0_test.o uart.o loader_stag KERNEL_STAGE2_OBJECTS=setup.o interrupt_vector.o interrupts.o uart.o demo_functionality.o paging.o ramfs_embeddable.o ramfs.o -PL_0_TEST_OBJECTS=PL0_utils.o svc.o PL0_test.o uart.o +PL_0_TEST_OBJECTS=PL0_utils.o svc.o PL0_test.o RAMFS_FILES=PL_0_test.img diff --git a/demo_functionality.c b/demo_functionality.c index 12bba9b..d8fbdb5 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -75,30 +75,20 @@ void demo_setup_PL0(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 - PL0_section = *PL0_section_entry, - UART_memory_section = *UART_memory_section_entry; + short_section_descriptor_t PL0_section = *PL0_section_entry; // set up address of PL0 section PL0_section.SECTION_BASE_ADDRESS_31_20 = UNPRIVILEGED_MEMORY_START >> 20; - // make the selected section and uart section available for PL0 + // make the selected section available for PL0 PL0_section.ACCESS_PERMISSIONS_2 = AP_2_0_MODEL_RW_ALL >> 2; PL0_section.ACCESS_PERMISSIONS_1_0 = AP_2_0_MODEL_RW_ALL & 0b011; - UART_memory_section.ACCESS_PERMISSIONS_2 = - AP_2_0_MODEL_RW_ALL >> 2; - 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" -- cgit v1.2.3 From c9e045dc2170a99c9f32386e3e53aee9e01a8e7c Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 17:34:23 +0100 Subject: io api rework --- Makefile | 10 ++++--- PL0_test.c | 6 ++--- PL0_utils.c | 14 +++------- PL0_utils.h | 6 +---- demo_functionality.c | 52 ++++++++++++++++++------------------- interrupts.c | 20 +++++++------- io.c | 64 +++++++++++++++++++++++++++++++++++++++++++++ io.h | 26 +++++++++++++++++++ loader_stage2.c | 11 ++++---- memory.h | 2 ++ paging.c | 27 ++++++++----------- setup.c | 13 +++++----- strings.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ strings.h | 22 +++++++++++----- uart.c | 10 ++----- uart.h | 5 ++-- 16 files changed, 258 insertions(+), 103 deletions(-) create mode 100644 io.c create mode 100644 io.h create mode 100644 strings.c diff --git a/Makefile b/Makefile index c3fc2f1..1e8f8fe 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,11 @@ ELFFLAGS=-nostdlib -lgcc ARM_OBJECTS=kernel.o paging.o demo_functionality.o PL0_test.o uart.o loader_stage1.o loader_stage2.o -KERNEL_STAGE2_OBJECTS=setup.o interrupt_vector.o interrupts.o uart.o demo_functionality.o paging.o ramfs_embeddable.o ramfs.o +KERNEL_STAGE2_OBJECTS=setup.o interrupt_vector.o interrupts.o uart.o demo_functionality.o paging.o ramfs_embeddable.o ramfs.o strings.o io.o -PL_0_TEST_OBJECTS=PL0_utils.o svc.o PL0_test.o +PL_0_TEST_OBJECTS=PL0_utils.o svc.o PL0_test.o strings.o io.o + +LOADER_STAGE2_OBJECTS=uart.o strings.o io.o loader_stage2.o RAMFS_FILES=PL_0_test.img @@ -41,8 +43,8 @@ kernel_stage2.elf : kernel_stage2.ld $(KERNEL_STAGE2_OBJECTS) #kernel.elf : boot.o kernel.o uart.o demo_functionality.o paging.o interrupt_vector.o interrupts.o ramfs_embeddable.o ramfs.o # arm-none-eabi-gcc -T linker.ld -o $@ $(ELFFLAGS) $^ -loader_stage2.elf : loader_stage2.o uart.o - arm-none-eabi-gcc -T loader_stage2_linker.ld -o $@ $(ELFFLAGS) $^ +loader_stage2.elf : loader_stage2_linker.ld $(LOADER_STAGE2_OBJECTS) + arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) $(LOADER_STAGE2_OBJECTS) loader_stage1.o : loader_stage1.S loader_stage2.img arm-none-eabi-as -mcpu=cortex-a7 $< -o $@ diff --git a/PL0_test.c b/PL0_test.c index f476eb7..ac74ad4 100644 --- a/PL0_test.c +++ b/PL0_test.c @@ -15,15 +15,15 @@ void PL0_main(void) first_kernel_byte[0] = *(char*) 0x0; first_kernel_byte[1] = '\0'; - uart_puts(first_kernel_byte); + puts(first_kernel_byte); while (1) { char c = getchar(); - - putchar(c); if (c == '\r') putchar('\n'); + + putchar(c); } } diff --git a/PL0_utils.c b/PL0_utils.c index 2cede90..d83edb9 100644 --- a/PL0_utils.c +++ b/PL0_utils.c @@ -2,26 +2,18 @@ #include #include "svc_interface.h" +#include "PL0_utils.h" // most generic definition possible // the actual function defined in svc.S uint32_t svc(enum svc_type, ...); -void putchar(int character) +void putchar(char character) { svc(UART_PUTCHAR, character); } -int getchar(void) +char getchar(void) { return svc(UART_GETCHAR); } - -void puts(char *string) -{ - for (size_t i = 0; string[i]; i++) - putchar(string[i]); - - putchar('\n'); - putchar('\r'); -} diff --git a/PL0_utils.h b/PL0_utils.h index ba72fd3..c26a100 100644 --- a/PL0_utils.h +++ b/PL0_utils.h @@ -1,10 +1,6 @@ #ifndef PL0_UTILS_H #define PL0_UTILS_H -void putchar(int character); - -int getchar(void); - -void puts(char *string); +#include "io.h" #endif // PL0_UTILS_H diff --git a/demo_functionality.c b/demo_functionality.c index d8fbdb5..2db40f8 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -1,4 +1,4 @@ -#include "uart.h" +#include "io.h" #include "psr.h" #include "memory.h" #include "translation_table_descriptors.h" @@ -14,16 +14,16 @@ void demo_paging_support(void) switch(ID_MMFR0 & 0xf) /* lowest 4 bits indicate VMSA support */ { - case 0 : paging = "no paging\n\r"; break; - case 1 : paging = "implementation defined paging\n\r"; break; - case 2 : paging = "VMSAv6, with cache and TLB type registers\n\r"; break; - case 3 : paging = "VMSAv7, with support for remapping and access flag\n\r"; break; - case 4 : paging = "VMSAv7 with PXN bit supported\n\r"; break; - case 5 : paging = "VMSAv7, PXN and long format descriptors. EPAE is supported.\n\r"; break; - default : paging = "?_? unknown paging ?_?\n\r"; + case 0 : paging = "no paging"; break; + case 1 : paging = "implementation defined paging"; break; + case 2 : paging = "VMSAv6, with cache and TLB type registers"; break; + case 3 : paging = "VMSAv7, with support for remapping and access flag"; break; + case 4 : paging = "VMSAv7 with PXN bit supported"; break; + case 5 : paging = "VMSAv7, PXN and long format descriptors. EPAE is supported."; break; + default : paging = "?_? unknown paging ?_?"; } - uart_puts(paging); + puts(paging); } void demo_current_mode(void) @@ -37,20 +37,20 @@ void demo_current_mode(void) switch(CPSR.fields.PSR_MODE_4_0) { - case MODE_USER : mode_name = "User (PL0)\r\n"; break; - case MODE_FIQ : mode_name = "FIQ (PL1)\r\n"; break; - case MODE_IRQ : mode_name = "IRQ (PL1)\r\n"; break; - case MODE_SUPERVISOR : mode_name = "Supervisor (PL1)\r\n"; break; - case MODE_MONITOR : mode_name = "Monitor (PL1)\r\n"; break; - case MODE_ABORT : mode_name = "Abort (PL1)\r\n"; break; - case MODE_HYPERVISOR : mode_name = "Hyp (PL2)\r\n"; break; - case MODE_UNDEFINED : mode_name = "Undefined (PL1)\r\n"; break; - case MODE_SYSTEM : mode_name = "System (PL1)\r\n"; break; - default : mode_name = "Unknown mode\r\n"; break; + case MODE_USER : mode_name = "User (PL0)"; break; + case MODE_FIQ : mode_name = "FIQ (PL1)"; break; + case MODE_IRQ : mode_name = "IRQ (PL1)"; break; + case MODE_SUPERVISOR : mode_name = "Supervisor (PL1)"; break; + case MODE_MONITOR : mode_name = "Monitor (PL1)"; break; + case MODE_ABORT : mode_name = "Abort (PL1)"; break; + case MODE_HYPERVISOR : mode_name = "Hyp (PL2)"; break; + case MODE_UNDEFINED : mode_name = "Undefined (PL1)"; break; + case MODE_SYSTEM : mode_name = "System (PL1)"; break; + default : mode_name = "Unknown mode"; break; } - uart_puts("current mode: "); - uart_puts(mode_name); + prints("current mode: "); + puts(mode_name); } #define TRANSLATION_TABLE \ @@ -69,7 +69,7 @@ void demo_setup_PL0(void) if (find_file(&_binary_ramfs_img_start, "PL_0_test.img", &PL_0_test_img)) { - uart_puts("PL_0_test.img not found :(\r\n"); + puts("PL_0_test.img not found :("); asm volatile ("wfi"); } @@ -96,20 +96,20 @@ void demo_setup_PL0(void) // check that translation works... by copying a string using one // mapping and reading it using other :D - char message[] = "mapped sections for PL0 code\n\r"; + char message[] = "mapped sections for PL0 code"; unsigned int i; for (i = 0; i < sizeof(message); i++) ((volatile char*) UNPRIVILEGED_MEMORY_START)[i] = message[i]; - uart_puts((char*) VIRTUAL_PL0_MEMORY_START); + puts((char*) VIRTUAL_PL0_MEMORY_START); // now paste a userspace program to that section for (uint32_t i = 0; i < PL_0_test_img.file_size; i++) ((volatile char*) VIRTUAL_PL0_MEMORY_START)[i] = PL_0_test_img.file_contents[i]; - uart_puts("copied PL0 code to it's section\n\r"); + puts("copied PL0 code to it's section"); } // needed for array initialization in demo_go_unprivileged() @@ -132,7 +132,7 @@ void demo_go_unprivileged(void) new_SPSR.fields.PSR_MODE_4_0 = MODE_USER; write_SPSR(new_SPSR); - uart_puts("All ready, jumping to PL0 code\n\r"); + puts("All ready, jumping to PL0 code"); asm volatile("cps %[sysmode]\n\r" "mov sp, %[stackaddr]\n\r" diff --git a/interrupts.c b/interrupts.c index f47bc1d..3102761 100644 --- a/interrupts.c +++ b/interrupts.c @@ -1,4 +1,4 @@ -#include "uart.h" +#include "io.h" #include "svc_interface.h" void setup(void); @@ -18,7 +18,7 @@ void reset_handler(void) void undefined_instruction_vector(void) { - uart_puts("Undefined instruction occured"); + puts("Undefined instruction occured"); while( 1 ) { /* Do Nothing! */ @@ -32,16 +32,16 @@ uint32_t supervisor_call_handler(enum svc_type request, uint32_t arg1, switch(request) { case UART_PUTCHAR: - uart_putc(arg1); + putchar(arg1); break; case UART_GETCHAR: - return uart_getc(); + return getchar(); case UART_WRITE: - uart_puts("UART_WRITE not implemented!!!!!\n\r"); + puts("UART_WRITE not implemented!!!!!"); break; default: // perhaps we should kill the process now? - uart_puts("unknown supervisor call type!!!!!\n\r"); + puts("unknown supervisor call type!!!!!"); } return 0; // a dummy value @@ -49,28 +49,28 @@ uint32_t supervisor_call_handler(enum svc_type request, uint32_t arg1, void abort_handler(void) { - uart_puts("re-entered system\n\r"); + puts("re-entered system"); while(1); } void generic_handler(void) { - uart_puts("something weird happened\n\r"); + puts("something weird happened"); while(1); } void irq_handler(void) { - uart_puts("irq happened\n\r"); + puts("irq happened"); while(1); } void fiq_handler(void) { - uart_puts("fiq happened\n\r"); + puts("fiq happened"); while(1); } diff --git a/io.c b/io.c new file mode 100644 index 0000000..f35fda9 --- /dev/null +++ b/io.c @@ -0,0 +1,64 @@ +#include + +#include "io.h" +#include "strings.h" + +void puts(char string[]) +{ + prints(string); + + putchar('\n'); + putchar('\r'); +} + +void prints(char string[]) +{ + for (size_t i = 0; string[i]; i++) + putchar(string[i]); +} + +void printdec(uint32_t number) +{ + char buf[11]; + + uint32_to_decstring(number, buf); + + prints(buf); +} + +void printhex(uint32_t number) +{ + char buf[9]; + + uint32_to_hexstring(number, buf); + + prints(buf); +} + +void printbin(uint32_t number) +{ + char buf[33]; + + uint32_to_binstring(number, buf); + + prints(buf); +} + +void printdect(uint32_t number) +{ + char buf[11]; + + uint32_to_decstringt(number, buf); + + prints(buf); +} + +void printhext(uint32_t number) +{ + char buf[9]; + + uint32_to_hexstringt(number, buf); + + prints(buf); +} + diff --git a/io.h b/io.h new file mode 100644 index 0000000..161728a --- /dev/null +++ b/io.h @@ -0,0 +1,26 @@ +#ifndef IO_H +#define IO_H + +#include + +// putchar() and getchar() are not part of io.c, but it's useful to +// have those symbols declared here +void putchar(char c); + +char getchar(void); + +void puts(char string[]); + +void prints(char string[]); + +void printdec(uint32_t number); + +void printhex(uint32_t number); + +void printbin(uint32_t number); + +void printdect(uint32_t number); + +void printhext(uint32_t number); + +#endif // IO_H diff --git a/loader_stage2.c b/loader_stage2.c index f49d94c..e05de51 100644 --- a/loader_stage2.c +++ b/loader_stage2.c @@ -1,6 +1,7 @@ #include #include #include +#include #include void *const kernel_load_addr = ((void*) 0x8000); @@ -17,10 +18,10 @@ void _stage2_main(uint32_t r0, uint32_t r1, uint32_t atags) // get kernel size via uart (little endian) uint32_t b0, b1, b2, b3; - b0 = uart_getc(); - b1 = uart_getc(); - b2 = uart_getc(); - b3 = uart_getc(); + b0 = getchar(); + b1 = getchar(); + b2 = getchar(); + b3 = getchar(); uint32_t kernel_size = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); @@ -28,7 +29,7 @@ void _stage2_main(uint32_t r0, uint32_t r1, uint32_t atags) char *dst = kernel_load_addr, *end = dst + kernel_size; while (dst < end) - *(dst++) = uart_getc(); + *(dst++) = getchar(); // jump to kernel ((void(*)(uint32_t, uint32_t, uint32_t)) kernel_load_addr) diff --git a/memory.h b/memory.h index adc3bc0..f6ece42 100644 --- a/memory.h +++ b/memory.h @@ -1,6 +1,8 @@ #ifndef MEMORY_H #define MEMORY_H +#include + // These macros were heavily used b4 I moved all the address // computation to the linker script. Now I'm just keeping them // in case they're needed for something else :) diff --git a/paging.c b/paging.c index 7c2a9de..2985e7e 100644 --- a/paging.c +++ b/paging.c @@ -1,24 +1,21 @@ #include "cp_regs.h" -#include "uart.h" #include "strings.h" #include "memory.h" #include "translation_table_descriptors.h" +#include "io.h" void setup_flat_map(void) { - char bits[33]; // for printing uint32_t bit values - // compute translation table base address // translation table shall start at first 2^14-bytes aligned // address after the kernel image - uint32_to_bits(TRANSLATION_TABLE_BASE, bits); - uart_puts("binary representation of chosen" - " lvl1 translation table address: "); - uart_puts(bits); uart_puts("\n\r"); + prints("chosen lvl1 translation table address: 0x"); + printhex(TRANSLATION_TABLE_BASE); + puts(""); // flat map all memory - uart_puts("preparing translation table\n\r"); + puts("preparing translation table"); short_descriptor_lvl1_t volatile *translation_table = (short_descriptor_lvl1_t*) TRANSLATION_TABLE_BASE; @@ -35,8 +32,7 @@ void setup_flat_map(void) }; // meddle with domain settings - uart_puts("setting domain0 to client access" - " and blocking other domains\n\r"); + puts("setting domain0 to client access and blocking other domains"); DACR_t DACR = 0; DACR = set_domain_permissions(DACR, 0, DOMAIN_CLIENT_ACCESS); @@ -55,7 +51,7 @@ void setup_flat_map(void) // we also disable data and instruction caches and the MMU // some of this is redundant (i.e. MMU should already be disabled) - uart_puts("setting C, I, AFE and TRE to 0 in SCTLR\n\r"); + puts("setting C, I, AFE and TRE to 0 in SCTLR"); SCTLR_t SCTLR; asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR.raw)); @@ -70,8 +66,8 @@ void setup_flat_map(void) // TODO: move invalidation instructions to some header as inlines - uart_puts("invalidating instruction cache, branch prediction," - " and entire main TLB\n\r"); + puts("invalidating instruction cache, branch prediction," + " and entire main TLB"); // invalidate instruction cache asm("mcr p15, 0, r0, c7, c5, 0\n\r" // r0 gets ignored @@ -86,8 +82,7 @@ void setup_flat_map(void) "isb" :: "r" (0) : "memory"); // now set TTBCR to use TTBR0 exclusively - uart_puts("Setting TTBCR.N to 0, so that" - " TTBR0 is used everywhere\n\r"); + puts("Setting TTBCR.N to 0, so that TTBR0 is used everywhere"); uint32_t TTBCR = 0; asm("mcr p15, 0, %0, c2, c0, 2" :: "r" (TTBCR)); @@ -102,7 +97,7 @@ void setup_flat_map(void) asm("mcr p15, 0, %0, c2, c0, 0" :: "r" (TTBR0.raw)); // enable MMU - uart_puts("enabling the MMU\n\r"); + puts("enabling the MMU"); // redundant - we already have SCTLR contents in the variable // asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR.raw)); diff --git a/setup.c b/setup.c index 48df825..3542043 100644 --- a/setup.c +++ b/setup.c @@ -1,4 +1,5 @@ #include "uart.h" +#include "io.h" #include "demo_functionality.h" #include "paging.h" @@ -9,9 +10,9 @@ void setup(void) // 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 - uart_getc(); + getchar(); - uart_puts("Hello, kernel World!\r\n"); + puts("Hello, kernel World!"); // prints some info demo_paging_support(); @@ -31,11 +32,11 @@ void setup(void) while (1) { - char c = uart_getc(); + char c = getchar(); - uart_putc(c); - if (c == '\r') - uart_putc('\n'); + putchar('\n'); + + putchar(c); } } diff --git a/strings.c b/strings.c new file mode 100644 index 0000000..55aff97 --- /dev/null +++ b/strings.c @@ -0,0 +1,73 @@ +#include + +#include "strings.h" + +void uint32_to_dec(uint32_t number, char buf[10]) +{ + for (int i = 0; i < 10; i++) + { + buf[10 - 1 - i] = number % 10; + number /= 10; + } +} + +void uint32_to_hex(uint32_t number, char buf[8]) +{ + for (int i = 0; i < 8; i++) + { + unsigned char quadbit = (number >> ((8 - i - 1) * 4)) & 0xf; + buf[i] = quadbit > 9 ? quadbit - 10 + 'a' : quadbit + '0'; + } +} + +void uint32_to_bin(uint32_t number, char buf[32]) +{ + for (int i = 0; i < 32; i++) + buf[i] = ((number >> (32 - i - 1)) & 1) ? '1' : '0'; +} + +void uint32_to_decstring(uint32_t number, char buf[11]) +{ + uint32_to_dec(number, buf); + buf[10] = '\0'; +} + +void uint32_to_hexstring(uint32_t number, char buf[9]) +{ + uint32_to_hex(number, buf); + buf[9] = '\0'; +} + +void uint32_to_binstring(uint32_t number, char buf[33]) +{ + uint32_to_bin(number, buf); + buf[32] = '\0'; +} + +void trim_0s(char string[]) +{ + size_t i; + for (i = 0; string[i] != '\0' && string[i] != '0'; i++); + + size_t j = 0; + + if (string[i] == '\0') + string[j++] = string[i--]; + + do + string[j] = string[i + j]; + while (string[j++]); +} + +void uint32_to_decstringt(uint32_t number, char buf[11]) +{ + uint32_to_decstring(number, buf); + trim_0s(buf); +} + +void uint32_to_hexstringt(uint32_t number, char buf[9]) +{ + uint32_to_hexstring(number, buf); + trim_0s(buf); +} + diff --git a/strings.h b/strings.h index 8d4b511..bfe6fd0 100644 --- a/strings.h +++ b/strings.h @@ -3,12 +3,22 @@ #include -static inline void uint32_to_bits(uint32_t number, char *buf) -{ - for (int i = 0; i < 32; i++) - buf[i] = ((number >> (32 - i - 1)) & 1) ? '1' : '0'; +void uint32_to_dec(uint32_t number, char buf[10]); - buf[32] = '\0'; -} +void uint32_to_hex(uint32_t number, char buf[8]); + +void uint32_to_bin(uint32_t number, char buf[32]); + +void uint32_to_decstring(uint32_t number, char buf[11]); + +void uint32_to_hexstring(uint32_t number, char buf[9]); + +void uint32_to_binstring(uint32_t number, char buf[33]); + +void trim_0s(char string[]); + +void uint32_to_decstringt(uint32_t number, char buf[11]); + +void uint32_to_hexstringt(uint32_t number, char buf[9]); #endif // STRINGS_H diff --git a/uart.c b/uart.c index 139cfe0..2030538 100644 --- a/uart.c +++ b/uart.c @@ -63,22 +63,16 @@ void uart_init() mmio_write(UART0_CR, (1 << 0) | (1 << 8) | (1 << 9)); } -void uart_putc(unsigned char c) +void putchar(char c) { // Wait for UART to become ready to transmit. while ( mmio_read(UART0_FR) & (1 << 5) ) { } mmio_write(UART0_DR, c); } -unsigned char uart_getc() +char getchar(void) { // Wait for UART to have received something. while ( mmio_read(UART0_FR) & (1 << 4) ) { } return mmio_read(UART0_DR); } - -void uart_puts(const char* str) -{ - for (size_t i = 0; str[i] != '\0'; i ++) - uart_putc((unsigned char)str[i]); -} diff --git a/uart.h b/uart.h index ec29d47..d5e931b 100644 --- a/uart.h +++ b/uart.h @@ -39,8 +39,7 @@ enum }; void uart_init(); -void uart_putc(unsigned char c); -unsigned char uart_getc(); -void uart_puts(const char* str); +void putchar(char c); +char getchar(void); #endif // UART_H -- cgit v1.2.3 From 68d11d4c42d6e82629e7a38e34c358d7d501e865 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 17:36:51 +0100 Subject: minor improvements to Makefile --- Makefile | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 1e8f8fe..6963722 100644 --- a/Makefile +++ b/Makefile @@ -34,23 +34,17 @@ kernel_stage1.o : kernel_stage1.S kernel_stage2.img kernel.elf : kernel_stage1.ld kernel_stage1.o arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) kernel_stage1.o -kernel.img : kernel.elf - arm-none-eabi-objcopy $^ -O binary $@ - kernel_stage2.elf : kernel_stage2.ld $(KERNEL_STAGE2_OBJECTS) arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) $(KERNEL_STAGE2_OBJECTS) -#kernel.elf : boot.o kernel.o uart.o demo_functionality.o paging.o interrupt_vector.o interrupts.o ramfs_embeddable.o ramfs.o -# arm-none-eabi-gcc -T linker.ld -o $@ $(ELFFLAGS) $^ - loader_stage2.elf : loader_stage2_linker.ld $(LOADER_STAGE2_OBJECTS) arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) $(LOADER_STAGE2_OBJECTS) loader_stage1.o : loader_stage1.S loader_stage2.img arm-none-eabi-as -mcpu=cortex-a7 $< -o $@ -loader.elf : loader_stage1.o - arm-none-eabi-gcc -T loader_stage1_linker.ld -o $@ $(ELFFLAGS) $^ +loader.elf : loader_stage1_linker.ld loader_stage1.o + arm-none-eabi-gcc -T $< -o $@ $(ELFFLAGS) loader_stage1.o loader.img : loader.elf arm-none-eabi-objcopy $^ -O binary $@ -- cgit v1.2.3 From 7745bb422f98730d6b555e4ab135ba6ca7479d7a Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 17:38:24 +0100 Subject: better naming of qemu-* targets --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6963722..ecf2b2f 100644 --- a/Makefile +++ b/Makefile @@ -54,10 +54,10 @@ loader.img : loader.elf qemu-elf : kernel.elf qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $^ -qemu-img : kernel.img +qemu-bin : kernel.img qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $^ -qemu-bin : loader.img kernel.img pipe_image +qemu-loader : loader.img kernel.img pipe_image ./pipe_image --stdout | qemu-system-arm -m 256 -M raspi2 -serial stdio -kernel $< run-on-rpi : kernel.img pipe_image -- cgit v1.2.3 From 142439f7240bf796dba4ed4e570c6df0a33997b1 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 20:16:44 +0100 Subject: uint32_to_hexstring() bugfix --- strings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings.c b/strings.c index 55aff97..34c269a 100644 --- a/strings.c +++ b/strings.c @@ -35,7 +35,7 @@ void uint32_to_decstring(uint32_t number, char buf[11]) void uint32_to_hexstring(uint32_t number, char buf[9]) { uint32_to_hex(number, buf); - buf[9] = '\0'; + buf[8] = '\0'; } void uint32_to_binstring(uint32_t number, char buf[33]) -- cgit v1.2.3 From 7efc53fe9a593eab08400c18e6b0def30c17e684 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 23:23:11 +0100 Subject: don't mark used values as unused --- loader_stage2.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/loader_stage2.c b/loader_stage2.c index e05de51..15d2003 100644 --- a/loader_stage2.c +++ b/loader_stage2.c @@ -8,11 +8,6 @@ void *const kernel_load_addr = ((void*) 0x8000); void _stage2_main(uint32_t r0, uint32_t r1, uint32_t atags) { - // Declare as unused - (void) r0; - (void) r1; - (void) atags; - uart_init(); // get kernel size via uart (little endian) -- cgit v1.2.3 From 6421fd0e09448ed9134dab3338cfdda848a8eeaa Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 23:23:30 +0100 Subject: preserve atags for stage2 --- kernel_stage1.S | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/kernel_stage1.S b/kernel_stage1.S index 1e0f614..dd3e6fd 100644 --- a/kernel_stage1.S +++ b/kernel_stage1.S @@ -20,8 +20,105 @@ _boot: // occur when the main core overwrites this part of memory wfe + // we'll use the size of stage1 to determine where we have free + // space after it. We'll then copy our atags/fdt there, so + // it doesn't get overwritten by stage2 we deploy at 0x0 +atags_magic: + .word 0x54410001 + proceed: - // copy stage2 of the kernel to address 0x0 + // load the second word of structure passed to us through r2; + // if it's atags, it's second word should be the magic number + // Btw, location of ATAGS is always 0x100. + ldr r3, [r2, #4] + adr r4, atags_magic + ldr r4, [r4] + + // compare second word of assumed atags with magic number + // to see, if it's really atags and not sth else (i.e. fdt) + cmp r3, r4 + + // normally at start r0 contains value 0; + // value 3 in r0 would tell stage2 code, we found no atags :( + movne r0, #3 + bne stage2_blob_copying + + // if atags was found, copying of it takes place here + + // the following loop finds, where atags ends + // r3 shall point to currently looked-at tag + mov r3, r2 + +find_end_of_atags_loop: + // load first word of tag header to r4 (it contains tag size) + ldr r4, [r3] + // make r3 point at the next tag (by adding 4*tag_size to it) + add r3, r4, lsl #2 + + // load second word of tag header to r5 (it contains tag type) + ldr r5, [r3, #4] + + // if tag value is 0, it is the last tag + cmp r5, #0 + bne find_end_of_atags_loop + + add r3, #8 // make r3 point at the end of last tag + sub r3, r2 // get atags size in r3 + + // at this pont r2 and r3 point at start and size of atags, + // respectively; now we'll compute, where we're going to have + // free space to put atags in; we want to put atags either + // right after our blob or, if if it doesn't fit between + // blob end and the address stage1 is loaded at, after stage1 + + // get blob size to r5 + adr r5, blob_size + ldr r5, [r5] + + // we could only copy atags to a 4-aligned address + mov r6, #4 + bl aling_r5_to_r6 + + // compute where atags copied right after blob would end + add r6, r5, r3 + // we can only overwrite stuff before the copying loop + adr r7, copy_atags_loop + cmp r6, r7 + ble copy_atags + + // atags wouldn't fit - use memory after stage1 as destination + adr r5, _boot + adr r6, stage1_size + ldr r6, [r6] + add r5, r6 + mov r6, #4 + bl aling_r5_to_r6 + +copy_atags: + // now copy atags (r2 - atags start; r3 - atags size; + // r5 - destination; r4 - iterator; r6 - buffor) + mov r4, #0 + +copy_atags_loop: + ldr r6, [r2, r4] + str r6, [r5, r4] + add r4, #4 + cmp r4, r3 + blo copy_atags_loop + + mov r2, r5 // place the new atags address in r2 + b stage2_blob_copying // atags stuff done; proceed + +// mini-function, that does what the label says; clobbers r7 +aling_r5_to_r6: + sub r5, #1 + sub r7, r6, #1 + bic r5, r7 + add r5, r6 + mov pc, lr + + +stage2_blob_copying: // copy stage2 of the kernel to address 0x0 // first, load address of stage2_start to r3 (a PIC way) adr r3, stage2_start @@ -47,6 +144,8 @@ proceed: blob_size: .word stage2_end - stage2_start +stage1_size: + .word stage1_end - _boot .align 4 stage2_start: @@ -61,7 +160,9 @@ loop: add r6, r6, #4 cmp r6, r5 blo loop - + // Call stage2 of the kernel (branch to 0x0, // which is the reset handler). bx r4 + +stage1_end: -- cgit v1.2.3 From a2885ace9af6b78172837734ddd3a0ea269e1734 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 23:40:08 +0100 Subject: fix number trimming --- strings.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/strings.c b/strings.c index 34c269a..fb3b0ac 100644 --- a/strings.c +++ b/strings.c @@ -47,12 +47,12 @@ void uint32_to_binstring(uint32_t number, char buf[33]) void trim_0s(char string[]) { size_t i; - for (i = 0; string[i] != '\0' && string[i] != '0'; i++); - + for (i = 0; string[i] == '0'; i++); + size_t j = 0; - if (string[i] == '\0') - string[j++] = string[i--]; + if (!string[i]) + string[j++] = string[--i]; do string[j] = string[i + j]; -- cgit v1.2.3 From 28bbb56f349721bf8d2b7221427e925a3960f8da Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Mon, 30 Dec 2019 23:41:04 +0100 Subject: inform about values passed to the kernel --- setup.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/setup.c b/setup.c index 3542043..be71547 100644 --- a/setup.c +++ b/setup.c @@ -3,17 +3,28 @@ #include "demo_functionality.h" #include "paging.h" -void setup(void) +void setup(uint32_t r0, uint32_t machine_type, + uint32_t atags) { uart_init(); // 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!"); + prints("ARM machine type: 0x"); printhext(machine_type); puts(""); + + // value 3 introduced by stage1 code, means no atags was found + if (r0 == 3) + puts("No ATAGS was found!"); + else + { + prints("ATAGS copied to 0x"); printhex(atags); puts(""); + } + // prints some info demo_paging_support(); -- cgit v1.2.3 From 47cebef7a2e4dd66be9f7f6b0b8e8cadfeb6064a Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 10:32:47 +0100 Subject: add strlen implementation --- strings.c | 8 ++++++++ strings.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/strings.c b/strings.c index fb3b0ac..7c87e29 100644 --- a/strings.c +++ b/strings.c @@ -71,3 +71,11 @@ void uint32_to_hexstringt(uint32_t number, char buf[9]) trim_0s(buf); } +size_t strlen(char string[]) +{ + size_t len; + + for (len = 0; string[len]; len++); + + return len; +} diff --git a/strings.h b/strings.h index bfe6fd0..7e772d3 100644 --- a/strings.h +++ b/strings.h @@ -21,4 +21,6 @@ void uint32_to_decstringt(uint32_t number, char buf[11]); void uint32_to_hexstringt(uint32_t number, char buf[9]); +size_t strlen(char string[]); + #endif // STRINGS_H -- cgit v1.2.3 From 1126a18822701632e5914e441386c7fa5d2cf474 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 10:35:00 +0100 Subject: fix number to decimal string conversion --- strings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strings.c b/strings.c index 7c87e29..4164467 100644 --- a/strings.c +++ b/strings.c @@ -6,7 +6,7 @@ void uint32_to_dec(uint32_t number, char buf[10]) { for (int i = 0; i < 10; i++) { - buf[10 - 1 - i] = number % 10; + buf[10 - 1 - i] = '0' + (number % 10); number /= 10; } } -- cgit v1.2.3 From 254e035cc27d5787348849b65619a702ae0d42e3 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 10:42:17 +0100 Subject: handle atags in C code, print (some of) it's contents --- Makefile | 2 +- atags.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ atags.h | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ setup.c | 14 +++++++-- 4 files changed, 213 insertions(+), 4 deletions(-) create mode 100644 atags.c create mode 100644 atags.h diff --git a/Makefile b/Makefile index ecf2b2f..feedd79 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ ELFFLAGS=-nostdlib -lgcc ARM_OBJECTS=kernel.o paging.o demo_functionality.o PL0_test.o uart.o loader_stage1.o loader_stage2.o -KERNEL_STAGE2_OBJECTS=setup.o interrupt_vector.o interrupts.o uart.o demo_functionality.o paging.o ramfs_embeddable.o ramfs.o strings.o io.o +KERNEL_STAGE2_OBJECTS=setup.o interrupt_vector.o interrupts.o uart.o demo_functionality.o paging.o ramfs_embeddable.o ramfs.o strings.o io.o atags.o PL_0_TEST_OBJECTS=PL0_utils.o svc.o PL0_test.o strings.o io.o diff --git a/atags.c b/atags.c new file mode 100644 index 0000000..9b88724 --- /dev/null +++ b/atags.c @@ -0,0 +1,99 @@ +#include "atags.h" +#include "io.h" + +static inline struct atag_header *next_tag(struct atag_header *tag) +{ + return (struct atag_header*) (((uint32_t*) tag) + tag->size); +} + +#define TAG_CONTENTS_FUN(tagname) \ + static inline struct atag_##tagname *tagname##_tag_contents \ + (struct atag_header *tag) \ + { \ + return (struct atag_##tagname*) (tag + 1); \ + } + +TAG_CONTENTS_FUN(header) +TAG_CONTENTS_FUN(core) +TAG_CONTENTS_FUN(mem) +TAG_CONTENTS_FUN(videotext) +TAG_CONTENTS_FUN(ramdisk) +TAG_CONTENTS_FUN(initrd2) +TAG_CONTENTS_FUN(serialnr) +TAG_CONTENTS_FUN(revision) +TAG_CONTENTS_FUN(videolfb) +TAG_CONTENTS_FUN(cmdline) + +uint32_t find_memory_size(struct atag_header *atags) +{ + // we silently assume there will only be one mem atag + while (atags->tag != ATAG_MEM && atags->tag != ATAG_NONE) + atags = next_tag(atags); + + if (atags->tag == ATAG_NONE) + return 0; + + struct atag_mem *mem_tag = mem_tag_contents(atags); + + // our design assumes address 0x0 is available, so we reject mem + // atag saying otherwise + if (mem_tag->start != 0) + return 0; + + return mem_tag->size; +} + +void print_tag(struct atag_header *tag) +{ +#define TAG_CASE(tagname_upcase, tagname_locase, instructions) \ + case ATAG_##tagname_upcase: \ + puts("ATAG_" #tagname_upcase ":"); \ + { \ + struct atag_##tagname_locase *contents = \ + tagname_locase##_tag_contents(tag); \ + instructions; \ + } \ + break + + switch (tag->tag) + { + TAG_CASE(CORE, core, + prints(" flags: 0x"); + printhex(contents->flags); puts(""); + prints(" page size: "); + printdec(contents->pagesize); puts(""); + prints(" root device: "); + printdec(contents->rootdev); puts("");); + TAG_CASE(MEM, mem, + prints(" memory size: 0x"); + printhex(contents->size); puts(""); + prints(" memory start: 0x"); + printhex(contents->start); puts("");); + // the rest are unimportant for now, + // as they're not passed by qemu + TAG_CASE(VIDEOTEXT, videotext, (void) contents;); + TAG_CASE(RAMDISK, ramdisk, (void) contents;); + TAG_CASE(INITRD2, initrd2, (void) contents;); + TAG_CASE(SERIAL, serialnr, (void) contents;); + TAG_CASE(REVISION, revision, (void) contents;); + TAG_CASE(VIDEOLFB, videolfb, (void) contents;); + TAG_CASE(CMDLINE, cmdline, (void) contents;); + + case ATAG_NONE: + puts("ATAG_NONE"); + break; + default: + prints("!! unknown tag: 0x"); printhex(tag->tag); puts(" !!"); + } +} + +void print_atags(struct atag_header *atags) +{ + while (atags->tag != ATAG_NONE) + { + print_tag(atags); + atags = next_tag(atags); + } + + print_tag(atags); // also print ATAG_NONE +} diff --git a/atags.h b/atags.h new file mode 100644 index 0000000..4b6879f --- /dev/null +++ b/atags.h @@ -0,0 +1,102 @@ +#ifndef ATAGS_H +#define ATAGS_H + +#include + +#define ATAG_NONE 0x00000000 +#define ATAG_CORE 0x54410001 +#define ATAG_MEM 0x54410002 +#define ATAG_VIDEOTEXT 0x54410003 +#define ATAG_RAMDISK 0x54410004 +#define ATAG_INITRD2 0x54420005 +#define ATAG_SERIAL 0x54410006 +#define ATAG_REVISION 0x54410007 +#define ATAG_VIDEOLFB 0x54410008 +#define ATAG_CMDLINE 0x54410009 + +struct atag_header +{ + uint32_t size; + uint32_t tag; +}; + +struct atag_core +{ + uint32_t flags; + uint32_t pagesize; + uint32_t rootdev; +}; + +struct atag_mem +{ + uint32_t size; + uint32_t start; +}; + +struct atag_videotext +{ + uint8_t x; + uint8_t y; + uint16_t video_page; + uint8_t video_mode; + uint8_t video_cols; + uint16_t video_ega_bx; + uint8_t video_lines; + uint8_t video_isvga; + uint16_t video_points; +}; + +struct atag_ramdisk +{ + uint32_t flags; + uint32_t size; + uint32_t start; +}; + +struct atag_initrd2 +{ + uint32_t start; + uint32_t size; +}; + +struct atag_serialnr +{ + uint32_t low; + uint32_t high; +}; + +struct atag_revision +{ + uint32_t rev; +}; + +struct atag_videolfb +{ + uint16_t lfb_width; + uint16_t lfb_height; + uint16_t lfb_depth; + uint16_t lfb_linelength; + uint32_t lfb_base; + uint32_t lfb_size; + uint8_t red_size; + uint8_t red_pos; + uint8_t green_size; + uint8_t green_pos; + uint8_t blue_size; + uint8_t blue_pos; + uint8_t rsvd_size; + uint8_t rsvd_pos; +}; + +struct atag_cmdline +{ + char cmdline[1]; +}; + +uint32_t find_memory_size(struct atag_header *atags); + +void print_tag(struct atag_header *tag); + +void print_atags(struct atag_header *atags); + +#endif // ATAGS_H diff --git a/setup.c b/setup.c index be71547..f0a9d0a 100644 --- a/setup.c +++ b/setup.c @@ -2,9 +2,10 @@ #include "io.h" #include "demo_functionality.h" #include "paging.h" +#include "atags.h" void setup(uint32_t r0, uint32_t machine_type, - uint32_t atags) + struct atag_header *atags) { uart_init(); @@ -17,12 +18,19 @@ void setup(uint32_t r0, uint32_t machine_type, prints("ARM machine type: 0x"); printhext(machine_type); puts(""); - // value 3 introduced by stage1 code, means no atags was found + // value 3 introduced by stage1 code means no atags was found if (r0 == 3) puts("No ATAGS was found!"); else { - prints("ATAGS copied to 0x"); printhex(atags); puts(""); + prints("ATAGS copied to 0x"); + printhex((uint32_t) atags); puts(""); + + puts("__ ATAGS contents __"); + + print_atags(atags); + + puts("__ end of ATAGS contents __"); } // prints some info -- cgit v1.2.3 From 8025e6b92a09fcf584c13fea3f04f2a0be9cbe64 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 11:05:33 +0100 Subject: add memcpy --- strings.c | 16 ++++++++++++++-- strings.h | 3 +++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/strings.c b/strings.c index 4164467..94cb6ac 100644 --- a/strings.c +++ b/strings.c @@ -1,5 +1,3 @@ -#include - #include "strings.h" void uint32_to_dec(uint32_t number, char buf[10]) @@ -79,3 +77,17 @@ size_t strlen(char string[]) return len; } + +void memcpy(void *dst, void *src, size_t nbytes) +{ + size_t iter; + + // copying by word is faster than by byte + // copy by word as much as possible + for (iter = 0; iter < nbytes / 4; iter++) + ((volatile uint32_t*) dst)[iter] = ((uint32_t*) src)[iter]; + + // copy the remaining 1, 2 or 3 bytes by byte + for (iter *= 4; iter < nbytes; iter++) + ((volatile uint8_t*) dst)[iter] = ((uint8_t*) src)[iter]; +} diff --git a/strings.h b/strings.h index 7e772d3..1eb291c 100644 --- a/strings.h +++ b/strings.h @@ -1,6 +1,7 @@ #ifndef STRINGS_H #define STRINGS_H +#include #include void uint32_to_dec(uint32_t number, char buf[10]); @@ -23,4 +24,6 @@ void uint32_to_hexstringt(uint32_t number, char buf[9]); size_t strlen(char string[]); +void memcpy(void *dst, void *src, size_t nbytes); + #endif // STRINGS_H -- cgit v1.2.3 From 455408524009bf6f62867b00bd5d6580bf79f3f0 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 11:05:46 +0100 Subject: use memcpy() --- demo_functionality.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/demo_functionality.c b/demo_functionality.c index 2db40f8..051ffd6 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -3,6 +3,7 @@ #include "memory.h" #include "translation_table_descriptors.h" #include "ramfs.h" +#include "strings.h" void demo_paging_support(void) { @@ -97,17 +98,14 @@ void demo_setup_PL0(void) // check that translation works... by copying a string using one // mapping and reading it using other :D char message[] = "mapped sections for PL0 code"; - - unsigned int i; - for (i = 0; i < sizeof(message); i++) - ((volatile char*) UNPRIVILEGED_MEMORY_START)[i] = message[i]; + + memcpy((void*) UNPRIVILEGED_MEMORY_START, message, sizeof(message)); puts((char*) VIRTUAL_PL0_MEMORY_START); // now paste a userspace program to that section - for (uint32_t i = 0; i < PL_0_test_img.file_size; i++) - ((volatile char*) VIRTUAL_PL0_MEMORY_START)[i] = - PL_0_test_img.file_contents[i]; + memcpy((void*) VIRTUAL_PL0_MEMORY_START, + PL_0_test_img.file_contents, PL_0_test_img.file_size); puts("copied PL0 code to it's section"); } -- cgit v1.2.3 From fa42eccf0b9c6161be0ad9e3c1b7f6489add2b2c Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 11:09:57 +0100 Subject: move memset() implementation to strings.c --- demo_functionality.c | 11 ----------- strings.c | 15 +++++++++++++++ strings.h | 2 ++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/demo_functionality.c b/demo_functionality.c index 051ffd6..7a9139c 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -110,17 +110,6 @@ void demo_setup_PL0(void) puts("copied PL0 code to it's section"); } -// needed for array initialization in demo_go_unprivileged() -void *memset(void *s, int c, size_t n) -{ - char *mem = s; - - for (size_t i = 0; i < n; i++) - mem[i] = c; - - return s; -} - void demo_go_unprivileged(void) { uint32_t PL0_regs[14] = {0}; diff --git a/strings.c b/strings.c index 94cb6ac..b518388 100644 --- a/strings.c +++ b/strings.c @@ -91,3 +91,18 @@ void memcpy(void *dst, void *src, size_t nbytes) for (iter *= 4; iter < nbytes; iter++) ((volatile uint8_t*) dst)[iter] = ((uint8_t*) src)[iter]; } + +// keep in mind memset is also needed for array initialization, like +// uint32_t buf[16] = {0}; +// gcc compiles this to memset call + +void *memset(void *s, int c, size_t n) +{ + volatile char *mem = s; + + for (size_t i = 0; i < n; i++) + mem[i] = c; + + return s; +} + diff --git a/strings.h b/strings.h index 1eb291c..3c49b7e 100644 --- a/strings.h +++ b/strings.h @@ -26,4 +26,6 @@ size_t strlen(char string[]); void memcpy(void *dst, void *src, size_t nbytes); +void *memset(void *s, int c, size_t n); + #endif // STRINGS_H -- cgit v1.2.3 From 9260694d7c18092f478f5d4ba142c12af83c067e Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 11:35:07 +0100 Subject: determine amount of memory available --- atags.c | 6 +++++- setup.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/atags.c b/atags.c index 9b88724..e2e6a24 100644 --- a/atags.c +++ b/atags.c @@ -38,7 +38,11 @@ uint32_t find_memory_size(struct atag_header *atags) // our design assumes address 0x0 is available, so we reject mem // atag saying otherwise if (mem_tag->start != 0) - return 0; + { + puts("ignoring information about memory, " + "that doesn't start at 0x0"); + return 0; + } return mem_tag->size; } diff --git a/setup.c b/setup.c index f0a9d0a..b7c03ad 100644 --- a/setup.c +++ b/setup.c @@ -3,6 +3,8 @@ #include "demo_functionality.h" #include "paging.h" #include "atags.h" +// for POWER_OF_2() macro... perhaps the macro should be moved +#include "memory.h" void setup(uint32_t r0, uint32_t machine_type, struct atag_header *atags) @@ -17,6 +19,8 @@ void setup(uint32_t r0, uint32_t machine_type, puts("Hello, kernel World!"); prints("ARM machine type: 0x"); printhext(machine_type); puts(""); + + uint32_t memory_size = 0; // value 3 introduced by stage1 code means no atags was found if (r0 == 3) @@ -31,8 +35,46 @@ void setup(uint32_t r0, uint32_t machine_type, print_atags(atags); puts("__ end of ATAGS contents __"); + + memory_size = find_memory_size(atags); } + if (memory_size) + { + char *unit; + uint32_t size_in_unit; + + if (memory_size % POWER_OF_2(10)) + { + unit = "B"; + size_in_unit = memory_size; + } + else if (memory_size % POWER_OF_2(20)) + { + unit = "KB"; + size_in_unit = memory_size / POWER_OF_2(10); + } + else if (memory_size % POWER_OF_2(30)) + { + unit = "MB"; + size_in_unit = memory_size / POWER_OF_2(20); + } + else + { + unit = "GB"; + size_in_unit = memory_size / POWER_OF_2(30); + } + + prints("memory available: "); + printdect(size_in_unit); puts(unit); + } + else + { + // Most Pis have move, but qemu might give us little + puts("Couldn't determine available memory - assuming 192MB"); + memory_size = 192 * POWER_OF_2(20); + } + // prints some info demo_paging_support(); -- cgit v1.2.3 From 5d4b43f71936baafdd80251751fc0c6b51b79fb9 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 11:39:02 +0100 Subject: typo --- setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.c b/setup.c index b7c03ad..0fd3522 100644 --- a/setup.c +++ b/setup.c @@ -70,7 +70,7 @@ void setup(uint32_t r0, uint32_t machine_type, } else { - // Most Pis have move, but qemu might give us little + // Most Pis have more, but qemu might give us little puts("Couldn't determine available memory - assuming 192MB"); memory_size = 192 * POWER_OF_2(20); } -- cgit v1.2.3 From 3387b288a53422131f22f1fc96168a128edc9902 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 12:04:14 +0100 Subject: remove misleading const --- memory.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/memory.h b/memory.h index f6ece42..7de556d 100644 --- a/memory.h +++ b/memory.h @@ -21,14 +21,14 @@ #define INTERRUPT_VECTOR_TABLE_START ((uint32_t) 0x0) // all those symbols are defined in the linker script -extern const char __end; -extern const char __start; -extern const char _translation_table_start; -extern const char _translation_table_end; -extern const char _stack_start; -extern const char _stack_top; -extern const char _unprivileged_memory_start; -extern const char _unprivileged_memory_end; +extern char __end; +extern char __start; +extern char _translation_table_start; +extern char _translation_table_end; +extern char _stack_start; +extern char _stack_top; +extern char _unprivileged_memory_start; +extern char _unprivileged_memory_end; #define KERNEL_START ((size_t) &__start) // this is 0x0 #define KERNEL_END ((size_t) &__end) -- cgit v1.2.3 From 7dcea5fdafe66d8bcf1eeacbaf3f3f3b1c258dfc Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 13:50:14 +0100 Subject: implement basic memory section allocation for processes --- kernel_stage2.ld | 12 ++++- memory.h | 6 +++ paging.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ paging.h | 8 ++++ 4 files changed, 157 insertions(+), 1 deletion(-) diff --git a/kernel_stage2.ld b/kernel_stage2.ld index dce2d1f..a30105e 100644 --- a/kernel_stage2.ld +++ b/kernel_stage2.ld @@ -1,6 +1,7 @@ /* This sesond stage of the kernel is run from address 0x0 */ TRANSLATION_TABLE_SIZE = 4096 * 4; +SECTIONS_LIST_SIZE = 4096 * 8; MMU_SECTION_SIZE = 1 << 20; SECTIONS @@ -39,9 +40,18 @@ SECTIONS _translation_table_end = .; } + .sections_list (NOLOAD) : + { + _sections_list_start = .; + + . = . + SECTIONS_LIST_SIZE; + + _sections_list_end = .; + } + . = ALIGN(1 << 20); . = . + MMU_SECTION_SIZE; - + .stack (NOLOAD) : { _stack_start = .; diff --git a/memory.h b/memory.h index 7de556d..2ab5485 100644 --- a/memory.h +++ b/memory.h @@ -25,6 +25,8 @@ extern char __end; extern char __start; extern char _translation_table_start; extern char _translation_table_end; +extern char _sections_list_start; +extern char _sections_list_end; extern char _stack_start; extern char _stack_top; extern char _unprivileged_memory_start; @@ -37,6 +39,10 @@ extern char _unprivileged_memory_end; #define TRANSLATION_TABLE_BASE ((size_t) &_translation_table_start) #define TRANSLATION_TABLE_END ((size_t) &_translation_table_end) +// another 32KB after the translation table are used for sections list +#define SECTIONS_LIST_START ((size_t) &_sections_list_start) +#define SECTIONS_LIST_END ((size_t) &_sections_list_end) + // first section after the translation table is left unused; // the next section is used as the stack #define STACK_START ((size_t) &_stack_start) diff --git a/paging.c b/paging.c index 2985e7e..0de63b8 100644 --- a/paging.c +++ b/paging.c @@ -4,6 +4,8 @@ #include "translation_table_descriptors.h" #include "io.h" +#include "paging.h" + void setup_flat_map(void) { // compute translation table base address @@ -107,3 +109,133 @@ void setup_flat_map(void) asm("mcr p15, 0, %0, c1, c0, 0\n\r" "isb" :: "r" (SCTLR.raw) : "memory"); } + +#define OWNER_FREE ((void*) 0) +#define OWNER_KERNEL ((void*) 1) +#define OWNER_SPLIT ((void*) 2) + +// we want to maintain a list of free and used physical sections +struct section_node +{ + // we're going to add processes, process management and + // struct process. Then, owner will be struct process*. + void *owner; // 0 if free, 1 if used by kernel, 2 if split to pages + + // it's actually a 2-directional lists; + // end of list is marked by reference to itself; + // we use offsets into sections_list array instead of pointers; + uint16_t prev, next; +}; + +static struct section_node volatile *sections_list; + +static uint16_t + all_sections_count, kernel_sections_count, + split_sections_count, free_sections_count; + +// those are undefined when the corresponding count is 0; +static uint16_t + first_free_section, first_kernel_section, first_split_section; + +void setup_pager_structures(uint32_t available_mem) +{ + all_sections_count = available_mem / SECTION_SIZE; + kernel_sections_count = PRIVILEGED_MEMORY_END / SECTION_SIZE; + free_sections_count = all_sections_count - kernel_sections_count; + split_sections_count = 0; + + sections_list = (struct section_node*) SECTIONS_LIST_START; + + for (uint16_t i = 0; i < kernel_sections_count; i++) + sections_list[i] = (struct section_node) { + .owner = OWNER_KERNEL, + .prev = i == 0 ? i : i - 1, + .next = i == kernel_sections_count - 1 ? i : i + 1 + }; + + first_kernel_section = 0; + + for (uint16_t i = kernel_sections_count; + i < all_sections_count; i++) + sections_list[i] = (struct section_node) { + .owner = OWNER_FREE, + .prev = i == kernel_sections_count ? i : i - 1, + .next = i == all_sections_count - 1 ? i : i + 1 + }; + + first_free_section = kernel_sections_count; +} + +// return section number or CLAIM_FAILURE in case of failure +static uint16_t claim_section(void *owner) +{ + if (!free_sections_count) + return CLAIM_FAILURE; // failure + + uint16_t section = first_free_section; + + if (--free_sections_count) + { + uint16_t next; + + next = sections_list[section].next; + sections_list[next].prev = next; + + first_free_section = next; + } + + if (owner == OWNER_KERNEL) + { + sections_list[first_kernel_section].prev = section; + + sections_list[section] = (struct section_node) { + .owner = owner, + .prev = section, + .next = first_kernel_section + }; + + kernel_sections_count++; + + first_kernel_section = section; + } + else + sections_list[section] = (struct section_node) { + .owner = owner, + .prev = section, + .next = section + }; + + return section; +} + +// return values like claim_section() +uint16_t claim_and_map_section +(void *owner, uint16_t where_to_map, uint8_t access_permissions) +{ + uint16_t section = claim_section(owner); + + if (section == CLAIM_FAILURE) + return section; + + short_section_descriptor_t volatile *section_entry = + &((short_section_descriptor_t*) + TRANSLATION_TABLE_BASE)[where_to_map]; + + short_section_descriptor_t descriptor = *section_entry; + + // set up address of section + descriptor.SECTION_BASE_ADDRESS_31_20 = section; + + // set requested permissions on section + descriptor.ACCESS_PERMISSIONS_2 = access_permissions >> 2; + descriptor.ACCESS_PERMISSIONS_1_0 = access_permissions & 0b011; + + // write modified descriptor to the table + *section_entry = descriptor; + + // invalidate main Translation Lookup Buffer + asm("mcr p15, 0, r1, c8, c7, 0\n\r" + "isb" ::: "memory"); + + return section; +} diff --git a/paging.h b/paging.h index 1218fb8..1715a6e 100644 --- a/paging.h +++ b/paging.h @@ -3,4 +3,12 @@ void setup_flat_map(void); +void setup_pager_structures(uint32_t available_mem); + +#define CLAIM_FAILURE 0xffff + +// returns section number or CLAIM_FAILURE in case of failure +uint16_t claim_and_map_section +(void *owner, uint16_t where_to_map, uint8_t access_permissions); + #endif // PAGING_H -- cgit v1.2.3 From 532559dc491d82c41de7f348b3c165d37356be73 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 13:50:55 +0100 Subject: use just implemented basic memory section allocation for processes --- demo_functionality.c | 28 ++++++++-------------------- setup.c | 8 ++++++++ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/demo_functionality.c b/demo_functionality.c index 7a9139c..23a844e 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -4,6 +4,7 @@ #include "translation_table_descriptors.h" #include "ramfs.h" #include "strings.h" +#include "paging.h" void demo_paging_support(void) { @@ -74,27 +75,14 @@ void demo_setup_PL0(void) asm volatile ("wfi"); } - short_section_descriptor_t volatile *PL0_section_entry = - &TRANSLATION_TABLE[PL0_SECTION_NUMBER]; - - short_section_descriptor_t PL0_section = *PL0_section_entry; - - // set up address of PL0 section - PL0_section.SECTION_BASE_ADDRESS_31_20 = - UNPRIVILEGED_MEMORY_START >> 20; - - // make the selected section available for PL0 - PL0_section.ACCESS_PERMISSIONS_2 = - AP_2_0_MODEL_RW_ALL >> 2; - PL0_section.ACCESS_PERMISSIONS_1_0 = - AP_2_0_MODEL_RW_ALL & 0b011; - - *PL0_section_entry = PL0_section; + // dummy value 5 for now, as we haven't implemented processes yet + if (claim_and_map_section((void*) 5, PL0_SECTION_NUMBER, + AP_2_0_MODEL_RW_ALL) == CLAIM_FAILURE) + { + puts("Couldn't claim memory section for unprivileged code :("); + while(1); + } - // invalidate main Translation Lookup Buffer (just in case) - asm("mcr p15, 0, %0, c8, c7, 0\n\r" - "isb" :: "r" (0) : "memory"); - // check that translation works... by copying a string using one // mapping and reading it using other :D char message[] = "mapped sections for PL0 code"; diff --git a/setup.c b/setup.c index 0fd3522..b7acf60 100644 --- a/setup.c +++ b/setup.c @@ -74,6 +74,12 @@ void setup(uint32_t r0, uint32_t machine_type, puts("Couldn't determine available memory - assuming 192MB"); memory_size = 192 * POWER_OF_2(20); } + + if (memory_size < UNPRIVILEGED_MEMORY_END) + { + puts("Not enough memory to continue"); + while (1); + } // prints some info demo_paging_support(); @@ -81,6 +87,8 @@ void setup(uint32_t r0, uint32_t machine_type, // prints some info demo_current_mode(); + setup_pager_structures(memory_size); + // prints some info and sets upp translation table, turns on MMU setup_flat_map(); -- cgit v1.2.3 From d2bd31b4a05cf4fc36ed6c8eaafa61e41b28b9d1 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 17:17:03 +0100 Subject: print information about mapping created for PL0 code --- demo_functionality.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/demo_functionality.c b/demo_functionality.c index 23a844e..366edd7 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -76,19 +76,34 @@ void demo_setup_PL0(void) } // dummy value 5 for now, as we haven't implemented processes yet - if (claim_and_map_section((void*) 5, PL0_SECTION_NUMBER, - AP_2_0_MODEL_RW_ALL) == CLAIM_FAILURE) + uint16_t physical_section_number = claim_and_map_section + ((void*) 5, PL0_SECTION_NUMBER, AP_2_0_MODEL_RW_ALL); + + if (physical_section_number == CLAIM_FAILURE) { puts("Couldn't claim memory section for unprivileged code :("); while(1); } - + + size_t physical_section_start = + (((size_t) physical_section_number) << 20); + // check that translation works... by copying a string using one // mapping and reading it using other :D - char message[] = "mapped sections for PL0 code"; + char str_part1[] = "mapped section for PL0 code (0x"; + char str_part2[] = " -> 0x"; + char str_part3[] = ")"; + + char *string_end = (char*) physical_section_start; + + memcpy(string_end, str_part1, sizeof(str_part1) - 1); + uint32_to_hex(VIRTUAL_PL0_MEMORY_START, + string_end += sizeof(str_part1) - 1); + memcpy(string_end += 8, str_part2, sizeof(str_part2) - 1); + uint32_to_hex(physical_section_start, + string_end += sizeof(str_part2) - 1); + memcpy(string_end += 8, str_part3, sizeof(str_part3)); - memcpy((void*) UNPRIVILEGED_MEMORY_START, message, sizeof(message)); - puts((char*) VIRTUAL_PL0_MEMORY_START); // now paste a userspace program to that section -- cgit v1.2.3 From ff405d15e20b360afe93af5c23d6972f28fc38b9 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 17:21:01 +0100 Subject: print info about completed initialization of kernel's paging structures --- paging.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/paging.c b/paging.c index 0de63b8..6560047 100644 --- a/paging.c +++ b/paging.c @@ -164,6 +164,10 @@ void setup_pager_structures(uint32_t available_mem) }; first_free_section = kernel_sections_count; + + puts("Initialized kernel's internal structures for paging"); + prints("We have "); printdect(free_sections_count); + puts(" free sections left for use"); } // return section number or CLAIM_FAILURE in case of failure -- cgit v1.2.3 From d2d7ebbea19d55fb2a292ca766d95b197691b941 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 17:28:26 +0100 Subject: introduce SECTION_NULL --- demo_functionality.c | 2 +- paging.c | 30 +++++++++++++++++------------- paging.h | 4 ++-- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/demo_functionality.c b/demo_functionality.c index 366edd7..3cf5b8f 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -79,7 +79,7 @@ void demo_setup_PL0(void) uint16_t physical_section_number = claim_and_map_section ((void*) 5, PL0_SECTION_NUMBER, AP_2_0_MODEL_RW_ALL); - if (physical_section_number == CLAIM_FAILURE) + if (physical_section_number == SECTION_NULL) { puts("Couldn't claim memory section for unprivileged code :("); while(1); diff --git a/paging.c b/paging.c index 6560047..771c681 100644 --- a/paging.c +++ b/paging.c @@ -122,7 +122,7 @@ struct section_node void *owner; // 0 if free, 1 if used by kernel, 2 if split to pages // it's actually a 2-directional lists; - // end of list is marked by reference to itself; + // end of list is marked by reference to SECTION_NULL; // we use offsets into sections_list array instead of pointers; uint16_t prev, next; }; @@ -133,7 +133,7 @@ static uint16_t all_sections_count, kernel_sections_count, split_sections_count, free_sections_count; -// those are undefined when the corresponding count is 0; +// those are SECTION_NULL when the corresponding count is 0; static uint16_t first_free_section, first_kernel_section, first_split_section; @@ -146,11 +146,13 @@ void setup_pager_structures(uint32_t available_mem) sections_list = (struct section_node*) SECTIONS_LIST_START; + first_split_section = SECTION_NULL; + for (uint16_t i = 0; i < kernel_sections_count; i++) sections_list[i] = (struct section_node) { .owner = OWNER_KERNEL, - .prev = i == 0 ? i : i - 1, - .next = i == kernel_sections_count - 1 ? i : i + 1 + .prev = i == 0 ? SECTION_NULL : i - 1, + .next = i == kernel_sections_count - 1 ? SECTION_NULL : i + 1 }; first_kernel_section = 0; @@ -159,8 +161,8 @@ void setup_pager_structures(uint32_t available_mem) i < all_sections_count; i++) sections_list[i] = (struct section_node) { .owner = OWNER_FREE, - .prev = i == kernel_sections_count ? i : i - 1, - .next = i == all_sections_count - 1 ? i : i + 1 + .prev = i == kernel_sections_count ? SECTION_NULL : i - 1, + .next = i == all_sections_count - 1 ? SECTION_NULL : i + 1 }; first_free_section = kernel_sections_count; @@ -170,11 +172,11 @@ void setup_pager_structures(uint32_t available_mem) puts(" free sections left for use"); } -// return section number or CLAIM_FAILURE in case of failure +// return section number or SECTION_NULL in case of failure static uint16_t claim_section(void *owner) { if (!free_sections_count) - return CLAIM_FAILURE; // failure + return SECTION_NULL; // failure uint16_t section = first_free_section; @@ -183,10 +185,12 @@ static uint16_t claim_section(void *owner) uint16_t next; next = sections_list[section].next; - sections_list[next].prev = next; + sections_list[next].prev = SECTION_NULL; first_free_section = next; } + else + first_free_section = SECTION_NULL; if (owner == OWNER_KERNEL) { @@ -194,7 +198,7 @@ static uint16_t claim_section(void *owner) sections_list[section] = (struct section_node) { .owner = owner, - .prev = section, + .prev = SECTION_NULL, .next = first_kernel_section }; @@ -205,8 +209,8 @@ static uint16_t claim_section(void *owner) else sections_list[section] = (struct section_node) { .owner = owner, - .prev = section, - .next = section + .prev = SECTION_NULL, + .next = SECTION_NULL }; return section; @@ -218,7 +222,7 @@ uint16_t claim_and_map_section { uint16_t section = claim_section(owner); - if (section == CLAIM_FAILURE) + if (section == SECTION_NULL) return section; short_section_descriptor_t volatile *section_entry = diff --git a/paging.h b/paging.h index 1715a6e..4ac8efa 100644 --- a/paging.h +++ b/paging.h @@ -5,9 +5,9 @@ void setup_flat_map(void); void setup_pager_structures(uint32_t available_mem); -#define CLAIM_FAILURE 0xffff +#define SECTION_NULL 0xffff -// returns section number or CLAIM_FAILURE in case of failure +// returns section number or SECTION_NULL in case of failure uint16_t claim_and_map_section (void *owner, uint16_t where_to_map, uint8_t access_permissions); -- cgit v1.2.3 From b77ef684b07bcd91c168b15f71611786dd5a3377 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 17:28:49 +0100 Subject: add strcat --- strings.c | 15 +++++++++++++++ strings.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/strings.c b/strings.c index b518388..c741938 100644 --- a/strings.c +++ b/strings.c @@ -106,3 +106,18 @@ void *memset(void *s, int c, size_t n) return s; } +char *strcat(char *dst, const char *src) +{ + char *where_to_append; + + for (where_to_append = dst; *where_to_append; where_to_append++); + + size_t i; + + for (i = 0; src[i]; i++) + ((char volatile*) where_to_append)[i] = src[i]; + + ((char volatile*) where_to_append)[i] = '\0'; + + return dst; +} diff --git a/strings.h b/strings.h index 3c49b7e..aff0533 100644 --- a/strings.h +++ b/strings.h @@ -28,4 +28,6 @@ void memcpy(void *dst, void *src, size_t nbytes); void *memset(void *s, int c, size_t n); +char *strcat(char *dst, const char *src); + #endif // STRINGS_H -- cgit v1.2.3 From 030cc96003d4518463b40f20d4194e51b1745c86 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 17:36:50 +0100 Subject: don't statically define the unprivileged section (we're going to have many dynamically-claimed unprivileged sections) --- kernel_stage2.ld | 9 --------- memory.h | 7 +------ setup.c | 3 ++- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/kernel_stage2.ld b/kernel_stage2.ld index a30105e..a3df063 100644 --- a/kernel_stage2.ld +++ b/kernel_stage2.ld @@ -60,13 +60,4 @@ SECTIONS _stack_top = .; } - - .unprivileged_memory (NOLOAD) : - { - _unprivileged_memory_start = .; - - . = . + MMU_SECTION_SIZE; - - _unprivileged_memory_end = .; - } } diff --git a/memory.h b/memory.h index 2ab5485..c7952f0 100644 --- a/memory.h +++ b/memory.h @@ -29,8 +29,6 @@ extern char _sections_list_start; extern char _sections_list_end; extern char _stack_start; extern char _stack_top; -extern char _unprivileged_memory_start; -extern char _unprivileged_memory_end; #define KERNEL_START ((size_t) &__start) // this is 0x0 #define KERNEL_END ((size_t) &__end) @@ -50,11 +48,8 @@ extern char _unprivileged_memory_end; #define PRIVILEGED_MEMORY_END STACK_END -#define UNPRIVILEGED_MEMORY_START \ - ((size_t) &_unprivileged_memory_start) // equal to STACK_END -#define UNPRIVILEGED_MEMORY_END \ - ((size_t) &_unprivileged_memory_end) +// the following describes the virtual section for our PL0 programs #define PL0_SECTION_NUMBER ((size_t) 0xaaa) #define VIRTUAL_PL0_MEMORY_START (PL0_SECTION_NUMBER << 20) diff --git a/setup.c b/setup.c index b7acf60..63ca054 100644 --- a/setup.c +++ b/setup.c @@ -75,7 +75,8 @@ void setup(uint32_t r0, uint32_t machine_type, memory_size = 192 * POWER_OF_2(20); } - if (memory_size < UNPRIVILEGED_MEMORY_END) + // assume we need at least one section for PL0 + if (memory_size < PRIVILEGED_MEMORY_END + SECTION_SIZE) { puts("Not enough memory to continue"); while (1); -- cgit v1.2.3 From 97612feede34cdd0099d72d0e6fa125dd65b5e9a Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 17:43:13 +0100 Subject: reset is used by us in a hacky way and never really triggered by hardware; mark that --- interrupts.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/interrupts.c b/interrupts.c index 3102761..c6e3f17 100644 --- a/interrupts.c +++ b/interrupts.c @@ -1,19 +1,14 @@ #include "io.h" #include "svc_interface.h" -void setup(void); +void __attribute__((noreturn)) setup(void); +// from what I've heard, reset is never used on the Pi; +// in our case it should run once - when stage1 of the kernel +// jumps to stage2 void reset_handler(void) { - static _Bool setup_done; - - if (!setup_done) - setup(); - - setup_done = 1; - - // TODO do something here - while(1); + setup(); } void undefined_instruction_vector(void) -- cgit v1.2.3 From 0ec2016f80ffb5971362559b98b10744bb5bf893 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 18:54:28 +0100 Subject: split stack into irq, fiq and supervisor stacks; add proper handling of those in interrupt handlers (asm code) --- interrupt_vector.S | 25 ++++++++++++++----------- kernel_stage2.ld | 22 +++++++++++++++++++--- memory.h | 18 +++++++++++++++--- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/interrupt_vector.S b/interrupt_vector.S index 88b32bf..af80eec 100644 --- a/interrupt_vector.S +++ b/interrupt_vector.S @@ -9,39 +9,42 @@ _interrupt_vectors: b fiq_handler_caller reset_handler_caller: - ldr sp, =_stack_top + ldr sp, =_supervisor_stack_top ldr r5, =reset_handler bx r5 undef_handler_caller: - ldr sp, =_stack_top + ldr sp, =_supervisor_stack_top ldr r5, =undefined_instruction_vector bx r5 svc_handler_caller: - ldr sp, =_stack_top + ldr sp, =_supervisor_stack_top + push {r5, lr} ldr r5, =supervisor_call_handler - push {lr} blx r5 - ldm sp!, {pc} ^ + ldm sp!, {r5, pc} ^ abort_handler_caller: - ldr sp, =_stack_top + ldr sp, =_supervisor_stack_top ldr r5, =abort_handler bx r5 generic_handler_caller: - ldr sp, =_stack_top + ldr sp, =_supervisor_stack_top ldr r5, =generic_handler bx r5 irq_handler_caller: - ldr sp, =_stack_top - ldr r5, =irq_handler - bx r5 + ldr sp, =_irq_stack_top + sub lr, #4 + push {r0-r3, lr} + ldr r3, =irq_handler + blx r3 + ldm sp!, {r0-r3, pc} ^ fiq_handler_caller: - ldr sp, =_stack_top + ldr sp, =_fiq_stack_top ldr r5, =fiq_handler bx r5 diff --git a/kernel_stage2.ld b/kernel_stage2.ld index a3df063..15b61ec 100644 --- a/kernel_stage2.ld +++ b/kernel_stage2.ld @@ -56,8 +56,24 @@ SECTIONS { _stack_start = .; - . = . + MMU_SECTION_SIZE; - - _stack_top = .; + _fiq_stack_start = .; + + . = . + (1 << 18); + + _fiq_stack_top = .; + + _irq_stack_start = .; + + . = . + (1 << 18); + + _irq_stack_top = .; + + _supervisor_stack_start = .; + + . = . + (1 << 19); + + _supervisor_stack_top = .; + + _stack_end = .; } } diff --git a/memory.h b/memory.h index c7952f0..bdeba52 100644 --- a/memory.h +++ b/memory.h @@ -28,7 +28,13 @@ extern char _translation_table_end; extern char _sections_list_start; extern char _sections_list_end; extern char _stack_start; -extern char _stack_top; +extern char _fiq_stack_start; +extern char _fiq_stack_top; +extern char _irq_stack_start; +extern char _irq_stack_top; +extern char _supervisor_stack_start; +extern char _supervisor_stack_top; +extern char _stack_end; #define KERNEL_START ((size_t) &__start) // this is 0x0 #define KERNEL_END ((size_t) &__end) @@ -43,8 +49,14 @@ extern char _stack_top; // first section after the translation table is left unused; // the next section is used as the stack -#define STACK_START ((size_t) &_stack_start) -#define STACK_END ((size_t) &_stack_top) +#define STACK_START ((size_t) &_stack_start) +#define FIQ_STACK_START ((size_t) &_fiq_stack_start) +#define FIQ_STACK_END ((size_t) &_fiq_stack_top) +#define IRQ_STACK_START ((size_t) &_irq_stack_start) +#define IRQ_STACK_END ((size_t) &_irq_stack_top) +#define SUPERVISOR_STACK_START ((size_t) &_supervisor_stack_start) +#define SUPERVISOR_STACK_END ((size_t) &_supervisor_stack_top) +#define STACK_END ((size_t) &_stack_end) #define PRIVILEGED_MEMORY_END STACK_END -- cgit v1.2.3 From 42636b818a2f8e1b14917e6060fc149f39987299 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 18:59:17 +0100 Subject: add cpsr-writing function --- psr.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/psr.h b/psr.h index b2adafb..5efc6d9 100644 --- a/psr.h +++ b/psr.h @@ -64,6 +64,12 @@ inline static PSR_t read_CPSR(void) return CPSR; } +inline static void write_CPSR(PSR_t CPSR) +{ + // set content of current program status register + asm("msr cpsr, %0" :: "r" (CPSR.raw) : "memory"); +} + inline static PSR_t read_SPSR(void) { PSR_t SPSR; -- cgit v1.2.3 From b1327588146761d10c949d365f3150f9a7504ee4 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 20:10:56 +0100 Subject: define peripherals base --- global.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/global.h b/global.h index b041a65..6fc19ed 100644 --- a/global.h +++ b/global.h @@ -5,13 +5,15 @@ #define RASPI 2 #if RASPI == 4 -#define GPIO_BASE 0xFE200000 +#define PERIF_BASE 0xFE000000 #else #if RASPI == 3 || RASPI == 2 -#define GPIO_BASE 0x3F200000 +#define PERIF_BASE 0x3F000000 #else -#define GPIO_BASE 0x20200000 +#define PERIF_BASE 0x20000000 #endif // RASPI == 3 || RASPI == 2 #endif // RASPI == 4 +#define GPIO_BASE (PERIF_BASE + 0x200000) + #endif // GLOBAL_H -- cgit v1.2.3 From 0d36a8bac1240eefdabe5ab96b9332cf73383d9d Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 20:11:37 +0100 Subject: use nice #define's instead of ugly enum --- uart.h | 56 +++++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/uart.h b/uart.h index d5e931b..f2fd6af 100644 --- a/uart.h +++ b/uart.h @@ -4,39 +4,37 @@ #include #include #include -enum - { - // The offsets for reach register. - // Controls actuation of pull up/down to ALL GPIO pins. - GPPUD = (GPIO_BASE + 0x94), +// The offsets for reach register. - // Controls actuation of pull up/down for specific GPIO pin. - GPPUDCLK0 = (GPIO_BASE + 0x98), +// Controls actuation of pull up/down to ALL GPIO pins. +#define GPPUD (GPIO_BASE + 0x94) - // The base address for UART. - UART0_BASE = 0x3F201000, // for raspi2 & 3, 0x20201000 for raspi1 +// Controls actuation of pull up/down for specific GPIO pin. +#define GPPUDCLK0 (GPIO_BASE + 0x98) - // The offsets for reach register for the UART. - UART0_DR = (UART0_BASE + 0x00), - UART0_RSRECR = (UART0_BASE + 0x04), - UART0_FR = (UART0_BASE + 0x18), - UART0_ILPR = (UART0_BASE + 0x20), - UART0_IBRD = (UART0_BASE + 0x24), - UART0_FBRD = (UART0_BASE + 0x28), - UART0_LCRH = (UART0_BASE + 0x2C), - UART0_CR = (UART0_BASE + 0x30), - UART0_IFLS = (UART0_BASE + 0x34), - UART0_IMSC = (UART0_BASE + 0x38), - UART0_RIS = (UART0_BASE + 0x3C), - UART0_MIS = (UART0_BASE + 0x40), - UART0_ICR = (UART0_BASE + 0x44), - UART0_DMACR = (UART0_BASE + 0x48), - UART0_ITCR = (UART0_BASE + 0x80), - UART0_ITIP = (UART0_BASE + 0x84), - UART0_ITOP = (UART0_BASE + 0x88), - UART0_TDR = (UART0_BASE + 0x8C), - }; +// The base address for UART. +#define UART0_BASE (GPIO_BASE + 0x1000) + +// The offsets for reach register for the UART. +#define UART0_DR (UART0_BASE + 0x00) +#define UART0_RSRECR (UART0_BASE + 0x04) +#define UART0_FR (UART0_BASE + 0x18) +#define UART0_ILPR (UART0_BASE + 0x20) +#define UART0_IBRD (UART0_BASE + 0x24) +#define UART0_FBRD (UART0_BASE + 0x28) +#define UART0_LCRH (UART0_BASE + 0x2C) +#define UART0_CR (UART0_BASE + 0x30) +#define UART0_IFLS (UART0_BASE + 0x34) +#define UART0_IMSC (UART0_BASE + 0x38) +#define UART0_RIS (UART0_BASE + 0x3C) +#define UART0_MIS (UART0_BASE + 0x40) +#define UART0_ICR (UART0_BASE + 0x44) +#define UART0_DMACR (UART0_BASE + 0x48) +#define UART0_ITCR (UART0_BASE + 0x80) +#define UART0_ITIP (UART0_BASE + 0x84) +#define UART0_ITOP (UART0_BASE + 0x88) +#define UART0_TDR (UART0_BASE + 0x8C) void uart_init(); void putchar(char c); -- cgit v1.2.3 From 3fb88e3c0237379e32bd6d1d27465d5324726684 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 20:21:06 +0100 Subject: make global.h more readable --- global.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/global.h b/global.h index 6fc19ed..202ca85 100644 --- a/global.h +++ b/global.h @@ -4,16 +4,23 @@ // board type, raspi2 #define RASPI 2 +// conditionally #define PERIF_BASE #if RASPI == 4 + #define PERIF_BASE 0xFE000000 -#else -#if RASPI == 3 || RASPI == 2 + +#elif RASPI == 3 || RASPI == 2 + #define PERIF_BASE 0x3F000000 -#else + +#else // if RASPI == 1 + #define PERIF_BASE 0x20000000 -#endif // RASPI == 3 || RASPI == 2 -#endif // RASPI == 4 +#endif + +// GPIO_BASE is #define'd in terms of PERIF_BASE +// (as in sane kernels - like linux, not like in wiki.osdev codes...) #define GPIO_BASE (PERIF_BASE + 0x200000) #endif // GLOBAL_H -- cgit v1.2.3 From 263a2ddec4f7f17c5bcd3a36ded396f6fe4e836a Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 21:56:20 +0100 Subject: copy by one byte in memcpy to avoid alignment faults --- strings.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/strings.c b/strings.c index c741938..368d7dc 100644 --- a/strings.c +++ b/strings.c @@ -82,13 +82,9 @@ void memcpy(void *dst, void *src, size_t nbytes) { size_t iter; - // copying by word is faster than by byte - // copy by word as much as possible - for (iter = 0; iter < nbytes / 4; iter++) - ((volatile uint32_t*) dst)[iter] = ((uint32_t*) src)[iter]; - - // copy the remaining 1, 2 or 3 bytes by byte - for (iter *= 4; iter < nbytes; iter++) + // copying by word is faster than by byte, + // but can easily cause alignment faults, so we resign from it... + for (iter = 0; iter < nbytes ; iter++) ((volatile uint8_t*) dst)[iter] = ((uint8_t*) src)[iter]; } -- cgit v1.2.3 From 13199395faf225fe78d2ef4540ea3e75edb4e640 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 23:12:54 +0100 Subject: GPU clock stuff (probably not to be finished...) --- bcmclock.h | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 bcmclock.h diff --git a/bcmclock.h b/bcmclock.h new file mode 100644 index 0000000..7fd192d --- /dev/null +++ b/bcmclock.h @@ -0,0 +1,53 @@ +#ifndef BCMCLOCK_H +#define BCMCLOCK_H + +#include + +#include "global.h" + +#define ST_BASE (PERIF_BASE + 0x3000) // System Timer + +#define ST_CS (ST_BASE + 0x0) // System Timer Control/Status +#define ST_CLO (ST_BASE + 0x4) // System Timer Counter Lower 32 bits +#define ST_CHI (ST_BASE + 0x8) // System Timer Counter Higher 32 bits +#define ST_C0 (ST_BASE + 0xC) // System Timer Compare 0 +#define ST_C1 (ST_BASE + 0x10) // System Timer Compare 1 +#define ST_C2 (ST_BASE + 0x14) // System Timer Compare 2 +#define ST_C3 (ST_BASE + 0x18) // System Timer Compare 3 + +// ARM control block +// called "base address for the ARM interrupt register" elsewhere +#define ARM_BASE (PERIF_BASE + 0xB000) + +#define ARM_IRQ_BASIC_PENDING (ARM_BASE + 0x200) +#define ARM_IRQ_PENDING_1 (ARM_BASE + 0x204) +#define ARM_IRQ_PENDING_2 (ARM_BASE + 0x208) +#define ARM_FIQ_CONTROL (ARM_BASE + 0x20C) +#define ARM_ENABLE_IRQS_1 (ARM_BASE + 0x210) +#define ARM_ENABLE_IRQS_2 (ARM_BASE + 0x214) +#define ARM_ENABLE_BASIC_IRQS (ARM_BASE + 0x218) +#define ARM_DISABLE_IRQS_1 (ARM_BASE + 0x21C) +#define ARM_DISABLE_IRQS_2 (ARM_BASE + 0x220) +#define ARM_DISABLE_BASIC_IRQS (ARM_BASE + 0x224) + + +static inline void enable_timer_irq(void) +{ + *(uint32_t volatile*) ARM_ENABLE_BASIC_IRQS = 1; + *(uint32_t volatile*) ARM_ENABLE_IRQS_1 = 1 << 2; +} + +static inline void disable_timer_irq(void) +{ + *(uint32_t volatile*) ARM_DISABLE_BASIC_IRQS = 1; + *(uint32_t volatile*) ARM_DISABLE_IRQS_1 = 1 << 2; +} + +static inline void set_timer_match_timeout(uint32_t timeout) +{ + uint32_t clock_now = *(uint32_t volatile*) ST_CLO; + *(uint32_t volatile*) ST_C2 = clock_now + timeout; + *(uint32_t volatile*) ST_CS = 1 << 2; +} + +#endif // BCMCLOCK_H -- cgit v1.2.3 From fc852b23608c2162b264302e6f48e5f8b3b0b512 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 23:32:42 +0100 Subject: move ARM_BASE definition to global.h --- bcmclock.h | 4 ---- global.h | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bcmclock.h b/bcmclock.h index 7fd192d..40d0559 100644 --- a/bcmclock.h +++ b/bcmclock.h @@ -15,10 +15,6 @@ #define ST_C2 (ST_BASE + 0x14) // System Timer Compare 2 #define ST_C3 (ST_BASE + 0x18) // System Timer Compare 3 -// ARM control block -// called "base address for the ARM interrupt register" elsewhere -#define ARM_BASE (PERIF_BASE + 0xB000) - #define ARM_IRQ_BASIC_PENDING (ARM_BASE + 0x200) #define ARM_IRQ_PENDING_1 (ARM_BASE + 0x204) #define ARM_IRQ_PENDING_2 (ARM_BASE + 0x208) diff --git a/global.h b/global.h index 202ca85..34867a1 100644 --- a/global.h +++ b/global.h @@ -23,4 +23,8 @@ // (as in sane kernels - like linux, not like in wiki.osdev codes...) #define GPIO_BASE (PERIF_BASE + 0x200000) +// ARM control block +// called "base address for the ARM interrupt register" elsewhere +#define ARM_BASE (PERIF_BASE + 0xB000) + #endif // GLOBAL_H -- cgit v1.2.3 From f762c5c65ff9578e4c365320bd89deb34912a047 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 23:34:43 +0100 Subject: more uniqe constant naming --- bcmclock.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/bcmclock.h b/bcmclock.h index 40d0559..345ff60 100644 --- a/bcmclock.h +++ b/bcmclock.h @@ -15,28 +15,28 @@ #define ST_C2 (ST_BASE + 0x14) // System Timer Compare 2 #define ST_C3 (ST_BASE + 0x18) // System Timer Compare 3 -#define ARM_IRQ_BASIC_PENDING (ARM_BASE + 0x200) -#define ARM_IRQ_PENDING_1 (ARM_BASE + 0x204) -#define ARM_IRQ_PENDING_2 (ARM_BASE + 0x208) -#define ARM_FIQ_CONTROL (ARM_BASE + 0x20C) -#define ARM_ENABLE_IRQS_1 (ARM_BASE + 0x210) -#define ARM_ENABLE_IRQS_2 (ARM_BASE + 0x214) -#define ARM_ENABLE_BASIC_IRQS (ARM_BASE + 0x218) -#define ARM_DISABLE_IRQS_1 (ARM_BASE + 0x21C) -#define ARM_DISABLE_IRQS_2 (ARM_BASE + 0x220) -#define ARM_DISABLE_BASIC_IRQS (ARM_BASE + 0x224) +#define BCMCLK_IRQ_BASIC_PENDING (ARM_BASE + 0x200) +#define BCMCLK_IRQ_PENDING_1 (ARM_BASE + 0x204) +#define BCMCLK_IRQ_PENDING_2 (ARM_BASE + 0x208) +#define BCMCLK_FIQ_CONTROL (ARM_BASE + 0x20C) +#define BCMCLK_ENABLE_IRQS_1 (ARM_BASE + 0x210) +#define BCMCLK_ENABLE_IRQS_2 (ARM_BASE + 0x214) +#define BCMCLK_ENABLE_BASIC_IRQS (ARM_BASE + 0x218) +#define BCMCLK_DISABLE_IRQS_1 (ARM_BASE + 0x21C) +#define BCMCLK_DISABLE_IRQS_2 (ARM_BASE + 0x220) +#define BCMCLK_DISABLE_BASIC_IRQS (ARM_BASE + 0x224) static inline void enable_timer_irq(void) { - *(uint32_t volatile*) ARM_ENABLE_BASIC_IRQS = 1; - *(uint32_t volatile*) ARM_ENABLE_IRQS_1 = 1 << 2; + *(uint32_t volatile*) BCMCLK_ENABLE_BASIC_IRQS = 1; + *(uint32_t volatile*) BCMCLK_ENABLE_IRQS_1 = 1 << 2; } static inline void disable_timer_irq(void) { - *(uint32_t volatile*) ARM_DISABLE_BASIC_IRQS = 1; - *(uint32_t volatile*) ARM_DISABLE_IRQS_1 = 1 << 2; + *(uint32_t volatile*) BCMCLK_DISABLE_BASIC_IRQS = 1; + *(uint32_t volatile*) BCMCLK_DISABLE_IRQS_1 = 1 << 2; } static inline void set_timer_match_timeout(uint32_t timeout) -- cgit v1.2.3 From 0e136bc41b1edcc146a075e0e1e41bfdbd37e572 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Tue, 31 Dec 2019 23:39:48 +0100 Subject: more uniqe function naming --- bcmclock.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bcmclock.h b/bcmclock.h index 345ff60..e4edb57 100644 --- a/bcmclock.h +++ b/bcmclock.h @@ -27,19 +27,19 @@ #define BCMCLK_DISABLE_BASIC_IRQS (ARM_BASE + 0x224) -static inline void enable_timer_irq(void) +static inline void bcmclk_enable_timer_irq(void) { *(uint32_t volatile*) BCMCLK_ENABLE_BASIC_IRQS = 1; *(uint32_t volatile*) BCMCLK_ENABLE_IRQS_1 = 1 << 2; } -static inline void disable_timer_irq(void) +static inline void bcmclk_disable_timer_irq(void) { *(uint32_t volatile*) BCMCLK_DISABLE_BASIC_IRQS = 1; *(uint32_t volatile*) BCMCLK_DISABLE_IRQS_1 = 1 << 2; } -static inline void set_timer_match_timeout(uint32_t timeout) +static inline void bcmclk_set_timer_match_timeout(uint32_t timeout) { uint32_t clock_now = *(uint32_t volatile*) ST_CLO; *(uint32_t volatile*) ST_C2 = clock_now + timeout; -- cgit v1.2.3 From ea465f85cf7a47f488332509a2f6d7ae5c88057c Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Wed, 1 Jan 2020 00:04:02 +0100 Subject: add messy armclock.h... although messy, it works (with modified setup.c i got an irq on real pi ^^) --- armclock.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 armclock.h diff --git a/armclock.h b/armclock.h new file mode 100644 index 0000000..67a4ab8 --- /dev/null +++ b/armclock.h @@ -0,0 +1,49 @@ +#ifndef ARMCLOCK_H +#define ARMCLOCK_H + +#include "global.h" + +#define ARMCLK_LOAD (ARM_BASE + 0x400) +#define ARMCLK_VALUE (ARM_BASE + 0x404) +#define ARMCLK_CONTROL (ARM_BASE + 0x408) +#define ARMCLK_IRQ_CLR_ACK (ARM_BASE + 0x40C) +#define ARMCLK_LOAD_RAW_IRQ (ARM_BASE + 0x410) +#define ARMCLK_LOAD_MASKED_IRQ (ARM_BASE + 0x414) +#define ARMCLK_LOAD_RELOAD (ARM_BASE + 0x418) +// the last 2 are said to not exist on the actual Pi +#define ARMCLK_LOAD_PRE_DRIVER (ARM_BASE + 0x41C) +#define ARMCLK_LOAD_FREE_RUNNING_COUNTER (ARM_BASE + 0x420) + +#define BCMCLK_ENABLE_BASIC_IRQS (ARM_BASE + 0x218) + +static inline void armclk_enable_timer_irq(void) +{ + // 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 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; +} + +static inline void armclk_set_timer_match_timeout(uint32_t timeout) +{ + *(uint32_t volatile*) ARMCLK_LOAD = timeout; +} + +#endif // ARMCLOCK_H -- cgit v1.2.3 From 3941fe97783c7a31ab04fbfb127f5026dd31ef78 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 2 Jan 2020 13:24:29 +0100 Subject: demo of arm timer irq --- PL0_test.c | 29 ++++++++++++++++------------ armclock.h | 53 +++++++++++++++++++++++++++++++++++++--------------- demo_functionality.c | 4 ++++ interrupts.c | 14 +++++++++++--- setup.c | 9 ++++++++- 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 + #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("<>"); + 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(); -- cgit v1.2.3 From 1d7ff3bda9b6cbd15deadc1b440d9c02113beec6 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 2 Jan 2020 13:40:19 +0100 Subject: change naming of functions scheduling timer irq for a specified time from now --- armclock.h | 2 +- bcmclock.h | 2 +- demo_functionality.c | 2 +- interrupts.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/armclock.h b/armclock.h index 700879a..bf225b0 100644 --- a/armclock.h +++ b/armclock.h @@ -58,7 +58,7 @@ static inline void armclk_disable_timer_irq(void) *(uint32_t volatile*) BCMCLK_DISABLE_BASIC_IRQS = 1; } -static inline void armclk_set_timer_match_timeout(uint32_t timeout) +static inline void armclk_irq_settimeout(uint32_t timeout) { *(uint32_t volatile*) ARMCLK_IRQ_CLR_ACK = 0; *(uint32_t volatile*) ARMCLK_LOAD = timeout; diff --git a/bcmclock.h b/bcmclock.h index e4edb57..75a3b07 100644 --- a/bcmclock.h +++ b/bcmclock.h @@ -39,7 +39,7 @@ static inline void bcmclk_disable_timer_irq(void) *(uint32_t volatile*) BCMCLK_DISABLE_IRQS_1 = 1 << 2; } -static inline void bcmclk_set_timer_match_timeout(uint32_t timeout) +static inline void bcmclk_irq_settimeout(uint32_t timeout) { uint32_t clock_now = *(uint32_t volatile*) ST_CLO; *(uint32_t volatile*) ST_C2 = clock_now + timeout; diff --git a/demo_functionality.c b/demo_functionality.c index a2d8550..1ef91a1 100644 --- a/demo_functionality.c +++ b/demo_functionality.c @@ -126,7 +126,7 @@ void demo_go_unprivileged(void) puts("All ready, jumping to PL0 code"); - armclk_set_timer_match_timeout(0x00100000); + armclk_irq_settimeout(0x00100000); asm volatile("cps %[sysmode]\n\r" "mov sp, %[stackaddr]\n\r" diff --git a/interrupts.c b/interrupts.c index 62c644b..f4192a0 100644 --- a/interrupts.c +++ b/interrupts.c @@ -62,7 +62,7 @@ void irq_handler(void) if (armclk_irq_pending()) { puts("<>"); - armclk_set_timer_match_timeout(0x00100000); + armclk_irq_settimeout(0x00100000); } else { -- cgit v1.2.3 From 7da46d099e1d1909bf5d09ecedfea21481a7a3b9 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 2 Jan 2020 13:43:06 +0100 Subject: move general irq register definitions to global.h --- armclock.h | 7 ++----- bcmclock.h | 20 ++++---------------- global.h | 11 +++++++++++ 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/armclock.h b/armclock.h index bf225b0..3e65d27 100644 --- a/armclock.h +++ b/armclock.h @@ -16,9 +16,6 @@ #define ARMCLK_LOAD_PRE_DRIVER (ARM_BASE + 0x41C) #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) - typedef union armclk_control { uint32_t raw; @@ -50,12 +47,12 @@ static inline void armclk_init(void) static inline void armclk_enable_timer_irq(void) { - *(uint32_t volatile*) BCMCLK_ENABLE_BASIC_IRQS = 1; + *(uint32_t volatile*) ARM_ENABLE_BASIC_IRQS = 1; } static inline void armclk_disable_timer_irq(void) { - *(uint32_t volatile*) BCMCLK_DISABLE_BASIC_IRQS = 1; + *(uint32_t volatile*) ARM_DISABLE_BASIC_IRQS = 1; } static inline void armclk_irq_settimeout(uint32_t timeout) diff --git a/bcmclock.h b/bcmclock.h index 75a3b07..b54c39a 100644 --- a/bcmclock.h +++ b/bcmclock.h @@ -15,28 +15,16 @@ #define ST_C2 (ST_BASE + 0x14) // System Timer Compare 2 #define ST_C3 (ST_BASE + 0x18) // System Timer Compare 3 -#define BCMCLK_IRQ_BASIC_PENDING (ARM_BASE + 0x200) -#define BCMCLK_IRQ_PENDING_1 (ARM_BASE + 0x204) -#define BCMCLK_IRQ_PENDING_2 (ARM_BASE + 0x208) -#define BCMCLK_FIQ_CONTROL (ARM_BASE + 0x20C) -#define BCMCLK_ENABLE_IRQS_1 (ARM_BASE + 0x210) -#define BCMCLK_ENABLE_IRQS_2 (ARM_BASE + 0x214) -#define BCMCLK_ENABLE_BASIC_IRQS (ARM_BASE + 0x218) -#define BCMCLK_DISABLE_IRQS_1 (ARM_BASE + 0x21C) -#define BCMCLK_DISABLE_IRQS_2 (ARM_BASE + 0x220) -#define BCMCLK_DISABLE_BASIC_IRQS (ARM_BASE + 0x224) - - static inline void bcmclk_enable_timer_irq(void) { - *(uint32_t volatile*) BCMCLK_ENABLE_BASIC_IRQS = 1; - *(uint32_t volatile*) BCMCLK_ENABLE_IRQS_1 = 1 << 2; + *(uint32_t volatile*) ARM_ENABLE_BASIC_IRQS = 1; + *(uint32_t volatile*) ARM_ENABLE_IRQS_1 = 1 << 2; } static inline void bcmclk_disable_timer_irq(void) { - *(uint32_t volatile*) BCMCLK_DISABLE_BASIC_IRQS = 1; - *(uint32_t volatile*) BCMCLK_DISABLE_IRQS_1 = 1 << 2; + *(uint32_t volatile*) ARM_DISABLE_BASIC_IRQS = 1; + *(uint32_t volatile*) ARM_DISABLE_IRQS_1 = 1 << 2; } static inline void bcmclk_irq_settimeout(uint32_t timeout) diff --git a/global.h b/global.h index 34867a1..f5fe9a6 100644 --- a/global.h +++ b/global.h @@ -27,4 +27,15 @@ // called "base address for the ARM interrupt register" elsewhere #define ARM_BASE (PERIF_BASE + 0xB000) +#define ARM_IRQ_BASIC_PENDING (ARM_BASE + 0x200) +#define ARM_IRQ_PENDING_1 (ARM_BASE + 0x204) +#define ARM_IRQ_PENDING_2 (ARM_BASE + 0x208) +#define ARM_FIQ_CONTROL (ARM_BASE + 0x20C) +#define ARM_ENABLE_IRQS_1 (ARM_BASE + 0x210) +#define ARM_ENABLE_IRQS_2 (ARM_BASE + 0x214) +#define ARM_ENABLE_BASIC_IRQS (ARM_BASE + 0x218) +#define ARM_DISABLE_IRQS_1 (ARM_BASE + 0x21C) +#define ARM_DISABLE_IRQS_2 (ARM_BASE + 0x220) +#define ARM_DISABLE_BASIC_IRQS (ARM_BASE + 0x224) + #endif // GLOBAL_H -- cgit v1.2.3 From 03e9c87115527eeb21d5c7c554c3a1b6f8211e54 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 2 Jan 2020 13:45:41 +0100 Subject: fix/improve arm timer register definitions --- armclock.h | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/armclock.h b/armclock.h index 3e65d27..2b2aec9 100644 --- a/armclock.h +++ b/armclock.h @@ -5,16 +5,15 @@ #include "global.h" -#define ARMCLK_LOAD (ARM_BASE + 0x400) -#define ARMCLK_VALUE (ARM_BASE + 0x404) -#define ARMCLK_CONTROL (ARM_BASE + 0x408) -#define ARMCLK_IRQ_CLR_ACK (ARM_BASE + 0x40C) -#define ARMCLK_LOAD_RAW_IRQ (ARM_BASE + 0x410) -#define ARMCLK_LOAD_MASKED_IRQ (ARM_BASE + 0x414) -#define ARMCLK_LOAD_RELOAD (ARM_BASE + 0x418) -// the last 2 are said to not exist on the actual Pi -#define ARMCLK_LOAD_PRE_DRIVER (ARM_BASE + 0x41C) -#define ARMCLK_LOAD_FREE_RUNNING_COUNTER (ARM_BASE + 0x420) +#define ARMCLK_LOAD (ARM_BASE + 0x400) +#define ARMCLK_VALUE (ARM_BASE + 0x404) +#define ARMCLK_CONTROL (ARM_BASE + 0x408) +#define ARMCLK_IRQ_CLR_ACK (ARM_BASE + 0x40C) +#define ARMCLK_RAW_IRQ (ARM_BASE + 0x410) +#define ARMCLK_MASKED_IRQ (ARM_BASE + 0x414) +#define ARMCLK_RELOAD (ARM_BASE + 0x418) +#define ARMCLK_PRE_DRIVER (ARM_BASE + 0x41C) +#define ARMCLK_FREE_RUNNING_COUNTER (ARM_BASE + 0x420) typedef union armclk_control { @@ -63,7 +62,7 @@ static inline void armclk_irq_settimeout(uint32_t timeout) static inline _Bool armclk_irq_pending(void) { - return *(uint32_t volatile*) ARMCLK_LOAD_RAW_IRQ; + return *(uint32_t volatile*) ARMCLK_RAW_IRQ; } #endif // ARMCLOCK_H -- cgit v1.2.3 From 6bf5a3b8c6e8a5d1cb3fb4880a5d9688ab094c62 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Thu, 2 Jan 2020 13:47:05 +0100 Subject: use clock3; don't write to registers of arm timer (former mistake) --- bcmclock.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/bcmclock.h b/bcmclock.h index b54c39a..dd7136b 100644 --- a/bcmclock.h +++ b/bcmclock.h @@ -17,21 +17,19 @@ static inline void bcmclk_enable_timer_irq(void) { - *(uint32_t volatile*) ARM_ENABLE_BASIC_IRQS = 1; - *(uint32_t volatile*) ARM_ENABLE_IRQS_1 = 1 << 2; + *(uint32_t volatile*) ARM_ENABLE_IRQS_1 = 1 << 3; } static inline void bcmclk_disable_timer_irq(void) { - *(uint32_t volatile*) ARM_DISABLE_BASIC_IRQS = 1; - *(uint32_t volatile*) ARM_DISABLE_IRQS_1 = 1 << 2; + *(uint32_t volatile*) ARM_DISABLE_IRQS_1 = 1 << 3; } static inline void bcmclk_irq_settimeout(uint32_t timeout) { uint32_t clock_now = *(uint32_t volatile*) ST_CLO; - *(uint32_t volatile*) ST_C2 = clock_now + timeout; - *(uint32_t volatile*) ST_CS = 1 << 2; + *(uint32_t volatile*) ST_C3 = clock_now + timeout; + *(uint32_t volatile*) ST_CS = 1 << 3; } #endif // BCMCLOCK_H -- cgit v1.2.3