Merge branch 'arm-next' into staging

This commit is contained in:
Julien Grall committed 2018-07-04 11:46:11 +01:00
commit 65a2c12576
38 files changed
+785 -428

No files matched your search

+18
View File
@@ -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
View File
@@ -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
View File
@@ -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(&region);
ret = __apply_alternatives(&region, 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(&region);
return __apply_alternatives(&region, 0);
}
/*
+2
View File
@@ -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);
+44 -4
View File
@@ -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.
+1 -1
View File
@@ -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;
+3 -1
View File
@@ -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
+199
View File
@@ -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
+29
View File
@@ -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
+9
View File
@@ -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:
+1 -1
View File
@@ -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);
+31
View File
@@ -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
View File
@@ -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
View File
@@ -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
-35
View File
@@ -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
+1 -1
View File
@@ -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;
+13
View File
@@ -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) )
+6 -2
View File
@@ -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
View File
@@ -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
+45
View File
@@ -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
View File
@@ -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();
+2
View File
@@ -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);
+37
View File
@@ -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;
+4
View File
@@ -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);
-3
View File
@@ -11,6 +11,3 @@ config VGA
Enable VGA output for the Xen hypervisor.
If unsure, say Y.
config HAS_ARM_HDLCD
bool
-1
View File
@@ -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
-281
View File
@@ -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:
*/
+39 -5
View File
@@ -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)
+25
View File
@@ -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 */
+42
View File
@@ -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:
+3 -1
View File
@@ -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__ */
+5 -1
View File
@@ -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)
+1 -1
View File
@@ -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
-6
View File
@@ -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:
+2 -2
View File
@@ -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
+1
View File
@@ -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);
+10 -3
View File
@@ -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)
+4
View File
@@ -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);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.