2007-11-17 20:14:51 +03:00
|
|
|
/*
|
2019-05-23 16:47:43 +03:00
|
|
|
* ARM kernel loader.
|
2007-11-17 20:14:51 +03:00
|
|
|
*
|
|
|
|
* Copyright (c) 2006 CodeSourcery.
|
|
|
|
* Written by Paul Brook
|
|
|
|
*
|
2011-06-26 06:21:35 +04:00
|
|
|
* This code is licensed under the LGPL.
|
2007-11-17 20:14:51 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2019-05-23 16:47:43 +03:00
|
|
|
#ifndef HW_ARM_BOOT_H
|
|
|
|
#define HW_ARM_BOOT_H
|
2007-11-17 20:14:51 +03:00
|
|
|
|
2016-10-11 09:56:52 +03:00
|
|
|
#include "target/arm/cpu-qom.h"
|
2015-06-02 14:29:12 +03:00
|
|
|
#include "qemu/notify.h"
|
2011-07-25 15:27:01 +04:00
|
|
|
|
2016-03-04 14:30:21 +03:00
|
|
|
typedef enum {
|
|
|
|
ARM_ENDIANNESS_UNKNOWN = 0,
|
|
|
|
ARM_ENDIANNESS_LE,
|
|
|
|
ARM_ENDIANNESS_BE8,
|
|
|
|
ARM_ENDIANNESS_BE32,
|
|
|
|
} arm_endianness;
|
|
|
|
|
2017-02-20 18:35:55 +03:00
|
|
|
/**
|
|
|
|
* armv7m_load_kernel:
|
|
|
|
* @cpu: CPU
|
|
|
|
* @kernel_filename: file to load
|
|
|
|
* @mem_size: mem_size: maximum image size to load
|
|
|
|
*
|
|
|
|
* Load the guest image for an ARMv7M system. This must be called by
|
2018-06-15 16:57:13 +03:00
|
|
|
* any ARMv7M board. (This is necessary to ensure that the CPU resets
|
|
|
|
* correctly on system reset, as well as for kernel loading.)
|
2017-02-20 18:35:55 +03:00
|
|
|
*/
|
|
|
|
void armv7m_load_kernel(ARMCPU *cpu, const char *kernel_filename, int mem_size);
|
2007-11-17 20:14:51 +03:00
|
|
|
|
|
|
|
/* arm_boot.c */
|
2008-04-15 00:27:51 +04:00
|
|
|
struct arm_boot_info {
|
2012-07-20 16:34:49 +04:00
|
|
|
uint64_t ram_size;
|
2008-04-15 00:27:51 +04:00
|
|
|
const char *kernel_filename;
|
|
|
|
const char *kernel_cmdline;
|
|
|
|
const char *initrd_filename;
|
2012-03-02 15:56:38 +04:00
|
|
|
const char *dtb_filename;
|
2012-10-23 14:30:10 +04:00
|
|
|
hwaddr loader_start;
|
2018-05-10 20:10:56 +03:00
|
|
|
hwaddr dtb_start;
|
|
|
|
hwaddr dtb_limit;
|
|
|
|
/* If set to True, arm_load_kernel() will not load DTB.
|
|
|
|
* It allows board to load DTB manually later.
|
|
|
|
* (default: False)
|
|
|
|
*/
|
|
|
|
bool skip_dtb_autoload;
|
2012-01-26 15:43:48 +04:00
|
|
|
/* multicore boards that use the default secondary core boot functions
|
|
|
|
* need to put the address of the secondary boot code, the boot reg,
|
|
|
|
* and the GIC address in the next 3 values, respectively. boards that
|
|
|
|
* have their own boot functions can use these values as they want.
|
|
|
|
*/
|
2012-10-23 14:30:10 +04:00
|
|
|
hwaddr smp_loader_start;
|
|
|
|
hwaddr smp_bootreg_addr;
|
|
|
|
hwaddr gic_cpu_if_addr;
|
2008-04-15 00:27:51 +04:00
|
|
|
int board_id;
|
2014-12-16 02:09:47 +03:00
|
|
|
/* ARM machines that support the ARM Security Extensions use this field to
|
|
|
|
* control whether Linux is booted as secure(true) or non-secure(false).
|
|
|
|
*/
|
|
|
|
bool secure_boot;
|
2011-06-23 19:53:48 +04:00
|
|
|
int (*atag_board)(const struct arm_boot_info *info, void *p);
|
2012-01-26 15:43:48 +04:00
|
|
|
/* multicore boards that use the default secondary core boot functions
|
|
|
|
* can ignore these two function calls. If the default functions won't
|
|
|
|
* work, then write_secondary_boot() should write a suitable blob of
|
2012-05-28 08:11:49 +04:00
|
|
|
* code mimicking the secondary CPU startup process used by the board's
|
2012-01-26 15:43:48 +04:00
|
|
|
* boot loader/boot ROM code, and secondary_cpu_reset_hook() should
|
2012-05-28 08:11:49 +04:00
|
|
|
* perform any necessary CPU reset handling and set the PC for the
|
2012-01-26 15:43:48 +04:00
|
|
|
* secondary CPUs to point at this boot blob.
|
2022-01-27 18:46:36 +03:00
|
|
|
*
|
|
|
|
* These hooks won't be called if secondary CPUs are booting via
|
|
|
|
* emulated PSCI (see psci_conduit below).
|
2012-01-26 15:43:48 +04:00
|
|
|
*/
|
2012-05-14 02:08:10 +04:00
|
|
|
void (*write_secondary_boot)(ARMCPU *cpu,
|
2012-01-26 15:43:48 +04:00
|
|
|
const struct arm_boot_info *info);
|
2012-05-14 03:05:40 +04:00
|
|
|
void (*secondary_cpu_reset_hook)(ARMCPU *cpu,
|
2012-01-26 15:43:48 +04:00
|
|
|
const struct arm_boot_info *info);
|
2013-11-22 21:17:10 +04:00
|
|
|
/* if a board is able to create a dtb without a dtb file then it
|
|
|
|
* sets get_dtb. This will only be used if no dtb file is provided
|
|
|
|
* by the user. On success, sets *size to the length of the created
|
|
|
|
* dtb, and returns a pointer to it. (The caller must free this memory
|
|
|
|
* with g_free() when it has finished with it.) On failure, returns NULL.
|
|
|
|
*/
|
|
|
|
void *(*get_dtb)(const struct arm_boot_info *info, int *size);
|
2013-07-16 16:25:10 +04:00
|
|
|
/* if a board needs to be able to modify a device tree provided by
|
|
|
|
* the user it should implement this hook.
|
|
|
|
*/
|
|
|
|
void (*modify_dtb)(const struct arm_boot_info *info, void *fdt);
|
hw/arm/boot: Support setting psci-conduit based on guest EL
Currently we expect board code to set the psci-conduit property on
CPUs and ensure that secondary CPUs are created with the
start-powered-off property set to false, if the board wishes to use
QEMU's builtin PSCI emulation. This worked OK for the virt board
where we first wanted to use it, because the virt board directly
creates its CPUs and is in a reasonable position to set those
properties. For other boards which model real hardware and use a
separate SoC object, however, it is more awkward. Most PSCI-using
boards just set the psci-conduit board unconditionally.
This was never strictly speaking correct (because you would not be
able to run EL3 guest firmware that itself provided the PSCI
interface, as the QEMU implementation would overrule it), but mostly
worked in practice because for non-PSCI SMC calls QEMU would emulate
the SMC instruction as normal (by trapping to guest EL3). However,
we would like to make our PSCI emulation follow the part of the SMCC
specification that mandates that SMC calls with unknown function
identifiers return a failure code, which means that all SMC calls
will be handled by the PSCI code and the "emulate as normal" path
will no longer be taken.
We tried to implement that in commit 9fcd15b9193e81
("arm: tcg: Adhere to SMCCC 1.3 section 5.2"), but this
regressed attempts to run EL3 guest code on the affected boards:
* mcimx6ul-evk, mcimx7d-sabre, orangepi, xlnx-zcu102
* for the case only of EL3 code loaded via -kernel (and
not via -bios or -pflash), virt and xlnx-versal-virt
so for the 7.0 release we reverted it (in commit 4825eaae4fdd56f).
This commit provides a mechanism that boards can use to arrange that
psci-conduit is set if running guest code at a low enough EL but not
if it would be running at the same EL that the conduit implies that
the QEMU PSCI implementation is using. (Later commits will convert
individual board models to use this mechanism.)
We do this by moving the setting of the psci-conduit and
start-powered-off properties to arm_load_kernel(). Boards which want
to potentially use emulated PSCI must set a psci_conduit field in the
arm_boot_info struct to the type of conduit they want to use (SMC or
HVC); arm_load_kernel() will then set the CPUs up accordingly if it
is not going to start the guest code at the same or higher EL as the
fake QEMU firmware would be at.
Board/SoC code which uses this mechanism should no longer set the CPU
psci-conduit property directly. It should only set the
start-powered-off property for secondaries if EL3 guest firmware
running bare metal expects that rather than the alternative "all CPUs
start executing the firmware at once".
Note that when calculating whether we are going to run guest
code at EL3, we ignore the setting of arm_boot_info::secure_board_setup,
which might cause us to run a stub bit of guest code at EL3 which
does some board-specific setup before dropping to EL2 or EL1 to
run the guest kernel. This is OK because only one board that
enables PSCI sets secure_board_setup (the highbank board), and
the stub code it writes will behave the same way whether the
one SMC call it makes is handled by "emulate the SMC" or by
"PSCI default returns an error code". So we can leave that stub
code in place until after we've changed the PSCI default behaviour;
at that point we will remove it.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Tested-by: Cédric Le Goater <clg@kaod.org>
Message-id: 20220127154639.2090164-4-peter.maydell@linaro.org
2022-01-27 18:46:26 +03:00
|
|
|
/*
|
|
|
|
* If a board wants to use the QEMU emulated-firmware PSCI support,
|
|
|
|
* it should set this to QEMU_PSCI_CONDUIT_HVC or QEMU_PSCI_CONDUIT_SMC
|
|
|
|
* as appropriate. arm_load_kernel() will set the psci-conduit and
|
|
|
|
* start-powered-off properties on the CPUs accordingly.
|
|
|
|
* Note that if the guest image is started at the same exception level
|
|
|
|
* as the conduit specifies calls should go to (eg guest firmware booted
|
|
|
|
* to EL3) then PSCI will not be enabled.
|
|
|
|
*/
|
|
|
|
int psci_conduit;
|
2009-11-11 21:07:53 +03:00
|
|
|
/* Used internally by arm_boot.c */
|
|
|
|
int is_linux;
|
2012-10-26 19:29:38 +04:00
|
|
|
hwaddr initrd_start;
|
2012-10-23 14:30:10 +04:00
|
|
|
hwaddr initrd_size;
|
|
|
|
hwaddr entry;
|
hw/arm: pass pristine kernel image to guest firmware over fw_cfg
Introduce the new boolean field "arm_boot_info.firmware_loaded". When this
field is set, it means that the portion of guest DRAM that the VCPU
normally starts to execute, or the pflash chip that the VCPU normally
starts to execute, has been populated by board-specific code with
full-fledged guest firmware code, before the board calls
arm_load_kernel().
Simultaneously, "arm_boot_info.firmware_loaded" guarantees that the board
code has set up the global firmware config instance, for arm_load_kernel()
to find with fw_cfg_find().
Guest kernel (-kernel) and guest firmware (-bios, -pflash) has always been
possible to specify independently on the command line. The following cases
should be considered:
nr -bios -pflash -kernel description
unit#0
-- ------- ------- ------- -------------------------------------------
1 present present absent Board code rejects this case, -bios and
present present present -pflash unit#0 are exclusive. Left intact
by this patch.
2 absent absent present Traditional kernel loading, with qemu's
minimal board firmware. Left intact by this
patch.
3 absent present absent Preexistent case for booting guest firmware
present absent absent loaded with -bios or -pflash. Left intact
by this patch.
4 absent absent absent Preexistent case for not loading any
firmware or kernel up-front. Left intact by
this patch.
5 present absent present New case introduced by this patch: kernel
absent present present image is passed to externally loaded
firmware in unmodified form, using fw_cfg.
An easy way to see that this patch doesn't interfere with existing cases
is to realize that "info->firmware_loaded" is constant zero at this point.
Which makes the "outer" condition unchanged, and the "inner" condition
(with the fw_cfg-related code) dead.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-id: 1419250305-31062-11-git-send-email-pbonzini@redhat.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2014-12-22 15:11:44 +03:00
|
|
|
|
|
|
|
/* Boot firmware has been loaded, typically at address 0, with -bios or
|
|
|
|
* -pflash. It also implies that fw_cfg_find() will succeed.
|
|
|
|
*/
|
|
|
|
bool firmware_loaded;
|
2015-11-03 16:49:41 +03:00
|
|
|
|
|
|
|
/* Address at which board specific loader/setup code exists. If enabled,
|
|
|
|
* this code-blob will run before anything else. It must return to the
|
|
|
|
* caller via the link register. There is no stack set up. Enabled by
|
|
|
|
* defining write_board_setup, which is responsible for loading the blob
|
|
|
|
* to the specified address.
|
|
|
|
*/
|
|
|
|
hwaddr board_setup_addr;
|
|
|
|
void (*write_board_setup)(ARMCPU *cpu,
|
|
|
|
const struct arm_boot_info *info);
|
2015-11-10 16:37:33 +03:00
|
|
|
|
2019-11-11 16:44:16 +03:00
|
|
|
/*
|
|
|
|
* If set, the board specific loader/setup blob will be run from secure
|
2015-11-10 16:37:33 +03:00
|
|
|
* mode, regardless of secure_boot. The blob becomes responsible for
|
2019-11-11 16:44:16 +03:00
|
|
|
* changing to non-secure state if implementing a non-secure boot,
|
|
|
|
* including setting up EL3/Secure registers such as the NSACR as
|
|
|
|
* required by the Linux booting ABI before the switch to non-secure.
|
2015-11-10 16:37:33 +03:00
|
|
|
*/
|
|
|
|
bool secure_board_setup;
|
2016-03-04 14:30:21 +03:00
|
|
|
|
|
|
|
arm_endianness endianness;
|
2008-04-15 00:27:51 +04:00
|
|
|
};
|
2015-06-02 14:29:12 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* arm_load_kernel - Loads memory with everything needed to boot
|
|
|
|
*
|
|
|
|
* @cpu: handle to the first CPU object
|
|
|
|
* @info: handle to the boot info struct
|
|
|
|
* Registers a machine init done notifier that copies to memory
|
|
|
|
* everything needed to boot, depending on machine and user options:
|
|
|
|
* kernel image, boot loaders, initrd, dtb. Also registers the CPU
|
|
|
|
* reset handler.
|
|
|
|
*
|
|
|
|
* In case the machine file supports the platform bus device and its
|
|
|
|
* dynamically instantiable sysbus devices, this function must be called
|
|
|
|
* before sysbus-fdt arm_register_platform_bus_fdt_creator. Indeed the
|
|
|
|
* machine init done notifiers are called in registration reverse order.
|
|
|
|
*/
|
2019-08-09 09:57:21 +03:00
|
|
|
void arm_load_kernel(ARMCPU *cpu, MachineState *ms, struct arm_boot_info *info);
|
2007-11-17 20:14:51 +03:00
|
|
|
|
2018-05-10 20:10:56 +03:00
|
|
|
AddressSpace *arm_boot_address_space(ARMCPU *cpu,
|
|
|
|
const struct arm_boot_info *info);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* arm_load_dtb() - load a device tree binary image into memory
|
|
|
|
* @addr: the address to load the image at
|
|
|
|
* @binfo: struct describing the boot environment
|
|
|
|
* @addr_limit: upper limit of the available memory area at @addr
|
|
|
|
* @as: address space to load image to
|
|
|
|
*
|
|
|
|
* Load a device tree supplied by the machine or by the user with the
|
|
|
|
* '-dtb' command line option, and put it at offset @addr in target
|
|
|
|
* memory.
|
|
|
|
*
|
|
|
|
* If @addr_limit contains a meaningful value (i.e., it is strictly greater
|
|
|
|
* than @addr), the device tree is only loaded if its size does not exceed
|
|
|
|
* the limit.
|
|
|
|
*
|
|
|
|
* Returns: the size of the device tree image on success,
|
|
|
|
* 0 if the image size exceeds the limit,
|
|
|
|
* -1 on errors.
|
|
|
|
*
|
|
|
|
* Note: Must not be called unless have_dtb(binfo) is true.
|
|
|
|
*/
|
|
|
|
int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
|
2019-08-09 09:57:21 +03:00
|
|
|
hwaddr addr_limit, AddressSpace *as, MachineState *ms);
|
2018-05-10 20:10:56 +03:00
|
|
|
|
2016-01-30 01:50:43 +03:00
|
|
|
/* Write a secure board setup routine with a dummy handler for SMCs */
|
|
|
|
void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
|
|
|
|
const struct arm_boot_info *info,
|
|
|
|
hwaddr mvbar_addr);
|
|
|
|
|
2019-05-23 16:47:43 +03:00
|
|
|
#endif /* HW_ARM_BOOT_H */
|