baremetal: fix heap and stack position in preparation for CLI arguments

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2020-04-01 02:00:01 +00:00
parent 6bb20c0386
commit e25e79c26b
9 changed files with 58 additions and 11 deletions

View File

@@ -19482,6 +19482,27 @@ It is not possible to call those C functions from the examples that don't use a
For this reason, we tend to create examples with bootloaders, as it is easier to write them portably. For this reason, we tend to create examples with bootloaders, as it is easier to write them portably.
=== Baremetal linker script
For things to work in baremetal, we often have to layout memory in specific ways.
Notably, since we start with <<arm-paging,paging>> disabled, there are more constraints on where memory can or cannot go.
Especially for C programs, this memory layout is specified by a "linker script", which is present at: link:baremetal/link.ld[]
Note how our linker script also exposes some symbols to C:
....
lkmc_heap_low = .;
lkmc_heap_top = .;
....
Those for example are required to implement `malloc` in Newlib. We can play with those variables more explicitly with link:baremetal/linker_variables.c[]:
....
./run --arch aarch64 --baremetal baremetal/linker_variables.c
....
=== Semihosting === Semihosting
Semihosting is a publicly documented interface specified by ARM Holdings that allows us to do some magic operations very useful in development. Semihosting is a publicly documented interface specified by ARM Holdings that allows us to do some magic operations very useful in development.

View File

@@ -18,7 +18,7 @@ __asm__(
" bne .Lsleep_forever\n" " bne .Lsleep_forever\n"
/* Prepare the stack for CPU1. This is what we need /* Prepare the stack for CPU1. This is what we need
* this assembly function for. */ * this assembly function for. */
" ldr x0, =(stack_top - 0x1000)\n" " ldr x0, =(lkmc_stack_top - 0x1000)\n"
" mov sp, x0\n" " mov sp, x0\n"
" bl main_cpu1\n" " bl main_cpu1\n"
".Lsleep_forever:\n" ".Lsleep_forever:\n"

View File

@@ -11,7 +11,7 @@ __asm__(
"lkmc_cpu_not_0:\n" "lkmc_cpu_not_0:\n"
" cmp r0, 1\n" " cmp r0, 1\n"
" bne .Lsleep_forever\n" " bne .Lsleep_forever\n"
" ldr sp, =(stack_top - 0x1000)\n" " ldr sp, =(lkmc_stack_top - 0x1000)\n"
" bl main_cpu1\n" " bl main_cpu1\n"
".Lsleep_forever:\n" ".Lsleep_forever:\n"
" wfe\n" " wfe\n"

View File

@@ -20,7 +20,7 @@ _start:
isb isb
/* Prepare the stack for main, mandatory for C code. */ /* Prepare the stack for main, mandatory for C code. */
ldr x0, =stack_top ldr x0, =lkmc_stack_top
mov sp, x0 mov sp, x0
/* https://cirosantilli.com/linux-kernel-module-cheat#magic-failure-string */ /* https://cirosantilli.com/linux-kernel-module-cheat#magic-failure-string */

View File

@@ -8,7 +8,7 @@ _start:
bne lkmc_cpu_not_0 bne lkmc_cpu_not_0
/* Prepare the stack for main, mandatory for C code. */ /* Prepare the stack for main, mandatory for C code. */
ldr sp, =stack_top ldr sp, =lkmc_stack_top
/* Enable floating point. /* Enable floating point.
* Code copied from: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0409h/CHDEGGFF.html * Code copied from: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0409h/CHDEGGFF.html

View File

@@ -12,8 +12,8 @@ enum {
UART_FR_RXFE = 0x10, UART_FR_RXFE = 0x10,
}; };
extern char heap_low; extern char lkmc_heap_low;
extern char heap_top; extern char lkmc_heap_top;
char *heap_end = 0; char *heap_end = 0;
@@ -90,10 +90,10 @@ _CLOCK_T_ _times_r (struct _reent *r, struct tms *ptms) {
caddr_t _sbrk(int incr) { caddr_t _sbrk(int incr) {
char *prev_heap_end; char *prev_heap_end;
if (heap_end == 0) { if (heap_end == 0) {
heap_end = &heap_low; heap_end = &lkmc_heap_low;
} }
prev_heap_end = heap_end; prev_heap_end = heap_end;
if (heap_end + incr > &heap_top) { if (heap_end + incr > &lkmc_heap_top) {
/* Heap and stack collision */ /* Heap and stack collision */
return (caddr_t)0; return (caddr_t)0;
} }

View File

@@ -1,3 +1,4 @@
/* https://cirosantilli.com/linux-kernel-module-cheat#baremetal-linker-script */
ENTRY(_start) ENTRY(_start)
SECTIONS SECTIONS
{ {
@@ -10,10 +11,18 @@ SECTIONS
} }
/* gem5 uses the bss as a measure of the kernel size. */ /* gem5 uses the bss as a measure of the kernel size. */
.bss : { *(.bss) } .bss : { *(.bss) }
heap_low = .; /* Fix the addresses of everything that comes after, no matter
* the exact size of the code present in .text. This allows us to
* place CLI arguments in memory at a known location! */
. = ADDR(.text) + 0x1000000;
lkmc_heap_low = .;
. = . + 0x1000000; . = . + 0x1000000;
heap_top = .; lkmc_heap_top = .;
. = . + 0x1000000; . = . + 0x1000000;
stack_top = .; lkmc_stack_top = .;
. = . + 0x1000000;
lkmc_argv = .;
. = . + 0x4;
lkmc_argc = .;
} }

View File

@@ -0,0 +1,16 @@
/* https://cirosantilli.com/linux-kernel-module-cheat#baremetal-linker-script */
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
extern int32_t lkmc_argc;
extern int32_t lkmc_heap_low;
int main(int argc, char **argv) {
(void)argc;
(void)argv;
printf("&lkmc_heap_low %p\n", (void*)&lkmc_heap_low);
printf("&lkmc_argc %p\n", (void*)&lkmc_argc);
printf("lkmc_argc %" PRId32 "\n", lkmc_argc);
}

View File

@@ -102,6 +102,7 @@ Build the baremetal examples with crosstool-NG.
) )
cc_flags.extend([ cc_flags.extend([
'-Wl,--section-start=.text={:#x}'.format(entry_address), LF, '-Wl,--section-start=.text={:#x}'.format(entry_address), LF,
'-Wl,--section-start=.lkmc_memory={:#x}'.format(entry_address + 0x1000000), LF,
'-T', self.env['baremetal_link_script'], LF, '-T', self.env['baremetal_link_script'], LF,
]) ])
with thread_pool.ThreadPool( with thread_pool.ThreadPool(