thermosphere: major refactor of memory map

- use recursive stage 1 page table (thanks @fincs for this idea)
- NULL now unmapped
- no identity mapping
- image + GICv2 now mapped at the same address for every platform
- tempbss mapped just after "real" bss, can now steal unused mem from
the latter
- no hardcoded VAs for other MMIO devices
- tegra: remove timers, use the generic timer instead
This commit is contained in:
TuxSH
2020-01-17 22:10:26 +00:00
parent 92a291cd41
commit 626f0ecb98
47 changed files with 795 additions and 469 deletions

View File

@@ -0,0 +1,27 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef PLATFORM_TEGRA
#include "tegra/devices.h"
#elif defined(PLATFORM_QEMU)
#include "qemu/devices.h"
#endif

View File

@@ -0,0 +1,31 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "devices.h"
#include "../../memory_map.h"
#include "../../utils.h"
#include "uart.h"
void devicesMapAllExtra(void)
{
uartSetRegisterBase(memoryMapPlatformMmio(MEMORY_MAP_PA_UART, 0x1000));
// Don't broadcast, since it's only ran once per boot by only one core, before the others are started...
__tlb_invalidate_el2_local();
__dsb();
__isb();
}

View File

@@ -0,0 +1,19 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
void devicesMapAllExtra(void);

View File

@@ -18,17 +18,17 @@
#include "../../gicv2.h"
// For both guest and host
#define MAX_NUM_REGISTERED_INTERRUPTS 512
#define MEMORY_MAP_PA_GICD 0x08000000ull
#define MEMORY_MAP_PA_GICC 0x08010000ull
#define MEMORY_MAP_PA_GICH 0x08030000ull
#define MEMORY_MAP_PA_GICV 0x08040000ull
#define GIC_IRQID_PMU 23
#define GIC_IRQID_MAINTENANCE 25
#define GIC_IRQID_NS_PHYS_HYP_TIMER 26
#define GIC_IRQID_NS_VIRT_TIMER 27
//#define GIC_IRQID_LEGACY_NFIQ 28 not defined?
#define GIC_IRQID_SEC_PHYS_TIMER 29
#define GIC_IRQID_NS_PHYS_TIMER 30
//#define GIC_IRQID_LEGACY_NIRQ 31 not defined?
#define GIC_IRQID_NS_VIRT_HYP_TIMER GIC_IRQID_SPURIOUS // SBSA: 28. Unimplemented
@@ -36,11 +36,3 @@
#define GIC_IRQID_SEC_VIRT_HYP_TIMER GIC_IRQID_SPURIOUS // SBSA: 19. Unimplemented
#define GIC_IRQID_UART (32 + 1)
static inline void initGicV2Pointers(ArmGicV2 *gic)
{
gic->gicd = (volatile ArmGicV2Distributor *)0x08000000ull;
gic->gicc = (volatile ArmGicV2Controller *)0x08010000ull;
gic->gich = (volatile ArmGicV2VirtualInterfaceController *)0x08030000ull;
gic->gicv = (volatile ArmGicV2Controller *)0x08040000ull;
}

View File

