diff options
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/io.c | 71 | ||||
-rw-r--r-- | src/utils/io.h | 28 | ||||
-rw-r--r-- | src/utils/pipe_image.c | 112 | ||||
-rw-r--r-- | src/utils/strings.c | 119 | ||||
-rw-r--r-- | src/utils/strings.h | 33 | ||||
-rw-r--r-- | src/utils/svc.S | 5 | ||||
-rw-r--r-- | src/utils/svc_interface.h | 11 | ||||
-rw-r--r-- | src/utils/uart.c | 103 | ||||
-rw-r--r-- | src/utils/uart.h | 106 |
9 files changed, 588 insertions, 0 deletions
diff --git a/src/utils/io.c b/src/utils/io.c new file mode 100644 index 0000000..bf9e0e3 --- /dev/null +++ b/src/utils/io.c @@ -0,0 +1,71 @@ +#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 error(char string[]) +{ + prints("ERROR! "); + puts(string); + while (1); +} + +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/src/utils/io.h b/src/utils/io.h new file mode 100644 index 0000000..dcad76e --- /dev/null +++ b/src/utils/io.h @@ -0,0 +1,28 @@ +#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 error(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/src/utils/pipe_image.c b/src/utils/pipe_image.c new file mode 100644 index 0000000..b148ac4 --- /dev/null +++ b/src/utils/pipe_image.c @@ -0,0 +1,112 @@ +#include <stdio.h> +#include <err.h> +#include <endian.h> +#include <stdint.h> +#include <sys/types.h> +#include "../../lib/rs232/rs232.h" + +#define ANSI_FG_RED "\033[0;31m" +#define ANSI_FG_DEFAULT "\033[0;39m" + +/* This program pipes it's argument file to /dev/ttyUSB0 or stdout */ +/* prepending it with it's size (4 bytes, little endian). */ +/* It is intended to be used with our bootloader. */ + +int main(int argc, const char **argv) { + const char *image_file_name = "kernel.img"; + _Bool stdout_instead_of_uart = 0; + + if (argc > 1) + if (!strcmp(argv[1], "--stdout")) + { + stdout_instead_of_uart = 1; + argc--; + argv++; + } + + if (argc > 1) + image_file_name = argv[1]; + + FILE *image_file_handle = fopen(image_file_name, "r"); + + if (!image_file_handle) + err(-1, "couldn't open" ANSI_FG_RED "%s" ANSI_FG_DEFAULT, + image_file_name); + + if (fseek(image_file_handle, 0, SEEK_END)) + err(-1, "error navigating through file"); + + ssize_t image_size = ftell(image_file_handle); + if (image_size < 0) + err(-1, "couldn't get image file size"); + + if (image_size >> 32) + err(-1, "file to big (should be smaller than 4G)"); + + if (fseek(image_file_handle, 0, SEEK_SET)) + err(-1, "error navigating through file"); + + //init comport + const int comport=16; + + if (!stdout_instead_of_uart) + if (RS232_OpenComport(comport, 115200, "8N1", 1) == 1) + err(-1, "Error opening comport"); + + uint32_t image_size_le = htole32(image_size); + + if (stdout_instead_of_uart) + { + if (fwrite((unsigned char*) &image_size_le, 4, 1, stdout) != 1) + err(-1, "error writing number to stdout"); + } + else + { + if (RS232_SendBuf(comport, (unsigned char*) &image_size_le, 4) + == -1) + err(-1, "error writing number to serial"); + } + + ssize_t bytes_left = image_size; + + unsigned char buf[1024]; + while (bytes_left) + { + size_t bytes_read; + if ((bytes_read = fread(buf, 1, sizeof(buf), image_file_handle)) + < 1) + err(-1, "error reading the file"); + + if (stdout_instead_of_uart) + { + if (fwrite((unsigned char*) buf, bytes_read, 1, stdout) != 1) + err(-1, "error writing to stdout"); + } + else + { + if (RS232_SendBuf(comport, buf, bytes_read) == -1) + err(-1, "error writing to serial"); + } + + bytes_left -= bytes_read; + } +/* + while(1){ + int bytes_read=read(0,buf,sizeof(buf)); + if (stdout_instead_of_uart) + { + if (fwrite((unsigned char*) buf, bytes_read, 1, stdout) != 1) + err(-1, "error writing to stdout"); + } + else + { + if (RS232_SendBuf(comport, buf, bytes_read) == 1) + err(-1, "error writing to serial"); + } + } + */ + if (!stdout_instead_of_uart) + RS232_CloseComport(comport); + + return 0; +} diff --git a/src/utils/strings.c b/src/utils/strings.c new file mode 100644 index 0000000..368d7dc --- /dev/null +++ b/src/utils/strings.c @@ -0,0 +1,119 @@ +#include "strings.h" + +void uint32_to_dec(uint32_t number, char buf[10]) +{ + for (int i = 0; i < 10; i++) + { + buf[10 - 1 - i] = '0' + (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[8] = '\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'; i++); + + size_t j = 0; + + if (!string[i]) + 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); +} + +size_t strlen(char string[]) +{ + size_t len; + + for (len = 0; string[len]; len++); + + return len; +} + +void memcpy(void *dst, void *src, size_t nbytes) +{ + size_t 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]; +} + +// 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; +} + +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/src/utils/strings.h b/src/utils/strings.h new file mode 100644 index 0000000..aff0533 --- /dev/null +++ b/src/utils/strings.h @@ -0,0 +1,33 @@ +#ifndef STRINGS_H +#define STRINGS_H + +#include <stddef.h> +#include <stdint.h> + +void uint32_to_dec(uint32_t number, char buf[10]); + +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]); + +size_t strlen(char string[]); + +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 diff --git a/src/utils/svc.S b/src/utils/svc.S new file mode 100644 index 0000000..65200d8 --- /dev/null +++ b/src/utils/svc.S @@ -0,0 +1,5 @@ +.global svc + +svc: + svc #0 + mov pc, lr diff --git a/src/utils/svc_interface.h b/src/utils/svc_interface.h new file mode 100644 index 0000000..aa478ce --- /dev/null +++ b/src/utils/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 diff --git a/src/utils/uart.c b/src/utils/uart.c new file mode 100644 index 0000000..a389e41 --- /dev/null +++ b/src/utils/uart.c @@ -0,0 +1,103 @@ +#include <stddef.h> +#include <stdint.h> +#include "uart.h" +#include "../global.h" + +// Loop <delay> times in a way that the compiler won't optimize away +static inline void delay(int32_t count) +{ + asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n" + : "=r"(count): [count]"0"(count) : "cc"); +} + +void uart_init() +{ + // Disable PL011_UART. + wr32(PL011_UART_CR, 0); + + // Setup the GPIO pin 14 && 15. + + // Disable pull up/down for all GPIO pins & delay for 150 cycles. + wr32(GPPUD, 0); + delay(150); + + // Disable pull up/down for pin 14,15 & delay for 150 cycles. + wr32(GPPUDCLK0, (1 << 14) | (1 << 15)); + delay(150); + + // Write 0 to GPPUDCLK0 to make it take effect. + wr32(GPPUDCLK0, 0); + + // Set integer & fractional part of baud rate. + // Divider = UART_CLOCK/(16 * Baud) + // Fraction part register = (Fractional part * 64) + 0.5 + // UART_CLOCK = 3000000; Baud = 115200. + + // Divider = 3000000 / (16 * 115200) = 1.627 = ~1. + wr32(PL011_UART_IBRD, 1); + // Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40. + wr32(PL011_UART_FBRD, 40); + + // Set 8 bit data transmission (1 stop bit, no parity) + // and disable FIFO to be able to receive interrupt every received + // char, not every 2 chars + wr32(PL011_UART_LCRH, (1 << 5) | (1 << 6)); + + // set interrupt to come when transmit FIFO becomes ≤ 1/8 full + // or receive FIFO becomes ≥ 1/8 full + // (not really matters, since we disabled FIFOs) + wr32(PL011_UART_IFLS, 0); + + // Enable PL011_UART, receive & transfer part of UART.2 + wr32(PL011_UART_CR, (1 << 0) | (1 << 8) | (1 << 9)); + + // At first, it's probably safer to disable interrupts :) + uart_irq_disable(); + + // The above disables the entire uart irq; + // Also disable single sources within it + wr32(PL011_UART_IMSC, 0); +} + +inline static _Bool can_transmit(void) +{ + return !(rd32(PL011_UART_FR) & (1 << 5)); +} + +inline static _Bool can_receive(void) +{ + return !(rd32(PL011_UART_FR) & (1 << 4)); +} + +void putchar(char c) +{ + while (!can_transmit()); + + wr32(PL011_UART_DR, c); +} + +char getchar(void) +{ + while (!can_receive()); + + return rd32(PL011_UART_DR); +} + +_Bool putchar_non_blocking(char c) +{ + if (can_transmit()) + { + wr32(PL011_UART_DR, c); + return 0; + } + + return 1; +} + +int getchar_non_blocking(void) +{ + if (can_receive()) + return rd32(PL011_UART_DR); + + return -1; +} diff --git a/src/utils/uart.h b/src/utils/uart.h new file mode 100644 index 0000000..2a8b7d4 --- /dev/null +++ b/src/utils/uart.h @@ -0,0 +1,106 @@ +#ifndef UART_H +#define UART_H + +#include <stdint.h> +#include "../global.h" +#include "../interrupts/interrupts.h" + +// The offsets for reach register. + +// Controls actuation of pull up/down to ALL GPIO pins. +#define GPPUD (GPIO_BASE + 0x94) + +// Controls actuation of pull up/down for specific GPIO pin. +#define GPPUDCLK0 (GPIO_BASE + 0x98) + +// The base address for UART. +#define PL011_UART_BASE (GPIO_BASE + 0x1000) + +// The offsets for reach register for the UART. +#define PL011_UART_DR (PL011_UART_BASE + 0x00) +#define PL011_UART_RSRECR (PL011_UART_BASE + 0x04) +#define PL011_UART_FR (PL011_UART_BASE + 0x18) +#define PL011_UART_ILPR (PL011_UART_BASE + 0x20) +#define PL011_UART_IBRD (PL011_UART_BASE + 0x24) +#define PL011_UART_FBRD (PL011_UART_BASE + 0x28) +#define PL011_UART_LCRH (PL011_UART_BASE + 0x2C) +#define PL011_UART_CR (PL011_UART_BASE + 0x30) +#define PL011_UART_IFLS (PL011_UART_BASE + 0x34) +#define PL011_UART_IMSC (PL011_UART_BASE + 0x38) +#define PL011_UART_RIS (PL011_UART_BASE + 0x3C) +#define PL011_UART_MIS (PL011_UART_BASE + 0x40) +#define PL011_UART_ICR (PL011_UART_BASE + 0x44) +#define PL011_UART_DMACR (PL011_UART_BASE + 0x48) +#define PL011_UART_ITCR (PL011_UART_BASE + 0x80) +#define PL011_UART_ITIP (PL011_UART_BASE + 0x84) +#define PL011_UART_ITOP (PL011_UART_BASE + 0x88) +#define PL011_UART_TDR (PL011_UART_BASE + 0x8C) + +void uart_init(); +void putchar(char c); +char getchar(void); +_Bool putchar_non_blocking(char c); +int getchar_non_blocking(void); + +// TODO experiment to see if this gives us raw uart irq or the uart +// irq bit or'd with it's enable bit (not crucial for now, sice in our +// code this function only gets called when this irq is enabled) +static inline _Bool uart_irq_pending(void) +{ + return + ((uint32_t) 1 << 25) & rd32(ARM_IRQ_PENDING_2); +} + +static inline void uart_irq_disable(void) +{ + // Mask uart in arm peripheral interrupts + wr32(ARM_DISABLE_IRQS_2, ((uint32_t) 1) << 25); +} + +static inline void uart_irq_enable(void) +{ + // Unmask uart in arm peripheral interrupts + wr32(ARM_ENABLE_IRQS_2, ((uint32_t) 1) << 25); +} + +static inline _Bool uart_recv_irq_pending(void) +{ + return (1 << 4) & rd32(PL011_UART_MIS); +} + +static inline void uart_recv_irq_disable(void) +{ + wr32(PL011_UART_IMSC, rd32(PL011_UART_IMSC) & ~(1 << 4)); +} + +static inline void uart_recv_irq_enable(void) +{ + wr32(PL011_UART_IMSC, rd32(PL011_UART_IMSC) | (1 << 4)); +} + +static inline void uart_clear_recv_irq(void) +{ + wr32(PL011_UART_ICR, (1 << 4)); +} + +static inline _Bool uart_send_irq_pending(void) +{ + return (1 << 5) & rd32(PL011_UART_MIS); +} + +static inline void uart_send_irq_disable(void) +{ + wr32(PL011_UART_IMSC, rd32(PL011_UART_IMSC) & ~(1 << 5)); +} + +static inline void uart_send_irq_enable(void) +{ + wr32(PL011_UART_IMSC, rd32(PL011_UART_IMSC) | (1 << 5)); +} + +static inline void uart_clear_send_irq(void) +{ + wr32(PL011_UART_ICR, (1 << 5)); +} + +#endif // UART_H |