diff options
Diffstat (limited to 'arch/x86/kernel')
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 6 | ||||
| -rw-r--r-- | arch/x86/kernel/entry_32.S | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/kvm.c | 12 | ||||
| -rw-r--r-- | arch/x86/kernel/setup.c | 80 | ||||
| -rw-r--r-- | arch/x86/kernel/step.c | 9 | 
5 files changed, 95 insertions, 13 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 4428fd178bc..6774c17a557 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -340,9 +340,6 @@ int x86_setup_perfctr(struct perf_event *event)  		/* BTS is currently only allowed for user-mode. */  		if (!attr->exclude_kernel)  			return -EOPNOTSUPP; - -		if (!attr->exclude_guest) -			return -EOPNOTSUPP;  	}  	hwc->config |= config; @@ -385,9 +382,6 @@ int x86_pmu_hw_config(struct perf_event *event)  	if (event->attr.precise_ip) {  		int precise = 0; -		if (!event->attr.exclude_guest) -			return -EOPNOTSUPP; -  		/* Support for constant skid */  		if (x86_pmu.pebs_active && !x86_pmu.pebs_broken) {  			precise++; diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index ff84d5469d7..6ed91d9980e 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -1065,7 +1065,6 @@ ENTRY(xen_failsafe_callback)  	lea 16(%esp),%esp  	CFI_ADJUST_CFA_OFFSET -16  	jz 5f -	addl $16,%esp  	jmp iret_exc  5:	pushl_cfi $-1 /* orig_ax = -1 => not a system call */  	SAVE_ALL diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 08b973f6403..9c2bd8bd4b4 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -43,6 +43,7 @@  #include <asm/apicdef.h>  #include <asm/hypervisor.h>  #include <asm/kvm_guest.h> +#include <asm/context_tracking.h>  static int kvmapf = 1; @@ -121,6 +122,8 @@ void kvm_async_pf_task_wait(u32 token)  	struct kvm_task_sleep_node n, *e;  	DEFINE_WAIT(wait); +	rcu_irq_enter(); +  	spin_lock(&b->lock);  	e = _find_apf_task(b, token);  	if (e) { @@ -128,6 +131,8 @@ void kvm_async_pf_task_wait(u32 token)  		hlist_del(&e->link);  		kfree(e);  		spin_unlock(&b->lock); + +		rcu_irq_exit();  		return;  	} @@ -152,13 +157,16 @@ void kvm_async_pf_task_wait(u32 token)  			/*  			 * We cannot reschedule. So halt.  			 */ +			rcu_irq_exit();  			native_safe_halt(); +			rcu_irq_enter();  			local_irq_disable();  		}  	}  	if (!n.halted)  		finish_wait(&n.wq, &wait); +	rcu_irq_exit();  	return;  }  EXPORT_SYMBOL_GPL(kvm_async_pf_task_wait); @@ -252,10 +260,10 @@ do_async_page_fault(struct pt_regs *regs, unsigned long error_code)  		break;  	case KVM_PV_REASON_PAGE_NOT_PRESENT:  		/* page is swapped out by the host. */ -		rcu_irq_enter(); +		exception_enter(regs);  		exit_idle();  		kvm_async_pf_task_wait((u32)read_cr2()); -		rcu_irq_exit(); +		exception_exit(regs);  		break;  	case KVM_PV_REASON_PAGE_READY:  		rcu_irq_enter(); diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 23ddd558fbd..00f6c1472b8 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -610,6 +610,83 @@ static __init void reserve_ibft_region(void)  static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10; +static bool __init snb_gfx_workaround_needed(void) +{ +#ifdef CONFIG_PCI +	int i; +	u16 vendor, devid; +	static const __initconst u16 snb_ids[] = { +		0x0102, +		0x0112, +		0x0122, +		0x0106, +		0x0116, +		0x0126, +		0x010a, +	}; + +	/* Assume no if something weird is going on with PCI */ +	if (!early_pci_allowed()) +		return false; + +	vendor = read_pci_config_16(0, 2, 0, PCI_VENDOR_ID); +	if (vendor != 0x8086) +		return false; + +	devid = read_pci_config_16(0, 2, 0, PCI_DEVICE_ID); +	for (i = 0; i < ARRAY_SIZE(snb_ids); i++) +		if (devid == snb_ids[i]) +			return true; +#endif + +	return false; +} + +/* + * Sandy Bridge graphics has trouble with certain ranges, exclude + * them from allocation. + */ +static void __init trim_snb_memory(void) +{ +	static const __initconst unsigned long bad_pages[] = { +		0x20050000, +		0x20110000, +		0x20130000, +		0x20138000, +		0x40004000, +	}; +	int i; + +	if (!snb_gfx_workaround_needed()) +		return; + +	printk(KERN_DEBUG "reserving inaccessible SNB gfx pages\n"); + +	/* +	 * Reserve all memory below the 1 MB mark that has not +	 * already been reserved. +	 */ +	memblock_reserve(0, 1<<20); +	 +	for (i = 0; i < ARRAY_SIZE(bad_pages); i++) { +		if (memblock_reserve(bad_pages[i], PAGE_SIZE)) +			printk(KERN_WARNING "failed to reserve 0x%08lx\n", +			       bad_pages[i]); +	} +} + +/* + * Here we put platform-specific memory range workarounds, i.e. + * memory known to be corrupt or otherwise in need to be reserved on + * specific platforms. + * + * If this gets used more widely it could use a real dispatch mechanism. + */ +static void __init trim_platform_memory_ranges(void) +{ +	trim_snb_memory(); +} +  static void __init trim_bios_range(void)  {  	/* @@ -630,6 +707,7 @@ static void __init trim_bios_range(void)  	 * take them out.  	 */  	e820_remove_range(BIOS_BEGIN, BIOS_END - BIOS_BEGIN, E820_RAM, 1); +  	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);  } @@ -908,6 +986,8 @@ void __init setup_arch(char **cmdline_p)  	setup_real_mode(); +	trim_platform_memory_ranges(); +  	init_gbpages();  	/* max_pfn_mapped is updated here */ diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index cd3b2438a98..9b4d51d0c0d 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c @@ -165,10 +165,11 @@ void set_task_blockstep(struct task_struct *task, bool on)  	 * Ensure irq/preemption can't change debugctl in between.  	 * Note also that both TIF_BLOCKSTEP and debugctl should  	 * be changed atomically wrt preemption. -	 * FIXME: this means that set/clear TIF_BLOCKSTEP is simply -	 * wrong if task != current, SIGKILL can wakeup the stopped -	 * tracee and set/clear can play with the running task, this -	 * can confuse the next __switch_to_xtra(). +	 * +	 * NOTE: this means that set/clear TIF_BLOCKSTEP is only safe if +	 * task is current or it can't be running, otherwise we can race +	 * with __switch_to_xtra(). We rely on ptrace_freeze_traced() but +	 * PTRACE_KILL is not safe.  	 */  	local_irq_disable();  	debugctl = get_debugctlmsr();  |