diff --git a/epicardium/l0der/l0der.c b/epicardium/l0der/l0der.c index b10d4d51b21042a40d6e46cde74f7252709b7364..13f86cde355a13a775657d5fec934242480346d8 100644 --- a/epicardium/l0der/l0der.c +++ b/epicardium/l0der/l0der.c @@ -28,6 +28,22 @@ * a memory map in stone. */ +struct _pie_load_info { + /// Populated by _load_pie + // Addresses within ELF file. + uint32_t image_start; + uint32_t image_limit; + + /// Populated by _get_load_addr + // Load address of ELF file. + uint32_t load_address; + // Addresses within memory of ELF file. + uint32_t image_load_start; + uint32_t image_load_limit; + // Stack top. + uint32_t stack_top; +}; + /* * Read an ELF header, check E_IDENT. */ @@ -223,9 +239,9 @@ static int _check_interp(FIL *fp, Elf32_Phdr *phdr) * * Currently this means trying to fit it into core1 RAM. */ -static int _get_load_addr(uint32_t image_start, uint32_t image_limit, void **load) +static int _get_load_addr(struct _pie_load_info *li) { - uint32_t image_size = image_limit - image_start; + uint32_t image_size = li->image_limit - li->image_start; // ref: Documentation/memorymap.rst uint32_t core1_mem_start = 0x20040000; @@ -238,7 +254,24 @@ static int _get_load_addr(uint32_t image_start, uint32_t image_limit, void **loa return -ENOMEM; } - *load = (void *)core1_mem_start; + // Place image at bottom of core1 memory range. + li->load_address = core1_mem_start; + li->image_load_start = li->load_address + li->image_start; + li->image_load_limit = li->load_address + li->image_limit; + + // Place stack at top of core1 memory range. + li->stack_top = core1_mem_limit; + + // Check that there is enough stack space. + uint32_t stack_space = li->stack_top - li->image_load_limit; + if (stack_space < 8192) { + LOG_WARN("l0der", "_get_load_addr: low stack space (%ld bytes)", stack_space); + } else if (stack_space < 256) { + LOG_ERR("l0der", "_get_load_addr: low stack space (%ld bytes), cannot continue", stack_space); + return -ENOMEM; + } + + LOG_INFO("l0der", "Stack at %08lx, %ld bytes available", li->stack_top, stack_space); return 0; } @@ -248,9 +281,9 @@ static int _get_load_addr(uint32_t image_start, uint32_t image_limit, void **loa * * Segment must be a LOAD segment. */ -static int _load_segment(FIL *fp, void *image_load_addr, Elf32_Phdr *phdr) +static int _load_segment(FIL *fp, struct _pie_load_info *li, Elf32_Phdr *phdr) { - uint32_t segment_start = (uint32_t)image_load_addr + phdr->p_vaddr; + uint32_t segment_start = li->load_address + phdr->p_vaddr; uint32_t segment_limit = segment_start + phdr->p_memsz; LOG_INFO("l0der", "Segment %08lx-%08lx: 0x%lx bytes from file", @@ -267,15 +300,12 @@ static int _load_segment(FIL *fp, void *image_load_addr, Elf32_Phdr *phdr) * the only one used when making 'standard' PIE binaries on RAM. However, other * kinds might have to be implemented in the future. */ -static int _run_relocations(FIL *fp, void *load_addr, uint32_t image_start, uint32_t image_limit, Elf32_Ehdr *hdr) { +static int _run_relocations(FIL *fp, struct _pie_load_info *li, Elf32_Ehdr *hdr) { int res; FRESULT fres; Elf32_Shdr shdr; Elf32_Rel rel; - uint32_t load_start = image_start + (uint32_t)load_addr; - uint32_t load_limit = image_limit + (uint32_t)load_addr; - // 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); @@ -323,14 +353,14 @@ static int _run_relocations(FIL *fp, void *load_addr, uint32_t image_start, uint LOG_ERR("l0der", "_run_relocations: R_ARM_RELATIVE address must be 4-byte aligned"); return -ENOEXEC; } - volatile uint32_t *addr = (uint32_t *)(rel.r_offset + load_addr); - if ((uint32_t)addr < load_start || (uint32_t)addr >= load_limit) { + volatile uint32_t *addr = (uint32_t *)(rel.r_offset + li->load_address); + if ((uint32_t)addr < li->image_load_start || (uint32_t)addr >= li->image_load_limit) { LOG_ERR("l0der", "_run_relocations: R_ARM_RELATIVE address (%08lx) is outside image boundaries", (uint32_t)addr); return -ENOEXEC; } - *addr += (uint32_t)load_addr; + *addr += li->load_address; break; default: LOG_ERR("l0der", "_run_relocations: unsupported relocation type %d", type); @@ -348,6 +378,7 @@ static int _run_relocations(FIL *fp, void *load_addr, uint32_t image_start, uint static int _load_pie(FIL *fp, Elf32_Ehdr *hdr, struct l0dable_info *info) { int res; + struct _pie_load_info li; // First pass over program headers: sanity check sizes and calculate // memory image bounds. l0der currently only supports loading the image into @@ -355,8 +386,8 @@ static int _load_pie(FIL *fp, Elf32_Ehdr *hdr, struct l0dable_info *info) // we need to ensure that all the LOADable segments can fit within this // range. - uint32_t image_start = 0xFFFFFFFF; - uint32_t image_limit = 0x0; + li.image_start = 0xffffffff; + li.image_limit = 0x0; Elf32_Phdr phdr; @@ -388,11 +419,11 @@ static int _load_pie(FIL *fp, Elf32_Ehdr *hdr, struct l0dable_info *info) uint32_t mem_limit = phdr.p_vaddr + phdr.p_memsz; // Record memory usage. - if (mem_start < image_start) { - image_start = mem_start; + if (mem_start < li.image_start) { + li.image_start = mem_start; } - if (mem_limit > image_limit) { - image_limit = mem_limit; + if (mem_limit > li.image_limit) { + li.image_limit = mem_limit; } } } @@ -404,20 +435,19 @@ static int _load_pie(FIL *fp, Elf32_Ehdr *hdr, struct l0dable_info *info) } - if (image_limit < image_start) { + if (li.image_limit < li.image_start) { // We didn't find any LOAD segment. LOG_ERR("l0der", "_load_pie: no loadable segments"); return -ENOEXEC; } - LOG_INFO("l0der", "Image bounds %08lx - %08lx", image_start, image_limit); + LOG_INFO("l0der", "Image bounds %08lx - %08lx", li.image_start, li.image_limit); - void *load_addr; - if ((res = _get_load_addr(image_start, image_limit, &load_addr)) != 0) { + if ((res = _get_load_addr(&li)) != 0) { return res; } - LOG_INFO("l0der", "Loading at %08lx", (uint32_t)load_addr); + LOG_INFO("l0der", "Loading at %08lx", li.load_address); // Second pass through program headers: load all LOAD segments. @@ -431,22 +461,25 @@ static int _load_pie(FIL *fp, Elf32_Ehdr *hdr, struct l0dable_info *info) continue; } - if ((res = _load_segment(fp, load_addr, &phdr)) != 0) { + if ((res = _load_segment(fp, &li, &phdr)) != 0) { return res; } } // Run relocations. - if ((res = _run_relocations(fp, load_addr, image_start, image_limit, hdr)) != 0) { + if ((res = _run_relocations(fp, &li, hdr)) != 0) { return res; } - uint32_t image_entrypoint = (uint32_t)load_addr + hdr->e_entry; + uint32_t image_entrypoint = li.load_address + hdr->e_entry; LOG_INFO("l0der", "Entrypoint (ISR Vector) at %08lx", image_entrypoint); - info->isr_vector = (void *)image_entrypoint; + // Setup stack + uint32_t *isr = (uint32_t *)image_entrypoint; + isr[0] = li.stack_top; + info->isr_vector = (void *)image_entrypoint; return 0; } diff --git a/l0dables/lib/crt.s b/l0dables/lib/crt.s index b2d1ba76af534f8621bcf7b452518aa85b4a09ba..be63692fdc8f7b1c268d7e38814957d5086f1eb4 100644 --- a/l0dables/lib/crt.s +++ b/l0dables/lib/crt.s @@ -23,7 +23,7 @@ .align 2 .globl __isr_vector __isr_vector: - .long CARD10_STACK_LIMIT /* Top of Stack */ + .long 0 /* Top of Stack, overriden by l0der at load time */ .long Reset_Handler /* Reset Handler */ .long NMI_Handler /* NMI Handler */ .long HardFault_Handler /* Hard Fault Handler */ @@ -145,10 +145,6 @@ __isr_vector: .thumb_func .align 2 Reset_Handler: - /* Set stack according to limits from linker script. */ - ldr r0, =CARD10_STACK_LIMIT - mov sp, r0 - /* Call system initialization from l0dables/lib/hardware.c. */ blx SystemInit diff --git a/l0dables/lib/l0dable.ld b/l0dables/lib/l0dable.ld index f09e39f6ba93637bde76d025c1914611a62b0179..c1c392153c9004eac56f0e434a96b02095bdaeac 100644 --- a/l0dables/lib/l0dable.ld +++ b/l0dables/lib/l0dable.ld @@ -71,14 +71,6 @@ SECTIONS { *(COMMON) } :data - . = ALIGN(4096); - .stack : - { - CARD10_STACK_START = .; - . += 8192; - CARD10_STACK_LIMIT = .; - } :data - /* Limit based on current limitations of l0dable setup - only uses core1 RAM. */ ASSERT(. < 0x40000, "Exceeded available RAM")