diff --git a/thermosphere/Makefile b/thermosphere/Makefile index 16cff99e3..be55d5a50 100644 --- a/thermosphere/Makefile +++ b/thermosphere/Makefile @@ -17,6 +17,22 @@ ifneq (, $(strip $(shell git status --porcelain 2>/dev/null))) AMSREV := $(AMSREV)-dirty endif +ifeq ($(PLATFORM), qemu) + +export PLATFORM := qemu + +PLATFORM_SOURCES := src/platform/qemu +PLATFORM_DEFINES := -DPLATFORM_QEMU + +else + +export PLATFORM := tegra + +PLATFORM_SOURCES := src/platform/tegra +PLATFORM_DEFINES := -DPLATFORM_TEGRA + +endif + #--------------------------------------------------------------------------------- # TARGET is the name of the output # BUILD is the directory where object files & intermediate files will be placed @@ -26,7 +42,7 @@ endif #--------------------------------------------------------------------------------- TARGET := $(notdir $(CURDIR)) BUILD := build -SOURCES := src +SOURCES := src $(PLATFORM_SOURCES) DATA := data INCLUDES := include ../common/include @@ -34,15 +50,16 @@ INCLUDES := include ../common/include # options for code generation #--------------------------------------------------------------------------------- ARCH := -march=armv8-a -mtune=cortex-a57 -mgeneral-regs-only #<- important -DEFINES := -D__CCPLEX__ -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\" -DATMOSPHERE_RELEASE_VERSION_HASH="0x$(AMSHASH)" +DEFINES := -D__CCPLEX__ -DATMOSPHERE_GIT_BRANCH=\"$(AMSBRANCH)\" -DATMOSPHERE_GIT_REV=\"$(AMSREV)\"\ + -DATMOSPHERE_RELEASE_VERSION_HASH="0x$(AMSHASH)" $(PLATFORM_DEFINES) CFLAGS := \ -g \ -Os \ -ffunction-sections \ -fdata-sections \ -fomit-frame-pointer \ - -fno-asynchronous-unwind-tables \ - -fno-unwind-tables \ + -fno-asynchronous-unwind-tables \ + -fno-unwind-tables \ -std=gnu11 \ -Werror \ -Wall \ @@ -109,11 +126,27 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) -.PHONY: $(BUILD) clean all +.PHONY: $(BUILD) clean all qemu qemudbg #--------------------------------------------------------------------------------- all: $(BUILD) +ifeq ($(PLATFORM), qemu) +QEMUFLAGS := -nographic -machine virt,secure=on,virtualization=on -cpu cortex-a57 -smp 2 -m 1024\ + -bios bl1.bin -d unimp -semihosting-config enable,target=native -serial mon:stdio + +# NOTE: copy bl1.bin, bl2.bin, bl31.bin from your own build of Arm Trusted Firmware! + +qemu: all + @cp thermosphere.bin bl33.bin + @qemu-system-aarch64 $(QEMUFLAGS) + +qemudbg: all + @cp thermosphere.bin bl33.bin + @qemu-system-aarch64 $(QEMUFLAGS) -s -S + +endif + $(BUILD): @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile @@ -121,7 +154,7 @@ $(BUILD): #--------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf + @rm -fr $(BUILD) $(TARGET).bin bl33.bin $(TARGET).elf #--------------------------------------------------------------------------------- diff --git a/thermosphere/linker.ld b/thermosphere/linker.ld index 63cfe80f9..60cb854c8 100644 --- a/thermosphere/linker.ld +++ b/thermosphere/linker.ld @@ -1,15 +1,9 @@ OUTPUT_ARCH(aarch64) ENTRY(_start) -MEMORY -{ - NULL : ORIGIN = 0, LENGTH = 0x1000 - main : ORIGIN = 0x80000000, LENGTH = 0xD000 - 0x1000 /* 0x1000 for stacks. */ -} - SECTIONS { - PROVIDE(__start__ = 0x80000000); + PROVIDE(__start__ = ORIGIN(main)); . = __start__; .text : diff --git a/thermosphere/linker.specs b/thermosphere/linker.specs index fb0cb34bc..e38905e89 100644 --- a/thermosphere/linker.specs +++ b/thermosphere/linker.specs @@ -1,4 +1,4 @@ %rename link old_link *link: -%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections +%(old_link) -T %:getenv(TOPDIR /%:getenv(PLATFORM .mem)) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections diff --git a/thermosphere/qemu.mem b/thermosphere/qemu.mem new file mode 100644 index 000000000..4c88484c0 --- /dev/null +++ b/thermosphere/qemu.mem @@ -0,0 +1,5 @@ +MEMORY +{ + NULL : ORIGIN = 0, LENGTH = 0x1000 + main : ORIGIN = 0x60000000, LENGTH = 128M /* QEMU's memory map changes dynamically? */ +} \ No newline at end of file diff --git a/thermosphere/src/log.c b/thermosphere/src/log.c index 492db46e0..7882b0225 100644 --- a/thermosphere/src/log.c +++ b/thermosphere/src/log.c @@ -16,7 +16,7 @@ #include #include "log.h" -#include "uart.h" +#include "platform/uart.h" #include "utils.h" // NOTE: UNSAFE! @@ -28,6 +28,6 @@ int serialLog(const char *fmt, ...) int res = vsprintf(buf, fmt, args); va_end(args); - uart_send(UART_C, buf, res); + uartWriteData(buf, (size_t)res); return res; } diff --git a/thermosphere/src/main.c b/thermosphere/src/main.c index 2b1c3936f..3e51e7a58 100644 --- a/thermosphere/src/main.c +++ b/thermosphere/src/main.c @@ -1,12 +1,10 @@ #include "utils.h" -#include "uart.h" #include "log.h" +#include "platform/uart.h" int main(void) { - uart_config(UART_C); - uart_reset(UART_C); - uart_init(UART_C, 115200, true); + uartInit(115200); //uart_send(UART_C, "0123\n", 3); serialLog("Hello from Thermosphere!\r\n"); diff --git a/thermosphere/src/platform/qemu/uart.c b/thermosphere/src/platform/qemu/uart.c new file mode 100644 index 000000000..45195c954 --- /dev/null +++ b/thermosphere/src/platform/qemu/uart.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "uart.h" +#include "../../utils.h" + +// Adapted from ARM TF asm code +// AMBA PL101 driver + +/* + * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +//115200 + +void uartInit(u32 baudRate) +{ + // First, disable UART + g_uartRegs->CR &= ~PL011_UARTCR_UARTEN; + + // Set baudrate, Divisor = (Uart clock * 4) / baudrate; stored in IBRD|FBRD + u32 divisor = (4 * UART0_CLK_IN_HZ) / baudRate; + g_uartRegs->IBRD = divisor >> 6; + g_uartRegs->FBRD = divisor & 0x3F; + g_uartRegs->LCR_H = PL011_LINE_CONTROL; + + // Clear any pending errors + g_uartRegs->ECR = 0; + + // Enable tx, rx, and uart overall + g_uartRegs->CR = PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN; +} + +void uartWriteData(const void *buffer, size_t size) +{ + const u8 *buf8 = (const u8 *)buffer; + for (size_t i = 0; i < size; i++) { + while (g_uartRegs->FR & PL011_UARTFR_TXFF); // while TX FIFO full + g_uartRegs->DR = buf8[i]; + } +} + +void uartReadData(void *buffer, size_t size) +{ + u8 *buf8 = (u8 *)buffer; + size_t i; + + for (i = 0; i < size; i++) { + while (g_uartRegs->FR & PL011_UARTFR_RXFE); + buf8[i] = g_uartRegs->DR; + } +} + +size_t uartReadDataMax(void *buffer, size_t maxSize) +{ + u8 *buf8 = (u8 *)buffer; + size_t i; + + for (i = 0; i < maxSize && !(g_uartRegs->FR & PL011_UARTFR_RXFE); i++) { + buf8[i] = g_uartRegs->DR; + } + + return 1 + i; +} \ No newline at end of file diff --git a/thermosphere/src/platform/qemu/uart.h b/thermosphere/src/platform/qemu/uart.h new file mode 100644 index 000000000..0b15bfb96 --- /dev/null +++ b/thermosphere/src/platform/qemu/uart.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "../../types.h" + +// AMBA PL011 driver + +/* + * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#if 0 +/* PL011 Registers */ +#define UARTDR 0x000 +#define UARTRSR 0x004 +#define UARTECR 0x004 +#define UARTFR 0x018 +#define UARTIMSC 0x038 +#define UARTRIS 0x03C +#define UARTICR 0x044 + +/* PL011 registers (out of the SBSA specification) */ +#if !PL011_GENERIC_UART +#define UARTILPR 0x020 +#define UARTIBRD 0x024 +#define UARTFBRD 0x028 +#define UARTLCR_H 0x02C +#define UARTCR 0x030 +#define UARTIFLS 0x034 +#define UARTMIS 0x040 +#define UARTDMACR 0x048 +#endif /* !PL011_GENERIC_UART */ + +#endif +typedef struct PL011UartRegisters { + u32 DR; + union { + u32 SR; + u32 ECR; + }; + u32 _0x08, _0x0C, _0x10; + u32 FR; + u32 _0x1C; + u32 ILPR; + u32 IBRD; + u32 FBRD; + u32 LCR_H; + u32 CR; + u32 IFLS; + u32 IMSC; + u32 TRIS; + u32 TMIS; + u32 TICR; + u32 TDMACR; +} PL011UartRegisters; + +/* Data status bits */ +#define UART_DATA_ERROR_MASK 0x0F00 + +/* Status reg bits */ +#define UART_STATUS_ERROR_MASK 0x0F + +/* Flag reg bits */ +#define PL011_UARTFR_RI (1 << 8) /* Ring indicator */ +#define PL011_UARTFR_TXFE (1 << 7) /* Transmit FIFO empty */ +#define PL011_UARTFR_RXFF (1 << 6) /* Receive FIFO full */ +#define PL011_UARTFR_TXFF (1 << 5) /* Transmit FIFO full */ +#define PL011_UARTFR_RXFE (1 << 4) /* Receive FIFO empty */ +#define PL011_UARTFR_BUSY (1 << 3) /* UART busy */ +#define PL011_UARTFR_DCD (1 << 2) /* Data carrier detect */ +#define PL011_UARTFR_DSR (1 << 1) /* Data set ready */ +#define PL011_UARTFR_CTS (1 << 0) /* Clear to send */ + +#define PL011_UARTFR_TXFF_BIT 5 /* Transmit FIFO full bit in UARTFR register */ +#define PL011_UARTFR_RXFE_BIT 4 /* Receive FIFO empty bit in UARTFR register */ +#define PL011_UARTFR_BUSY_BIT 3 /* UART busy bit in UARTFR register */ + +/* Control reg bits */ +#if !PL011_GENERIC_UART +#define PL011_UARTCR_CTSEN (1 << 15) /* CTS hardware flow control enable */ +#define PL011_UARTCR_RTSEN (1 << 14) /* RTS hardware flow control enable */ +#define PL011_UARTCR_RTS (1 << 11) /* Request to send */ +#define PL011_UARTCR_DTR (1 << 10) /* Data transmit ready. */ +#define PL011_UARTCR_RXE (1 << 9) /* Receive enable */ +#define PL011_UARTCR_TXE (1 << 8) /* Transmit enable */ +#define PL011_UARTCR_LBE (1 << 7) /* Loopback enable */ +#define PL011_UARTCR_UARTEN (1 << 0) /* UART Enable */ + +#if !defined(PL011_LINE_CONTROL) +/* FIFO Enabled / No Parity / 8 Data bit / One Stop Bit */ +#define PL011_LINE_CONTROL (PL011_UARTLCR_H_FEN | PL011_UARTLCR_H_WLEN_8) +#endif + +/* Line Control Register Bits */ +#define PL011_UARTLCR_H_SPS (1 << 7) /* Stick parity select */ +#define PL011_UARTLCR_H_WLEN_8 (3 << 5) +#define PL011_UARTLCR_H_WLEN_7 (2 << 5) +#define PL011_UARTLCR_H_WLEN_6 (1 << 5) +#define PL011_UARTLCR_H_WLEN_5 (0 << 5) +#define PL011_UARTLCR_H_FEN (1 << 4) /* FIFOs Enable */ +#define PL011_UARTLCR_H_STP2 (1 << 3) /* Two stop bits select */ +#define PL011_UARTLCR_H_EPS (1 << 2) /* Even parity select */ +#define PL011_UARTLCR_H_PEN (1 << 1) /* Parity Enable */ +#define PL011_UARTLCR_H_BRK (1 << 0) /* Send break */ + +#endif /* !PL011_GENERIC_UART */ + +#define UART0_BASE 0x09000000 +#define UART1_BASE 0x09040000 +#define UART0_CLK_IN_HZ 1 +#define UART1_CLK_IN_HZ 1 + +static volatile PL011UartRegisters *const g_uartRegs = (volatile PL011UartRegisters *)UART0_BASE; + +void uartInit(u32 baudRate); +void uartWriteData(const void *buffer, size_t size); +void uartReadData(void *buffer, size_t size); +size_t uartReadDataMax(void *buffer, size_t maxSize); diff --git a/thermosphere/src/car.c b/thermosphere/src/platform/tegra/car.c similarity index 99% rename from thermosphere/src/car.c rename to thermosphere/src/platform/tegra/car.c index d23635eaa..439d34c45 100644 --- a/thermosphere/src/car.c +++ b/thermosphere/src/platform/tegra/car.c @@ -16,7 +16,7 @@ #include "car.h" #include "timers.h" -#include "utils.h" +#include "../../utils.h" static inline uint32_t get_clk_source_reg(CarDevice dev) { switch (dev) { diff --git a/thermosphere/src/car.h b/thermosphere/src/platform/tegra/car.h similarity index 99% rename from thermosphere/src/car.h rename to thermosphere/src/platform/tegra/car.h index 72c9579de..60418ffc0 100644 --- a/thermosphere/src/car.h +++ b/thermosphere/src/platform/tegra/car.h @@ -15,7 +15,7 @@ */ #pragma once -#include "utils.h" +#include "../../utils.h" #define CAR_BASE 0x60006000 #define MAKE_CAR_REG(n) MAKE_REG32(CAR_BASE + n) diff --git a/thermosphere/src/gpio.c b/thermosphere/src/platform/tegra/gpio.c similarity index 99% rename from thermosphere/src/gpio.c rename to thermosphere/src/platform/tegra/gpio.c index ea44816d9..1684f99c1 100644 --- a/thermosphere/src/gpio.c +++ b/thermosphere/src/platform/tegra/gpio.c @@ -18,7 +18,7 @@ #include #include "gpio.h" -#include "utils.h" +#include "../../utils.h" /** * Returns a GPIO bank object that corresponds to the given GPIO pin, diff --git a/thermosphere/src/gpio.h b/thermosphere/src/platform/tegra/gpio.h similarity index 100% rename from thermosphere/src/gpio.h rename to thermosphere/src/platform/tegra/gpio.h diff --git a/thermosphere/src/misc.h b/thermosphere/src/platform/tegra/misc.h similarity index 98% rename from thermosphere/src/misc.h rename to thermosphere/src/platform/tegra/misc.h index 5e5b463c3..223e470bb 100644 --- a/thermosphere/src/misc.h +++ b/thermosphere/src/platform/tegra/misc.h @@ -16,7 +16,7 @@ #pragma once -#include "utils.h" +#include "../../utils.h" #define MISC_BASE 0x70000000ull diff --git a/thermosphere/src/pinmux.h b/thermosphere/src/platform/tegra/pinmux.h similarity index 99% rename from thermosphere/src/pinmux.h rename to thermosphere/src/platform/tegra/pinmux.h index 2eaad0667..7bc76400c 100644 --- a/thermosphere/src/pinmux.h +++ b/thermosphere/src/platform/tegra/pinmux.h @@ -16,6 +16,8 @@ #pragma once +#include + #define PINMUX_BASE 0x70003000 #define MAKE_PINMUX_REG(n) MAKE_REG32(PINMUX_BASE + n) diff --git a/thermosphere/src/timers.h b/thermosphere/src/platform/tegra/timers.h similarity index 99% rename from thermosphere/src/timers.h rename to thermosphere/src/platform/tegra/timers.h index 682938949..a0a85ecd9 100644 --- a/thermosphere/src/timers.h +++ b/thermosphere/src/platform/tegra/timers.h @@ -15,7 +15,7 @@ */ #pragma once -#include "utils.h" +#include "../../utils.h" #define TIMERS_BASE 0x60005000 #define MAKE_TIMERS_REG(n) MAKE_REG32(TIMERS_BASE + n) diff --git a/thermosphere/src/uart.c b/thermosphere/src/platform/tegra/uart.c similarity index 94% rename from thermosphere/src/uart.c rename to thermosphere/src/platform/tegra/uart.c index 747157018..a6a442e99 100644 --- a/thermosphere/src/uart.c +++ b/thermosphere/src/platform/tegra/uart.c @@ -130,3 +130,14 @@ void uart_recv(UartDevice dev, void *buf, size_t len) { *((uint8_t *)buf + i) = uart->UART_THR_DLAB; } } + +size_t uart_recv_max(UartDevice dev, void *buf, size_t max_len) { + volatile tegra_uart_t *uart = uart_get_regs(dev); + size_t i; + + for (i = 0; i < max_len && (uart->UART_LSR & UART_LSR_RDR); i++) { + *((uint8_t *)buf + i) = uart->UART_THR_DLAB; + } + + return 1 + i; +} \ No newline at end of file diff --git a/thermosphere/src/uart.h b/thermosphere/src/platform/tegra/uart.h similarity index 98% rename from thermosphere/src/uart.h rename to thermosphere/src/platform/tegra/uart.h index 8550181c4..66b34e4c8 100644 --- a/thermosphere/src/uart.h +++ b/thermosphere/src/platform/tegra/uart.h @@ -17,7 +17,7 @@ #pragma once -#include "types.h" +#include "../../utils.h" #define UART_BASE 0x70006000 @@ -162,6 +162,7 @@ void uart_init(UartDevice dev, uint32_t baud, bool inverted); void uart_wait_idle(UartDevice dev, UartVendorStatus status); void uart_send(UartDevice dev, const void *buf, size_t len); void uart_recv(UartDevice dev, void *buf, size_t len); +size_t uart_recv_max(UartDevice dev, void *buf, size_t max_len); static inline volatile tegra_uart_t *uart_get_regs(UartDevice dev) { static const size_t offsets[] = {0, 0x40, 0x200, 0x300, 0x400}; diff --git a/thermosphere/src/platform/uart.h b/thermosphere/src/platform/uart.h new file mode 100644 index 000000000..e34f4f388 --- /dev/null +++ b/thermosphere/src/platform/uart.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifdef PLATFORM_TEGRA +#include "tegra/uart.h" + +#define DEFAULT_UART UART_C +#define DEFAULT_UARTINV_STATUS true + +static inline void uartInit(u32 baudRate) +{ + uart_reset(DEFAULT_UART); + uart_init(DEFAULT_UART, baudRate, DEFAULT_UARTINV_STATUS); +} + +static inline void uartWriteData(const void *buffer, size_t size) +{ + uart_send(DEFAULT_UART, buffer, size); +} + +static inline void uartReadData(void *buffer, size_t size) +{ + uart_recv(DEFAULT_UART, buffer, size); +} + +static inline size_t uartReadDataMax(void *buffer, size_t maxSize) +{ + return uart_recv_max(DEFAULT_UART, buffer, maxSize); +} + +#elif defined(PLATFORM_QEMU) + +#include "qemu/uart.h" + +#else + +#error "Error: platform not defined" + +#endif \ No newline at end of file diff --git a/thermosphere/tegra.mem b/thermosphere/tegra.mem new file mode 100644 index 000000000..8d767effb --- /dev/null +++ b/thermosphere/tegra.mem @@ -0,0 +1,5 @@ +MEMORY +{ + NULL : ORIGIN = 0, LENGTH = 0x1000 + main : ORIGIN = 0x80000000, LENGTH = 0xD000 - 0x1000 /* 0x1000 for stacks. */ +} \ No newline at end of file