aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojtek Kosior <kwojtus@protonmail.com>2019-12-30 17:34:23 +0100
committerWojtek Kosior <kwojtus@protonmail.com>2019-12-30 17:34:23 +0100
commitc9e045dc2170a99c9f32386e3e53aee9e01a8e7c (patch)
treefaa57aef89cd1a03efc665c1e5809cf4f0304269
parenteae54c24e2e2b89f399bc2d3be195468c2e462a5 (diff)
downloadrpi-MMU-example-c9e045dc2170a99c9f32386e3e53aee9e01a8e7c.tar.gz
rpi-MMU-example-c9e045dc2170a99c9f32386e3e53aee9e01a8e7c.zip
io api rework
-rw-r--r--Makefile10
-rw-r--r--PL0_test.c6
-rw-r--r--PL0_utils.c14
-rw-r--r--PL0_utils.h6
-rw-r--r--demo_functionality.c52
-rw-r--r--interrupts.c20
-rw-r--r--io.c64
-rw-r--r--io.h26
-rw-r--r--loader_stage2.c11
-rw-r--r--memory.h2
-rw-r--r--paging.c27
-rw-r--r--setup.c13
-rw-r--r--strings.c73
-rw-r--r--strings.h22
-rw-r--r--uart.c10
-rw-r--r--uart.h5
16 files changed, 258 insertions, 103 deletions
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 <stdint.h>
#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 <stddef.h>
+
+#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 <stdint.h>
+
+// 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 <stddef.h>
#include <stdint.h>
#include <uart.h>
+#include <io.h>
#include <global.h>
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 <stddef.h>
+
// 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 <stddef.h>
+
+#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 <stdint.h>
-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