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 --- PL0_utils.h | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 PL0_utils.h (limited to 'PL0_utils.h') 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 -- 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 (limited to 'PL0_utils.h') 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