mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
Merge branch 'arm-next' into staging
This commit is contained in:
commit
65a2c12576
38 files changed
+785
-428
No files matched your search
@@ -1758,6 +1758,24 @@ enforces the maximum theoretically necessary timeout of 670ms. Any number
|
||||
is being interpreted as a custom timeout in milliseconds. Zero or boolean
|
||||
false disable the quirk workaround, which is also the default.
|
||||
|
||||
### spec-ctrl (Arm)
|
||||
> `= List of [ ssbd=force-disable|runtime|force-enable ]`
|
||||
|
||||
Controls for speculative execution sidechannel mitigations.
|
||||
|
||||
The option `ssbd=` is used to control the state of Speculative Store
|
||||
Bypass Disable (SSBD) mitigation.
|
||||
|
||||
* `ssbd=force-disable` will keep the mitigation permanently off. The guest
|
||||
will not be able to control the state of the mitigation.
|
||||
* `ssbd=runtime` will always turn on the mitigation when running in the
|
||||
hypervisor context. The guest will be to turn on/off the mitigation for
|
||||
itself by using the firmware interface ARCH\_WORKAROUND\_2.
|
||||
* `ssbd=force-enable` will keep the mitigation permanently on. The guest will
|
||||
not be able to control the state of the mitigation.
|
||||
|
||||
By default SSBD will be mitigated at runtime (i.e `ssbd=runtime`).
|
||||
|
||||
### spec-ctrl (x86)
|
||||
> `= List of [ <bool>, xen=<bool>, {pv,hvm,msr-sc,rsb}=<bool>,
|
||||
> bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,eager-fpu}=<bool> ]`
|
||||
|
||||
+27
-19
@@ -17,12 +17,10 @@ config ARM_64
|
||||
config ARM
|
||||
def_bool y
|
||||
select HAS_ALTERNATIVE
|
||||
select HAS_ARM_HDLCD
|
||||
select HAS_DEVICE_TREE
|
||||
select HAS_MEM_ACCESS
|
||||
select HAS_PASSTHROUGH
|
||||
select HAS_PDX
|
||||
select VIDEO
|
||||
|
||||
config ARCH_DEFCONFIG
|
||||
string
|
||||
@@ -73,6 +71,33 @@ config SBSA_VUART_CONSOLE
|
||||
Allows a guest to use SBSA Generic UART as a console. The
|
||||
SBSA Generic UART implements a subset of ARM PL011 UART.
|
||||
|
||||
config ARM_SSBD
|
||||
bool "Speculative Store Bypass Disable" if EXPERT = "y"
|
||||
depends on HAS_ALTERNATIVE
|
||||
default y
|
||||
help
|
||||
This enables mitigation of bypassing of previous stores by speculative
|
||||
loads.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config HARDEN_BRANCH_PREDICTOR
|
||||
bool "Harden the branch predictor against aliasing attacks" if EXPERT = "y"
|
||||
default y
|
||||
help
|
||||
Speculation attacks against some high-performance processors rely on
|
||||
being able to manipulate the branch predictor for a victim context by
|
||||
executing aliasing branches in the attacker context. Such attacks
|
||||
can be partially mitigated against by clearing internal branch
|
||||
predictor state and limiting the prediction logic in some situations.
|
||||
|
||||
This config option will take CPU-specific actions to harden the
|
||||
branch predictor against aliasing attacks and may rely on specific
|
||||
instruction sequences or control bits being set by the system
|
||||
firmware.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "ARM errata workaround via the alternative framework"
|
||||
@@ -187,23 +212,6 @@ config ARM64_ERRATUM_834220
|
||||
|
||||
endmenu
|
||||
|
||||
config HARDEN_BRANCH_PREDICTOR
|
||||
bool "Harden the branch predictor against aliasing attacks" if EXPERT
|
||||
default y
|
||||
help
|
||||
Speculation attacks against some high-performance processors rely on
|
||||
being able to manipulate the branch predictor for a victim context by
|
||||
executing aliasing branches in the attacker context. Such attacks
|
||||
can be partially mitigated against by clearing internal branch
|
||||
predictor state and limiting the prediction logic in some situations.
|
||||
|
||||
This config option will take CPU-specific actions to harden the
|
||||
branch predictor against aliasing attacks and may rely on specific
|
||||
instruction sequences or control bits being set by the system
|
||||
firmware.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config ARM64_HARDEN_BRANCH_PREDICTOR
|
||||
def_bool y if ARM_64 && HARDEN_BRANCH_PREDICTOR
|
||||
|
||||
|
||||
+47
-39
@@ -30,6 +30,8 @@
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/insn.h>
|
||||
/* XXX: Move ARCH_PATCH_INSN_SIZE out of livepatch.h */
|
||||
#include <asm/livepatch.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
/* Override macros from asm/page.h to make them work with mfn_t */
|
||||
@@ -94,39 +96,66 @@ static u32 get_alt_insn(const struct alt_instr *alt,
|
||||
return insn;
|
||||
}
|
||||
|
||||
static void patch_alternative(const struct alt_instr *alt,
|
||||
const uint32_t *origptr,
|
||||
uint32_t *updptr, int nr_inst)
|
||||
{
|
||||
const uint32_t *replptr;
|
||||
unsigned int i;
|
||||
|
||||
replptr = ALT_REPL_PTR(alt);
|
||||
for ( i = 0; i < nr_inst; i++ )
|
||||
{
|
||||
uint32_t insn;
|
||||
|
||||
insn = get_alt_insn(alt, origptr + i, replptr + i);
|
||||
updptr[i] = cpu_to_le32(insn);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The region patched should be read-write to allow __apply_alternatives
|
||||
* to replacing the instructions when necessary.
|
||||
*
|
||||
* @update_offset: Offset between the region patched and the writable
|
||||
* region for the update. 0 if the patched region is writable.
|
||||
*/
|
||||
static int __apply_alternatives(const struct alt_region *region)
|
||||
static int __apply_alternatives(const struct alt_region *region,
|
||||
paddr_t update_offset)
|
||||
{
|
||||
const struct alt_instr *alt;
|
||||
const u32 *replptr;
|
||||
u32 *origptr;
|
||||
const u32 *origptr;
|
||||
u32 *updptr;
|
||||
alternative_cb_t alt_cb;
|
||||
|
||||
printk(XENLOG_INFO "alternatives: Patching with alt table %p -> %p\n",
|
||||
region->begin, region->end);
|
||||
|
||||
for ( alt = region->begin; alt < region->end; alt++ )
|
||||
{
|
||||
u32 insn;
|
||||
int i, nr_inst;
|
||||
int nr_inst;
|
||||
|
||||
if ( !cpus_have_cap(alt->cpufeature) )
|
||||
/* Use ARM_CB_PATCH as an unconditional patch */
|
||||
if ( alt->cpufeature < ARM_CB_PATCH &&
|
||||
!cpus_have_cap(alt->cpufeature) )
|
||||
continue;
|
||||
|
||||
BUG_ON(alt->alt_len != alt->orig_len);
|
||||
if ( alt->cpufeature == ARM_CB_PATCH )
|
||||
BUG_ON(alt->alt_len != 0);
|
||||
else
|
||||
BUG_ON(alt->alt_len != alt->orig_len);
|
||||
|
||||
origptr = ALT_ORIG_PTR(alt);
|
||||
replptr = ALT_REPL_PTR(alt);
|
||||
updptr = (void *)origptr + update_offset;
|
||||
|
||||
nr_inst = alt->alt_len / sizeof(insn);
|
||||
nr_inst = alt->orig_len / ARCH_PATCH_INSN_SIZE;
|
||||
|
||||
for ( i = 0; i < nr_inst; i++ )
|
||||
{
|
||||
insn = get_alt_insn(alt, origptr + i, replptr + i);
|
||||
*(origptr + i) = cpu_to_le32(insn);
|
||||
}
|
||||
if ( alt->cpufeature < ARM_CB_PATCH )
|
||||
alt_cb = patch_alternative;
|
||||
else
|
||||
alt_cb = ALT_REPL_PTR(alt);
|
||||
|
||||
alt_cb(alt, origptr, updptr, nr_inst);
|
||||
|
||||
/* Ensure the new instructions reached the memory and nuke */
|
||||
clean_and_invalidate_dcache_va_range(origptr,
|
||||
@@ -162,9 +191,6 @@ static int __apply_alternatives_multi_stop(void *unused)
|
||||
paddr_t xen_size = _end - _start;
|
||||
unsigned int xen_order = get_order_from_bytes(xen_size);
|
||||
void *xenmap;
|
||||
struct virtual_region patch_region = {
|
||||
.list = LIST_HEAD_INIT(patch_region.list),
|
||||
};
|
||||
|
||||
BUG_ON(patched);
|
||||
|
||||
@@ -177,31 +203,13 @@ static int __apply_alternatives_multi_stop(void *unused)
|
||||
/* Re-mapping Xen is not expected to fail during boot. */
|
||||
BUG_ON(!xenmap);
|
||||
|
||||
/*
|
||||
* If we generate a new branch instruction, the target will be
|
||||
* calculated in this re-mapped Xen region. So we have to register
|
||||
* this re-mapped Xen region as a virtual region temporarily.
|
||||
*/
|
||||
patch_region.start = xenmap;
|
||||
patch_region.end = xenmap + xen_size;
|
||||
register_virtual_region(&patch_region);
|
||||
region.begin = __alt_instructions;
|
||||
region.end = __alt_instructions_end;
|
||||
|
||||
/*
|
||||
* Find the virtual address of the alternative region in the new
|
||||
* mapping.
|
||||
* alt_instr contains relative offset, so the function
|
||||
* __apply_alternatives will patch in the re-mapped version of
|
||||
* Xen.
|
||||
*/
|
||||
region.begin = (void *)__alt_instructions - (void *)_start + xenmap;
|
||||
region.end = (void *)__alt_instructions_end - (void *)_start + xenmap;
|
||||
|
||||
ret = __apply_alternatives(®ion);
|
||||
ret = __apply_alternatives(®ion, xenmap - (void *)_start);
|
||||
/* The patching is not expected to fail during boot. */
|
||||
BUG_ON(ret != 0);
|
||||
|
||||
unregister_virtual_region(&patch_region);
|
||||
|
||||
vunmap(xenmap);
|
||||
|
||||
/* Barriers provided by the cache flushing */
|
||||
@@ -235,7 +243,7 @@ int apply_alternatives(const struct alt_instr *start, const struct alt_instr *en
|
||||
.end = end,
|
||||
};
|
||||
|
||||
return __apply_alternatives(®ion);
|
||||
return __apply_alternatives(®ion, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
void __dummy__(void)
|
||||
{
|
||||
OFFSET(UREGS_X0, struct cpu_user_regs, x0);
|
||||
OFFSET(UREGS_X1, struct cpu_user_regs, x1);
|
||||
OFFSET(UREGS_LR, struct cpu_user_regs, lr);
|
||||
|
||||
OFFSET(UREGS_SP, struct cpu_user_regs, sp);
|
||||
@@ -45,6 +46,7 @@ void __dummy__(void)
|
||||
BLANK();
|
||||
|
||||
DEFINE(CPUINFO_sizeof, sizeof(struct cpu_info));
|
||||
OFFSET(CPUINFO_flags, struct cpu_info, flags);
|
||||
|
||||
OFFSET(VCPU_arch_saved_context, struct vcpu, arch.saved_context);
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <asm/asm_defns.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/macros.h>
|
||||
#include <asm/regs.h>
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/smccc.h>
|
||||
@@ -226,11 +228,11 @@ guest_sync:
|
||||
mrs x1, esr_el2
|
||||
lsr x1, x1, #HSR_EC_SHIFT /* x1 = ESR_EL2.EC */
|
||||
cmp x1, #HSR_EC_HVC64
|
||||
b.ne 1f /* Not a HVC skip fastpath. */
|
||||
b.ne guest_sync_slowpath /* Not a HVC skip fastpath. */
|
||||
|
||||
mrs x1, esr_el2
|
||||
and x1, x1, #0xffff /* Check the immediate [0:16] */
|
||||
cbnz x1, 1f /* should be 0 for HVC #0 */
|
||||
cbnz x1, guest_sync_slowpath /* should be 0 for HVC #0 */
|
||||
|
||||
/*
|
||||
* Fastest path possible for ARM_SMCCC_ARCH_WORKAROUND_1.
|
||||
@@ -241,7 +243,7 @@ guest_sync:
|
||||
* be encoded as an immediate for cmp.
|
||||
*/
|
||||
eor w0, w0, #ARM_SMCCC_ARCH_WORKAROUND_1_FID
|
||||
cbnz w0, 1f
|
||||
cbnz w0, check_wa2
|
||||
|
||||
/*
|
||||
* Clobber both x0 and x1 to prevent leakage. Note that thanks
|
||||
@@ -250,7 +252,45 @@ guest_sync:
|
||||
mov x1, xzr
|
||||
eret
|
||||
|
||||
1:
|
||||
check_wa2:
|
||||
/* ARM_SMCCC_ARCH_WORKAROUND_2 handling */
|
||||
eor w0, w0, #(ARM_SMCCC_ARCH_WORKAROUND_1_FID ^ ARM_SMCCC_ARCH_WORKAROUND_2_FID)
|
||||
cbnz w0, guest_sync_slowpath
|
||||
#ifdef CONFIG_ARM_SSBD
|
||||
alternative_cb arm_enable_wa2_handling
|
||||
b wa2_end
|
||||
alternative_cb_end
|
||||
/* Sanitize the argument */
|
||||
mov x0, #-(UREGS_kernel_sizeof - UREGS_X1) /* x0 := offset of guest's x1 on the stack */
|
||||
ldr x1, [sp, x0] /* Load guest's x1 */
|
||||
cmp w1, wzr
|
||||
cset x1, ne
|
||||
|
||||
/*
|
||||
* Update the guest flag. At this stage sp point after the field
|
||||
* guest_cpu_user_regs in cpu_info.
|
||||
*/
|
||||
adr_cpu_info x2
|
||||
ldr x0, [x2, #CPUINFO_flags]
|
||||
bfi x0, x1, #CPUINFO_WORKAROUND_2_FLAG_SHIFT, #1
|
||||
str x0, [x2, #CPUINFO_flags]
|
||||
|
||||
/* Check that we actually need to perform the call */
|
||||
ldr_this_cpu x0, ssbd_callback_required, x2
|
||||
cbz x0, wa2_end
|
||||
|
||||
mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2_FID
|
||||
smc #0
|
||||
|
||||
wa2_end:
|
||||
/* Don't leak data from the SMC call */
|
||||
mov x1, xzr
|
||||
mov x2, xzr
|
||||
mov x3, xzr
|
||||
#endif /* !CONFIG_ARM_SSBD */
|
||||
mov x0, xzr
|
||||
eret
|
||||
guest_sync_slowpath:
|
||||
/*
|
||||
* x0/x1 may have been scratch by the fast path above, so avoid
|
||||
* to save them.
|
||||
|
||||
@@ -104,7 +104,7 @@ int __init arch_cpu_init(int cpu, struct dt_device_node *dn)
|
||||
return smp_psci_init(cpu);
|
||||
}
|
||||
|
||||
int __init arch_cpu_up(int cpu)
|
||||
int arch_cpu_up(int cpu)
|
||||
{
|
||||
if ( !smp_enable_ops[cpu].prepare_cpu )
|
||||
return -ENODEV;
|
||||
|
||||
@@ -57,13 +57,15 @@ void do_sysreg(struct cpu_user_regs *regs,
|
||||
* ARMv8 (DDI 0487A.d): D1-1509 Table D1-58
|
||||
*
|
||||
* Unhandled:
|
||||
* OSLSR_EL1
|
||||
* DBGPRCR_EL1
|
||||
*/
|
||||
case HSR_SYSREG_OSLAR_EL1:
|
||||
return handle_wo_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
|
||||
case HSR_SYSREG_OSDLR_EL1:
|
||||
return handle_raz_wi(regs, regidx, hsr.sysreg.read, hsr, 1);
|
||||
case HSR_SYSREG_OSLSR_EL1:
|
||||
return handle_ro_read_val(regs, regidx, hsr.sysreg.read, hsr, 1,
|
||||
1 << 3);
|
||||
|
||||
/*
|
||||
* MDCR_EL2.TDA
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <xen/cpu.h>
|
||||
#include <xen/cpumask.h>
|
||||
#include <xen/mm.h>
|
||||
#include <xen/sizes.h>
|
||||
@@ -5,8 +6,10 @@
|
||||
#include <xen/spinlock.h>
|
||||
#include <xen/vmap.h>
|
||||
#include <xen/warning.h>
|
||||
#include <xen/notifier.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/cpuerrata.h>
|
||||
#include <asm/insn.h>
|
||||
#include <asm/psci.h>
|
||||
|
||||
/* Override macros from asm/page.h to make them work with mfn_t */
|
||||
@@ -235,6 +238,148 @@ static int enable_ic_inv_hardening(void *data)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ARM_SSBD
|
||||
|
||||
enum ssbd_state ssbd_state = ARM_SSBD_RUNTIME;
|
||||
|
||||
static int __init parse_spec_ctrl(const char *s)
|
||||
{
|
||||
const char *ss;
|
||||
int rc = 0;
|
||||
|
||||
do {
|
||||
ss = strchr(s, ',');
|
||||
if ( !ss )
|
||||
ss = strchr(s, '\0');
|
||||
|
||||
if ( !strncmp(s, "ssbd=", 5) )
|
||||
{
|
||||
s += 5;
|
||||
|
||||
if ( !strncmp(s, "force-disable", ss - s) )
|
||||
ssbd_state = ARM_SSBD_FORCE_DISABLE;
|
||||
else if ( !strncmp(s, "runtime", ss - s) )
|
||||
ssbd_state = ARM_SSBD_RUNTIME;
|
||||
else if ( !strncmp(s, "force-enable", ss - s) )
|
||||
ssbd_state = ARM_SSBD_FORCE_ENABLE;
|
||||
else
|
||||
rc = -EINVAL;
|
||||
}
|
||||
else
|
||||
rc = -EINVAL;
|
||||
|
||||
s = ss + 1;
|
||||
} while ( *ss );
|
||||
|
||||
return rc;
|
||||
}
|
||||
custom_param("spec-ctrl", parse_spec_ctrl);
|
||||
|
||||
/* Arm64 only for now as for Arm32 the workaround is currently handled in C. */
|
||||
#ifdef CONFIG_ARM_64
|
||||
void __init arm_enable_wa2_handling(const struct alt_instr *alt,
|
||||
const uint32_t *origptr,
|
||||
uint32_t *updptr, int nr_inst)
|
||||
{
|
||||
BUG_ON(nr_inst != 1);
|
||||
|
||||
/*
|
||||
* Only allow mitigation on guest ARCH_WORKAROUND_2 if the SSBD
|
||||
* state allow it to be flipped.
|
||||
*/
|
||||
if ( get_ssbd_state() == ARM_SSBD_RUNTIME )
|
||||
*updptr = aarch64_insn_gen_nop();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Assembly code may use the variable directly, so we need to make sure
|
||||
* it fits in a register.
|
||||
*/
|
||||
DEFINE_PER_CPU_READ_MOSTLY(register_t, ssbd_callback_required);
|
||||
|
||||
static bool has_ssbd_mitigation(const struct arm_cpu_capabilities *entry)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
bool required;
|
||||
|
||||
if ( smccc_ver < SMCCC_VERSION(1, 1) )
|
||||
return false;
|
||||
|
||||
arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FID,
|
||||
ARM_SMCCC_ARCH_WORKAROUND_2_FID, &res);
|
||||
|
||||
switch ( (int)res.a0 )
|
||||
{
|
||||
case ARM_SMCCC_NOT_SUPPORTED:
|
||||
ssbd_state = ARM_SSBD_UNKNOWN;
|
||||
return false;
|
||||
|
||||
case ARM_SMCCC_NOT_REQUIRED:
|
||||
ssbd_state = ARM_SSBD_MITIGATED;
|
||||
return false;
|
||||
|
||||
case ARM_SMCCC_SUCCESS:
|
||||
required = true;
|
||||
break;
|
||||
|
||||
case 1: /* Mitigation not required on this CPU. */
|
||||
required = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ( ssbd_state )
|
||||
{
|
||||
case ARM_SSBD_FORCE_DISABLE:
|
||||
{
|
||||
static bool once = true;
|
||||
|
||||
if ( once )
|
||||
printk("%s disabled from command-line\n", entry->desc);
|
||||
once = false;
|
||||
|
||||
arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2_FID, 0, NULL);
|
||||
required = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ARM_SSBD_RUNTIME:
|
||||
if ( required )
|
||||
{
|
||||
this_cpu(ssbd_callback_required) = 1;
|
||||
arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2_FID, 1, NULL);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ARM_SSBD_FORCE_ENABLE:
|
||||
{
|
||||
static bool once = true;
|
||||
|
||||
if ( once )
|
||||
printk("%s forced from command-line\n", entry->desc);
|
||||
once = false;
|
||||
|
||||
arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2_FID, 1, NULL);
|
||||
required = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ASSERT_UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
return required;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MIDR_RANGE(model, min, max) \
|
||||
.matches = is_affected_midr_range, \
|
||||
.midr_model = model, \
|
||||
@@ -335,6 +480,13 @@ static const struct arm_cpu_capabilities arm_errata[] = {
|
||||
MIDR_ALL_VERSIONS(MIDR_CORTEX_A15),
|
||||
.enable = enable_ic_inv_hardening,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_ARM_SSBD
|
||||
{
|
||||
.desc = "Speculative Store Bypass Disabled",
|
||||
.capability = ARM_SSBD,
|
||||
.matches = has_ssbd_mitigation,
|
||||
},
|
||||
#endif
|
||||
{},
|
||||
};
|
||||
@@ -349,6 +501,53 @@ void __init enable_errata_workarounds(void)
|
||||
enable_cpu_capabilities(arm_errata);
|
||||
}
|
||||
|
||||
static int cpu_errata_callback(struct notifier_block *nfb,
|
||||
unsigned long action,
|
||||
void *hcpu)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
switch ( action )
|
||||
{
|
||||
case CPU_STARTING:
|
||||
/*
|
||||
* At CPU_STARTING phase no notifier shall return an error, because the
|
||||
* system is designed with the assumption that starting a CPU cannot
|
||||
* fail at this point. If an error happens here it will cause Xen to hit
|
||||
* the BUG_ON() in notify_cpu_starting(). In future, either this
|
||||
* notifier/enabling capabilities should be fixed to always return
|
||||
* success/void or notify_cpu_starting() and other common code should be
|
||||
* fixed to expect an error at CPU_STARTING phase.
|
||||
*/
|
||||
ASSERT(system_state != SYS_STATE_boot);
|
||||
rc = enable_nonboot_cpu_caps(arm_errata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return !rc ? NOTIFY_DONE : notifier_from_errno(rc);
|
||||
}
|
||||
|
||||
static struct notifier_block cpu_errata_nfb = {
|
||||
.notifier_call = cpu_errata_callback,
|
||||
};
|
||||
|
||||
static int __init cpu_errata_notifier_init(void)
|
||||
{
|
||||
register_cpu_notifier(&cpu_errata_nfb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Initialization has to be done at init rather than presmp_init phase because
|
||||
* the callback should execute only after the secondary CPUs are initially
|
||||
* booted (in hotplug scenarios when the system state is not boot). On boot,
|
||||
* the enabling of errata workarounds will be triggered by the boot CPU from
|
||||
* start_xen().
|
||||
*/
|
||||
__initcall(cpu_errata_notifier_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
||||
@@ -68,6 +68,35 @@ void __init enable_cpu_capabilities(const struct arm_cpu_capabilities *caps)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Run through the enabled capabilities and enable() them on the calling CPU.
|
||||
* If enabling of any capability fails the error is returned. After enabling a
|
||||
* capability fails the error will be remembered into 'rc' and the remaining
|
||||
* capabilities will be enabled. If enabling multiple capabilities fail the
|
||||
* error returned by this function represents the error code of the last
|
||||
* failure.
|
||||
*/
|
||||
int enable_nonboot_cpu_caps(const struct arm_cpu_capabilities *caps)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
for ( ; caps->matches; caps++ )
|
||||
{
|
||||
if ( !cpus_have_cap(caps->capability) )
|
||||
continue;
|
||||
|
||||
if ( caps->enable )
|
||||
{
|
||||
int ret = caps->enable((void *)caps);
|
||||
|
||||
if ( ret )
|
||||
rc = ret;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <xen/wait.h>
|
||||
|
||||
#include <asm/alternative.h>
|
||||
#include <asm/cpuerrata.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/event.h>
|
||||
@@ -550,6 +551,7 @@ int vcpu_initialise(struct vcpu *v)
|
||||
v->arch.cpu_info = (struct cpu_info *)(v->arch.stack
|
||||
+ STACK_SIZE
|
||||
- sizeof(struct cpu_info));
|
||||
memset(v->arch.cpu_info, 0, sizeof(*v->arch.cpu_info));
|
||||
|
||||
memset(&v->arch.saved_context, 0, sizeof(v->arch.saved_context));
|
||||
v->arch.saved_context.sp = (register_t)v->arch.cpu_info;
|
||||
@@ -571,6 +573,13 @@ int vcpu_initialise(struct vcpu *v)
|
||||
if ( (rc = vcpu_vtimer_init(v)) != 0 )
|
||||
goto fail;
|
||||
|
||||
/*
|
||||
* The workaround 2 (i.e SSBD mitigation) is enabled by default if
|
||||
* supported.
|
||||
*/
|
||||
if ( get_ssbd_state() == ARM_SSBD_RUNTIME )
|
||||
v->arch.cpu_info->flags |= CPUINFO_WORKAROUND_2_FLAG;
|
||||
|
||||
return rc;
|
||||
|
||||
fail:
|
||||
|
||||
@@ -362,7 +362,7 @@ int vgic_vcpu_pending_irq(struct vcpu *v)
|
||||
ASSERT(v == current);
|
||||
|
||||
mask_priority = gic_hw_ops->read_vmcr_priority();
|
||||
active_priority = find_next_bit(&apr, 32, 0);
|
||||
active_priority = find_first_bit(&apr, 32);
|
||||
|
||||
spin_lock_irqsave(&v->arch.vgic.lock, flags);
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <xen/list.h>
|
||||
#include <xen/device_tree.h>
|
||||
#include <xen/acpi.h>
|
||||
#include <xen/cpu.h>
|
||||
#include <xen/notifier.h>
|
||||
#include <asm/p2m.h>
|
||||
#include <asm/domain.h>
|
||||
#include <asm/platform.h>
|
||||
@@ -462,6 +464,35 @@ int gic_iomem_deny_access(const struct domain *d)
|
||||
return gic_hw_ops->iomem_deny_access(d);
|
||||
}
|
||||
|
||||
static int cpu_gic_callback(struct notifier_block *nfb,
|
||||
unsigned long action,
|
||||
void *hcpu)
|
||||
{
|
||||
switch ( action )
|
||||
{
|
||||
case CPU_DYING:
|
||||
/* This is reverting the work done in init_maintenance_interrupt */
|
||||
release_irq(gic_hw_ops->info->maintenance_irq, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block cpu_gic_nfb = {
|
||||
.notifier_call = cpu_gic_callback,
|
||||
};
|
||||
|
||||
static int __init cpu_gic_notifier_init(void)
|
||||
{
|
||||
register_cpu_notifier(&cpu_gic_nfb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
__initcall(cpu_gic_notifier_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ irq_desc_t *__irq_to_desc(int irq)
|
||||
return &irq_desc[irq-NR_LOCAL_IRQS];
|
||||
}
|
||||
|
||||
int __init arch_init_one_irq_desc(struct irq_desc *desc)
|
||||
int arch_init_one_irq_desc(struct irq_desc *desc)
|
||||
{
|
||||
desc->arch.type = IRQ_TYPE_INVALID;
|
||||
return 0;
|
||||
|
||||
+48
-5
@@ -8,6 +8,8 @@
|
||||
#include <xen/iocap.h>
|
||||
#include <xen/mem_access.h>
|
||||
#include <xen/xmalloc.h>
|
||||
#include <xen/cpu.h>
|
||||
#include <xen/notifier.h>
|
||||
#include <public/vm_event.h>
|
||||
#include <asm/flushtlb.h>
|
||||
#include <asm/event.h>
|
||||
@@ -1451,10 +1453,12 @@ err:
|
||||
return page;
|
||||
}
|
||||
|
||||
static void __init setup_virt_paging_one(void *data)
|
||||
/* VTCR value to be configured by all CPUs. Set only once by the boot CPU */
|
||||
static uint32_t __read_mostly vtcr;
|
||||
|
||||
static void setup_virt_paging_one(void *data)
|
||||
{
|
||||
unsigned long val = (unsigned long)data;
|
||||
WRITE_SYSREG32(val, VTCR_EL2);
|
||||
WRITE_SYSREG32(vtcr, VTCR_EL2);
|
||||
isb();
|
||||
}
|
||||
|
||||
@@ -1538,10 +1542,49 @@ void __init setup_virt_paging(void)
|
||||
|
||||
/* It is not allowed to concatenate a level zero root */
|
||||
BUG_ON( P2M_ROOT_LEVEL == 0 && P2M_ROOT_ORDER > 0 );
|
||||
setup_virt_paging_one((void *)val);
|
||||
smp_call_function(setup_virt_paging_one, (void *)val, 1);
|
||||
vtcr = val;
|
||||
setup_virt_paging_one(NULL);
|
||||
smp_call_function(setup_virt_paging_one, NULL, 1);
|
||||
}
|
||||
|
||||
static int cpu_virt_paging_callback(struct notifier_block *nfb,
|
||||
unsigned long action,
|
||||
void *hcpu)
|
||||
{
|
||||
switch ( action )
|
||||
{
|
||||
case CPU_STARTING:
|
||||
ASSERT(system_state != SYS_STATE_boot);
|
||||
setup_virt_paging_one(NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block cpu_virt_paging_nfb = {
|
||||
.notifier_call = cpu_virt_paging_callback,
|
||||
};
|
||||
|
||||
static int __init cpu_virt_paging_init(void)
|
||||
{
|
||||
register_cpu_notifier(&cpu_virt_paging_nfb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Initialization of the notifier has to be done at init rather than presmp_init
|
||||
* phase because: the registered notifier is used to setup virtual paging for
|
||||
* non-boot CPUs after the initial virtual paging for all CPUs is already setup,
|
||||
* i.e. when a non-boot CPU is hotplugged after the system has booted. In other
|
||||
* words, the notifier should be registered after the virtual paging is
|
||||
* initially setup (setup_virt_paging() is called from start_xen()). This is
|
||||
* required because vtcr config value has to be set before a notifier can fire.
|
||||
*/
|
||||
__initcall(cpu_virt_paging_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
||||
@@ -59,41 +59,6 @@ static inline int vexpress_ctrl_start(uint32_t *syscfg, int write,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vexpress_syscfg(int write, int function, int device, uint32_t *data)
|
||||
{
|
||||
uint32_t *syscfg = (uint32_t *) FIXMAP_ADDR(FIXMAP_MISC);
|
||||
int ret = -1;
|
||||
|
||||
set_fixmap(FIXMAP_MISC, maddr_to_mfn(V2M_SYS_MMIO_BASE),
|
||||
PAGE_HYPERVISOR_NOCACHE);
|
||||
|
||||
if ( syscfg[V2M_SYS_CFGCTRL/4] & V2M_SYS_CFG_START )
|
||||
goto out;
|
||||
|
||||
/* clear the complete bit in the V2M_SYS_CFGSTAT status register */
|
||||
syscfg[V2M_SYS_CFGSTAT/4] = 0;
|
||||
|
||||
if ( write )
|
||||
{
|
||||
/* write data */
|
||||
syscfg[V2M_SYS_CFGDATA/4] = *data;
|
||||
|
||||
if ( vexpress_ctrl_start(syscfg, write, function, device) < 0 )
|
||||
goto out;
|
||||
} else {
|
||||
if ( vexpress_ctrl_start(syscfg, write, function, device) < 0 )
|
||||
goto out;
|
||||
else
|
||||
/* read data */
|
||||
*data = syscfg[V2M_SYS_CFGDATA/4];
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
clear_fixmap(FIXMAP_MISC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Get base address from the device tree
|
||||
* See arm,vexpress-reset node
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
static DEFINE_PER_CPU(struct processor *, processor);
|
||||
|
||||
void __init processor_setup(void)
|
||||
void processor_setup(void)
|
||||
{
|
||||
const struct proc_info_list *procinfo;
|
||||
|
||||
|
||||
@@ -46,6 +46,19 @@ int call_psci_cpu_on(int cpu)
|
||||
return call_smc(psci_cpu_on_nr, cpu_logical_map(cpu), __pa(init_secondary), 0);
|
||||
}
|
||||
|
||||
void call_psci_cpu_off(void)
|
||||
{
|
||||
if ( psci_ver > PSCI_VERSION(0, 1) )
|
||||
{
|
||||
int errno;
|
||||
|
||||
/* If successfull the PSCI cpu_off call doesn't return */
|
||||
errno = call_smc(PSCI_0_2_FN32_CPU_OFF, 0, 0, 0);
|
||||
panic("PSCI cpu off failed for CPU%d err=%d\n", smp_processor_id(),
|
||||
errno);
|
||||
}
|
||||
}
|
||||
|
||||
void call_psci_system_off(void)
|
||||
{
|
||||
if ( psci_ver > PSCI_VERSION(0, 1) )
|
||||
|
||||
@@ -171,8 +171,6 @@ static void __init processor_id(void)
|
||||
}
|
||||
|
||||
processor_setup();
|
||||
|
||||
check_local_cpu_errata();
|
||||
}
|
||||
|
||||
void dt_unreserved_regions(paddr_t s, paddr_t e,
|
||||
@@ -779,6 +777,12 @@ void __init start_xen(unsigned long boot_phys_offset,
|
||||
printk(XENLOG_INFO "SMP: Allowing %u CPUs\n", cpus);
|
||||
nr_cpu_ids = cpus;
|
||||
|
||||
/*
|
||||
* Some errata relies on SMCCC version which is detected by psci_init()
|
||||
* (called from smp_init_cpus()).
|
||||
*/
|
||||
check_local_cpu_errata();
|
||||
|
||||
init_xen_time();
|
||||
|
||||
gic_init();
|
||||
|
||||
+40
-2
@@ -52,8 +52,8 @@ nodemask_t __read_mostly node_online_map = { { [0] = 1UL } };
|
||||
static unsigned char __initdata cpu0_boot_stack[STACK_SIZE]
|
||||
__attribute__((__aligned__(STACK_SIZE)));
|
||||
|
||||
/* Initial boot cpu data */
|
||||
struct init_info __initdata init_data =
|
||||
/* Boot cpu data */
|
||||
struct init_info init_data =
|
||||
{
|
||||
.stack = cpu0_boot_stack,
|
||||
};
|
||||
@@ -89,6 +89,12 @@ static void setup_cpu_sibling_map(int cpu)
|
||||
cpumask_set_cpu(cpu, per_cpu(cpu_core_mask, cpu));
|
||||
}
|
||||
|
||||
static void remove_cpu_sibling_map(int cpu)
|
||||
{
|
||||
free_cpumask_var(per_cpu(cpu_sibling_mask, cpu));
|
||||
free_cpumask_var(per_cpu(cpu_core_mask, cpu));
|
||||
}
|
||||
|
||||
void __init
|
||||
smp_clear_cpu_maps (void)
|
||||
{
|
||||
@@ -395,6 +401,8 @@ void stop_cpu(void)
|
||||
/* Make sure the write happens before we sleep forever */
|
||||
dsb(sy);
|
||||
isb();
|
||||
call_psci_cpu_off();
|
||||
|
||||
while ( 1 )
|
||||
wfi();
|
||||
}
|
||||
@@ -497,6 +505,36 @@ void __cpu_die(unsigned int cpu)
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
static int cpu_smpboot_callback(struct notifier_block *nfb,
|
||||
unsigned long action,
|
||||
void *hcpu)
|
||||
{
|
||||
unsigned int cpu = (unsigned long)hcpu;
|
||||
|
||||
switch ( action )
|
||||
{
|
||||
case CPU_DEAD:
|
||||
remove_cpu_sibling_map(cpu);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block cpu_smpboot_nfb = {
|
||||
.notifier_call = cpu_smpboot_callback,
|
||||
};
|
||||
|
||||
static int __init cpu_smpboot_notifier_init(void)
|
||||
{
|
||||
register_cpu_notifier(&cpu_smpboot_nfb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
presmp_initcall(cpu_smpboot_notifier_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include <xen/sched.h>
|
||||
#include <xen/event.h>
|
||||
#include <xen/acpi.h>
|
||||
#include <xen/cpu.h>
|
||||
#include <xen/notifier.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/vgic.h>
|
||||
@@ -312,6 +314,21 @@ void init_timer_interrupt(void)
|
||||
check_timer_irq_cfg(timer_irq[TIMER_PHYS_NONSECURE_PPI], "NS-physical");
|
||||
}
|
||||
|
||||
/*
|
||||
* Revert actions done in init_timer_interrupt that are required to properly
|
||||
* disable this CPU.
|
||||
*/
|
||||
static void deinit_timer_interrupt(void)
|
||||
{
|
||||
WRITE_SYSREG32(0, CNTP_CTL_EL0); /* Disable physical timer */
|
||||
WRITE_SYSREG32(0, CNTHP_CTL_EL2); /* Disable hypervisor's timer */
|
||||
isb();
|
||||
|
||||
release_irq(timer_irq[TIMER_HYP_PPI], NULL);
|
||||
release_irq(timer_irq[TIMER_VIRT_PPI], NULL);
|
||||
release_irq(timer_irq[TIMER_PHYS_NONSECURE_PPI], NULL);
|
||||
}
|
||||
|
||||
/* Wait a set number of microseconds */
|
||||
void udelay(unsigned long usecs)
|
||||
{
|
||||
@@ -340,6 +357,34 @@ void domain_set_time_offset(struct domain *d, int64_t time_offset_seconds)
|
||||
/* XXX update guest visible wallclock time */
|
||||
}
|
||||
|
||||
static int cpu_time_callback(struct notifier_block *nfb,
|
||||
unsigned long action,
|
||||
void *hcpu)
|
||||
{
|
||||
switch ( action )
|
||||
{
|
||||
case CPU_DYING:
|
||||
deinit_timer_interrupt();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct notifier_block cpu_time_nfb = {
|
||||
.notifier_call = cpu_time_callback,
|
||||
};
|
||||
|
||||
static int __init cpu_time_notifier_init(void)
|
||||
{
|
||||
register_cpu_notifier(&cpu_time_nfb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
__initcall(cpu_time_notifier_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
|
||||
+45
-13
@@ -1739,12 +1739,13 @@ void handle_wo_wi(struct cpu_user_regs *regs,
|
||||
advance_pc(regs, hsr);
|
||||
}
|
||||
|
||||
/* Read only as read as zero */
|
||||
void handle_ro_raz(struct cpu_user_regs *regs,
|
||||
int regidx,
|
||||
bool read,
|
||||
const union hsr hsr,
|
||||
int min_el)
|
||||
/* Read only as value provided with 'val' argument of this function */
|
||||
void handle_ro_read_val(struct cpu_user_regs *regs,
|
||||
int regidx,
|
||||
bool read,
|
||||
const union hsr hsr,
|
||||
int min_el,
|
||||
register_t val)
|
||||
{
|
||||
ASSERT((min_el == 0) || (min_el == 1));
|
||||
|
||||
@@ -1753,13 +1754,22 @@ void handle_ro_raz(struct cpu_user_regs *regs,
|
||||
|
||||
if ( !read )
|
||||
return inject_undef_exception(regs, hsr);
|
||||
/* else: raz */
|
||||
|
||||
set_user_reg(regs, regidx, 0);
|
||||
set_user_reg(regs, regidx, val);
|
||||
|
||||
advance_pc(regs, hsr);
|
||||
}
|
||||
|
||||
/* Read only as read as zero */
|
||||
inline void handle_ro_raz(struct cpu_user_regs *regs,
|
||||
int regidx,
|
||||
bool read,
|
||||
const union hsr hsr,
|
||||
int min_el)
|
||||
{
|
||||
handle_ro_read_val(regs, regidx, read, hsr, min_el, 0);
|
||||
}
|
||||
|
||||
void dump_guest_s1_walk(struct domain *d, vaddr_t addr)
|
||||
{
|
||||
register_t ttbcr = READ_SYSREG(TCR_EL1);
|
||||
@@ -2011,18 +2021,33 @@ inject_abt:
|
||||
inject_iabt_exception(regs, gva, hsr.len);
|
||||
}
|
||||
|
||||
static inline bool needs_ssbd_flip(struct vcpu *v)
|
||||
{
|
||||
if ( !check_workaround_ssbd() )
|
||||
return false;
|
||||
|
||||
return !(v->arch.cpu_info->flags & CPUINFO_WORKAROUND_2_FLAG) &&
|
||||
cpu_require_ssbd_mitigation();
|
||||
}
|
||||
|
||||
static void enter_hypervisor_head(struct cpu_user_regs *regs)
|
||||
{
|
||||
if ( guest_mode(regs) )
|
||||
{
|
||||
struct vcpu *v = current;
|
||||
|
||||
/* If the guest has disabled the workaround, bring it back on. */
|
||||
if ( needs_ssbd_flip(v) )
|
||||
arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2_FID, 1, NULL);
|
||||
|
||||
/*
|
||||
* If we pended a virtual abort, preserve it until it gets cleared.
|
||||
* See ARM ARM DDI 0487A.j D1.14.3 (Virtual Interrupts) for details,
|
||||
* but the crucial bit is "On taking a vSError interrupt, HCR_EL2.VSE
|
||||
* (alias of HCR.VA) is cleared to 0."
|
||||
*/
|
||||
if ( current->arch.hcr_el2 & HCR_VA )
|
||||
current->arch.hcr_el2 = READ_SYSREG(HCR_EL2);
|
||||
if ( v->arch.hcr_el2 & HCR_VA )
|
||||
v->arch.hcr_el2 = READ_SYSREG(HCR_EL2);
|
||||
|
||||
#ifdef CONFIG_NEW_VGIC
|
||||
/*
|
||||
@@ -2032,11 +2057,11 @@ static void enter_hypervisor_head(struct cpu_user_regs *regs)
|
||||
* TODO: Investigate whether this is necessary to do on every
|
||||
* trap and how it can be optimised.
|
||||
*/
|
||||
vtimer_update_irqs(current);
|
||||
vcpu_update_evtchn_irq(current);
|
||||
vtimer_update_irqs(v);
|
||||
vcpu_update_evtchn_irq(v);
|
||||
#endif
|
||||
|
||||
vgic_sync_from_lrs(current);
|
||||
vgic_sync_from_lrs(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2260,6 +2285,13 @@ void leave_hypervisor_tail(void)
|
||||
*/
|
||||
SYNCHRONIZE_SERROR(SKIP_SYNCHRONIZE_SERROR_ENTRY_EXIT);
|
||||
|
||||
/*
|
||||
* The hypervisor runs with the workaround always present.
|
||||
* If the guest wants it disabled, so be it...
|
||||
*/
|
||||
if ( needs_ssbd_flip(current) )
|
||||
arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2_FID, 0, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
local_irq_enable();
|
||||
|
||||
@@ -485,6 +485,8 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info,
|
||||
|
||||
case VRANGE32(GICD_ISACTIVER, GICD_ISACTIVERN):
|
||||
if ( dabt.size != DABT_WORD ) goto bad_width;
|
||||
if ( r == 0 )
|
||||
goto write_ignore_32;
|
||||
printk(XENLOG_G_ERR
|
||||
"%pv: vGICD: unhandled word write %#"PRIregister" to ISACTIVER%d\n",
|
||||
v, r, gicd_reg - GICD_ISACTIVER);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <xen/lib.h>
|
||||
#include <xen/types.h>
|
||||
#include <public/arch-arm/smccc.h>
|
||||
#include <asm/cpuerrata.h>
|
||||
#include <asm/cpufeature.h>
|
||||
#include <asm/monitor.h>
|
||||
#include <asm/regs.h>
|
||||
@@ -104,6 +105,23 @@ static bool handle_arch(struct cpu_user_regs *regs)
|
||||
if ( cpus_have_cap(ARM_HARDEN_BRANCH_PREDICTOR) )
|
||||
ret = 0;
|
||||
break;
|
||||
case ARM_SMCCC_ARCH_WORKAROUND_2_FID:
|
||||
switch ( get_ssbd_state() )
|
||||
{
|
||||
case ARM_SSBD_UNKNOWN:
|
||||
case ARM_SSBD_FORCE_DISABLE:
|
||||
break;
|
||||
|
||||
case ARM_SSBD_RUNTIME:
|
||||
ret = ARM_SMCCC_SUCCESS;
|
||||
break;
|
||||
|
||||
case ARM_SSBD_FORCE_ENABLE:
|
||||
case ARM_SSBD_MITIGATED:
|
||||
ret = ARM_SMCCC_NOT_REQUIRED;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
set_user_reg(regs, 0, ret);
|
||||
@@ -114,6 +132,25 @@ static bool handle_arch(struct cpu_user_regs *regs)
|
||||
case ARM_SMCCC_ARCH_WORKAROUND_1_FID:
|
||||
/* No return value */
|
||||
return true;
|
||||
|
||||
case ARM_SMCCC_ARCH_WORKAROUND_2_FID:
|
||||
{
|
||||
bool enable = (uint32_t)get_user_reg(regs, 1);
|
||||
|
||||
/*
|
||||
* ARM_WORKAROUND_2_FID should only be called when mitigation
|
||||
* state can be changed at runtime.
|
||||
*/
|
||||
if ( unlikely(get_ssbd_state() != ARM_SSBD_RUNTIME) )
|
||||
return true;
|
||||
|
||||
if ( enable )
|
||||
get_cpu_info()->flags |= CPUINFO_WORKAROUND_2_FLAG;
|
||||
else
|
||||
get_cpu_info()->flags &= ~CPUINFO_WORKAROUND_2_FLAG;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -737,6 +737,7 @@ void restore_vcpu_affinity(struct domain *d)
|
||||
for_each_vcpu ( d, v )
|
||||
{
|
||||
spinlock_t *lock;
|
||||
unsigned int old_cpu = v->processor;
|
||||
|
||||
ASSERT(!vcpu_runnable(v));
|
||||
|
||||
@@ -769,6 +770,9 @@ void restore_vcpu_affinity(struct domain *d)
|
||||
lock = vcpu_schedule_lock_irq(v);
|
||||
v->processor = SCHED_OP(vcpu_scheduler(v), pick_cpu, v);
|
||||
spin_unlock_irq(lock);
|
||||
|
||||
if ( old_cpu != v->processor )
|
||||
sched_move_irqs(v);
|
||||
}
|
||||
|
||||
domain_update_node_affinity(d);
|
||||
|
||||
@@ -11,6 +11,3 @@ config VGA
|
||||
Enable VGA output for the Xen hypervisor.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config HAS_ARM_HDLCD
|
||||
bool
|
||||
@@ -4,4 +4,3 @@ obj-$(CONFIG_VIDEO) += font_8x16.o
|
||||
obj-$(CONFIG_VIDEO) += font_8x8.o
|
||||
obj-$(CONFIG_VIDEO) += lfb.o
|
||||
obj-$(CONFIG_VGA) += vesa.o
|
||||
obj-$(CONFIG_HAS_ARM_HDLCD) += arm_hdlcd.o
|
||||
@@ -1,281 +0,0 @@
|
||||
/*
|
||||
* xen/drivers/video/arm_hdlcd.c
|
||||
*
|
||||
* Driver for ARM HDLCD Controller
|
||||
*
|
||||
* Stefano Stabellini <stefano.stabellini@eu.citrix.com>
|
||||
* Copyright (c) 2013 Citrix Systems.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <asm/delay.h>
|
||||
#include <asm/types.h>
|
||||
#include <asm/platforms/vexpress.h>
|
||||
#include <xen/device_tree.h>
|
||||
#include <xen/libfdt/libfdt.h>
|
||||
#include <xen/init.h>
|
||||
#include <xen/mm.h>
|
||||
#include "font.h"
|
||||
#include "lfb.h"
|
||||
#include "modelines.h"
|
||||
|
||||
#define HDLCD ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_MISC))
|
||||
|
||||
#define HDLCD_INTMASK (0x18/4)
|
||||
#define HDLCD_FBBASE (0x100/4)
|
||||
#define HDLCD_LINELENGTH (0x104/4)
|
||||
#define HDLCD_LINECOUNT (0x108/4)
|
||||
#define HDLCD_LINEPITCH (0x10C/4)
|
||||
#define HDLCD_BUS (0x110/4)
|
||||
#define HDLCD_VSYNC (0x200/4)
|
||||
#define HDLCD_VBACK (0x204/4)
|
||||
#define HDLCD_VDATA (0x208/4)
|
||||
#define HDLCD_VFRONT (0x20C/4)
|
||||
#define HDLCD_HSYNC (0x210/4)
|
||||
#define HDLCD_HBACK (0x214/4)
|
||||
#define HDLCD_HDATA (0x218/4)
|
||||
#define HDLCD_HFRONT (0x21C/4)
|
||||
#define HDLCD_POLARITIES (0x220/4)
|
||||
#define HDLCD_COMMAND (0x230/4)
|
||||
#define HDLCD_PF (0x240/4)
|
||||
#define HDLCD_RED (0x244/4)
|
||||
#define HDLCD_GREEN (0x248/4)
|
||||
#define HDLCD_BLUE (0x24C/4)
|
||||
|
||||
struct color_masks {
|
||||
int red_shift;
|
||||
int red_size;
|
||||
int green_shift;
|
||||
int green_size;
|
||||
int blue_shift;
|
||||
int blue_size;
|
||||
};
|
||||
|
||||
struct pixel_colors {
|
||||
const char* bpp;
|
||||
struct color_masks colors;
|
||||
};
|
||||
|
||||
struct pixel_colors __initdata colors[] = {
|
||||
{ "16", { 0, 5, 11, 5, 6, 5 } },
|
||||
{ "24", { 0, 8, 16, 8, 8, 8 } },
|
||||
{ "32", { 0, 8, 16, 8, 8, 8 } },
|
||||
};
|
||||
|
||||
static void vga_noop_puts(const char *s) {}
|
||||
void (*video_puts)(const char *) = vga_noop_puts;
|
||||
|
||||
static void hdlcd_flush(void)
|
||||
{
|
||||
dsb(sy);
|
||||
}
|
||||
|
||||
static int __init get_color_masks(const char* bpp, struct color_masks **masks)
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < ARRAY_SIZE(colors); i++ )
|
||||
{
|
||||
if ( !strncmp(colors[i].bpp, bpp, 2) )
|
||||
{
|
||||
*masks = &colors[i].colors;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void __init set_pixclock(uint32_t pixclock)
|
||||
{
|
||||
if ( dt_find_compatible_node(NULL, NULL, "arm,vexpress") )
|
||||
vexpress_syscfg(1, V2M_SYS_CFG_OSC_FUNC,
|
||||
V2M_SYS_CFG_OSC5, &pixclock);
|
||||
}
|
||||
|
||||
void __init video_init(void)
|
||||
{
|
||||
struct lfb_prop lfbp;
|
||||
unsigned char *lfb;
|
||||
paddr_t hdlcd_start, hdlcd_size;
|
||||
paddr_t framebuffer_start, framebuffer_size;
|
||||
const char *mode_string;
|
||||
char _mode_string[16];
|
||||
int bytes_per_pixel = 4;
|
||||
struct color_masks *c = NULL;
|
||||
struct modeline *videomode = NULL;
|
||||
int i;
|
||||
const struct dt_device_node *dev;
|
||||
const __be32 *cells;
|
||||
u32 lenp;
|
||||
int res;
|
||||
|
||||
dev = dt_find_compatible_node(NULL, NULL, "arm,hdlcd");
|
||||
|
||||
if ( !dev )
|
||||
{
|
||||
printk("HDLCD: Cannot find node compatible with \"arm,hdcld\"\n");
|
||||
return;
|
||||
}
|
||||
|
||||
res = dt_device_get_address(dev, 0, &hdlcd_start, &hdlcd_size);
|
||||
if ( !res )
|
||||
{
|
||||
printk("HDLCD: Unable to retrieve MMIO base address\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cells = dt_get_property(dev, "framebuffer", &lenp);
|
||||
if ( !cells )
|
||||
{
|
||||
printk("HDLCD: Unable to retrieve framebuffer property\n");
|
||||
return;
|
||||
}
|
||||
|
||||
framebuffer_start = dt_next_cell(dt_n_addr_cells(dev), &cells);
|
||||
framebuffer_size = dt_next_cell(dt_n_size_cells(dev), &cells);
|
||||
|
||||
if ( !hdlcd_start )
|
||||
{
|
||||
printk(KERN_ERR "HDLCD: address missing from device tree, disabling driver\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !framebuffer_start )
|
||||
{
|
||||
printk(KERN_ERR "HDLCD: framebuffer address missing from device tree, disabling driver\n");
|
||||
return;
|
||||
}
|
||||
|
||||
res = dt_property_read_string(dev, "mode", &mode_string);
|
||||
if ( res )
|
||||
{
|
||||
get_color_masks("32", &c);
|
||||
memcpy(_mode_string, "1280x1024@60", strlen("1280x1024@60") + 1);
|
||||
bytes_per_pixel = 4;
|
||||
}
|
||||
else if ( strlen(mode_string) < strlen("800x600@60") ||
|
||||
strlen(mode_string) > sizeof(_mode_string) - 1 )
|
||||
{
|
||||
printk(KERN_ERR "HDLCD: invalid modeline=%s\n", mode_string);
|
||||
return;
|
||||
} else {
|
||||
char *s = strchr(mode_string, '-');
|
||||
if ( !s )
|
||||
{
|
||||
printk(KERN_INFO "HDLCD: bpp not found in modeline %s, assume 32 bpp\n",
|
||||
mode_string);
|
||||
get_color_masks("32", &c);
|
||||
memcpy(_mode_string, mode_string, strlen(mode_string) + 1);
|
||||
bytes_per_pixel = 4;
|
||||
} else {
|
||||
if ( strlen(s) < 6 )
|
||||
{
|
||||
printk(KERN_ERR "HDLCD: invalid mode %s\n", mode_string);
|
||||
return;
|
||||
}
|
||||
s++;
|
||||
if ( get_color_masks(s, &c) < 0 )
|
||||
{
|
||||
printk(KERN_WARNING "HDLCD: unsupported bpp %s\n", s);
|
||||
return;
|
||||
}
|
||||
bytes_per_pixel = simple_strtoll(s, NULL, 10) / 8;
|
||||
}
|
||||
i = s - mode_string - 1;
|
||||
memcpy(_mode_string, mode_string, i);
|
||||
memcpy(_mode_string + i, mode_string + i + 3, 4);
|
||||
}
|
||||
|
||||
for ( i = 0; i < ARRAY_SIZE(videomodes); i++ ) {
|
||||
if ( !strcmp(_mode_string, videomodes[i].mode) )
|
||||
{
|
||||
videomode = &videomodes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !videomode )
|
||||
{
|
||||
printk(KERN_WARNING "HDLCD: unsupported videomode %s\n",
|
||||
_mode_string);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( framebuffer_size < bytes_per_pixel * videomode->xres * videomode->yres )
|
||||
{
|
||||
printk(KERN_ERR "HDLCD: the framebuffer is too small, disabling the HDLCD driver\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "Initializing HDLCD driver\n");
|
||||
|
||||
lfb = ioremap_wc(framebuffer_start, framebuffer_size);
|
||||
if ( !lfb )
|
||||
{
|
||||
printk(KERN_ERR "Couldn't map the framebuffer\n");
|
||||
return;
|
||||
}
|
||||
memset(lfb, 0x00, bytes_per_pixel * videomode->xres * videomode->yres);
|
||||
|
||||
/* uses FIXMAP_MISC */
|
||||
set_pixclock(videomode->pixclock);
|
||||
|
||||
set_fixmap(FIXMAP_MISC, maddr_to_mfn(hdlcd_start), PAGE_HYPERVISOR_NOCACHE);
|
||||
HDLCD[HDLCD_COMMAND] = 0;
|
||||
|
||||
HDLCD[HDLCD_LINELENGTH] = videomode->xres * bytes_per_pixel;
|
||||
HDLCD[HDLCD_LINECOUNT] = videomode->yres - 1;
|
||||
HDLCD[HDLCD_LINEPITCH] = videomode->xres * bytes_per_pixel;
|
||||
HDLCD[HDLCD_PF] = ((bytes_per_pixel - 1) << 3);
|
||||
HDLCD[HDLCD_INTMASK] = 0;
|
||||
HDLCD[HDLCD_FBBASE] = framebuffer_start;
|
||||
HDLCD[HDLCD_BUS] = 0xf00 | (1 << 4);
|
||||
HDLCD[HDLCD_VBACK] = videomode->vback - 1;
|
||||
HDLCD[HDLCD_VSYNC] = videomode->vsync - 1;
|
||||
HDLCD[HDLCD_VDATA] = videomode->yres - 1;
|
||||
HDLCD[HDLCD_VFRONT] = videomode->vfront - 1;
|
||||
HDLCD[HDLCD_HBACK] = videomode->hback - 1;
|
||||
HDLCD[HDLCD_HSYNC] = videomode->hsync - 1;
|
||||
HDLCD[HDLCD_HDATA] = videomode->xres - 1;
|
||||
HDLCD[HDLCD_HFRONT] = videomode->hfront - 1;
|
||||
HDLCD[HDLCD_POLARITIES] = (1 << 2) | (1 << 3);
|
||||
HDLCD[HDLCD_RED] = (c->red_size << 8) | c->red_shift;
|
||||
HDLCD[HDLCD_GREEN] = (c->green_size << 8) | c->green_shift;
|
||||
HDLCD[HDLCD_BLUE] = (c->blue_size << 8) | c->blue_shift;
|
||||
HDLCD[HDLCD_COMMAND] = 1;
|
||||
clear_fixmap(FIXMAP_MISC);
|
||||
|
||||
lfbp.pixel_on = (((1 << c->red_size) - 1) << c->red_shift) |
|
||||
(((1 << c->green_size) - 1) << c->green_shift) |
|
||||
(((1 << c->blue_size) - 1) << c->blue_shift);
|
||||
lfbp.lfb = lfb;
|
||||
lfbp.font = &font_vga_8x16;
|
||||
lfbp.bits_per_pixel = bytes_per_pixel*8;
|
||||
lfbp.bytes_per_line = bytes_per_pixel*videomode->xres;
|
||||
lfbp.width = videomode->xres;
|
||||
lfbp.height = videomode->yres;
|
||||
lfbp.flush = hdlcd_flush;
|
||||
lfbp.text_columns = videomode->xres / 8;
|
||||
lfbp.text_rows = videomode->yres / 16;
|
||||
if ( lfb_init(&lfbp) < 0 )
|
||||
return;
|
||||
video_puts = lfb_scroll_puts;
|
||||
}
|
||||
|
||||
void __init video_endboot(void) { }
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* mode: C
|
||||
* c-file-style: "BSD"
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
#define ARM_CB_PATCH ARM_NCAPS
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <xen/init.h>
|
||||
@@ -18,16 +20,24 @@ struct alt_instr {
|
||||
};
|
||||
|
||||
/* Xen: helpers used by common code. */
|
||||
#define __ALT_PTR(a,f) ((u32 *)((void *)&(a)->f + (a)->f))
|
||||
#define __ALT_PTR(a,f) ((void *)&(a)->f + (a)->f)
|
||||
#define ALT_ORIG_PTR(a) __ALT_PTR(a, orig_offset)
|
||||
#define ALT_REPL_PTR(a) __ALT_PTR(a, alt_offset)
|
||||
|
||||
typedef void (*alternative_cb_t)(const struct alt_instr *alt,
|
||||
const uint32_t *origptr, uint32_t *updptr,
|
||||
int nr_inst);
|
||||
|
||||
void __init apply_alternatives_all(void);
|
||||
int apply_alternatives(const struct alt_instr *start, const struct alt_instr *end);
|
||||
|
||||
#define ALTINSTR_ENTRY(feature) \
|
||||
#define ALTINSTR_ENTRY(feature, cb) \
|
||||
" .word 661b - .\n" /* label */ \
|
||||
" .if " __stringify(cb) " == 0\n" \
|
||||
" .word 663f - .\n" /* new instruction */ \
|
||||
" .else\n" \
|
||||
" .word " __stringify(cb) "- .\n" /* callback */ \
|
||||
" .endif\n" \
|
||||
" .hword " __stringify(feature) "\n" /* feature bit */ \
|
||||
" .byte 662b-661b\n" /* source len */ \
|
||||
" .byte 664f-663f\n" /* replacement len */
|
||||
@@ -45,15 +55,18 @@ int apply_alternatives(const struct alt_instr *start, const struct alt_instr *en
|
||||
* but most assemblers die if insn1 or insn2 have a .inst. This should
|
||||
* be fixed in a binutils release posterior to 2.25.51.0.2 (anything
|
||||
* containing commit 4e4d08cf7399b606 or c1baaddf8861).
|
||||
*
|
||||
* Alternatives with callbacks do not generate replacement instructions.
|
||||
*/
|
||||
#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled) \
|
||||
#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled, cb) \
|
||||
".if "__stringify(cfg_enabled)" == 1\n" \
|
||||
"661:\n\t" \
|
||||
oldinstr "\n" \
|
||||
"662:\n" \
|
||||
".pushsection .altinstructions,\"a\"\n" \
|
||||
ALTINSTR_ENTRY(feature) \
|
||||
ALTINSTR_ENTRY(feature,cb) \
|
||||
".popsection\n" \
|
||||
" .if " __stringify(cb) " == 0\n" \
|
||||
".pushsection .altinstr_replacement, \"a\"\n" \
|
||||
"663:\n\t" \
|
||||
newinstr "\n" \
|
||||
@@ -61,11 +74,17 @@ int apply_alternatives(const struct alt_instr *start, const struct alt_instr *en
|
||||
".popsection\n\t" \
|
||||
".org . - (664b-663b) + (662b-661b)\n\t" \
|
||||
".org . - (662b-661b) + (664b-663b)\n" \
|
||||
".else\n\t" \
|
||||
"663:\n\t" \
|
||||
"664:\n\t" \
|
||||
".endif\n" \
|
||||
".endif\n"
|
||||
|
||||
#define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \
|
||||
__ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg))
|
||||
__ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg), 0)
|
||||
|
||||
#define ALTERNATIVE_CB(oldinstr, cb) \
|
||||
__ALTERNATIVE_CFG(oldinstr, "NOT_AN_INSTRUCTION", ARM_CB_PATCH, 1, cb)
|
||||
#else
|
||||
|
||||
#include <asm/asm_defns.h>
|
||||
@@ -126,6 +145,14 @@ int apply_alternatives(const struct alt_instr *start, const struct alt_instr *en
|
||||
663:
|
||||
.endm
|
||||
|
||||
.macro alternative_cb cb
|
||||
.set .Lasm_alt_mode, 0
|
||||
.pushsection .altinstructions, "a"
|
||||
altinstruction_entry 661f, \cb, ARM_CB_PATCH, 662f-661f, 0
|
||||
.popsection
|
||||
661:
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Complete an alternative code sequence.
|
||||
*/
|
||||
@@ -135,6 +162,13 @@ int apply_alternatives(const struct alt_instr *start, const struct alt_instr *en
|
||||
.org . - (662b-661b) + (664b-663b)
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Callback-based alternative epilogue
|
||||
*/
|
||||
.macro alternative_cb_end
|
||||
662:
|
||||
.endm
|
||||
|
||||
#define _ALTERNATIVE_CFG(insn1, insn2, cap, cfg, ...) \
|
||||
alternative_insn insn1, insn2, cap, IS_ENABLED(cfg)
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef __ASM_ARM_ARM64_MACROS_H
|
||||
#define __ASM_ARM_ARM64_MACROS_H
|
||||
|
||||
/*
|
||||
* @dst: Result of get_cpu_info()
|
||||
*/
|
||||
.macro adr_cpu_info, dst
|
||||
add \dst, sp, #STACK_SIZE
|
||||
and \dst, \dst, #~(STACK_SIZE - 1)
|
||||
sub \dst, \dst, #CPUINFO_sizeof
|
||||
.endm
|
||||
|
||||
/*
|
||||
* @dst: Result of READ_ONCE(per_cpu(sym, smp_processor_id()))
|
||||
* @sym: The name of the per-cpu variable
|
||||
* @tmp: scratch register
|
||||
*/
|
||||
.macro ldr_this_cpu, dst, sym, tmp
|
||||
ldr \dst, =per_cpu__\sym
|
||||
mrs \tmp, tpidr_el2
|
||||
ldr \dst, [\dst, \tmp]
|
||||
.endm
|
||||
|
||||
#endif /* __ASM_ARM_ARM64_MACROS_H */
|
||||
|
||||
@@ -27,9 +27,51 @@ static inline bool check_workaround_##erratum(void) \
|
||||
|
||||
CHECK_WORKAROUND_HELPER(766422, ARM32_WORKAROUND_766422, CONFIG_ARM_32)
|
||||
CHECK_WORKAROUND_HELPER(834220, ARM64_WORKAROUND_834220, CONFIG_ARM_64)
|
||||
CHECK_WORKAROUND_HELPER(ssbd, ARM_SSBD, CONFIG_ARM_SSBD)
|
||||
|
||||
#undef CHECK_WORKAROUND_HELPER
|
||||
|
||||
enum ssbd_state
|
||||
{
|
||||
ARM_SSBD_UNKNOWN,
|
||||
ARM_SSBD_FORCE_DISABLE,
|
||||
ARM_SSBD_RUNTIME,
|
||||
ARM_SSBD_FORCE_ENABLE,
|
||||
ARM_SSBD_MITIGATED,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARM_SSBD
|
||||
|
||||
#include <asm/current.h>
|
||||
|
||||
extern enum ssbd_state ssbd_state;
|
||||
|
||||
static inline enum ssbd_state get_ssbd_state(void)
|
||||
{
|
||||
return ssbd_state;
|
||||
}
|
||||
|
||||
DECLARE_PER_CPU(register_t, ssbd_callback_required);
|
||||
|
||||
static inline bool cpu_require_ssbd_mitigation(void)
|
||||
{
|
||||
return this_cpu(ssbd_callback_required);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline bool cpu_require_ssbd_mitigation(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline enum ssbd_state get_ssbd_state(void)
|
||||
{
|
||||
return ARM_SSBD_UNKNOWN;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __ARM_CPUERRATA_H__ */
|
||||
/*
|
||||
* Local variables:
|
||||
|
||||
@@ -43,8 +43,9 @@
|
||||
#define SKIP_SYNCHRONIZE_SERROR_ENTRY_EXIT 5
|
||||
#define SKIP_CTXT_SWITCH_SERROR_SYNC 6
|
||||
#define ARM_HARDEN_BRANCH_PREDICTOR 7
|
||||
#define ARM_SSBD 8
|
||||
|
||||
#define ARM_NCAPS 8
|
||||
#define ARM_NCAPS 9
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
@@ -88,6 +89,7 @@ void update_cpu_capabilities(const struct arm_cpu_capabilities *caps,
|
||||
const char *info);
|
||||
|
||||
void enable_cpu_capabilities(const struct arm_cpu_capabilities *caps);
|
||||
int enable_nonboot_cpu_caps(const struct arm_cpu_capabilities *caps);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#include <asm/percpu.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
/* Tell whether the guest vCPU enabled Workaround 2 (i.e variant 4) */
|
||||
#define CPUINFO_WORKAROUND_2_FLAG_SHIFT 0
|
||||
#define CPUINFO_WORKAROUND_2_FLAG (_AC(1, U) << CPUINFO_WORKAROUND_2_FLAG_SHIFT)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
struct vcpu;
|
||||
@@ -21,7 +25,7 @@ DECLARE_PER_CPU(struct vcpu *, curr_vcpu);
|
||||
struct cpu_info {
|
||||
struct cpu_user_regs guest_cpu_user_regs;
|
||||
unsigned long elr;
|
||||
unsigned int pad;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
static inline struct cpu_info *get_cpu_info(void)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#if defined (CONFIG_ARM_32)
|
||||
# include <asm/arm32/macros.h>
|
||||
#elif defined(CONFIG_ARM_64)
|
||||
/* No specific ARM64 macros for now */
|
||||
# include <asm/arm64/macros.h>
|
||||
#else
|
||||
# error "unknown ARM variant"
|
||||
#endif
|
||||
|
||||
@@ -26,12 +26,6 @@
|
||||
/* Board-specific: base address of system controller */
|
||||
#define SP810_ADDRESS 0x1C020000
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <xen/inttypes.h>
|
||||
|
||||
int vexpress_syscfg(int write, int function, int device, uint32_t *data);
|
||||
#endif
|
||||
|
||||
#endif /* __ASM_ARM_PLATFORMS_VEXPRESS_H */
|
||||
/*
|
||||
* Local variables:
|
||||
|
||||
@@ -35,9 +35,9 @@ struct proc_info_list {
|
||||
struct processor *processor;
|
||||
};
|
||||
|
||||
const __init struct proc_info_list *lookup_processor_type(void);
|
||||
const struct proc_info_list *lookup_processor_type(void);
|
||||
|
||||
void __init processor_setup(void);
|
||||
void processor_setup(void);
|
||||
void processor_vcpu_initialise(struct vcpu *v);
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,7 @@ extern uint32_t psci_ver;
|
||||
|
||||
int psci_init(void);
|
||||
int call_psci_cpu_on(int cpu);
|
||||
void call_psci_cpu_off(void);
|
||||
void call_psci_system_off(void);
|
||||
void call_psci_system_reset(void);
|
||||
|
||||
|
||||
@@ -254,11 +254,18 @@ struct arm_smccc_res {
|
||||
|
||||
#define ARM_SMCCC_ARCH_WORKAROUND_1_FID \
|
||||
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
|
||||
ARM_SMCCC_CONV_32, \
|
||||
ARM_SMCCC_OWNER_ARCH, \
|
||||
0x8000)
|
||||
ARM_SMCCC_CONV_32, \
|
||||
ARM_SMCCC_OWNER_ARCH, \
|
||||
0x8000)
|
||||
|
||||
#define ARM_SMCCC_ARCH_WORKAROUND_2_FID \
|
||||
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
|
||||
ARM_SMCCC_CONV_32, \
|
||||
ARM_SMCCC_OWNER_ARCH, \
|
||||
0x7FFF)
|
||||
|
||||
/* SMCCC error codes */
|
||||
#define ARM_SMCCC_NOT_REQUIRED (-2)
|
||||
#define ARM_SMCCC_ERR_UNKNOWN_FUNCTION (-1)
|
||||
#define ARM_SMCCC_NOT_SUPPORTED (-1)
|
||||
#define ARM_SMCCC_SUCCESS (0)
|
||||
|
||||
@@ -27,6 +27,10 @@ void handle_wo_wi(struct cpu_user_regs *regs, int regidx, bool read,
|
||||
void handle_ro_raz(struct cpu_user_regs *regs, int regidx, bool read,
|
||||
const union hsr hsr, int min_el);
|
||||
|
||||
/* Read only as value provided with 'val' argument */
|
||||
void handle_ro_read_val(struct cpu_user_regs *regs, int regidx, bool read,
|
||||
const union hsr hsr, int min_el, register_t val);
|
||||
|
||||
/* Co-processor registers emulation (see arch/arm/vcpreg.c). */
|
||||
void do_cp15_32(struct cpu_user_regs *regs, const union hsr hsr);
|
||||
void do_cp15_64(struct cpu_user_regs *regs, const union hsr hsr);
|
||||
|
||||