Skip to content
Snippets Groups Projects
Commit 017ef3f9 authored by q3k's avatar q3k Committed by Serge Bazanski
Browse files

l0dables: WIP

parent d4a24d51
No related branches found
No related tags found
No related merge requests found
#pragma once
/*
* 32-bit ELF structures.
*
* ref: Tool Interface Standard (TIS) Executable and Linking Format (ELF) Specification
* Version 1.2, May 1995
* http://refspecs.linuxbase.org/elf/elf.pdf
*
* ref: ELF for the ARM Architecture
* ARM IHI 0044F, current through ABI release 2.10, 24th November 2015
* http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf
*
*/
#include <stdint.h>
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
#define ET_DYN 3 // Shared object file or PIE binary
#define EM_ARM 40
#define EV_CURRENT 1
#define ELFMAG0 0x7f
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
#define ELFCLASS32 1
#define ELFDATA2LSB 1
typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
#define SHT_RELA 4
#define SHT_REL 9
typedef struct {
Elf32_Addr r_offset;
Elf32_Word r_info;
} Elf32_Rel;
#define ELF32_R_SYM(i) ((i)>>8)
#define ELF32_R_TYPE(i) ((unsigned char)(i))
#define R_ARM_RELATIVE 23
typedef struct {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
#define PT_LOAD 1
#define PT_INTERP 3
#include "l0der/l0der.h"
#include <stdio.h>
#include <string.h>
#include <ff.h>
#include "epicardium.h"
#include "l0der/elf.h"
#include "modules/log.h"
/*
* Read an ELF header, check E_IDENT.
*/
static int _read_elf_header(FIL *fp, Elf32_Ehdr *hdr)
{
f_lseek(fp, 0);
unsigned int read;
FRESULT fres = f_read(fp, hdr, sizeof(Elf32_Ehdr), &read);
if (fres != FR_OK) {
LOG_ERR("l0der", "_read_elf_header: f_read failed: %d", fres);
return -1;
}
if (read != sizeof(Elf32_Ehdr)) {
LOG_ERR("l0der", "_read_elf_header: file truncated");
return -1;
}
if (hdr->e_ident[0] != ELFMAG0 ||
hdr->e_ident[1] != ELFMAG1 ||
hdr->e_ident[2] != ELFMAG2 ||
hdr->e_ident[3] != ELFMAG3) {
LOG_ERR("l0der", "_read_elf_header: not an ELF file");
return -1;
}
if (hdr->e_ident[4] != ELFCLASS32) {
LOG_ERR("l0der", "_read_elf_header: not a 32-bit ELF");
return -1;
}
if (hdr->e_ident[5] != ELFDATA2LSB) {
LOG_ERR("l0der", "_read_elf_header: not a little-endian ELF");
return -1;
}
if (hdr->e_ident[6] != EV_CURRENT) {
LOG_ERR("l0der", "_read_elf_header: not a v1 ELF");
return -1;
}
if (hdr->e_ehsize < sizeof(Elf32_Ehdr)) {
LOG_ERR("l0der", "_raed_elf_header: header too small");
return -1;
}
return 0;
}
/*
* Read an ELF program header header.
*/
static int _read_program_header(FIL *fp, uint32_t phdr_addr, Elf32_Phdr *phdr)
{
FRESULT fres;
if ((fres = f_lseek(fp, phdr_addr)) != FR_OK) {
LOG_ERR("l0der", "_read_program_header: could not seek to 0x%lx: %d", phdr_addr, fres);
return -EIO;
}
unsigned int read;
if ((fres = f_read(fp, phdr, sizeof(Elf32_Phdr), &read)) != FR_OK || read < sizeof(Elf32_Phdr)) {
LOG_ERR("l0der", "_read_program_header: could not read phdr: %d", fres);
return -EIO;
}
return 0;
}
/*
* Read an ELF program header header.
*/
static int _read_section_header(FIL *fp, uint32_t shdr_addr, Elf32_Shdr *shdr)
{
FRESULT fres;
if ((fres = f_lseek(fp, shdr_addr)) != FR_OK) {
LOG_ERR("l0der", "_read_section_header: could not seek to 0x%lx: %d", shdr_addr, fres);
return -EIO;
}
unsigned int read;
if ((fres = f_read(fp, shdr, sizeof(Elf32_Shdr), &read)) != FR_OK || read < sizeof(Elf32_Shdr)) {
LOG_ERR("l0der", "_read_section_header: could not read shdr (0x%x bytes) at %08lx: %d, got 0x%x bytes",
sizeof(Elf32_Shdr), shdr_addr, fres, read);
return -EIO;
}
return 0;
}
/*
* Check an ELF program header.
*
* This function ensures basic memory sanity of a program header / segment.
* It ensures that it points to a file region that is contained within the file fully.
*/
static int _check_program_header(FIL *fp, Elf32_Phdr *phdr) {
size_t size = f_size(fp);
// Check file size/offset.
uint32_t file_start = phdr->p_offset;
uint32_t file_limit = phdr->p_offset + phdr->p_filesz;
if (file_limit < file_start) {
LOG_ERR("l0der", "_check_program_header: file size overflow");
return -ENOEXEC;
}
if (file_limit > size) {
LOG_ERR("l0der", "_check_program_header: extends past end of file");
return -ENOEXEC;
}
if (phdr->p_type == PT_LOAD) {
// Check mem/file size.
if (phdr->p_filesz > phdr->p_memsz) {
LOG_ERR("l0der", "_check_program_header: file size larger than memory size");
return -ENOEXEC;
}
uint32_t mem_start = phdr->p_vaddr;
uint32_t mem_limit = phdr->p_vaddr + phdr->p_memsz;
if (mem_limit < mem_start) {
LOG_ERR("l0der", "_check_program_header: mem size overflow");
return -ENOEXEC;
}
}
return 0;
}
/*
* Check an ELF section header.
*
* This function ensures basic memory sanity of a section header.
* It ensures that it points to a file region that is contained within the file fully.
*/
static int _check_section_header(FIL *fp, Elf32_Shdr *shdr) {
size_t size = f_size(fp);
// Check file size/offset.
uint32_t file_start = shdr->sh_offset;
uint32_t file_limit = shdr->sh_offset + shdr->sh_size;
if (file_limit < file_start) {
LOG_ERR("l0der", "_check_section_header: file size overflow");
return -ENOEXEC;
}
if (file_limit > size) {
LOG_ERR("l0der", "_check_section_header: extends past end of file");
return -ENOEXEC;
}
return 0;
}
static const char *_interpreter = "card10-l0dable";
static int _check_interp(FIL *fp, Elf32_Phdr *phdr)
{
uint32_t buffer_size = 64;
char interp[buffer_size];
memset(interp, 0, buffer_size);
if (phdr->p_filesz > buffer_size) {
LOG_ERR("l0der", "_check_interp: interpreter size too large");
return -1;
}
FRESULT fres;
if ((fres = f_lseek(fp, phdr->p_offset)) != FR_OK) {
LOG_ERR("l0der", "_check_interp: could not seek to 0x%lx: %d", phdr->p_offset, fres);
return -1;
}
unsigned int read; // unused (we don't care if the read gets truncated)
if ((fres = f_read(fp, interp, buffer_size, &read)) != FR_OK) {
LOG_ERR("l0der", "_check_interp: could not read segment %d", fres);
return -1;
}
if (strncmp(interp, _interpreter, strlen(_interpreter)) != 0) {
LOG_ERR("l0der", "_check_interp: invalid interpreter, want card10-l0dable");
return -1;
}
return 0;
}
static int _get_load_addr(uint32_t image_start, uint32_t image_limit, void **load)
{
uint32_t image_size = image_limit - image_start;
// ref: Documentation/memorymap.rst
uint32_t core1_mem_start = 0x20040000;
uint32_t core1_mem_limit = 0x20080000;
uint32_t core1_mem_size = core1_mem_limit - core1_mem_start;
if (image_size > core1_mem_size) {
LOG_ERR("l0der", "_get_load_addr: image too large (need 0x%08lx bytes, have %08lx",
image_size, core1_mem_size);
return -ENOMEM;
}
*load = (void *)core1_mem_start;
return 0;
}
static int _load_segment(FIL *fp, void *image_load_addr, Elf32_Phdr *phdr)
{
uint32_t segment_start = (uint32_t)image_load_addr + phdr->p_vaddr;
uint32_t segment_limit = segment_start + phdr->p_memsz;
LOG_INFO("l0der", "Segment %08lx-%08lx: 0x%lx bytes from file",
segment_start, segment_limit, phdr->p_filesz);
memset((void *)segment_start, 0, phdr->p_memsz);
FRESULT fres;
unsigned int read;
if ((fres = f_lseek(fp, phdr->p_offset)) != FR_OK) {
LOG_ERR("l0der", "_load_segment: seek failed: %d", fres);
return -EIO;
}
if ((fres = f_read(fp, (void *)segment_start, phdr->p_filesz, &read)) != FR_OK || read != phdr->p_filesz) {
LOG_ERR("l0der", "_load_segment: read failed");
return -EIO;
}
return 0;
}
static int _run_relocations(FIL *fp, void *load_addr, Elf32_Ehdr *hdr) {
int res;
FRESULT fres;
Elf32_Shdr shdr;
Elf32_Rel rel;
// Go through all relocation sections.
for (int i = 0; i < hdr->e_shnum; i++) {
uint32_t shdr_addr = hdr->e_shoff + (i * hdr->e_shentsize);
if ((res = _read_section_header(fp, shdr_addr, &shdr)) != 0) {
return res;
}
// We don't support RELA (relocation with addend) sections (yet?).
if (shdr.sh_type == SHT_RELA) {
LOG_ERR("l0der", "_run_relocations: found unsupported SHT_RELA section, bailing");
return -ENOEXEC;
}
if (shdr.sh_type != SHT_REL) {
continue;
}
if ((res = _check_section_header(fp, &shdr)) != 0) {
return res;
}
if ((shdr.sh_size % sizeof(Elf32_Rel)) != 0) {
LOG_ERR("l0der", "_run_relocations: SHT_REL section with invalid size: %ld", shdr.sh_size);
return -EIO;
}
uint32_t reloc_count = shdr.sh_size / sizeof(Elf32_Rel);
// Read relocations one by one.
if ((fres = f_lseek(fp, shdr.sh_offset)) != FR_OK) {
LOG_ERR("l0der", "_run_relocations: seek to first relocation (at 0x%lx) failed", shdr.sh_offset);
return -EIO;
}
for (int j = 0; j < reloc_count; j++) {
unsigned int read;
if ((fres = f_read(fp, &rel, sizeof(Elf32_Rel), &read)) != FR_OK || read != sizeof(Elf32_Rel)) {
LOG_ERR("l0der", "_run_relocations: relocation read failed: %d", fres);
return -EIO;
}
uint8_t type = ELF32_R_TYPE(rel.r_info);
switch (type) {
case R_ARM_RELATIVE:
if ((rel.r_offset % 4) != 0) {
LOG_ERR("l0der", "_run_relocations: R_ARM_RELATIVE address must be 4-byte aligned");
return -ENOEXEC;
}
// TODO(q3k): check whether offset is contained in binary.
volatile uint32_t *addr = (uint32_t *)(rel.r_offset + load_addr);
*addr += (uint32_t)load_addr;
break;
default:
LOG_ERR("l0der", "_run_relocations: unsupported relocation type %d", type);
return -ENOEXEC;
}
}
}
return 0;
}
static int _load_pie(FIL *fp, Elf32_Ehdr *hdr, struct l0dable_info *info)
{
int res;
// First pass over program headers: sanity check sizes and calculate
// memory image bounds. l0der currently only supports loading the image into
// the core1 address space, that is from 0x1008_0000 to 0x1010_0000. Thus,
// we need to ensure that all the LOADable segments can fit within this
// range.
uint32_t image_start = 0xFFFFFFFF;
uint32_t image_limit = 0x0;
Elf32_Phdr phdr;
int status_interp = -1;
for (int i = 0; i < hdr->e_phnum; i++) {
uint32_t phdr_addr = hdr->e_phoff + (i * hdr->e_phentsize);
if ((res = _read_program_header(fp, phdr_addr, &phdr)) != 0) {
return res;
}
if ((res = _check_program_header(fp, &phdr)) != 0) {
return res;
}
if (phdr.p_type == PT_INTERP) {
status_interp = _check_interp(fp, &phdr);
continue;
}
if (phdr.p_type == PT_LOAD) {
// Check alignment request.
if (phdr.p_align > 4) {
LOG_ERR("l0der", "_load_pie: phdr %d alignment too strict", i);
return -ENOEXEC;
}
uint32_t mem_start = phdr.p_vaddr;
uint32_t mem_limit = phdr.p_vaddr + phdr.p_memsz;
// Record memory usage.
if (mem_start < image_start) {
image_start = mem_start;
}
if (mem_limit > image_limit) {
image_limit = mem_limit;
}
}
}
if (status_interp != 0) {
LOG_ERR("l0der", "_load_pie: not a card10 l0dable");
return -ENOEXEC;
}
if (image_limit < image_start) {
LOG_ERR("l0der", "_load_pie: no loadable segments");
return -ENOEXEC;
}
LOG_INFO("l0der", "Image bounds %08lx - %08lx", image_start, image_limit);
void *load_addr;
if ((res = _get_load_addr(image_start, image_limit, &load_addr)) != 0) {
return res;
}
LOG_INFO("l0der", "Loading at %08lx", (uint32_t)load_addr);
// Second pass through program headers: load all LOAD segments.
for (int i = 0; i < hdr->e_phnum; i++) {
uint32_t phdr_addr = hdr->e_phoff + (i * hdr->e_phentsize);
if ((res = _read_program_header(fp, phdr_addr, &phdr)) != 0) {
return res;
}
if (phdr.p_type != PT_LOAD) {
continue;
}
if ((res = _load_segment(fp, load_addr, &phdr)) != 0) {
return res;
}
}
// Run relocations.
if ((res = _run_relocations(fp, load_addr, hdr)) != 0) {
return res;
}
uint32_t image_entrypoint = (uint32_t)load_addr + hdr->e_entry;
LOG_INFO("l0der", "Entrypoint (ISR Vector) at %08lx", image_entrypoint);
info->isr_vector = (void *)image_entrypoint;
return 0;
}
int l0der_load_path(const char *path, struct l0dable_info *info)
{
FIL fh;
FRESULT fres = f_open(&fh, path, FA_OPEN_EXISTING|FA_READ);
if (fres != FR_OK) {
LOG_ERR("l0der", "l0der_load_path: could not open ELF file %s: %d", path, fres);
return -ENOENT;
}
int size = f_size(&fh);
int res = 0;
// Load ELF header and ensure it's somewhat sane.
Elf32_Ehdr hdr;
if (_read_elf_header(&fh, &hdr) != 0) {
res = -EINVAL;
goto done;
}
// Sanitize segments.
uint32_t ph_start = hdr.e_phoff;
uint32_t ph_limit = hdr.e_phoff + (hdr.e_phnum * hdr.e_phentsize);
if (ph_limit < ph_start) {
LOG_ERR("l0der", "l0der_load_path: invalid program header count/size: overflow");
return -ENOEXEC;
}
if (ph_limit - ph_start == 0) {
LOG_ERR("l0der", "l0der_load_path: no segments");
return -ENOEXEC;
}
if (ph_limit > size) {
LOG_ERR("l0der", "l0der_load_path: program header table extends past end of file");
return -ENOEXEC;
}
if (hdr.e_phentsize < sizeof(Elf32_Phdr)) {
LOG_ERR("l0der", "l0der_load_path: invalid program header table entry size");
return -ENOEXEC;
}
// Sanitize sections.
uint32_t sh_start = hdr.e_shoff;
uint32_t sh_limit = hdr.e_shoff + (hdr.e_shnum + hdr.e_shentsize);
if (sh_limit < sh_start) {
LOG_ERR("l0der", "l0der_load_path: invalid section header count/size: overflow");
return -ENOEXEC;
}
if (sh_limit > size) {
LOG_ERR("l0der", "l0der_load_path: section header table extends past end of file");
return -ENOEXEC;
}
if (hdr.e_shentsize < sizeof(Elf32_Shdr)) {
LOG_ERR("l0der", "l0der_load_path: invalid section header table entry size");
return -ENOEXEC;
}
// Check whether it's something that we can load.
if (hdr.e_type == ET_DYN && hdr.e_machine == EM_ARM && hdr.e_version == EV_CURRENT) {
LOG_INFO("l0der", "Loading PIE l0dable %s ...", path);
res = _load_pie(&fh, &hdr, info);
goto done;
} else {
LOG_ERR("l0der", "l0der_load_path: %s: not an ARM PIE, cannot load.", path);
res = -ENOEXEC;
goto done;
}
done:
f_close(&fh);
return res;
}
#pragma once
/*
* l0der, the l0dable loader.
*
* l0der is the ELF loader responsible for retrieving a l0dable from FAT and
* into memory for core1 to execute.
*
* l0dables are PIE ELF binaries. They can be loaded anywhere into memory,
* although for now we load them at a static address (but that might change
* with address space evolution and/or multi-app / resident app support.
*
*/
struct l0dable_info {
/** The address of the entry ISR vector. */
void *isr_vector;
};
/**
* Load a l0dable into memory.
*
* :param const char *path: Path of l0dable on FAT filesystem.
* :param l0dable_info l0dable: Information about loaded l0dable.
* :returns: ``0`` on success or a negative value on error.
*/
int l0der_load_path(const char *path, struct l0dable_info *l0dable);
l0der_sources = files(
'l0der.c',
)
......@@ -9,6 +9,7 @@
#include "pmic.h"
#include "leds.h"
#include "api/dispatcher.h"
#include "l0der/l0der.h"
#include "modules/modules.h"
#include "modules/log.h"
#include "modules/stream.h"
......@@ -99,8 +100,16 @@ int main(void)
LOG_INFO("startup", "Initializing dispatcher ...");
api_dispatcher_init();
LOG_INFO("startup", "Starting core1 payload ...");
core1_start();
LOG_INFO("startup", "Testing l0der ...");
struct l0dable_info info;
int res = l0der_load_path("blinky.elf", &info);
if (res != 0) {
LOG_ERR("startup", "l0der failed: %d\n", res);
} else {
LOG_INFO("startup", "Starting core1 payload ...");
core1_start(info.isr_vector);
}
LOG_INFO("startup", "Starting FreeRTOS ...");
vTaskStartScheduler();
......
......@@ -66,12 +66,15 @@ freertos = static_library(
subdir('modules/')
subdir('l0der/')
elf = executable(
name + '.elf',
'cdcacm.c',
'main.c',
'support.c',
module_sources,
l0der_sources,
dependencies: [libcard10, max32665_startup_core0, maxusb, libff13],
link_with: [api_dispatcher_lib, freertos],
link_whole: [max32665_startup_core0_lib, board_card10_lib, newlib_heap_lib],
......
......@@ -31,7 +31,7 @@ int main(void)
int h = 0;
// Release core1
core1_start();
core1_start((void *)0x10080000);
while (1) {
#define NUM 15
......
#include "max32665.h"
#include "mxc_sys.h"
#include "gcr_regs.h"
#include "icc_regs.h"
#include "pwrseq_regs.h"
#include "epicardium.h"
uint32_t SystemCoreClock = HIRC_FREQ >> 1;
volatile uint32_t tombstone = 0;
void SystemCoreClockUpdate(void)
{
uint32_t base_freq, div, clk_src;
// Determine the clock source and frequency
clk_src = (MXC_GCR->clkcn & MXC_F_GCR_CLKCN_CLKSEL);
switch (clk_src)
{
case MXC_S_GCR_CLKCN_CLKSEL_HIRC:
base_freq = HIRC_FREQ;
break;
case MXC_S_GCR_CLKCN_CLKSEL_XTAL32M:
base_freq = XTAL32M_FREQ;
break;
case MXC_S_GCR_CLKCN_CLKSEL_LIRC8:
base_freq = LIRC8_FREQ;
break;
case MXC_S_GCR_CLKCN_CLKSEL_HIRC96:
base_freq = HIRC96_FREQ;
break;
case MXC_S_GCR_CLKCN_CLKSEL_HIRC8:
base_freq = HIRC8_FREQ;
break;
case MXC_S_GCR_CLKCN_CLKSEL_XTAL32K:
base_freq = XTAL32K_FREQ;
break;
default:
// Values 001 and 111 are reserved, and should never be encountered.
base_freq = HIRC_FREQ;
break;
}
// Clock divider is retrieved to compute system clock
div = (MXC_GCR->clkcn & MXC_F_GCR_CLKCN_PSC) >> MXC_F_GCR_CLKCN_PSC_POS;
SystemCoreClock = base_freq >> div;
}
int main(void) {
tombstone = 0x10;
// Enable FPU.
SCB->CPACR |= SCB_CPACR_CP10_Msk | SCB_CPACR_CP11_Msk;
__DSB();
__ISB();
tombstone = 0x11;
// Enable ICache1 Clock
MXC_GCR->perckcn1 &= ~(1 << 22);
tombstone = 0x12;
// Invalidate cache and wait until ready
MXC_ICC1->invalidate = 1;
while (!(MXC_ICC1->cache_ctrl & MXC_F_ICC_CACHE_CTRL_CACHE_RDY));
tombstone = 0x13;
// Enable Cache
MXC_ICC1->cache_ctrl |= MXC_F_ICC_CACHE_CTRL_CACHE_EN;
tombstone = 0x14;
SystemCoreClockUpdate();
tombstone = 0x15;
/* TMR5 is used to notify on keyboard interrupt */
//NVIC_EnableIRQ(TMR5_IRQn);
tombstone = 0x16;
epic_leds_set(0, 255, 255, 255);
tombstone = 0x17;
for (;;) {}
}
name = 'blinky'
elf = executable(
name + '.elf',
'main.c',
build_by_default: true,
dependencies: [l0dable_startup, api_caller],
link_whole: [l0dable_startup_lib],
link_args: [
'-Wl,-Map=' + meson.current_build_dir() + '/' + name + '.map',
],
pie: true,
)
/*MEMORY {
SPIX (rx) : ORIGIN = 0x08000000, LENGTH = 128M
FLASH (rx) : ORIGIN = 0x10080000, LENGTH = 512k
SRAM (rwx) : ORIGIN = 0x20040000, LENGTH = 256k
SPID (r) : ORIGIN = 0x80000000, LENGTH = 512M
}*/
ENTRY(isr_vector);
CARD10_CORE1_START = 0x20040000;
CARD10_CORE1_LIMIT = 0x20080000;
PHDRS
{
header PT_PHDR PHDRS ;
interp PT_INTERP ;
text PT_LOAD FILEHDR PHDRS ;
data PT_LOAD ;
dynamic PT_DYNAMIC ;
}
SECTIONS {
/* . = CARD10_CORE1_START; */
. = SIZEOF_HEADERS;
.cinterp :
{
*(.cinterp);
} :interp :text
.text :
{
*(.text*)
*(.rodata*)
KEEP(*(.init))
KEEP(*(.fini))
} :text
.data :
{
. = ALIGN(4);
*(.data*)
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
} :data
.dynamic :
{
*(.dynamic)
} :data :dynamic
.bss :
{
. = ALIGN(4);
CARD10_BSS_OFF_START = .;
*(.bss*)
*(COMMON)
CARD10_BSS_LIMIT = .;
} :data
. = ALIGN(4096);
.stack :
{
CARD10_STACK_START = .;
. += 4096;
CARD10_STACK_LIMIT = .;
} :data
/DISCARD/ :
{
/* *(*) */
/* *(.symtab) */
/* *(.strtab) */
/* *(.shstrtab) */
/**(.interp)*/
*(.comment)
*(.interp)
}
}
.syntax unified
.arch armv7-m
.section .data
.align 2
.globl isr_vector
isr_vector:
.long CARD10_STACK_LIMIT /* Top of Stack */
.long Reset_Handler /* Reset Handler */
.long NMI_Handler /* NMI Handler */
.long HardFault_Handler /* Hard Fault Handler */
.long MemManage_Handler /* MPU Fault Handler */
.long BusFault_Handler /* Bus Fault Handler */
.long UsageFault_Handler /* Usage Fault Handler */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long SVC_Handler /* SVCall Handler */
.long 0 /* Reserved */ /* @TODO: Is this the Debug Montior Interrupt? */
.long 0 /* Reserved */
.long PendSV_Handler /* PendSV Handler */
.long SysTick_Handler /* SysTick Handler */
/* Device-specific Interrupts */
.long PF_IRQHandler /* 0x10 0x0040 16: Power Fail */
.long WDT0_IRQHandler /* 0x11 0x0044 17: Watchdog 0 */
.long USB_IRQHandler /* 0x12 0x0048 18: USB */
.long RTC_IRQHandler /* 0x13 0x004C 19: RTC */
.long TRNG_IRQHandler /* 0x14 0x0050 20: True Random Number Generator */
.long TMR0_IRQHandler /* 0x15 0x0054 21: Timer 0 */
.long TMR1_IRQHandler /* 0x16 0x0058 22: Timer 1 */
.long TMR2_IRQHandler /* 0x17 0x005C 23: Timer 2 */
.long TMR3_IRQHandler /* 0x18 0x0060 24: Timer 3*/
.long TMR4_IRQHandler /* 0x19 0x0064 25: Timer 4*/
.long TMR5_IRQHandler /* 0x1A 0x0068 26: Timer 5 */
.long RSV11_IRQHandler /* 0x1B 0x006C 27: Reserved */
.long RSV12_IRQHandler /* 0x1C 0x0070 28: Reserved */
.long I2C0_IRQHandler /* 0x1D 0x0074 29: I2C0 */
.long UART0_IRQHandler /* 0x1E 0x0078 30: UART 0 */
.long UART1_IRQHandler /* 0x1F 0x007C 31: UART 1 */
.long SPI1_IRQHandler /* 0x20 0x0080 32: SPI1 */
.long SPI2_IRQHandler /* 0x21 0x0084 33: SPI2 */
.long RSV18_IRQHandler /* 0x22 0x0088 34: Reserved */
.long RSV19_IRQHandler /* 0x23 0x008C 35: Reserved */
.long ADC_IRQHandler /* 0x24 0x0090 36: ADC */
.long RSV21_IRQHandler /* 0x25 0x0094 37: Reserved */
.long RSV22_IRQHandler /* 0x26 0x0098 38: Reserved */
.long FLC0_IRQHandler /* 0x27 0x009C 39: Flash Controller */
.long GPIO0_IRQHandler /* 0x28 0x00A0 40: GPIO0 */
.long GPIO1_IRQHandler /* 0x29 0x00A4 41: GPIO2 */
.long RSV26_IRQHandler /* 0x2A 0x00A8 42: GPIO3 */
.long TPU_IRQHandler /* 0x2B 0x00AC 43: Crypto */
.long DMA0_IRQHandler /* 0x2C 0x00B0 44: DMA0 */
.long DMA1_IRQHandler /* 0x2D 0x00B4 45: DMA1 */
.long DMA2_IRQHandler /* 0x2E 0x00B8 46: DMA2 */
.long DMA3_IRQHandler /* 0x2F 0x00BC 47: DMA3 */
.long RSV32_IRQHandler /* 0x30 0x00C0 48: Reserved */
.long RSV33_IRQHandler /* 0x31 0x00C4 49: Reserved */
.long UART2_IRQHandler /* 0x32 0x00C8 50: UART 2 */
.long RSV35_IRQHandler /* 0x33 0x00CC 51: Reserved */
.long I2C1_IRQHandler /* 0x34 0x00D0 52: I2C1 */
.long RSV37_IRQHandler /* 0x35 0x00D4 53: Reserved */
.long SPIXFC_IRQHandler /* 0x36 0x00D8 54: SPI execute in place */
.long BTLE_TX_DONE_IRQHandler /* 0x37 0x00DC 55: BTLE TX Done */
.long BTLE_RX_RCVD_IRQHandler /* 0x38 0x00E0 56: BTLE RX Recived */
.long BTLE_RX_ENG_DET_IRQHandler /* 0x39 0x00E4 57: BTLE RX Energy Dectected */
.long BTLE_SFD_DET_IRQHandler /* 0x3A 0x00E8 58: BTLE SFD Detected */
.long BTLE_SFD_TO_IRQHandler /* 0x3B 0x00EC 59: BTLE SFD Timeout*/
.long BTLE_GP_EVENT_IRQHandler /* 0x3C 0x00F0 60: BTLE Timestamp*/
.long BTLE_CFO_IRQHandler /* 0x3D 0x00F4 61: BTLE CFO Done */
.long BTLE_SIG_DET_IRQHandler /* 0x3E 0x00F8 62: BTLE Signal Detected */
.long BTLE_AGC_EVENT_IRQHandler /* 0x3F 0x00FC 63: BTLE AGC Event */
.long BTLE_RFFE_SPIM_IRQHandler /* 0x40 0x0100 64: BTLE RFFE SPIM Done */
.long BTLE_TX_AES_IRQHandler /* 0x41 0x0104 65: BTLE TX AES Done */
.long BTLE_RX_AES_IRQHandler /* 0x42 0x0108 66: BTLE RX AES Done */
.long BTLE_INV_APB_ADDR_IRQHandler /* 0x43 0x010C 67: BTLE Invalid APB Address*/
.long BTLE_IQ_DATA_VALID_IRQHandler /* 0x44 0x0110 68: BTLE IQ Data Valid */
.long WUT_IRQHandler /* 0x45 0x0114 69: WUT Wakeup */
.long GPIOWAKE_IRQHandler /* 0x46 0x0118 70: GPIO Wakeup */
.long RSV55_IRQHandler /* 0x47 0x011C 71: Reserved */
.long SPI0_IRQHandler /* 0x48 0x0120 72: SPI AHB */
.long WDT1_IRQHandler /* 0x49 0x0124 73: Watchdog 1 */
.long RSV58_IRQHandler /* 0x4A 0x0128 74: Reserved */
.long PT_IRQHandler /* 0x4B 0x012C 75: Pulse train */
.long SDMA0_IRQHandler /* 0x4C 0x0130 76: Smart DMA 0 */
.long RSV61_IRQHandler /* 0x4D 0x0134 77: Reserved */
.long I2C2_IRQHandler /* 0x4E 0x0138 78: I2C 2 */
.long RSV63_IRQHandler /* 0x4F 0x013C 79: Reserved */
.long RSV64_IRQHandler /* 0x50 0x0140 80: Reserved */
.long RSV65_IRQHandler /* 0x51 0x0144 81: Reserved */
.long SDHC_IRQHandler /* 0x52 0x0148 82: SDIO/SDHC */
.long OWM_IRQHandler /* 0x53 0x014C 83: One Wire Master */
.long DMA4_IRQHandler /* 0x54 0x0150 84: DMA4 */
.long DMA5_IRQHandler /* 0x55 0x0154 85: DMA5 */
.long DMA6_IRQHandler /* 0x56 0x0158 86: DMA6 */
.long DMA7_IRQHandler /* 0x57 0x015C 87: DMA7 */
.long DMA8_IRQHandler /* 0x58 0x0160 88: DMA8 */
.long DMA9_IRQHandler /* 0x59 0x0164 89: DMA9 */
.long DMA10_IRQHandler /* 0x5A 0x0168 90: DMA10 */
.long DMA11_IRQHandler /* 0x5B 0x016C 91: DMA11 */
.long DMA12_IRQHandler /* 0x5C 0x0170 92: DMA12 */
.long DMA13_IRQHandler /* 0x5D 0x0174 93: DMA13 */
.long DMA14_IRQHandler /* 0x5E 0x0178 94: DMA14 */
.long DMA15_IRQHandler /* 0x5F 0x017C 95: DMA15 */
.long USBDMA_IRQHandler /* 0x60 0x0180 96: USB DMA */
.long WDT2_IRQHandler /* 0x61 0x0184 97: Watchdog Timer 2 */
.long ECC_IRQHandler /* 0x62 0x0188 98: Error Correction */
.long DVS_IRQHandler /* 0x63 0x018C 99: DVS Controller */
.long SIMO_IRQHandler /* 0x64 0x0190 100: SIMO Controller */
.long RPU_IRQHandler /* 0x65 0x0194 101: RPU */ /* @TODO: Is this correct? */
.long AUDIO_IRQHandler /* 0x66 0x0198 102: Audio subsystem */
.long FLC1_IRQHandler /* 0x67 0x019C 103: Flash Control 1 */
.long RSV88_IRQHandler /* 0x68 0x01A0 104: UART 3 */
.long RSV89_IRQHandler /* 0x69 0x01A4 105: UART 4 */
.long RSV90_IRQHandler /* 0x6A 0x01A8 106: UART 5 */
.long RSV91_IRQHandler /* 0x6B 0x01AC 107: Camera IF */
.long RSV92_IRQHandler /* 0x6C 0x01B0 108: I3C */
.long HTMR0_IRQHandler /* 0x6D 0x01B4 109: HTmr */
.long HTMR1_IRQHandler /* 0x6E 0x01B8 109: HTmr */
.text
.thumb
.thumb_func
.align 2
Reset_Handler:
// Set stack according to limits from linker script.
ldr r0, =CARD10_STACK_LIMIT
mov sp, r0
// Jump to C code
ldr r0, =main
blx r0
// Spin
// TODO(q3k): let epicardium know we're done
.spin:
bl .spin
// Macro to define default handlers. Default handler
// will be weak symbol and just dead loops. They can be
// overwritten by other handlers.
.macro def_irq_handler handler_name
.align 1
.thumb_func
.weak \handler_name
.type \handler_name, %function
\handler_name :
b .
.size \handler_name, . - \handler_name
.endm
// Default ISRs.
def_irq_handler NMI_Handler
def_irq_handler HardFault_Handler
def_irq_handler MemManage_Handler
def_irq_handler BusFault_Handler
def_irq_handler UsageFault_Handler
def_irq_handler SVC_Handler
def_irq_handler DebugMon_Handler
def_irq_handler PendSV_Handler
def_irq_handler Default_Handler
def_irq_handler PF_IRQHandler
def_irq_handler WDT0_IRQHandler
def_irq_handler USB_IRQHandler
def_irq_handler RTC_IRQHandler
def_irq_handler TRNG_IRQHandler
def_irq_handler TMR0_IRQHandler
def_irq_handler TMR1_IRQHandler
def_irq_handler TMR2_IRQHandler
def_irq_handler TMR3_IRQHandler
def_irq_handler TMR4_IRQHandler
def_irq_handler TMR5_IRQHandler
def_irq_handler RSV11_IRQHandler
def_irq_handler RSV12_IRQHandler
def_irq_handler I2C0_IRQHandler
def_irq_handler UART0_IRQHandler
def_irq_handler UART1_IRQHandler
def_irq_handler SPI1_IRQHandler
def_irq_handler SPI2_IRQHandler
def_irq_handler RSV18_IRQHandler
def_irq_handler RSV19_IRQHandler
def_irq_handler ADC_IRQHandler
def_irq_handler RSV21_IRQHandler
def_irq_handler RSV22_IRQHandler
def_irq_handler FLC0_IRQHandler
def_irq_handler GPIO0_IRQHandler
def_irq_handler GPIO1_IRQHandler
def_irq_handler RSV26_IRQHandler
def_irq_handler TPU_IRQHandler
def_irq_handler DMA0_IRQHandler
def_irq_handler DMA1_IRQHandler
def_irq_handler DMA2_IRQHandler
def_irq_handler DMA3_IRQHandler
def_irq_handler RSV32_IRQHandler
def_irq_handler RSV33_IRQHandler
def_irq_handler UART2_IRQHandler
def_irq_handler RSV35_IRQHandler
def_irq_handler I2C1_IRQHandler
def_irq_handler RSV37_IRQHandler
def_irq_handler SPIXFC_IRQHandler
def_irq_handler BTLE_TX_DONE_IRQHandler
def_irq_handler BTLE_RX_RCVD_IRQHandler
def_irq_handler BTLE_RX_ENG_DET_IRQHandler
def_irq_handler BTLE_SFD_DET_IRQHandler
def_irq_handler BTLE_SFD_TO_IRQHandler
def_irq_handler BTLE_GP_EVENT_IRQHandler
def_irq_handler BTLE_CFO_IRQHandler
def_irq_handler BTLE_SIG_DET_IRQHandler
def_irq_handler BTLE_AGC_EVENT_IRQHandler
def_irq_handler BTLE_RFFE_SPIM_IRQHandler
def_irq_handler BTLE_TX_AES_IRQHandler
def_irq_handler BTLE_RX_AES_IRQHandler
def_irq_handler BTLE_INV_APB_ADDR_IRQHandler
def_irq_handler BTLE_IQ_DATA_VALID_IRQHandler
def_irq_handler WUT_IRQHandler
def_irq_handler GPIOWAKE_IRQHandler
def_irq_handler RSV55_IRQHandler
def_irq_handler SPI0_IRQHandler
def_irq_handler WDT1_IRQHandler
def_irq_handler RSV58_IRQHandler
def_irq_handler PT_IRQHandler
def_irq_handler SDMA0_IRQHandler
def_irq_handler RSV61_IRQHandler
def_irq_handler I2C2_IRQHandler
def_irq_handler RSV63_IRQHandler
def_irq_handler RSV64_IRQHandler
def_irq_handler RSV65_IRQHandler
def_irq_handler SDHC_IRQHandler
def_irq_handler OWM_IRQHandler
def_irq_handler DMA4_IRQHandler
def_irq_handler DMA5_IRQHandler
def_irq_handler DMA6_IRQHandler
def_irq_handler DMA7_IRQHandler
def_irq_handler DMA8_IRQHandler
def_irq_handler DMA9_IRQHandler
def_irq_handler DMA10_IRQHandler
def_irq_handler DMA11_IRQHandler
def_irq_handler DMA12_IRQHandler
def_irq_handler DMA13_IRQHandler
def_irq_handler DMA14_IRQHandler
def_irq_handler DMA15_IRQHandler
def_irq_handler USBDMA_IRQHandler
def_irq_handler WDT2_IRQHandler
def_irq_handler ECC_IRQHandler
def_irq_handler DVS_IRQHandler
def_irq_handler SIMO_IRQHandler
def_irq_handler RPU_IRQHandler
def_irq_handler AUDIO_IRQHandler
def_irq_handler FLC1_IRQHandler
def_irq_handler RSV88_IRQHandler
def_irq_handler RSV89_IRQHandler
def_irq_handler RSV90_IRQHandler
def_irq_handler RSV91_IRQHandler
def_irq_handler RSV92_IRQHandler
def_irq_handler HTMR0_IRQHandler
def_irq_handler HTMR1_IRQHandler
.section .cinterp
.asciz "card10-l0dable"
.byte
l0dable_startup_lib = static_library(
'l0dable-startup',
'crt.s',
pic: true,
)
l0dable_startup = declare_dependency(
link_args: [
'-nostdlib', '-n',
'-T', meson.current_source_dir() + 'core1.ld',
],
compile_args: [
'-fPIE', '-pie',
],
)
subdir('blinky/')
......@@ -199,11 +199,9 @@ void card10_diag(void)
#endif
}
void core1_start(void)
{
//MXC_GCR->gp0 = (uint32_t)(&__isr_vector_core1);
MXC_GCR->gp0 = 0x10080000;
MXC_GCR->perckcn1 &= ~MXC_F_GCR_PERCKCN1_CPU1;
void core1_start(void *isr) {
MXC_GCR->gp0 = (uint32_t)isr;
MXC_GCR->perckcn1 &= ~MXC_F_GCR_PERCKCN1_CPU1;
}
void core1_stop(void)
......
......@@ -9,7 +9,7 @@ extern const gpio_cfg_t bhi_interrupt_pin;
void card10_init(void);
void card10_diag(void);
void core1_start(void);
void core1_start(void *isr);
void core1_stop(void);
void card10_poll(void);
......
......@@ -37,3 +37,5 @@ subdir('epicardium/')
subdir('pycardium/')
subdir('hw-tests/')
subdir('l0dables/')
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment