base-linux: add ARM support

This patch introduces a new platform 'linux_arm' for building and running
Genode/Linux on an ARM device.

Known limitations:

- libc 'setjmp()'/'longjmp()' doesn't currently save/restore floating
  point registers

Fixes #746.
This commit is contained in:
Christian Prochaska 2013-05-24 11:04:42 +02:00 committed by Norman Feske
parent 314d5c0975
commit 4a9b1c6aab
20 changed files with 350 additions and 11 deletions

View File

@ -9,8 +9,16 @@
ifeq ($(shell uname -m),x86_64) ifeq ($(shell uname -m),x86_64)
SPECS ?= genode linux_x86_64 sdl SPECS ?= genode linux_x86_64 sdl
else else
ifeq ($(shell uname -m),armv6l)
SPECS ?= genode linux_arm sdl arm_v6
else
ifeq ($(shell uname -m),armv7l)
SPECS ?= genode linux_arm sdl arm_v7a
else
SPECS ?= genode linux_x86_32 sdl SPECS ?= genode linux_x86_32 sdl
endif endif
endif
endif
# #
# If you want to build for the host platform, # If you want to build for the host platform,

View File

@ -97,8 +97,12 @@ USE_HOST_LD_SCRIPT = yes
ifeq (x86_64,$(findstring x86_64,$(SPECS))) ifeq (x86_64,$(findstring x86_64,$(SPECS)))
CXX_LINK_OPT += -Wl,--dynamic-linker=/lib64/ld-linux-x86-64.so.2 CXX_LINK_OPT += -Wl,--dynamic-linker=/lib64/ld-linux-x86-64.so.2
else else
ifeq (arm,$(findstring arm,$(SPECS)))
CXX_LINK_OPT += -Wl,--dynamic-linker=/lib/ld-linux.so.3
else
CXX_LINK_OPT += -Wl,--dynamic-linker=/lib/ld-linux.so.2 CXX_LINK_OPT += -Wl,--dynamic-linker=/lib/ld-linux.so.2
endif endif
endif
# because we use the host compiler's libgcc, omit the Genode toolchain's version # because we use the host compiler's libgcc, omit the Genode toolchain's version
LD_LIBGCC = LD_LIBGCC =

View File

@ -1,9 +1,9 @@
HOST_INC_DIR += $(dir $(call select_from_repositories,src/platform/linux_syscalls.h)) HOST_INC_DIR += $(dir $(call select_from_repositories,src/platform/linux_syscalls.h))
HOST_INC_DIR += /usr/include HOST_INC_DIR += /usr/include
# needed for Ubuntu 11.04 # needed for Ubuntu >= 11.04
HOST_INC_DIR += /usr/include/$(shell gcc -dumpmachine)
HOST_INC_DIR += /usr/include/i386-linux-gnu HOST_INC_DIR += /usr/include/i386-linux-gnu
HOST_INC_DIR += /usr/include/x86_64-linux-gnu
# #
# Some header files installed on GNU/Linux test for the GNU compiler. For # Some header files installed on GNU/Linux test for the GNU compiler. For

View File

@ -0,0 +1,8 @@
include $(REP_DIR)/lib/mk/base.inc
LIBS += startup cxx
SRC_CC += thread.cc thread_linux.cc
vpath thread.cc $(BASE_DIR)/src/base/thread
vpath thread_linux.cc $(REP_DIR)/src/base/thread

View File

@ -0,0 +1,5 @@
LIBS += syscall
include $(BASE_DIR)/lib/mk/startup.inc
vpath crt0.s $(REP_DIR)/src/platform/arm

View File

@ -0,0 +1,5 @@
REQUIRES = linux arm
SRC_S += lx_clone.S lx_syscall.S
vpath lx_clone.S $(REP_DIR)/../base-linux/src/platform/arm
vpath lx_syscall.S $(REP_DIR)/../base-linux/src/platform/arm

View File

@ -0,0 +1,25 @@
#
# Specifics for Linux on ARM
#
SPECS += linux arm
REP_INC_DIR += src/platform/arm
ifeq ($(shell gcc -dumpmachine),arm-linux-gnueabihf)
CC_MARCH += -mfloat-abi=hard
endif
#
# We need to manually add the default linker script on the command line in case
# of standard library use. Otherwise, we were not able to extend it by the
# context area section.
#
ifeq ($(USE_HOST_LD_SCRIPT),yes)
LD_SCRIPT_STATIC = ldscripts/armelf_linux_eabi.xc
endif
#
# Include less-specific configuration
#
include $(call select_from_repositories,mk/spec-arm.mk)
include $(call select_from_repositories,mk/spec-linux.mk)

View File

