kboot: aarch64 support
Add support for aarch64. exec.c and ldscript are copied from the EFI version with #ifdefs for the differences. Once complete, I'll refactor them. host_syscall.S implements a generic system call. tramp.S is a first attempt to create a tramoline that we can use to jump to the aarch64 kernel. Add aarch64-specific startup and stat files as well. exec.c tweaked slightly to avoid bringing in bi_load(), which will come in later. Includes tweaks to stat due to name differences between names on different Linux architectures. Sponsored by: Netflix
This commit is contained in:
parent
a0c075229f
commit
75cbdbc983
12
stand/kboot/arch/aarch64/Makefile.inc
Normal file
12
stand/kboot/arch/aarch64/Makefile.inc
Normal file
@ -0,0 +1,12 @@
|
||||
SRCS+= host_syscall.S tramp.S exec.c load_addr.c
|
||||
|
||||
.PATH: ${BOOTSRC}/arm64/libarm64
|
||||
CFLAGS+=-I${BOOTSRC}/arm64/libarm64
|
||||
SRCS+= cache.c
|
||||
|
||||
CFLAGS+= -I${SYSDIR}/contrib/dev/acpica/include
|
||||
# load address. set in linker script
|
||||
RELOC?= 0x0
|
||||
CFLAGS+= -DRELOC=${RELOC}
|
||||
|
||||
LDFLAGS= -nostdlib -static -T ${.CURDIR}/arch/${MACHINE_ARCH}/ldscript.${MACHINE_ARCH}
|
188
stand/kboot/arch/aarch64/exec.c
Normal file
188
stand/kboot/arch/aarch64/exec.c
Normal file
@ -0,0 +1,188 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Marcel Moolenaar
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <stand.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker.h>
|
||||
#include <machine/elf.h>
|
||||
|
||||
#include <bootstrap.h>
|
||||
|
||||
#ifdef EFI
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "loader_efi.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include "bootstrap.h"
|
||||
|
||||
#include "platform/acfreebsd.h"
|
||||
#include "acconfig.h"
|
||||
#define ACPI_SYSTEM_XFACE
|
||||
#include "actypes.h"
|
||||
#include "actbl.h"
|
||||
|
||||
#include "cache.h"
|
||||
|
||||
#ifdef EFI
|
||||
static EFI_GUID acpi_guid = ACPI_TABLE_GUID;
|
||||
static EFI_GUID acpi20_guid = ACPI_20_TABLE_GUID;
|
||||
#endif
|
||||
|
||||
static int elf64_exec(struct preloaded_file *amp);
|
||||
static int elf64_obj_exec(struct preloaded_file *amp);
|
||||
|
||||
/* Stub out temporarily */
|
||||
static int
|
||||
bi_load(char *args, vm_offset_t *modulep, vm_offset_t *kernendp,
|
||||
bool exit_bs)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
static struct file_format arm64_elf = {
|
||||
elf64_loadfile,
|
||||
elf64_exec
|
||||
};
|
||||
|
||||
struct file_format *file_formats[] = {
|
||||
&arm64_elf,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int
|
||||
elf64_exec(struct preloaded_file *fp)
|
||||
{
|
||||
vm_offset_t modulep, kernendp;
|
||||
vm_offset_t clean_addr;
|
||||
size_t clean_size;
|
||||
struct file_metadata *md;
|
||||
Elf_Ehdr *ehdr;
|
||||
void (*entry)(vm_offset_t);
|
||||
int err;
|
||||
#ifdef EFI
|
||||
ACPI_TABLE_RSDP *rsdp;
|
||||
char buf[24];
|
||||
int revision;
|
||||
#endif
|
||||
/*
|
||||
* Report the RSDP to the kernel. The old code used the 'hints' method
|
||||
* to communite this to the kernel. However, while convenient, the
|
||||
* 'hints' method is fragile and does not work when static hints are
|
||||
* compiled into the kernel. Instead, move to setting different tunables
|
||||
* that start with acpi. The old 'hints' can be removed before we branch
|
||||
* for FreeBSD 15.
|
||||
*/
|
||||
#ifdef EFI
|
||||
rsdp = efi_get_table(&acpi20_guid);
|
||||
if (rsdp == NULL) {
|
||||
rsdp = efi_get_table(&acpi_guid);
|
||||
}
|
||||
if (rsdp != NULL) {
|
||||
sprintf(buf, "0x%016llx", (unsigned long long)rsdp);
|
||||
setenv("hint.acpi.0.rsdp", buf, 1);
|
||||
setenv("acpi.rsdp", buf, 1);
|
||||
revision = rsdp->Revision;
|
||||
if (revision == 0)
|
||||
revision = 1;
|
||||
sprintf(buf, "%d", revision);
|
||||
setenv("hint.acpi.0.revision", buf, 1);
|
||||
setenv("acpi.revision", buf, 1);
|
||||
strncpy(buf, rsdp->OemId, sizeof(rsdp->OemId));
|
||||
buf[sizeof(rsdp->OemId)] = '\0';
|
||||
setenv("hint.acpi.0.oem", buf, 1);
|
||||
setenv("acpi.oem", buf, 1);
|
||||
sprintf(buf, "0x%016x", rsdp->RsdtPhysicalAddress);
|
||||
setenv("hint.acpi.0.rsdt", buf, 1);
|
||||
setenv("acpi.rsdt", buf, 1);
|
||||
if (revision >= 2) {
|
||||
/* XXX extended checksum? */
|
||||
sprintf(buf, "0x%016llx",
|
||||
(unsigned long long)rsdp->XsdtPhysicalAddress);
|
||||
setenv("hint.acpi.0.xsdt", buf, 1);
|
||||
setenv("acpi.xsdt", buf, 1);
|
||||
sprintf(buf, "%d", rsdp->Length);
|
||||
setenv("hint.acpi.0.xsdt_length", buf, 1);
|
||||
setenv("acpi.xsdt_length", buf, 1);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
if ((md = file_findmetadata(fp, MODINFOMD_ELFHDR)) == NULL)
|
||||
return(EFTYPE);
|
||||
|
||||
ehdr = (Elf_Ehdr *)&(md->md_data);
|
||||
#ifdef EFI
|
||||
entry = efi_translate(ehdr->e_entry);
|
||||
|
||||
efi_time_fini();
|
||||
#else
|
||||
entry = (void *)ehdr->e_entry;
|
||||
#endif
|
||||
err = bi_load(fp->f_args, &modulep, &kernendp, true);
|
||||
if (err != 0) {
|
||||
#ifdef EFI
|
||||
efi_time_init();
|
||||
#endif
|
||||
return (err);
|
||||
}
|
||||
|
||||
dev_cleanup();
|
||||
|
||||
/* Clean D-cache under kernel area and invalidate whole I-cache */
|
||||
#ifdef EFI
|
||||
clean_addr = (vm_offset_t)efi_translate(fp->f_addr);
|
||||
clean_size = (vm_offset_t)efi_translate(kernendp) - clean_addr;
|
||||
#else
|
||||
clean_addr = (vm_offset_t)fp->f_addr;
|
||||
clean_size = (vm_offset_t)kernendp - clean_addr;
|
||||
#endif
|
||||
|
||||
cpu_flush_dcache((void *)clean_addr, clean_size);
|
||||
cpu_inval_icache();
|
||||
|
||||
(*entry)(modulep);
|
||||
|
||||
panic("exec returned");
|
||||
}
|
||||
|
||||
static int
|
||||
elf64_obj_exec(struct preloaded_file *fp)
|
||||
{
|
||||
|
||||
printf("%s called for preloaded file %p (=%s):\n", __func__, fp,
|
||||
fp->f_name);
|
||||
return (ENOSYS);
|
||||
}
|
||||
|
18
stand/kboot/arch/aarch64/host_syscall.S
Normal file
18
stand/kboot/arch/aarch64/host_syscall.S
Normal file
@ -0,0 +1,18 @@
|
||||
#include <machine/asm.h>
|
||||
|
||||
/*
|
||||
* Emulate the Linux system call interface. System call number in x8.
|
||||
* Args in x0, x1, x2, x3, x4 and x5. Return in x0.
|
||||
*/
|
||||
ENTRY(host_syscall)
|
||||
mov x8, x0
|
||||
mov x0, x1
|
||||
mov x1, x2
|
||||
mov x2, x3
|
||||
mov x3, x4
|
||||
mov x4, x5
|
||||
mov x5, x6
|
||||
svc 0
|
||||
ret
|
||||
/* Note: We're exposing the raw return value to the caller */
|
||||
END(host_syscall)
|
72
stand/kboot/arch/aarch64/ldscript.aarch64
Normal file
72
stand/kboot/arch/aarch64/ldscript.aarch64
Normal file
@ -0,0 +1,72 @@
|
||||
/* $FreeBSD$ */
|
||||
OUTPUT_FORMAT("elf64-aarch64", "elf64-aarch64", "elf64-aarch64")
|
||||
OUTPUT_ARCH(aarch64)
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0x401000;
|
||||
ImageBase = .;
|
||||
.hash : { *(.hash) } /* this MUST come first! */
|
||||
. = ALIGN(4096);
|
||||
.eh_frame :
|
||||
{
|
||||
*(.eh_frame)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
.text : {
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||
*(.gnu.warning)
|
||||
*(.plt)
|
||||
} =0xCCCCCCCC
|
||||
. = ALIGN(4096);
|
||||
.data : {
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
*(.rodata1)
|
||||
*(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
|
||||
*(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
|
||||
*(.opd)
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
*(.data1)
|
||||
*(.plabel)
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
set_Xcommand_set : {
|
||||
__start_set_Xcommand_set = .;
|
||||
*(set_Xcommand_set)
|
||||
__stop_set_Xcommand_set = .;
|
||||
}
|
||||
set_Xficl_compile_set : {
|
||||
__start_set_Xficl_compile_set = .;
|
||||
*(set_Xficl_compile_set)
|
||||
__stop_set_Xficl_compile_set = .;
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
__gp = .;
|
||||
.sdata : {
|
||||
*(.got.plt .got)
|
||||
*(.sdata .sdata.* .gnu.linkonce.s.*)
|
||||
*(dynsbss)
|
||||
*(.sbss .sbss.* .gnu.linkonce.sb.*)
|
||||
*(.scommon)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
.dynamic : { *(.dynamic) }
|
||||
. = ALIGN(4096);
|
||||
.rela.dyn : {
|
||||
*(.rela.data*)
|
||||
*(.rela.got)
|
||||
*(.rela.stab)
|
||||
*(.relaset_*)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
.reloc : { *(.reloc) }
|
||||
. = ALIGN(4096);
|
||||
.dynsym : { *(.dynsym) }
|
||||
. = ALIGN(4096);
|
||||
.dynstr : { *(.dynstr) }
|
||||
}
|
0
stand/kboot/arch/aarch64/load_addr.c
Normal file
0
stand/kboot/arch/aarch64/load_addr.c
Normal file
36
stand/kboot/arch/aarch64/start_arch.h
Normal file
36
stand/kboot/arch/aarch64/start_arch.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Netflix, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
* Provides a _start routine that calls a _start_c routine that takes a pointer
|
||||
* to the stack as documented in crt1.c. We skip the pointer to _DYNAMIC since
|
||||
* we don't support dynamic libraries, at all. And while _start_c is our own
|
||||
* thing and doesn't have a second arg, we comport to the calling conventions
|
||||
* that glibc and musl have by passing x1 as 0 for the dynamic pointer. We
|
||||
* likely could call main directly with only a few more lines of code, but this
|
||||
* is simple enough and concentrates all the expressable in C stuff there. We
|
||||
* also generate eh_frames should we need to debug things (it doesn't change the
|
||||
* genreated code, but leaves enough breadcrumbs to keep gdb happy)
|
||||
*/
|
||||
|
||||
__asm__(
|
||||
".text\n" /* ENTRY(_start) -- can't expand and stringify, so by hand */
|
||||
".align 2\n"
|
||||
".global _start\n"
|
||||
".type _start, #function\n"
|
||||
"_start:\n"
|
||||
".cfi_startproc\n"
|
||||
/*
|
||||
* Linux zeros all registers so x29 (frame pointer) and x30 (link register) are 0.
|
||||
*/
|
||||
" mov x0, sp\n" /* Pointer to argc, etc kernel left on the stack */
|
||||
" and sp, x0, #-16\n" /* Align stack to 16-byte boundary */
|
||||
" b _start_c\n" /* Our MI code takes it from here */
|
||||
/* NORETURN */
|
||||
".ltorg\n" /* END(_start) */
|
||||
".cfi_endproc\n"
|
||||
".size _start, .-_start\n"
|
||||
);
|
29
stand/kboot/arch/aarch64/stat_arch.h
Normal file
29
stand/kboot/arch/aarch64/stat_arch.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2005-2020 Rich Felker, et al.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Note: From the musl project
|
||||
*/
|
||||
|
||||
struct host_kstat {
|
||||
host_dev_t st_dev;
|
||||
host_ino_t st_ino;
|
||||
host_mode_t st_mode;
|
||||
host_nlink_t st_nlink;
|
||||
host_uid_t st_uid;
|
||||
host_gid_t st_gid;
|
||||
host_dev_t st_rdev;
|
||||
unsigned long __pad;
|
||||
host_off_t st_size;
|
||||
host_blksize_t st_blksize;
|
||||
int __pad2;
|
||||
host_blkcnt_t st_blocks;
|
||||
long st_atime_sec;
|
||||
long st_atime_nsec;
|
||||
long st_mtime_sec;
|
||||
long st_mtime_nsec;
|
||||
long st_ctime_sec;
|
||||
long st_ctime_nsec;
|
||||
unsigned __pad_for_future[2];
|
||||
};
|
20
stand/kboot/arch/aarch64/syscall_nr.h
Normal file
20
stand/kboot/arch/aarch64/syscall_nr.h
Normal file
@ -0,0 +1,20 @@
|
||||
#define SYS_close 57
|
||||
#define SYS_dup 23
|
||||
#define SYS_fstat 80
|
||||
#define SYS_getdents64 61
|
||||
#define SYS_getpid 172
|
||||
#define SYS_gettimeofday 169
|
||||
#define SYS_lseek 62
|
||||
#define SYS_kexec_load 104
|
||||
#define SYS_mkdirat 34
|
||||
#define SYS_mmap 222
|
||||
#define SYS_mount 40
|
||||
#define SYS_munmap 215
|
||||
#define SYS_newfstatat 79
|
||||
#define SYS_openat 56
|
||||
#define SYS_pselect6 72
|
||||
#define SYS_read 63
|
||||
#define SYS_reboot 142
|
||||
#define SYS_symlinkat 36
|
||||
#define SYS_uname 160
|
||||
#define SYS_write 64
|
67
stand/kboot/arch/aarch64/tramp.S
Normal file
67
stand/kboot/arch/aarch64/tramp.S
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Netflix, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is the trampoline that starts the FreeBSD kernel. Since the Linux kernel
|
||||
* calls this routine with no args, and has a different environment than the boot
|
||||
* loader provides and that the kernel expects, this code is responsible for setting
|
||||
* all that up and calling the normal kernel entry point. It's analogous ot the
|
||||
* "purgatory" code in the linux kernel. Details about these operations are
|
||||
* contained in comments below. On aarch64, the kernel will start all the APs so
|
||||
* we don't have to worry about them here.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Keep in sync with exec.c. Kexec starts aarch64_tramp w/o any
|
||||
* parameters, so store them here.
|
||||
*
|
||||
* struct trampoline_data {
|
||||
* uint64_t entry; // 0 (PA where kernel loaded)
|
||||
* uint64_t modulep; // 8 module metadata
|
||||
* };
|
||||
*
|
||||
* The aarch64 _start routine assumes:
|
||||
* MMU on with an identity map, or off
|
||||
* D-Cache: off
|
||||
* I-Cache: on or off
|
||||
* We are loaded at a 2MiB aligned address
|
||||
* Module data (modulep) pointer in x0
|
||||
*
|
||||
* Unlike EFI, we don't support copying the staging area. We tell Linunx to land
|
||||
* the kernel in its final location with the needed alignment, etc.
|
||||
*
|
||||
* This trampoline installs sets up the arguments the kernel expects, flushes
|
||||
* the cache lines and jumps to the kernel _start address. We pass the modulep
|
||||
* pointer in x0, as _start expects.
|
||||
*/
|
||||
.text
|
||||
.globl aarch64_tramp
|
||||
aarch64_tramp:
|
||||
b 1f /* skip over our saved args */
|
||||
.p2align 3
|
||||
trampoline_data:
|
||||
#define TRAMP_ENTRY 0
|
||||
#define TRAMP_MODULEP 8
|
||||
#define TRAMP_TOTAL 16
|
||||
.space TRAMP_TOTAL
|
||||
#define TMPSTACKSIZE 48 /* 16 bytes for args +8 for pushq/popfq + 24 spare */
|
||||
1:
|
||||
adr x2, trampoline_data
|
||||
ldr x1, [x2, #TRAMP_ENTRY]
|
||||
ldr x0, [x2, #TRAMP_MODULEP]
|
||||
br x1
|
||||
|
||||
.p2align 4
|
||||
.space TMPSTACKSIZE
|
||||
aarch64_tramp_end: /* padding doubles as stack */
|
||||
|
||||
.data
|
||||
.globl aarch64_tramp_size
|
||||
aarch64_tramp_size:
|
||||
.long aarch64_tramp_end-aarch64_tramp
|
||||
.globl aarch64_tramp_data_offset
|
||||
aarch64_tramp_data_offset:
|
||||
.long trampoline_data-aarch64_tramp
|
@ -19,10 +19,15 @@ host_dup(int fd)
|
||||
return host_syscall(SYS_dup, fd);
|
||||
}
|
||||
|
||||
/* Same system call with different names on different Linux architectures due to history */
|
||||
int
|
||||
host_fstat(int fd, struct host_kstat *sb)
|
||||
{
|
||||
#ifdef SYS_newfstat
|
||||
return host_syscall(SYS_newfstat, fd, (uintptr_t)sb);
|
||||
#else
|
||||
return host_syscall(SYS_fstat, fd, (uintptr_t)sb);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
Reference in New Issue
Block a user