@@ -14,7 +14,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "memory_map.h"
#include "stage2_config.h"
#include "interrupt_config.h"
#include "../../memory_map.h"
#include "../../utils.h"
#include "../../mmu.h"
#include "../../core_ctx.h"
@@ -23,11 +25,10 @@
#define ADDRSPACESZ 39
#define ADDRSPACESZ2 ADDRSPACESZ
static ALIGN(0x1000) u64 g_ttbl[BIT(ADDRSPACESZ - 30)] = {0};
static ALIGN(0x1000) u64 g_vttbl[BIT(ADDRSPACESZ2 - 30)] = {0};
static TEMPORARY ALIGN(0x1000) u64 g_vttbl[BIT(ADDRSPACESZ2 - 30)] = {0};
static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l2_mmio_0_0[512] = {0};
static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l3_0[512] = {0};
static TEMPORARY uintptr_t g_vttblPaddr;
static inline void identityMapL1(u64 *tbl, uintptr_t addr, size_t size, u64 attribs)
{
@@ -44,39 +45,31 @@ static inline void identityMapL3(u64 *tbl, uintptr_t addr, size_t size, u64 attr
mmu_map_block_range(3, tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE);
}
uintptr_t configureMemoryMap(u32 *addrSpaceSize)
{
// QEMU virt RAM address space starts at 0x40000000
*addrSpaceSize = ADDRSPACESZ;
if (currentCoreCtx->isBootCore && !currentCoreCtx->warmboot) {
identityMapL1(g_ttbl, 0x00000000ull, BITL(30), ATTRIB_MEMTYPE_DEVICE);
identityMapL1(g_ttbl, 0x40000000ull, (BITL(ADDRSPACESZ - 30) - 1ull) << 30, ATTRIB_MEMTYPE_NORMAL);
}
return (uintptr_t)g_ttbl;
}
uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize)
uintptr_t stage2Configure(u32 *addrSpaceSize)
{
*addrSpaceSize = ADDRSPACESZ2;
static const u64 devattrs = MMU_S2AP_RW | MMU_MEMATTR_DEVICE_NGNRE;
static const u64 devattrs = 0 | MMU_S2AP_RW | MMU_MEMATTR_DEVICE_NGNRE;
static const u64 unchanged = MMU_S2AP_RW | MMU_MEMATTR_NORMAL_CACHEABLE_OR_UNCHANGED;
if (currentCoreCtx->isBootCore) {
g_vttblPaddr = va2pa(g_vttbl);
uintptr_t *l2pa = (uintptr_t *)va2pa(g_vttbl_l2_mmio_0_0);
uintptr_t *l3pa = (uintptr_t *)va2pa(g_vttbl_l3_0);
identityMapL1(g_vttbl, 0, 4ull << 30, unchanged);
identityMapL1(g_vttbl, 0x40000000ull, (BITL(ADDRSPACESZ2 - 30) - 1ull) << 30, unchanged);
mmu_map_table(1, g_vttbl, 0x00000000ull, g_vttbl_l2_mmio_0_0, 0);
mmu_map_table(1, g_vttbl, 0x00000000ull, l2pa, 0);
identityMapL2(g_vttbl_l2_mmio_0_0, 0x08000000ull, BITL(30), unchanged);
mmu_map_table(2, g_vttbl_l2_mmio_0_0, 0x08000000ull, g_vttbl_l3_0, 0);
mmu_map_table(2, g_vttbl_l2_mmio_0_0, 0x08000000ull, l3pa, 0);
identityMapL3(g_vttbl_l3_0, 0x08000000ull, BITL(21), unchanged);
// GICD -> trapped, GICv2 CPU -> vCPU interface, GICH -> trapped (deny access)
mmu_unmap_range(3, g_vttbl_l3_0, 0x08000000ull, 0x10000ull);
mmu_unmap_range(3, g_vttbl_l3_0, 0x08030000ull, 0x10000ull);
mmu_map_page_range(g_vttbl_l3_0, 0x08010000ull, 0x08040000ull, 0x10000ull, devattrs);
mmu_unmap_range(3, g_vttbl_l3_0, MEMORY_MAP_PA_GICD, 0x10000ull);
mmu_unmap_range(3, g_vttbl_l3_0, MEMORY_MAP_PA_GICH, 0x10000ull);
mmu_map_page_range(g_vttbl_l3_0, MEMORY_MAP_PA_GICC, MEMORY_MAP_PA_GICV, 0x10000ull, devattrs);
}
return (uintptr_t)g_vttbl;
return g_vttblPaddr;
}

View File

@@ -18,5 +18,4 @@
#include "../../types.h"
uintptr_t configureMemoryMap(u32 *addrSpaceSize);
uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize);
uintptr_t stage2Configure(u32 *addrSpaceSize);

View File