@ -70,7 +70,13 @@ Process::Process(Dataspace_capability elf_data_ds_cap,
PERR("Dynamically linked file found, but no dynamic linker binary present"); PERR("Dynamically linked file found, but no dynamic linker binary present");
return; return;
} }
elf_data_ds_cap = _dynamic_linker_cap; /*
* Starting the dynamic linker directly may cause it to be loaded at the
* wrong address on ARM-Linux. But since the dynamically linked
* application has a dynamic linker (by default ld.lib.so) defined as its
* interpreter in the ELF image, it's okay to just start the application
* directly on Linux.
*/
} }
/* /*

View File

@ -0,0 +1,66 @@
/*
* \brief Startup code for Genode applications
* \author Christian Helmuth
* \author Christian Prochaska
* \date 2006-07-06
*/
/*
* Copyright (C) 2006-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*--- .text (program code) -------------------------*/
.text
.globl _start
_start:
ldr r1,=__initial_sp
str sp,[r1]
/*
* environ = &argv[argc + 1]
* in Genode argc is always 1
*/
add sp,sp,#12
ldr r1,=lx_environ
str sp,[r1]
/* XXX Switch to our own stack. */
ldr sp,=_stack_high
/* Clear the frame pointer and the link register so that stack backtraces will work. */
mov fp,#0
mov lr,#0
/* Jump into init C code */
b _main
/*--------------------------------------------------*/
.data
.globl __dso_handle
__dso_handle:
.long 0
.globl __initial_sp
__initial_sp:
.long 0
/*--- .eh_frame (exception frames) -----------------*/
/*
.section .eh_frame,"aw"
.globl __EH_FRAME_BEGIN__
__EH_FRAME_BEGIN__:
*/
/*--- .bss (non-initialized data) ------------------*/
.bss
.p2align 4
.globl _stack_low
_stack_low:
.space 64*1024
.globl _stack_high
_stack_high:

View File

