Skip to content
Snippets Groups Projects
efi_boottime.c 35.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	if (efiobj)
    		list_del(&efiobj->link);
    
    	return EFI_EXIT(EFI_SUCCESS);
    }
    
    static void efi_exit_caches(void)
    {
    #if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
    	/*
    	 * Grub on 32bit ARM needs to have caches disabled before jumping into
    	 * a zImage, but does not know of all cache layers. Give it a hand.
    	 */
    	if (efi_is_direct_boot)
    		cleanup_before_linux();
    #endif
    }
    
    static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle,
    						  unsigned long map_key)
    {
    
    	EFI_ENTRY("%p, %ld", image_handle, map_key);
    
    
    	/* Notify that ExitBootServices is invoked. */
    	for (i = 0; i < ARRAY_SIZE(efi_events); ++i) {
    		if (efi_events[i].type != EVT_SIGNAL_EXIT_BOOT_SERVICES)
    			continue;
    		efi_signal_event(&efi_events[i]);
    	}
    	/* Make sure that notification functions are not called anymore */
    	efi_tpl = TPL_HIGH_LEVEL;
    
    
    #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
    	/* save any EFI variables that have been written: */
    	env_save();
    #endif
    
    
    	/* Fix up caches for EFI payloads if necessary */
    	efi_exit_caches();
    
    	/* This stops all lingering devices */
    	bootm_disable_interrupts();
    
    	/* Give the payload some time to boot */
    	WATCHDOG_RESET();
    
    	return EFI_EXIT(EFI_SUCCESS);
    }
    
    static efi_status_t EFIAPI efi_get_next_monotonic_count(uint64_t *count)
    {
    	static uint64_t mono = 0;
    	EFI_ENTRY("%p", count);
    	*count = mono++;
    	return EFI_EXIT(EFI_SUCCESS);
    }
    
    static efi_status_t EFIAPI efi_stall(unsigned long microseconds)
    {
    	EFI_ENTRY("%ld", microseconds);
    	udelay(microseconds);
    	return EFI_EXIT(EFI_SUCCESS);
    }
    
    static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout,
    						  uint64_t watchdog_code,
    						  unsigned long data_size,
    						  uint16_t *watchdog_data)
    {
    	EFI_ENTRY("%ld, 0x%"PRIx64", %ld, %p", timeout, watchdog_code,
    		  data_size, watchdog_data);
    
    	return efi_unsupported(__func__);
    
    }
    
    static efi_status_t EFIAPI efi_connect_controller(
    			efi_handle_t controller_handle,
    			efi_handle_t *driver_image_handle,
    			struct efi_device_path *remain_device_path,
    			bool recursive)
    {
    	EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle,
    		  remain_device_path, recursive);
    	return EFI_EXIT(EFI_NOT_FOUND);
    }
    
    static efi_status_t EFIAPI efi_disconnect_controller(void *controller_handle,
    						     void *driver_image_handle,
    						     void *child_handle)
    {
    	EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle,
    		  child_handle);
    	return EFI_EXIT(EFI_INVALID_PARAMETER);
    }
    
    static efi_status_t EFIAPI efi_close_protocol(void *handle,
    					      efi_guid_t *protocol,
    					      void *agent_handle,
    					      void *controller_handle)
    {
    
    Rob Clark's avatar
    Rob Clark committed
    	EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, agent_handle,
    
    		  controller_handle);
    	return EFI_EXIT(EFI_NOT_FOUND);
    }
    
    static efi_status_t EFIAPI efi_open_protocol_information(efi_handle_t handle,
    			efi_guid_t *protocol,
    			struct efi_open_protocol_info_entry **entry_buffer,
    			unsigned long *entry_count)
    {
    
    Rob Clark's avatar
    Rob Clark committed
    	EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, entry_buffer,
    
    		  entry_count);
    	return EFI_EXIT(EFI_NOT_FOUND);
    }
    
    static efi_status_t EFIAPI efi_protocols_per_handle(void *handle,
    			efi_guid_t ***protocol_buffer,
    			unsigned long *protocol_buffer_count)
    {
    
    	unsigned long buffer_size;
    	struct efi_object *efiobj;
    	unsigned long i, j;
    	struct list_head *lhandle;
    	efi_status_t r;
    
    
    	EFI_ENTRY("%p, %p, %p", handle, protocol_buffer,
    		  protocol_buffer_count);
    
    
    	if (!handle || !protocol_buffer || !protocol_buffer_count)
    		return EFI_EXIT(EFI_INVALID_PARAMETER);
    
    	*protocol_buffer = NULL;
    
    	*protocol_buffer_count = 0;
    
    	list_for_each(lhandle, &efi_obj_list) {
    		efiobj = list_entry(lhandle, struct efi_object, link);
    
    		if (efiobj->handle != handle)
    			continue;
    
    		/* Count protocols */
    		for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
    			if (efiobj->protocols[i].guid)
    				++*protocol_buffer_count;
    		}
    		/* Copy guids */
    		if (*protocol_buffer_count) {
    			buffer_size = sizeof(efi_guid_t *) *
    					*protocol_buffer_count;
    			r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
    					      buffer_size,
    					      (void **)protocol_buffer);
    			if (r != EFI_SUCCESS)
    				return EFI_EXIT(r);
    			j = 0;
    			for (i = 0; i < ARRAY_SIZE(efiobj->protocols); ++i) {
    				if (efiobj->protocols[i].guid) {
    					(*protocol_buffer)[j] = (void *)
    						efiobj->protocols[i].guid;
    					++j;
    				}
    			}
    		}
    		break;
    	}
    
    	return EFI_EXIT(EFI_SUCCESS);
    
    }
    
    static efi_status_t EFIAPI efi_locate_handle_buffer(
    			enum efi_locate_search_type search_type,
    			efi_guid_t *protocol, void *search_key,
    			unsigned long *no_handles, efi_handle_t **buffer)
    {
    
    	efi_status_t r;
    	unsigned long buffer_size = 0;
    
    
    Rob Clark's avatar
    Rob Clark committed
    	EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key,
    
    		  no_handles, buffer);
    
    
    	if (!no_handles || !buffer) {
    		r = EFI_INVALID_PARAMETER;
    		goto out;
    	}
    	*no_handles = 0;
    	*buffer = NULL;
    	r = efi_locate_handle(search_type, protocol, search_key, &buffer_size,
    			      *buffer);
    	if (r != EFI_BUFFER_TOO_SMALL)
    		goto out;
    	r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size,
    			      (void **)buffer);
    	if (r != EFI_SUCCESS)
    		goto out;
    	r = efi_locate_handle(search_type, protocol, search_key, &buffer_size,
    			      *buffer);
    	if (r == EFI_SUCCESS)
    		*no_handles = buffer_size / sizeof(void *);
    out:
    	return EFI_EXIT(r);
    
    }
    
    static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol,
    					       void *registration,
    					       void **protocol_interface)
    {
    
    	struct list_head *lhandle;
    
    Rob Clark's avatar
    Rob Clark committed
    	EFI_ENTRY("%pUl, %p, %p", protocol, registration, protocol_interface);
    
    
    	if (!protocol || !protocol_interface)
    		return EFI_EXIT(EFI_INVALID_PARAMETER);
    
    
    	EFI_PRINT_GUID("protocol", protocol);
    
    
    	list_for_each(lhandle, &efi_obj_list) {
    		struct efi_object *efiobj;
    
    		efiobj = list_entry(lhandle, struct efi_object, link);
    		for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
    			struct efi_handler *handler = &efiobj->protocols[i];
    
    			if (!handler->guid)
    				continue;
    			if (!guidcmp(handler->guid, protocol)) {
    				*protocol_interface =
    					handler->protocol_interface;
    				return EFI_EXIT(EFI_SUCCESS);
    			}
    
    	*protocol_interface = NULL;
    
    
    	return EFI_EXIT(EFI_NOT_FOUND);
    }
    
    static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces(
    			void **handle, ...)
    {
    	EFI_ENTRY("%p", handle);
    
    
    	va_list argptr;
    	efi_guid_t *protocol;
    	void *protocol_interface;
    	efi_status_t r = EFI_SUCCESS;
    	int i = 0;
    
    	if (!handle)
    		return EFI_EXIT(EFI_INVALID_PARAMETER);
    
    	va_start(argptr, handle);
    	for (;;) {
    		protocol = va_arg(argptr, efi_guid_t*);
    		if (!protocol)
    			break;
    		protocol_interface = va_arg(argptr, void*);
    		r = efi_install_protocol_interface(handle, protocol,
    						   EFI_NATIVE_INTERFACE,
    						   protocol_interface);
    		if (r != EFI_SUCCESS)
    			break;
    		i++;
    	}
    	va_end(argptr);
    	if (r == EFI_SUCCESS)
    		return EFI_EXIT(r);
    
    	/* If an error occured undo all changes. */
    	va_start(argptr, handle);
    	for (; i; --i) {
    		protocol = va_arg(argptr, efi_guid_t*);
    		protocol_interface = va_arg(argptr, void*);
    		efi_uninstall_protocol_interface(handle, protocol,
    						 protocol_interface);
    	}
    	va_end(argptr);
    
    	return EFI_EXIT(r);
    
    }
    
    static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
    			void *handle, ...)
    {
    	EFI_ENTRY("%p", handle);
    	return EFI_EXIT(EFI_INVALID_PARAMETER);
    }
    
    static efi_status_t EFIAPI efi_calculate_crc32(void *data,
    					       unsigned long data_size,
    					       uint32_t *crc32_p)
    {
    	EFI_ENTRY("%p, %ld", data, data_size);
    	*crc32_p = crc32(0, data, data_size);
    	return EFI_EXIT(EFI_SUCCESS);
    }
    
    static void EFIAPI efi_copy_mem(void *destination, void *source,
    				unsigned long length)
    {
    	EFI_ENTRY("%p, %p, %ld", destination, source, length);
    	memcpy(destination, source, length);
    }
    
    static void EFIAPI efi_set_mem(void *buffer, unsigned long size, uint8_t value)
    {
    	EFI_ENTRY("%p, %ld, 0x%x", buffer, size, value);
    	memset(buffer, value, size);
    }
    
    static efi_status_t EFIAPI efi_open_protocol(
    			void *handle, efi_guid_t *protocol,
    			void **protocol_interface, void *agent_handle,
    			void *controller_handle, uint32_t attributes)
    {
    	struct list_head *lhandle;
    	int i;
    
    	efi_status_t r = EFI_INVALID_PARAMETER;
    
    Rob Clark's avatar
    Rob Clark committed
    	EFI_ENTRY("%p, %pUl, %p, %p, %p, 0x%x", handle, protocol,
    
    		  protocol_interface, agent_handle, controller_handle,
    		  attributes);
    
    	if (!handle || !protocol ||
    	    (!protocol_interface && attributes !=
    	     EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) {
    		goto out;
    	}
    
    
    	EFI_PRINT_GUID("protocol", protocol);
    
    
    	switch (attributes) {
    	case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL:
    	case EFI_OPEN_PROTOCOL_GET_PROTOCOL:
    	case EFI_OPEN_PROTOCOL_TEST_PROTOCOL:
    		break;
    	case EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER:
    		if (controller_handle == handle)
    			goto out;
    	case EFI_OPEN_PROTOCOL_BY_DRIVER:
    	case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
    		if (controller_handle == NULL)
    			goto out;
    	case EFI_OPEN_PROTOCOL_EXCLUSIVE:
    		if (agent_handle == NULL)
    			goto out;
    		break;
    	default:
    
    	list_for_each(lhandle, &efi_obj_list) {
    		struct efi_object *efiobj;
    		efiobj = list_entry(lhandle, struct efi_object, link);
    
    		if (efiobj->handle != handle)
    			continue;
    
    		for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) {
    			struct efi_handler *handler = &efiobj->protocols[i];
    			const efi_guid_t *hprotocol = handler->guid;
    			if (!hprotocol)
    
    			if (!guidcmp(hprotocol, protocol)) {
    
    				if (attributes !=
    				    EFI_OPEN_PROTOCOL_TEST_PROTOCOL) {
    					*protocol_interface =
    						handler->protocol_interface;
    				}
    				r = EFI_SUCCESS;
    
    unsupported:
    	r = EFI_UNSUPPORTED;
    
    out:
    	return EFI_EXIT(r);
    }
    
    static efi_status_t EFIAPI efi_handle_protocol(void *handle,
    					       efi_guid_t *protocol,
    					       void **protocol_interface)
    {
    
    	return efi_open_protocol(handle, protocol, protocol_interface, NULL,
    				 NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
    
    }
    
    static const struct efi_boot_services efi_boot_services = {
    	.hdr = {
    		.headersize = sizeof(struct efi_table_hdr),
    	},
    	.raise_tpl = efi_raise_tpl,
    	.restore_tpl = efi_restore_tpl,
    	.allocate_pages = efi_allocate_pages_ext,
    	.free_pages = efi_free_pages_ext,
    	.get_memory_map = efi_get_memory_map_ext,
    
    	.allocate_pool = efi_allocate_pool_ext,
    
    	.free_pool = efi_free_pool_ext,
    
    	.create_event = efi_create_event_ext,
    
    	.set_timer = efi_set_timer_ext,
    
    	.wait_for_event = efi_wait_for_event,
    
    	.signal_event = efi_signal_event_ext,
    
    	.close_event = efi_close_event,
    	.check_event = efi_check_event,
    
    	.install_protocol_interface = efi_install_protocol_interface_ext,
    
    	.reinstall_protocol_interface = efi_reinstall_protocol_interface,
    
    	.uninstall_protocol_interface = efi_uninstall_protocol_interface_ext,
    
    	.handle_protocol = efi_handle_protocol,
    	.reserved = NULL,
    	.register_protocol_notify = efi_register_protocol_notify,
    
    	.locate_handle = efi_locate_handle_ext,
    
    	.locate_device_path = efi_locate_device_path,
    
    	.install_configuration_table = efi_install_configuration_table_ext,
    
    	.load_image = efi_load_image,
    	.start_image = efi_start_image,
    
    	.exit = efi_exit,
    
    	.unload_image = efi_unload_image,
    	.exit_boot_services = efi_exit_boot_services,
    	.get_next_monotonic_count = efi_get_next_monotonic_count,
    	.stall = efi_stall,
    	.set_watchdog_timer = efi_set_watchdog_timer,
    	.connect_controller = efi_connect_controller,
    	.disconnect_controller = efi_disconnect_controller,
    	.open_protocol = efi_open_protocol,
    	.close_protocol = efi_close_protocol,
    	.open_protocol_information = efi_open_protocol_information,
    	.protocols_per_handle = efi_protocols_per_handle,
    	.locate_handle_buffer = efi_locate_handle_buffer,
    	.locate_protocol = efi_locate_protocol,
    	.install_multiple_protocol_interfaces = efi_install_multiple_protocol_interfaces,
    	.uninstall_multiple_protocol_interfaces = efi_uninstall_multiple_protocol_interfaces,
    	.calculate_crc32 = efi_calculate_crc32,
    	.copy_mem = efi_copy_mem,
    	.set_mem = efi_set_mem,
    };
    
    
    
    static uint16_t __efi_runtime_data firmware_vendor[] =
    
    	{ 'D','a','s',' ','U','-','b','o','o','t',0 };
    
    
    struct efi_system_table __efi_runtime_data systab = {
    
    	.hdr = {
    		.signature = EFI_SYSTEM_TABLE_SIGNATURE,
    		.revision = 0x20005, /* 2.5 */
    		.headersize = sizeof(struct efi_table_hdr),
    	},
    	.fw_vendor = (long)firmware_vendor,
    	.con_in = (void*)&efi_con_in,
    	.con_out = (void*)&efi_con_out,
    	.std_err = (void*)&efi_con_out,
    	.runtime = (void*)&efi_runtime_services,
    	.boottime = (void*)&efi_boot_services,
    	.nr_tables = 0,
    	.tables = (void*)efi_conf_table,
    };