aboutsummaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/io.c71
-rw-r--r--src/utils/io.h28
-rw-r--r--src/utils/pipe_image.c112
-rw-r--r--src/utils/strings.c119
-rw-r--r--src/utils/strings.h33
-rw-r--r--src/utils/svc.S5
-rw-r--r--src/utils/svc_interface.h11
-rw-r--r--src/utils/uart.c103
-rw-r--r--src/utils/uart.h105
9 files changed, 587 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..77c3c07
--- /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..4dd1c2b
--- /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..61c6a38
--- /dev/null
+++ b/src/utils/uart.h
@@ -0,0 +1,105 @@
+#ifndef UART_H
+#define UART_H
+
+#include <stdint.h>
+#include "global.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