@ -0,0 +1,94 @@
/*
* \brief Linux clone() binding
* \author Christian Prochaska
* \date 2012-05-05
*
* based on eglibc-2.11.3/ports/sysdeps/unix/sysv/linux/arm/clone.S
*/
#define SYS_clone 120
#define SYS_exit 1
#define SYS_getpid 20
#define __ARM_EABI__ 1
#define CLONE_VM 0x00000100
#define CLONE_THREAD 0x00010000
.text
.globl lx_clone
.type lx_clone, #function
lx_clone:
@ insert the args onto the new stack
str r3, [r1, #-4]!
str r0, [r1, #-4]!
@ do the system call
@ get flags
mov r0, r2
#ifdef RESET_PID
mov ip, r2
#endif
@ new sp is already in r1
#ifdef __ARM_EABI__
stmfd sp!, {r4, r7}
#else
str r4, [sp, #-8]!
#endif
ldr r2, [sp, #8]
ldr r3, [sp, #12]
ldr r4, [sp, #16]
#ifdef __ARM_EABI__
ldr r7, =SYS_clone
swi 0x0
#else
swi SYS_clone
#endif
cmp r0, #0
beq 1f
#ifdef __ARM_EABI__
ldmfd sp!, {r4, r7}
#else
ldr r4, [sp], #8
#endif
#blt PLTJMP(C_SYMBOL_NAME(__syscall_error))
bx lr
1:
#ifdef RESET_PID
tst ip, #CLONE_THREAD
bne 3f
mov r0, #0xffff0fff
mov lr, pc
sub pc, r0, #31
mov r1, r0
tst ip, #CLONE_VM
movne r0, #-1
#ifdef __ARM_EABI__
ldr r7, =SYS_getpid
swieq 0x0
#else
swieq SYS_getpid
#endif
str r0, [r1, #PID_OFFSET]
str r0, [r1, #TID_OFFSET]
3:
#endif
@ pick the function arg and call address off the stack and execute
ldr r0, [sp, #4]
#if defined(__ARM_ARCH_4T__) && defined(__THUMB_INTERWORK__)
ldr ip, [sp], #8
mov lr, pc
bx ip
#else
mov lr, pc
ldr pc, [sp], #8
#endif
@ and we are done, passing the return value through r0
ldr r7, =SYS_exit
swi 0x0
/* tell the linker that this code does not need an executable stack */
.section .note.GNU-stack, "", %progbits

View File

@ -0,0 +1,29 @@
/*
* \brief Linux syscall() binding
* \author Christian Prochaska
* \date 2012-05-05
*
* based on eglibc-2.11.3/ports/sysdeps/unix/sysv/linux/arm/syscall.S
*
* error case:
* glibc's syscall() function returns -1 and sets errno
* lx_syscall() returns -errno
*/
.text
.globl lx_syscall
.type lx_syscall, #function
lx_syscall:
mov ip, sp
stmfd sp!, {r4, r5, r6, r7}
mov r7, r0
mov r0, r1
mov r1, r2
mov r2, r3
ldmfd ip, {r3, r4, r5, r6}
swi 0x0
ldmfd sp!, {r4, r5, r6, r7}
bx lr
/* tell the linker that this code does not need an executable stack */
.section .note.GNU-stack, "", %progbits

View File

@ -17,15 +17,25 @@
.globl _start .globl _start
_start: _start:
ldr sp, .initial_sp ldr r4, .initial_sp
str sp, [r4]
ldr sp, .stack_high
b _main b _main
.initial_sp: .word _stack_high .initial_sp: .word __initial_sp
.stack_high: .word _stack_high
/*--------------------------------------------------*/
.data
.globl __dso_handle .globl __dso_handle
__dso_handle: __dso_handle:
.long 0 .long 0
.globl __initial_sp
__initial_sp:
.long 0
/*--- .bss (non-initialized data) ------------------*/ /*--- .bss (non-initialized data) ------------------*/
.section ".bss" .section ".bss"

View File

@ -12,7 +12,4 @@ SRC_C += $(filter-out $(FILTER_OUT_C),$(notdir $(wildcard $(LIBC_GEN_ARM_DIR)/*
# fix missing include prefix for 'ucontext.h', should be 'sys/ucontext.h' # fix missing include prefix for 'ucontext.h', should be 'sys/ucontext.h'
CC_OPT_makecontext = -I$(REP_DIR)/include/libc/sys CC_OPT_makecontext = -I$(REP_DIR)/include/libc/sys
# needed to compile setjmp.S
CC_OPT += -DSOFTFLOAT
vpath % $(LIBC_GEN_ARM_DIR) vpath % $(LIBC_GEN_ARM_DIR)

View File

@ -7,6 +7,13 @@ SRC_S = _setjmp.S setjmp.S
# #
CC_OPT += -D_STANDALONE CC_OPT += -D_STANDALONE
#
# Needed to compile on hard-float Linux
# FIXME: Floating point registers don't get saved/restored
# when using this definition!
#
CC_OPT += -D__SOFTFP__
include $(REP_DIR)/lib/mk/libc-common.inc include $(REP_DIR)/lib/mk/libc-common.inc
vpath %.S $(LIBC_GEN_ARM_DIR) vpath %.S $(LIBC_GEN_ARM_DIR)

View File

@ -0,0 +1,3 @@
SRC_S = crt0.s
vpath crt0.s $(REP_DIR)/src/lib/ldso/arm/linux

View File

@ -20,10 +20,14 @@ _start_ldso:
ldr r2, .initial_utcb ldr r2, .initial_utcb
str r0, [r2] str r0, [r2]
ldr sp, .initial_sp ldr r2, .initial_sp
str sp, [r2]
ldr sp, .stack_high
bl init_rtld bl init_rtld
b _main b _main
.initial_sp: .word _stack_high .initial_sp: .word __initial_sp
.stack_high: .word _stack_high
.initial_utcb: .word _main_utcb .initial_utcb: .word _main_utcb

View File

@ -0,0 +1,58 @@
/*
* \brief Startup code for ld.lib.so (linux_arm)
* \author Christian Prochaska
* \date 2012-07-06
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/*--- .text (program code) -------------------------*/
.section ".text.crt0"
.globl _start_ldso
_start_ldso:
ldr sl, .L_GOT
.L_GOT_OFF:
add sl, pc, sl
ldr r1, .initial_sp
ldr r1, [sl, r1]
str sp, [r1]
/*
* environ = &argv[argc + 1]
* in Genode argc is always 1
*/
add sp, sp,#12
ldr r1, .lx_environ
ldr r1, [sl, r1]
str sp, [r1]
/* XXX Switch to our own stack. */
ldr r1, .stack_high
ldr sp, [sl, r1]
/* relocate ldso */
mov r1, #0
bl init_rtld
/*
* Clear the frame pointer and the link register so that stack
* backtraces will work.
*/
mov fp, #0
mov lr, #0
/* Jump into init C code */
b _main
.L_GOT: .word _GLOBAL_OFFSET_TABLE_ - (.L_GOT_OFF + 8)
.initial_sp: .word __initial_sp(GOT)
.lx_environ: .word lx_environ(GOT)
.stack_high: .word _stack_high(GOT)

View File

@ -18,7 +18,15 @@
*/ */
void call_main(void (*func)(void)) void call_main(void (*func)(void))
{ {
func(); extern long __initial_sp;
asm volatile ("mov %%sp, %0;"
"bx %1;"
:
: "r" (__initial_sp),
"r" (func)
: "memory"
);
} }
#endif /* _ARM__CALL_MAIN_H_ */ #endif /* _ARM__CALL_MAIN_H_ */

View File

@ -0,0 +1 @@
REPOSITORIES = $(GENODE_DIR)/base-linux

View File

@ -20,6 +20,7 @@ usage:
@echo @echo
@echo " <platform> can be:" @echo " <platform> can be:"
@echo " 'linux_x86'" @echo " 'linux_x86'"
@echo " 'linux_arm'"
@echo " 'fiasco_x86'" @echo " 'fiasco_x86'"
@echo " 'pistachio_x86'" @echo " 'pistachio_x86'"
@echo " 'okl4_x86'" @echo " 'okl4_x86'"