diff options
Diffstat (limited to 'arch/x86/platform')
| -rw-r--r-- | arch/x86/platform/efi/efi_64.c | 151 | 
1 files changed, 52 insertions, 99 deletions
| diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index fa8506e76bbe..d19a2edd63cb 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c @@ -180,7 +180,7 @@ void efi_sync_low_kernel_mappings(void)  static inline phys_addr_t  virt_to_phys_or_null_size(void *va, unsigned long size)  { -	bool bad_size; +	phys_addr_t pa;  	if (!va)  		return 0; @@ -188,16 +188,13 @@ virt_to_phys_or_null_size(void *va, unsigned long size)  	if (virt_addr_valid(va))  		return virt_to_phys(va); -	/* -	 * A fully aligned variable on the stack is guaranteed not to -	 * cross a page bounary. Try to catch strings on the stack by -	 * checking that 'size' is a power of two. -	 */ -	bad_size = size > PAGE_SIZE || !is_power_of_2(size); +	pa = slow_virt_to_phys(va); -	WARN_ON(!IS_ALIGNED((unsigned long)va, size) || bad_size); +	/* check if the object crosses a page boundary */ +	if (WARN_ON((pa ^ (pa + size - 1)) & PAGE_MASK)) +		return 0; -	return slow_virt_to_phys(va); +	return pa;  }  #define virt_to_phys_or_null(addr)				\ @@ -568,85 +565,25 @@ efi_thunk_set_virtual_address_map(unsigned long memory_map_size,  static efi_status_t efi_thunk_get_time(efi_time_t *tm, efi_time_cap_t *tc)  { -	efi_status_t status; -	u32 phys_tm, phys_tc; -	unsigned long flags; - -	spin_lock(&rtc_lock); -	spin_lock_irqsave(&efi_runtime_lock, flags); - -	phys_tm = virt_to_phys_or_null(tm); -	phys_tc = virt_to_phys_or_null(tc); - -	status = efi_thunk(get_time, phys_tm, phys_tc); - -	spin_unlock_irqrestore(&efi_runtime_lock, flags); -	spin_unlock(&rtc_lock); - -	return status; +	return EFI_UNSUPPORTED;  }  static efi_status_t efi_thunk_set_time(efi_time_t *tm)  { -	efi_status_t status; -	u32 phys_tm; -	unsigned long flags; - -	spin_lock(&rtc_lock); -	spin_lock_irqsave(&efi_runtime_lock, flags); - -	phys_tm = virt_to_phys_or_null(tm); - -	status = efi_thunk(set_time, phys_tm); - -	spin_unlock_irqrestore(&efi_runtime_lock, flags); -	spin_unlock(&rtc_lock); - -	return status; +	return EFI_UNSUPPORTED;  }  static efi_status_t  efi_thunk_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending,  			  efi_time_t *tm)  { -	efi_status_t status; -	u32 phys_enabled, phys_pending, phys_tm; -	unsigned long flags; - -	spin_lock(&rtc_lock); -	spin_lock_irqsave(&efi_runtime_lock, flags); - -	phys_enabled = virt_to_phys_or_null(enabled); -	phys_pending = virt_to_phys_or_null(pending); -	phys_tm = virt_to_phys_or_null(tm); - -	status = efi_thunk(get_wakeup_time, phys_enabled, -			     phys_pending, phys_tm); - -	spin_unlock_irqrestore(&efi_runtime_lock, flags); -	spin_unlock(&rtc_lock); - -	return status; +	return EFI_UNSUPPORTED;  }  static efi_status_t  efi_thunk_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)  { -	efi_status_t status; -	u32 phys_tm; -	unsigned long flags; - -	spin_lock(&rtc_lock); -	spin_lock_irqsave(&efi_runtime_lock, flags); - -	phys_tm = virt_to_phys_or_null(tm); - -	status = efi_thunk(set_wakeup_time, enabled, phys_tm); - -	spin_unlock_irqrestore(&efi_runtime_lock, flags); -	spin_unlock(&rtc_lock); - -	return status; +	return EFI_UNSUPPORTED;  }  static unsigned long efi_name_size(efi_char16_t *name) @@ -658,6 +595,8 @@ static efi_status_t  efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,  		       u32 *attr, unsigned long *data_size, void *data)  { +	u8 buf[24] __aligned(8); +	efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));  	efi_status_t status;  	u32 phys_name, phys_vendor, phys_attr;  	u32 phys_data_size, phys_data; @@ -665,14 +604,19 @@ efi_thunk_get_variable(efi_char16_t *name, efi_guid_t *vendor,  	spin_lock_irqsave(&efi_runtime_lock, flags); +	*vnd = *vendor; +  	phys_data_size = virt_to_phys_or_null(data_size); -	phys_vendor = virt_to_phys_or_null(vendor); +	phys_vendor = virt_to_phys_or_null(vnd);  	phys_name = virt_to_phys_or_null_size(name, efi_name_size(name));  	phys_attr = virt_to_phys_or_null(attr);  	phys_data = virt_to_phys_or_null_size(data, *data_size); -	status = efi_thunk(get_variable, phys_name, phys_vendor, -			   phys_attr, phys_data_size, phys_data); +	if (!phys_name || (data && !phys_data)) +		status = EFI_INVALID_PARAMETER; +	else +		status = efi_thunk(get_variable, phys_name, phys_vendor, +				   phys_attr, phys_data_size, phys_data);  	spin_unlock_irqrestore(&efi_runtime_lock, flags); @@ -683,19 +627,25 @@ static efi_status_t  efi_thunk_set_variable(efi_char16_t *name, efi_guid_t *vendor,  		       u32 attr, unsigned long data_size, void *data)  { +	u8 buf[24] __aligned(8); +	efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));  	u32 phys_name, phys_vendor, phys_data;  	efi_status_t status;  	unsigned long flags;  	spin_lock_irqsave(&efi_runtime_lock, flags); +	*vnd = *vendor; +  	phys_name = virt_to_phys_or_null_size(name, efi_name_size(name)); -	phys_vendor = virt_to_phys_or_null(vendor); +	phys_vendor = virt_to_phys_or_null(vnd);  	phys_data = virt_to_phys_or_null_size(data, data_size); -	/* If data_size is > sizeof(u32) we've got problems */ -	status = efi_thunk(set_variable, phys_name, phys_vendor, -			   attr, data_size, phys_data); +	if (!phys_name || !phys_data) +		status = EFI_INVALID_PARAMETER; +	else +		status = efi_thunk(set_variable, phys_name, phys_vendor, +				   attr, data_size, phys_data);  	spin_unlock_irqrestore(&efi_runtime_lock, flags); @@ -707,6 +657,8 @@ efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,  				   u32 attr, unsigned long data_size,  				   void *data)  { +	u8 buf[24] __aligned(8); +	efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));  	u32 phys_name, phys_vendor, phys_data;  	efi_status_t status;  	unsigned long flags; @@ -714,13 +666,17 @@ efi_thunk_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,  	if (!spin_trylock_irqsave(&efi_runtime_lock, flags))  		return EFI_NOT_READY; +	*vnd = *vendor; +  	phys_name = virt_to_phys_or_null_size(name, efi_name_size(name)); -	phys_vendor = virt_to_phys_or_null(vendor); +	phys_vendor = virt_to_phys_or_null(vnd);  	phys_data = virt_to_phys_or_null_size(data, data_size); -	/* If data_size is > sizeof(u32) we've got problems */ -	status = efi_thunk(set_variable, phys_name, phys_vendor, -			   attr, data_size, phys_data); +	if (!phys_name || !phys_data) +		status = EFI_INVALID_PARAMETER; +	else +		status = efi_thunk(set_variable, phys_name, phys_vendor, +				   attr, data_size, phys_data);  	spin_unlock_irqrestore(&efi_runtime_lock, flags); @@ -732,39 +688,36 @@ efi_thunk_get_next_variable(unsigned long *name_size,  			    efi_char16_t *name,  			    efi_guid_t *vendor)  { +	u8 buf[24] __aligned(8); +	efi_guid_t *vnd = PTR_ALIGN((efi_guid_t *)buf, sizeof(*vnd));  	efi_status_t status;  	u32 phys_name_size, phys_name, phys_vendor;  	unsigned long flags;  	spin_lock_irqsave(&efi_runtime_lock, flags); +	*vnd = *vendor; +  	phys_name_size = virt_to_phys_or_null(name_size); -	phys_vendor = virt_to_phys_or_null(vendor); +	phys_vendor = virt_to_phys_or_null(vnd);  	phys_name = virt_to_phys_or_null_size(name, *name_size); -	status = efi_thunk(get_next_variable, phys_name_size, -			   phys_name, phys_vendor); +	if (!phys_name) +		status = EFI_INVALID_PARAMETER; +	else +		status = efi_thunk(get_next_variable, phys_name_size, +				   phys_name, phys_vendor);  	spin_unlock_irqrestore(&efi_runtime_lock, flags); +	*vendor = *vnd;  	return status;  }  static efi_status_t  efi_thunk_get_next_high_mono_count(u32 *count)  { -	efi_status_t status; -	u32 phys_count; -	unsigned long flags; - -	spin_lock_irqsave(&efi_runtime_lock, flags); - -	phys_count = virt_to_phys_or_null(count); -	status = efi_thunk(get_next_high_mono_count, phys_count); - -	spin_unlock_irqrestore(&efi_runtime_lock, flags); - -	return status; +	return EFI_UNSUPPORTED;  }  static void |