@@ -28,16 +28,23 @@
//115200
static uintptr_t g_uartRegBase;
static inline volatile PL011UartRegisters *uartGetRegisters(UartDevice dev)
{
switch (dev) {
case UART_A:
return (volatile PL011UartRegisters *)0x09000000;
return (volatile PL011UartRegisters *)g_uartRegBase;
default:
return NULL;
}
}
void uartSetRegisterBase(uintptr_t regBase)
{
g_uartRegBase = regBase;
}
void uartInit(UartDevice dev, u32 baudRate, u32 flags)
{
/* The TRM (DDI0183) reads:

View File

@@ -19,6 +19,8 @@
#include "../../utils.h"
#include "interrupt_config.h"
#define MEMORY_MAP_PA_UART 0x09000000ull
// AMBA PL011 driver
// Originally from
/*
@@ -56,10 +58,10 @@ typedef struct PL011UartRegisters {
} PL011UartRegisters;
// Data status bits
#define UART_DATA_ERROR_MASK 0x0F00
#define PL011_DATA_ERROR_MASK 0x0F00
// Status reg bits
#define UART_STATUS_ERROR_MASK 0x0F
#define PL011_STATUS_ERROR_MASK 0x0F
// Errors
#define PL011_OE BIT(3) // Overrun error
@@ -128,6 +130,7 @@ typedef struct PL011UartRegisters {
#define UART_CLK_IN_HZ 1
void uartSetRegisterBase(uintptr_t regBase);
void uartInit(UartDevice dev, u32 baudRate, u32 flags);
void uartWriteData(UartDevice dev, const void *buffer, size_t size);
void uartReadData(UartDevice dev, void *buffer, size_t size);

View File

@@ -17,56 +17,12 @@
#include "../utils.h"
#include "../sysreg.h"
#include "../mmu.h"
#include "memory_map_mmu_cfg.h"
#include "stage2.h"
void configureMemoryMapEnableMmu(void)
void stage2ConfigureAndEnable(void)
{
u32 addrSpaceSize;
uintptr_t ttbr0 = configureMemoryMap(&addrSpaceSize);
u32 ps = GET_SYSREG(id_aa64mmfr0_el1) & 0xF;
/*
- PA size: from ID_AA64MMFR0_EL1
- Granule size: 4KB
- Shareability attribute for memory associated with translation table walks using TTBR0_EL2: Inner Shareable
- Outer cacheability attribute for memory associated with translation table walks using TTBR0_EL2: Normal memory, Outer Write-Back Read-Allocate Write-Allocate Cacheable
- Inner cacheability attribute for memory associated with translation table walks using TTBR0_EL2: Normal memory, Inner Write-Back Read-Allocate Write-Allocate Cacheable
- T0SZ = from configureMemoryMap
*/
u64 tcr = TCR_EL2_RSVD | TCR_PS(ps) | TCR_TG0_4K | TCR_SHARED_INNER | TCR_ORGN_WBWA | TCR_IRGN_WBWA | TCR_T0SZ(addrSpaceSize);
/*
- Attribute 0: Normal memory, Inner and Outer Write-Back Read-Allocate Write-Allocate Non-transient
- Attribute 1: Device-nGnRE memory
- Other attributes: Device-nGnRnE memory
*/
u64 mair = 0x4FFull;
// MMU regs config
SET_SYSREG(ttbr0_el2, ttbr0);
SET_SYSREG(tcr_el2, tcr);
SET_SYSREG(mair_el2, mair);
__dsb();
__isb();
// TLB invalidation
__tlb_invalidate_el2();
__dsb();
__isb();
// Enable MMU & enable caching
u64 sctlr = GET_SYSREG(sctlr_el2);
sctlr |= SCTLR_ELx_I | SCTLR_ELx_C | SCTLR_ELx_M;
SET_SYSREG(sctlr_el2, sctlr);
__dsb();
__isb();
}
void configureMemoryMapEnableStage2(void)
{
u32 addrSpaceSize;
uintptr_t vttbr = configureStage2MemoryMap(&addrSpaceSize);
uintptr_t vttbr = stage2Configure(&addrSpaceSize);
u32 ps = GET_SYSREG(id_aa64mmfr0_el1) & 0xF;
/*
@@ -86,15 +42,15 @@ void configureMemoryMapEnableStage2(void)
__dsb();
__isb();
// TLB invalidation
__tlb_invalidate_el1_stage12();
__dsb();
__isb();
// Enable stage 2
u64 hcr = GET_SYSREG(hcr_el2);
hcr |= HCR_VM;
SET_SYSREG(hcr_el2, hcr);
__dsb();
__isb();
// TLB invalidation
__tlb_invalidate_el1_stage12_local();
__dsb();
__isb();
}

View File

@@ -18,13 +18,12 @@
#ifdef PLATFORM_TEGRA
#include "tegra/memory_map.h"
#include "tegra/stage2_config.h"
#elif defined(PLATFORM_QEMU)
#include "qemu/memory_map.h"
#include "qemu/stage2_config.h"
#endif
void configureMemoryMapEnableMmu(void);
void configureMemoryMapEnableStage2(void);
void stage2ConfigureAndEnable(void);

View File

@@ -15,9 +15,20 @@
*/
#include "car.h"
#include "timers.h"
#include "../../utils.h"
static uintptr_t g_carRegs;
static inline volatile tegra_car_t *car_get_regs(void)
{
return (volatile tegra_car_t *)g_carRegs;
}
static inline volatile uint32_t *car_reg_at(uint32_t offset)
{
return (volatile uint32_t *)(g_carRegs + offset);
}
static inline uint32_t get_clk_source_reg(CarDevice dev) {
switch (dev) {
case CARDEVICE_UARTA: return 0x178;
@@ -93,24 +104,29 @@ static inline uint32_t get_clk_source_div(CarDevice dev) {
static uint32_t g_clk_reg_offsets[NUM_CAR_BANKS] = {0x010, 0x014, 0x018, 0x360, 0x364, 0x280, 0x298};
static uint32_t g_rst_reg_offsets[NUM_CAR_BANKS] = {0x004, 0x008, 0x00C, 0x358, 0x35C, 0x28C, 0x2A4};
void car_set_regs(uintptr_t regs)
{
g_carRegs = regs;
}
void clk_enable(CarDevice dev) {
uint32_t clk_source_reg;
if ((clk_source_reg = get_clk_source_reg(dev))) {
MAKE_CAR_REG(clk_source_reg) = (get_clk_source_val(dev) << 29) | get_clk_source_div(dev);
*car_reg_at(clk_source_reg) = (get_clk_source_val(dev) << 29) | get_clk_source_div(dev);
}
MAKE_CAR_REG(g_clk_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
*car_reg_at(g_clk_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
}
void clk_disable(CarDevice dev) {
MAKE_CAR_REG(g_clk_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
*car_reg_at(g_clk_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
}
void rst_enable(CarDevice dev) {
MAKE_CAR_REG(g_rst_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
*car_reg_at(g_rst_reg_offsets[dev >> 5]) |= BIT(dev & 0x1F);
}
void rst_disable(CarDevice dev) {
MAKE_CAR_REG(g_rst_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
*car_reg_at(g_rst_reg_offsets[dev >> 5]) &= ~(BIT(dev & 0x1F));
}
void clkrst_enable(CarDevice dev) {
@@ -127,10 +143,10 @@ void clkrst_reboot(CarDevice dev) {
clkrst_disable(dev);
if (dev == CARDEVICE_KFUSE) {
/* Workaround for KFUSE clock. */
clk_enable(dev);
/*clk_enable(dev);
udelay(100);
rst_disable(dev);
udelay(200);
udelay(200);*/
} else {
clkrst_enable(dev);
}

View File

@@ -17,8 +17,7 @@
#pragma once
#include "../../utils.h"
#define CAR_BASE 0x60006000
#define MAKE_CAR_REG(n) MAKE_REG32(CAR_BASE + n)
#define MEMORY_MAP_PA_CAR 0x60006000ul
#define CLK_L_SDMMC1 (1 << 14)
#define CLK_L_SDMMC2 (1 << 9)
@@ -485,9 +484,7 @@ typedef struct {
uint32_t sdmmc4_div_clk_shaper_ctrl; /* _SDMMC4_DIV_CLK_SHAPER_CTRL_0, 0x744 */
} tegra_car_t;
static inline volatile tegra_car_t *car_get_regs(void) {
return (volatile tegra_car_t *)CAR_BASE;
}
void car_set_regs(uintptr_t regs);
void clk_enable(CarDevice dev);
void clk_disable(CarDevice dev);

View File

@@ -0,0 +1,38 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "devices.h"
#include "../../memory_map.h"
#include "../../utils.h"
#include "uart.h"
#include "car.h"
#include "gpio.h"
#include "pinmux.h"
void devicesMapAllExtra(void)
{
uartSetRegisterBase(memoryMapPlatformMmio(MEMORY_MAP_PA_UART, 0x1000));
car_set_regs(memoryMapPlatformMmio(MEMORY_MAP_PA_CAR, 0x1000));
gpio_set_regs(memoryMapPlatformMmio(MEMORY_MAP_PA_GPIO, 0x1000));
pinmux_set_regs(memoryMapPlatformMmio(MEMORY_MAP_PA_PINMUX, 0x1000));
// Don't broadcast, since it's only ran once per boot by only one core, before the others are started...
__tlb_invalidate_el2_local();
__dsb();
__isb();
}

View File

@@ -0,0 +1,19 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
void devicesMapAllExtra(void);

View File

@@ -19,6 +19,13 @@
#include "gpio.h"
#include "../../utils.h"
static uintptr_t g_gpioRegs;
static inline volatile tegra_gpio_t *gpio_get_regs(void)
{
return (volatile tegra_gpio_t *)g_gpioRegs;
}
static volatile tegra_gpio_bank_t *gpio_get_bank(uint32_t pin) {
volatile tegra_gpio_t *gpio = gpio_get_regs();
uint32_t bank_number = (pin >> GPIO_BANK_SHIFT);
@@ -67,6 +74,11 @@ static bool gpio_simple_register_get(uint32_t pin, uint32_t offset) {
return !!(cluster[port] & mask);
}
void gpio_set_regs(uintptr_t regs)
{
g_gpioRegs = regs;
}
void gpio_configure_mode(uint32_t pin, uint32_t mode) {
gpio_simple_register_set(pin, mode == GPIO_MODE_GPIO, offsetof(tegra_gpio_bank_t, config));
}

View File

@@ -17,16 +17,15 @@
#pragma once
#include <stdint.h>
#define GPIO_BASE 0x6000D000
#define MAKE_GPIO_REG(n) MAKE_REG32(GPIO_BASE + n)
#define MEMORY_MAP_PA_GPIO 0x6000D000ul
#define TEGRA_GPIO_PORTS 4
#define TEGRA_GPIO_BANKS 8
#define GPIO_BANK_SHIFT 5
#define GPIO_BANK_SHIFT 5
#define GPIO_PORT_SHIFT 3
#define GPIO_PORT_MASK 0x03
#define GPIO_PIN_MASK 0x07
typedef enum {
TEGRA_GPIO_PORT_A = 0,
TEGRA_GPIO_PORT_B = 1,
@@ -85,11 +84,6 @@ typedef struct {
tegra_gpio_bank_t bank[TEGRA_GPIO_BANKS];
} tegra_gpio_t;
static inline volatile tegra_gpio_t *gpio_get_regs(void)
{
return (volatile tegra_gpio_t *)GPIO_BASE;
}
#define TEGRA_GPIO(port, offset) \
((TEGRA_GPIO_PORT_##port * 8) + offset)
@@ -117,6 +111,7 @@ static inline volatile tegra_gpio_t *gpio_get_regs(void)
#define GPIO_LCD_BL_EN TEGRA_GPIO(V, 1)
#define GPIO_LCD_BL_RST TEGRA_GPIO(V, 2)
void gpio_set_regs(uintptr_t regs);
void gpio_configure_mode(uint32_t pin, uint32_t mode);
void gpio_configure_direction(uint32_t pin, uint32_t dir);
void gpio_write(uint32_t pin, uint32_t value);

View File

@@ -18,8 +18,10 @@
#include "../../gicv2.h"
// For both guest and host
#define MAX_NUM_REGISTERED_INTERRUPTS 512
#define MEMORY_MAP_PA_GICD 0x50041000ull
#define MEMORY_MAP_PA_GICC 0x50042000ull
#define MEMORY_MAP_PA_GICH 0x50044000ull
#define MEMORY_MAP_PA_GICV 0x50046000ull
#define GIC_IRQID_MAINTENANCE 25
#define GIC_IRQID_NS_PHYS_HYP_TIMER 26
@@ -37,11 +39,3 @@
#define GIC_IRQID_UARTB (32 + 37)
#define GIC_IRQID_UARTC (32 + 46)
#define GIC_IRQID_UARTD (32 + 90)
static inline void initGicV2Pointers(ArmGicV2 *gic)
{
gic->gicd = (volatile ArmGicV2Distributor *)0x50041000ull;
gic->gicc = (volatile ArmGicV2Controller *)0x50042000ull;
gic->gich = (volatile ArmGicV2VirtualInterfaceController *)0x50044000ull;
gic->gicv = (volatile ArmGicV2Controller *)0x50046000ull;
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2018-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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../../utils.h"
#define MISC_BASE 0x70000000ull
#define MAKE_MISC_REG(n) MAKE_REG32(MISC_BASE + n)
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 MAKE_MISC_REG(0x0C00)
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 MAKE_MISC_REG(0x0C04)
#define APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0 MAKE_MISC_REG(0x0C08)
#define PINMUX_AUX_GEN1_I2C_SCL_0 MAKE_MISC_REG(0x30BC)
#define PINMUX_AUX_GEN1_I2C_SDA_0 MAKE_MISC_REG(0x30C0)
#define PINMUX_AUX_UARTn_TX_0(n) MAKE_MISC_REG(0x30E4 + 0x10 * (n))
#define PINMUX_AUX_UARTn_RX_0(n) MAKE_MISC_REG(0x30E8 + 0x10 * (n))
#define PINMUX_AUX_UARTn_RTS_0(n) MAKE_MISC_REG(0x30EC + 0x10 * (n))
#define PINMUX_AUX_UARTn_CTS_0(n) MAKE_MISC_REG(0x30F0 + 0x10 * (n))

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2018-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 <http://www.gnu.org/licenses/>.
*/
#include "pinmux.h"
uintptr_t g_pinmuxRegs;

View File

@@ -18,8 +18,7 @@
#include <stdint.h>
#define PINMUX_BASE 0x70003000
#define MAKE_PINMUX_REG(n) MAKE_REG32(PINMUX_BASE + n)
#define MEMORY_MAP_PA_PINMUX 0x70003000ul
#define PINMUX_TRISTATE (1 << 4)
#define PINMUX_PARKED (1 << 5)
@@ -30,7 +29,7 @@
#define PINMUX_SELECT_FUNCTION0 0
#define PINMUX_SELECT_FUNCTION1 1
#define PINMUX_SELECT_FUNCTION2 2
#define PINMUX_SELECT_FUNCTION3 3
#define PINMUX_SELECT_FUNCTION3 3
#define PINMUX_DRIVE_1X (0 << 13)
#define PINMUX_DRIVE_2X (1 << 13)
#define PINMUX_DRIVE_3X (2 << 13)
@@ -204,7 +203,14 @@ typedef struct {
uint32_t pz5;
} tegra_pinmux_t;
extern uintptr_t g_pinmuxRegs;
static inline void pinmux_set_regs(uintptr_t regs)
{
g_pinmuxRegs = regs;
}
static inline volatile tegra_pinmux_t *pinmux_get_regs(void)
{
return (volatile tegra_pinmux_t *)PINMUX_BASE;
return (volatile tegra_pinmux_t *)g_pinmuxRegs;
}

View File

@@ -14,21 +14,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "memory_map.h"
#include "stage2_config.h"
#include "interrupt_config.h"
#include "../../utils.h"
#include "../../mmu.h"
#include "../../core_ctx.h"
// Tegra PA size is 36-bit... should we limit ourselves to 34?
// i.e. 14GB of dram max
#define ADDRSPACESZ 36
#define ADDRSPACESZ2 ADDRSPACESZ
static ALIGN(0x1000) u64 g_ttbl[BIT(ADDRSPACESZ - 30)] = {0};
static ALIGN(0x1000) u64 g_vttbl[BIT(ADDRSPACESZ2 - 30)] = {0};
static TEMPORARY ALIGN(0x1000) u64 g_vttbl[BIT(ADDRSPACESZ2 - 30)] = {0};
static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l2_mmio_0[512] = {0};
static TEMPORARY ALIGN(0x1000) u64 g_vttbl_l3_0[512] = {0};
static TEMPORARY uintptr_t g_vttblPaddr;
static inline void identityMapL1(u64 *tbl, uintptr_t addr, size_t size, u64 attribs)
{
@@ -45,37 +43,30 @@ static inline void identityMapL3(u64 *tbl, uintptr_t addr, size_t size, u64 attr
mmu_map_block_range(3, tbl, addr, addr, size, attribs | MMU_PTE_BLOCK_INNER_SHAREBLE);
}
uintptr_t configureMemoryMap(u32 *addrSpaceSize)
{
*addrSpaceSize = ADDRSPACESZ;
if (currentCoreCtx->isBootCore && !currentCoreCtx->warmboot) {
identityMapL1(g_ttbl, 0x00000000ull, 2 * BITL(30), ATTRIB_MEMTYPE_DEVICE);
identityMapL1(g_ttbl, 0x80000000ull, (BITL(ADDRSPACESZ - 30) - 2ull) << 30, ATTRIB_MEMTYPE_NORMAL);
}
return (uintptr_t)g_ttbl;
}
uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize)
uintptr_t stage2Configure(u32 *addrSpaceSize)
{
*addrSpaceSize = ADDRSPACESZ2;
static const u64 devattrs = MMU_S2AP_RW | MMU_MEMATTR_DEVICE_NGNRE;
static const u64 devattrs = MMU_PTE_BLOCK_XN | MMU_S2AP_RW | MMU_MEMATTR_DEVICE_NGNRE;
static const u64 unchanged = MMU_S2AP_RW | MMU_MEMATTR_NORMAL_CACHEABLE_OR_UNCHANGED;
if (currentCoreCtx->isBootCore) {
g_vttblPaddr = va2pa(g_vttbl);
uintptr_t *l2pa = (uintptr_t *)va2pa(g_vttbl_l2_mmio_0);
uintptr_t *l3pa = (uintptr_t *)va2pa(g_vttbl_l3_0);
identityMapL1(g_vttbl, 0x00000000ull, BITL(30), unchanged);
identityMapL1(g_vttbl, 0x80000000ull, (BITL(ADDRSPACESZ2 - 30) - 2ull) << 30, unchanged);
mmu_map_table(1, g_vttbl, 0x40000000ull, g_vttbl_l2_mmio_0, 0);
mmu_map_table(1, g_vttbl, 0x40000000ull, l2pa, 0);
identityMapL2(g_vttbl_l2_mmio_0, 0x40000000ull, BITL(30), unchanged);
mmu_map_table(2, g_vttbl_l2_mmio_0, 0x50000000ull, g_vttbl_l3_0, 0);
mmu_map_table(2, g_vttbl_l2_mmio_0, 0x50000000ull, l3pa, 0);
identityMapL3(g_vttbl_l3_0, 0x00000000ull, BITL(21), unchanged);
// GICD -> trapped, GICv2 CPU -> vCPU interface, GICH -> trapped (access denied including for the unused view)
mmu_unmap_page(g_vttbl_l3_0, 0x50401000ull);
mmu_unmap_page(g_vttbl_l3_0, 0x50404000ull);
mmu_unmap_page(g_vttbl_l3_0, 0x50405000ull);
mmu_map_page_range(g_vttbl_l3_0, 0x50042000ull, 0x50046000ull, 0x2000ull, devattrs);
mmu_unmap_page(g_vttbl_l3_0, MEMORY_MAP_PA_GICD);
mmu_unmap_page(g_vttbl_l3_0, MEMORY_MAP_PA_GICH);
mmu_unmap_page(g_vttbl_l3_0, MEMORY_MAP_PA_GICH + 0x1000ull);
mmu_map_page_range(g_vttbl_l3_0, MEMORY_MAP_PA_GICC, MEMORY_MAP_PA_GICD, 0x2000ull, devattrs);
}
return (uintptr_t)g_vttbl;

View File

@@ -18,6 +18,5 @@
#include "../../types.h"
uintptr_t configureMemoryMap(u32 *addrSpaceSize);
uintptr_t configureStage2MemoryMap(u32 *addrSpaceSize);
uintptr_t stage2Configure(u32 *addrSpaceSize);

View File

@@ -1,95 +0,0 @@
/*
* Copyright (c) 2018-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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../../utils.h"
#define TIMERS_BASE 0x60005000
#define MAKE_TIMERS_REG(n) MAKE_REG32(TIMERS_BASE + n)
#define TIMERUS_CNTR_1US_0 MAKE_TIMERS_REG(0x10)
#define TIMERUS_USEC_CFG_0 MAKE_TIMERS_REG(0x14)
#define SHARED_INTR_STATUS_0 MAKE_TIMERS_REG(0x1A0)
#define SHARED_TIMER_SECURE_CFG_0 MAKE_TIMERS_REG(0x1A4)
#define RTC_BASE 0x7000E000
#define MAKE_RTC_REG(n) MAKE_REG32(RTC_BASE + n)
#define RTC_SECONDS MAKE_RTC_REG(0x08)
#define RTC_SHADOW_SECONDS MAKE_RTC_REG(0x0C)
#define RTC_MILLI_SECONDS MAKE_RTC_REG(0x10)
typedef struct {
uint32_t CONFIG;
uint32_t STATUS;
uint32_t COMMAND;
uint32_t PATTERN;
} watchdog_timers_t;
#define GET_WDT(n) ((volatile watchdog_timers_t *)(TIMERS_BASE + 0x100 + 0x20 * n))
#define WDT_REBOOT_PATTERN 0xC45A
#define GET_WDT_REBOOT_CFG_REG(n) MAKE_REG32(TIMERS_BASE + 0x60 + 0x8 * n)
void wait(uint32_t microseconds);
static inline uint32_t get_time_s(void) {
return RTC_SECONDS;
}
static inline uint32_t get_time_ms(void) {
return (RTC_MILLI_SECONDS | (RTC_SHADOW_SECONDS << 10));
}
static inline uint32_t get_time_us(void) {
return TIMERUS_CNTR_1US_0;
}
/**
* Returns the time in microseconds.
*/
static inline uint32_t get_time(void) {
return get_time_us();
}
/**
* Returns the number of microseconds that have passed since a given get_time().
*/
static inline uint32_t get_time_since(uint32_t base) {
return get_time_us() - base;
}
/**
* Delays for a given number of microseconds.
*/
static inline void udelay(uint32_t usecs) {
uint32_t start = get_time_us();
while (get_time_us() - start < usecs);
}
/**
* Delays until a number of usecs have passed since an absolute start time.
*/
static inline void udelay_absolute(uint32_t start, uint32_t usecs) {
while (get_time_us() - start < usecs);
}
/**
* Delays for a given number of milliseconds.
*/
static inline void mdelay(uint32_t msecs) {
uint32_t start = get_time_ms();
while (get_time_ms() - start < msecs);
}

View File

@@ -16,28 +16,28 @@
*/
#include "uart.h"
#include "timers.h"
#include "pinmux.h"
#include "gpio.h"
#include "car.h"
#include "../../irq.h"
#include "../../timer.h"
#define UART_BASE 0x70006000
static uintptr_t g_uartRegBase;
static inline volatile tegra_uart_t *uartGetRegisters(UartDevice dev)
{
static const size_t offsets[] = { 0, 0x40, 0x200, 0x300, 0x400 };
return (volatile tegra_uart_t *)(UART_BASE + offsets[dev]);
return (volatile tegra_uart_t *)(g_uartRegBase + offsets[dev]);
}
static inline void uartWaitCycles(u32 baud, u32 num)
{
udelay((num * 1000000 + 16 * baud - 1) / (16 * baud));
timerWaitUsecs((num * 1000000 + 16 * baud - 1) / (16 * baud));
}
static inline void uartWaitSyms(u32 baud, u32 num)
{
udelay((num * 1000000 + baud - 1) / baud);
timerWaitUsecs((num * 1000000 + baud - 1) / baud);
}
static void uartSetPinmuxConfig(UartDevice dev) {
@@ -96,7 +96,7 @@ static void uartReset(UartDevice dev)
// This function blocks until the UART device is in the desired state.
void uartWaitIdle(UartDevice dev, UartVendorStatus status)
static void uartWaitIdle(UartDevice dev, UartVendorStatus status)
{
volatile tegra_uart_t *uart = uartGetRegisters(dev);
@@ -109,6 +109,11 @@ void uartWaitIdle(UartDevice dev, UartVendorStatus status)
}
}
void uartSetRegisterBase(uintptr_t regBase)
{
g_uartRegBase = regBase;
}
void uartInit(UartDevice dev, u32 baud, u32 flags)
{
volatile tegra_uart_t *uart = uartGetRegisters(dev);

View File

@@ -20,6 +20,8 @@
#include "../../utils.h"
#include "interrupt_config.h"
#define MEMORY_MAP_PA_UART 0x70006000ul
/* UART devices */
typedef enum UartDevice {
UART_A = 0,
@@ -191,6 +193,7 @@ typedef struct {
u32 asr;
} tegra_uart_t;
void uartSetRegisterBase(uintptr_t regBase);
void uartInit(UartDevice dev, u32 baud, u32 flags);
void uartWriteData(UartDevice dev, const void *buffer, size_t size);
void uartReadData(UartDevice dev, void *buffer, size_t size);