From 4bd064de239dab2426b31c9789a1f4d78087dc63 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 23 Aug 2020 17:52:41 +0100 Subject: [build] Fix building on older versions of gcc Older versions of gcc (observed with gcc 4.5.3) require attributes to be specified on the first declaration of a symbol, and will silently ignore attributes specified after the initial declaration. This causes the ASN.1 OID-identified algorithms to end up misaligned. Fix by adding __asn1_algorithm to the initial declarations in asn1.h. Debugged-by: Dentcho Bankov Signed-off-by: Michael Brown --- src/include/ipxe/asn1.h | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index efc66631d..7bfba6066 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -313,22 +313,27 @@ struct asn1_algorithm { #define __asn1_algorithm __table_entry ( ASN1_ALGORITHMS, 01 ) /* ASN.1 OID-identified algorithms */ -extern struct asn1_algorithm rsa_encryption_algorithm; -extern struct asn1_algorithm md5_with_rsa_encryption_algorithm; -extern struct asn1_algorithm sha1_with_rsa_encryption_algorithm; -extern struct asn1_algorithm sha256_with_rsa_encryption_algorithm; -extern struct asn1_algorithm sha384_with_rsa_encryption_algorithm; -extern struct asn1_algorithm sha512_with_rsa_encryption_algorithm; -extern struct asn1_algorithm sha224_with_rsa_encryption_algorithm; -extern struct asn1_algorithm oid_md4_algorithm; -extern struct asn1_algorithm oid_md5_algorithm; -extern struct asn1_algorithm oid_sha1_algorithm; -extern struct asn1_algorithm oid_sha256_algorithm; -extern struct asn1_algorithm oid_sha384_algorithm; -extern struct asn1_algorithm oid_sha512_algorithm; -extern struct asn1_algorithm oid_sha224_algorithm; -extern struct asn1_algorithm oid_sha512_224_algorithm; -extern struct asn1_algorithm oid_sha512_256_algorithm; +extern struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm; +extern struct asn1_algorithm md5_with_rsa_encryption_algorithm __asn1_algorithm; +extern struct asn1_algorithm +sha1_with_rsa_encryption_algorithm __asn1_algorithm; +extern struct asn1_algorithm +sha256_with_rsa_encryption_algorithm __asn1_algorithm; +extern struct asn1_algorithm +sha384_with_rsa_encryption_algorithm __asn1_algorithm; +extern struct asn1_algorithm +sha512_with_rsa_encryption_algorithm __asn1_algorithm; +extern struct asn1_algorithm +sha224_with_rsa_encryption_algorithm __asn1_algorithm; +extern struct asn1_algorithm oid_md4_algorithm __asn1_algorithm; +extern struct asn1_algorithm oid_md5_algorithm __asn1_algorithm; +extern struct asn1_algorithm oid_sha1_algorithm __asn1_algorithm; +extern struct asn1_algorithm oid_sha256_algorithm __asn1_algorithm; +extern struct asn1_algorithm oid_sha384_algorithm __asn1_algorithm; +extern struct asn1_algorithm oid_sha512_algorithm __asn1_algorithm; +extern struct asn1_algorithm oid_sha224_algorithm __asn1_algorithm; +extern struct asn1_algorithm oid_sha512_224_algorithm __asn1_algorithm; +extern struct asn1_algorithm oid_sha512_256_algorithm __asn1_algorithm; /** An ASN.1 bit string */ struct asn1_bit_string { -- cgit v1.2.3-55-g7522 From e08ad61bf78b5b9c8448ce0eac58001d617327b5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 18 Sep 2020 22:49:02 +0100 Subject: [efi] Add debug wrappers for all boot services functions of interest Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi.h | 3 +- src/interface/efi/efi_debug.c | 2 +- src/interface/efi/efi_wrap.c | 602 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 605 insertions(+), 2 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index b8777ef47..94925bab8 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -222,7 +222,8 @@ extern EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path; extern EFI_SYSTEM_TABLE *efi_systab; extern int efi_shutdown_in_progress; -extern const __attribute__ (( pure )) char * efi_guid_ntoa ( EFI_GUID *guid ); +extern const __attribute__ (( pure )) char * +efi_guid_ntoa ( CONST EFI_GUID *guid ); extern const __attribute__ (( pure )) char * efi_locate_search_type_name ( EFI_LOCATE_SEARCH_TYPE search_type ); extern const __attribute__ (( pure )) char * diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index de9b1af55..f7be9476e 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -189,7 +189,7 @@ static struct efi_well_known_guid efi_well_known_guids[] = { * @v guid GUID * @ret string Printable string */ -const __attribute__ (( pure )) char * efi_guid_ntoa ( EFI_GUID *guid ) { +const __attribute__ (( pure )) char * efi_guid_ntoa ( CONST EFI_GUID *guid ) { union { union uuid uuid; EFI_GUID guid; diff --git a/src/interface/efi/efi_wrap.c b/src/interface/efi/efi_wrap.c index c0c40eec6..ce830feeb 100644 --- a/src/interface/efi/efi_wrap.c +++ b/src/interface/efi/efi_wrap.c @@ -111,6 +111,340 @@ static const char * efi_boolean ( BOOLEAN boolean ) { return ( boolean ? "TRUE" : "FALSE" ); } +/** + * Convert EFI TPL to text + * + * @v tpl Task priority level + * @ret text Task priority level as text + */ +static const char * efi_tpl ( EFI_TPL tpl ) { + static char buf[ 19 /* "0xXXXXXXXXXXXXXXXX" + NUL */ ]; + + switch ( tpl ) { + case TPL_APPLICATION: return "Application"; + case TPL_CALLBACK: return "Callback"; + case TPL_NOTIFY: return "Notify"; + case TPL_HIGH_LEVEL: return "HighLevel"; + default: + snprintf ( buf, sizeof ( buf ), "%#lx", + ( unsigned long ) tpl ); + return buf; + } +} + +/** + * Convert EFI allocation type to text + * + * @v type Allocation type + * @ret text Allocation type as text + */ +static const char * efi_allocate_type ( EFI_ALLOCATE_TYPE type ) { + static char buf[ 11 /* "0xXXXXXXXX" + NUL */ ]; + + switch ( type ) { + case AllocateAnyPages: return "AnyPages"; + case AllocateMaxAddress: return "MaxAddress"; + case AllocateAddress: return "Address"; + default: + snprintf ( buf, sizeof ( buf ), "%#x", type ); + return buf; + } +} + +/** + * Convert EFI memory type to text + * + * @v type Memory type + * @ret text Memory type as text + */ +static const char * efi_memory_type ( EFI_MEMORY_TYPE type ) { + static char buf[ 11 /* "0xXXXXXXXX" + NUL */ ]; + + switch ( type ) { + case EfiReservedMemoryType: return "Reserved"; + case EfiLoaderCode: return "LoaderCode"; + case EfiLoaderData: return "LoaderData"; + case EfiBootServicesCode: return "BootCode"; + case EfiBootServicesData: return "BootData"; + case EfiRuntimeServicesCode: return "RuntimeCode"; + case EfiRuntimeServicesData: return "RuntimeData"; + case EfiConventionalMemory: return "Conventional"; + case EfiUnusableMemory: return "Unusable"; + case EfiACPIReclaimMemory: return "ACPIReclaim"; + case EfiACPIMemoryNVS: return "ACPINVS"; + case EfiMemoryMappedIO: return "MMIO"; + case EfiMemoryMappedIOPortSpace:return "PIO"; + case EfiPalCode: return "PalCode"; + case EfiPersistentMemory: return "Persistent"; + default: + snprintf ( buf, sizeof ( buf ), "%#x", type ); + return buf; + } +} + +/** + * Convert EFI timer delay type to text + * + * @v type Timer delay type + * @ret text Timer delay type as text + */ +static const char * efi_timer_delay ( EFI_TIMER_DELAY type ) { + static char buf[ 11 /* "0xXXXXXXXX" + NUL */ ]; + + switch ( type ) { + case TimerCancel: return "Cancel"; + case TimerPeriodic: return "Periodic"; + case TimerRelative: return "Relative"; + default: + snprintf ( buf, sizeof ( buf ), "%#x", type ); + return buf; + } +} + +/** + * Wrap RaiseTPL() + * + */ +static EFI_TPL EFIAPI +efi_raise_tpl_wrapper ( EFI_TPL new_tpl ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_TPL old_tpl; + + DBGCP ( colour, "RaiseTPL ( %s ) ", efi_tpl ( new_tpl ) ); + old_tpl = bs->RaiseTPL ( new_tpl ); + DBGCP ( colour, "= %s -> %p\n", efi_tpl ( old_tpl ), retaddr ); + return old_tpl; +} + +/** + * Wrap RestoreTPL() + * + */ +static VOID EFIAPI +efi_restore_tpl_wrapper ( EFI_TPL old_tpl ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + + DBGCP ( colour, "RestoreTPL ( %s ) ", efi_tpl ( old_tpl ) ); + bs->RestoreTPL ( old_tpl ); + DBGCP ( colour, "-> %p\n", retaddr ); +} + +/** + * Wrap AllocatePages() + * + */ +static EFI_STATUS EFIAPI +efi_allocate_pages_wrapper ( EFI_ALLOCATE_TYPE type, + EFI_MEMORY_TYPE memory_type, UINTN pages, + EFI_PHYSICAL_ADDRESS *memory ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC2 ( colour, "AllocatePages ( %s, %s, %#llx, %#llx ) ", + efi_allocate_type ( type ), efi_memory_type ( memory_type ), + ( ( unsigned long long ) pages ), + ( ( unsigned long long ) *memory ) ); + efirc = bs->AllocatePages ( type, memory_type, pages, memory ); + DBGC2 ( colour, "= %s ( %#llx ) -> %p\n", efi_status ( efirc ), + ( ( unsigned long long ) *memory ), retaddr ); + return efirc; +} + +/** + * Wrap FreePages() + * + */ +static EFI_STATUS EFIAPI +efi_free_pages_wrapper ( EFI_PHYSICAL_ADDRESS memory, UINTN pages ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC2 ( colour, "FreePages ( %#llx, %#llx ) ", + ( ( unsigned long long ) memory ), + ( ( unsigned long long ) pages ) ); + efirc = bs->FreePages ( memory, pages ); + DBGC2 ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + return efirc; +} + +/** + * Wrap GetMemoryMap() + * + */ +static EFI_STATUS EFIAPI +efi_get_memory_map_wrapper ( UINTN *memory_map_size, + EFI_MEMORY_DESCRIPTOR *memory_map, UINTN *map_key, + UINTN *descriptor_size, + UINT32 *descriptor_version ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "GetMemoryMap ( %#llx, %p ) ", + ( ( unsigned long long ) *memory_map_size ), memory_map ); + efirc = bs->GetMemoryMap ( memory_map_size, memory_map, map_key, + descriptor_size, descriptor_version ); + DBGC ( colour, "= %s ( %#llx, %#llx, %#llx, v%d ) -> %p\n", + efi_status ( efirc ), + ( ( unsigned long long ) *memory_map_size ), + ( ( unsigned long long ) *map_key ), + ( ( unsigned long long ) *descriptor_size ), + *descriptor_version, retaddr ); + return efirc; +} + +/** + * Wrap AllocatePool() + * + */ +static EFI_STATUS EFIAPI +efi_allocate_pool_wrapper ( EFI_MEMORY_TYPE pool_type, UINTN size, + VOID **buffer ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC2 ( colour, "AllocatePool ( %s, %#llx ) ", + efi_memory_type ( pool_type ), + ( ( unsigned long long ) size ) ); + efirc = bs->AllocatePool ( pool_type, size, buffer ); + DBGC2 ( colour, "= %s ( %p ) -> %p\n", + efi_status ( efirc ), *buffer, retaddr ); + return efirc; +} + +/** + * Wrap FreePool() + * + */ +static EFI_STATUS EFIAPI +efi_free_pool_wrapper ( VOID *buffer ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC2 ( colour, "FreePool ( %p ) ", buffer ); + efirc = bs->FreePool ( buffer ); + DBGC2 ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + return efirc; +} + +/** + * Wrap CreateEvent() + * + */ +static EFI_STATUS EFIAPI +efi_create_event_wrapper ( UINT32 type, EFI_TPL notify_tpl, + EFI_EVENT_NOTIFY notify_function, + VOID *notify_context, EFI_EVENT *event ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "CreateEvent ( %#x, %s, %p, %p ) ", + type, efi_tpl ( notify_tpl ), notify_function, notify_context ); + efirc = bs->CreateEvent ( type, notify_tpl, notify_function, + notify_context, event ); + DBGC ( colour, "= %s ( %p ) -> %p\n", + efi_status ( efirc ), *event, retaddr ); + return efirc; +} + +/** + * Wrap SetTimer() + * + */ +static EFI_STATUS EFIAPI +efi_set_timer_wrapper ( EFI_EVENT event, EFI_TIMER_DELAY type, + UINT64 trigger_time ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "SetTimer ( %p, %s, %ld.%07ld00s ) ", + event, efi_timer_delay ( type ), + ( ( unsigned long ) ( trigger_time / 10000000 ) ), + ( ( unsigned long ) ( trigger_time % 10000000 ) ) ); + efirc = bs->SetTimer ( event, type, trigger_time ); + DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + return efirc; +} + +/** + * Wrap WaitForEvent() + * + */ +static EFI_STATUS EFIAPI +efi_wait_for_event_wrapper ( UINTN number_of_events, EFI_EVENT *event, + UINTN *index ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + unsigned int i; + EFI_STATUS efirc; + + DBGC ( colour, "WaitForEvent (" ); + for ( i = 0 ; i < number_of_events ; i++ ) + DBGC ( colour, " %p", event[i] ); + DBGC ( colour, " ) " ); + efirc = bs->WaitForEvent ( number_of_events, event, index ); + DBGC ( colour, "= %s", efi_status ( efirc ) ); + if ( efirc == 0 ) + DBGC ( colour, " ( %p )", event[*index] ); + DBGC ( colour, " -> %p\n", retaddr ); + return efirc; +} + +/** + * Wrap SignalEvent() + * + */ +static EFI_STATUS EFIAPI +efi_signal_event_wrapper ( EFI_EVENT event ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC2 ( colour, "SignalEvent ( %p ) ", event ); + efirc = bs->SignalEvent ( event ); + DBGC2 ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + return efirc; +} + +/** + * Wrap CloseEvent() + * + */ +static EFI_STATUS EFIAPI +efi_close_event_wrapper ( EFI_EVENT event ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "CloseEvent ( %p ) ", event ); + efirc = bs->SignalEvent ( event ); + DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + return efirc; +} +/** + * Wrap CheckEvent() + * + */ +static EFI_STATUS EFIAPI +efi_check_event_wrapper ( EFI_EVENT event ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGCP ( colour, "CheckEvent ( %p ) ", event ); + efirc = bs->SignalEvent ( event ); + DBGCP ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + return efirc; +} + /** * Wrap InstallProtocolInterface() * @@ -194,6 +528,25 @@ efi_handle_protocol_wrapper ( EFI_HANDLE handle, EFI_GUID *protocol, return efirc; } +/** + * Wrap RegisterProtocolNotify() + * + */ +static EFI_STATUS EFIAPI +efi_register_protocol_notify_wrapper ( EFI_GUID *protocol, EFI_EVENT event, + VOID **registration ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "RegisterProtocolNotify ( %s, %p ) ", + efi_guid_ntoa ( protocol ), event ); + efirc = bs->RegisterProtocolNotify ( protocol, event, registration ); + DBGC ( colour, "= %s ( %p ) -> %p\n", + efi_status ( efirc ), *registration, retaddr ); + return efirc; +} + /** * Wrap LocateHandle() * @@ -248,6 +601,23 @@ efi_locate_device_path_wrapper ( EFI_GUID *protocol, return efirc; } +/** + * Wrap InstallConfigurationTable() + * + */ +static EFI_STATUS EFIAPI +efi_install_configuration_table_wrapper ( EFI_GUID *guid, VOID *table ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "InstallConfigurationTable ( %s, %p ) ", + efi_guid_ntoa ( guid ), table ); + efirc = bs->InstallConfigurationTable ( guid, table ); + DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + return efirc; +} + /** * Wrap LoadImage() * @@ -361,6 +731,61 @@ efi_exit_boot_services_wrapper ( EFI_HANDLE image_handle, UINTN map_key ) { return efirc; } +/** + * Wrap GetNextMonotonicCount() + * + */ +static EFI_STATUS EFIAPI +efi_get_next_monotonic_count_wrapper ( UINT64 *count ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGCP ( colour, "GetNextMonotonicCount() " ); + efirc = bs->GetNextMonotonicCount ( count ); + DBGCP ( colour, "= %s ( %#llx ) -> %p\n", + efi_status ( efirc ), *count, retaddr ); + return efirc; +} + +/** + * Wrap Stall() + * + */ +static EFI_STATUS EFIAPI +efi_stall_wrapper ( UINTN microseconds ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC2 ( colour, "Stall ( %ld.%06lds ) ", + ( ( unsigned long ) ( microseconds / 1000000 ) ), + ( ( unsigned long ) ( microseconds % 1000000 ) ) ); + efirc = bs->Stall ( microseconds ); + DBGC2 ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + return efirc; +} + +/** + * Wrap SetWatchdogTimer() + * + */ +static EFI_STATUS EFIAPI +efi_set_watchdog_timer_wrapper ( UINTN timeout, UINT64 watchdog_code, + UINTN data_size, CHAR16 *watchdog_data ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "SetWatchdogTimer ( %lds, %#llx, %#llx, %p ) ", + ( ( unsigned long ) timeout ), watchdog_code, + ( ( unsigned long long ) data_size ), watchdog_data ); + efirc = bs->SetWatchdogTimer ( timeout, watchdog_code, data_size, + watchdog_data ); + DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr ); + return efirc; +} + /** * Wrap ConnectController() * @@ -462,6 +887,29 @@ efi_close_protocol_wrapper ( EFI_HANDLE handle, EFI_GUID *protocol, return efirc; } +/** + * Wrap OpenProtocolInformation() + * + */ +static EFI_STATUS EFIAPI +efi_open_protocol_information_wrapper ( EFI_HANDLE handle, EFI_GUID *protocol, + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY + **entry_buffer, + UINTN *entry_count ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "OpenProtocolInformation ( %s, %s ) ", + efi_handle_name ( handle ), efi_guid_ntoa ( protocol ) ); + efirc = bs->OpenProtocolInformation ( handle, protocol, entry_buffer, + entry_count ); + DBGC ( colour, "= %s ( %p, %#llx ) -> %p\n", + efi_status ( efirc ), *entry_buffer, + ( ( unsigned long long ) *entry_count ), retaddr ); + return efirc; +} + /** * Wrap ProtocolsPerHandle() * @@ -542,6 +990,132 @@ efi_locate_protocol_wrapper ( EFI_GUID *protocol, VOID *registration, return efirc; } +/** Maximum number of interfaces for wrapped ...MultipleProtocolInterfaces() */ +#define MAX_WRAP_MULTI 20 + +/** + * Wrap InstallMultipleProtocolInterfaces() + * + */ +static EFI_STATUS EFIAPI +efi_install_multiple_protocol_interfaces_wrapper ( EFI_HANDLE *handle, ... ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_GUID *protocol[ MAX_WRAP_MULTI + 1 ]; + VOID *interface[MAX_WRAP_MULTI]; + VA_LIST ap; + unsigned int i; + EFI_STATUS efirc; + + DBGC ( colour, "InstallMultipleProtocolInterfaces ( %s", + efi_handle_name ( *handle ) ); + memset ( protocol, 0, sizeof ( protocol ) ); + memset ( interface, 0, sizeof ( interface ) ); + VA_START ( ap, handle ); + for ( i = 0 ; ( protocol[i] = VA_ARG ( ap, EFI_GUID * ) ) ; i++ ) { + if ( i == MAX_WRAP_MULTI ) { + VA_END ( ap ); + efirc = EFI_OUT_OF_RESOURCES; + DBGC ( colour, " ) = %s " + "-> %p\n", efi_status ( efirc ), retaddr ); + return efirc; + } + interface[i] = VA_ARG ( ap, VOID * ); + DBGC ( colour, ", %s, %p", + efi_guid_ntoa ( protocol[i] ), interface[i] ); + } + VA_END ( ap ); + DBGC ( colour, " ) " ); + efirc = bs->InstallMultipleProtocolInterfaces ( handle, + protocol[0], interface[0], protocol[1], interface[1], + protocol[2], interface[2], protocol[3], interface[3], + protocol[4], interface[4], protocol[5], interface[5], + protocol[6], interface[6], protocol[7], interface[7], + protocol[8], interface[8], protocol[9], interface[9], + protocol[10], interface[10], protocol[11], interface[11], + protocol[12], interface[12], protocol[13], interface[13], + protocol[14], interface[14], protocol[15], interface[15], + protocol[16], interface[16], protocol[17], interface[17], + protocol[18], interface[18], protocol[19], interface[19], + NULL ); + DBGC ( colour, "= %s ( %s ) -> %p\n", + efi_status ( efirc ), efi_handle_name ( *handle ), retaddr ); + return efirc; +} + +/** + * Wrap UninstallMultipleProtocolInterfaces() + * + */ +static EFI_STATUS EFIAPI +efi_uninstall_multiple_protocol_interfaces_wrapper ( EFI_HANDLE handle, ... ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_GUID *protocol[ MAX_WRAP_MULTI + 1 ]; + VOID *interface[MAX_WRAP_MULTI]; + VA_LIST ap; + unsigned int i; + EFI_STATUS efirc; + + DBGC ( colour, "UninstallMultipleProtocolInterfaces ( %s", + efi_handle_name ( handle ) ); + memset ( protocol, 0, sizeof ( protocol ) ); + memset ( interface, 0, sizeof ( interface ) ); + VA_START ( ap, handle ); + for ( i = 0 ; ( protocol[i] = VA_ARG ( ap, EFI_GUID * ) ) ; i++ ) { + if ( i == MAX_WRAP_MULTI ) { + VA_END ( ap ); + efirc = EFI_OUT_OF_RESOURCES; + DBGC ( colour, " ) = %s " + "-> %p\n", efi_status ( efirc ), retaddr ); + return efirc; + } + interface[i] = VA_ARG ( ap, VOID * ); + DBGC ( colour, ", %s, %p", + efi_guid_ntoa ( protocol[i] ), interface[i] ); + } + VA_END ( ap ); + DBGC ( colour, " ) " ); + efirc = bs->UninstallMultipleProtocolInterfaces ( handle, + protocol[0], interface[0], protocol[1], interface[1], + protocol[2], interface[2], protocol[3], interface[3], + protocol[4], interface[4], protocol[5], interface[5], + protocol[6], interface[6], protocol[7], interface[7], + protocol[8], interface[8], protocol[9], interface[9], + protocol[10], interface[10], protocol[11], interface[11], + protocol[12], interface[12], protocol[13], interface[13], + protocol[14], interface[14], protocol[15], interface[15], + protocol[16], interface[16], protocol[17], interface[17], + protocol[18], interface[18], protocol[19], interface[19], + NULL ); + DBGC ( colour, "= %s -> %p\n", + efi_status ( efirc ), retaddr ); + return efirc; +} + +/** + * Wrap CreateEventEx() + * + */ +static EFI_STATUS EFIAPI +efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl, + EFI_EVENT_NOTIFY notify_function, + CONST VOID *notify_context, + CONST EFI_GUID *event_group, EFI_EVENT *event ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + void *retaddr = __builtin_return_address ( 0 ); + EFI_STATUS efirc; + + DBGC ( colour, "CreateEventEx ( %#x, %s, %p, %p, %s ) ", + type, efi_tpl ( notify_tpl ), notify_function, notify_context, + efi_guid_ntoa ( event_group ) ); + efirc = bs->CreateEventEx ( type, notify_tpl, notify_function, + notify_context, event_group, event ); + DBGC ( colour, "= %s ( %p ) -> %p\n", + efi_status ( efirc ), *event, retaddr ); + return efirc; +} + /** * Wrap the calls made by a loaded image * @@ -565,6 +1139,19 @@ efi_locate_protocol_wrapper ( EFI_GUID *protocol, VOID *registration, sizeof ( efi_systab_wrapper ) ); memcpy ( &efi_bs_wrapper, bs, sizeof ( efi_bs_wrapper ) ); efi_systab_wrapper.BootServices = &efi_bs_wrapper; + efi_bs_wrapper.RaiseTPL = efi_raise_tpl_wrapper; + efi_bs_wrapper.RestoreTPL = efi_restore_tpl_wrapper; + efi_bs_wrapper.AllocatePages = efi_allocate_pages_wrapper; + efi_bs_wrapper.FreePages = efi_free_pages_wrapper; + efi_bs_wrapper.GetMemoryMap = efi_get_memory_map_wrapper; + efi_bs_wrapper.AllocatePool = efi_allocate_pool_wrapper; + efi_bs_wrapper.FreePool = efi_free_pool_wrapper; + efi_bs_wrapper.CreateEvent = efi_create_event_wrapper; + efi_bs_wrapper.SetTimer = efi_set_timer_wrapper; + efi_bs_wrapper.WaitForEvent = efi_wait_for_event_wrapper; + efi_bs_wrapper.SignalEvent = efi_signal_event_wrapper; + efi_bs_wrapper.CloseEvent = efi_close_event_wrapper; + efi_bs_wrapper.CheckEvent = efi_check_event_wrapper; efi_bs_wrapper.InstallProtocolInterface = efi_install_protocol_interface_wrapper; efi_bs_wrapper.ReinstallProtocolInterface @@ -572,24 +1159,39 @@ efi_locate_protocol_wrapper ( EFI_GUID *protocol, VOID *registration, efi_bs_wrapper.UninstallProtocolInterface = efi_uninstall_protocol_interface_wrapper; efi_bs_wrapper.HandleProtocol = efi_handle_protocol_wrapper; + efi_bs_wrapper.RegisterProtocolNotify + = efi_register_protocol_notify_wrapper; efi_bs_wrapper.LocateHandle = efi_locate_handle_wrapper; efi_bs_wrapper.LocateDevicePath = efi_locate_device_path_wrapper; + efi_bs_wrapper.InstallConfigurationTable + = efi_install_configuration_table_wrapper; efi_bs_wrapper.LoadImage = efi_load_image_wrapper; efi_bs_wrapper.StartImage = efi_start_image_wrapper; efi_bs_wrapper.Exit = efi_exit_wrapper; efi_bs_wrapper.UnloadImage = efi_unload_image_wrapper; efi_bs_wrapper.ExitBootServices = efi_exit_boot_services_wrapper; + efi_bs_wrapper.GetNextMonotonicCount + = efi_get_next_monotonic_count_wrapper; + efi_bs_wrapper.Stall = efi_stall_wrapper; + efi_bs_wrapper.SetWatchdogTimer = efi_set_watchdog_timer_wrapper; efi_bs_wrapper.ConnectController = efi_connect_controller_wrapper; efi_bs_wrapper.DisconnectController = efi_disconnect_controller_wrapper; efi_bs_wrapper.OpenProtocol = efi_open_protocol_wrapper; efi_bs_wrapper.CloseProtocol = efi_close_protocol_wrapper; + efi_bs_wrapper.OpenProtocolInformation + = efi_open_protocol_information_wrapper; efi_bs_wrapper.ProtocolsPerHandle = efi_protocols_per_handle_wrapper; efi_bs_wrapper.LocateHandleBuffer = efi_locate_handle_buffer_wrapper; efi_bs_wrapper.LocateProtocol = efi_locate_protocol_wrapper; + efi_bs_wrapper.InstallMultipleProtocolInterfaces + = efi_install_multiple_protocol_interfaces_wrapper; + efi_bs_wrapper.UninstallMultipleProtocolInterfaces + = efi_uninstall_multiple_protocol_interfaces_wrapper; + efi_bs_wrapper.CreateEventEx = efi_create_event_ex_wrapper; /* Open loaded image protocol */ if ( ( efirc = bs->OpenProtocol ( handle, -- cgit v1.2.3-55-g7522 From 371af4eef2dfa1facf6645a5704d8a55ff45c965 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 24 Sep 2020 16:58:14 +0100 Subject: [pci] Define pci_ioremap() for mapping PCI bus addresses Define pci_ioremap() as a wrapper around ioremap() that could allow for a non-zero address translation offset. Signed-off-by: Michael Brown --- src/arch/x86/core/pcidirect.c | 1 + src/arch/x86/include/ipxe/pcibios.h | 13 +++++++++++++ src/arch/x86/include/ipxe/pcidirect.h | 13 +++++++++++++ src/arch/x86/interface/pcbios/pcibios.c | 1 + src/include/ipxe/efi/efi_pci_api.h | 13 +++++++++++++ src/include/ipxe/linux/linux_pci.h | 13 +++++++++++++ src/include/ipxe/pci_io.h | 11 +++++++++++ src/interface/efi/efi_pci.c | 1 + 8 files changed, 66 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/arch/x86/core/pcidirect.c b/src/arch/x86/core/pcidirect.c index 0d09be84b..9b8226fea 100644 --- a/src/arch/x86/core/pcidirect.c +++ b/src/arch/x86/core/pcidirect.c @@ -52,3 +52,4 @@ PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword ); PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_byte ); PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word ); PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword ); +PROVIDE_PCIAPI_INLINE ( direct, pci_ioremap ); diff --git a/src/arch/x86/include/ipxe/pcibios.h b/src/arch/x86/include/ipxe/pcibios.h index 7e1bcd814..bae4eede1 100644 --- a/src/arch/x86/include/ipxe/pcibios.h +++ b/src/arch/x86/include/ipxe/pcibios.h @@ -132,4 +132,17 @@ PCIAPI_INLINE ( pcbios, pci_write_config_dword ) ( struct pci_device *pci, return pcibios_write ( pci, PCIBIOS_WRITE_CONFIG_DWORD | where, value); } +/** + * Map PCI bus address as an I/O address + * + * @v bus_addr PCI bus address + * @v len Length of region + * @ret io_addr I/O address, or NULL on error + */ +static inline __always_inline void * +PCIAPI_INLINE ( pcbios, pci_ioremap ) ( struct pci_device *pci __unused, + unsigned long bus_addr, size_t len ) { + return ioremap ( bus_addr, len ); +} + #endif /* _IPXE_PCIBIOS_H */ diff --git a/src/arch/x86/include/ipxe/pcidirect.h b/src/arch/x86/include/ipxe/pcidirect.h index d924f2f20..9570fd7d6 100644 --- a/src/arch/x86/include/ipxe/pcidirect.h +++ b/src/arch/x86/include/ipxe/pcidirect.h @@ -138,4 +138,17 @@ PCIAPI_INLINE ( direct, pci_write_config_dword ) ( struct pci_device *pci, return 0; } +/** + * Map PCI bus address as an I/O address + * + * @v bus_addr PCI bus address + * @v len Length of region + * @ret io_addr I/O address, or NULL on error + */ +static inline __always_inline void * +PCIAPI_INLINE ( direct, pci_ioremap ) ( struct pci_device *pci __unused, + unsigned long bus_addr, size_t len ) { + return ioremap ( bus_addr, len ); +} + #endif /* _PCIDIRECT_H */ diff --git a/src/arch/x86/interface/pcbios/pcibios.c b/src/arch/x86/interface/pcbios/pcibios.c index 07ac0c18d..bf812f77f 100644 --- a/src/arch/x86/interface/pcbios/pcibios.c +++ b/src/arch/x86/interface/pcbios/pcibios.c @@ -121,3 +121,4 @@ PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword ); PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_byte ); PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word ); PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword ); +PROVIDE_PCIAPI_INLINE ( pcbios, pci_ioremap ); diff --git a/src/include/ipxe/efi/efi_pci_api.h b/src/include/ipxe/efi/efi_pci_api.h index 887d5ee14..df28cef34 100644 --- a/src/include/ipxe/efi/efi_pci_api.h +++ b/src/include/ipxe/efi/efi_pci_api.h @@ -148,4 +148,17 @@ PCIAPI_INLINE ( efi, pci_write_config_dword ) ( struct pci_device *pci, value ); } +/** + * Map PCI bus address as an I/O address + * + * @v bus_addr PCI bus address + * @v len Length of region + * @ret io_addr I/O address, or NULL on error + */ +static inline __always_inline void * +PCIAPI_INLINE ( efi, pci_ioremap ) ( struct pci_device *pci __unused, + unsigned long bus_addr, size_t len ) { + return ioremap ( bus_addr, len ); +} + #endif /* _IPXE_EFI_PCI_API_H */ diff --git a/src/include/ipxe/linux/linux_pci.h b/src/include/ipxe/linux/linux_pci.h index 22ae7f1bc..76ed8f252 100644 --- a/src/include/ipxe/linux/linux_pci.h +++ b/src/include/ipxe/linux/linux_pci.h @@ -127,4 +127,17 @@ PCIAPI_INLINE ( linux, pci_write_config_dword ) ( struct pci_device *pci, return linux_pci_write ( pci, where, value, sizeof ( value ) ); } +/** + * Map PCI bus address as an I/O address + * + * @v bus_addr PCI bus address + * @v len Length of region + * @ret io_addr I/O address, or NULL on error + */ +static inline __always_inline void * +PCIAPI_INLINE ( linux, pci_ioremap ) ( struct pci_device *pci __unused, + unsigned long bus_addr, size_t len ) { + return ioremap ( bus_addr, len ); +} + #endif /* _IPXE_LINUX_PCI_H */ diff --git a/src/include/ipxe/pci_io.h b/src/include/ipxe/pci_io.h index 10e69763e..2dcdd9b28 100644 --- a/src/include/ipxe/pci_io.h +++ b/src/include/ipxe/pci_io.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include /** @@ -122,4 +123,14 @@ int pci_write_config_word ( struct pci_device *pci, unsigned int where, int pci_write_config_dword ( struct pci_device *pci, unsigned int where, uint32_t value ); +/** + * Map PCI bus address as an I/O address + * + * @v bus_addr PCI bus address + * @v len Length of region + * @ret io_addr I/O address, or NULL on error + */ +void * pci_ioremap ( struct pci_device *pci, unsigned long bus_addr, + size_t len ); + #endif /* _IPXE_PCI_IO_H */ diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index a298f2407..6a929090c 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -231,6 +231,7 @@ PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword ); PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte ); PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word ); PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword ); +PROVIDE_PCIAPI_INLINE ( efi, pci_ioremap ); /****************************************************************************** * -- cgit v1.2.3-55-g7522 From 27e886c67b63b9a381f87238ed7a856775199fd9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 24 Sep 2020 21:41:35 +0100 Subject: [efi] Use address offset as reported by EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL Retrieve the address windows and translation offsets for the appropriate PCI root bridge and use them to adjust the PCI BAR address prior to calling ioremap(). Originally-implemented-by: Pankaj Bansal Signed-off-by: Michael Brown --- src/include/ipxe/acpi.h | 132 +++++++++++++++++++++++++++++++++++++ src/include/ipxe/efi/efi_pci_api.h | 13 ---- src/interface/efi/efi_pci.c | 75 ++++++++++++++++++++- 3 files changed, 206 insertions(+), 14 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index 78f402530..e41bd2890 100644 --- a/src/include/ipxe/acpi.h +++ b/src/include/ipxe/acpi.h @@ -19,6 +19,138 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +/** An ACPI small resource descriptor header */ +struct acpi_small_resource { + /** Tag byte */ + uint8_t tag; +} __attribute__ (( packed )); + +/** ACPI small resource length mask */ +#define ACPI_SMALL_LEN_MASK 0x03 + +/** An ACPI end resource descriptor */ +#define ACPI_END_RESOURCE 0x78 + +/** An ACPI end resource descriptor */ +struct acpi_end_resource { + /** Header */ + struct acpi_small_resource hdr; + /** Checksum */ + uint8_t checksum; +} __attribute__ (( packed )); + +/** An ACPI large resource descriptor header */ +struct acpi_large_resource { + /** Tag byte */ + uint8_t tag; + /** Length of data items */ + uint16_t len; +} __attribute__ (( packed )); + +/** ACPI large resource flag */ +#define ACPI_LARGE 0x80 + +/** An ACPI QWORD address space resource descriptor */ +#define ACPI_QWORD_ADDRESS_SPACE_RESOURCE 0x8a + +/** An ACPI QWORD address space resource descriptor */ +struct acpi_qword_address_space_resource { + /** Header */ + struct acpi_large_resource hdr; + /** Resource type */ + uint8_t type; + /** General flags */ + uint8_t general; + /** Type-specific flags */ + uint8_t specific; + /** Granularity */ + uint64_t granularity; + /** Minimum address */ + uint64_t min; + /** Maximum address */ + uint64_t max; + /** Translation offset */ + uint64_t offset; + /** Length */ + uint64_t len; +} __attribute__ (( packed )); + +/** A memory address space type */ +#define ACPI_ADDRESS_TYPE_MEM 0x00 + +/** An ACPI resource descriptor */ +union acpi_resource { + /** Tag byte */ + uint8_t tag; + /** Small resource descriptor */ + struct acpi_small_resource small; + /** End resource descriptor */ + struct acpi_end_resource end; + /** Large resource descriptor */ + struct acpi_large_resource large; + /** QWORD address space resource descriptor */ + struct acpi_qword_address_space_resource qword; +}; + +/** + * Get ACPI resource tag + * + * @v res ACPI resource descriptor + * @ret tag Resource tag + */ +static inline unsigned int acpi_resource_tag ( union acpi_resource *res ) { + + return ( ( res->tag & ACPI_LARGE ) ? + res->tag : ( res->tag & ~ACPI_SMALL_LEN_MASK ) ); +} + +/** + * Get length of ACPI small resource descriptor + * + * @v res Small resource descriptor + * @ret len Length of descriptor + */ +static inline size_t acpi_small_len ( struct acpi_small_resource *res ) { + + return ( sizeof ( *res ) + ( res->tag & ACPI_SMALL_LEN_MASK ) ); +} + +/** + * Get length of ACPI large resource descriptor + * + * @v res Large resource descriptor + * @ret len Length of descriptor + */ +static inline size_t acpi_large_len ( struct acpi_large_resource *res ) { + + return ( sizeof ( *res ) + le16_to_cpu ( res->len ) ); +} + +/** + * Get length of ACPI resource descriptor + * + * @v res ACPI resource descriptor + * @ret len Length of descriptor + */ +static inline size_t acpi_resource_len ( union acpi_resource *res ) { + + return ( ( res->tag & ACPI_LARGE ) ? + acpi_large_len ( &res->large ) : + acpi_small_len ( &res->small ) ); +} + +/** + * Get next ACPI resource descriptor + * + * @v res ACPI resource descriptor + * @ret next Next ACPI resource descriptor + */ +static inline union acpi_resource * +acpi_resource_next ( union acpi_resource *res ) { + + return ( ( ( void * ) res ) + acpi_resource_len ( res ) ); +} + /** * An ACPI description header * diff --git a/src/include/ipxe/efi/efi_pci_api.h b/src/include/ipxe/efi/efi_pci_api.h index df28cef34..887d5ee14 100644 --- a/src/include/ipxe/efi/efi_pci_api.h +++ b/src/include/ipxe/efi/efi_pci_api.h @@ -148,17 +148,4 @@ PCIAPI_INLINE ( efi, pci_write_config_dword ) ( struct pci_device *pci, value ); } -/** - * Map PCI bus address as an I/O address - * - * @v bus_addr PCI bus address - * @v len Length of region - * @ret io_addr I/O address, or NULL on error - */ -static inline __always_inline void * -PCIAPI_INLINE ( efi, pci_ioremap ) ( struct pci_device *pci __unused, - unsigned long bus_addr, size_t len ) { - return ioremap ( bus_addr, len ); -} - #endif /* _IPXE_EFI_PCI_API_H */ diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 6a929090c..93a3738a9 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -224,6 +225,78 @@ int efipci_write ( struct pci_device *pci, unsigned long location, return rc; } +/** + * Map PCI bus address as an I/O address + * + * @v bus_addr PCI bus address + * @v len Length of region + * @ret io_addr I/O address, or NULL on error + */ +void * efipci_ioremap ( struct pci_device *pci, unsigned long bus_addr, + size_t len ) { + union { + union acpi_resource *res; + void *raw; + } u; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root; + EFI_HANDLE handle; + unsigned int tag; + uint64_t offset; + uint64_t start; + uint64_t end; + void *io_addr = NULL; + EFI_STATUS efirc; + int rc; + + /* Open root bridge */ + if ( ( rc = efipci_root_open ( pci, &handle, &root ) ) != 0 ) + goto err_root; + + /* Get ACPI resource descriptors */ + if ( ( efirc = root->Configuration ( root, &u.raw ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( pci, "EFIPCI " PCI_FMT " cannot get configuration: " + "%s\n", PCI_ARGS ( pci ), strerror ( rc ) ); + goto err_config; + } + + /* Parse resource descriptors */ + for ( ; ( ( tag = acpi_resource_tag ( u.res ) ) != ACPI_END_RESOURCE ) ; + u.res = acpi_resource_next ( u.res ) ) { + + /* Ignore anything other than an address space descriptor */ + if ( tag != ACPI_QWORD_ADDRESS_SPACE_RESOURCE ) + continue; + + /* Ignore descriptors that do not cover this memory range */ + if ( u.res->qword.type != ACPI_ADDRESS_TYPE_MEM ) + continue; + offset = le64_to_cpu ( u.res->qword.offset ); + start = ( offset + le64_to_cpu ( u.res->qword.min ) ); + end = ( start + le64_to_cpu ( u.res->qword.len ) ); + if ( ( bus_addr < start ) || ( ( bus_addr + len ) > end ) ) + continue; + + /* Use this address space descriptor */ + DBGC2 ( pci, "EFIPCI " PCI_FMT " %08lx+%zx -> ", + PCI_ARGS ( pci ), bus_addr, len ); + bus_addr -= offset; + DBGC2 ( pci, "%08lx\n", bus_addr ); + io_addr = ioremap ( bus_addr, len ); + break; + } + if ( ! io_addr ) { + DBGC ( pci, "EFIPCI " PCI_FMT " %08lx+%zx is not within " + "root bridge address space\n", + PCI_ARGS ( pci ), bus_addr, len ); + } + + err_config: + efipci_root_close ( handle ); + err_root: + return io_addr; +} + PROVIDE_PCIAPI_INLINE ( efi, pci_num_bus ); PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte ); PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word ); @@ -231,7 +304,7 @@ PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword ); PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte ); PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word ); PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword ); -PROVIDE_PCIAPI_INLINE ( efi, pci_ioremap ); +PROVIDE_PCIAPI ( efi, pci_ioremap, efipci_ioremap ); /****************************************************************************** * -- cgit v1.2.3-55-g7522 From 7151fa3ffac09c316e2f7c2d3d384f1417325c0f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 1 Oct 2020 15:44:05 +0100 Subject: [efi] Allow DEBUG=efi_wrap to be used independently of a loaded image Allow temporary debugging code to call efi_wrap_systab() to obtain a pointer to the wrapper EFI system table. This can then be used to e.g. forcibly overwrite the boot services table pointer used by an already loaded and running UEFI driver, in order to trace calls made by that driver. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_wrap.h | 1 + src/interface/efi/efi_wrap.c | 59 ++++++++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 25 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_wrap.h b/src/include/ipxe/efi/efi_wrap.h index d8ed1a5cc..6c7ccf2e4 100644 --- a/src/include/ipxe/efi/efi_wrap.h +++ b/src/include/ipxe/efi/efi_wrap.h @@ -10,6 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +extern EFI_SYSTEM_TABLE * efi_wrap_systab ( void ); extern void efi_wrap ( EFI_HANDLE handle ); #endif /* _IPXE_EFI_WRAP_H */ diff --git a/src/interface/efi/efi_wrap.c b/src/interface/efi/efi_wrap.c index 66d2d29bd..5c02a7ee1 100644 --- a/src/interface/efi/efi_wrap.c +++ b/src/interface/efi/efi_wrap.c @@ -37,14 +37,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -/** EFI system table wrapper */ -static EFI_SYSTEM_TABLE efi_systab_wrapper; - -/** EFI boot services table wrapper */ -static EFI_BOOT_SERVICES efi_bs_wrapper; - /** Colour for debug messages */ -#define colour &efi_systab_wrapper +#define colour &efi_systab /** * Convert EFI status code to text @@ -1135,28 +1129,17 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl, } /** - * Wrap the calls made by a loaded image + * Build table wrappers * - * @v handle Image handle + * @ret systab Wrapped system table */ - void efi_wrap ( EFI_HANDLE handle ) { +EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) { + static EFI_SYSTEM_TABLE efi_systab_wrapper; + static EFI_BOOT_SERVICES efi_bs_wrapper; EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - union { - EFI_LOADED_IMAGE_PROTOCOL *image; - void *intf; - } loaded; - EFI_STATUS efirc; - int rc; - /* Do nothing unless debugging is enabled */ - if ( ! DBG_LOG ) - return; - - /* Populate table wrappers */ - memcpy ( &efi_systab_wrapper, efi_systab, - sizeof ( efi_systab_wrapper ) ); + /* Build boot services table wrapper */ memcpy ( &efi_bs_wrapper, bs, sizeof ( efi_bs_wrapper ) ); - efi_systab_wrapper.BootServices = &efi_bs_wrapper; efi_bs_wrapper.RaiseTPL = efi_raise_tpl_wrapper; efi_bs_wrapper.RestoreTPL = efi_restore_tpl_wrapper; efi_bs_wrapper.AllocatePages = efi_allocate_pages_wrapper; @@ -1211,6 +1194,32 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl, = efi_uninstall_multiple_protocol_interfaces_wrapper; efi_bs_wrapper.CreateEventEx = efi_create_event_ex_wrapper; + /* Build system table wrapper */ + memcpy ( &efi_systab_wrapper, efi_systab, + sizeof ( efi_systab_wrapper ) ); + efi_systab_wrapper.BootServices = &efi_bs_wrapper; + + return &efi_systab_wrapper; +} + +/** + * Wrap the calls made by a loaded image + * + * @v handle Image handle + */ +void efi_wrap ( EFI_HANDLE handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_LOADED_IMAGE_PROTOCOL *image; + void *intf; + } loaded; + EFI_STATUS efirc; + int rc; + + /* Do nothing unless debugging is enabled */ + if ( ! DBG_LOG ) + return; + /* Open loaded image protocol */ if ( ( efirc = bs->OpenProtocol ( handle, &efi_loaded_image_protocol_guid, @@ -1223,7 +1232,7 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl, } /* Provide system table wrapper to image */ - loaded.image->SystemTable = &efi_systab_wrapper; + loaded.image->SystemTable = efi_wrap_systab(); DBGC ( colour, "WRAP %s at base %p has protocols:\n", efi_handle_name ( handle ), loaded.image->ImageBase ); DBGC_EFI_PROTOCOLS ( colour, handle ); -- cgit v1.2.3-55-g7522 From 02201417104c751545dda261eb33f0012703d1ff Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 1 Oct 2020 18:41:37 +0100 Subject: [efi] Fix reporting of USB supported languages array The length as returned by UsbGetSupportedLanguages() should not include the length of the descriptor header itself. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_usb.h | 4 +++- src/interface/efi/efi_usb.c | 25 +++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_usb.h b/src/include/ipxe/efi/efi_usb.h index 05b4fad00..41d9cc665 100644 --- a/src/include/ipxe/efi/efi_usb.h +++ b/src/include/ipxe/efi/efi_usb.h @@ -24,7 +24,9 @@ struct efi_usb_device { /** Configuration descriptor */ struct usb_configuration_descriptor *config; /** Supported languages */ - struct usb_descriptor_header *languages; + uint16_t *lang; + /** Length of supported languages */ + size_t lang_len; /** List of interfaces */ struct list_head interfaces; }; diff --git a/src/interface/efi/efi_usb.c b/src/interface/efi/efi_usb.c index a8c274a57..7f761145f 100644 --- a/src/interface/efi/efi_usb.c +++ b/src/interface/efi/efi_usb.c @@ -1044,9 +1044,8 @@ efi_usb_get_supported_languages ( EFI_USB_IO_PROTOCOL *usbio, DBGC2 ( usbdev, "USBDEV %s get supported languages\n", usbintf->name ); /* Return cached supported languages */ - *languages = ( ( ( void * ) usbdev->languages ) + - sizeof ( *(usbdev->languages) ) ); - *len = usbdev->languages->len; + *languages = usbdev->lang; + *len = usbdev->lang_len; return 0; } @@ -1255,7 +1254,9 @@ static int efi_usb_probe ( struct usb_function *func, struct efi_usb_interface *usbintf; struct efi_device *efidev; struct usb_descriptor_header header; + struct usb_descriptor_header *lang; size_t config_len; + size_t lang_len; unsigned int i; int rc; @@ -1275,9 +1276,12 @@ static int efi_usb_probe ( struct usb_function *func, /* Assume no strings are present */ header.len = 0; } + lang_len = ( ( header.len >= sizeof ( header ) ) ? + ( header.len - sizeof ( header ) ) : 0 ); /* Allocate and initialise structure */ - usbdev = zalloc ( sizeof ( *usbdev ) + config_len + header.len ); + usbdev = zalloc ( sizeof ( *usbdev ) + config_len + + sizeof ( *lang ) + lang_len ); if ( ! usbdev ) { rc = -ENOMEM; goto err_alloc; @@ -1288,14 +1292,15 @@ static int efi_usb_probe ( struct usb_function *func, usbdev->efidev = efidev; usbdev->config = ( ( ( void * ) usbdev ) + sizeof ( *usbdev ) ); memcpy ( usbdev->config, config, config_len ); - usbdev->languages = ( ( ( void * ) usbdev->config ) + config_len ); + lang = ( ( ( void * ) usbdev->config ) + config_len ); + usbdev->lang = ( ( ( void * ) lang ) + sizeof ( *lang ) ); + usbdev->lang_len = lang_len; INIT_LIST_HEAD ( &usbdev->interfaces ); - /* Get supported languages descriptor */ - if ( header.len && - ( rc = usb_get_descriptor ( usb, 0, USB_STRING_DESCRIPTOR, 0, 0, - usbdev->languages, - header.len ) ) != 0 ) { + /* Get supported languages descriptor, if applicable */ + if ( lang_len && + ( ( rc = usb_get_descriptor ( usb, 0, USB_STRING_DESCRIPTOR, + 0, 0, lang, header.len ) ) != 0 ) ) { DBGC ( usbdev, "USBDEV %s could not get supported languages: " "%s\n", usbdev->name, strerror ( rc ) ); goto err_get_languages; -- cgit v1.2.3-55-g7522 From ebf01660810c4ff923754323049d49d37321fd49 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 12 Oct 2020 15:21:25 +0100 Subject: [usb] Allow device halt to be cleared independently of host controller Closing and reopening a USB endpoint will clear any halt status recorded by the host controller, but may leave the endpoint halted at the device. This will cause the first packet submitted to the reopened endpoint to be lost, before the automatic stall recovery mechanism detects the halt and resets the endpoint. This is relatively harmless for USB network or HID devices, since the wire protocols will recover gracefully from dropped packets. Some protocols (e.g. for USB mass storage devices) assume zero packet loss and so would be adversely affected. Fix by allowing any device endpoint halt status to be cleared on a freshly opened endpoint. Signed-off-by: Michael Brown --- src/drivers/bus/usb.c | 45 +++++++++++++++++++++++++++++++-------------- src/include/ipxe/usb.h | 1 + 2 files changed, 32 insertions(+), 14 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index 14eabb6b4..88df9c64a 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -362,6 +362,35 @@ static int usb_endpoint_clear_tt ( struct usb_endpoint *ep ) { return 0; } +/** + * Clear endpoint halt (if applicable) + * + * @v ep USB endpoint + * @ret rc Return status code + */ +int usb_endpoint_clear_halt ( struct usb_endpoint *ep ) { + struct usb_device *usb = ep->usb; + unsigned int type; + int rc; + + /* Clear transaction translator, if applicable */ + if ( ( rc = usb_endpoint_clear_tt ( ep ) ) != 0 ) + return rc; + + /* Clear endpoint halt (if applicable) */ + type = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK ); + if ( ( type != USB_ENDPOINT_ATTR_CONTROL ) && + ( ( rc = usb_clear_feature ( usb, USB_RECIP_ENDPOINT, + USB_ENDPOINT_HALT, + ep->address ) ) != 0 ) ) { + DBGC ( usb, "USB %s %s could not clear endpoint halt: %s\n", + usb->name, usb_endpoint_name ( ep ), strerror ( rc ) ); + return rc; + } + + return 0; +} + /** * Close USB endpoint * @@ -399,27 +428,15 @@ void usb_endpoint_close ( struct usb_endpoint *ep ) { */ static int usb_endpoint_reset ( struct usb_endpoint *ep ) { struct usb_device *usb = ep->usb; - unsigned int type; int rc; /* Sanity check */ assert ( ! list_empty ( &ep->halted ) ); - /* Clear transaction translator, if applicable */ - if ( ( rc = usb_endpoint_clear_tt ( ep ) ) != 0 ) + /* Clear device halt, if applicable */ + if ( ( rc = usb_endpoint_clear_halt ( ep ) ) != 0 ) return rc; - /* Clear endpoint halt, if applicable */ - type = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK ); - if ( ( type != USB_ENDPOINT_ATTR_CONTROL ) && - ( ( rc = usb_clear_feature ( usb, USB_RECIP_ENDPOINT, - USB_ENDPOINT_HALT, - ep->address ) ) != 0 ) ) { - DBGC ( usb, "USB %s %s could not clear endpoint halt: %s\n", - usb->name, usb_endpoint_name ( ep ), strerror ( rc ) ); - return rc; - } - /* Reset endpoint */ if ( ( rc = ep->host->reset ( ep ) ) != 0 ) { DBGC ( usb, "USB %s %s could not reset: %s\n", diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index 68289d26d..a05ac613c 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -580,6 +580,7 @@ usb_endpoint_described ( struct usb_endpoint *ep, struct usb_interface_descriptor *interface, unsigned int type, unsigned int index ); extern int usb_endpoint_open ( struct usb_endpoint *ep ); +extern int usb_endpoint_clear_halt ( struct usb_endpoint *ep ); extern void usb_endpoint_close ( struct usb_endpoint *ep ); extern int usb_message ( struct usb_endpoint *ep, unsigned int request, unsigned int value, unsigned int index, -- cgit v1.2.3-55-g7522 From e30c26d01c7493a7e02e77fc80c490fc85612d5a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 12 Oct 2020 15:28:26 +0100 Subject: [usb] Allow endpoints to be refilled to a specified upper limit For USB mass storage devices, we do not want to submit more bulk IN packets than are required for the inbound data, since this will waste memory. Allow an upper limit to be specified on each refill attempt. The endpoint will be refilled to the lower of this limit or the limit specified by usb_refill_init(). Signed-off-by: Michael Brown --- src/drivers/bus/usb.c | 19 ++++++++++++++++--- src/include/ipxe/usb.h | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index 88df9c64a..70a86c913 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -651,12 +651,13 @@ int usb_prefill ( struct usb_endpoint *ep ) { } /** - * Refill endpoint + * Refill endpoint up to specified limit * * @v ep USB endpoint + * @v max Fill limit * @ret rc Return status code */ -int usb_refill ( struct usb_endpoint *ep ) { +int usb_refill_limit ( struct usb_endpoint *ep, unsigned int max ) { struct io_buffer *iobuf; size_t reserve = ep->reserve; size_t len = ( ep->len ? ep->len : ep->mtu ); @@ -667,7 +668,9 @@ int usb_refill ( struct usb_endpoint *ep ) { assert ( ep->max > 0 ); /* Refill endpoint */ - while ( ep->fill < ep->max ) { + if ( max > ep->max ) + max = ep->max; + while ( ep->fill < max ) { /* Get or allocate buffer */ if ( list_empty ( &ep->recycled ) ) { @@ -698,6 +701,16 @@ int usb_refill ( struct usb_endpoint *ep ) { return 0; } +/** + * Refill endpoint + * + * @v ep USB endpoint + * @ret rc Return status code + */ +int usb_refill ( struct usb_endpoint *ep ) { + return usb_refill_limit ( ep, ep->max ); +} + /** * Discard endpoint recycled buffer list * diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index a05ac613c..70d6daf33 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -621,6 +621,7 @@ usb_recycle ( struct usb_endpoint *ep, struct io_buffer *iobuf ) { } extern int usb_prefill ( struct usb_endpoint *ep ); +extern int usb_refill_limit ( struct usb_endpoint *ep, unsigned int max ); extern int usb_refill ( struct usb_endpoint *ep ); extern void usb_flush ( struct usb_endpoint *ep ); -- cgit v1.2.3-55-g7522 From 88288407af0e24bebdc7a6cebe93a82285bbc4a1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Oct 2020 15:29:23 +0100 Subject: [usb] Move usbio driver to end of USB driver list iPXE will often have multiple drivers available for a USB device. For example: some USB network devices will support both RNDIS and CDC-ECM, and any device may be consumed by the fallback "usbio" driver under UEFI in order to expose an EFI_USB_IO_PROTOCOL instance. The driver scoring mechanism is used to select a device configuration based on the availability of drivers for the interfaces exposed in each configuration. For the case of RNDIS versus CDC-ECM, this mechanism will always produce the correct result since RNDIS and CDC-ECM will not exist within the same configuration and so each configuration will receive a score based on the relevant driver. This guarantee does not hold for the "usbio" driver, which will match against any device. It is a surprising coincidence that the "usbio" driver seems to usually end up at the tail end of the USB drivers list, thereby resulting in the expected behaviour. Guarantee the expected behaviour by explicitly placing the "usbio" driver at the end of the USB drivers list. Signed-off-by: Michael Brown --- src/include/ipxe/usb.h | 3 +++ src/interface/efi/efi_usb.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index 70d6daf33..f41f4c355 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -1398,6 +1398,9 @@ struct usb_driver { /** Declare a USB driver */ #define __usb_driver __table_entry ( USB_DRIVERS, 01 ) +/** Declare a USB fallback driver */ +#define __usb_fallback_driver __table_entry ( USB_DRIVERS, 02 ) + /** USB driver scores */ enum usb_driver_score { /** Fallback driver (has no effect on overall score) */ diff --git a/src/interface/efi/efi_usb.c b/src/interface/efi/efi_usb.c index 7f761145f..4ddc14910 100644 --- a/src/interface/efi/efi_usb.c +++ b/src/interface/efi/efi_usb.c @@ -1355,7 +1355,7 @@ static struct usb_device_id efi_usb_ids[] = { }; /** USB I/O protocol driver */ -struct usb_driver usbio_driver __usb_driver = { +struct usb_driver usbio_driver __usb_fallback_driver = { .ids = efi_usb_ids, .id_count = ( sizeof ( efi_usb_ids ) / sizeof ( efi_usb_ids[0] ) ), .class = USB_CLASS_ID ( USB_ANY_ID, USB_ANY_ID, USB_ANY_ID ), -- cgit v1.2.3-55-g7522 From 6d680bdec59b103f84ee922ec66ae5219c939938 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 12 Oct 2020 15:31:49 +0100 Subject: [usbblk] Add support for USB mass storage devices Some UEFI BIOSes (observed with at least the Insyde UEFI BIOS on a Microsoft Surface Go) provide a very broken version of the UsbMassStorageDxe driver that is incapable of binding to the standard EFI_USB_IO_PROTOCOL instances and instead relies on an undocumented proprietary protocol (with GUID c965c76a-d71e-4e66-ab06-c6230d528425) installed by the platform's custom version of UsbCoreDxe. The upshot is that USB mass storage devices become inaccessible once iPXE's native USB host controller drivers are loaded. One possible workaround is to load a known working version of UsbMassStorageDxe (e.g. from the EDK2 tree): this driver will correctly bind to the standard EFI_USB_IO_PROTOCOL instances exposed by iPXE. This workaround is ugly in practice, since it involves embedding UsbMassStorageDxe.efi into the iPXE binary and including an embedded script to perform the required "chain UsbMassStorageDxe.efi". Provide a native USB mass storage driver for iPXE, allowing USB mass storage devices to be exposed as iPXE SAN devices. Signed-off-by: Michael Brown --- src/config/config_usb.c | 3 + src/config/defaults/efi.h | 1 + src/config/defaults/pcbios.h | 1 + src/config/usb.h | 1 + src/drivers/usb/usbblk.c | 897 +++++++++++++++++++++++++++++++++++++++++++ src/drivers/usb/usbblk.h | 121 ++++++ src/include/ipxe/errfile.h | 1 + 7 files changed, 1025 insertions(+) create mode 100644 src/drivers/usb/usbblk.c create mode 100644 src/drivers/usb/usbblk.h (limited to 'src/include/ipxe') diff --git a/src/config/config_usb.c b/src/config/config_usb.c index 17296d277..b679aeb27 100644 --- a/src/config/config_usb.c +++ b/src/config/config_usb.c @@ -53,6 +53,9 @@ REQUIRE_OBJECT ( usbio ); #ifdef USB_KEYBOARD REQUIRE_OBJECT ( usbkbd ); #endif +#ifdef USB_BLOCK +REQUIRE_OBJECT ( usbblk ); +#endif /* * Drag in USB external interfaces diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index e707dfa6a..4ae6a316e 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -39,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define USB_HCD_EHCI /* EHCI USB host controller */ #define USB_HCD_UHCI /* UHCI USB host controller */ #define USB_EFI /* Provide EFI_USB_IO_PROTOCOL interface */ +#define USB_BLOCK /* USB block devices */ #define REBOOT_CMD /* Reboot command */ diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 21821c95c..41afb9033 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -48,6 +48,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define USB_HCD_EHCI /* EHCI USB host controller */ #define USB_HCD_UHCI /* UHCI USB host controller */ #define USB_KEYBOARD /* USB keyboards */ +#define USB_BLOCK /* USB block devices */ #define REBOOT_CMD /* Reboot command */ #define CPUID_CMD /* x86 CPU feature detection command */ diff --git a/src/config/usb.h b/src/config/usb.h index d2519d877..4252ec229 100644 --- a/src/config/usb.h +++ b/src/config/usb.h @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ //#undef USB_KEYBOARD /* USB keyboards */ +//#undef USB_BLOCK /* USB block devices */ /* * USB external interfaces diff --git a/src/drivers/usb/usbblk.c b/src/drivers/usb/usbblk.c new file mode 100644 index 000000000..a68e3ced5 --- /dev/null +++ b/src/drivers/usb/usbblk.c @@ -0,0 +1,897 @@ +/* + * Copyright (C) 2020 Michael Brown . + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include "usbblk.h" + +/** @file + * + * USB mass storage driver + * + */ + +static void usbblk_stop ( struct usbblk_device *usbblk, int rc ); + +/** List of USB block devices */ +static LIST_HEAD ( usbblk_devices ); + +/****************************************************************************** + * + * Endpoint management + * + ****************************************************************************** + */ + +/** + * Open endpoints + * + * @v usbblk USB block device + * @ret rc Return status code + */ +static int usbblk_open ( struct usbblk_device *usbblk ) { + struct usb_device *usb = usbblk->func->usb; + unsigned int interface = usbblk->func->interface[0]; + int rc; + + /* Sanity checks */ + assert ( ! usbblk->in.open ); + assert ( ! usbblk->out.open ); + + /* Issue reset */ + if ( ( rc = usb_control ( usb, USBBLK_RESET, 0, interface, + NULL, 0 ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not issue reset: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_reset; + } + + /* Open bulk OUT endpoint */ + if ( ( rc = usb_endpoint_open ( &usbblk->out ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not open bulk OUT: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_open_out; + } + + /* Clear any bulk OUT halt condition */ + if ( ( rc = usb_endpoint_clear_halt ( &usbblk->out ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not reset bulk OUT: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_clear_out; + } + + /* Open bulk IN endpoint */ + if ( ( rc = usb_endpoint_open ( &usbblk->in ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not open bulk IN: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_open_in; + } + + /* Clear any bulk IN halt condition */ + if ( ( rc = usb_endpoint_clear_halt ( &usbblk->in ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not reset bulk IN: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_clear_in; + } + + return 0; + + err_clear_in: + usb_endpoint_close ( &usbblk->in ); + err_open_in: + err_clear_out: + usb_endpoint_close ( &usbblk->out ); + err_open_out: + err_reset: + return rc; +} + +/** + * Close endpoints + * + * @v usbblk USB block device + */ +static void usbblk_close ( struct usbblk_device *usbblk ) { + + /* Close bulk OUT endpoint */ + if ( usbblk->out.open ) + usb_endpoint_close ( &usbblk->out ); + + /* Close bulk IN endpoint */ + if ( usbblk->in.open ) + usb_endpoint_close ( &usbblk->in ); +} + +/****************************************************************************** + * + * Bulk OUT endpoint + * + ****************************************************************************** + */ + +/** + * Issue bulk OUT command + * + * @v usbblk USB block device + * @ret rc Return status code + */ +static int usbblk_out_command ( struct usbblk_device *usbblk ) { + struct usbblk_command *cmd = &usbblk->cmd; + struct usbblk_command_wrapper *wrapper; + struct io_buffer *iobuf; + int rc; + + /* Sanity checks */ + assert ( cmd->tag ); + assert ( ! ( cmd->scsi.data_in_len && cmd->scsi.data_out_len ) ); + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( sizeof ( *wrapper ) ); + if ( ! iobuf ) { + rc = -ENOMEM; + goto err_alloc; + } + + /* Populate command */ + wrapper = iob_put ( iobuf, sizeof ( *wrapper ) ); + memset ( wrapper, 0, sizeof ( *wrapper ) ); + wrapper->signature = cpu_to_le32 ( USBBLK_COMMAND_SIGNATURE ); + wrapper->tag = cmd->tag; /* non-endian */ + if ( cmd->scsi.data_out_len ) { + wrapper->len = cpu_to_le32 ( cmd->scsi.data_out_len ); + } else { + wrapper->len = cpu_to_le32 ( cmd->scsi.data_in_len ); + wrapper->flags = USB_DIR_IN; + } + wrapper->lun = ntohs ( cmd->scsi.lun.u16[0] ); + wrapper->cblen = sizeof ( wrapper->cb ); + memcpy ( wrapper->cb, &cmd->scsi.cdb, sizeof ( wrapper->cb ) ); + + /* Issue command */ + if ( ( rc = usb_stream ( &usbblk->out, iobuf, 0 ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s bulk OUT could not issue command: " + "%s\n", usbblk->func->name, strerror ( rc ) ); + goto err_stream; + } + + return 0; + + err_stream: + free_iob ( iobuf ); + err_alloc: + return rc; +} + +/** + * Send bulk OUT data block + * + * @v usbblk USB block device + * @ret rc Return status code + */ +static int usbblk_out_data ( struct usbblk_device *usbblk ) { + struct usbblk_command *cmd = &usbblk->cmd; + struct io_buffer *iobuf; + size_t len; + int rc; + + /* Calculate length */ + assert ( cmd->tag ); + assert ( cmd->scsi.data_out != UNULL ); + assert ( cmd->offset < cmd->scsi.data_out_len ); + len = ( cmd->scsi.data_out_len - cmd->offset ); + if ( len > USBBLK_MAX_LEN ) + len = USBBLK_MAX_LEN; + assert ( ( len % usbblk->out.mtu ) == 0 ); + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) { + rc = -ENOMEM; + goto err_alloc; + } + + /* Populate I/O buffer */ + copy_from_user ( iob_put ( iobuf, len ), cmd->scsi.data_out, + cmd->offset, len ); + + /* Send data */ + if ( ( rc = usb_stream ( &usbblk->out, iobuf, 0 ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s bulk OUT could not send data: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_stream; + } + + /* Consume data */ + cmd->offset += len; + + return 0; + + err_stream: + free_iob ( iobuf ); + err_alloc: + return rc; +} + +/** + * Refill bulk OUT endpoint + * + * @v usbblk USB block device + * @ret rc Return status code + */ +static int usbblk_out_refill ( struct usbblk_device *usbblk ) { + struct usbblk_command *cmd = &usbblk->cmd; + int rc; + + /* Sanity checks */ + assert ( cmd->tag ); + + /* Refill endpoint */ + while ( ( cmd->offset < cmd->scsi.data_out_len ) && + ( usbblk->out.fill < USBBLK_MAX_FILL ) ) { + if ( ( rc = usbblk_out_data ( usbblk ) ) != 0 ) + return rc; + } + + return 0; +} + +/** + * Complete bulk OUT transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void usbblk_out_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct usbblk_device *usbblk = + container_of ( ep, struct usbblk_device, out ); + struct usbblk_command *cmd = &usbblk->cmd; + + /* Ignore cancellations after closing endpoint */ + if ( ! ep->open ) + goto drop; + + /* Sanity check */ + assert ( cmd->tag ); + + /* Check for failures */ + if ( rc != 0 ) { + DBGC ( usbblk, "USBBLK %s bulk OUT failed: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err; + } + + /* Trigger refill process, if applicable */ + if ( cmd->offset < cmd->scsi.data_out_len ) + process_add ( &usbblk->process ); + + drop: + /* Free I/O buffer */ + free_iob ( iobuf ); + + return; + + err: + free_iob ( iobuf ); + usbblk_stop ( usbblk, rc ); +} + +/** Bulk OUT endpoint operations */ +static struct usb_endpoint_driver_operations usbblk_out_operations = { + .complete = usbblk_out_complete, +}; + +/****************************************************************************** + * + * Bulk IN endpoint + * + ****************************************************************************** + */ + +/** + * Handle bulk IN data block + * + * @v usbblk USB block device + * @v data Data block + * @v len Length of data + * @ret rc Return status code + */ +static int usbblk_in_data ( struct usbblk_device *usbblk, const void *data, + size_t len ) { + struct usbblk_command *cmd = &usbblk->cmd; + + /* Sanity checks */ + assert ( cmd->tag ); + assert ( cmd->scsi.data_in != UNULL ); + assert ( cmd->offset <= cmd->scsi.data_in_len ); + assert ( len <= ( cmd->scsi.data_in_len - cmd->offset ) ); + + /* Store data */ + copy_to_user ( cmd->scsi.data_in, cmd->offset, data, len ); + cmd->offset += len; + + return 0; +} + +/** + * Handle bulk IN status + * + * @v usbblk USB block device + * @v data Status data + * @v len Length of status data + * @ret rc Return status code + */ +static int usbblk_in_status ( struct usbblk_device *usbblk, const void *data, + size_t len ) { + struct usbblk_command *cmd = &usbblk->cmd; + const struct usbblk_status_wrapper *stat; + + /* Sanity checks */ + assert ( cmd->tag ); + + /* Validate length */ + if ( len < sizeof ( *stat ) ) { + DBGC ( usbblk, "USBBLK %s bulk IN malformed status:\n", + usbblk->func->name ); + DBGC_HDA ( usbblk, 0, data, len ); + return -EIO; + } + stat = data; + + /* Validate signature */ + if ( stat->signature != cpu_to_le32 ( USBBLK_STATUS_SIGNATURE ) ) { + DBGC ( usbblk, "USBBLK %s bulk IN invalid signature %08x:\n", + usbblk->func->name, le32_to_cpu ( stat->signature ) ); + DBGC_HDA ( usbblk, 0, stat, sizeof ( *stat ) ); + return -EIO; + } + + /* Validate tag */ + if ( stat->tag != cmd->tag ) { + DBGC ( usbblk, "USBBLK %s bulk IN tag mismatch (got %08x, " + "expected %08x):\n", + usbblk->func->name, stat->tag, cmd->tag ); + DBGC_HDA ( usbblk, 0, stat, sizeof ( *stat ) ); + return -EIO; + } + + /* Check status */ + if ( stat->status ) { + DBGC ( usbblk, "USBBLK %s bulk IN status %02x:\n", + usbblk->func->name, stat->status ); + DBGC_HDA ( usbblk, 0, stat, sizeof ( *stat ) ); + return -EIO; + } + + /* Check for residual data */ + if ( stat->residue ) { + DBGC ( usbblk, "USBBLK %s bulk IN residue %#x:\n", + usbblk->func->name, le32_to_cpu ( stat->residue ) ); + return -EIO; + } + + /* Mark command as complete */ + usbblk_stop ( usbblk, 0 ); + + return 0; +} + +/** + * Refill bulk IN endpoint + * + * @v usbblk USB block device + * @ret rc Return status code + */ +static int usbblk_in_refill ( struct usbblk_device *usbblk ) { + struct usbblk_command *cmd = &usbblk->cmd; + struct usbblk_status_wrapper *stat; + size_t remaining; + unsigned int max; + int rc; + + /* Sanity checks */ + assert ( cmd->tag ); + + /* Calculate maximum required refill */ + remaining = sizeof ( *stat ); + if ( cmd->scsi.data_in_len ) { + assert ( cmd->offset <= cmd->scsi.data_in_len ); + remaining += ( cmd->scsi.data_in_len - cmd->offset ); + } + max = ( ( remaining + USBBLK_MAX_LEN - 1 ) / USBBLK_MAX_LEN ); + + /* Refill bulk IN endpoint */ + if ( ( rc = usb_refill_limit ( &usbblk->in, max ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Complete bulk IN transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void usbblk_in_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct usbblk_device *usbblk = + container_of ( ep, struct usbblk_device, in ); + struct usbblk_command *cmd = &usbblk->cmd; + size_t remaining; + size_t len; + + /* Ignore cancellations after closing endpoint */ + if ( ! ep->open ) + goto drop; + + /* Sanity check */ + assert ( cmd->tag ); + + /* Handle errors */ + if ( rc != 0 ) { + DBGC ( usbblk, "USBBLK %s bulk IN failed: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err; + } + + /* Trigger refill process */ + process_add ( &usbblk->process ); + + /* Handle data portion, if any */ + if ( cmd->scsi.data_in_len ) { + assert ( cmd->offset <= cmd->scsi.data_in_len ); + remaining = ( cmd->scsi.data_in_len - cmd->offset ); + len = iob_len ( iobuf ); + if ( len > remaining ) + len = remaining; + if ( len ) { + if ( ( rc = usbblk_in_data ( usbblk, iobuf->data, + len ) ) != 0 ) + goto err; + iob_pull ( iobuf, len ); + } + } + + /* Handle status portion, if any */ + len = iob_len ( iobuf ); + if ( len ) { + if ( ( rc = usbblk_in_status ( usbblk, iobuf->data, + len ) ) != 0 ) + goto err; + } + + drop: + /* Free I/O buffer */ + free_iob ( iobuf ); + + return; + + err: + free_iob ( iobuf ); + usbblk_stop ( usbblk, rc ); +} + +/** Bulk IN endpoint operations */ +static struct usb_endpoint_driver_operations usbblk_in_operations = { + .complete = usbblk_in_complete, +}; + +/****************************************************************************** + * + * Refill process + * + ****************************************************************************** + */ + +/** + * Refill endpoints + * + * @v usbblk USB block device + */ +static void usbblk_step ( struct usbblk_device *usbblk ) { + + /* Refill bulk OUT endpoint */ + usbblk_out_refill ( usbblk ); + + /* Refill bulk IN endpoint */ + usbblk_in_refill ( usbblk ); +} + +/** Refill process descriptor */ +static struct process_descriptor usbblk_process_desc = + PROC_DESC ( struct usbblk_device, process, usbblk_step ); + +/****************************************************************************** + * + * SCSI command management + * + ****************************************************************************** + */ + +/** Next command tag */ +static uint16_t usbblk_tag; + +/** + * Stop SCSI command + * + * @v usbblk USB block device + * @v rc Reason for stop + */ +static void usbblk_stop ( struct usbblk_device *usbblk, int rc ) { + + /* Stop process */ + process_del ( &usbblk->process ); + + /* Reset command */ + memset ( &usbblk->cmd, 0, sizeof ( usbblk->cmd ) ); + + /* Close endpoints if an error occurred */ + if ( rc != 0 ) { + DBGC ( usbblk, "USBBLK %s closing for error recovery\n", + usbblk->func->name ); + usbblk_close ( usbblk ); + } + + /* Terminate command */ + intf_restart ( &usbblk->data, rc ); +} + +/** + * Start new SCSI command + * + * @v usbblk USB block device + * @v scsicmd SCSI command + * @ret rc Return status code + */ +static int usbblk_start ( struct usbblk_device *usbblk, + struct scsi_cmd *scsicmd ) { + struct usbblk_command *cmd = &usbblk->cmd; + int rc; + + /* Fail if command is in progress */ + if ( cmd->tag ) { + rc = -EBUSY; + DBGC ( usbblk, "USBBLK %s cannot support multiple commands\n", + usbblk->func->name ); + goto err_busy; + } + + /* Refuse bidirectional commands */ + if ( scsicmd->data_in_len && scsicmd->data_out_len ) { + rc = -EOPNOTSUPP; + DBGC ( usbblk, "USBBLK %s cannot support bidirectional " + "commands\n", usbblk->func->name ); + goto err_bidirectional; + } + + /* Sanity checks */ + assert ( ! process_running ( &usbblk->process ) ); + assert ( cmd->offset == 0 ); + + /* Initialise command */ + memcpy ( &cmd->scsi, scsicmd, sizeof ( cmd->scsi ) ); + cmd->tag = ( USBBLK_TAG_MAGIC | ++usbblk_tag ); + + /* Issue bulk OUT command */ + if ( ( rc = usbblk_out_command ( usbblk ) ) != 0 ) + goto err_command; + + /* Start refill process */ + process_add ( &usbblk->process ); + + return 0; + + err_command: + memset ( &usbblk->cmd, 0, sizeof ( usbblk->cmd ) ); + err_bidirectional: + err_busy: + return rc; +} + +/****************************************************************************** + * + * SCSI interfaces + * + ****************************************************************************** + */ + +/** SCSI data interface operations */ +static struct interface_operation usbblk_data_operations[] = { + INTF_OP ( intf_close, struct usbblk_device *, usbblk_stop ), +}; + +/** SCSI data interface descriptor */ +static struct interface_descriptor usbblk_data_desc = + INTF_DESC ( struct usbblk_device, data, usbblk_data_operations ); + +/** + * Check SCSI command flow-control window + * + * @v usbblk USB block device + * @ret len Length of window + */ +static size_t usbblk_scsi_window ( struct usbblk_device *usbblk ) { + struct usbblk_command *cmd = &usbblk->cmd; + + /* Allow a single command if no command is currently in progress */ + return ( cmd->tag ? 0 : 1 ); +} + +/** + * Issue SCSI command + * + * @v usbblk USB block device + * @v data SCSI data interface + * @v scsicmd SCSI command + * @ret tag Command tag, or negative error + */ +static int usbblk_scsi_command ( struct usbblk_device *usbblk, + struct interface *data, + struct scsi_cmd *scsicmd ) { + struct usbblk_command *cmd = &usbblk->cmd; + int rc; + + /* (Re)open endpoints if needed */ + if ( ( ! usbblk->in.open ) && ( ( rc = usbblk_open ( usbblk ) ) != 0 ) ) + goto err_open; + + /* Start new command */ + if ( ( rc = usbblk_start ( usbblk, scsicmd ) ) != 0 ) + goto err_start; + + /* Attach to parent interface and return */ + intf_plug_plug ( &usbblk->data, data ); + return cmd->tag; + + usbblk_stop ( usbblk, rc ); + err_start: + usbblk_close ( usbblk ); + err_open: + return rc; +} + +/** + * Close SCSI interface + * + * @v usbblk USB block device + * @v rc Reason for close + */ +static void usbblk_scsi_close ( struct usbblk_device *usbblk, int rc ) { + + /* Restart interfaces */ + intfs_restart ( rc, &usbblk->scsi, &usbblk->data, NULL ); + + /* Stop any in-progress command */ + usbblk_stop ( usbblk, rc ); + + /* Close endpoints */ + usbblk_close ( usbblk ); + + /* Flag as closed */ + usbblk->opened = 0; +} + +/** SCSI command interface operations */ +static struct interface_operation usbblk_scsi_operations[] = { + INTF_OP ( scsi_command, struct usbblk_device *, usbblk_scsi_command ), + INTF_OP ( xfer_window, struct usbblk_device *, usbblk_scsi_window ), + INTF_OP ( intf_close, struct usbblk_device *, usbblk_scsi_close ), +}; + +/** SCSI command interface descriptor */ +static struct interface_descriptor usbblk_scsi_desc = + INTF_DESC ( struct usbblk_device, scsi, usbblk_scsi_operations ); + +/****************************************************************************** + * + * SAN device interface + * + ****************************************************************************** + */ + +/** + * Find USB block device + * + * @v name USB block device name + * @ret usbblk USB block device, or NULL + */ +static struct usbblk_device * usbblk_find ( const char *name ) { + struct usbblk_device *usbblk; + + /* Look for matching device */ + list_for_each_entry ( usbblk, &usbblk_devices, list ) { + if ( strcmp ( usbblk->func->name, name ) == 0 ) + return usbblk; + } + + return NULL; +} + +/** + * Open USB block device URI + * + * @v parent Parent interface + * @v uri URI + * @ret rc Return status code + */ +static int usbblk_open_uri ( struct interface *parent, struct uri *uri ) { + static struct scsi_lun lun; + struct usbblk_device *usbblk; + int rc; + + /* Sanity check */ + if ( ! uri->opaque ) + return -EINVAL; + + /* Find matching device */ + usbblk = usbblk_find ( uri->opaque ); + if ( ! usbblk ) + return -ENOENT; + + /* Fail if device is already open */ + if ( usbblk->opened ) + return -EBUSY; + + /* Open SCSI device */ + if ( ( rc = scsi_open ( parent, &usbblk->scsi, &lun ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not open SCSI device: %s\n", + usbblk->func->name, strerror ( rc ) ); + return rc; + } + + /* Mark as opened */ + usbblk->opened = 1; + + return 0; +} + +/** USB block device URI opener */ +struct uri_opener usbblk_uri_opener __uri_opener = { + .scheme = "usb", + .open = usbblk_open_uri, +}; + +/****************************************************************************** + * + * USB interface + * + ****************************************************************************** + */ + +/** + * Probe device + * + * @v func USB function + * @v config Configuration descriptor + * @ret rc Return status code + */ +static int usbblk_probe ( struct usb_function *func, + struct usb_configuration_descriptor *config ) { + struct usb_device *usb = func->usb; + struct usbblk_device *usbblk; + struct usb_interface_descriptor *desc; + int rc; + + /* Allocate and initialise structure */ + usbblk = zalloc ( sizeof ( *usbblk ) ); + if ( ! usbblk ) { + rc = -ENOMEM; + goto err_alloc; + } + usbblk->func = func; + usb_endpoint_init ( &usbblk->out, usb, &usbblk_out_operations ); + usb_endpoint_init ( &usbblk->in, usb, &usbblk_in_operations ); + usb_refill_init ( &usbblk->in, 0, USBBLK_MAX_LEN, USBBLK_MAX_FILL ); + intf_init ( &usbblk->scsi, &usbblk_scsi_desc, &usbblk->refcnt ); + intf_init ( &usbblk->data, &usbblk_data_desc, &usbblk->refcnt ); + process_init_stopped ( &usbblk->process, &usbblk_process_desc, + &usbblk->refcnt ); + + /* Locate interface descriptor */ + desc = usb_interface_descriptor ( config, func->interface[0], 0 ); + if ( ! desc ) { + DBGC ( usbblk, "USBBLK %s missing interface descriptor\n", + usbblk->func->name ); + rc = -ENOENT; + goto err_desc; + } + + /* Describe endpoints */ + if ( ( rc = usb_endpoint_described ( &usbblk->out, config, desc, + USB_BULK_OUT, 0 ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not describe bulk OUT: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_out; + } + if ( ( rc = usb_endpoint_described ( &usbblk->in, config, desc, + USB_BULK_IN, 0 ) ) != 0 ) { + DBGC ( usbblk, "USBBLK %s could not describe bulk IN: %s\n", + usbblk->func->name, strerror ( rc ) ); + goto err_in; + } + + /* Add to list of devices */ + list_add_tail ( &usbblk->list, &usbblk_devices ); + + usb_func_set_drvdata ( func, usbblk ); + return 0; + + err_in: + err_out: + err_desc: + ref_put ( &usbblk->refcnt ); + err_alloc: + return rc; +} + +/** + * Remove device + * + * @v func USB function + */ +static void usbblk_remove ( struct usb_function *func ) { + struct usbblk_device *usbblk = usb_func_get_drvdata ( func ); + + /* Remove from list of devices */ + list_del ( &usbblk->list ); + + /* Close all interfaces */ + usbblk_scsi_close ( usbblk, -ENODEV ); + + /* Shut down interfaces */ + intfs_shutdown ( -ENODEV, &usbblk->scsi, &usbblk->data, NULL ); + + /* Drop reference */ + ref_put ( &usbblk->refcnt ); +} + +/** Mass storage class device IDs */ +static struct usb_device_id usbblk_ids[] = { + { + .name = "usbblk", + .vendor = USB_ANY_ID, + .product = USB_ANY_ID, + }, +}; + +/** Mass storage driver */ +struct usb_driver usbblk_driver __usb_driver = { + .ids = usbblk_ids, + .id_count = ( sizeof ( usbblk_ids ) / sizeof ( usbblk_ids[0] ) ), + .class = USB_CLASS_ID ( USB_CLASS_MSC, USB_SUBCLASS_MSC_SCSI, + USB_PROTOCOL_MSC_BULK ), + .score = USB_SCORE_NORMAL, + .probe = usbblk_probe, + .remove = usbblk_remove, +}; diff --git a/src/drivers/usb/usbblk.h b/src/drivers/usb/usbblk.h new file mode 100644 index 000000000..65d0705e3 --- /dev/null +++ b/src/drivers/usb/usbblk.h @@ -0,0 +1,121 @@ +#ifndef _USBBLK_H +#define _USBBLK_H + +/** @file + * + * USB mass storage driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include + +/** Mass storage class code */ +#define USB_CLASS_MSC 0x08 + +/** SCSI command set subclass code */ +#define USB_SUBCLASS_MSC_SCSI 0x06 + +/** Bulk-only transport protocol */ +#define USB_PROTOCOL_MSC_BULK 0x50 + +/** Mass storage reset command */ +#define USBBLK_RESET ( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE | \ + USB_REQUEST_TYPE ( 255 ) ) + +/** Command block wrapper */ +struct usbblk_command_wrapper { + /** Signature */ + uint32_t signature; + /** Tag */ + uint32_t tag; + /** Data transfer length */ + uint32_t len; + /** Flags */ + uint8_t flags; + /** LUN */ + uint8_t lun; + /** Command block length */ + uint8_t cblen; + /** Command block */ + uint8_t cb[16]; +} __attribute__ (( packed )); + +/** Command block wrapper signature */ +#define USBBLK_COMMAND_SIGNATURE 0x43425355UL + +/** Command status wrapper */ +struct usbblk_status_wrapper { + /** Signature */ + uint32_t signature; + /** Tag */ + uint32_t tag; + /** Data residue */ + uint32_t residue; + /** Status */ + uint8_t status; +} __attribute__ (( packed )); + +/** Command status wrapper signature */ +#define USBBLK_STATUS_SIGNATURE 0x53425355UL + +/** A USB mass storage command */ +struct usbblk_command { + /** SCSI command */ + struct scsi_cmd scsi; + /** Command tag (0 for no command in progress) */ + uint32_t tag; + /** Offset within data buffer */ + size_t offset; +}; + +/** A USB mass storage device */ +struct usbblk_device { + /** Reference count */ + struct refcnt refcnt; + /** List of devices */ + struct list_head list; + + /** USB function */ + struct usb_function *func; + /** Bulk OUT endpoint */ + struct usb_endpoint out; + /** Bulk IN endpoint */ + struct usb_endpoint in; + + /** SCSI command-issuing interface */ + struct interface scsi; + /** SCSI data interface */ + struct interface data; + /** Command process */ + struct process process; + /** Device opened flag */ + int opened; + + /** Current command (if any) */ + struct usbblk_command cmd; +}; + +/** Command tag magic + * + * This is a policy decision. + */ +#define USBBLK_TAG_MAGIC 0x18ae0000 + +/** Maximum length of USB data block + * + * This is a policy decision. + */ +#define USBBLK_MAX_LEN 2048 + +/** Maximum endpoint fill level + * + * This is a policy decision. + */ +#define USBBLK_MAX_FILL 4 + +#endif /* _USBBLK_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 242f91f82..8238d4925 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -208,6 +208,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_intelxl ( ERRFILE_DRIVER | 0x00cb0000 ) #define ERRFILE_pcimsix ( ERRFILE_DRIVER | 0x00cc0000 ) #define ERRFILE_intelxlvf ( ERRFILE_DRIVER | 0x00cd0000 ) +#define ERRFILE_usbblk ( ERRFILE_DRIVER | 0x00ce0000 ) #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) -- cgit v1.2.3-55-g7522 From c504c1d6937a07b038ad21646eaec51f34684736 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 16 Oct 2020 14:59:36 +0100 Subject: [interface] Allow for the definition of an unused interface operation Allow an interface operation to be declared as unused. This will perform full type-checking and compilation of the implementing method, without including any code in the resulting object (other than a NULL entry in the interface operations table). The intention is to provide a relatively clean way for interface operation methods to be omitted in builds for which the operation is not required (such as an operation to describe an object using an EFI device path, which would not be required in a non-EFI build). Signed-off-by: Michael Brown --- src/include/ipxe/interface.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/interface.h b/src/include/ipxe/interface.h index b65002c80..9281aeef5 100644 --- a/src/include/ipxe/interface.h +++ b/src/include/ipxe/interface.h @@ -36,6 +36,21 @@ struct interface_operation { ? op_func : op_func ), \ } +/** + * Define an unused object interface operation + * + * @v op_type Operation type + * @v object_type Implementing method's expected object type + * @v op_func Implementing method + * @ret op Object interface operation + */ +#define UNUSED_INTF_OP( op_type, object_type, op_func ) { \ + .type = NULL, \ + .func = ( ( ( ( typeof ( op_func ) * ) NULL ) == \ + ( ( op_type ## _TYPE ( object_type ) * ) NULL ) ) \ + ? NULL : NULL ), \ + } + /** An object interface descriptor */ struct interface_descriptor { /** Offset of interface within containing object */ -- cgit v1.2.3-55-g7522 From bcf858c56da382337eec4601f36db619a79a1d8e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 16 Oct 2020 15:02:46 +0100 Subject: [efi] Provide EFI_INTF_OP for EFI-only interface operations Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index 94925bab8..62609b4b3 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -275,6 +275,13 @@ extern void dbg_efi_protocols ( EFI_HANDLE handle ); #define DBGCP_EFI_PROTOCOLS( ... ) \ DBGC_EFI_PROTOCOLS_IF ( PROFILE, ##__VA_ARGS__ ) +/* Allow for EFI-only interface operations */ +#ifdef PLATFORM_efi +#define EFI_INTF_OP INTF_OP +#else +#define EFI_INTF_OP UNUSED_INTF_OP +#endif + extern unsigned long __stack_chk_guard; extern unsigned long efi_stack_cookie ( EFI_HANDLE handle ); extern void __stack_chk_fail ( void ); -- cgit v1.2.3-55-g7522 From 2bf0fd39cafcfaf9a2a66f1f22bbe36640a72b6c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 16 Oct 2020 14:12:56 +0100 Subject: [efi] Split device path functions out to efi_path.c Signed-off-by: Michael Brown --- src/drivers/usb/usbio.c | 5 ++-- src/image/efi_image.c | 4 +-- src/include/ipxe/efi/efi_path.h | 19 ++++++++++++++ src/include/ipxe/efi/efi_utils.h | 4 --- src/interface/efi/efi_block.c | 8 +++--- src/interface/efi/efi_debug.c | 4 +-- src/interface/efi/efi_driver.c | 4 +-- src/interface/efi/efi_init.c | 4 +-- src/interface/efi/efi_local.c | 4 +-- src/interface/efi/efi_path.c | 57 ++++++++++++++++++++++++++++++++++++++++ src/interface/efi/efi_snp.c | 3 ++- src/interface/efi/efi_snp_hii.c | 3 ++- src/interface/efi/efi_usb.c | 4 +-- src/interface/efi/efi_utils.c | 30 --------------------- 14 files changed, 99 insertions(+), 54 deletions(-) create mode 100644 src/include/ipxe/efi/efi_path.h create mode 100644 src/interface/efi/efi_path.c (limited to 'src/include/ipxe') diff --git a/src/drivers/usb/usbio.c b/src/drivers/usb/usbio.c index dfb93dab1..278b43cd3 100644 --- a/src/drivers/usb/usbio.c +++ b/src/drivers/usb/usbio.c @@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -206,7 +207,7 @@ static int usbio_open ( struct usbio_device *usbio, unsigned int interface ) { path = usbio->path; usbpath = usbio->usbpath; usbpath->InterfaceNumber = interface; - end = efi_devpath_end ( path ); + end = efi_path_end ( path ); /* Locate handle for this endpoint's interface */ if ( ( efirc = bs->LocateDevicePath ( &efi_usb_io_protocol_guid, &path, @@ -1503,7 +1504,7 @@ static int usbio_path ( struct usbio_device *usbio ) { path = u.interface; /* Locate end of device path and sanity check */ - len = efi_devpath_len ( path ); + len = efi_path_len ( path ); if ( len < sizeof ( *usbpath ) ) { DBGC ( usbio, "USBIO %s underlength device path\n", efi_handle_name ( handle ) ); diff --git a/src/image/efi_image.c b/src/image/efi_image.c index 942b7aeeb..3c98decbf 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include +#include #include #include #include @@ -75,7 +75,7 @@ efi_image_path ( struct image *image, EFI_DEVICE_PATH_PROTOCOL *parent ) { size_t len; /* Calculate device path lengths */ - prefix_len = efi_devpath_len ( parent ); + prefix_len = efi_path_len ( parent ); name_len = strlen ( image->name ); filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH + ( name_len + 1 /* NUL */ ) * sizeof ( wchar_t ) ); diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h new file mode 100644 index 000000000..f8b95fd21 --- /dev/null +++ b/src/include/ipxe/efi/efi_path.h @@ -0,0 +1,19 @@ +#ifndef _IPXE_EFI_PATH_H +#define _IPXE_EFI_PATH_H + +/** @file + * + * EFI device paths + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +extern EFI_DEVICE_PATH_PROTOCOL * +efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ); + +#endif /* _IPXE_EFI_PATH_H */ diff --git a/src/include/ipxe/efi/efi_utils.h b/src/include/ipxe/efi/efi_utils.h index 67acba17e..270d38dc8 100644 --- a/src/include/ipxe/efi/efi_utils.h +++ b/src/include/ipxe/efi/efi_utils.h @@ -9,13 +9,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include -#include struct device; -extern EFI_DEVICE_PATH_PROTOCOL * -efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ); -extern size_t efi_devpath_len ( EFI_DEVICE_PATH_PROTOCOL *path ); extern int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol, EFI_HANDLE *parent ); extern int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ); diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 0024fbbea..a63bc9ccf 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -54,7 +54,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include /** ACPI table protocol protocol */ @@ -288,7 +288,7 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, } /* Calculate length of private data */ - prefix_len = efi_devpath_len ( snpdev->path ); + prefix_len = efi_path_len ( snpdev->path ); uri_len = format_uri ( uris[0], NULL, 0 ); vendor_len = ( sizeof ( *vendor ) + ( ( uri_len + 1 /* NUL */ ) * sizeof ( wchar_t ) ) ); @@ -551,7 +551,7 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, } /* Check if this device is a child of our block device */ - prefix_len = efi_devpath_len ( block->path ); + prefix_len = efi_path_len ( block->path ); if ( memcmp ( path.path, block->path, prefix_len ) != 0 ) { /* Not a child device */ rc = -ENOTTY; @@ -561,7 +561,7 @@ static int efi_block_boot_image ( struct san_device *sandev, EFI_HANDLE handle, sandev->drive, efi_devpath_text ( path.path ) ); /* Construct device path for boot image */ - end = efi_devpath_end ( path.path ); + end = efi_path_end ( path.path ); prefix_len = ( ( ( void * ) end ) - ( ( void * ) path.path ) ); filepath_len = ( SIZE_OF_FILEPATH_DEVICE_PATH + ( filename ? diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index f7be9476e..7cff14614 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include #include #include @@ -378,7 +378,7 @@ efi_devpath_text ( EFI_DEVICE_PATH_PROTOCOL *path ) { /* If we have no DevicePathToText protocol then use a raw hex string */ if ( ! efidpt ) { DBG ( "[No DevicePathToText]" ); - len = efi_devpath_len ( path ); + len = efi_path_len ( path ); base16_encode ( path, len, text, sizeof ( text ) ); return text; } diff --git a/src/interface/efi/efi_driver.c b/src/interface/efi/efi_driver.c index a6c0f3032..8388dd535 100644 --- a/src/interface/efi/efi_driver.c +++ b/src/interface/efi/efi_driver.c @@ -30,7 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include +#include #include /** @file @@ -202,7 +202,7 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, efi_handle_name ( device ), strerror ( rc ) ); goto err_open_path; } - path_len = ( efi_devpath_len ( path.path ) + sizeof ( *path_end ) ); + path_len = ( efi_path_len ( path.path ) + sizeof ( *path_end ) ); /* Allocate and initialise structure */ efidev = zalloc ( sizeof ( *efidev ) + path_len ); diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c index 70212b184..6d46c5669 100644 --- a/src/interface/efi/efi_init.c +++ b/src/interface/efi/efi_init.c @@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include +#include #include /** Image handle passed to entry point */ @@ -252,7 +252,7 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle, * path, since the device handle itself may become invalidated * when we load our own drivers. */ - device_path_len = ( efi_devpath_len ( device_path ) + + device_path_len = ( efi_path_len ( device_path ) + sizeof ( EFI_DEVICE_PATH_PROTOCOL ) ); if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, device_path_len, &device_path_copy ) ) != 0 ) { diff --git a/src/interface/efi/efi_local.c b/src/interface/efi/efi_local.c index 617895650..4ebca5726 100644 --- a/src/interface/efi/efi_local.c +++ b/src/interface/efi/efi_local.c @@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include #include #include @@ -425,7 +425,7 @@ static int efi_local_open_resolved ( struct efi_local *local, static int efi_local_open_path ( struct efi_local *local, const char *path ) { FILEPATH_DEVICE_PATH *fp = container_of ( efi_loaded_image->FilePath, FILEPATH_DEVICE_PATH, Header); - size_t fp_len = ( fp ? efi_devpath_len ( &fp->Header ) : 0 ); + size_t fp_len = ( fp ? efi_path_len ( &fp->Header ) : 0 ); char base[ fp_len / 2 /* Cannot exceed this length */ ]; size_t remaining = sizeof ( base ); size_t len; diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c new file mode 100644 index 000000000..1b297567c --- /dev/null +++ b/src/interface/efi/efi_path.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include + +/** @file + * + * EFI device paths + * + */ + +/** + * Find end of device path + * + * @v path Path to device + * @ret path_end End of device path + */ +EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ) { + + while ( path->Type != END_DEVICE_PATH_TYPE ) { + path = ( ( ( void * ) path ) + + /* There's this amazing new-fangled thing known as + * a UINT16, but who wants to use one of those? */ + ( ( path->Length[1] << 8 ) | path->Length[0] ) ); + } + + return path; +} + +/** + * Find length of device path (excluding terminator) + * + * @v path Path to device + * @ret path_len Length of device path + */ +size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { + EFI_DEVICE_PATH_PROTOCOL *end = efi_path_end ( path ); + + return ( ( ( void * ) end ) - ( ( void * ) path ) ); +} diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index d648700f6..f5c736a11 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -1714,7 +1715,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { "%s", netdev->name ); /* Allocate the new device path */ - path_prefix_len = efi_devpath_len ( efidev->path ); + path_prefix_len = efi_path_len ( efidev->path ); snpdev->path = zalloc ( path_prefix_len + sizeof ( *macpath ) + sizeof ( *vlanpath ) + sizeof ( *path_end ) ); if ( ! snpdev->path ) { diff --git a/src/interface/efi/efi_snp_hii.c b/src/interface/efi/efi_snp_hii.c index 1e681a429..05c068a8c 100644 --- a/src/interface/efi/efi_snp_hii.c +++ b/src/interface/efi/efi_snp_hii.c @@ -63,6 +63,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include @@ -680,7 +681,7 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { } /* Allocate the new device path */ - path_prefix_len = efi_devpath_len ( snpdev->path ); + path_prefix_len = efi_path_len ( snpdev->path ); snpdev->hii_child_path = zalloc ( path_prefix_len + sizeof ( *vendor_path ) + sizeof ( *path_end ) ); diff --git a/src/interface/efi/efi_usb.c b/src/interface/efi/efi_usb.c index 4ddc14910..7ffeb7ffa 100644 --- a/src/interface/efi/efi_usb.c +++ b/src/interface/efi/efi_usb.c @@ -30,7 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include #include #include @@ -1120,7 +1120,7 @@ static int efi_usb_install ( struct efi_usb_device *usbdev, /* Calculate device path length */ path_count = ( usb_depth ( usbdev->usb ) + 1 ); - path_prefix_len = efi_devpath_len ( efidev->path ); + path_prefix_len = efi_path_len ( efidev->path ); path_len = ( path_prefix_len + ( path_count * sizeof ( *usbpath ) ) + sizeof ( *path_end ) ); diff --git a/src/interface/efi/efi_utils.c b/src/interface/efi/efi_utils.c index 4dc75414c..f8ffce915 100644 --- a/src/interface/efi/efi_utils.c +++ b/src/interface/efi/efi_utils.c @@ -32,36 +32,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** - * Find end of device path - * - * @v path Path to device - * @ret path_end End of device path - */ -EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) { - - while ( path->Type != END_DEVICE_PATH_TYPE ) { - path = ( ( ( void * ) path ) + - /* There's this amazing new-fangled thing known as - * a UINT16, but who wants to use one of those? */ - ( ( path->Length[1] << 8 ) | path->Length[0] ) ); - } - - return path; -} - -/** - * Find length of device path (excluding terminator) - * - * @v path Path to device - * @ret path_len Length of device path - */ -size_t efi_devpath_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { - EFI_DEVICE_PATH_PROTOCOL *end = efi_devpath_end ( path ); - - return ( ( ( void * ) end ) - ( ( void * ) path ) ); -} - /** * Locate parent device supporting a given protocol * -- cgit v1.2.3-55-g7522 From 2091288eaa5b3b6144afba193f44cce985705e79 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 16 Oct 2020 15:09:52 +0100 Subject: [efi] Define an interface operation to describe using an EFI device path Allow arbitrary objects to support describing themselves using an EFI device path. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 5 +++++ src/interface/efi/efi_path.c | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index f8b95fd21..0d5b902e5 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -9,6 +9,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include @@ -16,4 +17,8 @@ extern EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ); extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern EFI_DEVICE_PATH_PROTOCOL * efi_describe ( struct interface *interface ); +#define efi_describe_TYPE( object_type ) \ + typeof ( EFI_DEVICE_PATH_PROTOCOL * ( object_type ) ) + #endif /* _IPXE_EFI_PATH_H */ diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 1b297567c..fa4306020 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -55,3 +55,29 @@ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { return ( ( ( void * ) end ) - ( ( void * ) path ) ); } + +/** + * Describe object as an EFI device path + * + * @v intf Interface + * @ret path EFI device path, or NULL + * + * The caller is responsible for eventually calling free() on the + * allocated device path. + */ +EFI_DEVICE_PATH_PROTOCOL * efi_describe ( struct interface *intf ) { + struct interface *dest; + efi_describe_TYPE ( void * ) *op = + intf_get_dest_op ( intf, efi_describe, &dest ); + void *object = intf_object ( dest ); + EFI_DEVICE_PATH_PROTOCOL *path; + + if ( op ) { + path = op ( object ); + } else { + path = NULL; + } + + intf_put ( dest ); + return path; +} -- cgit v1.2.3-55-g7522 From 87e39a9c9345e177c46f74dc1e3d6d94136315be Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 16 Oct 2020 15:07:14 +0100 Subject: [efi] Split efi_usb_path() out to a separate function Provide efi_usb_path() as a standalone function, to allow for reuse by the USB mass storage driver. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 3 ++ src/include/ipxe/efi/efi_usb.h | 6 ++-- src/interface/efi/efi_path.c | 60 +++++++++++++++++++++++++++++++++ src/interface/efi/efi_usb.c | 74 +++++++++++++---------------------------- 4 files changed, 89 insertions(+), 54 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index 0d5b902e5..c1d53e764 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -13,9 +13,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +struct usb_function; + extern EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ); extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ); extern EFI_DEVICE_PATH_PROTOCOL * efi_describe ( struct interface *interface ); #define efi_describe_TYPE( object_type ) \ diff --git a/src/include/ipxe/efi/efi_usb.h b/src/include/ipxe/efi/efi_usb.h index 41d9cc665..06baff529 100644 --- a/src/include/ipxe/efi/efi_usb.h +++ b/src/include/ipxe/efi/efi_usb.h @@ -17,10 +17,8 @@ struct efi_usb_device { /** Name */ const char *name; - /** The underlying USB device */ - struct usb_device *usb; - /** The underlying EFI device */ - struct efi_device *efidev; + /** The underlying USB function */ + struct usb_function *func; /** Configuration descriptor */ struct usb_configuration_descriptor *config; /** Supported languages */ diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index fa4306020..162400a0f 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -17,7 +17,11 @@ * 02110-1301, USA. */ +#include +#include +#include #include +#include #include /** @file @@ -56,6 +60,62 @@ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { return ( ( ( void * ) end ) - ( ( void * ) path ) ); } +/** + * Construct EFI device path for USB function + * + * @v func USB function + * @ret path EFI device path, or NULL on error + * + * The caller is responsible for eventually calling free() on the + * allocated device path. + */ +EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ) { + struct usb_device *usb = func->usb; + struct efi_device *efidev; + EFI_DEVICE_PATH_PROTOCOL *path; + EFI_DEVICE_PATH_PROTOCOL *end; + USB_DEVICE_PATH *usbpath; + unsigned int count; + size_t prefix_len; + size_t len; + + /* Sanity check */ + assert ( func->desc.count >= 1 ); + + /* Find parent EFI device */ + efidev = efidev_parent ( &func->dev ); + if ( ! efidev ) + return NULL; + + /* Calculate device path length */ + count = ( usb_depth ( usb ) + 1 ); + prefix_len = efi_path_len ( efidev->path ); + len = ( prefix_len + ( count * sizeof ( *usbpath ) ) + + sizeof ( *end ) ); + + /* Allocate device path */ + path = zalloc ( len ); + if ( ! path ) + return NULL; + + /* Construct device path */ + memcpy ( path, efidev->path, prefix_len ); + end = ( ( ( void * ) path ) + len - sizeof ( *end ) ); + end->Type = END_DEVICE_PATH_TYPE; + end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + end->Length[0] = sizeof ( *end ); + usbpath = ( ( ( void * ) end ) - sizeof ( *usbpath ) ); + usbpath->InterfaceNumber = func->interface[0]; + for ( ; usb ; usbpath--, usb = usb->port->hub->usb ) { + usbpath->Header.Type = MESSAGING_DEVICE_PATH; + usbpath->Header.SubType = MSG_USB_DP; + usbpath->Header.Length[0] = sizeof ( *usbpath ); + usbpath->ParentPortNumber = ( usb->port->address - 1 ); + } + + return path; +} + /** * Describe object as an EFI device path * diff --git a/src/interface/efi/efi_usb.c b/src/interface/efi/efi_usb.c index 7ffeb7ffa..55b5bc880 100644 --- a/src/interface/efi/efi_usb.c +++ b/src/interface/efi/efi_usb.c @@ -73,10 +73,10 @@ static const char * efi_usb_direction_name ( EFI_USB_DATA_DIRECTION direction ){ static VOID EFIAPI efi_usb_timer ( EFI_EVENT event __unused, VOID *context ) { struct efi_usb_endpoint *usbep = context; - struct usb_bus *bus = usbep->usbintf->usbdev->usb->port->hub->bus; + struct usb_function *func = usbep->usbintf->usbdev->func; /* Poll bus */ - usb_poll ( bus ); + usb_poll ( func->usb->port->hub->bus ); /* Refill endpoint */ if ( usbep->ep.open ) @@ -179,7 +179,7 @@ static int efi_usb_open ( struct efi_usb_interface *usbintf, } /* Allocate and initialise structure */ - usb_endpoint_init ( &usbep->ep, usbdev->usb, driver ); + usb_endpoint_init ( &usbep->ep, usbdev->func->usb, driver ); usb_endpoint_describe ( &usbep->ep, endpoint, attributes, mtu, 0, ( interval << 3 /* microframes */ ) ); @@ -354,7 +354,7 @@ static int efi_usb_sync_transfer ( struct efi_usb_interface *usbintf, for ( i = 0 ; ( ( timeout == 0 ) || ( i < timeout ) ) ; i++ ) { /* Poll bus */ - usb_poll ( usbdev->usb->port->hub->bus ); + usb_poll ( usbdev->func->usb->port->hub->bus ); /* Check for completion */ if ( usbep->rc != -EINPROGRESS ) { @@ -594,7 +594,7 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio, efi_usb_close_all ( usbintf ); /* Issue control transfer */ - if ( ( rc = usb_control ( usbdev->usb, request, value, index, + if ( ( rc = usb_control ( usbdev->func->usb, request, value, index, data, len ) ) != 0 ) { DBGC ( usbdev, "USBDEV %s control %04x:%04x:%04x:%04x %p+%zx " "failed: %s\n", usbintf->name, request, value, index, @@ -841,7 +841,7 @@ efi_usb_get_device_descriptor ( EFI_USB_IO_PROTOCOL *usbio, DBGC2 ( usbdev, "USBDEV %s get device descriptor\n", usbintf->name ); /* Copy cached device descriptor */ - memcpy ( efidesc, &usbdev->usb->device, sizeof ( *efidesc ) ); + memcpy ( efidesc, &usbdev->func->usb->device, sizeof ( *efidesc ) ); return 0; } @@ -972,8 +972,9 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language, saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); /* Read descriptor header */ - if ( ( rc = usb_get_descriptor ( usbdev->usb, 0, USB_STRING_DESCRIPTOR, - index, language, &header, + if ( ( rc = usb_get_descriptor ( usbdev->func->usb, 0, + USB_STRING_DESCRIPTOR, index, + language, &header, sizeof ( header ) ) ) != 0 ) { DBGC ( usbdev, "USBDEV %s could not get string %d:%d " "descriptor header: %s\n", usbintf->name, language, @@ -996,9 +997,9 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language, } /* Read whole descriptor */ - if ( ( rc = usb_get_descriptor ( usbdev->usb, 0, USB_STRING_DESCRIPTOR, - index, language, buffer, - len ) ) != 0 ) { + if ( ( rc = usb_get_descriptor ( usbdev->func->usb, 0, + USB_STRING_DESCRIPTOR, index, + language, buffer, len ) ) != 0 ) { DBGC ( usbdev, "USBDEV %s could not get string %d:%d " "descriptor: %s\n", usbintf->name, language, index, strerror ( rc ) ); @@ -1107,25 +1108,13 @@ static EFI_USB_IO_PROTOCOL efi_usb_io_protocol = { static int efi_usb_install ( struct efi_usb_device *usbdev, unsigned int interface ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct efi_device *efidev = usbdev->efidev; + struct usb_function *func = usbdev->func; struct efi_usb_interface *usbintf; - struct usb_device *usb; - EFI_DEVICE_PATH_PROTOCOL *path_end; - USB_DEVICE_PATH *usbpath; - unsigned int path_count; - size_t path_prefix_len; - size_t path_len; EFI_STATUS efirc; int rc; - /* Calculate device path length */ - path_count = ( usb_depth ( usbdev->usb ) + 1 ); - path_prefix_len = efi_path_len ( efidev->path ); - path_len = ( path_prefix_len + ( path_count * sizeof ( *usbpath ) ) + - sizeof ( *path_end ) ); - /* Allocate and initialise structure */ - usbintf = zalloc ( sizeof ( *usbintf ) + path_len ); + usbintf = zalloc ( sizeof ( *usbintf ) ); if ( ! usbintf ) { rc = -ENOMEM; goto err_alloc; @@ -1136,22 +1125,12 @@ static int efi_usb_install ( struct efi_usb_device *usbdev, usbintf->interface = interface; memcpy ( &usbintf->usbio, &efi_usb_io_protocol, sizeof ( usbintf->usbio ) ); - usbintf->path = ( ( ( void * ) usbintf ) + sizeof ( *usbintf ) ); /* Construct device path */ - memcpy ( usbintf->path, efidev->path, path_prefix_len ); - path_end = ( ( ( void * ) usbintf->path ) + path_len - - sizeof ( *path_end ) ); - path_end->Type = END_DEVICE_PATH_TYPE; - path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - path_end->Length[0] = sizeof ( *path_end ); - usbpath = ( ( ( void * ) path_end ) - sizeof ( *usbpath ) ); - usbpath->InterfaceNumber = interface; - for ( usb = usbdev->usb ; usb ; usbpath--, usb = usb->port->hub->usb ) { - usbpath->Header.Type = MESSAGING_DEVICE_PATH; - usbpath->Header.SubType = MSG_USB_DP; - usbpath->Header.Length[0] = sizeof ( *usbpath ); - usbpath->ParentPortNumber = ( usb->port->address - 1 ); + usbintf->path = efi_usb_path ( func ); + if ( ! usbintf->path ) { + rc = -ENODEV; + goto err_path; } /* Add to list of interfaces */ @@ -1182,6 +1161,8 @@ static int efi_usb_install ( struct efi_usb_device *usbdev, efi_usb_close_all ( usbintf ); efi_usb_free_all ( usbintf ); list_del ( &usbintf->list ); + free ( usbintf->path ); + err_path: free ( usbintf ); err_alloc: return rc; @@ -1219,6 +1200,9 @@ static void efi_usb_uninstall ( struct efi_usb_interface *usbintf ) { /* Remove from list of interfaces */ list_del ( &usbintf->list ); + /* Free device path */ + free ( usbintf->path ); + /* Free interface */ free ( usbintf ); } @@ -1252,7 +1236,6 @@ static int efi_usb_probe ( struct usb_function *func, struct usb_device *usb = func->usb; struct efi_usb_device *usbdev; struct efi_usb_interface *usbintf; - struct efi_device *efidev; struct usb_descriptor_header header; struct usb_descriptor_header *lang; size_t config_len; @@ -1260,13 +1243,6 @@ static int efi_usb_probe ( struct usb_function *func, unsigned int i; int rc; - /* Find parent EFI device */ - efidev = efidev_parent ( &func->dev ); - if ( ! efidev ) { - rc = -ENOTTY; - goto err_no_efidev; - } - /* Get configuration length */ config_len = le16_to_cpu ( config->len ); @@ -1288,8 +1264,7 @@ static int efi_usb_probe ( struct usb_function *func, } usb_func_set_drvdata ( func, usbdev ); usbdev->name = func->name; - usbdev->usb = usb; - usbdev->efidev = efidev; + usbdev->func = func; usbdev->config = ( ( ( void * ) usbdev ) + sizeof ( *usbdev ) ); memcpy ( usbdev->config, config, config_len ); lang = ( ( ( void * ) usbdev->config ) + config_len ); @@ -1325,7 +1300,6 @@ static int efi_usb_probe ( struct usb_function *func, err_get_languages: free ( usbdev ); err_alloc: - err_no_efidev: return rc; } -- cgit v1.2.3-55-g7522 From f2c826179aa03951c7da39211fc5754aa571d019 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 16 Oct 2020 15:09:15 +0100 Subject: [efi] Provide efi_uri_path() to construct a URI device path Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 2 ++ src/interface/efi/efi_path.c | 43 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index c1d53e764..f52410e36 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -13,11 +13,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +struct uri; struct usb_function; extern EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ); extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ); extern EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ); extern EFI_DEVICE_PATH_PROTOCOL * efi_describe ( struct interface *interface ); diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 162400a0f..6201c023e 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -60,6 +61,48 @@ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { return ( ( ( void * ) end ) - ( ( void * ) path ) ); } +/** + * Construct EFI device path for URI + * + * @v uri URI + * @ret path EFI device path, or NULL on error + * + * The caller is responsible for eventually calling free() on the + * allocated device path. + */ +EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ) { + EFI_DEVICE_PATH_PROTOCOL *path; + EFI_DEVICE_PATH_PROTOCOL *end; + URI_DEVICE_PATH *uripath; + size_t uri_len; + size_t uripath_len; + size_t len; + + /* Calculate device path length */ + uri_len = ( format_uri ( uri, NULL, 0 ) + 1 /* NUL */ ); + uripath_len = ( sizeof ( *uripath ) + uri_len ); + len = ( uripath_len + sizeof ( *end ) ); + + /* Allocate device path */ + path = zalloc ( len ); + if ( ! path ) + return NULL; + + /* Construct device path */ + uripath = ( ( void * ) path ); + uripath->Header.Type = MESSAGING_DEVICE_PATH; + uripath->Header.SubType = MSG_URI_DP; + uripath->Header.Length[0] = ( uripath_len & 0xff ); + uripath->Header.Length[1] = ( uripath_len >> 8 ); + format_uri ( uri, uripath->Uri, uri_len ); + end = ( ( ( void * ) path ) + uripath_len ); + end->Type = END_DEVICE_PATH_TYPE; + end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + end->Length[0] = sizeof ( *end ); + + return path; +} + /** * Construct EFI device path for USB function * -- cgit v1.2.3-55-g7522 From 6154b1fb2003bafa56ce35365f681d0c2fb1a503 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Oct 2020 13:44:43 +0100 Subject: [efi] Split efi_netdev_path() out to a separate function Provide efi_netdev_path() as a standalone function, to allow for reuse when constructing child device paths. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 2 ++ src/interface/efi/efi_path.c | 65 +++++++++++++++++++++++++++++++++++++++++ src/interface/efi/efi_snp.c | 41 +++----------------------- 3 files changed, 71 insertions(+), 37 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index f52410e36..d4d43852f 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -13,12 +13,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +struct net_device; struct uri; struct usb_function; extern EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ); extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ); extern EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ); extern EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ); diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 6201c023e..3faf47617 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -19,6 +19,9 @@ #include #include +#include +#include +#include #include #include #include @@ -61,6 +64,68 @@ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { return ( ( ( void * ) end ) - ( ( void * ) path ) ); } +/** + * Construct EFI device path for network device + * + * @v netdev Network device + * @ret path EFI device path, or NULL on error + * + * The caller is responsible for eventually calling free() on the + * allocated device path. + */ +EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ) { + struct efi_device *efidev; + EFI_DEVICE_PATH_PROTOCOL *path; + MAC_ADDR_DEVICE_PATH *macpath; + VLAN_DEVICE_PATH *vlanpath; + EFI_DEVICE_PATH_PROTOCOL *end; + unsigned int tag; + size_t prefix_len; + size_t len; + + /* Find parent EFI device */ + efidev = efidev_parent ( netdev->dev ); + if ( ! efidev ) + return NULL; + + /* Calculate device path length */ + prefix_len = efi_path_len ( efidev->path ); + len = ( prefix_len + sizeof ( *macpath ) + sizeof ( *vlanpath ) + + sizeof ( *end ) ); + + /* Allocate device path */ + path = zalloc ( len ); + if ( ! path ) + return NULL; + + /* Construct device path */ + memcpy ( path, efidev->path, prefix_len ); + macpath = ( ( ( void * ) path ) + prefix_len ); + macpath->Header.Type = MESSAGING_DEVICE_PATH; + macpath->Header.SubType = MSG_MAC_ADDR_DP; + macpath->Header.Length[0] = sizeof ( *macpath ); + assert ( netdev->ll_protocol->ll_addr_len < + sizeof ( macpath->MacAddress ) ); + memcpy ( &macpath->MacAddress, netdev->ll_addr, + netdev->ll_protocol->ll_addr_len ); + macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto ); + if ( ( tag = vlan_tag ( netdev ) ) ) { + vlanpath = ( ( ( void * ) macpath ) + sizeof ( *macpath ) ); + vlanpath->Header.Type = MESSAGING_DEVICE_PATH; + vlanpath->Header.SubType = MSG_VLAN_DP; + vlanpath->Header.Length[0] = sizeof ( *vlanpath ); + vlanpath->VlanId = tag; + end = ( ( ( void * ) vlanpath ) + sizeof ( *vlanpath ) ); + } else { + end = ( ( ( void * ) macpath ) + sizeof ( *macpath ) ); + } + end->Type = END_DEVICE_PATH_TYPE; + end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + end->Length[0] = sizeof ( *end ); + + return path; +} + /** * Construct EFI device path for URI * diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index f5c736a11..91e796a2e 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -1624,12 +1624,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_device *efidev; struct efi_snp_device *snpdev; - EFI_DEVICE_PATH_PROTOCOL *path_end; - MAC_ADDR_DEVICE_PATH *macpath; - VLAN_DEVICE_PATH *vlanpath; - size_t path_prefix_len = 0; unsigned int ifcnt; - unsigned int tag; void *interface; EFI_STATUS efirc; int rc; @@ -1714,41 +1709,13 @@ static int efi_snp_probe ( struct net_device *netdev ) { sizeof ( snpdev->name[0] ) ), "%s", netdev->name ); - /* Allocate the new device path */ - path_prefix_len = efi_path_len ( efidev->path ); - snpdev->path = zalloc ( path_prefix_len + sizeof ( *macpath ) + - sizeof ( *vlanpath ) + sizeof ( *path_end ) ); + /* Construct device path */ + snpdev->path = efi_netdev_path ( netdev ); if ( ! snpdev->path ) { rc = -ENOMEM; - goto err_alloc_device_path; + goto err_path; } - /* Populate the device path */ - memcpy ( snpdev->path, efidev->path, path_prefix_len ); - macpath = ( ( ( void * ) snpdev->path ) + path_prefix_len ); - memset ( macpath, 0, sizeof ( *macpath ) ); - macpath->Header.Type = MESSAGING_DEVICE_PATH; - macpath->Header.SubType = MSG_MAC_ADDR_DP; - macpath->Header.Length[0] = sizeof ( *macpath ); - memcpy ( &macpath->MacAddress, netdev->ll_addr, - netdev->ll_protocol->ll_addr_len ); - macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto ); - if ( ( tag = vlan_tag ( netdev ) ) ) { - vlanpath = ( ( ( void * ) macpath ) + sizeof ( *macpath ) ); - memset ( vlanpath, 0, sizeof ( *vlanpath ) ); - vlanpath->Header.Type = MESSAGING_DEVICE_PATH; - vlanpath->Header.SubType = MSG_VLAN_DP; - vlanpath->Header.Length[0] = sizeof ( *vlanpath ); - vlanpath->VlanId = tag; - path_end = ( ( ( void * ) vlanpath ) + sizeof ( *vlanpath ) ); - } else { - path_end = ( ( ( void * ) macpath ) + sizeof ( *macpath ) ); - } - memset ( path_end, 0, sizeof ( *path_end ) ); - path_end->Type = END_DEVICE_PATH_TYPE; - path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; - path_end->Length[0] = sizeof ( *path_end ); - /* Install the SNP */ if ( ( efirc = bs->InstallMultipleProtocolInterfaces ( &snpdev->handle, @@ -1847,7 +1814,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { NULL ); err_install_protocol_interface: free ( snpdev->path ); - err_alloc_device_path: + err_path: bs->CloseEvent ( snpdev->snp.WaitForPacket ); err_create_event: err_ll_addr_len: -- cgit v1.2.3-55-g7522 From 2d49ce6f08002d9e92c2ba819c65a8b093e975f4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Oct 2020 14:12:48 +0100 Subject: [efi] Provide utility function to concatenate device paths Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 2 ++ src/interface/efi/efi_path.c | 52 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index d4d43852f..b27441d07 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -20,6 +20,8 @@ struct usb_function; extern EFI_DEVICE_PATH_PROTOCOL * efi_path_end ( EFI_DEVICE_PATH_PROTOCOL *path ); extern size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ); +extern EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, + ... ); extern EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ); extern EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ); extern EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ); diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 3faf47617..3c8a3be57 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -64,6 +65,57 @@ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) { return ( ( ( void * ) end ) - ( ( void * ) path ) ); } +/** + * Concatenate EFI device paths + * + * @v ... List of device paths (NULL terminated) + * @ret path Concatenated device path, or NULL on error + * + * The caller is responsible for eventually calling free() on the + * allocated device path. + */ +EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, ... ) { + EFI_DEVICE_PATH_PROTOCOL *path; + EFI_DEVICE_PATH_PROTOCOL *src; + EFI_DEVICE_PATH_PROTOCOL *dst; + EFI_DEVICE_PATH_PROTOCOL *end; + va_list args; + size_t len; + + /* Calculate device path length */ + va_start ( args, first ); + len = 0; + src = first; + while ( src ) { + len += efi_path_len ( src ); + src = va_arg ( args, EFI_DEVICE_PATH_PROTOCOL * ); + } + va_end ( args ); + + /* Allocate device path */ + path = zalloc ( len + sizeof ( *end ) ); + if ( ! path ) + return NULL; + + /* Populate device path */ + va_start ( args, first ); + dst = path; + src = first; + while ( src ) { + len = efi_path_len ( src ); + memcpy ( dst, src, len ); + dst = ( ( ( void * ) dst ) + len ); + src = va_arg ( args, EFI_DEVICE_PATH_PROTOCOL * ); + } + va_end ( args ); + end = dst; + end->Type = END_DEVICE_PATH_TYPE; + end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + end->Length[0] = sizeof ( *end ); + + return path; +} + /** * Construct EFI device path for network device * -- cgit v1.2.3-55-g7522 From 04cb17de505317db56623b8b4d07b242dec35256 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Oct 2020 14:42:11 +0100 Subject: [aoe] Allow AoE device to be described using an EFI device path There is no standard defined for AoE device paths in the UEFI specification, and it seems unlikely that any standard will be adopted in future. Choose to construct an AoE device path using a concatenation of the network device path and a SATA device path, treating the AoE major and minor numbers as the HBA port number and port multiplier port number respectively. Signed-off-by: Michael Brown --- src/include/ipxe/aoe.h | 31 +++++++++++++++++++++++++++ src/include/ipxe/efi/efi_path.h | 2 ++ src/interface/efi/efi_path.c | 47 +++++++++++++++++++++++++++++++++++++++++ src/net/aoe.c | 31 ++------------------------- 4 files changed, 82 insertions(+), 29 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/aoe.h b/src/include/ipxe/aoe.h index a51044d15..14d11c5cb 100644 --- a/src/include/ipxe/aoe.h +++ b/src/include/ipxe/aoe.h @@ -15,6 +15,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include +#include /** An AoE config command */ struct aoecfg { @@ -109,6 +111,35 @@ struct aoehdr { /** Maximum number of sectors per packet */ #define AOE_MAX_COUNT 2 +/** An AoE device */ +struct aoe_device { + /** Reference counter */ + struct refcnt refcnt; + + /** Network device */ + struct net_device *netdev; + /** ATA command issuing interface */ + struct interface ata; + + /** Major number */ + uint16_t major; + /** Minor number */ + uint8_t minor; + /** Target MAC address */ + uint8_t target[MAX_LL_ADDR_LEN]; + + /** Saved timeout value */ + unsigned long timeout; + + /** Configuration command interface */ + struct interface config; + /** Device is configued */ + int configured; + + /** ACPI descriptor */ + struct acpi_descriptor desc; +}; + /** AoE boot firmware table signature */ #define ABFT_SIG ACPI_SIGNATURE ( 'a', 'B', 'F', 'T' ) diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index b27441d07..3921fcee2 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -15,6 +15,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); struct net_device; struct uri; +struct aoe_device; struct usb_function; extern EFI_DEVICE_PATH_PROTOCOL * @@ -24,6 +25,7 @@ extern EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, ... ); extern EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ); extern EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ); +extern EFI_DEVICE_PATH_PROTOCOL * efi_aoe_path ( struct aoe_device *aoedev ); extern EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ); extern EFI_DEVICE_PATH_PROTOCOL * efi_describe ( struct interface *interface ); diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 3c8a3be57..8636c965b 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -220,6 +221,52 @@ EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ) { return path; } +/** + * Construct EFI device path for AoE device + * + * @v aoedev AoE device + * @ret path EFI device path, or NULL on error + */ +EFI_DEVICE_PATH_PROTOCOL * efi_aoe_path ( struct aoe_device *aoedev ) { + struct { + SATA_DEVICE_PATH sata; + EFI_DEVICE_PATH_PROTOCOL end; + } satapath; + EFI_DEVICE_PATH_PROTOCOL *netpath; + EFI_DEVICE_PATH_PROTOCOL *path; + + /* Get network device path */ + netpath = efi_netdev_path ( aoedev->netdev ); + if ( ! netpath ) + goto err_netdev; + + /* Construct SATA path */ + memset ( &satapath, 0, sizeof ( satapath ) ); + satapath.sata.Header.Type = MESSAGING_DEVICE_PATH; + satapath.sata.Header.SubType = MSG_SATA_DP; + satapath.sata.Header.Length[0] = sizeof ( satapath.sata ); + satapath.sata.HBAPortNumber = aoedev->major; + satapath.sata.PortMultiplierPortNumber = aoedev->minor; + satapath.end.Type = END_DEVICE_PATH_TYPE; + satapath.end.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + satapath.end.Length[0] = sizeof ( satapath.end ); + + /* Construct overall device path */ + path = efi_paths ( netpath, &satapath, NULL ); + if ( ! path ) + goto err_paths; + + /* Free temporary paths */ + free ( netpath ); + + return path; + + err_paths: + free ( netpath ); + err_netdev: + return NULL; +} + /** * Construct EFI device path for USB function * diff --git a/src/net/aoe.c b/src/net/aoe.c index 3a6611d04..e785e8979 100644 --- a/src/net/aoe.c +++ b/src/net/aoe.c @@ -42,6 +42,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include /** @file @@ -68,35 +69,6 @@ static LIST_HEAD ( aoe_devices ); /** List of active AoE commands */ static LIST_HEAD ( aoe_commands ); -/** An AoE device */ -struct aoe_device { - /** Reference counter */ - struct refcnt refcnt; - - /** Network device */ - struct net_device *netdev; - /** ATA command issuing interface */ - struct interface ata; - - /** Major number */ - uint16_t major; - /** Minor number */ - uint8_t minor; - /** Target MAC address */ - uint8_t target[MAX_LL_ADDR_LEN]; - - /** Saved timeout value */ - unsigned long timeout; - - /** Configuration command interface */ - struct interface config; - /** Device is configued */ - int configured; - - /** ACPI descriptor */ - struct acpi_descriptor desc; -}; - /** An AoE command */ struct aoe_command { /** Reference count */ @@ -811,6 +783,7 @@ static struct interface_operation aoedev_ata_op[] = { INTF_OP ( acpi_describe, struct aoe_device *, aoedev_describe ), INTF_OP ( identify_device, struct aoe_device *, aoedev_identify_device ), + EFI_INTF_OP ( efi_describe, struct aoe_device *, efi_aoe_path ), }; /** AoE device ATA interface descriptor */ -- cgit v1.2.3-55-g7522 From e6f9054d13bd9bc95720ca3e8cf6c4dcf4eae018 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 20 Oct 2020 14:48:29 +0100 Subject: [iscsi] Allow iSCSI device to be described using an EFI device path Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 3 ++ src/interface/efi/efi_path.c | 70 +++++++++++++++++++++++++++++++++++++++++ src/net/tcp/iscsi.c | 2 ++ 3 files changed, 75 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index 3921fcee2..370197601 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -15,6 +15,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); struct net_device; struct uri; +struct iscsi_session; struct aoe_device; struct usb_function; @@ -25,6 +26,8 @@ extern EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, ... ); extern EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ); extern EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ); +extern EFI_DEVICE_PATH_PROTOCOL * +efi_iscsi_path ( struct iscsi_session *iscsi ); extern EFI_DEVICE_PATH_PROTOCOL * efi_aoe_path ( struct aoe_device *aoedev ); extern EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ); diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 8636c965b..3c14a2ee6 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -221,6 +223,74 @@ EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ) { return path; } +/** + * Construct EFI device path for iSCSI device + * + * @v iscsi iSCSI session + * @ret path EFI device path, or NULL on error + */ +EFI_DEVICE_PATH_PROTOCOL * efi_iscsi_path ( struct iscsi_session *iscsi ) { + struct sockaddr_tcpip *st_target; + struct net_device *netdev; + EFI_DEVICE_PATH_PROTOCOL *netpath; + EFI_DEVICE_PATH_PROTOCOL *path; + EFI_DEVICE_PATH_PROTOCOL *end; + ISCSI_DEVICE_PATH *iscsipath; + char *name; + size_t prefix_len; + size_t name_len; + size_t iscsi_len; + size_t len; + + /* Get network device associated with target address */ + st_target = ( ( struct sockaddr_tcpip * ) &iscsi->target_sockaddr ); + netdev = tcpip_netdev ( st_target ); + if ( ! netdev ) + goto err_netdev; + + /* Get network device path */ + netpath = efi_netdev_path ( netdev ); + if ( ! netpath ) + goto err_netpath; + + /* Calculate device path length */ + prefix_len = efi_path_len ( netpath ); + name_len = ( strlen ( iscsi->target_iqn ) + 1 /* NUL */ ); + iscsi_len = ( sizeof ( *iscsipath ) + name_len ); + len = ( prefix_len + iscsi_len + sizeof ( *end ) ); + + /* Allocate device path */ + path = zalloc ( len ); + if ( ! path ) + goto err_alloc; + + /* Construct device path */ + memcpy ( path, netpath, prefix_len ); + iscsipath = ( ( ( void * ) path ) + prefix_len ); + iscsipath->Header.Type = MESSAGING_DEVICE_PATH; + iscsipath->Header.SubType = MSG_ISCSI_DP; + iscsipath->Header.Length[0] = iscsi_len; + iscsipath->LoginOption = ISCSI_LOGIN_OPTION_AUTHMETHOD_NON; + memcpy ( &iscsipath->Lun, &iscsi->lun, sizeof ( iscsipath->Lun ) ); + name = ( ( ( void * ) iscsipath ) + sizeof ( *iscsipath ) ); + memcpy ( name, iscsi->target_iqn, name_len ); + end = ( ( ( void * ) name ) + name_len ); + end->Type = END_DEVICE_PATH_TYPE; + end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + end->Length[0] = sizeof ( *end ); + + /* Free temporary paths */ + free ( netpath ); + + return path; + + err_alloc: + free ( netpath ); + err_netpath: + err_netdev: + return NULL; +} + /** * Construct EFI device path for AoE device * diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index 3a44b90f0..e36d5619d 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -46,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include /** @file @@ -1863,6 +1864,7 @@ static struct interface_operation iscsi_control_op[] = { INTF_OP ( xfer_window, struct iscsi_session *, iscsi_scsi_window ), INTF_OP ( intf_close, struct iscsi_session *, iscsi_close ), INTF_OP ( acpi_describe, struct iscsi_session *, iscsi_describe ), + EFI_INTF_OP ( efi_describe, struct iscsi_session *, efi_iscsi_path ), }; /** iSCSI SCSI command-issuing interface descriptor */ -- cgit v1.2.3-55-g7522 From bf051a76eef07bb4bd04ad4ff2b8b5e23ef26740 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Oct 2020 14:01:27 +0100 Subject: [fcp] Allow Fibre Channel device to be described using an EFI device path Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 2 ++ src/include/ipxe/fcp.h | 8 ++++++++ src/interface/efi/efi_path.c | 31 +++++++++++++++++++++++++++++++ src/net/fcp.c | 28 ++++++++++++++++++++-------- 4 files changed, 61 insertions(+), 8 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index 370197601..91a6c255d 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -17,6 +17,7 @@ struct net_device; struct uri; struct iscsi_session; struct aoe_device; +struct fcp_description; struct usb_function; extern EFI_DEVICE_PATH_PROTOCOL * @@ -29,6 +30,7 @@ extern EFI_DEVICE_PATH_PROTOCOL * efi_uri_path ( struct uri *uri ); extern EFI_DEVICE_PATH_PROTOCOL * efi_iscsi_path ( struct iscsi_session *iscsi ); extern EFI_DEVICE_PATH_PROTOCOL * efi_aoe_path ( struct aoe_device *aoedev ); +extern EFI_DEVICE_PATH_PROTOCOL * efi_fcp_path ( struct fcp_description *desc ); extern EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ); extern EFI_DEVICE_PATH_PROTOCOL * efi_describe ( struct interface *interface ); diff --git a/src/include/ipxe/fcp.h b/src/include/ipxe/fcp.h index 853ca13f6..d86afab42 100644 --- a/src/include/ipxe/fcp.h +++ b/src/include/ipxe/fcp.h @@ -163,4 +163,12 @@ struct fcp_prli_service_parameters { /** Enhanced discovery supported */ #define FCP_PRLI_ENH_DISC 0x0800 +/** An FCP device description */ +struct fcp_description { + /** Fibre Channel WWN */ + struct fc_name wwn; + /** SCSI LUN */ + struct scsi_lun lun; +}; + #endif /* _IPXE_FCP_H */ diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 3c14a2ee6..76b1e4dae 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -337,6 +338,36 @@ EFI_DEVICE_PATH_PROTOCOL * efi_aoe_path ( struct aoe_device *aoedev ) { return NULL; } +/** + * Construct EFI device path for Fibre Channel device + * + * @v desc FCP device description + * @ret path EFI device path, or NULL on error + */ +EFI_DEVICE_PATH_PROTOCOL * efi_fcp_path ( struct fcp_description *desc ) { + struct { + FIBRECHANNELEX_DEVICE_PATH fc; + EFI_DEVICE_PATH_PROTOCOL end; + } __attribute__ (( packed )) *path; + + /* Allocate device path */ + path = zalloc ( sizeof ( *path ) ); + if ( ! path ) + return NULL; + + /* Construct device path */ + path->fc.Header.Type = MESSAGING_DEVICE_PATH; + path->fc.Header.SubType = MSG_FIBRECHANNELEX_DP; + path->fc.Header.Length[0] = sizeof ( path->fc ); + memcpy ( path->fc.WWN, &desc->wwn, sizeof ( path->fc.WWN ) ); + memcpy ( path->fc.Lun, &desc->lun, sizeof ( path->fc.Lun ) ); + path->end.Type = END_DEVICE_PATH_TYPE; + path->end.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + path->end.Length[0] = sizeof ( path->end ); + + return &path->fc.Header; +} + /** * Construct EFI device path for USB function * diff --git a/src/net/fcp.c b/src/net/fcp.c index d92cfdcf3..f78f7bd9b 100644 --- a/src/net/fcp.c +++ b/src/net/fcp.c @@ -43,6 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -158,10 +159,8 @@ struct fcp_device { /** List of active commands */ struct list_head fcpcmds; - /** Fibre Channel WWN (for boot firmware table) */ - struct fc_name wwn; - /** SCSI LUN (for boot firmware table) */ - struct scsi_lun lun; + /** Device description (for boot firmware table) */ + struct fcp_description desc; }; /** An FCP command */ @@ -864,9 +863,9 @@ static int fcpdev_edd_describe ( struct fcp_device *fcpdev, } lun; type->type = cpu_to_le64 ( EDD_INTF_TYPE_FIBRE ); - memcpy ( &wwn.fc, &fcpdev->wwn, sizeof ( wwn.fc ) ); + memcpy ( &wwn.fc, &fcpdev->desc.wwn, sizeof ( wwn.fc ) ); path->fibre.wwn = be64_to_cpu ( wwn.u64 ); - memcpy ( &lun.scsi, &fcpdev->lun, sizeof ( lun.scsi ) ); + memcpy ( &lun.scsi, &fcpdev->desc.lun, sizeof ( lun.scsi ) ); path->fibre.lun = be64_to_cpu ( lun.u64 ); return 0; } @@ -893,6 +892,18 @@ static struct device * fcpdev_identify_device ( struct fcp_device *fcpdev ) { return identify_device ( &fcpdev->user.ulp->peer->port->transport ); } +/** + * Describe as an EFI device path + * + * @v fcp FCP device + * @ret path EFI device path, or NULL on error + */ +static EFI_DEVICE_PATH_PROTOCOL * +fcpdev_efi_describe ( struct fcp_device *fcpdev ) { + + return efi_fcp_path ( &fcpdev->desc ); +} + /** FCP device SCSI interface operations */ static struct interface_operation fcpdev_scsi_op[] = { INTF_OP ( scsi_command, struct fcp_device *, fcpdev_scsi_command ), @@ -901,6 +912,7 @@ static struct interface_operation fcpdev_scsi_op[] = { INTF_OP ( edd_describe, struct fcp_device *, fcpdev_edd_describe ), INTF_OP ( identify_device, struct fcp_device *, fcpdev_identify_device ), + EFI_INTF_OP ( efi_describe, struct fcp_device *, fcpdev_efi_describe ), }; /** FCP device SCSI interface descriptor */ @@ -965,8 +977,8 @@ static int fcpdev_open ( struct interface *parent, struct fc_name *wwn, fc_ulp_attach ( ulp, &fcpdev->user ); /* Preserve parameters required for boot firmware table */ - memcpy ( &fcpdev->wwn, wwn, sizeof ( fcpdev->wwn ) ); - memcpy ( &fcpdev->lun, lun, sizeof ( fcpdev->lun ) ); + memcpy ( &fcpdev->desc.wwn, wwn, sizeof ( fcpdev->desc.wwn ) ); + memcpy ( &fcpdev->desc.lun, lun, sizeof ( fcpdev->desc.lun ) ); /* Attach SCSI device to parent interface */ if ( ( rc = scsi_open ( parent, &fcpdev->scsi, lun ) ) != 0 ) { -- cgit v1.2.3-55-g7522 From a2e44077cdb0713d90766e61165ca71fce902003 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 23 Oct 2020 15:26:30 +0100 Subject: [infiniband] Allow SRP device to be described using an EFI device path The UEFI specification provides a partial definition of an Infiniband device path structure. Use this structure to construct what may be a plausible path containing at least some of the information required to identify an SRP target device. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_path.h | 3 +++ src/include/ipxe/ib_srp.h | 35 ++++++++++++++++++++++++++ src/interface/efi/efi_path.c | 55 +++++++++++++++++++++++++++++++++++++++++ src/net/infiniband/ib_srp.c | 35 ++------------------------ 4 files changed, 95 insertions(+), 33 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_path.h b/src/include/ipxe/efi/efi_path.h index 91a6c255d..76ded728c 100644 --- a/src/include/ipxe/efi/efi_path.h +++ b/src/include/ipxe/efi/efi_path.h @@ -18,6 +18,7 @@ struct uri; struct iscsi_session; struct aoe_device; struct fcp_description; +struct ib_srp_device; struct usb_function; extern EFI_DEVICE_PATH_PROTOCOL * @@ -31,6 +32,8 @@ extern EFI_DEVICE_PATH_PROTOCOL * efi_iscsi_path ( struct iscsi_session *iscsi ); extern EFI_DEVICE_PATH_PROTOCOL * efi_aoe_path ( struct aoe_device *aoedev ); extern EFI_DEVICE_PATH_PROTOCOL * efi_fcp_path ( struct fcp_description *desc ); +extern EFI_DEVICE_PATH_PROTOCOL * +efi_ib_srp_path ( struct ib_srp_device *ib_srp ); extern EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ); extern EFI_DEVICE_PATH_PROTOCOL * efi_describe ( struct interface *interface ); diff --git a/src/include/ipxe/ib_srp.h b/src/include/ipxe/ib_srp.h index ad407b0cf..4b6df8d3b 100644 --- a/src/include/ipxe/ib_srp.h +++ b/src/include/ipxe/ib_srp.h @@ -10,6 +10,8 @@ FILE_LICENCE ( BSD2 ); #include +#include +#include #include #include @@ -55,4 +57,37 @@ struct sbft_ib_subtable { uint8_t reserved[6]; } __attribute__ (( packed )); +/** + * An Infiniband SRP sBFT created by iPXE + */ +struct ipxe_ib_sbft { + /** The table header */ + struct sbft_table table; + /** The SCSI subtable */ + struct sbft_scsi_subtable scsi; + /** The SRP subtable */ + struct sbft_srp_subtable srp; + /** The Infiniband subtable */ + struct sbft_ib_subtable ib; +}; + +/** An Infiniband SRP device */ +struct ib_srp_device { + /** Reference count */ + struct refcnt refcnt; + + /** SRP transport interface */ + struct interface srp; + /** CMRC interface */ + struct interface cmrc; + + /** Infiniband device */ + struct ib_device *ibdev; + + /** ACPI descriptor */ + struct acpi_descriptor desc; + /** Boot firmware table parameters */ + struct ipxe_ib_sbft sbft; +}; + #endif /* _IPXE_IB_SRP_H */ diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c index 76b1e4dae..bae0ac4b5 100644 --- a/src/interface/efi/efi_path.c +++ b/src/interface/efi/efi_path.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -368,6 +369,60 @@ EFI_DEVICE_PATH_PROTOCOL * efi_fcp_path ( struct fcp_description *desc ) { return &path->fc.Header; } +/** + * Construct EFI device path for Infiniband SRP device + * + * @v ib_srp Infiniband SRP device + * @ret path EFI device path, or NULL on error + */ +EFI_DEVICE_PATH_PROTOCOL * efi_ib_srp_path ( struct ib_srp_device *ib_srp ) { + const struct ipxe_ib_sbft *sbft = &ib_srp->sbft; + union ib_srp_target_port_id *id = + container_of ( &sbft->srp.target, union ib_srp_target_port_id, + srp ); + struct efi_device *efidev; + EFI_DEVICE_PATH_PROTOCOL *path; + INFINIBAND_DEVICE_PATH *ibpath; + EFI_DEVICE_PATH_PROTOCOL *end; + size_t prefix_len; + size_t len; + + /* Find parent EFI device */ + efidev = efidev_parent ( ib_srp->ibdev->dev ); + if ( ! efidev ) + return NULL; + + /* Calculate device path length */ + prefix_len = efi_path_len ( efidev->path ); + len = ( prefix_len + sizeof ( *ibpath ) + sizeof ( *end ) ); + + /* Allocate device path */ + path = zalloc ( len ); + if ( ! path ) + return NULL; + + /* Construct device path */ + memcpy ( path, efidev->path, prefix_len ); + ibpath = ( ( ( void * ) path ) + prefix_len ); + ibpath->Header.Type = MESSAGING_DEVICE_PATH; + ibpath->Header.SubType = MSG_INFINIBAND_DP; + ibpath->Header.Length[0] = sizeof ( *ibpath ); + ibpath->ResourceFlags = INFINIBAND_RESOURCE_FLAG_STORAGE_PROTOCOL; + memcpy ( ibpath->PortGid, &sbft->ib.dgid, sizeof ( ibpath->PortGid ) ); + memcpy ( &ibpath->ServiceId, &sbft->ib.service_id, + sizeof ( ibpath->ServiceId ) ); + memcpy ( &ibpath->TargetPortId, &id->ib.ioc_guid, + sizeof ( ibpath->TargetPortId ) ); + memcpy ( &ibpath->DeviceId, &id->ib.id_ext, + sizeof ( ibpath->DeviceId ) ); + end = ( ( ( void * ) ibpath ) + sizeof ( *ibpath ) ); + end->Type = END_DEVICE_PATH_TYPE; + end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + end->Length[0] = sizeof ( *end ); + + return path; +} + /** * Construct EFI device path for USB function * diff --git a/src/net/infiniband/ib_srp.c b/src/net/infiniband/ib_srp.c index 4913f449c..e6b43291f 100644 --- a/src/net/infiniband/ib_srp.c +++ b/src/net/infiniband/ib_srp.c @@ -37,6 +37,7 @@ FILE_LICENCE ( BSD2 ); #include #include #include +#include #include #include #include @@ -69,39 +70,6 @@ struct acpi_model ib_sbft_model __acpi_model; ****************************************************************************** */ -/** - * An IB SRP sBFT created by iPXE - */ -struct ipxe_ib_sbft { - /** The table header */ - struct sbft_table table; - /** The SCSI subtable */ - struct sbft_scsi_subtable scsi; - /** The SRP subtable */ - struct sbft_srp_subtable srp; - /** The Infiniband subtable */ - struct sbft_ib_subtable ib; -}; - -/** An Infiniband SRP device */ -struct ib_srp_device { - /** Reference count */ - struct refcnt refcnt; - - /** SRP transport interface */ - struct interface srp; - /** CMRC interface */ - struct interface cmrc; - - /** Infiniband device */ - struct ib_device *ibdev; - - /** ACPI descriptor */ - struct acpi_descriptor desc; - /** Boot firmware table parameters */ - struct ipxe_ib_sbft sbft; -}; - /** * Free IB SRP device * @@ -153,6 +121,7 @@ static struct interface_descriptor ib_srp_cmrc_desc = static struct interface_operation ib_srp_srp_op[] = { INTF_OP ( acpi_describe, struct ib_srp_device *, ib_srp_describe ), INTF_OP ( intf_close, struct ib_srp_device *, ib_srp_close ), + EFI_INTF_OP ( efi_describe, struct ib_srp_device *, efi_ib_srp_path ), }; /** IB SRP SRP interface descriptor */ -- cgit v1.2.3-55-g7522 From 5b41b9a80ffb365376d8d522675a8d248a8717ab Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Oct 2020 15:10:18 +0000 Subject: [efi] Nullify interfaces and leak memory on uninstallation failure The UEFI specification allows uninstallation of a protocol interface to fail. There is no sensible way for code to react to this, since uninstallation is likely to be taking place on a code path that cannot itself fail (e.g. a code path that is itself a failure path). Where the protocol structure exists within a dynamically allocated block of memory, this leads to possible use-after-free bugs. Work around this unfortunate design choice by nullifying the protocol (i.e. overwriting the method pointers with no-ops) and leaking the memory containing the protocol structure. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_null.h | 31 +++ src/include/ipxe/efi/efi_snp.h | 2 +- src/interface/efi/efi_block.c | 52 +++- src/interface/efi/efi_null.c | 532 ++++++++++++++++++++++++++++++++++++++++ src/interface/efi/efi_pxe.c | 36 ++- src/interface/efi/efi_snp.c | 56 ++++- src/interface/efi/efi_snp_hii.c | 78 ++++-- 7 files changed, 737 insertions(+), 50 deletions(-) create mode 100644 src/include/ipxe/efi/efi_null.h create mode 100644 src/interface/efi/efi_null.c (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_null.h b/src/include/ipxe/efi/efi_null.h new file mode 100644 index 000000000..cc91e09bb --- /dev/null +++ b/src/include/ipxe/efi/efi_null.h @@ -0,0 +1,31 @@ +#ifndef _IPXE_EFI_NULL_H +#define _IPXE_EFI_NULL_H + +/** @file + * + * EFI null interfaces + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern void efi_nullify_snp ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ); +extern void efi_nullify_nii ( EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *nii ); +extern void efi_nullify_name2 ( EFI_COMPONENT_NAME2_PROTOCOL *name2 ); +extern void efi_nullify_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file ); +extern void efi_nullify_hii ( EFI_HII_CONFIG_ACCESS_PROTOCOL *hii ); +extern void efi_nullify_block ( EFI_BLOCK_IO_PROTOCOL *block ); +extern void efi_nullify_pxe ( EFI_PXE_BASE_CODE_PROTOCOL *pxe ); +extern void efi_nullify_apple ( EFI_APPLE_NET_BOOT_PROTOCOL *apple ); + +#endif /* _IPXE_EFI_NULL_H */ diff --git a/src/include/ipxe/efi/efi_snp.h b/src/include/ipxe/efi/efi_snp.h index 9076f1d56..c278b1d4c 100644 --- a/src/include/ipxe/efi/efi_snp.h +++ b/src/include/ipxe/efi/efi_snp.h @@ -76,7 +76,7 @@ struct efi_snp_device { }; extern int efi_snp_hii_install ( struct efi_snp_device *snpdev ); -extern void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ); +extern int efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ); extern struct efi_snp_device * find_snpdev ( EFI_HANDLE handle ); extern struct efi_snp_device * last_opened_snpdev ( void ); extern void efi_snp_add_claim ( int delta ); diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index c974ca065..19f669fd2 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -55,6 +55,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include /** ACPI table protocol protocol */ @@ -244,6 +245,7 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct san_device *sandev; struct efi_block_data *block; + int leak = 0; EFI_STATUS efirc; int rc; @@ -317,20 +319,33 @@ static int efi_block_hook ( unsigned int drive, struct uri **uris, return drive; - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( block->handle, &efi_block_io_protocol_guid, &block->block_io, - &efi_device_path_protocol_guid, block->path, NULL ); + &efi_device_path_protocol_guid, block->path, + NULL ) ) != 0 ) { + DBGC ( sandev, "EFIBLK %#02x could not uninstall protocols: " + "%s\n", sandev->drive, strerror ( -EEFI ( efirc ) ) ); + efi_nullify_block ( &block->block_io ); + leak = 1; + } err_install: - free ( block->path ); - block->path = NULL; + if ( ! leak ) { + free ( block->path ); + block->path = NULL; + } err_describe: err_active: unregister_sandev ( sandev ); err_register: - sandev_put ( sandev ); + if ( ! leak ) + sandev_put ( sandev ); err_alloc: err_no_uris: + if ( leak ) { + DBGC ( sandev, "EFIBLK %#02x nullified and leaked\n", + sandev->drive ); + } return rc; } @@ -343,6 +358,8 @@ static void efi_block_unhook ( unsigned int drive ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct san_device *sandev; struct efi_block_data *block; + int leak = 0; + EFI_STATUS efirc; /* Find SAN device */ sandev = sandev_find ( drive ); @@ -353,20 +370,35 @@ static void efi_block_unhook ( unsigned int drive ) { block = sandev->priv; /* Uninstall protocols */ - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( block->handle, &efi_block_io_protocol_guid, &block->block_io, - &efi_device_path_protocol_guid, block->path, NULL ); + &efi_device_path_protocol_guid, block->path, + NULL ) ) != 0 ) { + DBGC ( sandev, "EFIBLK %#02x could not uninstall protocols: " + "%s\n", sandev->drive, strerror ( -EEFI ( efirc ) ) ); + efi_nullify_block ( &block->block_io ); + leak = 1; + } /* Free device path */ - free ( block->path ); - block->path = NULL; + if ( ! leak ) { + free ( block->path ); + block->path = NULL; + } /* Unregister SAN device */ unregister_sandev ( sandev ); /* Drop reference to drive */ - sandev_put ( sandev ); + if ( ! leak ) + sandev_put ( sandev ); + + /* Report leakage, if applicable */ + if ( leak ) { + DBGC ( sandev, "EFIBLK %#02x nullified and leaked\n", + sandev->drive ); + } } /** An installed ACPI table */ diff --git a/src/interface/efi/efi_null.c b/src/interface/efi/efi_null.c new file mode 100644 index 000000000..0bd69633b --- /dev/null +++ b/src/interface/efi/efi_null.c @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2020 Michael Brown . + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include + +/** @file + * + * EFI null interfaces + * + */ + +/****************************************************************************** + * + * Simple Network Protocol + * + ****************************************************************************** + */ + +static EFI_STATUS EFIAPI +efi_null_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused, + UINTN extra_rx_bufsize __unused, + UINTN extra_tx_bufsize __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused, + BOOLEAN ext_verify __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused, + UINT32 enable __unused, + UINT32 disable __unused, + BOOLEAN mcast_reset __unused, + UINTN mcast_count __unused, + EFI_MAC_ADDRESS *mcast __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused, + BOOLEAN reset __unused, + EFI_MAC_ADDRESS *new __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused, + BOOLEAN reset __unused, UINTN *stats_len __unused, + EFI_NETWORK_STATISTICS *stats __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused, + BOOLEAN ipv6 __unused, + EFI_IP_ADDRESS *ip __unused, + EFI_MAC_ADDRESS *mac __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused, + BOOLEAN read __unused, UINTN offset __unused, + UINTN len __unused, VOID *data __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused, + UINT32 *interrupts __unused, VOID **txbuf __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused, + UINTN ll_header_len __unused, UINTN len __unused, + VOID *data __unused, EFI_MAC_ADDRESS *ll_src __unused, + EFI_MAC_ADDRESS *ll_dest __unused, + UINT16 *net_proto __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp __unused, + UINTN *ll_header_len __unused, UINTN *len __unused, + VOID *data __unused, EFI_MAC_ADDRESS *ll_src __unused, + EFI_MAC_ADDRESS *ll_dest __unused, + UINT16 *net_proto __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_SIMPLE_NETWORK_PROTOCOL efi_null_snp = { + .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION, + .Start = efi_null_snp_start, + .Stop = efi_null_snp_stop, + .Initialize = efi_null_snp_initialize, + .Reset = efi_null_snp_reset, + .Shutdown = efi_null_snp_shutdown, + .ReceiveFilters = efi_null_snp_receive_filters, + .StationAddress = efi_null_snp_station_address, + .Statistics = efi_null_snp_statistics, + .MCastIpToMac = efi_null_snp_mcast_ip_to_mac, + .NvData = efi_null_snp_nvdata, + .GetStatus = efi_null_snp_get_status, + .Transmit = efi_null_snp_transmit, + .Receive = efi_null_snp_receive, +}; + +/** + * Nullify SNP interface + * + * @v snp SNP interface + */ +void efi_nullify_snp ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { + + memcpy ( snp, &efi_null_snp, + offsetof ( typeof ( *snp ), WaitForPacket ) ); + snp->Mode->State = EfiSimpleNetworkStopped; +} + +/****************************************************************************** + * + * Network Interface Identification protocol + * + ****************************************************************************** + */ + +static EFIAPI VOID efi_null_undi_issue ( UINT64 cdb_phys ) { + PXE_CDB *cdb = ( ( void * ) ( intptr_t ) cdb_phys ); + + cdb->StatCode = PXE_STATCODE_UNSUPPORTED; + cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED; +} + +static PXE_SW_UNDI efi_null_undi __attribute__ (( aligned ( 16 ) )) = { + .Signature = PXE_ROMID_SIGNATURE, + .Len = sizeof ( efi_null_undi ), + .Rev = PXE_ROMID_REV, + .MajorVer = PXE_ROMID_MAJORVER, + .MinorVer = PXE_ROMID_MINORVER, + .Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR, +}; + +/** + * Nullify NII interface + * + * @v nii NII interface + */ +void efi_nullify_nii ( EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *nii ) { + efi_null_undi.EntryPoint = ( ( intptr_t ) efi_null_undi_issue ); + nii->Id = ( ( intptr_t ) &efi_null_undi ); +} + +/****************************************************************************** + * + * Component name protocol + * + ****************************************************************************** + */ + +static EFI_STATUS EFIAPI +efi_null_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2 __unused, + CHAR8 *language __unused, + CHAR16 **driver_name __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2 __unused, + EFI_HANDLE device __unused, + EFI_HANDLE child __unused, + CHAR8 *language __unused, + CHAR16 **controller_name __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_COMPONENT_NAME2_PROTOCOL efi_null_name2 = { + .GetDriverName = efi_null_get_driver_name, + .GetControllerName = efi_null_get_controller_name, + .SupportedLanguages = "", +}; + +/** + * Nullify Component Name Protocol interface + * + * @v name2 Component name protocol + */ +void efi_nullify_name2 ( EFI_COMPONENT_NAME2_PROTOCOL *name2 ) { + + memcpy ( name2, &efi_null_name2, sizeof ( name2 ) ); +} + +/****************************************************************************** + * + * Load file protocol + * + ****************************************************************************** + */ + +static EFI_STATUS EFIAPI +efi_null_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file __unused, + EFI_DEVICE_PATH_PROTOCOL *path __unused, + BOOLEAN booting __unused, UINTN *len __unused, + VOID *data __unused ) { + return EFI_UNSUPPORTED; +} + +/** + * Nullify Load File Protocol interface + * + * @v load_file Load file protocol + */ +void efi_nullify_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file ) { + load_file->LoadFile = efi_null_load_file; +} + +/****************************************************************************** + * + * HII configuration access protocol + * + ****************************************************************************** + */ + +static EFI_STATUS EFIAPI +efi_null_hii_extract ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii __unused, + EFI_STRING request __unused, + EFI_STRING *progress __unused, + EFI_STRING *results __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_hii_route ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii __unused, + EFI_STRING config __unused, + EFI_STRING *progress __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_hii_callback ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii __unused, + EFI_BROWSER_ACTION action __unused, + EFI_QUESTION_ID question_id __unused, + UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused, + EFI_BROWSER_ACTION_REQUEST *action_request __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_null_hii = { + .ExtractConfig = efi_null_hii_extract, + .RouteConfig = efi_null_hii_route, + .Callback = efi_null_hii_callback, +}; + +/** + * Nullify HII configuration access protocol + * + * @v hii HII configuration access protocol + */ +void efi_nullify_hii ( EFI_HII_CONFIG_ACCESS_PROTOCOL *hii ) { + + memcpy ( hii, &efi_null_hii, sizeof ( *hii ) ); +} + +/****************************************************************************** + * + * Block I/O protocol + * + ****************************************************************************** + */ + +static EFI_STATUS EFIAPI +efi_null_block_reset ( EFI_BLOCK_IO_PROTOCOL *block __unused, + BOOLEAN verify __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_block_read ( EFI_BLOCK_IO_PROTOCOL *block __unused, + UINT32 media __unused, EFI_LBA lba __unused, + UINTN len __unused, VOID *data __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_block_write ( EFI_BLOCK_IO_PROTOCOL *block __unused, + UINT32 media __unused, EFI_LBA lba __unused, + UINTN len __unused, VOID *data __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_block_flush ( EFI_BLOCK_IO_PROTOCOL *block __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_BLOCK_IO_MEDIA efi_null_block_media; + +static EFI_BLOCK_IO_PROTOCOL efi_null_block = { + .Revision = EFI_BLOCK_IO_INTERFACE_REVISION, + .Media = &efi_null_block_media, + .Reset = efi_null_block_reset, + .ReadBlocks = efi_null_block_read, + .WriteBlocks = efi_null_block_write, + .FlushBlocks = efi_null_block_flush, +}; + +/** + * Nullify block I/O protocol + * + * @v block Block I/O protocol + */ +void efi_nullify_block ( EFI_BLOCK_IO_PROTOCOL *block ) { + + memcpy ( block, &efi_null_block, sizeof ( *block ) ); +} + +/****************************************************************************** + * + * PXE base code protocol + * + ****************************************************************************** + */ + +static EFI_STATUS EFIAPI +efi_null_pxe_start ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + BOOLEAN use_ipv6 __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_stop ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_dhcp ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + BOOLEAN sort __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_discover ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + UINT16 type __unused, UINT16 *layer __unused, + BOOLEAN bis __unused, + EFI_PXE_BASE_CODE_DISCOVER_INFO *info __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_mtftp ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + EFI_PXE_BASE_CODE_TFTP_OPCODE opcode __unused, + VOID *data __unused, BOOLEAN overwrite __unused, + UINT64 *len __unused, UINTN *blksize __unused, + EFI_IP_ADDRESS *ip __unused, UINT8 *filename __unused, + EFI_PXE_BASE_CODE_MTFTP_INFO *info __unused, + BOOLEAN callback __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_udp_write ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + UINT16 flags __unused, + EFI_IP_ADDRESS *dest_ip __unused, + EFI_PXE_BASE_CODE_UDP_PORT *dest_port __unused, + EFI_IP_ADDRESS *gateway __unused, + EFI_IP_ADDRESS *src_ip __unused, + EFI_PXE_BASE_CODE_UDP_PORT *src_port __unused, + UINTN *hdr_len __unused, VOID *hdr __unused, + UINTN *len __unused, VOID *data __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_udp_read ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + UINT16 flags __unused, + EFI_IP_ADDRESS *dest_ip __unused, + EFI_PXE_BASE_CODE_UDP_PORT *dest_port __unused, + EFI_IP_ADDRESS *src_ip __unused, + EFI_PXE_BASE_CODE_UDP_PORT *src_port __unused, + UINTN *hdr_len __unused, VOID *hdr __unused, + UINTN *len __unused, VOID *data __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_set_ip_filter ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + EFI_PXE_BASE_CODE_IP_FILTER *filter __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_arp ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + EFI_IP_ADDRESS *ip __unused, + EFI_MAC_ADDRESS *mac __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_set_parameters ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + BOOLEAN *autoarp __unused, + BOOLEAN *sendguid __unused, UINT8 *ttl __unused, + UINT8 *tos __unused, + BOOLEAN *callback __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_set_station_ip ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + EFI_IP_ADDRESS *ip __unused, + EFI_IP_ADDRESS *netmask __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_pxe_set_packets ( EFI_PXE_BASE_CODE_PROTOCOL *pxe __unused, + BOOLEAN *dhcpdisc_ok __unused, + BOOLEAN *dhcpack_ok __unused, + BOOLEAN *proxyoffer_ok __unused, + BOOLEAN *pxebsdisc_ok __unused, + BOOLEAN *pxebsack_ok __unused, + BOOLEAN *pxebsbis_ok __unused, + EFI_PXE_BASE_CODE_PACKET *dhcpdisc __unused, + EFI_PXE_BASE_CODE_PACKET *dhcpack __unused, + EFI_PXE_BASE_CODE_PACKET *proxyoffer __unused, + EFI_PXE_BASE_CODE_PACKET *pxebsdisc __unused, + EFI_PXE_BASE_CODE_PACKET *pxebsack __unused, + EFI_PXE_BASE_CODE_PACKET *pxebsbis __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_PXE_BASE_CODE_PROTOCOL efi_null_pxe = { + .Revision = EFI_PXE_BASE_CODE_PROTOCOL_REVISION, + .Start = efi_null_pxe_start, + .Stop = efi_null_pxe_stop, + .Dhcp = efi_null_pxe_dhcp, + .Discover = efi_null_pxe_discover, + .Mtftp = efi_null_pxe_mtftp, + .UdpWrite = efi_null_pxe_udp_write, + .UdpRead = efi_null_pxe_udp_read, + .SetIpFilter = efi_null_pxe_set_ip_filter, + .Arp = efi_null_pxe_arp, + .SetParameters = efi_null_pxe_set_parameters, + .SetStationIp = efi_null_pxe_set_station_ip, + .SetPackets = efi_null_pxe_set_packets, +}; + +/** + * Nullify PXE base code protocol + * + * @v pxe PXE base code protocol + */ +void efi_nullify_pxe ( EFI_PXE_BASE_CODE_PROTOCOL *pxe ) { + + memcpy ( pxe, &efi_null_pxe, offsetof ( typeof ( *pxe ), Mode ) ); + pxe->Mode->Started = FALSE; +} + +/****************************************************************************** + * + * Apple Net Boot protocol + * + ****************************************************************************** + */ + +static EFI_STATUS EFIAPI +efi_null_apple_dhcp ( EFI_APPLE_NET_BOOT_PROTOCOL *apple __unused, + UINTN *len __unused, VOID *data __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_apple_bsdp ( EFI_APPLE_NET_BOOT_PROTOCOL *apple __unused, + UINTN *len __unused, VOID *data __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_APPLE_NET_BOOT_PROTOCOL efi_null_apple = { + .GetDhcpResponse = efi_null_apple_dhcp, + .GetBsdpResponse = efi_null_apple_bsdp, +}; + +/** + * Nullify Apple Net Boot protocol + * + * @v apple Apple Net Boot protocol + */ +void efi_nullify_apple ( EFI_APPLE_NET_BOOT_PROTOCOL *apple ) { + + memcpy ( apple, &efi_null_apple, sizeof ( *apple ) ); +} diff --git a/src/interface/efi/efi_pxe.c b/src/interface/efi/efi_pxe.c index a1f81df59..4422dd283 100644 --- a/src/interface/efi/efi_pxe.c +++ b/src/interface/efi/efi_pxe.c @@ -41,6 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -1591,6 +1592,7 @@ int efi_pxe_install ( EFI_HANDLE handle, struct net_device *netdev ) { struct efi_pxe *pxe; struct in_addr ip; BOOLEAN use_ipv6; + int leak = 0; EFI_STATUS efirc; int rc; @@ -1643,14 +1645,23 @@ int efi_pxe_install ( EFI_HANDLE handle, struct net_device *netdev ) { pxe->name, efi_handle_name ( handle ) ); return 0; - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( handle, &efi_pxe_base_code_protocol_guid, &pxe->base, &efi_apple_net_boot_protocol_guid, &pxe->apple, - NULL ); + NULL ) ) != 0 ) { + DBGC ( pxe, "PXE %s could not uninstall: %s\n", + pxe->name, strerror ( -EEFI ( efirc ) ) ); + efi_nullify_pxe ( &pxe->base ); + efi_nullify_apple ( &pxe->apple ); + leak = 1; + } err_install_protocol: - ref_put ( &pxe->refcnt ); + if ( ! leak ) + ref_put ( &pxe->refcnt ); err_alloc: + if ( leak ) + DBGC ( pxe, "PXE %s nullified and leaked\n", pxe->name ); return rc; } @@ -1662,6 +1673,8 @@ int efi_pxe_install ( EFI_HANDLE handle, struct net_device *netdev ) { void efi_pxe_uninstall ( EFI_HANDLE handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_pxe *pxe; + int leak = 0; + EFI_STATUS efirc; /* Locate PXE base code */ pxe = efi_pxe_find ( handle ); @@ -1675,13 +1688,24 @@ void efi_pxe_uninstall ( EFI_HANDLE handle ) { efi_pxe_stop ( &pxe->base ); /* Uninstall PXE base code protocol */ - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( handle, &efi_pxe_base_code_protocol_guid, &pxe->base, &efi_apple_net_boot_protocol_guid, &pxe->apple, - NULL ); + NULL ) ) != 0 ) { + DBGC ( pxe, "PXE %s could not uninstall: %s\n", + pxe->name, strerror ( -EEFI ( efirc ) ) ); + efi_nullify_pxe ( &pxe->base ); + efi_nullify_apple ( &pxe->apple ); + leak = 1; + } /* Remove from list and drop list's reference */ list_del ( &pxe->list ); - ref_put ( &pxe->refcnt ); + if ( ! leak ) + ref_put ( &pxe->refcnt ); + + /* Report leakage, if applicable */ + if ( leak ) + DBGC ( pxe, "PXE %s nullified and leaked\n", pxe->name ); } diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index 91e796a2e..5285d322b 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -1626,6 +1627,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { struct efi_snp_device *snpdev; unsigned int ifcnt; void *interface; + int leak = 0; EFI_STATUS efirc; int rc; @@ -1794,7 +1796,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { list_del ( &snpdev->list ); if ( snpdev->package_list ) - efi_snp_hii_uninstall ( snpdev ); + leak |= efi_snp_hii_uninstall ( snpdev ); efi_child_del ( efidev->device, snpdev->handle ); err_efi_child_add: bs->CloseProtocol ( snpdev->handle, &efi_nii31_protocol_guid, @@ -1803,7 +1805,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { bs->CloseProtocol ( snpdev->handle, &efi_nii_protocol_guid, efi_image_handle, snpdev->handle ); err_open_nii: - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( snpdev->handle, &efi_simple_network_protocol_guid, &snpdev->snp, &efi_device_path_protocol_guid, snpdev->path, @@ -1811,17 +1813,30 @@ static int efi_snp_probe ( struct net_device *netdev ) { &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, &efi_load_file_protocol_guid, &snpdev->load_file, - NULL ); + NULL ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not uninstall: %s\n", + snpdev, strerror ( -EEFI ( efirc ) ) ); + efi_nullify_snp ( &snpdev->snp ); + efi_nullify_nii ( &snpdev->nii ); + efi_nullify_name2 ( &snpdev->name2 ); + efi_nullify_load_file ( &snpdev->load_file ); + leak = 1; + } err_install_protocol_interface: - free ( snpdev->path ); + if ( ! leak ) + free ( snpdev->path ); err_path: bs->CloseEvent ( snpdev->snp.WaitForPacket ); err_create_event: err_ll_addr_len: - netdev_put ( netdev ); - free ( snpdev ); + if ( ! leak ) { + netdev_put ( netdev ); + free ( snpdev ); + } err_alloc_snp: err_no_efidev: + if ( leak ) + DBGC ( snpdev, "SNPDEV %p nullified and leaked\n", snpdev ); return rc; } @@ -1858,6 +1873,8 @@ static void efi_snp_notify ( struct net_device *netdev ) { static void efi_snp_remove ( struct net_device *netdev ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev; + int leak = 0; + EFI_STATUS efirc; /* Locate SNP device */ snpdev = efi_snp_demux ( netdev ); @@ -1869,13 +1886,13 @@ static void efi_snp_remove ( struct net_device *netdev ) { /* Uninstall the SNP */ list_del ( &snpdev->list ); if ( snpdev->package_list ) - efi_snp_hii_uninstall ( snpdev ); + leak |= efi_snp_hii_uninstall ( snpdev ); efi_child_del ( snpdev->efidev->device, snpdev->handle ); bs->CloseProtocol ( snpdev->handle, &efi_nii_protocol_guid, efi_image_handle, snpdev->handle ); bs->CloseProtocol ( snpdev->handle, &efi_nii31_protocol_guid, efi_image_handle, snpdev->handle ); - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( snpdev->handle, &efi_simple_network_protocol_guid, &snpdev->snp, &efi_device_path_protocol_guid, snpdev->path, @@ -1883,11 +1900,26 @@ static void efi_snp_remove ( struct net_device *netdev ) { &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, &efi_load_file_protocol_guid, &snpdev->load_file, - NULL ); - free ( snpdev->path ); + NULL ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not uninstall: %s\n", + snpdev, strerror ( -EEFI ( efirc ) ) ); + efi_nullify_snp ( &snpdev->snp ); + efi_nullify_nii ( &snpdev->nii ); + efi_nullify_name2 ( &snpdev->name2 ); + efi_nullify_load_file ( &snpdev->load_file ); + leak = 1; + } + if ( ! leak ) + free ( snpdev->path ); bs->CloseEvent ( snpdev->snp.WaitForPacket ); - netdev_put ( snpdev->netdev ); - free ( snpdev ); + if ( ! leak ) { + netdev_put ( snpdev->netdev ); + free ( snpdev ); + } + + /* Report leakage, if applicable */ + if ( leak ) + DBGC ( snpdev, "SNPDEV %p nullified and leaked\n", snpdev ); } /** SNP driver */ diff --git a/src/interface/efi/efi_snp_hii.c b/src/interface/efi/efi_snp_hii.c index 05c068a8c..4bb7214ff 100644 --- a/src/interface/efi/efi_snp_hii.c +++ b/src/interface/efi/efi_snp_hii.c @@ -65,6 +65,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include /** EFI platform setup formset GUID */ @@ -659,7 +660,8 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { VENDOR_DEVICE_PATH *vendor_path; EFI_DEVICE_PATH_PROTOCOL *path_end; size_t path_prefix_len; - int efirc; + int leak = 0; + EFI_STATUS efirc; int rc; /* Do nothing if HII database protocol is not supported */ @@ -751,23 +753,37 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { efi_child_del ( snpdev->handle, snpdev->hii_child_handle ); err_efi_child_add: - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( snpdev->hii_child_handle, &efi_hii_config_access_protocol_guid, &snpdev->hii, - NULL ); + NULL ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not uninstall HII protocol: " + "%s\n", snpdev, strerror ( -EEFI ( efirc ) ) ); + efi_nullify_hii ( &snpdev->hii ); + leak = 1; + } err_install_protocol: - efihii->RemovePackageList ( efihii, snpdev->hii_handle ); + if ( ! leak ) + efihii->RemovePackageList ( efihii, snpdev->hii_handle ); err_new_package_list: - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( snpdev->hii_child_handle, &efi_device_path_protocol_guid, snpdev->hii_child_path, - NULL ); + NULL ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not uninstall HII path: %s\n", + snpdev, strerror ( -EEFI ( efirc ) ) ); + leak = 1; + } err_hii_child_handle: - free ( snpdev->hii_child_path ); - snpdev->hii_child_path = NULL; + if ( ! leak ) { + free ( snpdev->hii_child_path ); + snpdev->hii_child_path = NULL; + } err_alloc_child_path: - free ( snpdev->package_list ); - snpdev->package_list = NULL; + if ( ! leak ) { + free ( snpdev->package_list ); + snpdev->package_list = NULL; + } err_build_package_list: err_no_hii: return rc; @@ -777,27 +793,47 @@ int efi_snp_hii_install ( struct efi_snp_device *snpdev ) { * Uninstall HII protocol and package for SNP device * * @v snpdev SNP device + * @ret leak Uninstallation failed: leak memory */ -void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ) { +int efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + int leak = 0; + EFI_STATUS efirc; /* Do nothing if HII database protocol is not supported */ if ( ! efihii ) - return; + return 0; /* Uninstall protocols and remove package list */ efi_child_del ( snpdev->handle, snpdev->hii_child_handle ); - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( snpdev->hii_child_handle, &efi_hii_config_access_protocol_guid, &snpdev->hii, - NULL ); - efihii->RemovePackageList ( efihii, snpdev->hii_handle ); - bs->UninstallMultipleProtocolInterfaces ( + NULL ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not uninstall HII protocol: " + "%s\n", snpdev, strerror ( -EEFI ( efirc ) ) ); + efi_nullify_hii ( &snpdev->hii ); + leak = 1; + } + if ( ! leak ) + efihii->RemovePackageList ( efihii, snpdev->hii_handle ); + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( snpdev->hii_child_handle, &efi_device_path_protocol_guid, snpdev->hii_child_path, - NULL ); - free ( snpdev->hii_child_path ); - snpdev->hii_child_path = NULL; - free ( snpdev->package_list ); - snpdev->package_list = NULL; + NULL ) ) != 0 ) { + DBGC ( snpdev, "SNPDEV %p could not uninstall HII path: %s\n", + snpdev, strerror ( -EEFI ( efirc ) ) ); + leak = 1; + } + if ( ! leak ) { + free ( snpdev->hii_child_path ); + snpdev->hii_child_path = NULL; + free ( snpdev->package_list ); + snpdev->package_list = NULL; + } + + /* Report leakage, if applicable */ + if ( leak ) + DBGC ( snpdev, "SNPDEV %p HII nullified and leaked\n", snpdev ); + return leak; } -- cgit v1.2.3-55-g7522 From 16873703ddea2d64fac1809967ef5198b8764baa Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 30 Oct 2020 13:51:30 +0000 Subject: [efi] Avoid dragging in USB subsystem via efi_usb_path() Commit 87e39a9c9 ("[efi] Split efi_usb_path() out to a separate function") unintentionally introduced an undefined symbol reference from efi_path.o to usb_depth(), causing the USB subsystem to become a dependency of all EFI builds. Fix by converting usb_depth() to a static inline function. Reported-by: Pico Mitchell Signed-off-by: Michael Brown --- src/drivers/bus/usb.c | 17 ----------------- src/include/ipxe/usb.h | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 18 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c index 70a86c913..428ae26c1 100644 --- a/src/drivers/bus/usb.c +++ b/src/drivers/bus/usb.c @@ -2277,23 +2277,6 @@ unsigned int usb_route_string ( struct usb_device *usb ) { return route; } -/** - * Get USB depth - * - * @v usb USB device - * @ret depth Hub depth - */ -unsigned int usb_depth ( struct usb_device *usb ) { - struct usb_device *parent; - unsigned int depth; - - /* Navigate up to root hub, constructing depth as we go */ - for ( depth = 0 ; ( parent = usb->port->hub->usb ) ; usb = parent ) - depth++; - - return depth; -} - /** * Get USB root hub port * diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h index f41f4c355..911247ede 100644 --- a/src/include/ipxe/usb.h +++ b/src/include/ipxe/usb.h @@ -1239,6 +1239,23 @@ usb_set_interface ( struct usb_device *usb, unsigned int interface, NULL, 0 ); } +/** + * Get USB depth + * + * @v usb USB device + * @ret depth Hub depth + */ +static inline unsigned int usb_depth ( struct usb_device *usb ) { + struct usb_device *parent; + unsigned int depth; + + /* Navigate up to root hub, constructing depth as we go */ + for ( depth = 0 ; ( parent = usb->port->hub->usb ) ; usb = parent ) + depth++; + + return depth; +} + extern struct list_head usb_buses; extern struct usb_interface_descriptor * @@ -1274,7 +1291,6 @@ extern struct usb_bus * find_usb_bus_by_location ( unsigned int bus_type, extern int usb_alloc_address ( struct usb_bus *bus ); extern void usb_free_address ( struct usb_bus *bus, unsigned int address ); extern unsigned int usb_route_string ( struct usb_device *usb ); -extern unsigned int usb_depth ( struct usb_device *usb ); extern struct usb_port * usb_root_hub_port ( struct usb_device *usb ); extern struct usb_port * usb_transaction_translator ( struct usb_device *usb ); -- cgit v1.2.3-55-g7522 From 36dde9b0bf27ae411af677ca1fa3075113133cfe Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 4 Nov 2020 15:08:48 +0000 Subject: [efi] Retain a long-lived reference to the EFI_PCI_IO_PROTOCOL instance Provide opened EFI PCI devices with access to the underlying EFI_PCI_IO_PROTOCOL instance, in order to facilitate the future use of the DMA mapping methods within the fast data path. Do not require the use of this stored EFI_PCI_IO_PROTOCOL instance for memory-mapped I/O (since the entire point of memory-mapped I/O as a concept is to avoid this kind of unnecessary complexity) or for slow-path PCI configuration space accesses (since these may be required for access to PCI bus:dev.fn addresses that do not correspond to a device bound via our driver binding protocol instance). Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_pci.h | 12 +++++-- src/interface/efi/efi_bofm.c | 15 +++++---- src/interface/efi/efi_pci.c | 74 ++++++++++++++++++++++-------------------- src/interface/efi/efi_utils.c | 8 ++--- 4 files changed, 60 insertions(+), 49 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_pci.h b/src/include/ipxe/efi/efi_pci.h index 6dd945f05..2ea1a8f0e 100644 --- a/src/include/ipxe/efi/efi_pci.h +++ b/src/include/ipxe/efi/efi_pci.h @@ -17,9 +17,17 @@ static inline EFIAPI uint64_t LShiftU64 ( UINT64 value, UINTN shift ) { return ( value << shift ); } +/** An EFI PCI device */ +struct efi_pci_device { + /** PCI device */ + struct pci_device pci; + /** PCI I/O protocol */ + EFI_PCI_IO_PROTOCOL *io; +}; + extern int efipci_open ( EFI_HANDLE device, UINT32 attributes, - struct pci_device *pci ); + struct efi_pci_device *efipci ); extern void efipci_close ( EFI_HANDLE device ); -extern int efipci_info ( EFI_HANDLE device, struct pci_device *pci ); +extern int efipci_info ( EFI_HANDLE device, struct efi_pci_device *efipci ); #endif /* _IPXE_EFI_PCI_H */ diff --git a/src/interface/efi/efi_bofm.c b/src/interface/efi/efi_bofm.c index 00f6a1d5c..15f3837cc 100644 --- a/src/interface/efi/efi_bofm.c +++ b/src/interface/efi/efi_bofm.c @@ -164,7 +164,7 @@ static EFI_GUID bofm2_protocol_guid = */ static int efi_bofm_supported ( EFI_HANDLE device ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct pci_device pci; + struct efi_pci_device efipci; union { IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *bofm1; void *interface; @@ -173,11 +173,11 @@ static int efi_bofm_supported ( EFI_HANDLE device ) { int rc; /* Get PCI device information */ - if ( ( rc = efipci_info ( device, &pci ) ) != 0 ) + if ( ( rc = efipci_info ( device, &efipci ) ) != 0 ) return rc; /* Look for a BOFM driver */ - if ( ( rc = bofm_find_driver ( &pci ) ) != 0 ) { + if ( ( rc = bofm_find_driver ( &efipci.pci ) ) != 0 ) { DBGCP ( device, "EFIBOFM %s has no driver\n", efi_handle_name ( device ) ); return rc; @@ -204,7 +204,7 @@ static int efi_bofm_supported ( EFI_HANDLE device ) { } DBGC ( device, "EFIBOFM %s has driver \"%s\"\n", - efi_handle_name ( device ), pci.id->name ); + efi_handle_name ( device ), efipci.pci.id->name ); return 0; } @@ -225,7 +225,7 @@ static int efi_bofm_start ( struct efi_device *efidev ) { IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL2 *bofm2; void *interface; } bofm2; - struct pci_device pci; + struct efi_pci_device efipci; IBM_BOFM_TABLE *bofmtab; IBM_BOFM_TABLE *bofmtab2; int bofmrc; @@ -234,7 +234,7 @@ static int efi_bofm_start ( struct efi_device *efidev ) { /* Open PCI device, if possible */ if ( ( rc = efipci_open ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL, - &pci ) ) != 0 ) + &efipci ) ) != 0 ) goto err_open; /* Locate BOFM protocol */ @@ -274,7 +274,8 @@ static int efi_bofm_start ( struct efi_device *efidev ) { efi_handle_name ( device ) ); DBGC2_HD ( device, bofmtab2, bofmtab2->Parameters.Length ); } - bofmrc = bofm ( virt_to_user ( bofmtab2 ? bofmtab2 : bofmtab ), &pci ); + bofmrc = bofm ( virt_to_user ( bofmtab2 ? bofmtab2 : bofmtab ), + &efipci.pci ); DBGC ( device, "EFIBOFM %s status %08x\n", efi_handle_name ( device ), bofmrc ); DBGC2 ( device, "EFIBOFM %s version 1 after processing:\n", diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index f72ba13b4..27ab61733 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -316,11 +316,11 @@ PROVIDE_PCIAPI ( efi, pci_ioremap, efipci_ioremap ); * * @v device EFI device handle * @v attributes Protocol opening attributes - * @v pci PCI device to fill in + * @v efipci EFI PCI device to fill in * @ret rc Return status code */ int efipci_open ( EFI_HANDLE device, UINT32 attributes, - struct pci_device *pci ) { + struct efi_pci_device *efipci ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; union { EFI_PCI_IO_PROTOCOL *pci_io; @@ -340,6 +340,7 @@ int efipci_open ( EFI_HANDLE device, UINT32 attributes, efi_handle_name ( device ), strerror ( rc ) ); goto err_open_protocol; } + efipci->io = pci_io.pci_io; /* Get PCI bus:dev.fn address */ if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io, &pci_segment, @@ -351,9 +352,9 @@ int efipci_open ( EFI_HANDLE device, UINT32 attributes, goto err_get_location; } busdevfn = PCI_BUSDEVFN ( pci_segment, pci_bus, pci_dev, pci_fn ); - pci_init ( pci, busdevfn ); + pci_init ( &efipci->pci, busdevfn ); DBGCP ( device, "EFIPCI " PCI_FMT " is %s\n", - PCI_ARGS ( pci ), efi_handle_name ( device ) ); + PCI_ARGS ( &efipci->pci ), efi_handle_name ( device ) ); /* Try to enable I/O cycles, memory cycles, and bus mastering. * Some platforms will 'helpfully' report errors if these bits @@ -372,10 +373,10 @@ int efipci_open ( EFI_HANDLE device, UINT32 attributes, EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL ); /* Populate PCI device */ - if ( ( rc = pci_read_config ( pci ) ) != 0 ) { + if ( ( rc = pci_read_config ( &efipci->pci ) ) != 0 ) { DBGC ( device, "EFIPCI " PCI_FMT " cannot read PCI " "configuration: %s\n", - PCI_ARGS ( pci ), strerror ( rc ) ); + PCI_ARGS ( &efipci->pci ), strerror ( rc ) ); goto err_pci_read_config; } @@ -405,15 +406,15 @@ void efipci_close ( EFI_HANDLE device ) { * Get EFI PCI device information * * @v device EFI device handle - * @v pci PCI device to fill in + * @v efipci EFI PCI device to fill in * @ret rc Return status code */ -int efipci_info ( EFI_HANDLE device, struct pci_device *pci ) { +int efipci_info ( EFI_HANDLE device, struct efi_pci_device *efipci ) { int rc; /* Open PCI device, if possible */ if ( ( rc = efipci_open ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL, - pci ) ) != 0 ) + efipci ) ) != 0 ) return rc; /* Close PCI device */ @@ -436,23 +437,24 @@ int efipci_info ( EFI_HANDLE device, struct pci_device *pci ) { * @ret rc Return status code */ static int efipci_supported ( EFI_HANDLE device ) { - struct pci_device pci; + struct efi_pci_device efipci; int rc; /* Get PCI device information */ - if ( ( rc = efipci_info ( device, &pci ) ) != 0 ) + if ( ( rc = efipci_info ( device, &efipci ) ) != 0 ) return rc; /* Look for a driver */ - if ( ( rc = pci_find_driver ( &pci ) ) != 0 ) { + if ( ( rc = pci_find_driver ( &efipci.pci ) ) != 0 ) { DBGC ( device, "EFIPCI " PCI_FMT " (%04x:%04x class %06x) " - "has no driver\n", PCI_ARGS ( &pci ), pci.vendor, - pci.device, pci.class ); + "has no driver\n", PCI_ARGS ( &efipci.pci ), + efipci.pci.vendor, efipci.pci.device, + efipci.pci.class ); return rc; } DBGC ( device, "EFIPCI " PCI_FMT " (%04x:%04x class %06x) has driver " - "\"%s\"\n", PCI_ARGS ( &pci ), pci.vendor, pci.device, - pci.class, pci.id->name ); + "\"%s\"\n", PCI_ARGS ( &efipci.pci ), efipci.pci.vendor, + efipci.pci.device, efipci.pci.class, efipci.pci.id->name ); return 0; } @@ -465,12 +467,12 @@ static int efipci_supported ( EFI_HANDLE device ) { */ static int efipci_start ( struct efi_device *efidev ) { EFI_HANDLE device = efidev->device; - struct pci_device *pci; + struct efi_pci_device *efipci; int rc; /* Allocate PCI device */ - pci = zalloc ( sizeof ( *pci ) ); - if ( ! pci ) { + efipci = zalloc ( sizeof ( *efipci ) ); + if ( ! efipci ) { rc = -ENOMEM; goto err_alloc; } @@ -478,7 +480,7 @@ static int efipci_start ( struct efi_device *efidev ) { /* Open PCI device */ if ( ( rc = efipci_open ( device, ( EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE ), - pci ) ) != 0 ) { + efipci ) ) != 0 ) { DBGC ( device, "EFIPCI %s could not open PCI device: %s\n", efi_handle_name ( device ), strerror ( rc ) ); DBGC_EFI_OPENERS ( device, device, &efi_pci_io_protocol_guid ); @@ -486,36 +488,36 @@ static int efipci_start ( struct efi_device *efidev ) { } /* Find driver */ - if ( ( rc = pci_find_driver ( pci ) ) != 0 ) { + if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) { DBGC ( device, "EFIPCI " PCI_FMT " has no driver\n", - PCI_ARGS ( pci ) ); + PCI_ARGS ( &efipci->pci ) ); goto err_find_driver; } /* Mark PCI device as a child of the EFI device */ - pci->dev.parent = &efidev->dev; - list_add ( &pci->dev.siblings, &efidev->dev.children ); + efipci->pci.dev.parent = &efidev->dev; + list_add ( &efipci->pci.dev.siblings, &efidev->dev.children ); /* Probe driver */ - if ( ( rc = pci_probe ( pci ) ) != 0 ) { + if ( ( rc = pci_probe ( &efipci->pci ) ) != 0 ) { DBGC ( device, "EFIPCI " PCI_FMT " could not probe driver " - "\"%s\": %s\n", PCI_ARGS ( pci ), pci->id->name, - strerror ( rc ) ); + "\"%s\": %s\n", PCI_ARGS ( &efipci->pci ), + efipci->pci.id->name, strerror ( rc ) ); goto err_probe; } DBGC ( device, "EFIPCI " PCI_FMT " using driver \"%s\"\n", - PCI_ARGS ( pci ), pci->id->name ); + PCI_ARGS ( &efipci->pci ), efipci->pci.id->name ); - efidev_set_drvdata ( efidev, pci ); + efidev_set_drvdata ( efidev, efipci ); return 0; - pci_remove ( pci ); + pci_remove ( &efipci->pci ); err_probe: - list_del ( &pci->dev.siblings ); + list_del ( &efipci->pci.dev.siblings ); err_find_driver: efipci_close ( device ); err_open: - free ( pci ); + free ( efipci ); err_alloc: return rc; } @@ -526,13 +528,13 @@ static int efipci_start ( struct efi_device *efidev ) { * @v efidev EFI device */ static void efipci_stop ( struct efi_device *efidev ) { - struct pci_device *pci = efidev_get_drvdata ( efidev ); + struct efi_pci_device *efipci = efidev_get_drvdata ( efidev ); EFI_HANDLE device = efidev->device; - pci_remove ( pci ); - list_del ( &pci->dev.siblings ); + pci_remove ( &efipci->pci ); + list_del ( &efipci->pci.dev.siblings ); efipci_close ( device ); - free ( pci ); + free ( efipci ); } /** EFI PCI driver */ diff --git a/src/interface/efi/efi_utils.c b/src/interface/efi/efi_utils.c index f8ffce915..8e660e9d7 100644 --- a/src/interface/efi/efi_utils.c +++ b/src/interface/efi/efi_utils.c @@ -145,7 +145,7 @@ void efi_child_del ( EFI_HANDLE parent, EFI_HANDLE child ) { static int efi_pci_info ( EFI_HANDLE device, const char *prefix, struct device *dev ) { EFI_HANDLE pci_device; - struct pci_device pci; + struct efi_pci_device efipci; int rc; /* Find parent PCI device */ @@ -157,16 +157,16 @@ static int efi_pci_info ( EFI_HANDLE device, const char *prefix, } /* Get PCI device information */ - if ( ( rc = efipci_info ( pci_device, &pci ) ) != 0 ) { + if ( ( rc = efipci_info ( pci_device, &efipci ) ) != 0 ) { DBGC ( device, "EFIDEV %s could not get PCI information: %s\n", efi_handle_name ( device ), strerror ( rc ) ); return rc; } /* Populate device information */ - memcpy ( &dev->desc, &pci.dev.desc, sizeof ( dev->desc ) ); + memcpy ( &dev->desc, &efipci.pci.dev.desc, sizeof ( dev->desc ) ); snprintf ( dev->name, sizeof ( dev->name ), "%s-%s", - prefix, pci.dev.name ); + prefix, efipci.pci.dev.name ); return 0; } -- cgit v1.2.3-55-g7522 From be1c87b72237f633c4f4b05bcb133acf2967d788 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 5 Nov 2020 19:08:48 +0000 Subject: [malloc] Rename malloc_dma() to malloc_phys() The malloc_dma() function allocates memory with specified physical alignment, and is typically (though not exclusively) used to allocate memory for DMA. Rename to malloc_phys() to more closely match the functionality, and to create name space for functions that specifically allocate and map DMA-capable buffers. Signed-off-by: Michael Brown --- src/arch/x86/drivers/hyperv/hyperv.c | 12 ++--- src/arch/x86/drivers/xen/hvm.c | 4 +- src/core/iobuf.c | 12 ++--- src/core/malloc.c | 4 +- src/drivers/infiniband/arbel.c | 62 +++++++++++----------- src/drivers/infiniband/golan.c | 58 ++++++++++---------- src/drivers/infiniband/hermon.c | 60 ++++++++++----------- src/drivers/infiniband/linda.c | 16 +++--- .../mlx_utils_flexboot/src/mlx_memory_priv.c | 4 +- src/drivers/infiniband/qib7322.c | 16 +++--- src/drivers/net/3c90x.c | 8 +-- src/drivers/net/ath/ath5k/ath5k.c | 6 +-- src/drivers/net/ath/ath9k/ath9k_init.c | 6 +-- src/drivers/net/atl1e.c | 4 +- src/drivers/net/b44.c | 12 ++--- src/drivers/net/bnxt/bnxt.c | 30 +++++------ src/drivers/net/eepro100.c | 18 +++---- src/drivers/net/ena.c | 24 ++++----- src/drivers/net/etherfabric.c | 4 +- src/drivers/net/exanic.c | 6 +-- src/drivers/net/forcedeth.c | 4 +- src/drivers/net/icplus.c | 6 +-- src/drivers/net/igbvf/igbvf_main.c | 10 ++-- src/drivers/net/intel.c | 4 +- src/drivers/net/intelxl.c | 10 ++-- src/drivers/net/jme.c | 8 +-- src/drivers/net/myri10ge.c | 8 +-- src/drivers/net/myson.c | 6 +-- src/drivers/net/natsemi.c | 6 +-- src/drivers/net/netfront.c | 6 +-- src/drivers/net/pcnet32.c | 8 +-- src/drivers/net/phantom/phantom.c | 16 +++--- src/drivers/net/realtek.c | 10 ++-- src/drivers/net/rhine.c | 4 +- src/drivers/net/rtl818x/rtl818x.c | 12 ++--- src/drivers/net/sfc/efx_hunt.c | 4 +- src/drivers/net/sis190.c | 8 +-- src/drivers/net/skge.c | 4 +- src/drivers/net/sky2.c | 14 ++--- src/drivers/net/tg3/tg3.c | 20 +++---- src/drivers/net/velocity.c | 12 +++-- src/drivers/net/vmxnet3.c | 7 +-- src/drivers/net/vxge/vxge_config.c | 12 ++--- src/drivers/usb/ehci.c | 29 +++++----- src/drivers/usb/uhci.c | 26 ++++----- src/drivers/usb/xhci.c | 42 +++++++-------- src/include/ipxe/malloc.h | 32 +++++------ src/interface/hyperv/vmbus.c | 6 +-- 48 files changed, 350 insertions(+), 350 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/arch/x86/drivers/hyperv/hyperv.c b/src/arch/x86/drivers/hyperv/hyperv.c index 1903d1db2..9d3a42da0 100644 --- a/src/arch/x86/drivers/hyperv/hyperv.c +++ b/src/arch/x86/drivers/hyperv/hyperv.c @@ -83,7 +83,7 @@ hv_alloc_pages ( struct hv_hypervisor *hv, ... ) { /* Allocate and zero pages */ va_start ( args, hv ); for ( i = 0 ; ( ( page = va_arg ( args, void ** ) ) != NULL ); i++ ) { - *page = malloc_dma ( PAGE_SIZE, PAGE_SIZE ); + *page = malloc_phys ( PAGE_SIZE, PAGE_SIZE ); if ( ! *page ) goto err_alloc; memset ( *page, 0, PAGE_SIZE ); @@ -97,7 +97,7 @@ hv_alloc_pages ( struct hv_hypervisor *hv, ... ) { va_start ( args, hv ); for ( ; i >= 0 ; i-- ) { page = va_arg ( args, void ** ); - free_dma ( *page, PAGE_SIZE ); + free_phys ( *page, PAGE_SIZE ); } va_end ( args ); return -ENOMEM; @@ -116,7 +116,7 @@ hv_free_pages ( struct hv_hypervisor *hv, ... ) { va_start ( args, hv ); while ( ( page = va_arg ( args, void * ) ) != NULL ) - free_dma ( page, PAGE_SIZE ); + free_phys ( page, PAGE_SIZE ); va_end ( args ); } @@ -131,8 +131,8 @@ static int hv_alloc_message ( struct hv_hypervisor *hv ) { /* Allocate buffer. Must be aligned to at least 8 bytes and * must not cross a page boundary, so align on its own size. */ - hv->message = malloc_dma ( sizeof ( *hv->message ), - sizeof ( *hv->message ) ); + hv->message = malloc_phys ( sizeof ( *hv->message ), + sizeof ( *hv->message ) ); if ( ! hv->message ) return -ENOMEM; @@ -147,7 +147,7 @@ static int hv_alloc_message ( struct hv_hypervisor *hv ) { static void hv_free_message ( struct hv_hypervisor *hv ) { /* Free buffer */ - free_dma ( hv->message, sizeof ( *hv->message ) ); + free_phys ( hv->message, sizeof ( *hv->message ) ); } /** diff --git a/src/arch/x86/drivers/xen/hvm.c b/src/arch/x86/drivers/xen/hvm.c index 311f343ca..b77cdd14c 100644 --- a/src/arch/x86/drivers/xen/hvm.c +++ b/src/arch/x86/drivers/xen/hvm.c @@ -106,7 +106,7 @@ static int hvm_map_hypercall ( struct hvm_device *hvm ) { /* Allocate pages */ hvm->hypercall_len = ( pages * PAGE_SIZE ); - hvm->xen.hypercall = malloc_dma ( hvm->hypercall_len, PAGE_SIZE ); + hvm->xen.hypercall = malloc_phys ( hvm->hypercall_len, PAGE_SIZE ); if ( ! hvm->xen.hypercall ) { DBGC ( hvm, "HVM could not allocate %d hypercall page(s)\n", pages ); @@ -141,7 +141,7 @@ static int hvm_map_hypercall ( struct hvm_device *hvm ) { static void hvm_unmap_hypercall ( struct hvm_device *hvm ) { /* Free pages */ - free_dma ( hvm->xen.hypercall, hvm->hypercall_len ); + free_phys ( hvm->xen.hypercall, hvm->hypercall_len ); } /** diff --git a/src/core/iobuf.c b/src/core/iobuf.c index 0ee53e038..941bb3446 100644 --- a/src/core/iobuf.c +++ b/src/core/iobuf.c @@ -88,8 +88,8 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { len += ( ( - len - offset ) & ( __alignof__ ( *iobuf ) - 1 ) ); /* Allocate memory for buffer plus descriptor */ - data = malloc_dma_offset ( len + sizeof ( *iobuf ), align, - offset ); + data = malloc_phys_offset ( len + sizeof ( *iobuf ), align, + offset ); if ( ! data ) return NULL; iobuf = ( data + len ); @@ -97,14 +97,14 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { } else { /* Allocate memory for buffer */ - data = malloc_dma_offset ( len, align, offset ); + data = malloc_phys_offset ( len, align, offset ); if ( ! data ) return NULL; /* Allocate memory for descriptor */ iobuf = malloc ( sizeof ( *iobuf ) ); if ( ! iobuf ) { - free_dma ( data, len ); + free_phys ( data, len ); return NULL; } } @@ -159,12 +159,12 @@ void free_iob ( struct io_buffer *iobuf ) { if ( iobuf->end == iobuf ) { /* Descriptor is inline */ - free_dma ( iobuf->head, ( len + sizeof ( *iobuf ) ) ); + free_phys ( iobuf->head, ( len + sizeof ( *iobuf ) ) ); } else { /* Descriptor is detached */ - free_dma ( iobuf->head, len ); + free_phys ( iobuf->head, len ); free ( iobuf ); } } diff --git a/src/core/malloc.c b/src/core/malloc.c index 0a7843a14..8499ab45a 100644 --- a/src/core/malloc.c +++ b/src/core/malloc.c @@ -596,8 +596,8 @@ void * malloc ( size_t size ) { * * @v ptr Memory allocated by malloc(), or NULL * - * Memory allocated with malloc_dma() cannot be freed with free(); it - * must be freed with free_dma() instead. + * Memory allocated with malloc_phys() cannot be freed with free(); it + * must be freed with free_phys() instead. * * If @c ptr is NULL, no action is taken. */ diff --git a/src/drivers/infiniband/arbel.c b/src/drivers/infiniband/arbel.c index eb7911aa4..fb48487f3 100644 --- a/src/drivers/infiniband/arbel.c +++ b/src/drivers/infiniband/arbel.c @@ -639,8 +639,8 @@ static int arbel_create_cq ( struct ib_device *ibdev, /* Allocate completion queue itself */ arbel_cq->cqe_size = ( cq->num_cqes * sizeof ( arbel_cq->cqe[0] ) ); - arbel_cq->cqe = malloc_dma ( arbel_cq->cqe_size, - sizeof ( arbel_cq->cqe[0] ) ); + arbel_cq->cqe = malloc_phys ( arbel_cq->cqe_size, + sizeof ( arbel_cq->cqe[0] ) ); if ( ! arbel_cq->cqe ) { rc = -ENOMEM; goto err_cqe; @@ -697,7 +697,7 @@ static int arbel_create_cq ( struct ib_device *ibdev, err_sw2hw_cq: MLX_FILL_1 ( ci_db_rec, 1, res, ARBEL_UAR_RES_NONE ); MLX_FILL_1 ( arm_db_rec, 1, res, ARBEL_UAR_RES_NONE ); - free_dma ( arbel_cq->cqe, arbel_cq->cqe_size ); + free_phys ( arbel_cq->cqe, arbel_cq->cqe_size ); err_cqe: free ( arbel_cq ); err_arbel_cq: @@ -737,7 +737,7 @@ static void arbel_destroy_cq ( struct ib_device *ibdev, MLX_FILL_1 ( arm_db_rec, 1, res, ARBEL_UAR_RES_NONE ); /* Free memory */ - free_dma ( arbel_cq->cqe, arbel_cq->cqe_size ); + free_phys ( arbel_cq->cqe, arbel_cq->cqe_size ); free ( arbel_cq ); /* Mark queue number as free */ @@ -873,8 +873,8 @@ static int arbel_create_send_wq ( struct arbel_send_work_queue *arbel_send_wq, /* Allocate work queue */ arbel_send_wq->wqe_size = ( num_wqes * sizeof ( arbel_send_wq->wqe[0] ) ); - arbel_send_wq->wqe = malloc_dma ( arbel_send_wq->wqe_size, - sizeof ( arbel_send_wq->wqe[0] ) ); + arbel_send_wq->wqe = malloc_phys ( arbel_send_wq->wqe_size, + sizeof ( arbel_send_wq->wqe[0] ) ); if ( ! arbel_send_wq->wqe ) return -ENOMEM; memset ( arbel_send_wq->wqe, 0, arbel_send_wq->wqe_size ); @@ -914,8 +914,8 @@ static int arbel_create_recv_wq ( struct arbel_recv_work_queue *arbel_recv_wq, /* Allocate work queue */ arbel_recv_wq->wqe_size = ( num_wqes * sizeof ( arbel_recv_wq->wqe[0] ) ); - arbel_recv_wq->wqe = malloc_dma ( arbel_recv_wq->wqe_size, - sizeof ( arbel_recv_wq->wqe[0] ) ); + arbel_recv_wq->wqe = malloc_phys ( arbel_recv_wq->wqe_size, + sizeof ( arbel_recv_wq->wqe[0] ) ); if ( ! arbel_recv_wq->wqe ) { rc = -ENOMEM; goto err_alloc_wqe; @@ -927,8 +927,8 @@ static int arbel_create_recv_wq ( struct arbel_recv_work_queue *arbel_recv_wq, ( type == IB_QPT_UD ) ) { arbel_recv_wq->grh_size = ( num_wqes * sizeof ( arbel_recv_wq->grh[0] ) ); - arbel_recv_wq->grh = malloc_dma ( arbel_recv_wq->grh_size, - sizeof ( void * ) ); + arbel_recv_wq->grh = malloc_phys ( arbel_recv_wq->grh_size, + sizeof ( void * ) ); if ( ! arbel_recv_wq->grh ) { rc = -ENOMEM; goto err_alloc_grh; @@ -954,9 +954,9 @@ static int arbel_create_recv_wq ( struct arbel_recv_work_queue *arbel_recv_wq, return 0; - free_dma ( arbel_recv_wq->grh, arbel_recv_wq->grh_size ); + free_phys ( arbel_recv_wq->grh, arbel_recv_wq->grh_size ); err_alloc_grh: - free_dma ( arbel_recv_wq->wqe, arbel_recv_wq->wqe_size ); + free_phys ( arbel_recv_wq->wqe, arbel_recv_wq->wqe_size ); err_alloc_wqe: return rc; } @@ -1102,10 +1102,10 @@ static int arbel_create_qp ( struct ib_device *ibdev, MLX_FILL_1 ( send_db_rec, 1, res, ARBEL_UAR_RES_NONE ); MLX_FILL_1 ( recv_db_rec, 1, res, ARBEL_UAR_RES_NONE ); err_unsupported_address_split: - free_dma ( arbel_qp->recv.grh, arbel_qp->recv.grh_size ); - free_dma ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size ); + free_phys ( arbel_qp->recv.grh, arbel_qp->recv.grh_size ); + free_phys ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size ); err_create_recv_wq: - free_dma ( arbel_qp->send.wqe, arbel_qp->send.wqe_size ); + free_phys ( arbel_qp->send.wqe, arbel_qp->send.wqe_size ); err_create_send_wq: free ( arbel_qp ); err_arbel_qp: @@ -1231,9 +1231,9 @@ static void arbel_destroy_qp ( struct ib_device *ibdev, MLX_FILL_1 ( recv_db_rec, 1, res, ARBEL_UAR_RES_NONE ); /* Free memory */ - free_dma ( arbel_qp->recv.grh, arbel_qp->recv.grh_size ); - free_dma ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size ); - free_dma ( arbel_qp->send.wqe, arbel_qp->send.wqe_size ); + free_phys ( arbel_qp->recv.grh, arbel_qp->recv.grh_size ); + free_phys ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size ); + free_phys ( arbel_qp->send.wqe, arbel_qp->send.wqe_size ); free ( arbel_qp ); /* Mark queue number as free */ @@ -1758,8 +1758,8 @@ static int arbel_create_eq ( struct arbel *arbel ) { /* Allocate event queue itself */ arbel_eq->eqe_size = ( ARBEL_NUM_EQES * sizeof ( arbel_eq->eqe[0] ) ); - arbel_eq->eqe = malloc_dma ( arbel_eq->eqe_size, - sizeof ( arbel_eq->eqe[0] ) ); + arbel_eq->eqe = malloc_phys ( arbel_eq->eqe_size, + sizeof ( arbel_eq->eqe[0] ) ); if ( ! arbel_eq->eqe ) { rc = -ENOMEM; goto err_eqe; @@ -1806,7 +1806,7 @@ static int arbel_create_eq ( struct arbel *arbel ) { err_map_eq: arbel_cmd_hw2sw_eq ( arbel, arbel_eq->eqn, &eqctx ); err_sw2hw_eq: - free_dma ( arbel_eq->eqe, arbel_eq->eqe_size ); + free_phys ( arbel_eq->eqe, arbel_eq->eqe_size ); err_eqe: memset ( arbel_eq, 0, sizeof ( *arbel_eq ) ); return rc; @@ -1844,7 +1844,7 @@ static void arbel_destroy_eq ( struct arbel *arbel ) { } /* Free memory */ - free_dma ( arbel_eq->eqe, arbel_eq->eqe_size ); + free_phys ( arbel_eq->eqe, arbel_eq->eqe_size ); memset ( arbel_eq, 0, sizeof ( *arbel_eq ) ); } @@ -2455,7 +2455,7 @@ static int arbel_alloc_icm ( struct arbel *arbel, icm_phys = user_to_phys ( arbel->icm, 0 ); /* Allocate doorbell UAR */ - arbel->db_rec = malloc_dma ( ARBEL_PAGE_SIZE, ARBEL_PAGE_SIZE ); + arbel->db_rec = malloc_phys ( ARBEL_PAGE_SIZE, ARBEL_PAGE_SIZE ); if ( ! arbel->db_rec ) { rc = -ENOMEM; goto err_alloc_doorbell; @@ -2513,7 +2513,7 @@ static int arbel_alloc_icm ( struct arbel *arbel, err_map_icm: arbel_cmd_unmap_icm_aux ( arbel ); err_map_icm_aux: - free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE ); + free_phys ( arbel->db_rec, ARBEL_PAGE_SIZE ); arbel->db_rec= NULL; err_alloc_doorbell: err_alloc_icm: @@ -2536,7 +2536,7 @@ static void arbel_free_icm ( struct arbel *arbel ) { arbel_cmd_unmap_icm ( arbel, ( arbel->icm_len / ARBEL_PAGE_SIZE ), &unmap_icm ); arbel_cmd_unmap_icm_aux ( arbel ); - free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE ); + free_phys ( arbel->db_rec, ARBEL_PAGE_SIZE ); arbel->db_rec = NULL; } @@ -2984,18 +2984,18 @@ static struct arbel * arbel_alloc ( void ) { goto err_arbel; /* Allocate space for mailboxes */ - arbel->mailbox_in = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN ); + arbel->mailbox_in = malloc_phys ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN ); if ( ! arbel->mailbox_in ) goto err_mailbox_in; - arbel->mailbox_out = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN ); + arbel->mailbox_out = malloc_phys ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN ); if ( ! arbel->mailbox_out ) goto err_mailbox_out; return arbel; - free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE ); + free_phys ( arbel->mailbox_out, ARBEL_MBOX_SIZE ); err_mailbox_out: - free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE ); + free_phys ( arbel->mailbox_in, ARBEL_MBOX_SIZE ); err_mailbox_in: free ( arbel ); err_arbel: @@ -3011,8 +3011,8 @@ static void arbel_free ( struct arbel *arbel ) { ufree ( arbel->icm ); ufree ( arbel->firmware_area ); - free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE ); - free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE ); + free_phys ( arbel->mailbox_out, ARBEL_MBOX_SIZE ); + free_phys ( arbel->mailbox_in, ARBEL_MBOX_SIZE ); free ( arbel ); } diff --git a/src/drivers/infiniband/golan.c b/src/drivers/infiniband/golan.c index 7ab4a4ee6..9bd810e23 100755 --- a/src/drivers/infiniband/golan.c +++ b/src/drivers/infiniband/golan.c @@ -585,9 +585,9 @@ static inline int golan_set_access_reg ( struct golan *golan __attribute__ (( un static inline void golan_cmd_uninit ( struct golan *golan ) { - free_dma(golan->mboxes.outbox, GOLAN_PAGE_SIZE); - free_dma(golan->mboxes.inbox, GOLAN_PAGE_SIZE); - free_dma(golan->cmd.addr, GOLAN_PAGE_SIZE); + free_phys(golan->mboxes.outbox, GOLAN_PAGE_SIZE); + free_phys(golan->mboxes.inbox, GOLAN_PAGE_SIZE); + free_phys(golan->cmd.addr, GOLAN_PAGE_SIZE); } /** @@ -602,17 +602,17 @@ static inline int golan_cmd_init ( struct golan *golan ) int rc = 0; uint32_t addr_l_sz; - if (!(golan->cmd.addr = malloc_dma(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { + if (!(golan->cmd.addr = malloc_phys(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { rc = -ENOMEM; - goto malloc_dma_failed; + goto malloc_phys_failed; } - if (!(golan->mboxes.inbox = malloc_dma(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { + if (!(golan->mboxes.inbox = malloc_phys(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { rc = -ENOMEM; - goto malloc_dma_inbox_failed; + goto malloc_phys_inbox_failed; } - if (!(golan->mboxes.outbox = malloc_dma(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { + if (!(golan->mboxes.outbox = malloc_phys(GOLAN_PAGE_SIZE , GOLAN_PAGE_SIZE))) { rc = -ENOMEM; - goto malloc_dma_outbox_failed; + goto malloc_phys_outbox_failed; } addr_l_sz = be32_to_cpu(readl(&golan->iseg->cmdq_addr_l_sz)); @@ -629,11 +629,11 @@ static inline int golan_cmd_init ( struct golan *golan ) DBGC( golan , "%s Command interface was initialized\n", __FUNCTION__); return 0; -malloc_dma_outbox_failed: - free_dma(golan->mboxes.inbox, GOLAN_PAGE_SIZE); -malloc_dma_inbox_failed: - free_dma(golan->cmd.addr, GOLAN_PAGE_SIZE); -malloc_dma_failed: +malloc_phys_outbox_failed: + free_phys(golan->mboxes.inbox, GOLAN_PAGE_SIZE); +malloc_phys_inbox_failed: + free_phys(golan->cmd.addr, GOLAN_PAGE_SIZE); +malloc_phys_failed: DBGC (golan ,"%s Failed to initialize command interface (rc = 0x%x)\n", __FUNCTION__, rc); return rc; @@ -743,7 +743,7 @@ static int golan_create_eq(struct golan *golan) eq->cons_index = 0; eq->size = GOLAN_NUM_EQES * sizeof(eq->eqes[0]); - eq->eqes = malloc_dma ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); + eq->eqes = malloc_phys ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); if (!eq->eqes) { rc = -ENOMEM; goto err_create_eq_eqe_alloc; @@ -781,7 +781,7 @@ static int golan_create_eq(struct golan *golan) return 0; err_create_eq_cmd: - free_dma ( eq->eqes , GOLAN_PAGE_SIZE ); + free_phys ( eq->eqes , GOLAN_PAGE_SIZE ); err_create_eq_eqe_alloc: DBGC (golan ,"%s [%d] out\n", __FUNCTION__, rc); return rc; @@ -806,7 +806,7 @@ static void golan_destory_eq(struct golan *golan) rc = send_command_and_wait(golan, DEF_CMD_IDX, NO_MBOX, NO_MBOX, __FUNCTION__); GOLAN_PRINT_RC_AND_CMD_STATUS; - free_dma ( golan->eq.eqes , GOLAN_PAGE_SIZE ); + free_phys ( golan->eq.eqes , GOLAN_PAGE_SIZE ); golan->eq.eqn = 0; DBGC( golan, "%s Event queue (0x%x) was destroyed\n", __FUNCTION__, eqn); @@ -962,14 +962,14 @@ static int golan_create_cq(struct ib_device *ibdev, goto err_create_cq; } golan_cq->size = sizeof(golan_cq->cqes[0]) * cq->num_cqes; - golan_cq->doorbell_record = malloc_dma(GOLAN_CQ_DB_RECORD_SIZE, + golan_cq->doorbell_record = malloc_phys(GOLAN_CQ_DB_RECORD_SIZE, GOLAN_CQ_DB_RECORD_SIZE); if (!golan_cq->doorbell_record) { rc = -ENOMEM; goto err_create_cq_db_alloc; } - golan_cq->cqes = malloc_dma ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); + golan_cq->cqes = malloc_phys ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); if (!golan_cq->cqes) { rc = -ENOMEM; goto err_create_cq_cqe_alloc; @@ -1008,9 +1008,9 @@ static int golan_create_cq(struct ib_device *ibdev, return 0; err_create_cq_cmd: - free_dma( golan_cq->cqes , GOLAN_PAGE_SIZE ); + free_phys( golan_cq->cqes , GOLAN_PAGE_SIZE ); err_create_cq_cqe_alloc: - free_dma(golan_cq->doorbell_record, GOLAN_CQ_DB_RECORD_SIZE); + free_phys(golan_cq->doorbell_record, GOLAN_CQ_DB_RECORD_SIZE); err_create_cq_db_alloc: free ( golan_cq ); err_create_cq: @@ -1045,8 +1045,8 @@ static void golan_destroy_cq(struct ib_device *ibdev, cq->cqn = 0; ib_cq_set_drvdata(cq, NULL); - free_dma ( golan_cq->cqes , GOLAN_PAGE_SIZE ); - free_dma(golan_cq->doorbell_record, GOLAN_CQ_DB_RECORD_SIZE); + free_phys ( golan_cq->cqes , GOLAN_PAGE_SIZE ); + free_phys(golan_cq->doorbell_record, GOLAN_CQ_DB_RECORD_SIZE); free(golan_cq); DBGC (golan, "%s CQ number 0x%x was destroyed\n", __FUNCTION__, cqn); @@ -1138,7 +1138,7 @@ static int golan_create_qp_aux(struct ib_device *ibdev, golan_qp->size = golan_qp->sq.size + golan_qp->rq.size; /* allocate dma memory for WQEs (1 page is enough) - should change it */ - golan_qp->wqes = malloc_dma ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); + golan_qp->wqes = malloc_phys ( GOLAN_PAGE_SIZE, GOLAN_PAGE_SIZE ); if (!golan_qp->wqes) { rc = -ENOMEM; goto err_create_qp_wqe_alloc; @@ -1160,7 +1160,7 @@ static int golan_create_qp_aux(struct ib_device *ibdev, data++; } - golan_qp->doorbell_record = malloc_dma(sizeof(struct golan_qp_db), + golan_qp->doorbell_record = malloc_phys(sizeof(struct golan_qp_db), sizeof(struct golan_qp_db)); if (!golan_qp->doorbell_record) { rc = -ENOMEM; @@ -1213,9 +1213,9 @@ static int golan_create_qp_aux(struct ib_device *ibdev, return 0; err_create_qp_cmd: - free_dma(golan_qp->doorbell_record, sizeof(struct golan_qp_db)); + free_phys(golan_qp->doorbell_record, sizeof(struct golan_qp_db)); err_create_qp_db_alloc: - free_dma ( golan_qp->wqes, GOLAN_PAGE_SIZE ); + free_phys ( golan_qp->wqes, GOLAN_PAGE_SIZE ); err_create_qp_wqe_alloc: err_create_qp_sq_size: err_create_qp_sq_wqe_size: @@ -1422,8 +1422,8 @@ static void golan_destroy_qp(struct ib_device *ibdev, qp->qpn = 0; ib_qp_set_drvdata(qp, NULL); - free_dma(golan_qp->doorbell_record, sizeof(struct golan_qp_db)); - free_dma ( golan_qp->wqes, GOLAN_PAGE_SIZE ); + free_phys(golan_qp->doorbell_record, sizeof(struct golan_qp_db)); + free_phys ( golan_qp->wqes, GOLAN_PAGE_SIZE ); free(golan_qp); DBGC( golan ,"%s QP 0x%lx was destroyed\n", __FUNCTION__, qpn); diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index b6599588f..fdf2d9dd8 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -864,8 +864,8 @@ static int hermon_create_cq ( struct ib_device *ibdev, } /* Allocate doorbell */ - hermon_cq->doorbell = malloc_dma ( sizeof ( hermon_cq->doorbell[0] ), - sizeof ( hermon_cq->doorbell[0] ) ); + hermon_cq->doorbell = malloc_phys ( sizeof ( hermon_cq->doorbell[0] ), + sizeof ( hermon_cq->doorbell[0] ) ); if ( ! hermon_cq->doorbell ) { rc = -ENOMEM; goto err_doorbell; @@ -874,8 +874,8 @@ static int hermon_create_cq ( struct ib_device *ibdev, /* Allocate completion queue itself */ hermon_cq->cqe_size = ( cq->num_cqes * sizeof ( hermon_cq->cqe[0] ) ); - hermon_cq->cqe = malloc_dma ( hermon_cq->cqe_size, - sizeof ( hermon_cq->cqe[0] ) ); + hermon_cq->cqe = malloc_phys ( hermon_cq->cqe_size, + sizeof ( hermon_cq->cqe[0] ) ); if ( ! hermon_cq->cqe ) { rc = -ENOMEM; goto err_cqe; @@ -925,9 +925,9 @@ static int hermon_create_cq ( struct ib_device *ibdev, err_sw2hw_cq: hermon_free_mtt ( hermon, &hermon_cq->mtt ); err_alloc_mtt: - free_dma ( hermon_cq->cqe, hermon_cq->cqe_size ); + free_phys ( hermon_cq->cqe, hermon_cq->cqe_size ); err_cqe: - free_dma ( hermon_cq->doorbell, sizeof ( hermon_cq->doorbell[0] ) ); + free_phys ( hermon_cq->doorbell, sizeof ( hermon_cq->doorbell[0] ) ); err_doorbell: free ( hermon_cq ); err_hermon_cq: @@ -962,8 +962,8 @@ static void hermon_destroy_cq ( struct ib_device *ibdev, hermon_free_mtt ( hermon, &hermon_cq->mtt ); /* Free memory */ - free_dma ( hermon_cq->cqe, hermon_cq->cqe_size ); - free_dma ( hermon_cq->doorbell, sizeof ( hermon_cq->doorbell[0] ) ); + free_phys ( hermon_cq->cqe, hermon_cq->cqe_size ); + free_phys ( hermon_cq->doorbell, sizeof ( hermon_cq->doorbell[0] ) ); free ( hermon_cq ); /* Mark queue number as free */ @@ -1128,8 +1128,8 @@ static int hermon_create_qp ( struct ib_device *ibdev, /* Allocate doorbells */ hermon_qp->recv.doorbell = - malloc_dma ( sizeof ( hermon_qp->recv.doorbell[0] ), - sizeof ( hermon_qp->recv.doorbell[0] ) ); + malloc_phys ( sizeof ( hermon_qp->recv.doorbell[0] ), + sizeof ( hermon_qp->recv.doorbell[0] ) ); if ( ! hermon_qp->recv.doorbell ) { rc = -ENOMEM; goto err_recv_doorbell; @@ -1157,8 +1157,8 @@ static int hermon_create_qp ( struct ib_device *ibdev, hermon_qp->wqe_size = ( hermon_qp->send.wqe_size + hermon_qp->recv.wqe_size + hermon_qp->recv.grh_size ); - hermon_qp->wqe = malloc_dma ( hermon_qp->wqe_size, - sizeof ( hermon_qp->send.wqe[0] ) ); + hermon_qp->wqe = malloc_phys ( hermon_qp->wqe_size, + sizeof ( hermon_qp->send.wqe[0] ) ); if ( ! hermon_qp->wqe ) { rc = -ENOMEM; goto err_alloc_wqe; @@ -1248,10 +1248,10 @@ static int hermon_create_qp ( struct ib_device *ibdev, err_rst2init_qp: hermon_free_mtt ( hermon, &hermon_qp->mtt ); err_alloc_mtt: - free_dma ( hermon_qp->wqe, hermon_qp->wqe_size ); + free_phys ( hermon_qp->wqe, hermon_qp->wqe_size ); err_alloc_wqe: - free_dma ( hermon_qp->recv.doorbell, - sizeof ( hermon_qp->recv.doorbell[0] ) ); + free_phys ( hermon_qp->recv.doorbell, + sizeof ( hermon_qp->recv.doorbell[0] ) ); err_recv_doorbell: free ( hermon_qp ); err_hermon_qp: @@ -1363,9 +1363,9 @@ static void hermon_destroy_qp ( struct ib_device *ibdev, hermon_free_mtt ( hermon, &hermon_qp->mtt ); /* Free memory */ - free_dma ( hermon_qp->wqe, hermon_qp->wqe_size ); - free_dma ( hermon_qp->recv.doorbell, - sizeof ( hermon_qp->recv.doorbell[0] ) ); + free_phys ( hermon_qp->wqe, hermon_qp->wqe_size ); + free_phys ( hermon_qp->recv.doorbell, + sizeof ( hermon_qp->recv.doorbell[0] ) ); free ( hermon_qp ); /* Mark queue number as free */ @@ -1887,8 +1887,8 @@ static int hermon_create_eq ( struct hermon *hermon ) { /* Allocate event queue itself */ hermon_eq->eqe_size = ( HERMON_NUM_EQES * sizeof ( hermon_eq->eqe[0] ) ); - hermon_eq->eqe = malloc_dma ( hermon_eq->eqe_size, - sizeof ( hermon_eq->eqe[0] ) ); + hermon_eq->eqe = malloc_phys ( hermon_eq->eqe_size, + sizeof ( hermon_eq->eqe[0] ) ); if ( ! hermon_eq->eqe ) { rc = -ENOMEM; goto err_eqe; @@ -1946,7 +1946,7 @@ static int hermon_create_eq ( struct hermon *hermon ) { err_sw2hw_eq: hermon_free_mtt ( hermon, &hermon_eq->mtt ); err_alloc_mtt: - free_dma ( hermon_eq->eqe, hermon_eq->eqe_size ); + free_phys ( hermon_eq->eqe, hermon_eq->eqe_size ); err_eqe: memset ( hermon_eq, 0, sizeof ( *hermon_eq ) ); return rc; @@ -1986,7 +1986,7 @@ static void hermon_destroy_eq ( struct hermon *hermon ) { hermon_free_mtt ( hermon, &hermon_eq->mtt ); /* Free memory */ - free_dma ( hermon_eq->eqe, hermon_eq->eqe_size ); + free_phys ( hermon_eq->eqe, hermon_eq->eqe_size ); memset ( hermon_eq, 0, sizeof ( *hermon_eq ) ); } @@ -3736,20 +3736,20 @@ static struct hermon * hermon_alloc ( void ) { goto err_hermon; /* Allocate space for mailboxes */ - hermon->mailbox_in = malloc_dma ( HERMON_MBOX_SIZE, - HERMON_MBOX_ALIGN ); + hermon->mailbox_in = malloc_phys ( HERMON_MBOX_SIZE, + HERMON_MBOX_ALIGN ); if ( ! hermon->mailbox_in ) goto err_mailbox_in; - hermon->mailbox_out = malloc_dma ( HERMON_MBOX_SIZE, - HERMON_MBOX_ALIGN ); + hermon->mailbox_out = malloc_phys ( HERMON_MBOX_SIZE, + HERMON_MBOX_ALIGN ); if ( ! hermon->mailbox_out ) goto err_mailbox_out; return hermon; - free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE ); + free_phys ( hermon->mailbox_out, HERMON_MBOX_SIZE ); err_mailbox_out: - free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE ); + free_phys ( hermon->mailbox_in, HERMON_MBOX_SIZE ); err_mailbox_in: free ( hermon ); err_hermon: @@ -3765,8 +3765,8 @@ static void hermon_free ( struct hermon *hermon ) { ufree ( hermon->icm ); ufree ( hermon->firmware_area ); - free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE ); - free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE ); + free_phys ( hermon->mailbox_out, HERMON_MBOX_SIZE ); + free_phys ( hermon->mailbox_in, HERMON_MBOX_SIZE ); free ( hermon ); } diff --git a/src/drivers/infiniband/linda.c b/src/drivers/infiniband/linda.c index 8c2c090bc..b275268a2 100644 --- a/src/drivers/infiniband/linda.c +++ b/src/drivers/infiniband/linda.c @@ -531,8 +531,8 @@ static int linda_init_send ( struct linda *linda ) { linda->send_buf[i] = i; /* Allocate space for the SendBufAvail array */ - linda->sendbufavail = malloc_dma ( sizeof ( *linda->sendbufavail ), - LINDA_SENDBUFAVAIL_ALIGN ); + linda->sendbufavail = malloc_phys ( sizeof ( *linda->sendbufavail ), + LINDA_SENDBUFAVAIL_ALIGN ); if ( ! linda->sendbufavail ) { rc = -ENOMEM; goto err_alloc_sendbufavail; @@ -555,7 +555,7 @@ static int linda_init_send ( struct linda *linda ) { return 0; - free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); + free_phys ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); err_alloc_sendbufavail: return rc; } @@ -576,7 +576,7 @@ static void linda_fini_send ( struct linda *linda ) { /* Ensure hardware has seen this disable */ linda_readq ( linda, &sendctrl, QIB_7220_SendCtrl_offset ); - free_dma ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); + free_phys ( linda->sendbufavail, sizeof ( *linda->sendbufavail ) ); } /*************************************************************************** @@ -613,8 +613,8 @@ static int linda_create_recv_wq ( struct linda *linda, linda_wq->eager_cons = 0; /* Allocate receive header buffer */ - linda_wq->header = malloc_dma ( LINDA_RECV_HEADERS_SIZE, - LINDA_RECV_HEADERS_ALIGN ); + linda_wq->header = malloc_phys ( LINDA_RECV_HEADERS_SIZE, + LINDA_RECV_HEADERS_ALIGN ); if ( ! linda_wq->header ) { rc = -ENOMEM; goto err_alloc_header; @@ -650,7 +650,7 @@ static int linda_create_recv_wq ( struct linda *linda, virt_to_bus ( &linda_wq->header_prod ) ); return 0; - free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); + free_phys ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); err_alloc_header: return rc; } @@ -679,7 +679,7 @@ static void linda_destroy_recv_wq ( struct linda *linda, mb(); /* Free headers ring */ - free_dma ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); + free_phys ( linda_wq->header, LINDA_RECV_HEADERS_SIZE ); /* Free context */ linda_free_ctx ( linda, ctx ); diff --git a/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c b/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c index cb9e759bf..e368d459b 100644 --- a/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c +++ b/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c @@ -61,7 +61,7 @@ mlx_memory_alloc_dma_priv( ) { mlx_status status = MLX_SUCCESS; - *ptr = malloc_dma(size, align); + *ptr = malloc_phys(size, align); if (*ptr == NULL) { status = MLX_OUT_OF_RESOURCES; } else { @@ -78,7 +78,7 @@ mlx_memory_free_dma_priv( ) { mlx_status status = MLX_SUCCESS; - free_dma(ptr, size); + free_phys(ptr, size); return status; } mlx_status diff --git a/src/drivers/infiniband/qib7322.c b/src/drivers/infiniband/qib7322.c index a5606dd03..e3250147d 100644 --- a/src/drivers/infiniband/qib7322.c +++ b/src/drivers/infiniband/qib7322.c @@ -669,8 +669,8 @@ static int qib7322_init_send ( struct qib7322 *qib7322 ) { } /* Allocate space for the SendBufAvail array */ - qib7322->sendbufavail = malloc_dma ( sizeof ( *qib7322->sendbufavail ), - QIB7322_SENDBUFAVAIL_ALIGN ); + qib7322->sendbufavail = malloc_phys ( sizeof ( *qib7322->sendbufavail ), + QIB7322_SENDBUFAVAIL_ALIGN ); if ( ! qib7322->sendbufavail ) { rc = -ENOMEM; goto err_alloc_sendbufavail; @@ -697,7 +697,7 @@ static int qib7322_init_send ( struct qib7322 *qib7322 ) { return 0; - free_dma ( qib7322->sendbufavail, sizeof ( *qib7322->sendbufavail ) ); + free_phys ( qib7322->sendbufavail, sizeof ( *qib7322->sendbufavail ) ); err_alloc_sendbufavail: qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_vl15_port1 ); err_create_send_bufs_vl15_port1: @@ -724,7 +724,7 @@ static void qib7322_fini_send ( struct qib7322 *qib7322 ) { /* Ensure hardware has seen this disable */ qib7322_readq ( qib7322, &sendctrl, QIB_7322_SendCtrl_offset ); - free_dma ( qib7322->sendbufavail, sizeof ( *qib7322->sendbufavail ) ); + free_phys ( qib7322->sendbufavail, sizeof ( *qib7322->sendbufavail ) ); qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_vl15_port1 ); qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_vl15_port0 ); qib7322_destroy_send_bufs ( qib7322, qib7322->send_bufs_small ); @@ -767,8 +767,8 @@ static int qib7322_create_recv_wq ( struct ib_device *ibdev, qib7322_wq->eager_cons = 0; /* Allocate receive header buffer */ - qib7322_wq->header = malloc_dma ( QIB7322_RECV_HEADERS_SIZE, - QIB7322_RECV_HEADERS_ALIGN ); + qib7322_wq->header = malloc_phys ( QIB7322_RECV_HEADERS_SIZE, + QIB7322_RECV_HEADERS_ALIGN ); if ( ! qib7322_wq->header ) { rc = -ENOMEM; goto err_alloc_header; @@ -810,7 +810,7 @@ static int qib7322_create_recv_wq ( struct ib_device *ibdev, virt_to_bus ( &qib7322_wq->header_prod ) ); return 0; - free_dma ( qib7322_wq->header, QIB7322_RECV_HEADERS_SIZE ); + free_phys ( qib7322_wq->header, QIB7322_RECV_HEADERS_SIZE ); err_alloc_header: return rc; } @@ -846,7 +846,7 @@ static void qib7322_destroy_recv_wq ( struct ib_device *ibdev, mb(); /* Free headers ring */ - free_dma ( qib7322_wq->header, QIB7322_RECV_HEADERS_SIZE ); + free_phys ( qib7322_wq->header, QIB7322_RECV_HEADERS_SIZE ); } /** diff --git a/src/drivers/net/3c90x.c b/src/drivers/net/3c90x.c index 853de2b52..63e07777f 100644 --- a/src/drivers/net/3c90x.c +++ b/src/drivers/net/3c90x.c @@ -249,7 +249,7 @@ static int a3c90x_setup_tx_ring(struct INF_3C90X *p) { DBGP("a3c90x_setup_tx_ring\n"); p->tx_ring = - malloc_dma(TX_RING_SIZE * sizeof(struct TXD), TX_RING_ALIGN); + malloc_phys(TX_RING_SIZE * sizeof(struct TXD), TX_RING_ALIGN); if (!p->tx_ring) { DBG("Could not allocate TX-ring\n"); @@ -304,7 +304,7 @@ static void a3c90x_free_tx_ring(struct INF_3C90X *p) { DBGP("a3c90x_free_tx_ring\n"); - free_dma(p->tx_ring, TX_RING_SIZE * sizeof(struct TXD)); + free_phys(p->tx_ring, TX_RING_SIZE * sizeof(struct TXD)); p->tx_ring = NULL; /* io_buffers are free()ed by netdev_tx_complete[,_err]() */ } @@ -461,7 +461,7 @@ static int a3c90x_setup_rx_ring(struct INF_3C90X *p) DBGP("a3c90x_setup_rx_ring\n"); p->rx_ring = - malloc_dma(RX_RING_SIZE * sizeof(struct RXD), RX_RING_ALIGN); + malloc_phys(RX_RING_SIZE * sizeof(struct RXD), RX_RING_ALIGN); if (!p->rx_ring) { DBG("Could not allocate RX-ring\n"); @@ -491,7 +491,7 @@ static void a3c90x_free_rx_ring(struct INF_3C90X *p) { DBGP("a3c90x_free_rx_ring\n"); - free_dma(p->rx_ring, RX_RING_SIZE * sizeof(struct RXD)); + free_phys(p->rx_ring, RX_RING_SIZE * sizeof(struct RXD)); p->rx_ring = NULL; } diff --git a/src/drivers/net/ath/ath5k/ath5k.c b/src/drivers/net/ath/ath5k/ath5k.c index d8c47909d..e43eb0aaf 100644 --- a/src/drivers/net/ath/ath5k/ath5k.c +++ b/src/drivers/net/ath/ath5k/ath5k.c @@ -877,7 +877,7 @@ ath5k_desc_alloc(struct ath5k_softc *sc) /* allocate descriptors */ sc->desc_len = sizeof(struct ath5k_desc) * (ATH_TXBUF + ATH_RXBUF + 1); - sc->desc = malloc_dma(sc->desc_len, ATH5K_DESC_ALIGN); + sc->desc = malloc_phys(sc->desc_len, ATH5K_DESC_ALIGN); if (sc->desc == NULL) { DBG("ath5k: can't allocate descriptors\n"); ret = -ENOMEM; @@ -915,7 +915,7 @@ ath5k_desc_alloc(struct ath5k_softc *sc) return 0; err_free: - free_dma(sc->desc, sc->desc_len); + free_phys(sc->desc, sc->desc_len); err: sc->desc = NULL; return ret; @@ -932,7 +932,7 @@ ath5k_desc_free(struct ath5k_softc *sc) ath5k_rxbuf_free(sc, bf); /* Free memory associated with all descriptors */ - free_dma(sc->desc, sc->desc_len); + free_phys(sc->desc, sc->desc_len); free(sc->bufptr); sc->bufptr = NULL; diff --git a/src/drivers/net/ath/ath9k/ath9k_init.c b/src/drivers/net/ath/ath9k/ath9k_init.c index 98a0d6d59..05ed3336a 100644 --- a/src/drivers/net/ath/ath9k/ath9k_init.c +++ b/src/drivers/net/ath/ath9k/ath9k_init.c @@ -223,7 +223,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, } /* allocate descriptors */ - dd->dd_desc = malloc_dma(dd->dd_desc_len, 16); + dd->dd_desc = malloc_phys(dd->dd_desc_len, 16); if (dd->dd_desc == NULL) { error = -ENOMEM; goto fail; @@ -264,7 +264,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, } return 0; fail2: - free_dma(dd->dd_desc, dd->dd_desc_len); + free_phys(dd->dd_desc, dd->dd_desc_len); fail: memset(dd, 0, sizeof(*dd)); return error; @@ -588,7 +588,7 @@ void ath_descdma_cleanup(struct ath_softc *sc __unused, struct ath_descdma *dd, struct list_head *head) { - free_dma(dd->dd_desc, dd->dd_desc_len); + free_phys(dd->dd_desc, dd->dd_desc_len); INIT_LIST_HEAD(head); free(dd->dd_bufptr); diff --git a/src/drivers/net/atl1e.c b/src/drivers/net/atl1e.c index d010d8c4a..0f0df5326 100644 --- a/src/drivers/net/atl1e.c +++ b/src/drivers/net/atl1e.c @@ -370,7 +370,7 @@ static void atl1e_free_ring_resources(struct atl1e_adapter *adapter) atl1e_clean_rx_ring(adapter); if (adapter->ring_vir_addr) { - free_dma(adapter->ring_vir_addr, adapter->ring_size); + free_phys(adapter->ring_vir_addr, adapter->ring_size); adapter->ring_vir_addr = NULL; adapter->ring_dma = 0; } @@ -405,7 +405,7 @@ static int atl1e_setup_ring_resources(struct atl1e_adapter *adapter) /* real ring DMA buffer */ size = adapter->ring_size; - adapter->ring_vir_addr = malloc_dma(adapter->ring_size, 32); + adapter->ring_vir_addr = malloc_phys(adapter->ring_size, 32); if (adapter->ring_vir_addr == NULL) { DBG("atl1e: out of memory allocating %d bytes for %s ring\n", diff --git a/src/drivers/net/b44.c b/src/drivers/net/b44.c index e0e6f4642..eaf6d35ce 100644 --- a/src/drivers/net/b44.c +++ b/src/drivers/net/b44.c @@ -436,7 +436,7 @@ static void b44_free_rx_ring(struct b44_private *bp) free_iob(bp->rx_iobuf[i]); bp->rx_iobuf[i] = NULL; } - free_dma(bp->rx, B44_RX_RING_LEN_BYTES); + free_phys(bp->rx, B44_RX_RING_LEN_BYTES); bp->rx = NULL; } } @@ -446,11 +446,11 @@ static int b44_init_rx_ring(struct b44_private *bp) { b44_free_rx_ring(bp); - bp->rx = malloc_dma(B44_RX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); + bp->rx = malloc_phys(B44_RX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); if (!bp->rx) return -ENOMEM; if (!b44_address_ok(bp->rx)) { - free_dma(bp->rx, B44_RX_RING_LEN_BYTES); + free_phys(bp->rx, B44_RX_RING_LEN_BYTES); return -ENOTSUP; } @@ -468,7 +468,7 @@ static int b44_init_rx_ring(struct b44_private *bp) static void b44_free_tx_ring(struct b44_private *bp) { if (bp->tx) { - free_dma(bp->tx, B44_TX_RING_LEN_BYTES); + free_phys(bp->tx, B44_TX_RING_LEN_BYTES); bp->tx = NULL; } } @@ -478,11 +478,11 @@ static int b44_init_tx_ring(struct b44_private *bp) { b44_free_tx_ring(bp); - bp->tx = malloc_dma(B44_TX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); + bp->tx = malloc_phys(B44_TX_RING_LEN_BYTES, B44_DMA_ALIGNMENT); if (!bp->tx) return -ENOMEM; if (!b44_address_ok(bp->tx)) { - free_dma(bp->tx, B44_TX_RING_LEN_BYTES); + free_phys(bp->tx, B44_TX_RING_LEN_BYTES); return -ENOTSUP; } diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c index fe84ea0e4..b8663c00a 100644 --- a/src/drivers/net/bnxt/bnxt.c +++ b/src/drivers/net/bnxt/bnxt.c @@ -495,39 +495,39 @@ void bnxt_free_mem ( struct bnxt *bp ) { DBGP ( "%s\n", __func__ ); if ( bp->nq.bd_virt ) { - free_dma ( bp->nq.bd_virt, NQ_RING_BUFFER_SIZE ); + free_phys ( bp->nq.bd_virt, NQ_RING_BUFFER_SIZE ); bp->nq.bd_virt = NULL; } if ( bp->cq.bd_virt ) { - free_dma ( bp->cq.bd_virt, CQ_RING_BUFFER_SIZE ); + free_phys ( bp->cq.bd_virt, CQ_RING_BUFFER_SIZE ); bp->cq.bd_virt = NULL; } if ( bp->rx.bd_virt ) { - free_dma ( bp->rx.bd_virt, RX_RING_BUFFER_SIZE ); + free_phys ( bp->rx.bd_virt, RX_RING_BUFFER_SIZE ); bp->rx.bd_virt = NULL; } if ( bp->tx.bd_virt ) { - free_dma ( bp->tx.bd_virt, TX_RING_BUFFER_SIZE ); + free_phys ( bp->tx.bd_virt, TX_RING_BUFFER_SIZE ); bp->tx.bd_virt = NULL; } if ( bp->hwrm_addr_dma ) { - free_dma ( bp->hwrm_addr_dma, DMA_BUFFER_SIZE ); + free_phys ( bp->hwrm_addr_dma, DMA_BUFFER_SIZE ); bp->dma_addr_mapping = 0; bp->hwrm_addr_dma = NULL; } if ( bp->hwrm_addr_resp ) { - free_dma ( bp->hwrm_addr_resp, RESP_BUFFER_SIZE ); + free_phys ( bp->hwrm_addr_resp, RESP_BUFFER_SIZE ); bp->resp_addr_mapping = 0; bp->hwrm_addr_resp = NULL; } if ( bp->hwrm_addr_req ) { - free_dma ( bp->hwrm_addr_req, REQ_BUFFER_SIZE ); + free_phys ( bp->hwrm_addr_req, REQ_BUFFER_SIZE ); bp->req_addr_mapping = 0; bp->hwrm_addr_req = NULL; } @@ -537,14 +537,14 @@ void bnxt_free_mem ( struct bnxt *bp ) int bnxt_alloc_mem ( struct bnxt *bp ) { DBGP ( "%s\n", __func__ ); - bp->hwrm_addr_req = malloc_dma ( REQ_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); - bp->hwrm_addr_resp = malloc_dma ( RESP_BUFFER_SIZE, - BNXT_DMA_ALIGNMENT ); - bp->hwrm_addr_dma = malloc_dma ( DMA_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); - bp->tx.bd_virt = malloc_dma ( TX_RING_BUFFER_SIZE, DMA_ALIGN_4K ); - bp->rx.bd_virt = malloc_dma ( RX_RING_BUFFER_SIZE, DMA_ALIGN_4K ); - bp->cq.bd_virt = malloc_dma ( CQ_RING_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); - bp->nq.bd_virt = malloc_dma ( NQ_RING_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); + bp->hwrm_addr_req = malloc_phys ( REQ_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); + bp->hwrm_addr_resp = malloc_phys ( RESP_BUFFER_SIZE, + BNXT_DMA_ALIGNMENT ); + bp->hwrm_addr_dma = malloc_phys ( DMA_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); + bp->tx.bd_virt = malloc_phys ( TX_RING_BUFFER_SIZE, DMA_ALIGN_4K ); + bp->rx.bd_virt = malloc_phys ( RX_RING_BUFFER_SIZE, DMA_ALIGN_4K ); + bp->cq.bd_virt = malloc_phys ( CQ_RING_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); + bp->nq.bd_virt = malloc_phys ( NQ_RING_BUFFER_SIZE, BNXT_DMA_ALIGNMENT ); test_if ( bp->hwrm_addr_req && bp->hwrm_addr_resp && bp->hwrm_addr_dma && diff --git a/src/drivers/net/eepro100.c b/src/drivers/net/eepro100.c index 1046cda39..1a802b590 100644 --- a/src/drivers/net/eepro100.c +++ b/src/drivers/net/eepro100.c @@ -93,7 +93,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* * Debugging levels: - * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_dma(), + * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_phys(), * TX overflow, corrupted packets, ... * - DBG2() is for successful events, like packet received, * packet transmitted, and other general notifications. @@ -335,7 +335,7 @@ static int ifec_net_open ( struct net_device *netdev ) ifec_mdio_setup ( netdev, options ); /* Prepare MAC address w/ Individual Address Setup (ias) command.*/ - ias = malloc_dma ( sizeof ( *ias ), CB_ALIGN ); + ias = malloc_phys ( sizeof ( *ias ), CB_ALIGN ); if ( !ias ) { rc = -ENOMEM; goto error; @@ -345,7 +345,7 @@ static int ifec_net_open ( struct net_device *netdev ) memcpy ( ias->ia, netdev->ll_addr, ETH_ALEN ); /* Prepare operating parameters w/ a configure command. */ - cfg = malloc_dma ( sizeof ( *cfg ), CB_ALIGN ); + cfg = malloc_phys ( sizeof ( *cfg ), CB_ALIGN ); if ( !cfg ) { rc = -ENOMEM; goto error; @@ -367,8 +367,8 @@ static int ifec_net_open ( struct net_device *netdev ) DBG ( "Failed to initiate!\n" ); goto error; } - free_dma ( ias, sizeof ( *ias ) ); - free_dma ( cfg, sizeof ( *cfg ) ); + free_phys ( ias, sizeof ( *ias ) ); + free_phys ( cfg, sizeof ( *cfg ) ); DBG2 ( "cfg " ); /* Enable rx by sending ring address to card */ @@ -381,8 +381,8 @@ static int ifec_net_open ( struct net_device *netdev ) return 0; error: - free_dma ( cfg, sizeof ( *cfg ) ); - free_dma ( ias, sizeof ( *ias ) ); + free_phys ( cfg, sizeof ( *cfg ) ); + free_phys ( ias, sizeof ( *ias ) ); ifec_free ( netdev ); ifec_reset ( netdev ); return rc; @@ -703,7 +703,7 @@ static void ifec_free ( struct net_device *netdev ) } /* free TX ring buffer */ - free_dma ( priv->tcbs, TX_RING_BYTES ); + free_phys ( priv->tcbs, TX_RING_BYTES ); priv->tcbs = NULL; } @@ -1025,7 +1025,7 @@ static int ifec_tx_setup ( struct net_device *netdev ) DBGP ( "ifec_tx_setup\n" ); /* allocate tx ring */ - priv->tcbs = malloc_dma ( TX_RING_BYTES, CB_ALIGN ); + priv->tcbs = malloc_phys ( TX_RING_BYTES, CB_ALIGN ); if ( !priv->tcbs ) { DBG ( "TX-ring allocation failed\n" ); return -ENOMEM; diff --git a/src/drivers/net/ena.c b/src/drivers/net/ena.c index 5c76eb6fd..12c161522 100644 --- a/src/drivers/net/ena.c +++ b/src/drivers/net/ena.c @@ -164,7 +164,7 @@ static int ena_create_admin ( struct ena_nic *ena ) { int rc; /* Allocate admin completion queue */ - ena->acq.rsp = malloc_dma ( acq_len, acq_len ); + ena->acq.rsp = malloc_phys ( acq_len, acq_len ); if ( ! ena->acq.rsp ) { rc = -ENOMEM; goto err_alloc_acq; @@ -172,7 +172,7 @@ static int ena_create_admin ( struct ena_nic *ena ) { memset ( ena->acq.rsp, 0, acq_len ); /* Allocate admin queue */ - ena->aq.req = malloc_dma ( aq_len, aq_len ); + ena->aq.req = malloc_phys ( aq_len, aq_len ); if ( ! ena->aq.req ) { rc = -ENOMEM; goto err_alloc_aq; @@ -196,9 +196,9 @@ static int ena_create_admin ( struct ena_nic *ena ) { ena_clear_caps ( ena, ENA_AQ_CAPS ); ena_clear_caps ( ena, ENA_ACQ_CAPS ); - free_dma ( ena->aq.req, aq_len ); + free_phys ( ena->aq.req, aq_len ); err_alloc_aq: - free_dma ( ena->acq.rsp, acq_len ); + free_phys ( ena->acq.rsp, acq_len ); err_alloc_acq: return rc; } @@ -218,8 +218,8 @@ static void ena_destroy_admin ( struct ena_nic *ena ) { wmb(); /* Free queues */ - free_dma ( ena->aq.req, aq_len ); - free_dma ( ena->acq.rsp, acq_len ); + free_phys ( ena->aq.req, aq_len ); + free_phys ( ena->acq.rsp, acq_len ); DBGC ( ena, "ENA %p AQ and ACQ destroyed\n", ena ); } @@ -338,7 +338,7 @@ static int ena_create_sq ( struct ena_nic *ena, struct ena_sq *sq, int rc; /* Allocate submission queue entries */ - sq->sqe.raw = malloc_dma ( sq->len, ENA_ALIGN ); + sq->sqe.raw = malloc_phys ( sq->len, ENA_ALIGN ); if ( ! sq->sqe.raw ) { rc = -ENOMEM; goto err_alloc; @@ -375,7 +375,7 @@ static int ena_create_sq ( struct ena_nic *ena, struct ena_sq *sq, return 0; err_admin: - free_dma ( sq->sqe.raw, sq->len ); + free_phys ( sq->sqe.raw, sq->len ); err_alloc: return rc; } @@ -403,7 +403,7 @@ static int ena_destroy_sq ( struct ena_nic *ena, struct ena_sq *sq ) { return rc; /* Free submission queue entries */ - free_dma ( sq->sqe.raw, sq->len ); + free_phys ( sq->sqe.raw, sq->len ); DBGC ( ena, "ENA %p %s SQ%d destroyed\n", ena, ena_direction ( sq->direction ), sq->id ); @@ -423,7 +423,7 @@ static int ena_create_cq ( struct ena_nic *ena, struct ena_cq *cq ) { int rc; /* Allocate completion queue entries */ - cq->cqe.raw = malloc_dma ( cq->len, ENA_ALIGN ); + cq->cqe.raw = malloc_phys ( cq->len, ENA_ALIGN ); if ( ! cq->cqe.raw ) { rc = -ENOMEM; goto err_alloc; @@ -461,7 +461,7 @@ static int ena_create_cq ( struct ena_nic *ena, struct ena_cq *cq ) { return 0; err_admin: - free_dma ( cq->cqe.raw, cq->len ); + free_phys ( cq->cqe.raw, cq->len ); err_alloc: return rc; } @@ -488,7 +488,7 @@ static int ena_destroy_cq ( struct ena_nic *ena, struct ena_cq *cq ) { return rc; /* Free completion queue entries */ - free_dma ( cq->cqe.raw, cq->len ); + free_phys ( cq->cqe.raw, cq->len ); DBGC ( ena, "ENA %p CQ%d destroyed\n", ena, cq->id ); return 0; diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c index cd567f1d9..e43d4336e 100644 --- a/src/drivers/net/etherfabric.c +++ b/src/drivers/net/etherfabric.c @@ -3025,7 +3025,7 @@ falcon_free_special_buffer ( void *p ) { /* We don't bother cleaning up the buffer table entries - * we're hardly limited */ - free_dma ( p, EFAB_BUF_ALIGN ); + free_phys ( p, EFAB_BUF_ALIGN ); } static void* @@ -3038,7 +3038,7 @@ falcon_alloc_special_buffer ( struct efab_nic *efab, int bytes, unsigned long dma_addr; /* Allocate the buffer, aligned on a buffer address boundary */ - buffer = malloc_dma ( bytes, EFAB_BUF_ALIGN ); + buffer = malloc_phys ( bytes, EFAB_BUF_ALIGN ); if ( ! buffer ) return NULL; diff --git a/src/drivers/net/exanic.c b/src/drivers/net/exanic.c index 8849da285..aaa6a28a1 100644 --- a/src/drivers/net/exanic.c +++ b/src/drivers/net/exanic.c @@ -831,7 +831,7 @@ static int exanic_probe ( struct pci_device *pci ) { } /* Allocate transmit feedback region (shared between all ports) */ - exanic->txf = malloc_dma ( EXANIC_TXF_LEN, EXANIC_ALIGN ); + exanic->txf = malloc_phys ( EXANIC_TXF_LEN, EXANIC_ALIGN ); if ( ! exanic->txf ) { rc = -ENOMEM; goto err_alloc_txf; @@ -853,7 +853,7 @@ static int exanic_probe ( struct pci_device *pci ) { for ( i-- ; i >= 0 ; i-- ) exanic_remove_port ( exanic, i ); exanic_reset ( exanic ); - free_dma ( exanic->txf, EXANIC_TXF_LEN ); + free_phys ( exanic->txf, EXANIC_TXF_LEN ); err_alloc_txf: iounmap ( exanic->tx ); err_ioremap_tx: @@ -882,7 +882,7 @@ static void exanic_remove ( struct pci_device *pci ) { exanic_reset ( exanic ); /* Free transmit feedback region */ - free_dma ( exanic->txf, EXANIC_TXF_LEN ); + free_phys ( exanic->txf, EXANIC_TXF_LEN ); /* Unmap transmit region */ iounmap ( exanic->tx ); diff --git a/src/drivers/net/forcedeth.c b/src/drivers/net/forcedeth.c index 94cc6063b..7fba08a08 100644 --- a/src/drivers/net/forcedeth.c +++ b/src/drivers/net/forcedeth.c @@ -267,7 +267,7 @@ nv_init_rings ( struct forcedeth_private *priv ) /* Allocate ring for both TX and RX */ priv->rx_ring = - malloc_dma ( sizeof(struct ring_desc) * RXTX_RING_SIZE, 32 ); + malloc_phys ( sizeof(struct ring_desc) * RXTX_RING_SIZE, 32 ); if ( ! priv->rx_ring ) goto err_malloc; priv->tx_ring = &priv->rx_ring[RX_RING_SIZE]; @@ -308,7 +308,7 @@ nv_free_rxtx_resources ( struct forcedeth_private *priv ) DBGP ( "nv_free_rxtx_resources\n" ); - free_dma ( priv->rx_ring, sizeof(struct ring_desc) * RXTX_RING_SIZE ); + free_phys ( priv->rx_ring, sizeof(struct ring_desc) * RXTX_RING_SIZE ); for ( i = 0; i < RX_RING_SIZE; i++ ) { free_iob ( priv->rx_iobuf[i] ); diff --git a/src/drivers/net/icplus.c b/src/drivers/net/icplus.c index 58092fade..acd2e2363 100644 --- a/src/drivers/net/icplus.c +++ b/src/drivers/net/icplus.c @@ -343,7 +343,7 @@ static int icplus_create_ring ( struct icplus_nic *icp, struct icplus_ring *ring struct icplus_descriptor *next; /* Allocate descriptor ring */ - ring->entry = malloc_dma ( len, ICP_ALIGN ); + ring->entry = malloc_phys ( len, ICP_ALIGN ); if ( ! ring->entry ) { rc = -ENOMEM; goto err_alloc; @@ -369,7 +369,7 @@ static int icplus_create_ring ( struct icplus_nic *icp, struct icplus_ring *ring ( virt_to_bus ( ring->entry ) + len ) ); return 0; - free_dma ( ring->entry, len ); + free_phys ( ring->entry, len ); ring->entry = NULL; err_alloc: return rc; @@ -386,7 +386,7 @@ static void icplus_destroy_ring ( struct icplus_nic *icp __unused, size_t len = ( sizeof ( ring->entry[0] ) * ICP_NUM_DESC ); /* Free descriptor ring */ - free_dma ( ring->entry, len ); + free_phys ( ring->entry, len ); ring->entry = NULL; } diff --git a/src/drivers/net/igbvf/igbvf_main.c b/src/drivers/net/igbvf/igbvf_main.c index 39d4e7f8a..a5ed0c451 100644 --- a/src/drivers/net/igbvf/igbvf_main.c +++ b/src/drivers/net/igbvf/igbvf_main.c @@ -46,7 +46,7 @@ int igbvf_setup_tx_resources ( struct igbvf_adapter *adapter ) /* Allocate transmit descriptor ring memory. It must not cross a 64K boundary because of hardware errata #23 - so we use malloc_dma() requesting a 128 byte block that is + so we use malloc_phys() requesting a 128 byte block that is 128 byte aligned. This should guarantee that the memory allocated will not cross a 64K boundary, because 128 is an even multiple of 65536 ( 65536 / 128 == 512 ), so all possible @@ -55,7 +55,7 @@ int igbvf_setup_tx_resources ( struct igbvf_adapter *adapter ) */ adapter->tx_base = - malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size ); + malloc_phys ( adapter->tx_ring_size, adapter->tx_ring_size ); if ( ! adapter->tx_base ) { return -ENOMEM; @@ -78,7 +78,7 @@ void igbvf_free_tx_resources ( struct igbvf_adapter *adapter ) { DBG ( "igbvf_free_tx_resources\n" ); - free_dma ( adapter->tx_base, adapter->tx_ring_size ); + free_phys ( adapter->tx_base, adapter->tx_ring_size ); } /** @@ -93,7 +93,7 @@ void igbvf_free_rx_resources ( struct igbvf_adapter *adapter ) DBG ( "igbvf_free_rx_resources\n" ); - free_dma ( adapter->rx_base, adapter->rx_ring_size ); + free_phys ( adapter->rx_base, adapter->rx_ring_size ); for ( i = 0; i < NUM_RX_DESC; i++ ) { free_iob ( adapter->rx_iobuf[i] ); @@ -574,7 +574,7 @@ int igbvf_setup_rx_resources ( struct igbvf_adapter *adapter ) */ adapter->rx_base = - malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size ); + malloc_phys ( adapter->rx_ring_size, adapter->rx_ring_size ); if ( ! adapter->rx_base ) { return -ENOMEM; diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 97f50a943..3a4e4341b 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -504,7 +504,7 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { * prevent any possible page-crossing errors due to hardware * errata. */ - ring->desc = malloc_dma ( ring->len, ring->len ); + ring->desc = malloc_phys ( ring->len, ring->len ); if ( ! ring->desc ) return -ENOMEM; @@ -553,7 +553,7 @@ void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { intel_reset_ring ( intel, ring->reg ); /* Free descriptor ring */ - free_dma ( ring->desc, ring->len ); + free_phys ( ring->desc, ring->len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 08c90bc48..d16b759e7 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -195,7 +195,7 @@ static int intelxl_alloc_admin ( struct intelxl_nic *intelxl, size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Allocate admin queue */ - admin->buf = malloc_dma ( ( buf_len + len ), INTELXL_ALIGN ); + admin->buf = malloc_phys ( ( buf_len + len ), INTELXL_ALIGN ); if ( ! admin->buf ) return -ENOMEM; admin->desc = ( ( ( void * ) admin->buf ) + buf_len ); @@ -277,7 +277,7 @@ static void intelxl_free_admin ( struct intelxl_nic *intelxl __unused, size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Free queue */ - free_dma ( admin->buf, ( buf_len + len ) ); + free_phys ( admin->buf, ( buf_len + len ) ); } /** @@ -926,7 +926,7 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, int rc; /* Allocate descriptor ring */ - ring->desc.raw = malloc_dma ( ring->len, INTELXL_ALIGN ); + ring->desc.raw = malloc_phys ( ring->len, INTELXL_ALIGN ); if ( ! ring->desc.raw ) { rc = -ENOMEM; goto err_alloc; @@ -950,7 +950,7 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, return 0; - free_dma ( ring->desc.raw, ring->len ); + free_phys ( ring->desc.raw, ring->len ); err_alloc: return rc; } @@ -965,7 +965,7 @@ void intelxl_free_ring ( struct intelxl_nic *intelxl __unused, struct intelxl_ring *ring ) { /* Free descriptor ring */ - free_dma ( ring->desc.raw, ring->len ); + free_phys ( ring->desc.raw, ring->len ); ring->desc.raw = NULL; } diff --git a/src/drivers/net/jme.c b/src/drivers/net/jme.c index b68b96c88..c7307728d 100644 --- a/src/drivers/net/jme.c +++ b/src/drivers/net/jme.c @@ -262,7 +262,7 @@ jme_free_tx_resources(struct jme_adapter *jme) sizeof(struct io_buffer *) * jme->tx_ring_size); free(txring->bufinf); } - free_dma(txring->desc, jme->tx_ring_size * TX_DESC_SIZE); + free_phys(txring->desc, jme->tx_ring_size * TX_DESC_SIZE); txring->desc = NULL; txring->dma = 0; txring->bufinf = NULL; @@ -277,7 +277,7 @@ jme_alloc_tx_resources(struct jme_adapter *jme) { struct jme_ring *txring = &jme->txring; - txring->desc = malloc_dma(jme->tx_ring_size * TX_DESC_SIZE, + txring->desc = malloc_phys(jme->tx_ring_size * TX_DESC_SIZE, RING_DESC_ALIGN); if (!txring->desc) { DBG("Can not allocate transmit ring descriptors.\n"); @@ -442,7 +442,7 @@ jme_free_rx_resources(struct jme_adapter *jme) free(rxring->bufinf); } - free_dma(rxring->desc, jme->rx_ring_size * RX_DESC_SIZE); + free_phys(rxring->desc, jme->rx_ring_size * RX_DESC_SIZE); rxring->desc = NULL; rxring->dma = 0; rxring->bufinf = NULL; @@ -458,7 +458,7 @@ jme_alloc_rx_resources(struct jme_adapter *jme) struct jme_ring *rxring = &jme->rxring; struct io_buffer **bufinf; - rxring->desc = malloc_dma(jme->rx_ring_size * RX_DESC_SIZE, + rxring->desc = malloc_phys(jme->rx_ring_size * RX_DESC_SIZE, RING_DESC_ALIGN); if (!rxring->desc) { DBG("Can not allocate receive ring descriptors.\n"); diff --git a/src/drivers/net/myri10ge.c b/src/drivers/net/myri10ge.c index ae6b6c21e..6d0f723f2 100644 --- a/src/drivers/net/myri10ge.c +++ b/src/drivers/net/myri10ge.c @@ -66,7 +66,7 @@ FILE_LICENCE ( GPL2_ONLY ); /* * Debugging levels: - * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_dma(), + * - DBG() is for any errors, i.e. failed alloc_iob(), malloc_phys(), * TX overflow, corrupted packets, ... * - DBG2() is for successful events, like packet received, * packet transmitted, and other general notifications. @@ -918,7 +918,7 @@ static void myri10ge_net_close ( struct net_device *netdev ) /* Release DMAable memory. */ - free_dma ( priv->dma, sizeof ( *priv->dma ) ); + free_phys ( priv->dma, sizeof ( *priv->dma ) ); /* Erase all state from the open. */ @@ -988,7 +988,7 @@ static int myri10ge_net_open ( struct net_device *netdev ) /* Allocate cleared DMAable buffers. */ - priv->dma = malloc_dma ( sizeof ( *priv->dma ) , 128 ); + priv->dma = malloc_phys ( sizeof ( *priv->dma ) , 128 ); if ( !priv->dma ) { rc = -ENOMEM; dbg = "DMA"; @@ -1152,7 +1152,7 @@ abort_with_receives_posted: free_iob ( priv->receive_iob[priv->receives_posted] ); abort_with_dma: /* Because the link is not up, we don't have to reset the NIC here. */ - free_dma ( priv->dma, sizeof ( *priv->dma ) ); + free_phys ( priv->dma, sizeof ( *priv->dma ) ); abort_with_nothing: /* Erase all signs of the failed open. */ memset ( priv, 0, sizeof ( *priv ) ); diff --git a/src/drivers/net/myson.c b/src/drivers/net/myson.c index 4dd0aab4a..4ab2bf345 100644 --- a/src/drivers/net/myson.c +++ b/src/drivers/net/myson.c @@ -165,7 +165,7 @@ static int myson_create_ring ( struct myson_nic *myson, int rc; /* Allocate descriptor ring */ - ring->desc = malloc_dma ( len, MYSON_RING_ALIGN ); + ring->desc = malloc_phys ( len, MYSON_RING_ALIGN ); if ( ! ring->desc ) { rc = -ENOMEM; goto err_alloc; @@ -197,7 +197,7 @@ static int myson_create_ring ( struct myson_nic *myson, return 0; err_64bit: - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); ring->desc = NULL; err_alloc: return rc; @@ -217,7 +217,7 @@ static void myson_destroy_ring ( struct myson_nic *myson, writel ( 0, myson->regs + ring->reg ); /* Free descriptor ring */ - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 33cf68b3c..ba99bc2fe 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -408,7 +408,7 @@ static int natsemi_create_ring ( struct natsemi_nic *natsemi, * ensure that it can't possibly cross the boundary of 32-bit * address space. */ - ring->desc = malloc_dma ( len, len ); + ring->desc = malloc_phys ( len, len ); if ( ! ring->desc ) { rc = -ENOMEM; goto err_alloc; @@ -454,7 +454,7 @@ static int natsemi_create_ring ( struct natsemi_nic *natsemi, return 0; err_64bit: - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); ring->desc = NULL; err_alloc: return rc; @@ -476,7 +476,7 @@ static void natsemi_destroy_ring ( struct natsemi_nic *natsemi, writel ( 0, natsemi->regs + ring->reg + 4 ); /* Free descriptor ring */ - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; diff --git a/src/drivers/net/netfront.c b/src/drivers/net/netfront.c index b6205542b..be210850a 100644 --- a/src/drivers/net/netfront.c +++ b/src/drivers/net/netfront.c @@ -338,7 +338,7 @@ static int netfront_create_ring ( struct netfront_nic *netfront, ring->id_cons = 0; /* Allocate and initialise shared ring */ - ring->sring.raw = malloc_dma ( PAGE_SIZE, PAGE_SIZE ); + ring->sring.raw = malloc_phys ( PAGE_SIZE, PAGE_SIZE ); if ( ! ring->sring.raw ) { rc = -ENOMEM; goto err_alloc; @@ -368,7 +368,7 @@ static int netfront_create_ring ( struct netfront_nic *netfront, err_write_num: xengrant_invalidate ( xen, ring->ref ); err_permit_access: - free_dma ( ring->sring.raw, PAGE_SIZE ); + free_phys ( ring->sring.raw, PAGE_SIZE ); err_alloc: return rc; } @@ -490,7 +490,7 @@ static void netfront_destroy_ring ( struct netfront_nic *netfront, xengrant_invalidate ( xen, ring->ref ); /* Free page */ - free_dma ( ring->sring.raw, PAGE_SIZE ); + free_phys ( ring->sring.raw, PAGE_SIZE ); ring->sring.raw = NULL; } diff --git a/src/drivers/net/pcnet32.c b/src/drivers/net/pcnet32.c index 2635aaca2..c0dea86a8 100644 --- a/src/drivers/net/pcnet32.c +++ b/src/drivers/net/pcnet32.c @@ -246,7 +246,7 @@ pcnet32_setup_rx_resources ( struct pcnet32_private *priv ) { DBGP ( "pcnet32_setup_rx_resources\n" ); - priv->rx_base = malloc_dma ( RX_RING_BYTES, RX_RING_ALIGN ); + priv->rx_base = malloc_phys ( RX_RING_BYTES, RX_RING_ALIGN ); DBG ( "priv->rx_base = %#08lx\n", virt_to_bus ( priv->rx_base ) ); @@ -270,7 +270,7 @@ pcnet32_free_rx_resources ( struct pcnet32_private *priv ) DBGP ( "pcnet32_free_rx_resources\n" ); - free_dma ( priv->rx_base, RX_RING_BYTES ); + free_phys ( priv->rx_base, RX_RING_BYTES ); for ( i = 0; i < RX_RING_SIZE; i++ ) { free_iob ( priv->rx_iobuf[i] ); @@ -290,7 +290,7 @@ pcnet32_setup_tx_resources ( struct pcnet32_private *priv ) { DBGP ( "pcnet32_setup_tx_resources\n" ); - priv->tx_base = malloc_dma ( TX_RING_BYTES, TX_RING_ALIGN ); + priv->tx_base = malloc_phys ( TX_RING_BYTES, TX_RING_ALIGN ); if ( ! priv->tx_base ) { return -ENOMEM; @@ -312,7 +312,7 @@ pcnet32_free_tx_resources ( struct pcnet32_private *priv ) { DBGP ( "pcnet32_free_tx_resources\n" ); - free_dma ( priv->tx_base, TX_RING_BYTES ); + free_phys ( priv->tx_base, TX_RING_BYTES ); } static int diff --git a/src/drivers/net/phantom/phantom.c b/src/drivers/net/phantom/phantom.c index 8f247ff8e..843459059 100644 --- a/src/drivers/net/phantom/phantom.c +++ b/src/drivers/net/phantom/phantom.c @@ -640,7 +640,7 @@ static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) { int rc; /* Allocate context creation buffer */ - buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); + buf = malloc_phys ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); if ( ! buf ) { rc = -ENOMEM; goto out; @@ -716,7 +716,7 @@ static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) { phantom, phantom->sds_irq_mask_crb ); out: - free_dma ( buf, sizeof ( *buf ) ); + free_phys ( buf, sizeof ( *buf ) ); return rc; } @@ -765,7 +765,7 @@ static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) { int rc; /* Allocate context creation buffer */ - buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); + buf = malloc_phys ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN ); if ( ! buf ) { rc = -ENOMEM; goto out; @@ -821,7 +821,7 @@ static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) { phantom, phantom->cds_producer_crb ); out: - free_dma ( buf, sizeof ( *buf ) ); + free_phys ( buf, sizeof ( *buf ) ); return rc; } @@ -1164,8 +1164,8 @@ static int phantom_open ( struct net_device *netdev ) { int rc; /* Allocate and zero descriptor rings */ - phantom->desc = malloc_dma ( sizeof ( *(phantom->desc) ), - UNM_DMA_BUFFER_ALIGN ); + phantom->desc = malloc_phys ( sizeof ( *(phantom->desc) ), + UNM_DMA_BUFFER_ALIGN ); if ( ! phantom->desc ) { rc = -ENOMEM; goto err_alloc_desc; @@ -1208,7 +1208,7 @@ static int phantom_open ( struct net_device *netdev ) { err_create_tx_ctx: phantom_destroy_rx_ctx ( phantom ); err_create_rx_ctx: - free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) ); + free_phys ( phantom->desc, sizeof ( *(phantom->desc) ) ); phantom->desc = NULL; err_alloc_desc: return rc; @@ -1229,7 +1229,7 @@ static void phantom_close ( struct net_device *netdev ) { phantom_del_macaddr ( phantom, netdev->ll_broadcast ); phantom_destroy_tx_ctx ( phantom ); phantom_destroy_rx_ctx ( phantom ); - free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) ); + free_phys ( phantom->desc, sizeof ( *(phantom->desc) ) ); phantom->desc = NULL; /* Flush any uncompleted descriptors */ diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index e74128c4c..f432dce5f 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -514,7 +514,7 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { return 0; /* Allocate buffer */ - rtl->rx_buffer = malloc_dma ( len, RTL_RXBUF_ALIGN ); + rtl->rx_buffer = malloc_phys ( len, RTL_RXBUF_ALIGN ); if ( ! rtl->rx_buffer ) { rc = -ENOMEM; goto err_alloc; @@ -539,7 +539,7 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { return 0; err_64bit: - free_dma ( rtl->rx_buffer, len ); + free_phys ( rtl->rx_buffer, len ); rtl->rx_buffer = NULL; err_alloc: return rc; @@ -561,7 +561,7 @@ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { writel ( 0, rtl->regs + RTL_RBSTART ); /* Free buffer */ - free_dma ( rtl->rx_buffer, len ); + free_phys ( rtl->rx_buffer, len ); rtl->rx_buffer = NULL; rtl->rx_offset = 0; } @@ -582,7 +582,7 @@ static int realtek_create_ring ( struct realtek_nic *rtl, return 0; /* Allocate descriptor ring */ - ring->desc = malloc_dma ( ring->len, RTL_RING_ALIGN ); + ring->desc = malloc_phys ( ring->len, RTL_RING_ALIGN ); if ( ! ring->desc ) return -ENOMEM; @@ -623,7 +623,7 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, writel ( 0, rtl->regs + ring->reg + 4 ); /* Free descriptor ring */ - free_dma ( ring->desc, ring->len ); + free_phys ( ring->desc, ring->len ); ring->desc = NULL; } diff --git a/src/drivers/net/rhine.c b/src/drivers/net/rhine.c index cbe21c316..f4d3a2580 100644 --- a/src/drivers/net/rhine.c +++ b/src/drivers/net/rhine.c @@ -292,7 +292,7 @@ static int rhine_create_ring ( struct rhine_nic *rhn, unsigned int i; /* Allocate descriptors */ - ring->desc = malloc_dma ( len, RHINE_RING_ALIGN ); + ring->desc = malloc_phys ( len, RHINE_RING_ALIGN ); if ( ! ring->desc ) return -ENOMEM; @@ -328,7 +328,7 @@ static void rhine_destroy_ring ( struct rhine_nic *rhn, writel ( 0, rhn->regs + ring->reg ); /* Free descriptor ring */ - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; diff --git a/src/drivers/net/rtl818x/rtl818x.c b/src/drivers/net/rtl818x/rtl818x.c index f5082084e..599d36fad 100644 --- a/src/drivers/net/rtl818x/rtl818x.c +++ b/src/drivers/net/rtl818x/rtl818x.c @@ -328,8 +328,8 @@ static int rtl818x_init_rx_ring(struct net80211_device *dev) struct rtl818x_rx_desc *entry; int i; - priv->rx_ring = malloc_dma(sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE, - RTL818X_RING_ALIGN); + priv->rx_ring = malloc_phys(sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE, + RTL818X_RING_ALIGN); priv->rx_ring_dma = virt_to_bus(priv->rx_ring); if (!priv->rx_ring) { DBG("rtl818x %s: cannot allocate RX ring\n", dev->netdev->name); @@ -364,7 +364,7 @@ static void rtl818x_free_rx_ring(struct net80211_device *dev) priv->rx_buf[i] = NULL; } - free_dma(priv->rx_ring, sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE); + free_phys(priv->rx_ring, sizeof(*priv->rx_ring) * RTL818X_RX_RING_SIZE); priv->rx_ring = NULL; } @@ -373,8 +373,8 @@ static int rtl818x_init_tx_ring(struct net80211_device *dev) struct rtl818x_priv *priv = dev->priv; int i; - priv->tx_ring = malloc_dma(sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE, - RTL818X_RING_ALIGN); + priv->tx_ring = malloc_phys(sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE, + RTL818X_RING_ALIGN); priv->tx_ring_dma = virt_to_bus(priv->tx_ring); if (!priv->tx_ring) { DBG("rtl818x %s: cannot allocate TX ring\n", dev->netdev->name); @@ -402,7 +402,7 @@ static void rtl818x_free_tx_ring(struct net80211_device *dev) priv->tx_buf[i] = NULL; } - free_dma(priv->tx_ring, sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE); + free_phys(priv->tx_ring, sizeof(*priv->tx_ring) * RTL818X_TX_RING_SIZE); priv->tx_ring = NULL; } diff --git a/src/drivers/net/sfc/efx_hunt.c b/src/drivers/net/sfc/efx_hunt.c index 07dd7dfea..c846379af 100644 --- a/src/drivers/net/sfc/efx_hunt.c +++ b/src/drivers/net/sfc/efx_hunt.c @@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); void efx_hunt_free_special_buffer(void *buf, int bytes) { - free_dma(buf, bytes); + free_phys(buf, bytes); } static void *efx_hunt_alloc_special_buffer(int bytes, @@ -50,7 +50,7 @@ static void *efx_hunt_alloc_special_buffer(int bytes, * buffer will be passed into an MC_CMD_INIT_*Q command to setup the * appropriate type of queue via MCDI. */ - buffer = malloc_dma(bytes, EFX_BUF_ALIGN); + buffer = malloc_phys(bytes, EFX_BUF_ALIGN); if (!buffer) return NULL; diff --git a/src/drivers/net/sis190.c b/src/drivers/net/sis190.c index 11dda1c97..0e4f0762e 100644 --- a/src/drivers/net/sis190.c +++ b/src/drivers/net/sis190.c @@ -552,7 +552,7 @@ static int sis190_open(struct net_device *dev) int rc; /* Allocate TX ring */ - tp->TxDescRing = malloc_dma(TX_RING_BYTES, RING_ALIGNMENT); + tp->TxDescRing = malloc_phys(TX_RING_BYTES, RING_ALIGNMENT); if (!tp->TxDescRing) { DBG("sis190: TX ring allocation failed\n"); rc = -ENOMEM; @@ -561,7 +561,7 @@ static int sis190_open(struct net_device *dev) tp->tx_dma = cpu_to_le32(virt_to_bus(tp->TxDescRing)); /* Allocate RX ring */ - tp->RxDescRing = malloc_dma(RX_RING_BYTES, RING_ALIGNMENT); + tp->RxDescRing = malloc_phys(RX_RING_BYTES, RING_ALIGNMENT); if (!tp->RxDescRing) { DBG("sis190: RX ring allocation failed\n"); rc = -ENOMEM; @@ -600,8 +600,8 @@ static void sis190_free(struct net_device *dev) struct sis190_private *tp = netdev_priv(dev); int i; - free_dma(tp->TxDescRing, TX_RING_BYTES); - free_dma(tp->RxDescRing, RX_RING_BYTES); + free_phys(tp->TxDescRing, TX_RING_BYTES); + free_phys(tp->RxDescRing, RX_RING_BYTES); tp->TxDescRing = NULL; tp->RxDescRing = NULL; diff --git a/src/drivers/net/skge.c b/src/drivers/net/skge.c index c9a7891ba..5aa5e2a6a 100755 --- a/src/drivers/net/skge.c +++ b/src/drivers/net/skge.c @@ -1699,7 +1699,7 @@ void skge_free(struct net_device *dev) free(skge->tx_ring.start); skge->tx_ring.start = NULL; - free_dma(skge->mem, RING_SIZE); + free_phys(skge->mem, RING_SIZE); skge->mem = NULL; skge->dma = 0; } @@ -1714,7 +1714,7 @@ static int skge_up(struct net_device *dev) DBG2(PFX "%s: enabling interface\n", dev->name); - skge->mem = malloc_dma(RING_SIZE, SKGE_RING_ALIGN); + skge->mem = malloc_phys(RING_SIZE, SKGE_RING_ALIGN); skge->dma = virt_to_bus(skge->mem); if (!skge->mem) return -ENOMEM; diff --git a/src/drivers/net/sky2.c b/src/drivers/net/sky2.c index 0d11e17df..9d612c997 100644 --- a/src/drivers/net/sky2.c +++ b/src/drivers/net/sky2.c @@ -1112,10 +1112,10 @@ nomem: /* Free the le and ring buffers */ static void sky2_free_rings(struct sky2_port *sky2) { - free_dma(sky2->rx_le, RX_LE_BYTES); + free_phys(sky2->rx_le, RX_LE_BYTES); free(sky2->rx_ring); - free_dma(sky2->tx_le, TX_RING_SIZE * sizeof(struct sky2_tx_le)); + free_phys(sky2->tx_le, TX_RING_SIZE * sizeof(struct sky2_tx_le)); free(sky2->tx_ring); sky2->tx_le = NULL; @@ -1137,7 +1137,7 @@ static int sky2_up(struct net_device *dev) netdev_link_down(dev); /* must be power of 2 */ - sky2->tx_le = malloc_dma(TX_RING_SIZE * sizeof(struct sky2_tx_le), TX_RING_ALIGN); + sky2->tx_le = malloc_phys(TX_RING_SIZE * sizeof(struct sky2_tx_le), TX_RING_ALIGN); sky2->tx_le_map = virt_to_bus(sky2->tx_le); if (!sky2->tx_le) goto err_out; @@ -1149,7 +1149,7 @@ static int sky2_up(struct net_device *dev) tx_init(sky2); - sky2->rx_le = malloc_dma(RX_LE_BYTES, RX_RING_ALIGN); + sky2->rx_le = malloc_phys(RX_LE_BYTES, RX_RING_ALIGN); sky2->rx_le_map = virt_to_bus(sky2->rx_le); if (!sky2->rx_le) goto err_out; @@ -2285,7 +2285,7 @@ static int sky2_probe(struct pci_device *pdev) } /* ring for status responses */ - hw->st_le = malloc_dma(STATUS_LE_BYTES, STATUS_RING_ALIGN); + hw->st_le = malloc_phys(STATUS_LE_BYTES, STATUS_RING_ALIGN); if (!hw->st_le) goto err_out_iounmap; hw->st_dma = virt_to_bus(hw->st_le); @@ -2344,7 +2344,7 @@ err_out_free_netdev: netdev_put(dev); err_out_free_pci: sky2_write8(hw, B0_CTST, CS_RST_SET); - free_dma(hw->st_le, STATUS_LE_BYTES); + free_phys(hw->st_le, STATUS_LE_BYTES); err_out_iounmap: iounmap((void *)hw->regs); err_out_free_hw: @@ -2373,7 +2373,7 @@ static void sky2_remove(struct pci_device *pdev) sky2_write8(hw, B0_CTST, CS_RST_SET); sky2_read8(hw, B0_CTST); - free_dma(hw->st_le, STATUS_LE_BYTES); + free_phys(hw->st_le, STATUS_LE_BYTES); for (i = hw->ports-1; i >= 0; --i) { netdev_nullify(hw->dev[i]); diff --git a/src/drivers/net/tg3/tg3.c b/src/drivers/net/tg3/tg3.c index f6c038112..cec599c1c 100644 --- a/src/drivers/net/tg3/tg3.c +++ b/src/drivers/net/tg3/tg3.c @@ -42,7 +42,7 @@ void tg3_rx_prodring_fini(struct tg3_rx_prodring_set *tpr) { DBGP("%s\n", __func__); if (tpr->rx_std) { - free_dma(tpr->rx_std, TG3_RX_STD_RING_BYTES(tp)); + free_phys(tpr->rx_std, TG3_RX_STD_RING_BYTES(tp)); tpr->rx_std = NULL; } } @@ -55,7 +55,7 @@ static void tg3_free_consistent(struct tg3 *tp) { DBGP("%s\n", __func__); if (tp->tx_ring) { - free_dma(tp->tx_ring, TG3_TX_RING_BYTES); + free_phys(tp->tx_ring, TG3_TX_RING_BYTES); tp->tx_ring = NULL; } @@ -63,7 +63,7 @@ static void tg3_free_consistent(struct tg3 *tp) tp->tx_buffers = NULL; if (tp->rx_rcb) { - free_dma(tp->rx_rcb, TG3_RX_RCB_RING_BYTES(tp)); + free_phys(tp->rx_rcb, TG3_RX_RCB_RING_BYTES(tp)); tp->rx_rcb_mapping = 0; tp->rx_rcb = NULL; } @@ -71,7 +71,7 @@ static void tg3_free_consistent(struct tg3 *tp) tg3_rx_prodring_fini(&tp->prodring); if (tp->hw_status) { - free_dma(tp->hw_status, TG3_HW_STATUS_SIZE); + free_phys(tp->hw_status, TG3_HW_STATUS_SIZE); tp->status_mapping = 0; tp->hw_status = NULL; } @@ -87,7 +87,7 @@ int tg3_alloc_consistent(struct tg3 *tp) struct tg3_hw_status *sblk; struct tg3_rx_prodring_set *tpr = &tp->prodring; - tp->hw_status = malloc_dma(TG3_HW_STATUS_SIZE, TG3_DMA_ALIGNMENT); + tp->hw_status = malloc_phys(TG3_HW_STATUS_SIZE, TG3_DMA_ALIGNMENT); if (!tp->hw_status) { DBGC(tp->dev, "hw_status alloc failed\n"); goto err_out; @@ -97,7 +97,7 @@ int tg3_alloc_consistent(struct tg3 *tp) memset(tp->hw_status, 0, TG3_HW_STATUS_SIZE); sblk = tp->hw_status; - tpr->rx_std = malloc_dma(TG3_RX_STD_RING_BYTES(tp), TG3_DMA_ALIGNMENT); + tpr->rx_std = malloc_phys(TG3_RX_STD_RING_BYTES(tp), TG3_DMA_ALIGNMENT); if (!tpr->rx_std) { DBGC(tp->dev, "rx prodring alloc failed\n"); goto err_out; @@ -109,7 +109,7 @@ int tg3_alloc_consistent(struct tg3 *tp) if (!tp->tx_buffers) goto err_out; - tp->tx_ring = malloc_dma(TG3_TX_RING_BYTES, TG3_DMA_ALIGNMENT); + tp->tx_ring = malloc_phys(TG3_TX_RING_BYTES, TG3_DMA_ALIGNMENT); if (!tp->tx_ring) goto err_out; tp->tx_desc_mapping = virt_to_bus(tp->tx_ring); @@ -123,7 +123,7 @@ int tg3_alloc_consistent(struct tg3 *tp) tp->rx_rcb_prod_idx = &sblk->idx[0].rx_producer; - tp->rx_rcb = malloc_dma(TG3_RX_RCB_RING_BYTES(tp), TG3_DMA_ALIGNMENT); + tp->rx_rcb = malloc_phys(TG3_RX_RCB_RING_BYTES(tp), TG3_DMA_ALIGNMENT); if (!tp->rx_rcb) goto err_out; tp->rx_rcb_mapping = virt_to_bus(tp->rx_rcb); @@ -541,7 +541,7 @@ static int tg3_test_dma(struct tg3 *tp) u32 *buf; int ret = 0; - buf = malloc_dma(TEST_BUFFER_SIZE, TG3_DMA_ALIGNMENT); + buf = malloc_phys(TEST_BUFFER_SIZE, TG3_DMA_ALIGNMENT); if (!buf) { ret = -ENOMEM; goto out_nofree; @@ -708,7 +708,7 @@ static int tg3_test_dma(struct tg3 *tp) } out: - free_dma(buf, TEST_BUFFER_SIZE); + free_phys(buf, TEST_BUFFER_SIZE); out_nofree: return ret; } diff --git a/src/drivers/net/velocity.c b/src/drivers/net/velocity.c index 994e07a64..373714293 100644 --- a/src/drivers/net/velocity.c +++ b/src/drivers/net/velocity.c @@ -320,7 +320,8 @@ static int velocity_alloc_rings ( struct velocity_nic *vlc ) { vlc->rx_prod = 0; vlc->rx_cons = 0; vlc->rx_commit = 0; - vlc->rx_ring = malloc_dma ( VELOCITY_RXDESC_SIZE, VELOCITY_RING_ALIGN ); + vlc->rx_ring = malloc_phys ( VELOCITY_RXDESC_SIZE, + VELOCITY_RING_ALIGN ); if ( ! vlc->rx_ring ) return -ENOMEM; @@ -332,7 +333,8 @@ static int velocity_alloc_rings ( struct velocity_nic *vlc ) { /* Allocate TX descriptor ring */ vlc->tx_prod = 0; vlc->tx_cons = 0; - vlc->tx_ring = malloc_dma ( VELOCITY_TXDESC_SIZE, VELOCITY_RING_ALIGN ); + vlc->tx_ring = malloc_phys ( VELOCITY_TXDESC_SIZE, + VELOCITY_RING_ALIGN ); if ( ! vlc->tx_ring ) { rc = -ENOMEM; goto err_tx_alloc; @@ -356,7 +358,7 @@ static int velocity_alloc_rings ( struct velocity_nic *vlc ) { return 0; err_tx_alloc: - free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE ); + free_phys ( vlc->rx_ring, VELOCITY_RXDESC_SIZE ); return rc; } @@ -482,7 +484,7 @@ static void velocity_close ( struct net_device *netdev ) { writew ( 0, vlc->regs + VELOCITY_RXDESCNUM ); /* Destroy RX ring */ - free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE ); + free_phys ( vlc->rx_ring, VELOCITY_RXDESC_SIZE ); vlc->rx_ring = NULL; vlc->rx_prod = 0; vlc->rx_cons = 0; @@ -499,7 +501,7 @@ static void velocity_close ( struct net_device *netdev ) { writew ( 0, vlc->regs + VELOCITY_TXDESCNUM ); /* Destroy TX ring */ - free_dma ( vlc->tx_ring, VELOCITY_TXDESC_SIZE ); + free_phys ( vlc->tx_ring, VELOCITY_TXDESC_SIZE ); vlc->tx_ring = NULL; vlc->tx_prod = 0; vlc->tx_cons = 0; diff --git a/src/drivers/net/vmxnet3.c b/src/drivers/net/vmxnet3.c index 3e0ab03cd..63bcf0e01 100644 --- a/src/drivers/net/vmxnet3.c +++ b/src/drivers/net/vmxnet3.c @@ -465,7 +465,8 @@ static int vmxnet3_open ( struct net_device *netdev ) { int rc; /* Allocate DMA areas */ - vmxnet->dma = malloc_dma ( sizeof ( *vmxnet->dma ), VMXNET3_DMA_ALIGN ); + vmxnet->dma = malloc_phys ( sizeof ( *vmxnet->dma ), + VMXNET3_DMA_ALIGN ); if ( ! vmxnet->dma ) { DBGC ( vmxnet, "VMXNET3 %p could not allocate DMA area\n", vmxnet ); @@ -542,7 +543,7 @@ static int vmxnet3_open ( struct net_device *netdev ) { err_activate: vmxnet3_flush_tx ( netdev ); vmxnet3_flush_rx ( netdev ); - free_dma ( vmxnet->dma, sizeof ( *vmxnet->dma ) ); + free_phys ( vmxnet->dma, sizeof ( *vmxnet->dma ) ); err_alloc_dma: return rc; } @@ -559,7 +560,7 @@ static void vmxnet3_close ( struct net_device *netdev ) { vmxnet3_command ( vmxnet, VMXNET3_CMD_RESET_DEV ); vmxnet3_flush_tx ( netdev ); vmxnet3_flush_rx ( netdev ); - free_dma ( vmxnet->dma, sizeof ( *vmxnet->dma ) ); + free_phys ( vmxnet->dma, sizeof ( *vmxnet->dma ) ); } /** vmxnet3 net device operations */ diff --git a/src/drivers/net/vxge/vxge_config.c b/src/drivers/net/vxge/vxge_config.c index ba62b508e..f4d217097 100644 --- a/src/drivers/net/vxge/vxge_config.c +++ b/src/drivers/net/vxge/vxge_config.c @@ -624,10 +624,10 @@ __vxge_hw_ring_create(struct __vxge_hw_virtualpath *vpath, hldev = vpath->hldev; vp_id = vpath->vp_id; - ring->rxdl = malloc_dma(sizeof(struct __vxge_hw_ring_block), + ring->rxdl = malloc_phys(sizeof(struct __vxge_hw_ring_block), sizeof(struct __vxge_hw_ring_block)); if (!ring->rxdl) { - vxge_debug(VXGE_ERR, "%s:%d malloc_dma error\n", + vxge_debug(VXGE_ERR, "%s:%d malloc_phys error\n", __func__, __LINE__); status = VXGE_HW_ERR_OUT_OF_MEMORY; goto exit; @@ -667,7 +667,7 @@ enum vxge_hw_status __vxge_hw_ring_delete(struct __vxge_hw_ring *ring) } if (ring->rxdl) { - free_dma(ring->rxdl, sizeof(struct __vxge_hw_ring_block)); + free_phys(ring->rxdl, sizeof(struct __vxge_hw_ring_block)); ring->rxdl = NULL; } ring->rxd_offset = 0; @@ -826,10 +826,10 @@ __vxge_hw_fifo_create(struct __vxge_hw_virtualpath *vpath, fifo->tx_intr_num = (vpath->vp_id * VXGE_HW_MAX_INTR_PER_VP) + VXGE_HW_VPATH_INTR_TX; - fifo->txdl = malloc_dma(sizeof(struct vxge_hw_fifo_txd) + fifo->txdl = malloc_phys(sizeof(struct vxge_hw_fifo_txd) * fifo->depth, fifo->depth); if (!fifo->txdl) { - vxge_debug(VXGE_ERR, "%s:%d malloc_dma error\n", + vxge_debug(VXGE_ERR, "%s:%d malloc_phys error\n", __func__, __LINE__); return VXGE_HW_ERR_OUT_OF_MEMORY; } @@ -846,7 +846,7 @@ enum vxge_hw_status __vxge_hw_fifo_delete(struct __vxge_hw_fifo *fifo) vxge_trace(); if (fifo->txdl) - free_dma(fifo->txdl, + free_phys(fifo->txdl, sizeof(struct vxge_hw_fifo_txd) * fifo->depth); fifo->txdl = NULL; diff --git a/src/drivers/usb/ehci.c b/src/drivers/usb/ehci.c index 15193efe1..77022a47d 100644 --- a/src/drivers/usb/ehci.c +++ b/src/drivers/usb/ehci.c @@ -565,8 +565,8 @@ static int ehci_ring_alloc ( struct ehci_device *ehci, } /* Allocate queue head */ - ring->head = malloc_dma ( sizeof ( *ring->head ), - ehci_align ( sizeof ( *ring->head ) ) ); + ring->head = malloc_phys ( sizeof ( *ring->head ), + ehci_align ( sizeof ( *ring->head ) ) ); if ( ! ring->head ) { rc = -ENOMEM; goto err_alloc_queue; @@ -579,7 +579,7 @@ static int ehci_ring_alloc ( struct ehci_device *ehci, /* Allocate transfer descriptors */ len = ( EHCI_RING_COUNT * sizeof ( ring->desc[0] ) ); - ring->desc = malloc_dma ( len, sizeof ( ring->desc[0] ) ); + ring->desc = malloc_phys ( len, sizeof ( ring->desc[0] ) ); if ( ! ring->desc ) { rc = -ENOMEM; goto err_alloc_desc; @@ -607,10 +607,10 @@ static int ehci_ring_alloc ( struct ehci_device *ehci, return 0; err_unreachable_desc: - free_dma ( ring->desc, len ); + free_phys ( ring->desc, len ); err_alloc_desc: err_unreachable_queue: - free_dma ( ring->head, sizeof ( *ring->head ) ); + free_phys ( ring->head, sizeof ( *ring->head ) ); err_alloc_queue: free ( ring->iobuf ); err_alloc_iobuf: @@ -631,10 +631,11 @@ static void ehci_ring_free ( struct ehci_ring *ring ) { assert ( ring->iobuf[i] == NULL ); /* Free transfer descriptors */ - free_dma ( ring->desc, ( EHCI_RING_COUNT * sizeof ( ring->desc[0] ) ) ); + free_phys ( ring->desc, ( EHCI_RING_COUNT * + sizeof ( ring->desc[0] ) ) ); /* Free queue head */ - free_dma ( ring->head, sizeof ( *ring->head ) ); + free_phys ( ring->head, sizeof ( *ring->head ) ); /* Free I/O buffers */ free ( ring->iobuf ); @@ -1787,8 +1788,8 @@ static int ehci_bus_open ( struct usb_bus *bus ) { assert ( list_empty ( &ehci->periodic ) ); /* Allocate and initialise asynchronous queue head */ - ehci->head = malloc_dma ( sizeof ( *ehci->head ), - ehci_align ( sizeof ( *ehci->head ) ) ); + ehci->head = malloc_phys ( sizeof ( *ehci->head ), + ehci_align ( sizeof ( *ehci->head ) ) ); if ( ! ehci->head ) { rc = -ENOMEM; goto err_alloc_head; @@ -1816,7 +1817,7 @@ static int ehci_bus_open ( struct usb_bus *bus ) { /* Allocate periodic frame list */ frames = EHCI_PERIODIC_FRAMES ( ehci->flsize ); len = ( frames * sizeof ( ehci->frame[0] ) ); - ehci->frame = malloc_dma ( len, EHCI_PAGE_ALIGN ); + ehci->frame = malloc_phys ( len, EHCI_PAGE_ALIGN ); if ( ! ehci->frame ) { rc = -ENOMEM; goto err_alloc_frame; @@ -1836,10 +1837,10 @@ static int ehci_bus_open ( struct usb_bus *bus ) { ehci_stop ( ehci ); err_unreachable_frame: - free_dma ( ehci->frame, len ); + free_phys ( ehci->frame, len ); err_alloc_frame: err_ctrldssegment: - free_dma ( ehci->head, sizeof ( *ehci->head ) ); + free_phys ( ehci->head, sizeof ( *ehci->head ) ); err_alloc_head: return rc; } @@ -1861,10 +1862,10 @@ static void ehci_bus_close ( struct usb_bus *bus ) { ehci_stop ( ehci ); /* Free periodic frame list */ - free_dma ( ehci->frame, ( frames * sizeof ( ehci->frame[0] ) ) ); + free_phys ( ehci->frame, ( frames * sizeof ( ehci->frame[0] ) ) ); /* Free asynchronous schedule */ - free_dma ( ehci->head, sizeof ( *ehci->head ) ); + free_phys ( ehci->head, sizeof ( *ehci->head ) ); } /** diff --git a/src/drivers/usb/uhci.c b/src/drivers/usb/uhci.c index ce2962d36..47474bdc7 100644 --- a/src/drivers/usb/uhci.c +++ b/src/drivers/usb/uhci.c @@ -179,7 +179,7 @@ static int uhci_ring_alloc ( struct uhci_ring *ring ) { memset ( ring, 0, sizeof ( *ring ) ); /* Allocate queue head */ - ring->head = malloc_dma ( sizeof ( *ring->head ), UHCI_ALIGN ); + ring->head = malloc_phys ( sizeof ( *ring->head ), UHCI_ALIGN ); if ( ! ring->head ) { rc = -ENOMEM; goto err_alloc; @@ -194,7 +194,7 @@ static int uhci_ring_alloc ( struct uhci_ring *ring ) { return 0; err_unreachable: - free_dma ( ring->head, sizeof ( *ring->head ) ); + free_phys ( ring->head, sizeof ( *ring->head ) ); err_alloc: return rc; } @@ -213,7 +213,7 @@ static void uhci_ring_free ( struct uhci_ring *ring ) { assert ( ring->xfer[i] == NULL ); /* Free queue head */ - free_dma ( ring->head, sizeof ( *ring->head ) ); + free_phys ( ring->head, sizeof ( *ring->head ) ); } /** @@ -263,7 +263,7 @@ static int uhci_enqueue ( struct uhci_ring *ring, struct io_buffer *iobuf, /* Allocate transfer descriptors */ len = ( count * sizeof ( xfer->desc[0] ) ); - xfer->desc = malloc_dma ( len, UHCI_ALIGN ); + xfer->desc = malloc_phys ( len, UHCI_ALIGN ); if ( ! xfer->desc ) { rc = -ENOMEM; goto err_alloc_desc; @@ -299,7 +299,7 @@ static int uhci_enqueue ( struct uhci_ring *ring, struct io_buffer *iobuf, return 0; err_unreachable_desc: - free_dma ( xfer->desc, len ); + free_phys ( xfer->desc, len ); err_alloc_desc: free ( xfer ); err_alloc_xfer: @@ -377,7 +377,7 @@ static struct io_buffer * uhci_dequeue ( struct uhci_ring *ring ) { /* Free transfer descriptors */ len = ( xfer->prod * sizeof ( xfer->desc[0] ) ); - free_dma ( xfer->desc, len ); + free_phys ( xfer->desc, len ); /* Free transfer */ free ( xfer ); @@ -1312,7 +1312,7 @@ static int uhci_bus_open ( struct usb_bus *bus ) { assert ( list_empty ( &uhci->periodic ) ); /* Allocate and initialise asynchronous queue head */ - uhci->head = malloc_dma ( sizeof ( *uhci->head ), UHCI_ALIGN ); + uhci->head = malloc_phys ( sizeof ( *uhci->head ), UHCI_ALIGN ); if ( ! uhci->head ) { rc = -ENOMEM; goto err_alloc_head; @@ -1324,8 +1324,8 @@ static int uhci_bus_open ( struct usb_bus *bus ) { uhci_async_schedule ( uhci ); /* Allocate periodic frame list */ - uhci->frame = malloc_dma ( sizeof ( *uhci->frame ), - sizeof ( *uhci->frame ) ); + uhci->frame = malloc_phys ( sizeof ( *uhci->frame ), + sizeof ( *uhci->frame ) ); if ( ! uhci->frame ) { rc = -ENOMEM; goto err_alloc_frame; @@ -1343,10 +1343,10 @@ static int uhci_bus_open ( struct usb_bus *bus ) { uhci_stop ( uhci ); err_unreachable_frame: - free_dma ( uhci->frame, sizeof ( *uhci->frame ) ); + free_phys ( uhci->frame, sizeof ( *uhci->frame ) ); err_alloc_frame: err_unreachable_head: - free_dma ( uhci->head, sizeof ( *uhci->head ) ); + free_phys ( uhci->head, sizeof ( *uhci->head ) ); err_alloc_head: return rc; } @@ -1367,10 +1367,10 @@ static void uhci_bus_close ( struct usb_bus *bus ) { uhci_stop ( uhci ); /* Free periodic frame list */ - free_dma ( uhci->frame, sizeof ( *uhci->frame ) ); + free_phys ( uhci->frame, sizeof ( *uhci->frame ) ); /* Free asynchronous schedule */ - free_dma ( uhci->head, sizeof ( *uhci->head ) ); + free_phys ( uhci->head, sizeof ( *uhci->head ) ); } /** diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index c4a1dc337..7f55a90f2 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -919,7 +919,7 @@ static int xhci_dcbaa_alloc ( struct xhci_device *xhci ) { * with a minimum of 64 bytes). */ len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) ); - xhci->dcbaa = malloc_dma ( len, xhci_align ( len ) ); + xhci->dcbaa = malloc_phys ( len, xhci_align ( len ) ); if ( ! xhci->dcbaa ) { DBGC ( xhci, "XHCI %s could not allocate DCBAA\n", xhci->name ); rc = -ENOMEM; @@ -938,7 +938,7 @@ static int xhci_dcbaa_alloc ( struct xhci_device *xhci ) { return 0; err_writeq: - free_dma ( xhci->dcbaa, len ); + free_phys ( xhci->dcbaa, len ); err_alloc: return rc; } @@ -961,7 +961,7 @@ static void xhci_dcbaa_free ( struct xhci_device *xhci ) { /* Free DCBAA */ len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) ); - free_dma ( xhci->dcbaa, len ); + free_phys ( xhci->dcbaa, len ); } /****************************************************************************** @@ -1002,7 +1002,7 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { /* Allocate scratchpad array */ array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] )); xhci->scratchpad_array = - malloc_dma ( array_len, xhci_align ( array_len ) ); + malloc_phys ( array_len, xhci_align ( array_len ) ); if ( ! xhci->scratchpad_array ) { DBGC ( xhci, "XHCI %s could not allocate scratchpad buffer " "array\n", xhci->name ); @@ -1027,7 +1027,7 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { ( virt_to_phys ( xhci->scratchpad_array ) + array_len ) ); return 0; - free_dma ( xhci->scratchpad_array, array_len ); + free_phys ( xhci->scratchpad_array, array_len ); err_alloc_array: ufree ( xhci->scratchpad ); err_alloc: @@ -1052,7 +1052,7 @@ static void xhci_scratchpad_free ( struct xhci_device *xhci ) { /* Free scratchpad array */ array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] )); - free_dma ( xhci->scratchpad_array, array_len ); + free_phys ( xhci->scratchpad_array, array_len ); /* Free scratchpads */ ufree ( xhci->scratchpad ); @@ -1202,7 +1202,7 @@ static int xhci_ring_alloc ( struct xhci_device *xhci, } /* Allocate TRBs */ - ring->trb = malloc_dma ( ring->len, xhci_align ( ring->len ) ); + ring->trb = malloc_phys ( ring->len, xhci_align ( ring->len ) ); if ( ! ring->trb ) { rc = -ENOMEM; goto err_alloc_trb; @@ -1218,7 +1218,7 @@ static int xhci_ring_alloc ( struct xhci_device *xhci, return 0; - free_dma ( ring->trb, ring->len ); + free_phys ( ring->trb, ring->len ); err_alloc_trb: free ( ring->iobuf ); err_alloc_iobuf: @@ -1256,7 +1256,7 @@ static void xhci_ring_free ( struct xhci_trb_ring *ring ) { assert ( ring->iobuf[i] == NULL ); /* Free TRBs */ - free_dma ( ring->trb, ring->len ); + free_phys ( ring->trb, ring->len ); /* Free I/O buffers */ free ( ring->iobuf ); @@ -1469,7 +1469,7 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { /* Allocate event ring */ count = ( 1 << XHCI_EVENT_TRBS_LOG2 ); len = ( count * sizeof ( event->trb[0] ) ); - event->trb = malloc_dma ( len, xhci_align ( len ) ); + event->trb = malloc_phys ( len, xhci_align ( len ) ); if ( ! event->trb ) { rc = -ENOMEM; goto err_alloc_trb; @@ -1477,8 +1477,8 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { memset ( event->trb, 0, len ); /* Allocate event ring segment table */ - event->segment = malloc_dma ( sizeof ( event->segment[0] ), - xhci_align ( sizeof (event->segment[0]))); + event->segment = malloc_phys ( sizeof ( event->segment[0] ), + xhci_align ( sizeof(event->segment[0]))); if ( ! event->segment ) { rc = -ENOMEM; goto err_alloc_segment; @@ -1508,9 +1508,9 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { err_writeq_erstba: xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) ); err_writeq_erdp: - free_dma ( event->trb, len ); + free_phys ( event->trb, len ); err_alloc_segment: - free_dma ( event->segment, sizeof ( event->segment[0] ) ); + free_phys ( event->segment, sizeof ( event->segment[0] ) ); err_alloc_trb: return rc; } @@ -1531,12 +1531,12 @@ static void xhci_event_free ( struct xhci_device *xhci ) { xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) ); /* Free event ring segment table */ - free_dma ( event->segment, sizeof ( event->segment[0] ) ); + free_phys ( event->segment, sizeof ( event->segment[0] ) ); /* Free event ring */ count = ( 1 << XHCI_EVENT_TRBS_LOG2 ); len = ( count * sizeof ( event->trb[0] ) ); - free_dma ( event->trb, len ); + free_phys ( event->trb, len ); } /** @@ -1948,7 +1948,7 @@ static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot, /* Allocate an input context */ len = xhci_input_context_offset ( xhci, XHCI_CTX_END ); - input = malloc_dma ( len, xhci_align ( len ) ); + input = malloc_phys ( len, xhci_align ( len ) ); if ( ! input ) { rc = -ENOMEM; goto err_alloc; @@ -1969,7 +1969,7 @@ static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot, goto err_command; err_command: - free_dma ( input, len ); + free_phys ( input, len ); err_alloc: return rc; } @@ -2693,7 +2693,7 @@ static int xhci_device_open ( struct usb_device *usb ) { /* Allocate a device context */ len = xhci_device_context_offset ( xhci, XHCI_CTX_END ); - slot->context = malloc_dma ( len, xhci_align ( len ) ); + slot->context = malloc_phys ( len, xhci_align ( len ) ); if ( ! slot->context ) { rc = -ENOMEM; goto err_alloc_context; @@ -2710,7 +2710,7 @@ static int xhci_device_open ( struct usb_device *usb ) { return 0; xhci->dcbaa[id] = 0; - free_dma ( slot->context, len ); + free_phys ( slot->context, len ); err_alloc_context: xhci->slot[id] = NULL; free ( slot ); @@ -2750,7 +2750,7 @@ static void xhci_device_close ( struct usb_device *usb ) { /* Free slot */ if ( slot->context ) { - free_dma ( slot->context, len ); + free_phys ( slot->context, len ); xhci->dcbaa[id] = 0; } xhci->slot[id] = NULL; diff --git a/src/include/ipxe/malloc.h b/src/include/ipxe/malloc.h index 1878978fd..180ca001d 100644 --- a/src/include/ipxe/malloc.h +++ b/src/include/ipxe/malloc.h @@ -14,7 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /* * Prototypes for the standard functions (malloc() et al) are in * stdlib.h. Include only if you need the - * non-standard functions, such as malloc_dma(). + * non-standard functions, such as malloc_phys(). * */ #include @@ -32,20 +32,18 @@ extern void mpopulate ( void *start, size_t len ); extern void mdumpfree ( void ); /** - * Allocate memory for DMA + * Allocate memory with specified physical alignment and offset * * @v size Requested size * @v align Physical alignment * @v offset Offset from physical alignment * @ret ptr Memory, or NULL * - * Allocates physically-aligned memory for DMA. - * * @c align must be a power of two. @c size may not be zero. */ -static inline void * __malloc malloc_dma_offset ( size_t size, - size_t phys_align, - size_t offset ) { +static inline void * __malloc malloc_phys_offset ( size_t size, + size_t phys_align, + size_t offset ) { void * ptr = alloc_memblock ( size, phys_align, offset ); if ( ptr && size ) VALGRIND_MALLOCLIKE_BLOCK ( ptr, size, 0, 0 ); @@ -53,32 +51,30 @@ static inline void * __malloc malloc_dma_offset ( size_t size, } /** - * Allocate memory for DMA + * Allocate memory with specified physical alignment * * @v size Requested size * @v align Physical alignment * @ret ptr Memory, or NULL * - * Allocates physically-aligned memory for DMA. - * * @c align must be a power of two. @c size may not be zero. */ -static inline void * __malloc malloc_dma ( size_t size, size_t phys_align ) { - return malloc_dma_offset ( size, phys_align, 0 ); +static inline void * __malloc malloc_phys ( size_t size, size_t phys_align ) { + return malloc_phys_offset ( size, phys_align, 0 ); } /** - * Free memory allocated with malloc_dma() + * Free memory allocated with malloc_phys() * - * @v ptr Memory allocated by malloc_dma(), or NULL - * @v size Size of memory, as passed to malloc_dma() + * @v ptr Memory allocated by malloc_phys(), or NULL + * @v size Size of memory, as passed to malloc_phys() * - * Memory allocated with malloc_dma() can only be freed with - * free_dma(); it cannot be freed with the standard free(). + * Memory allocated with malloc_phys() can only be freed with + * free_phys(); it cannot be freed with the standard free(). * * If @c ptr is NULL, no action is taken. */ -static inline void free_dma ( void *ptr, size_t size ) { +static inline void free_phys ( void *ptr, size_t size ) { VALGRIND_FREELIKE_BLOCK ( ptr, 0 ); free_memblock ( ptr, size ); } diff --git a/src/interface/hyperv/vmbus.c b/src/interface/hyperv/vmbus.c index e50fe9951..86d2a08d7 100644 --- a/src/interface/hyperv/vmbus.c +++ b/src/interface/hyperv/vmbus.c @@ -434,7 +434,7 @@ int vmbus_open ( struct vmbus_device *vmdev, len = ( sizeof ( *vmdev->out ) + out_len + sizeof ( *vmdev->in ) + in_len ); assert ( ( len % PAGE_SIZE ) == 0 ); - ring = malloc_dma ( len, PAGE_SIZE ); + ring = malloc_phys ( len, PAGE_SIZE ); if ( ! ring ) { rc = -ENOMEM; goto err_alloc_ring; @@ -509,7 +509,7 @@ int vmbus_open ( struct vmbus_device *vmdev, err_post_message: vmbus_gpadl_teardown ( vmdev, vmdev->gpadl ); err_establish: - free_dma ( ring, len ); + free_phys ( ring, len ); err_alloc_ring: free ( packet ); err_alloc_packet: @@ -555,7 +555,7 @@ void vmbus_close ( struct vmbus_device *vmdev ) { /* Free ring buffer */ len = ( sizeof ( *vmdev->out ) + vmdev->out_len + sizeof ( *vmdev->in ) + vmdev->in_len ); - free_dma ( vmdev->out, len ); + free_phys ( vmdev->out, len ); vmdev->out = NULL; vmdev->in = NULL; -- cgit v1.2.3-55-g7522 From dda03c884d70d18546bb2d02f92acb4c4da28fc8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 4 Nov 2020 15:18:49 +0000 Subject: [dma] Define a DMA API to allow for non-flat device address spaces iPXE currently assumes that DMA-capable devices can directly address physical memory using host addresses. This assumption fails when using an IOMMU. Define an internal DMA API with two implementations: a "flat" implementation for use in legacy BIOS or other environments in which flat physical addressing is guaranteed to be used and all allocated physical addresses are guaranteed to be within a 32-bit address space, and an "operations-based" implementation for use in UEFI or other environments in which DMA mapping may require bus-specific handling. The purpose of the fully inlined "flat" implementation is to allow the trivial identity DMA mappings to be optimised out at build time, thereby avoiding an increase in code size for legacy BIOS builds. Signed-off-by: Michael Brown --- src/config/defaults/efi.h | 1 + src/config/defaults/linux.h | 1 + src/config/defaults/pcbios.h | 1 + src/core/dma.c | 179 +++++++++++++++++++++++ src/include/ipxe/dma.h | 334 +++++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + 6 files changed, 517 insertions(+) create mode 100644 src/core/dma.c create mode 100644 src/include/ipxe/dma.h (limited to 'src/include/ipxe') diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 0979887fc..9ef34ab62 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define UACCESS_EFI #define IOMAP_VIRT #define PCIAPI_EFI +#define DMAAPI_OP #define CONSOLE_EFI #define TIMER_EFI #define UMALLOC_EFI diff --git a/src/config/defaults/linux.h b/src/config/defaults/linux.h index 75fd617f9..98d2dafec 100644 --- a/src/config/defaults/linux.h +++ b/src/config/defaults/linux.h @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define TIME_LINUX #define REBOOT_NULL #define PCIAPI_LINUX +#define DMAAPI_FLAT #define DRIVERS_LINUX diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 41afb9033..83835805a 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define UACCESS_LIBRM #define IOAPI_X86 #define PCIAPI_PCBIOS +#define DMAAPI_FLAT #define TIMER_PCBIOS #define CONSOLE_PCBIOS #define NAP_PCBIOS diff --git a/src/core/dma.c b/src/core/dma.c new file mode 100644 index 000000000..9fc0c5453 --- /dev/null +++ b/src/core/dma.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2020 Michael Brown . + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include + +/** @file + * + * DMA mappings + * + */ + +/****************************************************************************** + * + * Flat address space DMA API + * + ****************************************************************************** + */ + +PROVIDE_DMAAPI_INLINE ( flat, dma_map ); +PROVIDE_DMAAPI_INLINE ( flat, dma_unmap ); +PROVIDE_DMAAPI_INLINE ( flat, dma_alloc ); +PROVIDE_DMAAPI_INLINE ( flat, dma_free ); +PROVIDE_DMAAPI_INLINE ( flat, dma_set_mask ); + +/****************************************************************************** + * + * Operations-based DMA API + * + ****************************************************************************** + */ + +/** + * Map buffer for DMA + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v flags Mapping flags + * @v map DMA mapping to fill in + * @ret rc Return status code + */ +static int dma_op_map ( struct dma_device *dma, physaddr_t addr, size_t len, + int flags, struct dma_mapping *map ) { + struct dma_operations *op = dma->op; + + if ( ! op ) + return -ENODEV; + return op->map ( dma, addr, len, flags, map ); +} + +/** + * Unmap buffer + * + * @v dma DMA device + * @v map DMA mapping + */ +static void dma_op_unmap ( struct dma_device *dma, struct dma_mapping *map ) { + struct dma_operations *op = dma->op; + + assert ( op != NULL ); + op->unmap ( dma, map ); +} + +/** + * Allocate and map DMA-coherent buffer + * + * @v dma DMA device + * @v len Length of buffer + * @v align Physical alignment + * @v map DMA mapping to fill in + * @ret addr Buffer address, or NULL on error + */ +static void * dma_op_alloc ( struct dma_device *dma, size_t len, size_t align, + struct dma_mapping *map ) { + struct dma_operations *op = dma->op; + + if ( ! op ) + return NULL; + return op->alloc ( dma, len, align, map ); +} + +/** + * Unmap and free DMA-coherent buffer + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v map DMA mapping + */ +static void dma_op_free ( struct dma_device *dma, void *addr, size_t len, + struct dma_mapping *map ) { + struct dma_operations *op = dma->op; + + assert ( op != NULL ); + op->free ( dma, addr, len, map ); +} + +/** + * Set addressable space mask + * + * @v dma DMA device + * @v mask Addressable space mask + */ +static void dma_op_set_mask ( struct dma_device *dma, physaddr_t mask ) { + struct dma_operations *op = dma->op; + + if ( op ) + op->set_mask ( dma, mask ); +} + +PROVIDE_DMAAPI ( op, dma_map, dma_op_map ); +PROVIDE_DMAAPI ( op, dma_unmap, dma_op_unmap ); +PROVIDE_DMAAPI ( op, dma_alloc, dma_op_alloc ); +PROVIDE_DMAAPI ( op, dma_free, dma_op_free ); +PROVIDE_DMAAPI ( op, dma_set_mask, dma_op_set_mask ); + +/****************************************************************************** + * + * Utility functions + * + ****************************************************************************** + */ + +/** + * Allocate and map I/O buffer for receiving data from device + * + * @v dma DMA device + * @v len Length of I/O buffer + * @v map DMA mapping to fill in + * @ret iobuf I/O buffer, or NULL on error + */ +struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, + struct dma_mapping *map ) { + struct io_buffer *iobuf; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) + goto err_alloc; + + /* Map I/O buffer */ + if ( ( rc = dma_map ( dma, virt_to_phys ( iobuf->data ), len, + DMA_RX, map ) ) != 0 ) + goto err_map; + + return iobuf; + + dma_unmap ( dma, map ); + err_map: + free_iob ( iobuf ); + err_alloc: + return NULL; +} diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h new file mode 100644 index 000000000..d3db061f7 --- /dev/null +++ b/src/include/ipxe/dma.h @@ -0,0 +1,334 @@ +#ifndef _IPXE_DMA_H +#define _IPXE_DMA_H + +/** @file + * + * DMA mappings + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include + +#ifdef DMAAPI_OP +#define DMAAPI_PREFIX_op +#else +#define DMAAPI_PREFIX_op __op_ +#endif + +#ifdef DMAAPI_FLAT +#define DMAAPI_PREFIX_flat +#else +#define DMAAPI_PREFIX_flat __flat_ +#endif + +/** A DMA mapping */ +struct dma_mapping { + /** Device-side address */ + physaddr_t addr; +}; + +/** A DMA-capable device */ +struct dma_device { + /** DMA operations */ + struct dma_operations *op; + /** Addressable space mask */ + physaddr_t mask; + /** Total number of mappings (for debugging) */ + unsigned int mapped; + /** Total number of allocations (for debugging) */ + unsigned int allocated; +}; + +/** DMA operations */ +struct dma_operations { + /** + * Map buffer for DMA + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v flags Mapping flags + * @v map DMA mapping to fill in + * @ret rc Return status code + */ + int ( * map ) ( struct dma_device *dma, physaddr_t addr, size_t len, + int flags, struct dma_mapping *map ); + /** + * Unmap buffer + * + * @v dma DMA device + * @v map DMA mapping + */ + void ( * unmap ) ( struct dma_device *dma, struct dma_mapping *map ); + /** + * Allocate and map DMA-coherent buffer + * + * @v dma DMA device + * @v len Length of buffer + * @v align Physical alignment + * @v map DMA mapping to fill in + * @ret addr Buffer address, or NULL on error + */ + void * ( * alloc ) ( struct dma_device *dma, size_t len, size_t align, + struct dma_mapping *map ); + /** + * Unmap and free DMA-coherent buffer + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v map DMA mapping + */ + void ( * free ) ( struct dma_device *dma, void *addr, size_t len, + struct dma_mapping *map ); + /** + * Set addressable space mask + * + * @v dma DMA device + * @v mask Addressable space mask + */ + void ( * set_mask ) ( struct dma_device *dma, physaddr_t mask ); +}; + +/** Device will read data from host memory */ +#define DMA_TX 0x01 + +/** Device will write data to host memory */ +#define DMA_RX 0x02 + +/** Device will both read data from and write data to host memory */ +#define DMA_BI ( DMA_TX | DMA_RX ) + +/** + * Calculate static inline DMA I/O API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define DMAAPI_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( DMAAPI_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide a DMA I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_DMAAPI( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( DMAAPI_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline DMA I/O API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_DMAAPI_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( DMAAPI_PREFIX_ ## _subsys, _api_func ) + +/** + * Map buffer for DMA + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v flags Mapping flags + * @v map DMA mapping to fill in + * @ret rc Return status code + */ +static inline __always_inline int +DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, physaddr_t addr, + size_t len __unused, int flags __unused, + struct dma_mapping *map ) { + + /* Use physical address as device address */ + map->addr = addr; + + /* Increment mapping count (for debugging) */ + if ( DBG_LOG ) + dma->mapped++; + + return 0; +} + +/** + * Unmap buffer + * + * @v dma DMA device + * @v map DMA mapping + */ +static inline __always_inline void +DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_device *dma, + struct dma_mapping *map __unused ) { + + /* Decrement mapping count (for debugging) */ + if ( DBG_LOG ) + dma->mapped--; +} + +/** + * Allocate and map DMA-coherent buffer + * + * @v dma DMA device + * @v len Length of buffer + * @v align Physical alignment + * @v map DMA mapping to fill in + * @ret addr Buffer address, or NULL on error + */ +static inline __always_inline void * +DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, size_t len, + size_t align, struct dma_mapping *map ) { + void *addr; + + /* Allocate buffer */ + addr = malloc_phys ( len, align ); + map->addr = virt_to_phys ( addr ); + + /* Increment allocation count (for debugging) */ + if ( DBG_LOG && addr ) + dma->allocated++; + + return addr; +} + +/** + * Unmap and free DMA-coherent buffer + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v map DMA mapping + */ +static inline __always_inline void +DMAAPI_INLINE ( flat, dma_free ) ( struct dma_device *dma, + void *addr, size_t len, + struct dma_mapping *map __unused ) { + + /* Free buffer */ + free_phys ( addr, len ); + + /* Decrement allocation count (for debugging) */ + if ( DBG_LOG ) + dma->allocated--; +} + +/** + * Set addressable space mask + * + * @v dma DMA device + * @v mask Addressable space mask + */ +static inline __always_inline void +DMAAPI_INLINE ( flat, dma_set_mask ) ( struct dma_device *dma __unused, + physaddr_t mask __unused ) { + + /* Nothing to do */ +} + +/** + * Map buffer for DMA + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v flags Mapping flags + * @v map DMA mapping to fill in + * @ret rc Return status code + */ +int dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, + int flags, struct dma_mapping *map ); + +/** + * Unmap buffer + * + * @v dma DMA device + * @v map DMA mapping + */ +void dma_unmap ( struct dma_device *dma, struct dma_mapping *map ); + +/** + * Allocate and map DMA-coherent buffer + * + * @v dma DMA device + * @v len Length of buffer + * @v align Physical alignment + * @v map DMA mapping to fill in + * @ret addr Buffer address, or NULL on error + */ +void * dma_alloc ( struct dma_device *dma, size_t len, size_t align, + struct dma_mapping *map ); + +/** + * Unmap and free DMA-coherent buffer + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v map DMA mapping + */ +void dma_free ( struct dma_device *dma, void *addr, size_t len, + struct dma_mapping *map ); + +/** + * Set addressable space mask + * + * @v dma DMA device + * @v mask Addressable space mask + */ +void dma_set_mask ( struct dma_device *dma, physaddr_t mask ); + +/** + * Initialise DMA device + * + * @v dma DMA device + * @v op DMA operations + */ +static inline __always_inline void dma_init ( struct dma_device *dma, + struct dma_operations *op ) { + + /* Set operations table */ + dma->op = op; +} + +/** + * Set 64-bit addressable space mask + * + * @v dma DMA device + */ +static inline __always_inline void +dma_set_mask_64bit ( struct dma_device *dma ) { + + /* Set mask to maximum physical address */ + dma_set_mask ( dma, ~( ( physaddr_t ) 0 ) ); +} + +/** + * Map I/O buffer for transmitting data to device + * + * @v dma DMA device + * @v iobuf I/O buffer + * @v map DMA mapping to fill in + * @ret rc Return status code + */ +static inline __always_inline int +dma_map_tx_iob ( struct dma_device *dma, struct io_buffer *iobuf, + struct dma_mapping *map ) { + + /* Map I/O buffer */ + return dma_map ( dma, virt_to_phys ( iobuf->data ), iob_len ( iobuf ), + DMA_TX, map ); +} + +extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, + struct dma_mapping *map ); + +#endif /* _IPXE_DMA_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 8238d4925..1c41feff3 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -75,6 +75,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_sanboot ( ERRFILE_CORE | 0x00230000 ) #define ERRFILE_dummy_sanboot ( ERRFILE_CORE | 0x00240000 ) #define ERRFILE_fdt ( ERRFILE_CORE | 0x00250000 ) +#define ERRFILE_dma ( ERRFILE_CORE | 0x00260000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) -- cgit v1.2.3-55-g7522 From 38a54bd3b1c083b0904555dacf641615370ba172 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 4 Nov 2020 15:23:14 +0000 Subject: [efi] Provide DMA operations for EFI PCI devices Signed-off-by: Michael Brown --- src/include/ipxe/dma.h | 2 + src/include/ipxe/pci.h | 3 + src/interface/efi/efi_pci.c | 237 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index d3db061f7..878e03f11 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -32,6 +32,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); struct dma_mapping { /** Device-side address */ physaddr_t addr; + /** Platform mapping token */ + void *token; }; /** A DMA-capable device */ diff --git a/src/include/ipxe/pci.h b/src/include/ipxe/pci.h index 272c4c06f..6632c574d 100644 --- a/src/include/ipxe/pci.h +++ b/src/include/ipxe/pci.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include /** PCI vendor ID */ @@ -187,6 +188,8 @@ struct pci_class_id { struct pci_device { /** Generic device */ struct device dev; + /** DMA device */ + struct dma_device dma; /** Memory base * * This is the physical address of the first valid memory BAR. diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 27ab61733..6c6ac5c77 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -304,6 +304,240 @@ PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word ); PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword ); PROVIDE_PCIAPI ( efi, pci_ioremap, efipci_ioremap ); +/****************************************************************************** + * + * EFI PCI DMA mappings + * + ****************************************************************************** + */ + +/** + * Map buffer for DMA + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v flags Mapping flags + * @v map DMA mapping to fill in + * @ret rc Return status code + */ +static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, + int flags, struct dma_mapping *map ) { + struct efi_pci_device *efipci = + container_of ( dma, struct efi_pci_device, pci.dma ); + struct pci_device *pci = &efipci->pci; + EFI_PCI_IO_PROTOCOL *pci_io = efipci->io; + EFI_PCI_IO_PROTOCOL_OPERATION op; + EFI_PHYSICAL_ADDRESS bus; + UINTN count; + VOID *mapping; + EFI_STATUS efirc; + int rc; + + /* Sanity check */ + assert ( map->addr == 0 ); + assert ( map->token == NULL ); + + /* Determine operation */ + switch ( flags ) { + case DMA_TX: + op = EfiPciIoOperationBusMasterRead; + break; + case DMA_RX: + op = EfiPciIoOperationBusMasterWrite; + break; + default: + op = EfiPciIoOperationBusMasterCommonBuffer; + break; + } + + /* Map buffer */ + count = len; + if ( ( efirc = pci_io->Map ( pci_io, op, phys_to_virt ( addr ), &count, + &bus, &mapping ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( pci, "EFIPCI " PCI_FMT " cannot map %08lx+%zx: %s\n", + PCI_ARGS ( pci ), addr, len, strerror ( rc ) ); + goto err_map; + } + + /* Check that full length was mapped. The UEFI specification + * allows for multiple mappings to be required, but even the + * EDK2 PCI device drivers will fail if a platform ever + * requires this. + */ + if ( count != len ) { + DBGC ( pci, "EFIPCI " PCI_FMT " attempted split mapping for " + "%08lx+%zx\n", PCI_ARGS ( pci ), addr, len ); + rc = -ENOTSUP; + goto err_len; + } + + /* Populate mapping */ + map->addr = bus; + map->token = mapping; + + /* Increment mapping count (for debugging) */ + if ( DBG_LOG ) + dma->mapped++; + + return 0; + + err_len: + pci_io->Unmap ( pci_io, mapping ); + err_map: + return rc; +} + +/** + * Unmap buffer + * + * @v dma DMA device + * @v map DMA mapping + */ +static void efipci_dma_unmap ( struct dma_device *dma, + struct dma_mapping *map ) { + struct efi_pci_device *efipci = + container_of ( dma, struct efi_pci_device, pci.dma ); + EFI_PCI_IO_PROTOCOL *pci_io = efipci->io; + + /* Sanity check */ + assert ( map->token != NULL ); + + /* Unmap buffer */ + pci_io->Unmap ( pci_io, map->token ); + + /* Clear mapping */ + map->addr = 0; + map->token = NULL; + + /* Decrement mapping count (for debugging) */ + if ( DBG_LOG ) + dma->mapped--; +} + +/** + * Allocate and map DMA-coherent buffer + * + * @v dma DMA device + * @v len Length of buffer + * @v align Physical alignment + * @v map DMA mapping to fill in + * @ret addr Buffer address, or NULL on error + */ +static void * efipci_dma_alloc ( struct dma_device *dma, size_t len, + size_t align __unused, + struct dma_mapping *map ) { + struct efi_pci_device *efipci = + container_of ( dma, struct efi_pci_device, pci.dma ); + struct pci_device *pci = &efipci->pci; + EFI_PCI_IO_PROTOCOL *pci_io = efipci->io; + unsigned int pages; + VOID *addr; + EFI_STATUS efirc; + int rc; + + /* Calculate number of pages */ + pages = ( ( len + EFI_PAGE_SIZE - 1 ) / EFI_PAGE_SIZE ); + + /* Allocate (page-aligned) buffer */ + if ( ( efirc = pci_io->AllocateBuffer ( pci_io, AllocateAnyPages, + EfiBootServicesData, pages, + &addr, 0 ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( pci, "EFIPCI " PCI_FMT " could not allocate %zd bytes: " + "%s\n", PCI_ARGS ( pci ), len, strerror ( rc ) ); + goto err_alloc; + } + + /* Map buffer */ + if ( ( rc = efipci_dma_map ( dma, virt_to_phys ( addr ), len, DMA_BI, + map ) ) != 0 ) + goto err_map; + + /* Increment allocation count (for debugging) */ + if ( DBG_LOG ) + dma->allocated++; + + return addr; + + efipci_dma_unmap ( dma, map ); + err_map: + pci_io->FreeBuffer ( pci_io, pages, addr ); + err_alloc: + return NULL; +} + +/** + * Unmap and free DMA-coherent buffer + * + * @v dma DMA device + * @v addr Buffer address + * @v len Length of buffer + * @v map DMA mapping + */ +static void efipci_dma_free ( struct dma_device *dma, void *addr, size_t len, + struct dma_mapping *map ) { + struct efi_pci_device *efipci = + container_of ( dma, struct efi_pci_device, pci.dma ); + EFI_PCI_IO_PROTOCOL *pci_io = efipci->io; + unsigned int pages; + + /* Calculate number of pages */ + pages = ( ( len + EFI_PAGE_SIZE - 1 ) / EFI_PAGE_SIZE ); + + /* Unmap buffer */ + efipci_dma_unmap ( dma, map ); + + /* Free buffer */ + pci_io->FreeBuffer ( pci_io, pages, addr ); + + /* Decrement allocation count (for debugging) */ + if ( DBG_LOG ) + dma->allocated--; +} + +/** + * Set addressable space mask + * + * @v dma DMA device + * @v mask Addressable space mask + */ +static void efipci_dma_set_mask ( struct dma_device *dma, physaddr_t mask ) { + struct efi_pci_device *efipci = + container_of ( dma, struct efi_pci_device, pci.dma ); + struct pci_device *pci = &efipci->pci; + EFI_PCI_IO_PROTOCOL *pci_io = efipci->io; + EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION op; + UINT64 attrs; + int is64; + EFI_STATUS efirc; + int rc; + + /* Set dual address cycle attribute for 64-bit capable devices */ + is64 = ( ( ( ( uint64_t ) mask ) + 1 ) == 0 ); + op = ( is64 ? EfiPciIoAttributeOperationEnable : + EfiPciIoAttributeOperationDisable ); + attrs = EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE; + if ( ( efirc = pci_io->Attributes ( pci_io, op, attrs, NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( pci, "EFIPCI " PCI_FMT " could not %sable DAC: %s\n", + PCI_ARGS ( pci ), ( is64 ? "en" : "dis" ), + strerror ( rc ) ); + /* Ignore failure: errors will manifest in mapping attempts */ + return; + } +} + +/** EFI PCI DMA operations */ +static struct dma_operations efipci_dma_operations = { + .map = efipci_dma_map, + .unmap = efipci_dma_unmap, + .alloc = efipci_dma_alloc, + .free = efipci_dma_free, + .set_mask = efipci_dma_set_mask, +}; + /****************************************************************************** * * EFI PCI device instantiation @@ -353,6 +587,7 @@ int efipci_open ( EFI_HANDLE device, UINT32 attributes, } busdevfn = PCI_BUSDEVFN ( pci_segment, pci_bus, pci_dev, pci_fn ); pci_init ( &efipci->pci, busdevfn ); + dma_init ( &efipci->pci.dma, &efipci_dma_operations ); DBGCP ( device, "EFIPCI " PCI_FMT " is %s\n", PCI_ARGS ( &efipci->pci ), efi_handle_name ( device ) ); @@ -533,6 +768,8 @@ static void efipci_stop ( struct efi_device *efidev ) { pci_remove ( &efipci->pci ); list_del ( &efipci->pci.dev.siblings ); + assert ( efipci->pci.dma.mapped == 0 ); + assert ( efipci->pci.dma.allocated == 0 ); efipci_close ( device ); free ( efipci ); } -- cgit v1.2.3-55-g7522 From 0e26220902592fb3066d2043dec212d957215b79 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 7 Nov 2020 11:25:00 -0500 Subject: [efi] Rename efi_blacklist to efi_veto Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_blacklist.h | 13 -- src/include/ipxe/efi/efi_veto.h | 13 ++ src/include/ipxe/errfile.h | 2 +- src/interface/efi/efi_blacklist.c | 237 ----------------------------------- src/interface/efi/efi_veto.c | 236 ++++++++++++++++++++++++++++++++++ src/interface/efi/efiprefix.c | 6 +- 6 files changed, 253 insertions(+), 254 deletions(-) delete mode 100644 src/include/ipxe/efi/efi_blacklist.h create mode 100644 src/include/ipxe/efi/efi_veto.h delete mode 100644 src/interface/efi/efi_blacklist.c create mode 100644 src/interface/efi/efi_veto.c (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_blacklist.h b/src/include/ipxe/efi/efi_blacklist.h deleted file mode 100644 index c5a5a61dc..000000000 --- a/src/include/ipxe/efi/efi_blacklist.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _IPXE_EFI_BLACKLIST_H -#define _IPXE_EFI_BLACKLIST_H - -/** @file - * - * EFI driver blacklist - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -extern void efi_unload_blacklist ( void ); - -#endif /* _IPXE_EFI_BLACKLIST_H */ diff --git a/src/include/ipxe/efi/efi_veto.h b/src/include/ipxe/efi/efi_veto.h new file mode 100644 index 000000000..f0c225543 --- /dev/null +++ b/src/include/ipxe/efi/efi_veto.h @@ -0,0 +1,13 @@ +#ifndef _IPXE_EFI_VETO_H +#define _IPXE_EFI_VETO_H + +/** @file + * + * EFI driver vetoes + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +extern void efi_veto_unload ( void ); + +#endif /* _IPXE_EFI_VETO_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 1c41feff3..7c98909d1 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -380,7 +380,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_cert_cmd ( ERRFILE_OTHER | 0x004f0000 ) #define ERRFILE_acpi_settings ( ERRFILE_OTHER | 0x00500000 ) #define ERRFILE_ntlm ( ERRFILE_OTHER | 0x00510000 ) -#define ERRFILE_efi_blacklist ( ERRFILE_OTHER | 0x00520000 ) +#define ERRFILE_efi_veto ( ERRFILE_OTHER | 0x00520000 ) /** @} */ diff --git a/src/interface/efi/efi_blacklist.c b/src/interface/efi/efi_blacklist.c deleted file mode 100644 index 292b28e8c..000000000 --- a/src/interface/efi/efi_blacklist.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2019 Michael Brown . - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** @file - * - * EFI driver blacklist - * - */ - -/** A blacklisted driver */ -struct efi_blacklist { - /** Name */ - const char *name; - /** - * Check if driver is blacklisted - * - * @v binding Driver binding protocol - * @v loaded Loaded image protocol - * @v wtf Component name protocol, if present - * @ret blacklisted Driver is the blacklisted driver - */ - int ( * blacklist ) ( EFI_DRIVER_BINDING_PROTOCOL *binding, - EFI_LOADED_IMAGE_PROTOCOL *loaded, - EFI_COMPONENT_NAME_PROTOCOL *wtf ); -}; - -/** - * Blacklist Dell Ip4ConfigDxe driver - * - * @v binding Driver binding protocol - * @v loaded Loaded image protocol - * @v wtf Component name protocol, if present - * @ret blacklisted Driver is the blacklisted driver - */ -static int -efi_blacklist_dell_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused, - EFI_LOADED_IMAGE_PROTOCOL *loaded __unused, - EFI_COMPONENT_NAME_PROTOCOL *wtf ) { - static const CHAR16 ip4cfg[] = L"IP4 CONFIG Network Service Driver"; - static const char dell[] = "Dell Inc."; - char manufacturer[ sizeof ( dell ) ]; - CHAR16 *name; - - /* Check driver name */ - if ( ! wtf ) - return 0; - if ( wtf->GetDriverName ( wtf, "eng", &name ) != 0 ) - return 0; - if ( memcmp ( name, ip4cfg, sizeof ( ip4cfg ) ) != 0 ) - return 0; - - /* Check manufacturer */ - fetch_string_setting ( NULL, &manufacturer_setting, manufacturer, - sizeof ( manufacturer ) ); - if ( strcmp ( manufacturer, dell ) != 0 ) - return 0; - - return 1; -} - -/** Blacklisted drivers */ -static struct efi_blacklist efi_blacklists[] = { - { - .name = "Dell Ip4Config", - .blacklist = efi_blacklist_dell_ip4config, - }, -}; - -/** - * Find driver blacklisting, if any - * - * @v driver Driver binding handle - * @ret blacklist Driver blacklisting, or NULL - * @ret rc Return status code - */ -static int efi_blacklist ( EFI_HANDLE driver, - struct efi_blacklist **blacklist ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - union { - EFI_DRIVER_BINDING_PROTOCOL *binding; - void *interface; - } binding; - union { - EFI_LOADED_IMAGE_PROTOCOL *loaded; - void *interface; - } loaded; - union { - EFI_COMPONENT_NAME_PROTOCOL *wtf; - void *interface; - } wtf; - unsigned int i; - EFI_HANDLE image; - EFI_STATUS efirc; - int rc; - - DBGC2 ( &efi_blacklists, "EFIBL checking %s\n", - efi_handle_name ( driver ) ); - - /* Mark as not blacklisted */ - *blacklist = NULL; - - /* Open driver binding protocol */ - if ( ( efirc = bs->OpenProtocol ( - driver, &efi_driver_binding_protocol_guid, - &binding.interface, efi_image_handle, driver, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( driver, "EFIBL %s could not open driver binding " - "protocol: %s\n", efi_handle_name ( driver ), - strerror ( rc ) ); - goto err_binding; - } - image = binding.binding->ImageHandle; - - /* Open loaded image protocol */ - if ( ( efirc = bs->OpenProtocol ( - image, &efi_loaded_image_protocol_guid, - &loaded.interface, efi_image_handle, image, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( driver, "EFIBL %s could not open", - efi_handle_name ( driver ) ); - DBGC ( driver, " %s loaded image protocol: %s\n", - efi_handle_name ( image ), strerror ( rc ) ); - goto err_loaded; - } - - /* Open component name protocol, if present*/ - if ( ( efirc = bs->OpenProtocol ( - driver, &efi_component_name_protocol_guid, - &wtf.interface, efi_image_handle, driver, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { - /* Ignore failure; is not required to be present */ - wtf.interface = NULL; - } - - /* Check blacklistings */ - for ( i = 0 ; i < ( sizeof ( efi_blacklists ) / - sizeof ( efi_blacklists[0] ) ) ; i++ ) { - if ( efi_blacklists[i].blacklist ( binding.binding, - loaded.loaded, wtf.wtf ) ) { - *blacklist = &efi_blacklists[i]; - break; - } - } - - /* Success */ - rc = 0; - - /* Close protocols */ - if ( wtf.wtf ) { - bs->CloseProtocol ( driver, &efi_component_name_protocol_guid, - efi_image_handle, driver ); - } - bs->CloseProtocol ( image, &efi_loaded_image_protocol_guid, - efi_image_handle, image ); - err_loaded: - bs->CloseProtocol ( driver, &efi_driver_binding_protocol_guid, - efi_image_handle, driver ); - err_binding: - return rc; -} - -/** - * Unload any blacklisted drivers - * - */ -void efi_unload_blacklist ( void ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct efi_blacklist *blacklist; - EFI_HANDLE *drivers; - EFI_HANDLE driver; - UINTN num_drivers; - unsigned int i; - EFI_STATUS efirc; - int rc; - - /* Locate all driver binding protocol handles */ - if ( ( efirc = bs->LocateHandleBuffer ( - ByProtocol, &efi_driver_binding_protocol_guid, - NULL, &num_drivers, &drivers ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( &efi_blacklists, "EFIBL could not list all drivers: " - "%s\n", strerror ( rc ) ); - return; - } - - /* Unload any blacklisted drivers */ - for ( i = 0 ; i < num_drivers ; i++ ) { - driver = drivers[i]; - if ( ( rc = efi_blacklist ( driver, &blacklist ) ) != 0 ) { - DBGC ( driver, "EFIBL could not determine " - "blacklisting for %s: %s\n", - efi_handle_name ( driver ), strerror ( rc ) ); - continue; - } - if ( ! blacklist ) - continue; - DBGC ( driver, "EFIBL unloading %s (%s)\n", - efi_handle_name ( driver ), blacklist->name ); - if ( ( efirc = bs->UnloadImage ( driver ) ) != 0 ) { - DBGC ( driver, "EFIBL could not unload %s: %s\n", - efi_handle_name ( driver ), strerror ( rc ) ); - } - } - - /* Free handle list */ - bs->FreePool ( drivers ); -} diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c new file mode 100644 index 000000000..0abaa3014 --- /dev/null +++ b/src/interface/efi/efi_veto.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2019 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * EFI driver vetoes + * + */ + +/** A driver veto */ +struct efi_veto { + /** Veto name (for debugging) */ + const char *name; + /** + * Check if driver is vetoed + * + * @v binding Driver binding protocol + * @v loaded Loaded image protocol + * @v wtf Component name protocol, if present + * @ret vetoed Driver is to be vetoed + */ + int ( * veto ) ( EFI_DRIVER_BINDING_PROTOCOL *binding, + EFI_LOADED_IMAGE_PROTOCOL *loaded, + EFI_COMPONENT_NAME_PROTOCOL *wtf ); +}; + +/** + * Veto Dell Ip4ConfigDxe driver + * + * @v binding Driver binding protocol + * @v loaded Loaded image protocol + * @v wtf Component name protocol, if present + * @ret vetoed Driver is to be vetoed + */ +static int +efi_veto_dell_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused, + EFI_LOADED_IMAGE_PROTOCOL *loaded __unused, + EFI_COMPONENT_NAME_PROTOCOL *wtf ) { + static const CHAR16 ip4cfg[] = L"IP4 CONFIG Network Service Driver"; + static const char dell[] = "Dell Inc."; + char manufacturer[ sizeof ( dell ) ]; + CHAR16 *name; + + /* Check driver name */ + if ( ! wtf ) + return 0; + if ( wtf->GetDriverName ( wtf, "eng", &name ) != 0 ) + return 0; + if ( memcmp ( name, ip4cfg, sizeof ( ip4cfg ) ) != 0 ) + return 0; + + /* Check manufacturer */ + fetch_string_setting ( NULL, &manufacturer_setting, manufacturer, + sizeof ( manufacturer ) ); + if ( strcmp ( manufacturer, dell ) != 0 ) + return 0; + + return 1; +} + +/** Driver vetoes */ +static struct efi_veto efi_vetoes[] = { + { + .name = "Dell Ip4Config", + .veto = efi_veto_dell_ip4config, + }, +}; + +/** + * Find driver veto, if any + * + * @v driver Driver binding handle + * @ret veto Driver veto, or NULL + * @ret rc Return status code + */ +static int efi_veto ( EFI_HANDLE driver, struct efi_veto **veto ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_DRIVER_BINDING_PROTOCOL *binding; + void *interface; + } binding; + union { + EFI_LOADED_IMAGE_PROTOCOL *loaded; + void *interface; + } loaded; + union { + EFI_COMPONENT_NAME_PROTOCOL *wtf; + void *interface; + } wtf; + unsigned int i; + EFI_HANDLE image; + EFI_STATUS efirc; + int rc; + + DBGC2 ( &efi_vetoes, "EFIVETO checking %s\n", + efi_handle_name ( driver ) ); + + /* Mark as not vetoed */ + *veto = NULL; + + /* Open driver binding protocol */ + if ( ( efirc = bs->OpenProtocol ( + driver, &efi_driver_binding_protocol_guid, + &binding.interface, efi_image_handle, driver, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not open driver binding " + "protocol: %s\n", efi_handle_name ( driver ), + strerror ( rc ) ); + goto err_binding; + } + image = binding.binding->ImageHandle; + + /* Open loaded image protocol */ + if ( ( efirc = bs->OpenProtocol ( + image, &efi_loaded_image_protocol_guid, + &loaded.interface, efi_image_handle, image, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not open", + efi_handle_name ( driver ) ); + DBGC ( driver, " %s loaded image protocol: %s\n", + efi_handle_name ( image ), strerror ( rc ) ); + goto err_loaded; + } + + /* Open component name protocol, if present*/ + if ( ( efirc = bs->OpenProtocol ( + driver, &efi_component_name_protocol_guid, + &wtf.interface, efi_image_handle, driver, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { + /* Ignore failure; is not required to be present */ + wtf.interface = NULL; + } + + /* Check vetoes */ + for ( i = 0 ; i < ( sizeof ( efi_vetoes ) / + sizeof ( efi_vetoes[0] ) ) ; i++ ) { + if ( efi_vetoes[i].veto ( binding.binding, loaded.loaded, + wtf.wtf ) ) { + *veto = &efi_vetoes[i]; + break; + } + } + + /* Success */ + rc = 0; + + /* Close protocols */ + if ( wtf.wtf ) { + bs->CloseProtocol ( driver, &efi_component_name_protocol_guid, + efi_image_handle, driver ); + } + bs->CloseProtocol ( image, &efi_loaded_image_protocol_guid, + efi_image_handle, image ); + err_loaded: + bs->CloseProtocol ( driver, &efi_driver_binding_protocol_guid, + efi_image_handle, driver ); + err_binding: + return rc; +} + +/** + * Unload any vetoed drivers + * + */ +void efi_veto_unload ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + struct efi_veto *veto; + EFI_HANDLE *drivers; + EFI_HANDLE driver; + UINTN num_drivers; + unsigned int i; + EFI_STATUS efirc; + int rc; + + /* Locate all driver binding protocol handles */ + if ( ( efirc = bs->LocateHandleBuffer ( + ByProtocol, &efi_driver_binding_protocol_guid, + NULL, &num_drivers, &drivers ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efi_vetoes, "EFIVETO could not list all drivers: " + "%s\n", strerror ( rc ) ); + return; + } + + /* Unload any vetoed drivers */ + for ( i = 0 ; i < num_drivers ; i++ ) { + driver = drivers[i]; + if ( ( rc = efi_veto ( driver, &veto ) ) != 0 ) { + DBGC ( driver, "EFIVETO could not determine " + "vetoing for %s: %s\n", + efi_handle_name ( driver ), strerror ( rc ) ); + continue; + } + if ( ! veto ) + continue; + DBGC ( driver, "EFIVETO unloading %s (%s)\n", + efi_handle_name ( driver ), veto->name ); + if ( ( efirc = bs->UnloadImage ( driver ) ) != 0 ) { + DBGC ( driver, "EFIVETO could not unload %s: %s\n", + efi_handle_name ( driver ), strerror ( rc ) ); + } + } + + /* Free handle list */ + bs->FreePool ( drivers ); +} diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c index 2c5a5b31d..14f36661f 100644 --- a/src/interface/efi/efiprefix.c +++ b/src/interface/efi/efiprefix.c @@ -27,7 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include +#include /** * EFI entry point @@ -79,8 +79,8 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle, */ static int efi_probe ( struct root_device *rootdev __unused ) { - /* Unloaded any blacklisted drivers */ - efi_unload_blacklist(); + /* Unloaded any vetoed drivers */ + efi_veto_unload(); /* Connect our drivers */ return efi_driver_connect_all(); -- cgit v1.2.3-55-g7522 From e10a40d41fa082ddbd5ccca1d1cc415815759f02 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 20 Nov 2020 15:15:15 +0000 Subject: [efi] Avoid dropping below TPL as at entry to iPXE iPXE will currently drop to TPL_APPLICATION whenever the current system time is obtained via currticks(), since the system time mechanism relies on a timer that can fire only when the TPL is below TPL_CALLBACK. This can cause unexpected behaviour if the system time is obtained in the middle of an API call into iPXE by external code. For example, MnpDxe sets up a 10ms periodic timer running at TPL_CALLBACK to poll the underling EFI_SIMPLE_NETWORK_PROTOCOL device for received packets. If the resulting poll within iPXE happens to hit a code path that requires obtaining the current system time (e.g. due to reception of an STP packet, which affects iPXE's blocked link timer), then iPXE will end up temporarily dropping to TPL_APPLICATION. This can potentially result in retriggering the MnpDxe periodic timer, causing code to be unexpectedly re-entered. Fix by recording the external TPL at any entry point into iPXE and dropping only as far as this external TPL, rather than dropping unconditionally to TPL_APPLICATION. The side effect of this change is that iPXE's view of the current system time will be frozen for the duration of any API calls made into iPXE by external code at TPL_CALLBACK or above. Since any such external code is already responsible for allowing execution at TPL_APPLICATION to occur, then this should not cause a problem in practice. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi.h | 11 ++++++++ src/interface/efi/efi_driver.c | 15 +++++------ src/interface/efi/efi_entropy.c | 4 +-- src/interface/efi/efi_init.c | 34 +++++++++++++++++++++++ src/interface/efi/efi_snp.c | 58 +++++++++++++++++----------------------- src/interface/efi/efi_timer.c | 15 ++++++++--- src/interface/efi/efi_usb.c | 36 +++++++++++-------------- src/interface/efi/efidrvprefix.c | 8 +++--- 8 files changed, 110 insertions(+), 71 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index 62609b4b3..6d0c25674 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -68,6 +68,14 @@ typedef struct {} *EFI_HANDLE; #include #include +/** An EFI saved task priority level */ +struct efi_saved_tpl { + /** Current external TPL */ + EFI_TPL current; + /** Previous external TPL */ + EFI_TPL previous; +}; + /** An EFI protocol used by iPXE */ struct efi_protocol { /** GUID */ @@ -220,6 +228,7 @@ extern EFI_HANDLE efi_image_handle; extern EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image; extern EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path; extern EFI_SYSTEM_TABLE *efi_systab; +extern EFI_TPL efi_external_tpl; extern int efi_shutdown_in_progress; extern const __attribute__ (( pure )) char * @@ -314,5 +323,7 @@ efi_init_stack_guard ( EFI_HANDLE handle ) { extern EFI_STATUS efi_init ( EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab ); +extern void efi_raise_tpl ( struct efi_saved_tpl *tpl ); +extern void efi_restore_tpl ( struct efi_saved_tpl *tpl ); #endif /* _IPXE_EFI_H */ diff --git a/src/interface/efi/efi_driver.c b/src/interface/efi/efi_driver.c index 8388dd535..8e537d535 100644 --- a/src/interface/efi/efi_driver.c +++ b/src/interface/efi/efi_driver.c @@ -156,13 +156,13 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_driver *efidrv; struct efi_device *efidev; + struct efi_saved_tpl tpl; union { EFI_DEVICE_PATH_PROTOCOL *path; void *interface; } path; EFI_DEVICE_PATH_PROTOCOL *path_end; size_t path_len; - EFI_TPL saved_tpl; EFI_STATUS efirc; int rc; @@ -181,7 +181,7 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, } /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Do nothing if we are currently disconnecting drivers */ if ( efi_driver_disconnecting ) { @@ -236,7 +236,7 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, DBGC ( device, "EFIDRV %s using driver \"%s\"\n", efi_handle_name ( device ), efidev->driver->name ); - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); return 0; } DBGC ( device, "EFIDRV %s could not start driver \"%s\": %s\n", @@ -254,7 +254,7 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, } err_open_path: err_disconnecting: - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); err_already_started: return efirc; } @@ -273,10 +273,9 @@ static EFI_STATUS EFIAPI efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, EFI_HANDLE device, UINTN num_children, EFI_HANDLE *children ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_driver *efidrv; struct efi_device *efidev; - EFI_TPL saved_tpl; + struct efi_saved_tpl tpl; UINTN i; DBGC ( device, "EFIDRV %s DRIVER_STOP", efi_handle_name ( device ) ); @@ -295,7 +294,7 @@ efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, } /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Stop this device */ efidrv = efidev->driver; @@ -304,7 +303,7 @@ efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused, list_del ( &efidev->dev.siblings ); free ( efidev ); - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); return 0; } diff --git a/src/interface/efi/efi_entropy.c b/src/interface/efi/efi_entropy.c index dca0b6f1d..70cd06293 100644 --- a/src/interface/efi/efi_entropy.c +++ b/src/interface/efi/efi_entropy.c @@ -79,8 +79,8 @@ static int efi_entropy_enable ( void ) { DBGC ( &tick, "ENTROPY %s RNG protocol\n", ( efirng ? "has" : "has no" ) ); - /* Drop to TPL_APPLICATION to allow timer tick event to take place */ - bs->RestoreTPL ( TPL_APPLICATION ); + /* Drop to external TPL to allow timer tick event to take place */ + bs->RestoreTPL ( efi_external_tpl ); /* Create timer tick event */ if ( ( efirc = bs->CreateEvent ( EVT_TIMER, TPL_NOTIFY, NULL, NULL, diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c index 6d46c5669..b7cac16e5 100644 --- a/src/interface/efi/efi_init.c +++ b/src/interface/efi/efi_init.c @@ -47,6 +47,9 @@ EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path; */ EFI_SYSTEM_TABLE * _C2 ( PLATFORM, _systab ); +/** External task priority level */ +EFI_TPL efi_external_tpl = TPL_APPLICATION; + /** EFI shutdown is in progress */ int efi_shutdown_in_progress; @@ -361,3 +364,34 @@ __attribute__ (( noreturn )) void __stack_chk_fail ( void ) { while ( 1 ) {} } + +/** + * Raise task priority level to TPL_CALLBACK + * + * @v tpl Saved TPL + */ +void efi_raise_tpl ( struct efi_saved_tpl *tpl ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + /* Record current external TPL */ + tpl->previous = efi_external_tpl; + + /* Raise TPL and record previous TPL as new external TPL */ + tpl->current = bs->RaiseTPL ( TPL_CALLBACK ); + efi_external_tpl = tpl->current; +} + +/** + * Restore task priority level + * + * @v tpl Saved TPL + */ +void efi_restore_tpl ( struct efi_saved_tpl *tpl ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + /* Restore external TPL */ + efi_external_tpl = tpl->previous; + + /* Restore TPL */ + bs->RestoreTPL ( tpl->current ); +} diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index 5285d322b..c1ce90427 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -48,7 +48,7 @@ static LIST_HEAD ( efi_snp_devices ); static int efi_snp_claimed; /** TPL prior to network devices being claimed */ -static EFI_TPL efi_snp_old_tpl; +static struct efi_saved_tpl efi_snp_saved_tpl; /* Downgrade user experience if configured to do so * @@ -235,10 +235,9 @@ efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { static EFI_STATUS EFIAPI efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev = container_of ( snp, struct efi_snp_device, snp ); - EFI_TPL saved_tpl; + struct efi_saved_tpl tpl; int rc; DBGC ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n", @@ -252,7 +251,7 @@ efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, } /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Open network device */ if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) { @@ -263,7 +262,7 @@ efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, efi_snp_set_state ( snpdev ); err_open: - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); err_claimed: return EFIRC ( rc ); } @@ -277,10 +276,9 @@ efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, */ static EFI_STATUS EFIAPI efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev = container_of ( snp, struct efi_snp_device, snp ); - EFI_TPL saved_tpl; + struct efi_saved_tpl tpl; int rc; DBGC ( snpdev, "SNPDEV %p RESET (%s extended verification)\n", @@ -293,7 +291,7 @@ efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) { } /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Close network device */ netdev_close ( snpdev->netdev ); @@ -309,7 +307,7 @@ efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) { efi_snp_set_state ( snpdev ); err_open: - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); err_claimed: return EFIRC ( rc ); } @@ -322,10 +320,9 @@ efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) { */ static EFI_STATUS EFIAPI efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev = container_of ( snp, struct efi_snp_device, snp ); - EFI_TPL saved_tpl; + struct efi_saved_tpl tpl; DBGC ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev ); @@ -334,7 +331,7 @@ efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { return EFI_NOT_READY; /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Close network device */ netdev_close ( snpdev->netdev ); @@ -342,7 +339,7 @@ efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) { efi_snp_flush ( snpdev ); /* Restore TPL */ - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); return 0; } @@ -546,10 +543,9 @@ efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read, static EFI_STATUS EFIAPI efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 *interrupts, VOID **txbuf ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev = container_of ( snp, struct efi_snp_device, snp ); - EFI_TPL saved_tpl; + struct efi_saved_tpl tpl; DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev ); @@ -560,7 +556,7 @@ efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, } /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Poll the network device */ efi_snp_poll ( snpdev ); @@ -585,7 +581,7 @@ efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, } /* Restore TPL */ - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); DBGC2 ( snpdev, "\n" ); return 0; @@ -608,14 +604,13 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINTN ll_header_len, UINTN len, VOID *data, EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest, UINT16 *net_proto ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev = container_of ( snp, struct efi_snp_device, snp ); struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; + struct efi_saved_tpl tpl; struct io_buffer *iobuf; size_t payload_len; unsigned int tx_fill; - EFI_TPL saved_tpl; int rc; DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data, @@ -642,7 +637,7 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, } /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Sanity checks */ if ( ll_header_len ) { @@ -727,7 +722,7 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, snpdev->interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; /* Restore TPL */ - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); return 0; @@ -737,7 +732,7 @@ efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, free_iob ( iobuf ); err_alloc_iob: err_sanity: - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); err_claimed: return EFIRC ( rc ); } @@ -759,17 +754,16 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINTN *ll_header_len, UINTN *len, VOID *data, EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest, UINT16 *net_proto ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev = container_of ( snp, struct efi_snp_device, snp ); struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol; + struct efi_saved_tpl tpl; struct io_buffer *iobuf; const void *iob_ll_dest; const void *iob_ll_src; uint16_t iob_net_proto; unsigned int iob_flags; size_t copy_len; - EFI_TPL saved_tpl; int rc; DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data, @@ -782,7 +776,7 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, } /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Poll the network device */ efi_snp_poll ( snpdev ); @@ -831,7 +825,7 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, out_bad_ll_header: free_iob ( iobuf ); out_no_packet: - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); err_claimed: return EFIRC ( rc ); } @@ -844,9 +838,8 @@ efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, */ static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event __unused, VOID *context ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev = context; - EFI_TPL saved_tpl; + struct efi_saved_tpl tpl; DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev ); @@ -859,13 +852,13 @@ static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event __unused, return; /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Poll the network device */ efi_snp_poll ( snpdev ); /* Restore TPL */ - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); } /** SNP interface */ @@ -1967,12 +1960,11 @@ struct efi_snp_device * last_opened_snpdev ( void ) { * @v delta Claim count change */ void efi_snp_add_claim ( int delta ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev; /* Raise TPL if we are about to claim devices */ if ( ! efi_snp_claimed ) - efi_snp_old_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &efi_snp_saved_tpl ); /* Claim SNP devices */ efi_snp_claimed += delta; @@ -1984,5 +1976,5 @@ void efi_snp_add_claim ( int delta ) { /* Restore TPL if we have released devices */ if ( ! efi_snp_claimed ) - bs->RestoreTPL ( efi_snp_old_tpl ); + efi_restore_tpl ( &efi_snp_saved_tpl ); } diff --git a/src/interface/efi/efi_timer.c b/src/interface/efi/efi_timer.c index 8f40cb81a..405cd3454 100644 --- a/src/interface/efi/efi_timer.c +++ b/src/interface/efi/efi_timer.c @@ -97,8 +97,17 @@ static unsigned long efi_currticks ( void ) { * gain us any substantive benefits (since even with such * calls we would still be suffering from the limitations of a * polling design), we instead choose to run at TPL_CALLBACK - * almost all of the time, dropping to TPL_APPLICATION to - * allow timer ticks to occur. + * almost all of the time, dropping to a lower TPL to allow + * timer ticks to occur. + * + * We record the external TPL at the point of entry into iPXE, + * and drop back only as far as this external TPL. This + * avoids the unexpected behaviour that may arise from having + * iPXE temporarily drop to TPL_APPLICATION in the middle of + * an entry point invoked at TPL_CALLBACK. The side effect is + * that iPXE's view of the system time is effectively frozen + * for the duration of any call made in to iPXE at + * TPL_CALLBACK or higher. * * * For added excitement, UEFI provides no clean way for device @@ -127,7 +136,7 @@ static unsigned long efi_currticks ( void ) { if ( efi_shutdown_in_progress ) { efi_jiffies++; } else { - bs->RestoreTPL ( TPL_APPLICATION ); + bs->RestoreTPL ( efi_external_tpl ); bs->RaiseTPL ( TPL_CALLBACK ); } diff --git a/src/interface/efi/efi_usb.c b/src/interface/efi/efi_usb.c index 55b5bc880..bcf156999 100644 --- a/src/interface/efi/efi_usb.c +++ b/src/interface/efi/efi_usb.c @@ -551,7 +551,6 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio, EFI_USB_DATA_DIRECTION direction, UINT32 timeout, VOID *data, UINTN len, UINT32 *status ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_usb_interface *usbintf = container_of ( usbio, struct efi_usb_interface, usbio ); struct efi_usb_device *usbdev = usbintf->usbdev; @@ -559,7 +558,7 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio, USB_REQUEST_TYPE ( packet->Request ) ); unsigned int value = le16_to_cpu ( packet->Value ); unsigned int index = le16_to_cpu ( packet->Index ); - EFI_TPL saved_tpl; + struct efi_saved_tpl tpl; int rc; DBGC2 ( usbdev, "USBDEV %s control %04x:%04x:%04x:%04x %s %dms " @@ -569,7 +568,7 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio, ( ( size_t ) len ) ); /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Clear status */ *status = 0; @@ -613,7 +612,7 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio, err_control: err_change_config: - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); return EFIRC ( rc ); } @@ -631,12 +630,11 @@ efi_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio, static EFI_STATUS EFIAPI efi_usb_bulk_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data, UINTN *len, UINTN timeout, UINT32 *status ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_usb_interface *usbintf = container_of ( usbio, struct efi_usb_interface, usbio ); struct efi_usb_device *usbdev = usbintf->usbdev; size_t actual = *len; - EFI_TPL saved_tpl; + struct efi_saved_tpl tpl; int rc; DBGC2 ( usbdev, "USBDEV %s bulk %s %p+%zx %dms\n", usbintf->name, @@ -644,7 +642,7 @@ efi_usb_bulk_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data, ( ( size_t ) *len ), ( ( unsigned int ) timeout ) ); /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Clear status */ *status = 0; @@ -659,7 +657,7 @@ efi_usb_bulk_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data, } err_transfer: - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); return EFIRC ( rc ); } @@ -678,12 +676,11 @@ static EFI_STATUS EFIAPI efi_usb_sync_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, VOID *data, UINTN *len, UINTN timeout, UINT32 *status ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_usb_interface *usbintf = container_of ( usbio, struct efi_usb_interface, usbio ); struct efi_usb_device *usbdev = usbintf->usbdev; size_t actual = *len; - EFI_TPL saved_tpl; + struct efi_saved_tpl tpl; int rc; DBGC2 ( usbdev, "USBDEV %s sync intr %s %p+%zx %dms\n", usbintf->name, @@ -691,7 +688,7 @@ efi_usb_sync_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, ( ( size_t ) *len ), ( ( unsigned int ) timeout ) ); /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Clear status */ *status = 0; @@ -706,7 +703,7 @@ efi_usb_sync_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, } err_transfer: - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); return EFIRC ( rc ); } @@ -727,11 +724,10 @@ efi_usb_async_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, BOOLEAN start, UINTN interval, UINTN len, EFI_ASYNC_USB_TRANSFER_CALLBACK callback, VOID *context ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_usb_interface *usbintf = container_of ( usbio, struct efi_usb_interface, usbio ); struct efi_usb_device *usbdev = usbintf->usbdev; - EFI_TPL saved_tpl; + struct efi_saved_tpl tpl; int rc; DBGC2 ( usbdev, "USBDEV %s async intr %s len %#zx int %d %p/%p\n", @@ -741,7 +737,7 @@ efi_usb_async_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, callback, context ); /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Start/stop transfer as applicable */ if ( start ) { @@ -763,7 +759,7 @@ efi_usb_async_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio, UINT8 endpoint, } err_start: - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); return EFIRC ( rc ); } @@ -959,9 +955,9 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language, container_of ( usbio, struct efi_usb_interface, usbio ); struct efi_usb_device *usbdev = usbintf->usbdev; struct usb_descriptor_header header; + struct efi_saved_tpl tpl; VOID *buffer; size_t len; - EFI_TPL saved_tpl; EFI_STATUS efirc; int rc; @@ -969,7 +965,7 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language, usbintf->name, language, index ); /* Raise TPL */ - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Read descriptor header */ if ( ( rc = usb_get_descriptor ( usbdev->func->usb, 0, @@ -1012,7 +1008,7 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language, memset ( ( buffer + len - sizeof ( header ) ), 0, sizeof ( **string ) ); /* Restore TPL */ - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); /* Return allocated string */ *string = buffer; @@ -1023,7 +1019,7 @@ efi_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio, UINT16 language, err_alloc: err_len: err_get_header: - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); return EFIRC ( rc ); } diff --git a/src/interface/efi/efidrvprefix.c b/src/interface/efi/efidrvprefix.c index ac7d94374..9ca54ff4f 100644 --- a/src/interface/efi/efidrvprefix.c +++ b/src/interface/efi/efidrvprefix.c @@ -34,8 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ EFI_STATUS EFIAPI _efidrv_start ( EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab ) { - EFI_BOOT_SERVICES *bs; - EFI_TPL saved_tpl; + static struct efi_saved_tpl tpl; /* avoid triggering stack protector */ EFI_STATUS efirc; /* Initialise stack cookie */ @@ -46,15 +45,14 @@ EFI_STATUS EFIAPI _efidrv_start ( EFI_HANDLE image_handle, return efirc; /* Raise TPL */ - bs = efi_systab->BootServices; - saved_tpl = bs->RaiseTPL ( TPL_CALLBACK ); + efi_raise_tpl ( &tpl ); /* Initialise iPXE environment */ initialise(); startup(); /* Restore TPL */ - bs->RestoreTPL ( saved_tpl ); + efi_restore_tpl ( &tpl ); return 0; } -- cgit v1.2.3-55-g7522 From cf12a41703a8b2292e5d2d7528c2733c37869681 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 25 Nov 2020 15:52:00 +0000 Subject: [dma] Modify DMA API to simplify calculation of medial addresses Redefine the value stored within a DMA mapping to be the offset between physical addresses and DMA addresses within the mapped region. Provide a dma() wrapper function to calculate the DMA address for any pointer within a mapped region, thereby simplifying the use cases when a device needs to be given addresses other than the region start address. On a platform using the "flat" DMA implementation the DMA offset for any mapped region is always zero, with the result that dma_map() can be optimised away completely and dma() reduces to a straightforward call to virt_to_phys(). Signed-off-by: Michael Brown --- src/core/dma.c | 2 ++ src/drivers/net/intel.c | 10 ++---- src/drivers/net/intelxl.c | 33 ++++++-------------- src/drivers/net/intelxlvf.c | 6 ++-- src/drivers/net/realtek.c | 27 +++++++++-------- src/include/ipxe/dma.h | 74 +++++++++++++++++++++++++++++++++++++++------ src/interface/efi/efi_pci.c | 6 ++-- 7 files changed, 100 insertions(+), 58 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/core/dma.c b/src/core/dma.c index 9fc0c5453..3bf6957b9 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -46,6 +46,7 @@ PROVIDE_DMAAPI_INLINE ( flat, dma_unmap ); PROVIDE_DMAAPI_INLINE ( flat, dma_alloc ); PROVIDE_DMAAPI_INLINE ( flat, dma_free ); PROVIDE_DMAAPI_INLINE ( flat, dma_set_mask ); +PROVIDE_DMAAPI_INLINE ( flat, dma_phys ); /****************************************************************************** * @@ -138,6 +139,7 @@ PROVIDE_DMAAPI ( op, dma_unmap, dma_op_unmap ); PROVIDE_DMAAPI ( op, dma_alloc, dma_op_alloc ); PROVIDE_DMAAPI ( op, dma_free, dma_op_free ); PROVIDE_DMAAPI ( op, dma_set_mask, dma_op_set_mask ); +PROVIDE_DMAAPI_INLINE ( op, dma_phys ); /****************************************************************************** * diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 408101bad..5c6dc2143 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -513,7 +513,7 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { memset ( ring->desc, 0, ring->len ); /* Program ring address */ - address = ring->map.addr; + address = dma ( &ring->map, ring->desc ); writel ( ( address & 0xffffffffUL ), ( intel->regs + ring->reg + INTEL_xDBAL ) ); if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { @@ -571,7 +571,6 @@ void intel_refill_rx ( struct intel_nic *intel ) { struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; - physaddr_t address; unsigned int refilled = 0; /* Refill ring */ @@ -596,8 +595,7 @@ void intel_refill_rx ( struct intel_nic *intel ) { intel->rx.ring.prod++; /* Populate receive descriptor */ - address = map->addr; - intel->rx.ring.describe ( rx, address, 0 ); + intel->rx.ring.describe ( rx, dma ( map, iobuf->data ), 0 ); DBGC2 ( intel, "INTEL %p RX %d is [%lx,%lx)\n", intel, rx_idx, virt_to_phys ( iobuf->data ), @@ -762,7 +760,6 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; - physaddr_t address; size_t len; int rc; @@ -783,9 +780,8 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { intel->tx.ring.prod++; /* Populate transmit descriptor */ - address = map->addr; len = iob_len ( iobuf ); - intel->tx.ring.describe ( tx, address, len ); + intel->tx.ring.describe ( tx, dma ( map, iobuf->data ), len ); wmb(); /* Notify card that there are packets ready to transmit */ diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 14a5858f3..0808c784a 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -152,7 +152,8 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl, } /* Configure interrupt zero to write to dummy location */ - pci_msix_map ( &intelxl->msix.cap, 0, intelxl->msix.map.addr, 0 ); + pci_msix_map ( &intelxl->msix.cap, 0, + dma ( &intelxl->msix.map, &intelxl->msix.msg ), 0 ); /* Enable dummy interrupt zero */ pci_msix_unmask ( &intelxl->msix.cap, 0 ); @@ -230,22 +231,6 @@ static int intelxl_alloc_admin ( struct intelxl_nic *intelxl, return 0; } -/** - * Get DMA address for admin descriptor or buffer entry - * - * @v admin Admin queue - * @v addr Virtual address - * @ret addr DMA address - */ -static physaddr_t intelxl_admin_address ( struct intelxl_admin *admin, - void *addr ) { - size_t offset; - - /* Calculate offset within mapped area */ - offset = ( addr - ( ( void * ) admin->buf ) ); - return ( admin->map.addr + offset ); -} - /** * Enable admin queue * @@ -270,7 +255,7 @@ static void intelxl_enable_admin ( struct intelxl_nic *intelxl, admin->index = 0; /* Program queue address */ - address = intelxl_admin_address ( admin, admin->desc ); + address = dma ( &admin->map, admin->desc ); writel ( ( address & 0xffffffffUL ), admin_regs + regs->bal ); if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { writel ( ( ( ( uint64_t ) address ) >> 32 ), @@ -365,7 +350,7 @@ static void intelxl_admin_event_init ( struct intelxl_nic *intelxl, /* Initialise descriptor */ evt = &admin->desc[ index % INTELXL_ADMIN_NUM_DESC ]; buf = &admin->buf[ index % INTELXL_ADMIN_NUM_DESC ]; - address = intelxl_admin_address ( admin, buf ); + address = dma ( &admin->map, buf ); evt->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ); evt->len = cpu_to_le16 ( sizeof ( *buf ) ); evt->params.buffer.high = cpu_to_le32 ( address >> 32 ); @@ -410,7 +395,7 @@ int intelxl_admin_command ( struct intelxl_nic *intelxl ) { /* Populate data buffer address if applicable */ if ( cmd->flags & cpu_to_le16 ( INTELXL_ADMIN_FL_BUF ) ) { - address = intelxl_admin_address ( admin, buf ); + address = dma ( &admin->map, buf ); cmd->params.buffer.high = cpu_to_le32 ( address >> 32 ); cmd->params.buffer.low = cpu_to_le32 ( address & 0xffffffffUL ); } @@ -1267,6 +1252,7 @@ static int intelxl_disable_ring ( struct intelxl_nic *intelxl, */ static int intelxl_create_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ) { + physaddr_t address; int rc; /* Allocate descriptor ring */ @@ -1274,7 +1260,8 @@ static int intelxl_create_ring ( struct intelxl_nic *intelxl, goto err_alloc; /* Program queue context */ - if ( ( rc = ring->context ( intelxl, ring->map.addr ) ) != 0 ) + address = dma ( &ring->map, ring->desc.raw ); + if ( ( rc = ring->context ( intelxl, address ) ) != 0 ) goto err_context; /* Enable ring */ @@ -1346,7 +1333,7 @@ static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { intelxl->rx.ring.prod++; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( map->addr ); + rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); rx->flags = 0; DBGC2 ( intelxl, "INTELXL %p RX %d is [%08lx,%08lx)\n", @@ -1537,7 +1524,7 @@ int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { /* Populate transmit descriptor */ len = iob_len ( iobuf ); - tx->address = cpu_to_le64 ( map->addr ); + tx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); tx->len = cpu_to_le32 ( INTELXL_TX_DATA_LEN ( len ) ); tx->flags = cpu_to_le32 ( INTELXL_TX_DATA_DTYP | INTELXL_TX_DATA_EOP | INTELXL_TX_DATA_RS | INTELXL_TX_DATA_JFDI ); diff --git a/src/drivers/net/intelxlvf.c b/src/drivers/net/intelxlvf.c index 61ac5e5c0..f944b4daa 100644 --- a/src/drivers/net/intelxlvf.c +++ b/src/drivers/net/intelxlvf.c @@ -380,12 +380,14 @@ static int intelxlvf_admin_configure ( struct net_device *netdev ) { buf->cfg.count = cpu_to_le16 ( 1 ); buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC ); - buf->cfg.tx.base = cpu_to_le64 ( intelxl->tx.ring.map.addr ); + buf->cfg.tx.base = cpu_to_le64 ( dma ( &intelxl->tx.ring.map, + intelxl->tx.ring.desc.raw ) ); buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC ); buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs ); buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs ); - buf->cfg.rx.base = cpu_to_le64 ( intelxl->rx.ring.map.addr ); + buf->cfg.rx.base = cpu_to_le64 ( dma ( &intelxl->rx.ring.map, + intelxl->rx.ring.desc.raw ) ); /* Issue command */ if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 ) diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index 0f3038d36..bca52266f 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -506,6 +506,7 @@ static void realtek_check_link ( struct net_device *netdev ) { * @ret rc Return status code */ static int realtek_create_buffer ( struct realtek_nic *rtl ) { + struct realtek_rx_buffer *rxbuf = &rtl->rxbuf; size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD ); /* Do nothing unless in legacy mode */ @@ -513,17 +514,16 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { return 0; /* Allocate buffer */ - rtl->rxbuf.data = dma_alloc ( rtl->dma, len, RTL_RXBUF_ALIGN, - &rtl->rxbuf.map ); - if ( ! rtl->rxbuf.data ) + rxbuf->data = dma_alloc ( rtl->dma, len, RTL_RXBUF_ALIGN, &rxbuf->map ); + if ( ! rxbuf->data ) return -ENOMEM; /* Program buffer address */ - writel ( rtl->rxbuf.map.addr, rtl->regs + RTL_RBSTART ); + writel ( dma ( &rxbuf->map, rxbuf->data ), rtl->regs + RTL_RBSTART ); DBGC ( rtl, "REALTEK %p receive buffer is at [%08lx,%08lx,%08lx)\n", - rtl, virt_to_phys ( rtl->rxbuf.data ), - ( virt_to_phys ( rtl->rxbuf.data ) + RTL_RXBUF_LEN ), - ( virt_to_phys ( rtl->rxbuf.data ) + len ) ); + rtl, virt_to_phys ( rxbuf->data ), + ( virt_to_phys ( rxbuf->data ) + RTL_RXBUF_LEN ), + ( virt_to_phys ( rxbuf->data ) + len ) ); return 0; } @@ -534,6 +534,7 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { * @v rtl Realtek device */ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { + struct realtek_rx_buffer *rxbuf = &rtl->rxbuf; size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD ); /* Do nothing unless in legacy mode */ @@ -544,9 +545,9 @@ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { writel ( 0, rtl->regs + RTL_RBSTART ); /* Free buffer */ - dma_free ( rtl->dma, rtl->rxbuf.data, len, &rtl->rxbuf.map ); - rtl->rxbuf.data = NULL; - rtl->rxbuf.offset = 0; + dma_free ( rtl->dma, rxbuf->data, len, &rxbuf->map ); + rxbuf->data = NULL; + rxbuf->offset = 0; } /** @@ -574,7 +575,7 @@ static int realtek_create_ring ( struct realtek_nic *rtl, memset ( ring->desc, 0, ring->len ); /* Program ring address */ - address = ring->map.addr; + address = dma ( &ring->map, ring->desc ); writel ( ( ( ( uint64_t ) address ) >> 32 ), rtl->regs + ring->reg + 4 ); writel ( ( address & 0xffffffffUL ), rtl->regs + ring->reg ); @@ -648,7 +649,7 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { rtl->rx.ring.prod++; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( map->addr ); + rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); rx->length = cpu_to_le16 ( RTL_RX_MAX_LEN ); wmb(); rx->flags = ( cpu_to_le16 ( RTL_DESC_OWN ) | @@ -797,7 +798,7 @@ static int realtek_transmit ( struct net_device *netdev, /* Map I/O buffer */ if ( ( rc = dma_map_tx_iob ( rtl->dma, iobuf, map ) ) != 0 ) return rc; - address = map->addr; + address = dma ( map, iobuf->data ); /* Update producer index */ rtl->tx.ring.prod++; diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index 878e03f11..0577493c7 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -30,8 +30,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** A DMA mapping */ struct dma_mapping { - /** Device-side address */ - physaddr_t addr; + /** Address offset + * + * This is the value that must be added to a physical address + * within the mapping in order to produce the corresponding + * device-side DMA address. + */ + physaddr_t offset; /** Platform mapping token */ void *token; }; @@ -148,12 +153,10 @@ struct dma_operations { * @ret rc Return status code */ static inline __always_inline int -DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, physaddr_t addr, +DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, + physaddr_t addr __unused, size_t len __unused, int flags __unused, - struct dma_mapping *map ) { - - /* Use physical address as device address */ - map->addr = addr; + struct dma_mapping *map __unused ) { /* Increment mapping count (for debugging) */ if ( DBG_LOG ) @@ -187,13 +190,13 @@ DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_device *dma, * @ret addr Buffer address, or NULL on error */ static inline __always_inline void * -DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, size_t len, - size_t align, struct dma_mapping *map ) { +DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, + size_t len, size_t align, + struct dma_mapping *map __unused ) { void *addr; /* Allocate buffer */ addr = malloc_phys ( len, align ); - map->addr = virt_to_phys ( addr ); /* Increment allocation count (for debugging) */ if ( DBG_LOG && addr ) @@ -236,6 +239,35 @@ DMAAPI_INLINE ( flat, dma_set_mask ) ( struct dma_device *dma __unused, /* Nothing to do */ } +/** + * Get DMA address from physical address + * + * @v map DMA mapping + * @v addr Physical address within the mapped region + * @ret addr Device-side DMA address + */ +static inline __always_inline physaddr_t +DMAAPI_INLINE ( flat, dma_phys ) ( struct dma_mapping *map __unused, + physaddr_t addr ) { + + /* Use physical address as device address */ + return addr; +} + +/** + * Get DMA address from physical address + * + * @v map DMA mapping + * @v addr Physical address within the mapped region + * @ret addr Device-side DMA address + */ +static inline __always_inline physaddr_t +DMAAPI_INLINE ( op, dma_phys ) ( struct dma_mapping *map, physaddr_t addr ) { + + /* Adjust physical address using mapping offset */ + return ( addr + map->offset ); +} + /** * Map buffer for DMA * @@ -288,6 +320,28 @@ void dma_free ( struct dma_device *dma, void *addr, size_t len, */ void dma_set_mask ( struct dma_device *dma, physaddr_t mask ); +/** + * Get DMA address from physical address + * + * @v map DMA mapping + * @v addr Physical address within the mapped region + * @ret addr Device-side DMA address + */ +physaddr_t dma_phys ( struct dma_mapping *map, physaddr_t addr ); + +/** + * Get DMA address from virtual address + * + * @v map DMA mapping + * @v addr Virtual address within the mapped region + * @ret addr Device-side DMA address + */ +static inline __always_inline physaddr_t dma ( struct dma_mapping *map, + void *addr ) { + + return dma_phys ( map, virt_to_phys ( addr ) ); +} + /** * Initialise DMA device * diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 6c6ac5c77..e33a8980d 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -335,7 +335,7 @@ static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, int rc; /* Sanity check */ - assert ( map->addr == 0 ); + assert ( map->offset == 0 ); assert ( map->token == NULL ); /* Determine operation */ @@ -374,7 +374,7 @@ static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, } /* Populate mapping */ - map->addr = bus; + map->offset = ( bus - addr ); map->token = mapping; /* Increment mapping count (for debugging) */ @@ -408,7 +408,7 @@ static void efipci_dma_unmap ( struct dma_device *dma, pci_io->Unmap ( pci_io, map->token ); /* Clear mapping */ - map->addr = 0; + map->offset = 0; map->token = NULL; /* Decrement mapping count (for debugging) */ -- cgit v1.2.3-55-g7522 From 70e6e83243b77a3771756106871d6f945062a44b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 27 Nov 2020 11:27:22 +0000 Subject: [dma] Record DMA device as part of DMA mapping if needed Allow for dma_unmap() to be called by code other than the DMA device driver itself. Signed-off-by: Michael Brown --- src/core/dma.c | 52 +++++++++---------- src/drivers/net/intel.c | 18 +++---- src/drivers/net/intelxl.c | 40 +++++++-------- src/drivers/net/realtek.c | 23 +++++---- src/include/ipxe/dma.h | 121 +++++++++++++++++++++++++------------------- src/interface/efi/efi_pci.c | 25 ++++----- 6 files changed, 150 insertions(+), 129 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/core/dma.c b/src/core/dma.c index 3bf6957b9..561aec1e1 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -59,66 +59,65 @@ PROVIDE_DMAAPI_INLINE ( flat, dma_phys ); * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ -static int dma_op_map ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ) { +static int dma_op_map ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ) { struct dma_operations *op = dma->op; if ( ! op ) return -ENODEV; - return op->map ( dma, addr, len, flags, map ); + return op->map ( dma, map, addr, len, flags ); } /** * Unmap buffer * - * @v dma DMA device * @v map DMA mapping */ -static void dma_op_unmap ( struct dma_device *dma, struct dma_mapping *map ) { - struct dma_operations *op = dma->op; +static void dma_op_unmap ( struct dma_mapping *map ) { + struct dma_device *dma = map->dma; - assert ( op != NULL ); - op->unmap ( dma, map ); + assert ( dma != NULL ); + assert ( dma->op != NULL ); + dma->op->unmap ( dma, map ); } /** * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ -static void * dma_op_alloc ( struct dma_device *dma, size_t len, size_t align, - struct dma_mapping *map ) { +static void * dma_op_alloc ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ) { struct dma_operations *op = dma->op; if ( ! op ) return NULL; - return op->alloc ( dma, len, align, map ); + return op->alloc ( dma, map, len, align ); } /** * Unmap and free DMA-coherent buffer * - * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ -static void dma_op_free ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ) { - struct dma_operations *op = dma->op; +static void dma_op_free ( struct dma_mapping *map, void *addr, size_t len ) { + struct dma_device *dma = map->dma; - assert ( op != NULL ); - op->free ( dma, addr, len, map ); + assert ( dma != NULL ); + assert ( dma->op != NULL ); + dma->op->free ( dma, map, addr, len ); } /** @@ -152,12 +151,13 @@ PROVIDE_DMAAPI_INLINE ( op, dma_phys ); * Allocate and map I/O buffer for receiving data from device * * @v dma DMA device - * @v len Length of I/O buffer * @v map DMA mapping to fill in + * @v len Length of I/O buffer * @ret iobuf I/O buffer, or NULL on error */ -struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, - struct dma_mapping *map ) { +struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, + struct dma_mapping *map, + size_t len ) { struct io_buffer *iobuf; int rc; @@ -167,13 +167,13 @@ struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, goto err_alloc; /* Map I/O buffer */ - if ( ( rc = dma_map ( dma, virt_to_phys ( iobuf->data ), len, - DMA_RX, map ) ) != 0 ) + if ( ( rc = dma_map ( dma, map, virt_to_phys ( iobuf->data ), + len, DMA_RX ) ) != 0 ) goto err_map; return iobuf; - dma_unmap ( dma, map ); + dma_unmap ( map ); err_map: free_iob ( iobuf ); err_alloc: diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 5c6dc2143..93c5fd1f6 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -504,8 +504,8 @@ int intel_create_ring ( struct intel_nic *intel, struct intel_ring *ring ) { * prevent any possible page-crossing errors due to hardware * errata. */ - ring->desc = dma_alloc ( intel->dma, ring->len, ring->len, - &ring->map ); + ring->desc = dma_alloc ( intel->dma, &ring->map, ring->len, + ring->len ); if ( ! ring->desc ) return -ENOMEM; @@ -554,7 +554,7 @@ void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { intel_reset_ring ( intel, ring->reg ); /* Free descriptor ring */ - dma_free ( intel->dma, ring->desc, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc, ring->len ); ring->desc = NULL; ring->prod = 0; ring->cons = 0; @@ -584,7 +584,7 @@ void intel_refill_rx ( struct intel_nic *intel ) { assert ( intel->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intel->dma, INTEL_RX_MAX_LEN, map ); + iobuf = dma_alloc_rx_iob ( intel->dma, map, INTEL_RX_MAX_LEN ); if ( ! iobuf ) { /* Wait for next refill */ break; @@ -630,7 +630,7 @@ void intel_flush ( struct intel_nic *intel ) { /* Discard unused receive buffers */ for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) { if ( intel->rx.iobuf[i] ) { - dma_unmap ( intel->dma, &intel->rx.map[i] ); + dma_unmap ( &intel->rx.map[i] ); free_iob ( intel->rx.iobuf[i] ); } intel->rx.iobuf[i] = NULL; @@ -639,7 +639,7 @@ void intel_flush ( struct intel_nic *intel ) { /* Unmap incomplete transmit buffers */ for ( i = intel->tx.ring.cons ; i != intel->tx.ring.prod ; i++ ) { tx_idx = ( i % INTEL_NUM_TX_DESC ); - dma_unmap ( intel->dma, &intel->tx.map[tx_idx] ); + dma_unmap ( &intel->tx.map[tx_idx] ); } } @@ -773,7 +773,7 @@ int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { map = &intel->tx.map[tx_idx]; /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intel->dma, iobuf, map ) ) != 0 ) + if ( ( rc = dma_map_tx_iob ( intel->dma, map, iobuf ) ) != 0 ) return rc; /* Update producer index */ @@ -822,7 +822,7 @@ void intel_poll_tx ( struct net_device *netdev ) { DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx ); /* Unmap I/O buffer */ - dma_unmap ( intel->dma, &intel->tx.map[tx_idx] ); + dma_unmap ( &intel->tx.map[tx_idx] ); /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); @@ -854,7 +854,7 @@ void intel_poll_rx ( struct net_device *netdev ) { return; /* Unmap I/O buffer */ - dma_unmap ( intel->dma, &intel->rx.map[rx_idx] ); + dma_unmap ( &intel->rx.map[rx_idx] ); /* Populate I/O buffer */ iobuf = intel->rx.iobuf[rx_idx]; diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 0808c784a..5de432a6a 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -136,9 +136,9 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl, int rc; /* Map dummy target location */ - if ( ( rc = dma_map ( intelxl->dma, virt_to_phys ( &intelxl->msix.msg ), - sizeof ( intelxl->msix.msg ), DMA_RX, - &intelxl->msix.map ) ) != 0 ) { + if ( ( rc = dma_map ( intelxl->dma, &intelxl->msix.map, + virt_to_phys ( &intelxl->msix.msg ), + sizeof ( intelxl->msix.msg ), DMA_RX ) ) != 0 ) { DBGC ( intelxl, "INTELXL %p could not map MSI-X target: %s\n", intelxl, strerror ( rc ) ); goto err_map; @@ -162,7 +162,7 @@ int intelxl_msix_enable ( struct intelxl_nic *intelxl, pci_msix_disable ( pci, &intelxl->msix.cap ); err_enable: - dma_unmap ( intelxl->dma, &intelxl->msix.map ); + dma_unmap ( &intelxl->msix.map ); err_map: return rc; } @@ -183,7 +183,7 @@ void intelxl_msix_disable ( struct intelxl_nic *intelxl, pci_msix_disable ( pci, &intelxl->msix.cap ); /* Unmap dummy target location */ - dma_unmap ( intelxl->dma, &intelxl->msix.map ); + dma_unmap ( &intelxl->msix.map ); } /****************************************************************************** @@ -215,8 +215,8 @@ static int intelxl_alloc_admin ( struct intelxl_nic *intelxl, size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Allocate admin queue */ - admin->buf = dma_alloc ( intelxl->dma, ( buf_len + len ), - INTELXL_ALIGN, &admin->map ); + admin->buf = dma_alloc ( intelxl->dma, &admin->map, ( buf_len + len ), + INTELXL_ALIGN ); if ( ! admin->buf ) return -ENOMEM; admin->desc = ( ( ( void * ) admin->buf ) + buf_len ); @@ -291,13 +291,13 @@ static void intelxl_disable_admin ( struct intelxl_nic *intelxl, * @v intelxl Intel device * @v admin Admin queue */ -static void intelxl_free_admin ( struct intelxl_nic *intelxl, +static void intelxl_free_admin ( struct intelxl_nic *intelxl __unused, struct intelxl_admin *admin ) { size_t buf_len = ( sizeof ( admin->buf[0] ) * INTELXL_ADMIN_NUM_DESC ); size_t len = ( sizeof ( admin->desc[0] ) * INTELXL_ADMIN_NUM_DESC ); /* Free queue */ - dma_free ( intelxl->dma, admin->buf, ( buf_len + len ), &admin->map ); + dma_free ( &admin->map, admin->buf, ( buf_len + len ) ); } /** @@ -945,8 +945,8 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, int rc; /* Allocate descriptor ring */ - ring->desc.raw = dma_alloc ( intelxl->dma, ring->len, INTELXL_ALIGN, - &ring->map ); + ring->desc.raw = dma_alloc ( intelxl->dma, &ring->map, ring->len, + INTELXL_ALIGN ); if ( ! ring->desc.raw ) { rc = -ENOMEM; goto err_alloc; @@ -969,7 +969,7 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, return 0; - dma_free ( intelxl->dma, ring->desc.raw, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc.raw, ring->len ); err_alloc: return rc; } @@ -980,11 +980,11 @@ int intelxl_alloc_ring ( struct intelxl_nic *intelxl, * @v intelxl Intel device * @v ring Descriptor ring */ -void intelxl_free_ring ( struct intelxl_nic *intelxl, +void intelxl_free_ring ( struct intelxl_nic *intelxl __unused, struct intelxl_ring *ring ) { /* Free descriptor ring */ - dma_free ( intelxl->dma, ring->desc.raw, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc.raw, ring->len ); ring->desc.raw = NULL; } @@ -1322,7 +1322,7 @@ static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { assert ( intelxl->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intelxl->dma, intelxl->mfs, map ); + iobuf = dma_alloc_rx_iob ( intelxl->dma, map, intelxl->mfs ); if ( ! iobuf ) { /* Wait for next refill */ break; @@ -1365,7 +1365,7 @@ void intelxl_flush ( struct intelxl_nic *intelxl ) { /* Discard any unused receive buffers */ for ( i = 0 ; i < INTELXL_RX_NUM_DESC ; i++ ) { if ( intelxl->rx.iobuf[i] ) { - dma_unmap ( intelxl->dma, &intelxl->rx.map[i] ); + dma_unmap ( &intelxl->rx.map[i] ); free_iob ( intelxl->rx.iobuf[i] ); } intelxl->rx.iobuf[i] = NULL; @@ -1374,7 +1374,7 @@ void intelxl_flush ( struct intelxl_nic *intelxl ) { /* Unmap incomplete transmit buffers */ for ( i = intelxl->tx.ring.cons ; i != intelxl->tx.ring.prod ; i++ ) { tx_idx = ( i % INTELXL_TX_NUM_DESC ); - dma_unmap ( intelxl->dma, &intelxl->tx.map[tx_idx] ); + dma_unmap ( &intelxl->tx.map[tx_idx] ); } } @@ -1516,7 +1516,7 @@ int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { map = &intelxl->tx.map[tx_idx]; /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intelxl->dma, iobuf, map ) ) != 0 ) + if ( ( rc = dma_map_tx_iob ( intelxl->dma, map, iobuf ) ) != 0 ) return rc; /* Update producer index */ @@ -1564,7 +1564,7 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { intelxl, tx_idx ); /* Unmap I/O buffer */ - dma_unmap ( intelxl->dma, &intelxl->tx.map[tx_idx] ); + dma_unmap ( &intelxl->tx.map[tx_idx] ); /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); @@ -1597,7 +1597,7 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { return; /* Unmap I/O buffer */ - dma_unmap ( intelxl->dma, &intelxl->rx.map[rx_idx] ); + dma_unmap ( &intelxl->rx.map[rx_idx] ); /* Populate I/O buffer */ iobuf = intelxl->rx.iobuf[rx_idx]; diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index bca52266f..47d435f72 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -514,7 +514,8 @@ static int realtek_create_buffer ( struct realtek_nic *rtl ) { return 0; /* Allocate buffer */ - rxbuf->data = dma_alloc ( rtl->dma, len, RTL_RXBUF_ALIGN, &rxbuf->map ); + rxbuf->data = dma_alloc ( rtl->dma, &rxbuf->map, len, + RTL_RXBUF_ALIGN ); if ( ! rxbuf->data ) return -ENOMEM; @@ -545,7 +546,7 @@ static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { writel ( 0, rtl->regs + RTL_RBSTART ); /* Free buffer */ - dma_free ( rtl->dma, rxbuf->data, len, &rxbuf->map ); + dma_free ( &rxbuf->map, rxbuf->data, len ); rxbuf->data = NULL; rxbuf->offset = 0; } @@ -566,8 +567,8 @@ static int realtek_create_ring ( struct realtek_nic *rtl, return 0; /* Allocate descriptor ring */ - ring->desc = dma_alloc ( rtl->dma, ring->len, RTL_RING_ALIGN, - &ring->map ); + ring->desc = dma_alloc ( rtl->dma, &ring->map, ring->len, + RTL_RING_ALIGN ); if ( ! ring->desc ) return -ENOMEM; @@ -608,7 +609,7 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, writel ( 0, rtl->regs + ring->reg + 4 ); /* Free descriptor ring */ - dma_free ( rtl->dma, ring->desc, ring->len, &ring->map ); + dma_free ( &ring->map, ring->desc, ring->len ); ring->desc = NULL; } @@ -638,7 +639,7 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { assert ( rtl->rx.iobuf[rx_idx] == NULL ); /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( rtl->dma, RTL_RX_MAX_LEN, map ); + iobuf = dma_alloc_rx_iob ( rtl->dma, map, RTL_RX_MAX_LEN ); if ( ! iobuf ) { /* Wait for next refill */ return; @@ -748,7 +749,7 @@ static void realtek_close ( struct net_device *netdev ) { /* Discard any unused receive buffers */ for ( i = 0 ; i < RTL_NUM_RX_DESC ; i++ ) { if ( rtl->rx.iobuf[i] ) { - dma_unmap ( rtl->dma, &rtl->rx.map[i] ); + dma_unmap ( &rtl->rx.map[i] ); free_iob ( rtl->rx.iobuf[i] ); } rtl->rx.iobuf[i] = NULL; @@ -756,7 +757,7 @@ static void realtek_close ( struct net_device *netdev ) { /* Unmap any incomplete transmit buffers */ for ( i = rtl->tx.ring.cons ; i != rtl->tx.ring.prod ; i++ ) - dma_unmap ( rtl->dma, &rtl->tx.map[ i % RTL_NUM_TX_DESC ] ); + dma_unmap ( &rtl->tx.map[ i % RTL_NUM_TX_DESC ] ); /* Destroy transmit descriptor ring */ realtek_destroy_ring ( rtl, &rtl->tx.ring ); @@ -796,7 +797,7 @@ static int realtek_transmit ( struct net_device *netdev, iob_pad ( iobuf, ETH_ZLEN ); /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( rtl->dma, iobuf, map ) ) != 0 ) + if ( ( rc = dma_map_tx_iob ( rtl->dma, map, iobuf ) ) != 0 ) return rc; address = dma ( map, iobuf->data ); @@ -870,7 +871,7 @@ static void realtek_poll_tx ( struct net_device *netdev ) { DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx ); /* Unmap I/O buffer */ - dma_unmap ( rtl->dma, &rtl->tx.map[tx_idx] ); + dma_unmap ( &rtl->tx.map[tx_idx] ); /* Complete TX descriptor */ rtl->tx.ring.cons++; @@ -964,7 +965,7 @@ static void realtek_poll_rx ( struct net_device *netdev ) { return; /* Unmap buffer */ - dma_unmap ( rtl->dma, &rtl->rx.map[rx_idx] ); + dma_unmap ( &rtl->rx.map[rx_idx] ); /* Populate I/O buffer */ iobuf = rtl->rx.iobuf[rx_idx]; diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index 0577493c7..842c9d6ef 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -37,6 +37,8 @@ struct dma_mapping { * device-side DMA address. */ physaddr_t offset; + /** DMA device (if unmapping is required) */ + struct dma_device *dma; /** Platform mapping token */ void *token; }; @@ -59,14 +61,14 @@ struct dma_operations { * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ - int ( * map ) ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ); + int ( * map ) ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ); /** * Unmap buffer * @@ -78,23 +80,23 @@ struct dma_operations { * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ - void * ( * alloc ) ( struct dma_device *dma, size_t len, size_t align, - struct dma_mapping *map ); + void * ( * alloc ) ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ); /** * Unmap and free DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ - void ( * free ) ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ); + void ( * free ) ( struct dma_device *dma, struct dma_mapping *map, + void *addr, size_t len ); /** * Set addressable space mask * @@ -146,21 +148,23 @@ struct dma_operations { * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ static inline __always_inline int DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, + struct dma_mapping *map, physaddr_t addr __unused, - size_t len __unused, int flags __unused, - struct dma_mapping *map __unused ) { + size_t len __unused, int flags __unused ) { /* Increment mapping count (for debugging) */ - if ( DBG_LOG ) + if ( DBG_LOG ) { + map->dma = dma; dma->mapped++; + } return 0; } @@ -168,39 +172,42 @@ DMAAPI_INLINE ( flat, dma_map ) ( struct dma_device *dma, /** * Unmap buffer * - * @v dma DMA device * @v map DMA mapping */ static inline __always_inline void -DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_device *dma, - struct dma_mapping *map __unused ) { +DMAAPI_INLINE ( flat, dma_unmap ) ( struct dma_mapping *map ) { /* Decrement mapping count (for debugging) */ - if ( DBG_LOG ) - dma->mapped--; + if ( DBG_LOG ) { + assert ( map->dma != NULL ); + map->dma->mapped--; + map->dma = NULL; + } } /** * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ static inline __always_inline void * DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, - size_t len, size_t align, - struct dma_mapping *map __unused ) { + struct dma_mapping *map, + size_t len, size_t align ) { void *addr; /* Allocate buffer */ addr = malloc_phys ( len, align ); - /* Increment allocation count (for debugging) */ - if ( DBG_LOG && addr ) - dma->allocated++; + /* Increment mapping count (for debugging) */ + if ( DBG_LOG && addr ) { + map->dma = dma; + dma->mapped++; + } return addr; } @@ -208,22 +215,23 @@ DMAAPI_INLINE ( flat, dma_alloc ) ( struct dma_device *dma, /** * Unmap and free DMA-coherent buffer * - * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ static inline __always_inline void -DMAAPI_INLINE ( flat, dma_free ) ( struct dma_device *dma, - void *addr, size_t len, - struct dma_mapping *map __unused ) { +DMAAPI_INLINE ( flat, dma_free ) ( struct dma_mapping *map, + void *addr, size_t len ) { /* Free buffer */ free_phys ( addr, len ); - /* Decrement allocation count (for debugging) */ - if ( DBG_LOG ) - dma->allocated--; + /* Decrement mapping count (for debugging) */ + if ( DBG_LOG ) { + assert ( map->dma != NULL ); + map->dma->mapped--; + map->dma = NULL; + } } /** @@ -272,45 +280,42 @@ DMAAPI_INLINE ( op, dma_phys ) ( struct dma_mapping *map, physaddr_t addr ) { * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ -int dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ); +int dma_map ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ); /** * Unmap buffer * - * @v dma DMA device * @v map DMA mapping */ -void dma_unmap ( struct dma_device *dma, struct dma_mapping *map ); +void dma_unmap ( struct dma_mapping *map ); /** * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ -void * dma_alloc ( struct dma_device *dma, size_t len, size_t align, - struct dma_mapping *map ); +void * dma_alloc ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ); /** * Unmap and free DMA-coherent buffer * - * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ -void dma_free ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ); +void dma_free ( struct dma_mapping *map, void *addr, size_t len ); /** * Set addressable space mask @@ -339,9 +344,22 @@ physaddr_t dma_phys ( struct dma_mapping *map, physaddr_t addr ); static inline __always_inline physaddr_t dma ( struct dma_mapping *map, void *addr ) { + /* Get DMA address from corresponding physical address */ return dma_phys ( map, virt_to_phys ( addr ) ); } +/** + * Check if DMA unmapping is required + * + * @v map DMA mapping + * @v unmap Unmapping is required + */ +static inline __always_inline int dma_mapped ( struct dma_mapping *map ) { + + /* Unmapping is required if a DMA device was recorded */ + return ( map->dma != NULL ); +} + /** * Initialise DMA device * @@ -371,20 +389,21 @@ dma_set_mask_64bit ( struct dma_device *dma ) { * Map I/O buffer for transmitting data to device * * @v dma DMA device - * @v iobuf I/O buffer * @v map DMA mapping to fill in + * @v iobuf I/O buffer * @ret rc Return status code */ static inline __always_inline int -dma_map_tx_iob ( struct dma_device *dma, struct io_buffer *iobuf, - struct dma_mapping *map ) { +dma_map_tx_iob ( struct dma_device *dma, struct dma_mapping *map, + struct io_buffer *iobuf ) { /* Map I/O buffer */ - return dma_map ( dma, virt_to_phys ( iobuf->data ), iob_len ( iobuf ), - DMA_TX, map ); + return dma_map ( dma, map, virt_to_phys ( iobuf->data ), + iob_len ( iobuf ), DMA_TX ); } -extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, size_t len, - struct dma_mapping *map ); +extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, + struct dma_mapping *map, + size_t len ); #endif /* _IPXE_DMA_H */ diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index e33a8980d..7687ffb43 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -315,14 +315,14 @@ PROVIDE_PCIAPI ( efi, pci_ioremap, efipci_ioremap ); * Map buffer for DMA * * @v dma DMA device + * @v map DMA mapping to fill in * @v addr Buffer address * @v len Length of buffer * @v flags Mapping flags - * @v map DMA mapping to fill in * @ret rc Return status code */ -static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, - int flags, struct dma_mapping *map ) { +static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map, + physaddr_t addr, size_t len, int flags ) { struct efi_pci_device *efipci = container_of ( dma, struct efi_pci_device, pci.dma ); struct pci_device *pci = &efipci->pci; @@ -374,6 +374,7 @@ static int efipci_dma_map ( struct dma_device *dma, physaddr_t addr, size_t len, } /* Populate mapping */ + map->dma = dma; map->offset = ( bus - addr ); map->token = mapping; @@ -420,14 +421,14 @@ static void efipci_dma_unmap ( struct dma_device *dma, * Allocate and map DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping to fill in * @v len Length of buffer * @v align Physical alignment - * @v map DMA mapping to fill in * @ret addr Buffer address, or NULL on error */ -static void * efipci_dma_alloc ( struct dma_device *dma, size_t len, - size_t align __unused, - struct dma_mapping *map ) { +static void * efipci_dma_alloc ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align __unused ) { struct efi_pci_device *efipci = container_of ( dma, struct efi_pci_device, pci.dma ); struct pci_device *pci = &efipci->pci; @@ -451,8 +452,8 @@ static void * efipci_dma_alloc ( struct dma_device *dma, size_t len, } /* Map buffer */ - if ( ( rc = efipci_dma_map ( dma, virt_to_phys ( addr ), len, DMA_BI, - map ) ) != 0 ) + if ( ( rc = efipci_dma_map ( dma, map, virt_to_phys ( addr ), + len, DMA_BI ) ) != 0 ) goto err_map; /* Increment allocation count (for debugging) */ @@ -472,12 +473,12 @@ static void * efipci_dma_alloc ( struct dma_device *dma, size_t len, * Unmap and free DMA-coherent buffer * * @v dma DMA device + * @v map DMA mapping * @v addr Buffer address * @v len Length of buffer - * @v map DMA mapping */ -static void efipci_dma_free ( struct dma_device *dma, void *addr, size_t len, - struct dma_mapping *map ) { +static void efipci_dma_free ( struct dma_device *dma, struct dma_mapping *map, + void *addr, size_t len ) { struct efi_pci_device *efipci = container_of ( dma, struct efi_pci_device, pci.dma ); EFI_PCI_IO_PROTOCOL *pci_io = efipci->io; -- cgit v1.2.3-55-g7522 From 8d337ecdae3c6d555ea57996bc2280debd984a9c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 26 Nov 2020 12:25:02 +0000 Subject: [dma] Move I/O buffer DMA operations to iobuf.h Include a potential DMA mapping within the definition of an I/O buffer, and move all I/O buffer DMA mapping functions from dma.h to iobuf.h. This avoids the need for drivers to maintain a separate list of DMA mappings for each I/O buffer that they may handle. Network device drivers typically do not keep track of transmit I/O buffers, since the network device core already maintains a transmit queue. Drivers will typically call netdev_tx_complete_next() to complete a transmission without first obtaining the relevant I/O buffer pointer (and will rely on the network device core automatically cancelling any pending transmissions when the device is closed). To allow this driver design approach to be retained, update the netdev_tx_complete() family of functions to automatically perform the DMA unmapping operation if required. For symmetry, also update the netdev_rx() family of functions to behave the same way. As a further convenience for drivers, allow the network device core to automatically perform DMA mapping on the transmit datapath before calling the driver's transmit() method. This avoids the need to introduce a mapping error handling code path into the typically error-free transmit methods. With these changes, the modifications required to update a typical network device driver to use the new DMA API are fairly minimal: - Allocate and free descriptor rings and similar coherent structures using dma_alloc()/dma_free() rather than malloc_phys()/free_phys() - Allocate and free receive buffers using alloc_rx_iob()/free_rx_iob() rather than alloc_iob()/free_iob() - Calculate DMA addresses using dma() or iob_dma() rather than virt_to_bus() - Set a 64-bit DMA mask if needed using dma_set_mask_64bit() and thereafter eliminate checks on DMA address ranges - Either record the DMA device in netdev->dma, or call iob_map_tx() as part of the transmit() method - Ensure that debug messages use virt_to_phys() when displaying "hardware" addresses Signed-off-by: Michael Brown --- src/core/dma.c | 41 ------------- src/core/iobuf.c | 45 +++++++++++++++ src/drivers/net/intel.c | 120 ++++++++++++++------------------------ src/drivers/net/intel.h | 46 +++++---------- src/drivers/net/intelx.c | 21 +++---- src/drivers/net/intelxl.c | 134 ++++++++++++++++--------------------------- src/drivers/net/intelxl.h | 30 +++------- src/drivers/net/intelxlvf.c | 33 +++++------ src/drivers/net/intelxvf.c | 21 +++---- src/drivers/net/realtek.c | 101 ++++++++++++++------------------ src/drivers/net/realtek.h | 24 ++------ src/include/ipxe/dma.h | 22 ------- src/include/ipxe/iobuf.h | 55 ++++++++++++++++++ src/include/ipxe/netdevice.h | 6 ++ src/interface/efi/efi_pci.c | 2 + src/net/netdevice.c | 32 +++++++++++ 16 files changed, 342 insertions(+), 391 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/core/dma.c b/src/core/dma.c index 561aec1e1..e5fa3f323 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -25,7 +25,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include #include /** @file @@ -139,43 +138,3 @@ PROVIDE_DMAAPI ( op, dma_alloc, dma_op_alloc ); PROVIDE_DMAAPI ( op, dma_free, dma_op_free ); PROVIDE_DMAAPI ( op, dma_set_mask, dma_op_set_mask ); PROVIDE_DMAAPI_INLINE ( op, dma_phys ); - -/****************************************************************************** - * - * Utility functions - * - ****************************************************************************** - */ - -/** - * Allocate and map I/O buffer for receiving data from device - * - * @v dma DMA device - * @v map DMA mapping to fill in - * @v len Length of I/O buffer - * @ret iobuf I/O buffer, or NULL on error - */ -struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, - struct dma_mapping *map, - size_t len ) { - struct io_buffer *iobuf; - int rc; - - /* Allocate I/O buffer */ - iobuf = alloc_iob ( len ); - if ( ! iobuf ) - goto err_alloc; - - /* Map I/O buffer */ - if ( ( rc = dma_map ( dma, map, virt_to_phys ( iobuf->data ), - len, DMA_RX ) ) != 0 ) - goto err_map; - - return iobuf; - - dma_unmap ( map ); - err_map: - free_iob ( iobuf ); - err_alloc: - return NULL; -} diff --git a/src/core/iobuf.c b/src/core/iobuf.c index 941bb3446..c9970bc76 100644 --- a/src/core/iobuf.c +++ b/src/core/iobuf.c @@ -110,6 +110,7 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { } /* Populate descriptor */ + memset ( &iobuf->map, 0, sizeof ( iobuf->map ) ); iobuf->head = iobuf->data = iobuf->tail = data; iobuf->end = ( data + len ); @@ -153,6 +154,7 @@ void free_iob ( struct io_buffer *iobuf ) { assert ( iobuf->head <= iobuf->data ); assert ( iobuf->data <= iobuf->tail ); assert ( iobuf->tail <= iobuf->end ); + assert ( ! dma_mapped ( &iobuf->map ) ); /* Free buffer */ len = ( iobuf->end - iobuf->head ); @@ -169,6 +171,49 @@ void free_iob ( struct io_buffer *iobuf ) { } } +/** + * Allocate and map I/O buffer for receive DMA + * + * @v len Length of I/O buffer + * @v dma DMA device + * @ret iobuf I/O buffer, or NULL on error + */ +struct io_buffer * alloc_rx_iob ( size_t len, struct dma_device *dma ) { + struct io_buffer *iobuf; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) + goto err_alloc; + + /* Map I/O buffer */ + if ( ( rc = iob_map_rx ( iobuf, dma ) ) != 0 ) + goto err_map; + + return iobuf; + + iob_unmap ( iobuf ); + err_map: + free_iob ( iobuf ); + err_alloc: + return NULL; +} + +/** + * Unmap and free I/O buffer for receive DMA + * + * @v iobuf I/O buffer + */ +void free_rx_iob ( struct io_buffer *iobuf ) { + + /* Unmap I/O buffer */ + iob_unmap ( iobuf ); + + /* Free I/O buffer */ + free_iob ( iobuf ); +} + /** * Ensure I/O buffer has sufficient headroom * diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c index 93c5fd1f6..83492961f 100644 --- a/src/drivers/net/intel.c +++ b/src/drivers/net/intel.c @@ -568,34 +568,30 @@ void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ) { void intel_refill_rx ( struct intel_nic *intel ) { struct intel_descriptor *rx; struct io_buffer *iobuf; - struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; unsigned int refilled = 0; /* Refill ring */ - while ( ( intel->rx.ring.prod - - intel->rx.ring.cons ) < INTEL_RX_FILL ) { - - /* Get next receive descriptor */ - rx_idx = ( intel->rx.ring.prod % INTEL_NUM_RX_DESC ); - rx = &intel->rx.ring.desc[rx_idx]; - map = &intel->rx.map[rx_idx]; - assert ( intel->rx.iobuf[rx_idx] == NULL ); + while ( ( intel->rx.prod - intel->rx.cons ) < INTEL_RX_FILL ) { /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intel->dma, map, INTEL_RX_MAX_LEN ); + iobuf = alloc_rx_iob ( INTEL_RX_MAX_LEN, intel->dma ); if ( ! iobuf ) { /* Wait for next refill */ break; } - intel->rx.iobuf[rx_idx] = iobuf; - /* Update producer index */ - intel->rx.ring.prod++; + /* Get next receive descriptor */ + rx_idx = ( intel->rx.prod++ % INTEL_NUM_RX_DESC ); + rx = &intel->rx.desc[rx_idx]; /* Populate receive descriptor */ - intel->rx.ring.describe ( rx, dma ( map, iobuf->data ), 0 ); + intel->rx.describe ( rx, iob_dma ( iobuf ), 0 ); + + /* Record I/O buffer */ + assert ( intel->rx_iobuf[rx_idx] == NULL ); + intel->rx_iobuf[rx_idx] = iobuf; DBGC2 ( intel, "INTEL %p RX %d is [%lx,%lx)\n", intel, rx_idx, virt_to_phys ( iobuf->data ), @@ -606,40 +602,27 @@ void intel_refill_rx ( struct intel_nic *intel ) { /* Push descriptors to card, if applicable */ if ( refilled ) { wmb(); - rx_tail = ( intel->rx.ring.prod % INTEL_NUM_RX_DESC ); + rx_tail = ( intel->rx.prod % INTEL_NUM_RX_DESC ); profile_start ( &intel_vm_refill_profiler ); - writel ( rx_tail, - intel->regs + intel->rx.ring.reg + INTEL_xDT ); + writel ( rx_tail, intel->regs + intel->rx.reg + INTEL_xDT ); profile_stop ( &intel_vm_refill_profiler ); profile_exclude ( &intel_vm_refill_profiler ); } } /** - * Flush unused I/O buffers + * Discard unused receive I/O buffers * * @v intel Intel device - * - * Discard any unused receive I/O buffers and unmap any incomplete - * transmit I/O buffers. */ -void intel_flush ( struct intel_nic *intel ) { +void intel_empty_rx ( struct intel_nic *intel ) { unsigned int i; - unsigned int tx_idx; /* Discard unused receive buffers */ for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) { - if ( intel->rx.iobuf[i] ) { - dma_unmap ( &intel->rx.map[i] ); - free_iob ( intel->rx.iobuf[i] ); - } - intel->rx.iobuf[i] = NULL; - } - - /* Unmap incomplete transmit buffers */ - for ( i = intel->tx.ring.cons ; i != intel->tx.ring.prod ; i++ ) { - tx_idx = ( i % INTEL_NUM_TX_DESC ); - dma_unmap ( &intel->tx.map[tx_idx] ); + if ( intel->rx_iobuf[i] ) + free_rx_iob ( intel->rx_iobuf[i] ); + intel->rx_iobuf[i] = NULL; } } @@ -670,11 +653,11 @@ static int intel_open ( struct net_device *netdev ) { } /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) goto err_create_rx; /* Program MAC address */ @@ -713,9 +696,9 @@ static int intel_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); err_create_tx: return rc; } @@ -735,13 +718,13 @@ static void intel_close ( struct net_device *netdev ) { writel ( 0, intel->regs + INTEL_TCTL ); /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); - /* Flush unused buffers */ - intel_flush ( intel ); + /* Discard any unused receive buffers */ + intel_empty_rx ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); /* Reset the NIC, to flush the transmit and receive FIFOs */ intel_reset ( intel ); @@ -757,37 +740,27 @@ static void intel_close ( struct net_device *netdev ) { int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct intel_nic *intel = netdev->priv; struct intel_descriptor *tx; - struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; size_t len; - int rc; /* Get next transmit descriptor */ - if ( ( intel->tx.ring.prod - intel->tx.ring.cons ) >= INTEL_TX_FILL ) { + if ( ( intel->tx.prod - intel->tx.cons ) >= INTEL_TX_FILL ) { DBGC ( intel, "INTEL %p out of transmit descriptors\n", intel ); return -ENOBUFS; } - tx_idx = ( intel->tx.ring.prod % INTEL_NUM_TX_DESC ); - tx = &intel->tx.ring.desc[tx_idx]; - map = &intel->tx.map[tx_idx]; - - /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intel->dma, map, iobuf ) ) != 0 ) - return rc; - - /* Update producer index */ - intel->tx.ring.prod++; + tx_idx = ( intel->tx.prod++ % INTEL_NUM_TX_DESC ); + tx_tail = ( intel->tx.prod % INTEL_NUM_TX_DESC ); + tx = &intel->tx.desc[tx_idx]; /* Populate transmit descriptor */ len = iob_len ( iobuf ); - intel->tx.ring.describe ( tx, dma ( map, iobuf->data ), len ); + intel->tx.describe ( tx, iob_dma ( iobuf ), len ); wmb(); /* Notify card that there are packets ready to transmit */ profile_start ( &intel_vm_tx_profiler ); - tx_tail = ( intel->tx.ring.prod % INTEL_NUM_TX_DESC ); - writel ( tx_tail, intel->regs + intel->tx.ring.reg + INTEL_xDT ); + writel ( tx_tail, intel->regs + intel->tx.reg + INTEL_xDT ); profile_stop ( &intel_vm_tx_profiler ); profile_exclude ( &intel_vm_tx_profiler ); @@ -809,11 +782,11 @@ void intel_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( intel->tx.ring.cons != intel->tx.ring.prod ) { + while ( intel->tx.cons != intel->tx.prod ) { /* Get next transmit descriptor */ - tx_idx = ( intel->tx.ring.cons % INTEL_NUM_TX_DESC ); - tx = &intel->tx.ring.desc[tx_idx]; + tx_idx = ( intel->tx.cons % INTEL_NUM_TX_DESC ); + tx = &intel->tx.desc[tx_idx]; /* Stop if descriptor is still in use */ if ( ! ( tx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) ) @@ -821,12 +794,9 @@ void intel_poll_tx ( struct net_device *netdev ) { DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx ); - /* Unmap I/O buffer */ - dma_unmap ( &intel->tx.map[tx_idx] ); - /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); - intel->tx.ring.cons++; + intel->tx.cons++; } } @@ -843,22 +813,19 @@ void intel_poll_rx ( struct net_device *netdev ) { size_t len; /* Check for received packets */ - while ( intel->rx.ring.cons != intel->rx.ring.prod ) { + while ( intel->rx.cons != intel->rx.prod ) { /* Get next receive descriptor */ - rx_idx = ( intel->rx.ring.cons % INTEL_NUM_RX_DESC ); - rx = &intel->rx.ring.desc[rx_idx]; + rx_idx = ( intel->rx.cons % INTEL_NUM_RX_DESC ); + rx = &intel->rx.desc[rx_idx]; /* Stop if descriptor is still in use */ if ( ! ( rx->status & cpu_to_le32 ( INTEL_DESC_STATUS_DD ) ) ) return; - /* Unmap I/O buffer */ - dma_unmap ( &intel->rx.map[rx_idx] ); - /* Populate I/O buffer */ - iobuf = intel->rx.iobuf[rx_idx]; - intel->rx.iobuf[rx_idx] = NULL; + iobuf = intel->rx_iobuf[rx_idx]; + intel->rx_iobuf[rx_idx] = NULL; len = le16_to_cpu ( rx->length ); iob_put ( iobuf, len ); @@ -873,7 +840,7 @@ void intel_poll_rx ( struct net_device *netdev ) { intel, rx_idx, len ); netdev_rx ( netdev, iobuf ); } - intel->rx.ring.cons++; + intel->rx.cons++; } } @@ -981,9 +948,9 @@ static int intel_probe ( struct pci_device *pci ) { memset ( intel, 0, sizeof ( *intel ) ); intel->port = PCI_FUNC ( pci->busdevfn ); intel->flags = pci->id->driver_data; - intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTEL_TD, + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD, intel_describe_tx ); - intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTEL_RD, + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD, intel_describe_rx ); /* Fix up PCI device */ @@ -999,6 +966,7 @@ static int intel_probe ( struct pci_device *pci ) { /* Configure DMA */ intel->dma = &pci->dma; dma_set_mask_64bit ( intel->dma ); + netdev->dma = intel->dma; /* Reset the NIC */ if ( ( rc = intel_reset ( intel ) ) != 0 ) diff --git a/src/drivers/net/intel.h b/src/drivers/net/intel.h index 731b5f225..4f51a80f6 100644 --- a/src/drivers/net/intel.h +++ b/src/drivers/net/intel.h @@ -276,24 +276,6 @@ intel_init_mbox ( struct intel_mailbox *mbox, unsigned int ctrl, mbox->mem = mem; } -/** Transmit ring */ -struct intel_tx_ring { - /** Descriptor ring */ - struct intel_ring ring; - /** DMA mappings */ - struct dma_mapping map[INTEL_NUM_TX_DESC]; -}; - -/** Receive ring */ -struct intel_rx_ring { - /** Descriptor ring */ - struct intel_ring ring; - /** I/O buffers */ - struct io_buffer *iobuf[INTEL_NUM_RX_DESC]; - /** DMA mappings */ - struct dma_mapping map[INTEL_NUM_RX_DESC]; -}; - /** An Intel network card */ struct intel_nic { /** Registers */ @@ -317,10 +299,12 @@ struct intel_nic { /** Mailbox */ struct intel_mailbox mbox; - /** Transmit ring */ - struct intel_tx_ring tx; - /** Receive ring */ - struct intel_rx_ring rx; + /** Transmit descriptor ring */ + struct intel_ring tx; + /** Receive descriptor ring */ + struct intel_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[INTEL_NUM_RX_DESC]; }; /** Driver flags */ @@ -349,14 +333,14 @@ static inline void intel_diag ( struct intel_nic *intel ) { DBGC ( intel, "INTEL %p TX %04x(%02x)/%04x(%02x) " "RX %04x(%02x)/%04x(%02x)\n", intel, - ( intel->tx.ring.cons & 0xffff ), - readl ( intel->regs + intel->tx.ring.reg + INTEL_xDH ), - ( intel->tx.ring.prod & 0xffff ), - readl ( intel->regs + intel->tx.ring.reg + INTEL_xDT ), - ( intel->rx.ring.cons & 0xffff ), - readl ( intel->regs + intel->rx.ring.reg + INTEL_xDH ), - ( intel->rx.ring.prod & 0xffff ), - readl ( intel->regs + intel->rx.ring.reg + INTEL_xDT ) ); + ( intel->tx.cons & 0xffff ), + readl ( intel->regs + intel->tx.reg + INTEL_xDH ), + ( intel->tx.prod & 0xffff ), + readl ( intel->regs + intel->tx.reg + INTEL_xDT ), + ( intel->rx.cons & 0xffff ), + readl ( intel->regs + intel->rx.reg + INTEL_xDH ), + ( intel->rx.prod & 0xffff ), + readl ( intel->regs + intel->rx.reg + INTEL_xDT ) ); } extern void intel_describe_tx ( struct intel_descriptor *tx, @@ -371,7 +355,7 @@ extern int intel_create_ring ( struct intel_nic *intel, extern void intel_destroy_ring ( struct intel_nic *intel, struct intel_ring *ring ); extern void intel_refill_rx ( struct intel_nic *intel ); -extern void intel_flush ( struct intel_nic *intel ); +extern void intel_empty_rx ( struct intel_nic *intel ); extern int intel_transmit ( struct net_device *netdev, struct io_buffer *iobuf ); extern void intel_poll_tx ( struct net_device *netdev ); diff --git a/src/drivers/net/intelx.c b/src/drivers/net/intelx.c index 364ec76c5..ccf6b0648 100644 --- a/src/drivers/net/intelx.c +++ b/src/drivers/net/intelx.c @@ -185,11 +185,11 @@ static int intelx_open ( struct net_device *netdev ) { int rc; /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) goto err_create_rx; /* Program MAC address */ @@ -263,9 +263,9 @@ static int intelx_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); err_create_tx: return rc; } @@ -291,13 +291,13 @@ static void intelx_close ( struct net_device *netdev ) { writel ( dmatxctl, intel->regs + INTELX_DMATXCTL ); /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); - /* Flush unused buffers */ - intel_flush ( intel ); + /* Discard any unused receive buffers */ + intel_empty_rx ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); /* Reset the NIC, to flush the transmit and receive FIFOs */ intelx_reset ( intel ); @@ -395,9 +395,9 @@ static int intelx_probe ( struct pci_device *pci ) { netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); intel->port = PCI_FUNC ( pci->busdevfn ); - intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTELX_TD, + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELX_TD, intel_describe_tx ); - intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTELX_RD, + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELX_RD, intel_describe_rx ); /* Fix up PCI device */ @@ -413,6 +413,7 @@ static int intelx_probe ( struct pci_device *pci ) { /* Configure DMA */ intel->dma = &pci->dma; dma_set_mask_64bit ( intel->dma ); + netdev->dma = intel->dma; /* Reset the NIC */ if ( ( rc = intelx_reset ( intel ) ) != 0 ) diff --git a/src/drivers/net/intelxl.c b/src/drivers/net/intelxl.c index 5de432a6a..ac9e37c5a 100644 --- a/src/drivers/net/intelxl.c +++ b/src/drivers/net/intelxl.c @@ -1306,36 +1306,32 @@ static void intelxl_destroy_ring ( struct intelxl_nic *intelxl, static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { struct intelxl_rx_data_descriptor *rx; struct io_buffer *iobuf; - struct dma_mapping *map; unsigned int rx_idx; unsigned int rx_tail; unsigned int refilled = 0; /* Refill ring */ - while ( ( intelxl->rx.ring.prod - - intelxl->rx.ring.cons ) < INTELXL_RX_FILL ) { - - /* Get next receive descriptor */ - rx_idx = ( intelxl->rx.ring.prod % INTELXL_RX_NUM_DESC ); - rx = &intelxl->rx.ring.desc.rx[rx_idx].data; - map = &intelxl->rx.map[rx_idx]; - assert ( intelxl->rx.iobuf[rx_idx] == NULL ); + while ( ( intelxl->rx.prod - intelxl->rx.cons ) < INTELXL_RX_FILL ) { /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( intelxl->dma, map, intelxl->mfs ); + iobuf = alloc_rx_iob ( intelxl->mfs, intelxl->dma ); if ( ! iobuf ) { /* Wait for next refill */ break; } - intelxl->rx.iobuf[rx_idx] = iobuf; - /* Update producer index */ - intelxl->rx.ring.prod++; + /* Get next receive descriptor */ + rx_idx = ( intelxl->rx.prod++ % INTELXL_RX_NUM_DESC ); + rx = &intelxl->rx.desc.rx[rx_idx].data; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); + rx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); rx->flags = 0; + /* Record I/O buffer */ + assert ( intelxl->rx_iobuf[rx_idx] == NULL ); + intelxl->rx_iobuf[rx_idx] = iobuf; + DBGC2 ( intelxl, "INTELXL %p RX %d is [%08lx,%08lx)\n", intelxl, rx_idx, virt_to_phys ( iobuf->data ), ( virt_to_phys ( iobuf->data ) + intelxl->mfs ) ); @@ -1345,36 +1341,24 @@ static void intelxl_refill_rx ( struct intelxl_nic *intelxl ) { /* Push descriptors to card, if applicable */ if ( refilled ) { wmb(); - rx_tail = ( intelxl->rx.ring.prod % INTELXL_RX_NUM_DESC ); - writel ( rx_tail, ( intelxl->regs + intelxl->rx.ring.tail ) ); + rx_tail = ( intelxl->rx.prod % INTELXL_RX_NUM_DESC ); + writel ( rx_tail, ( intelxl->regs + intelxl->rx.tail ) ); } } /** - * Flush unused I/O buffers + * Discard unused receive I/O buffers * * @v intelxl Intel device - * - * Discard any unused receive I/O buffers and unmap any incomplete - * transmit I/O buffers. */ -void intelxl_flush ( struct intelxl_nic *intelxl ) { +void intelxl_empty_rx ( struct intelxl_nic *intelxl ) { unsigned int i; - unsigned int tx_idx; /* Discard any unused receive buffers */ for ( i = 0 ; i < INTELXL_RX_NUM_DESC ; i++ ) { - if ( intelxl->rx.iobuf[i] ) { - dma_unmap ( &intelxl->rx.map[i] ); - free_iob ( intelxl->rx.iobuf[i] ); - } - intelxl->rx.iobuf[i] = NULL; - } - - /* Unmap incomplete transmit buffers */ - for ( i = intelxl->tx.ring.cons ; i != intelxl->tx.ring.prod ; i++ ) { - tx_idx = ( i % INTELXL_TX_NUM_DESC ); - dma_unmap ( &intelxl->tx.map[tx_idx] ); + if ( intelxl->rx_iobuf[i] ) + free_rx_iob ( intelxl->rx_iobuf[i] ); + intelxl->rx_iobuf[i] = NULL; } } @@ -1415,7 +1399,7 @@ static int intelxl_open ( struct net_device *netdev ) { /* Associate transmit queue to PF */ writel ( ( INTELXL_QXX_CTL_PFVF_Q_PF | INTELXL_QXX_CTL_PFVF_PF_INDX ( intelxl->pf ) ), - ( intelxl->regs + intelxl->tx.ring.reg + INTELXL_QXX_CTL ) ); + ( intelxl->regs + intelxl->tx.reg + INTELXL_QXX_CTL ) ); /* Clear transmit pre queue disable */ queue = ( intelxl->base + intelxl->queue ); @@ -1427,11 +1411,11 @@ static int intelxl_open ( struct net_device *netdev ) { writel ( 0, ( intelxl->regs + INTELXL_QTX_HEAD ( intelxl->queue ) ) ); /* Create receive descriptor ring */ - if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx.ring ) ) != 0 ) + if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->rx ) ) != 0 ) goto err_create_rx; /* Create transmit descriptor ring */ - if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx.ring ) ) != 0 ) + if ( ( rc = intelxl_create_ring ( intelxl, &intelxl->tx ) ) != 0 ) goto err_create_tx; /* Fill receive ring */ @@ -1449,9 +1433,9 @@ static int intelxl_open ( struct net_device *netdev ) { INTELXL_GLLAN_TXPRE_QDIS_QINDX ( queue ) ), ( intelxl->regs + INTELXL_GLLAN_TXPRE_QDIS ( queue ) ) ); udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US ); - intelxl_destroy_ring ( intelxl, &intelxl->tx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->tx ); err_create_tx: - intelxl_destroy_ring ( intelxl, &intelxl->rx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->rx ); err_create_rx: return rc; } @@ -1479,13 +1463,13 @@ static void intelxl_close ( struct net_device *netdev ) { udelay ( INTELXL_QUEUE_PRE_DISABLE_DELAY_US ); /* Destroy transmit descriptor ring */ - intelxl_destroy_ring ( intelxl, &intelxl->tx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->tx ); /* Destroy receive descriptor ring */ - intelxl_destroy_ring ( intelxl, &intelxl->rx.ring ); + intelxl_destroy_ring ( intelxl, &intelxl->rx ); - /* Flush unused buffers */ - intelxl_flush ( intelxl ); + /* Discard any unused receive buffers */ + intelxl_empty_rx ( intelxl ); } /** @@ -1498,41 +1482,30 @@ static void intelxl_close ( struct net_device *netdev ) { int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct intelxl_nic *intelxl = netdev->priv; struct intelxl_tx_data_descriptor *tx; - struct dma_mapping *map; unsigned int tx_idx; unsigned int tx_tail; size_t len; - int rc; /* Get next transmit descriptor */ - if ( ( intelxl->tx.ring.prod - - intelxl->tx.ring.cons ) >= INTELXL_TX_FILL ) { + if ( ( intelxl->tx.prod - intelxl->tx.cons ) >= INTELXL_TX_FILL ) { DBGC ( intelxl, "INTELXL %p out of transmit descriptors\n", intelxl ); return -ENOBUFS; } - tx_idx = ( intelxl->tx.ring.prod % INTELXL_TX_NUM_DESC ); - tx = &intelxl->tx.ring.desc.tx[tx_idx].data; - map = &intelxl->tx.map[tx_idx]; - - /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( intelxl->dma, map, iobuf ) ) != 0 ) - return rc; - - /* Update producer index */ - intelxl->tx.ring.prod++; + tx_idx = ( intelxl->tx.prod++ % INTELXL_TX_NUM_DESC ); + tx_tail = ( intelxl->tx.prod % INTELXL_TX_NUM_DESC ); + tx = &intelxl->tx.desc.tx[tx_idx].data; /* Populate transmit descriptor */ len = iob_len ( iobuf ); - tx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); + tx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); tx->len = cpu_to_le32 ( INTELXL_TX_DATA_LEN ( len ) ); tx->flags = cpu_to_le32 ( INTELXL_TX_DATA_DTYP | INTELXL_TX_DATA_EOP | INTELXL_TX_DATA_RS | INTELXL_TX_DATA_JFDI ); wmb(); /* Notify card that there are packets ready to transmit */ - tx_tail = ( intelxl->tx.ring.prod % INTELXL_TX_NUM_DESC ); - writel ( tx_tail, ( intelxl->regs + intelxl->tx.ring.tail ) ); + writel ( tx_tail, ( intelxl->regs + intelxl->tx.tail ) ); DBGC2 ( intelxl, "INTELXL %p TX %d is [%08lx,%08lx)\n", intelxl, tx_idx, virt_to_phys ( iobuf->data ), @@ -1551,11 +1524,11 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( intelxl->tx.ring.cons != intelxl->tx.ring.prod ) { + while ( intelxl->tx.cons != intelxl->tx.prod ) { /* Get next transmit descriptor */ - tx_idx = ( intelxl->tx.ring.cons % INTELXL_TX_NUM_DESC ); - tx_wb = &intelxl->tx.ring.desc.tx[tx_idx].wb; + tx_idx = ( intelxl->tx.cons % INTELXL_TX_NUM_DESC ); + tx_wb = &intelxl->tx.desc.tx[tx_idx].wb; /* Stop if descriptor is still in use */ if ( ! ( tx_wb->flags & INTELXL_TX_WB_FL_DD ) ) @@ -1563,12 +1536,9 @@ static void intelxl_poll_tx ( struct net_device *netdev ) { DBGC2 ( intelxl, "INTELXL %p TX %d complete\n", intelxl, tx_idx ); - /* Unmap I/O buffer */ - dma_unmap ( &intelxl->tx.map[tx_idx] ); - /* Complete TX descriptor */ netdev_tx_complete_next ( netdev ); - intelxl->tx.ring.cons++; + intelxl->tx.cons++; } } @@ -1586,22 +1556,19 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { size_t len; /* Check for received packets */ - while ( intelxl->rx.ring.cons != intelxl->rx.ring.prod ) { + while ( intelxl->rx.cons != intelxl->rx.prod ) { /* Get next receive descriptor */ - rx_idx = ( intelxl->rx.ring.cons % INTELXL_RX_NUM_DESC ); - rx_wb = &intelxl->rx.ring.desc.rx[rx_idx].wb; + rx_idx = ( intelxl->rx.cons % INTELXL_RX_NUM_DESC ); + rx_wb = &intelxl->rx.desc.rx[rx_idx].wb; /* Stop if descriptor is still in use */ if ( ! ( rx_wb->flags & cpu_to_le32 ( INTELXL_RX_WB_FL_DD ) ) ) return; - /* Unmap I/O buffer */ - dma_unmap ( &intelxl->rx.map[rx_idx] ); - /* Populate I/O buffer */ - iobuf = intelxl->rx.iobuf[rx_idx]; - intelxl->rx.iobuf[rx_idx] = NULL; + iobuf = intelxl->rx_iobuf[rx_idx]; + intelxl->rx_iobuf[rx_idx] = NULL; len = INTELXL_RX_WB_LEN ( le32_to_cpu ( rx_wb->len ) ); iob_put ( iobuf, len ); @@ -1623,7 +1590,7 @@ static void intelxl_poll_rx ( struct net_device *netdev ) { "%zd)\n", intelxl, rx_idx, len ); vlan_netdev_rx ( netdev, tag, iobuf ); } - intelxl->rx.ring.cons++; + intelxl->rx.cons++; } } @@ -1710,11 +1677,11 @@ static int intelxl_probe ( struct pci_device *pci ) { &intelxl_admin_offsets ); intelxl_init_admin ( &intelxl->event, INTELXL_ADMIN_EVT, &intelxl_admin_offsets ); - intelxl_init_ring ( &intelxl->tx.ring, INTELXL_TX_NUM_DESC, - sizeof ( intelxl->tx.ring.desc.tx[0] ), + intelxl_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC, + sizeof ( intelxl->tx.desc.tx[0] ), intelxl_context_tx ); - intelxl_init_ring ( &intelxl->rx.ring, INTELXL_RX_NUM_DESC, - sizeof ( intelxl->rx.ring.desc.rx[0] ), + intelxl_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC, + sizeof ( intelxl->rx.desc.rx[0] ), intelxl_context_rx ); /* Fix up PCI device */ @@ -1730,6 +1697,7 @@ static int intelxl_probe ( struct pci_device *pci ) { /* Configure DMA */ intelxl->dma = &pci->dma; dma_set_mask_64bit ( intelxl->dma ); + netdev->dma = intelxl->dma; /* Reset the NIC */ if ( ( rc = intelxl_reset ( intelxl ) ) != 0 ) @@ -1775,10 +1743,10 @@ static int intelxl_probe ( struct pci_device *pci ) { goto err_admin_promisc; /* Configure queue register addresses */ - intelxl->tx.ring.reg = INTELXL_QTX ( intelxl->queue ); - intelxl->tx.ring.tail = ( intelxl->tx.ring.reg + INTELXL_QXX_TAIL ); - intelxl->rx.ring.reg = INTELXL_QRX ( intelxl->queue ); - intelxl->rx.ring.tail = ( intelxl->rx.ring.reg + INTELXL_QXX_TAIL ); + intelxl->tx.reg = INTELXL_QTX ( intelxl->queue ); + intelxl->tx.tail = ( intelxl->tx.reg + INTELXL_QXX_TAIL ); + intelxl->rx.reg = INTELXL_QRX ( intelxl->queue ); + intelxl->rx.tail = ( intelxl->rx.reg + INTELXL_QXX_TAIL ); /* Configure interrupt causes */ writel ( ( INTELXL_QINT_TQCTL_NEXTQ_INDX_NONE | diff --git a/src/drivers/net/intelxl.h b/src/drivers/net/intelxl.h index cffc0da96..a4a776d28 100644 --- a/src/drivers/net/intelxl.h +++ b/src/drivers/net/intelxl.h @@ -1030,24 +1030,6 @@ union intelxl_receive_address { uint8_t raw[ETH_ALEN]; }; -/** Transmit ring */ -struct intelxl_tx_ring { - /** Descriptor ring */ - struct intelxl_ring ring; - /** DMA mappings */ - struct dma_mapping map[INTELXL_TX_NUM_DESC]; -}; - -/** Receive ring */ -struct intelxl_rx_ring { - /** Descriptor ring */ - struct intelxl_ring ring; - /** I/O buffers */ - struct io_buffer *iobuf[INTELXL_RX_NUM_DESC]; - /** DMA mappings */ - struct dma_mapping map[INTELXL_RX_NUM_DESC]; -}; - /** MSI-X interrupt */ struct intelxl_msix { /** PCI capability */ @@ -1098,10 +1080,12 @@ struct intelxl_nic { /** Current VF event data buffer */ union intelxl_admin_buffer vbuf; - /** Transmit ring */ - struct intelxl_tx_ring tx; - /** Receive ring */ - struct intelxl_rx_ring rx; + /** Transmit descriptor ring */ + struct intelxl_ring tx; + /** Receive descriptor ring */ + struct intelxl_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[INTELXL_RX_NUM_DESC]; }; extern int intelxl_msix_enable ( struct intelxl_nic *intelxl, @@ -1121,7 +1105,7 @@ extern int intelxl_alloc_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ); extern void intelxl_free_ring ( struct intelxl_nic *intelxl, struct intelxl_ring *ring ); -extern void intelxl_flush ( struct intelxl_nic *intelxl ); +extern void intelxl_empty_rx ( struct intelxl_nic *intelxl ); extern int intelxl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ); extern void intelxl_poll ( struct net_device *netdev ); diff --git a/src/drivers/net/intelxlvf.c b/src/drivers/net/intelxlvf.c index f944b4daa..752de7815 100644 --- a/src/drivers/net/intelxlvf.c +++ b/src/drivers/net/intelxlvf.c @@ -380,14 +380,14 @@ static int intelxlvf_admin_configure ( struct net_device *netdev ) { buf->cfg.count = cpu_to_le16 ( 1 ); buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC ); - buf->cfg.tx.base = cpu_to_le64 ( dma ( &intelxl->tx.ring.map, - intelxl->tx.ring.desc.raw ) ); + buf->cfg.tx.base = cpu_to_le64 ( dma ( &intelxl->tx.map, + intelxl->tx.desc.raw ) ); buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi ); buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC ); buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs ); buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs ); - buf->cfg.rx.base = cpu_to_le64 ( dma ( &intelxl->rx.ring.map, - intelxl->rx.ring.desc.raw ) ); + buf->cfg.rx.base = cpu_to_le64 ( dma ( &intelxl->rx.map, + intelxl->rx.desc.raw ) ); /* Issue command */ if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 ) @@ -501,11 +501,11 @@ static int intelxlvf_open ( struct net_device *netdev ) { INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) ); /* Allocate transmit descriptor ring */ - if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx.ring ) ) != 0 ) + if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx ) ) != 0 ) goto err_alloc_tx; /* Allocate receive descriptor ring */ - if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx.ring ) ) != 0 ) + if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx ) ) != 0 ) goto err_alloc_rx; /* Configure queues */ @@ -531,9 +531,9 @@ static int intelxlvf_open ( struct net_device *netdev ) { err_enable: err_irq_map: err_configure: - intelxl_free_ring ( intelxl, &intelxl->rx.ring ); + intelxl_free_ring ( intelxl, &intelxl->rx ); err_alloc_rx: - intelxl_free_ring ( intelxl, &intelxl->tx.ring ); + intelxl_free_ring ( intelxl, &intelxl->tx ); err_alloc_tx: return rc; } @@ -554,13 +554,13 @@ static void intelxlvf_close ( struct net_device *netdev ) { } /* Free receive descriptor ring */ - intelxl_free_ring ( intelxl, &intelxl->rx.ring ); + intelxl_free_ring ( intelxl, &intelxl->rx ); /* Free transmit descriptor ring */ - intelxl_free_ring ( intelxl, &intelxl->tx.ring ); + intelxl_free_ring ( intelxl, &intelxl->tx ); - /* Flush unused buffers */ - intelxl_flush ( intelxl ); + /* Discard any unused receive buffers */ + intelxl_empty_rx ( intelxl ); } /** Network device operations */ @@ -605,11 +605,11 @@ static int intelxlvf_probe ( struct pci_device *pci ) { &intelxlvf_admin_command_offsets ); intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN, &intelxlvf_admin_event_offsets ); - intelxlvf_init_ring ( &intelxl->tx.ring, INTELXL_TX_NUM_DESC, - sizeof ( intelxl->tx.ring.desc.tx[0] ), + intelxlvf_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC, + sizeof ( intelxl->tx.desc.tx[0] ), INTELXLVF_QTX_TAIL ); - intelxlvf_init_ring ( &intelxl->rx.ring, INTELXL_RX_NUM_DESC, - sizeof ( intelxl->rx.ring.desc.rx[0] ), + intelxlvf_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC, + sizeof ( intelxl->rx.desc.rx[0] ), INTELXLVF_QRX_TAIL ); /* Fix up PCI device */ @@ -625,6 +625,7 @@ static int intelxlvf_probe ( struct pci_device *pci ) { /* Configure DMA */ intelxl->dma = &pci->dma; dma_set_mask_64bit ( intelxl->dma ); + netdev->dma = intelxl->dma; /* Locate PCI Express capability */ intelxl->exp = pci_find_capability ( pci, PCI_CAP_ID_EXP ); diff --git a/src/drivers/net/intelxvf.c b/src/drivers/net/intelxvf.c index a650979ef..f0ba091d5 100644 --- a/src/drivers/net/intelxvf.c +++ b/src/drivers/net/intelxvf.c @@ -276,11 +276,11 @@ static int intelxvf_open ( struct net_device *netdev ) { } /* Create transmit descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->tx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = intel_create_ring ( intel, &intel->rx.ring ) ) != 0 ) + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) goto err_create_rx; /* Allocate interrupt vectors */ @@ -317,9 +317,9 @@ static int intelxvf_open ( struct net_device *netdev ) { return 0; - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); err_create_rx: - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); err_create_tx: err_mbox_set_mtu: err_mbox_set_mac: @@ -337,13 +337,13 @@ static void intelxvf_close ( struct net_device *netdev ) { struct intel_nic *intel = netdev->priv; /* Destroy receive descriptor ring */ - intel_destroy_ring ( intel, &intel->rx.ring ); + intel_destroy_ring ( intel, &intel->rx ); - /* Flush unused buffers */ - intel_flush ( intel ); + /* Discard any unused receive buffers */ + intel_empty_rx ( intel ); /* Destroy transmit descriptor ring */ - intel_destroy_ring ( intel, &intel->tx.ring ); + intel_destroy_ring ( intel, &intel->tx ); /* Reset the function */ intelxvf_reset ( intel ); @@ -447,9 +447,9 @@ static int intelxvf_probe ( struct pci_device *pci ) { netdev->dev = &pci->dev; memset ( intel, 0, sizeof ( *intel ) ); intel_init_mbox ( &intel->mbox, INTELXVF_MBCTRL, INTELXVF_MBMEM ); - intel_init_ring ( &intel->tx.ring, INTEL_NUM_TX_DESC, INTELXVF_TD(0), + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTELXVF_TD(0), intel_describe_tx_adv ); - intel_init_ring ( &intel->rx.ring, INTEL_NUM_RX_DESC, INTELXVF_RD(0), + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTELXVF_RD(0), intel_describe_rx ); /* Fix up PCI device */ @@ -465,6 +465,7 @@ static int intelxvf_probe ( struct pci_device *pci ) { /* Configure DMA */ intel->dma = &pci->dma; dma_set_mask_64bit ( intel->dma ); + netdev->dma = intel->dma; /* Reset the function */ intelxvf_reset ( intel ); diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index 47d435f72..0af3416d5 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -621,7 +621,6 @@ static void realtek_destroy_ring ( struct realtek_nic *rtl, static void realtek_refill_rx ( struct realtek_nic *rtl ) { struct realtek_descriptor *rx; struct io_buffer *iobuf; - struct dma_mapping *map; unsigned int rx_idx; int is_last; @@ -629,34 +628,32 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { if ( rtl->legacy ) return; - while ( ( rtl->rx.ring.prod - rtl->rx.ring.cons ) < RTL_NUM_RX_DESC ) { - - /* Get next receive descriptor */ - rx_idx = ( rtl->rx.ring.prod % RTL_NUM_RX_DESC ); - is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) ); - rx = &rtl->rx.ring.desc[rx_idx]; - map = &rtl->rx.map[rx_idx]; - assert ( rtl->rx.iobuf[rx_idx] == NULL ); + while ( ( rtl->rx.prod - rtl->rx.cons ) < RTL_NUM_RX_DESC ) { /* Allocate I/O buffer */ - iobuf = dma_alloc_rx_iob ( rtl->dma, map, RTL_RX_MAX_LEN ); + iobuf = alloc_rx_iob ( RTL_RX_MAX_LEN, rtl->dma ); if ( ! iobuf ) { /* Wait for next refill */ return; } - rtl->rx.iobuf[rx_idx] = iobuf; - /* Update producer index */ - rtl->rx.ring.prod++; + /* Get next receive descriptor */ + rx_idx = ( rtl->rx.prod++ % RTL_NUM_RX_DESC ); + is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) ); + rx = &rtl->rx.desc[rx_idx]; /* Populate receive descriptor */ - rx->address = cpu_to_le64 ( dma ( map, iobuf->data ) ); + rx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); rx->length = cpu_to_le16 ( RTL_RX_MAX_LEN ); wmb(); rx->flags = ( cpu_to_le16 ( RTL_DESC_OWN ) | ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) ); wmb(); + /* Record I/O buffer */ + assert ( rtl->rx_iobuf[rx_idx] == NULL ); + rtl->rx_iobuf[rx_idx] = iobuf; + DBGC2 ( rtl, "REALTEK %p RX %d is [%lx,%lx)\n", rtl, rx_idx, virt_to_phys ( iobuf->data ), ( virt_to_phys ( iobuf->data ) + RTL_RX_MAX_LEN ) ); @@ -676,11 +673,11 @@ static int realtek_open ( struct net_device *netdev ) { int rc; /* Create transmit descriptor ring */ - if ( ( rc = realtek_create_ring ( rtl, &rtl->tx.ring ) ) != 0 ) + if ( ( rc = realtek_create_ring ( rtl, &rtl->tx ) ) != 0 ) goto err_create_tx; /* Create receive descriptor ring */ - if ( ( rc = realtek_create_ring ( rtl, &rtl->rx.ring ) ) != 0 ) + if ( ( rc = realtek_create_ring ( rtl, &rtl->rx ) ) != 0 ) goto err_create_rx; /* Create receive buffer */ @@ -721,9 +718,9 @@ static int realtek_open ( struct net_device *netdev ) { realtek_destroy_buffer ( rtl ); err_create_buffer: - realtek_destroy_ring ( rtl, &rtl->rx.ring ); + realtek_destroy_ring ( rtl, &rtl->rx ); err_create_rx: - realtek_destroy_ring ( rtl, &rtl->tx.ring ); + realtek_destroy_ring ( rtl, &rtl->tx ); err_create_tx: return rc; } @@ -744,23 +741,17 @@ static void realtek_close ( struct net_device *netdev ) { realtek_destroy_buffer ( rtl ); /* Destroy receive descriptor ring */ - realtek_destroy_ring ( rtl, &rtl->rx.ring ); + realtek_destroy_ring ( rtl, &rtl->rx ); /* Discard any unused receive buffers */ for ( i = 0 ; i < RTL_NUM_RX_DESC ; i++ ) { - if ( rtl->rx.iobuf[i] ) { - dma_unmap ( &rtl->rx.map[i] ); - free_iob ( rtl->rx.iobuf[i] ); - } - rtl->rx.iobuf[i] = NULL; + if ( rtl->rx_iobuf[i] ) + free_rx_iob ( rtl->rx_iobuf[i] ); + rtl->rx_iobuf[i] = NULL; } - /* Unmap any incomplete transmit buffers */ - for ( i = rtl->tx.ring.cons ; i != rtl->tx.ring.prod ; i++ ) - dma_unmap ( &rtl->tx.map[ i % RTL_NUM_TX_DESC ] ); - /* Destroy transmit descriptor ring */ - realtek_destroy_ring ( rtl, &rtl->tx.ring ); + realtek_destroy_ring ( rtl, &rtl->tx ); /* Reset legacy transmit descriptor index, if applicable */ if ( rtl->legacy ) @@ -778,37 +769,33 @@ static int realtek_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { struct realtek_nic *rtl = netdev->priv; struct realtek_descriptor *tx; - struct dma_mapping *map; unsigned int tx_idx; - physaddr_t address; int is_last; int rc; /* Get next transmit descriptor */ - if ( ( rtl->tx.ring.prod - rtl->tx.ring.cons ) >= RTL_NUM_TX_DESC ) { + if ( ( rtl->tx.prod - rtl->tx.cons ) >= RTL_NUM_TX_DESC ) { netdev_tx_defer ( netdev, iobuf ); return 0; } - tx_idx = ( rtl->tx.ring.prod % RTL_NUM_TX_DESC ); - map = &rtl->tx.map[tx_idx]; + tx_idx = ( rtl->tx.prod % RTL_NUM_TX_DESC ); /* Pad and align packet, if needed */ if ( rtl->legacy ) iob_pad ( iobuf, ETH_ZLEN ); /* Map I/O buffer */ - if ( ( rc = dma_map_tx_iob ( rtl->dma, map, iobuf ) ) != 0 ) + if ( ( rc = iob_map_tx ( iobuf, rtl->dma ) ) != 0 ) return rc; - address = dma ( map, iobuf->data ); /* Update producer index */ - rtl->tx.ring.prod++; + rtl->tx.prod++; /* Transmit packet */ if ( rtl->legacy ) { /* Add to transmit ring */ - writel ( address, rtl->regs + RTL_TSAD ( tx_idx ) ); + writel ( iob_dma ( iobuf ), rtl->regs + RTL_TSAD ( tx_idx ) ); writel ( ( RTL_TSD_ERTXTH_DEFAULT | iob_len ( iobuf ) ), rtl->regs + RTL_TSD ( tx_idx ) ); @@ -816,8 +803,8 @@ static int realtek_transmit ( struct net_device *netdev, /* Populate transmit descriptor */ is_last = ( tx_idx == ( RTL_NUM_TX_DESC - 1 ) ); - tx = &rtl->tx.ring.desc[tx_idx]; - tx->address = cpu_to_le64 ( address ); + tx = &rtl->tx.desc[tx_idx]; + tx->address = cpu_to_le64 ( iob_dma ( iobuf ) ); tx->length = cpu_to_le16 ( iob_len ( iobuf ) ); wmb(); tx->flags = ( cpu_to_le16 ( RTL_DESC_OWN | RTL_DESC_FS | @@ -847,10 +834,10 @@ static void realtek_poll_tx ( struct net_device *netdev ) { unsigned int tx_idx; /* Check for completed packets */ - while ( rtl->tx.ring.cons != rtl->tx.ring.prod ) { + while ( rtl->tx.cons != rtl->tx.prod ) { /* Get next transmit descriptor */ - tx_idx = ( rtl->tx.ring.cons % RTL_NUM_TX_DESC ); + tx_idx = ( rtl->tx.cons % RTL_NUM_TX_DESC ); /* Stop if descriptor is still in use */ if ( rtl->legacy ) { @@ -863,18 +850,15 @@ static void realtek_poll_tx ( struct net_device *netdev ) { } else { /* Check ownership bit in descriptor */ - tx = &rtl->tx.ring.desc[tx_idx]; + tx = &rtl->tx.desc[tx_idx]; if ( tx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) return; } DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx ); - /* Unmap I/O buffer */ - dma_unmap ( &rtl->tx.map[tx_idx] ); - /* Complete TX descriptor */ - rtl->tx.ring.cons++; + rtl->tx.cons++; netdev_tx_complete_next ( netdev ); } } @@ -954,22 +938,19 @@ static void realtek_poll_rx ( struct net_device *netdev ) { } /* Check for received packets */ - while ( rtl->rx.ring.cons != rtl->rx.ring.prod ) { + while ( rtl->rx.cons != rtl->rx.prod ) { /* Get next receive descriptor */ - rx_idx = ( rtl->rx.ring.cons % RTL_NUM_RX_DESC ); - rx = &rtl->rx.ring.desc[rx_idx]; + rx_idx = ( rtl->rx.cons % RTL_NUM_RX_DESC ); + rx = &rtl->rx.desc[rx_idx]; /* Stop if descriptor is still in use */ if ( rx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) return; - /* Unmap buffer */ - dma_unmap ( &rtl->rx.map[rx_idx] ); - /* Populate I/O buffer */ - iobuf = rtl->rx.iobuf[rx_idx]; - rtl->rx.iobuf[rx_idx] = NULL; + iobuf = rtl->rx_iobuf[rx_idx]; + rtl->rx_iobuf[rx_idx] = NULL; len = ( le16_to_cpu ( rx->length ) & RTL_DESC_SIZE_MASK ); iob_put ( iobuf, ( len - 4 /* strip CRC */ ) ); @@ -984,7 +965,7 @@ static void realtek_poll_rx ( struct net_device *netdev ) { "%zd)\n", rtl, rx_idx, len ); netdev_rx ( netdev, iobuf ); } - rtl->rx.ring.cons++; + rtl->rx.cons++; } } @@ -1128,9 +1109,8 @@ static int realtek_probe ( struct pci_device *pci ) { pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( rtl, 0, sizeof ( *rtl ) ); - rtl->dma = &pci->dma; - realtek_init_ring ( &rtl->tx.ring, RTL_NUM_TX_DESC, RTL_TNPDS ); - realtek_init_ring ( &rtl->rx.ring, RTL_NUM_RX_DESC, RTL_RDSAR ); + realtek_init_ring ( &rtl->tx, RTL_NUM_TX_DESC, RTL_TNPDS ); + realtek_init_ring ( &rtl->rx, RTL_NUM_RX_DESC, RTL_RDSAR ); /* Fix up PCI device */ adjust_pci_device ( pci ); @@ -1142,6 +1122,9 @@ static int realtek_probe ( struct pci_device *pci ) { goto err_ioremap; } + /* Configure DMA */ + rtl->dma = &pci->dma; + /* Reset the NIC */ if ( ( rc = realtek_reset ( rtl ) ) != 0 ) goto err_reset; diff --git a/src/drivers/net/realtek.h b/src/drivers/net/realtek.h index c7cb7e422..d4642fd76 100644 --- a/src/drivers/net/realtek.h +++ b/src/drivers/net/realtek.h @@ -274,24 +274,6 @@ realtek_init_ring ( struct realtek_ring *ring, unsigned int count, ring->reg = reg; } -/** Transmit ring */ -struct realtek_tx_ring { - /** Descriptor ring */ - struct realtek_ring ring; - /** DMA mappings */ - struct dma_mapping map[RTL_NUM_TX_DESC]; -}; - -/** Receive ring */ -struct realtek_rx_ring { - /** Descriptor ring */ - struct realtek_ring ring; - /** I/O buffers */ - struct io_buffer *iobuf[RTL_NUM_RX_DESC]; - /** DMA mappings */ - struct dma_mapping map[RTL_NUM_RX_DESC]; -}; - /** Receive buffer (legacy mode *) */ struct realtek_rx_buffer { /** Buffer */ @@ -327,9 +309,11 @@ struct realtek_nic { unsigned int tppoll; /** Transmit descriptor ring */ - struct realtek_tx_ring tx; + struct realtek_ring tx; /** Receive descriptor ring */ - struct realtek_rx_ring rx; + struct realtek_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[RTL_NUM_RX_DESC]; /** Receive buffer (legacy mode) */ struct realtek_rx_buffer rxbuf; }; diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index 842c9d6ef..b3fa24e47 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -12,7 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include @@ -385,25 +384,4 @@ dma_set_mask_64bit ( struct dma_device *dma ) { dma_set_mask ( dma, ~( ( physaddr_t ) 0 ) ); } -/** - * Map I/O buffer for transmitting data to device - * - * @v dma DMA device - * @v map DMA mapping to fill in - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static inline __always_inline int -dma_map_tx_iob ( struct dma_device *dma, struct dma_mapping *map, - struct io_buffer *iobuf ) { - - /* Map I/O buffer */ - return dma_map ( dma, map, virt_to_phys ( iobuf->data ), - iob_len ( iobuf ), DMA_TX ); -} - -extern struct io_buffer * dma_alloc_rx_iob ( struct dma_device *dma, - struct dma_mapping *map, - size_t len ); - #endif /* _IPXE_DMA_H */ diff --git a/src/include/ipxe/iobuf.h b/src/include/ipxe/iobuf.h index b40ade350..630a7753c 100644 --- a/src/include/ipxe/iobuf.h +++ b/src/include/ipxe/iobuf.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include /** * Minimum I/O buffer length @@ -38,6 +39,9 @@ struct io_buffer { */ struct list_head list; + /** DMA mapping */ + struct dma_mapping map; + /** Start of the buffer */ void *head; /** Start of data */ @@ -210,10 +214,61 @@ static inline void iob_populate ( struct io_buffer *iobuf, (iobuf) = NULL; \ __iobuf; } ) +/** + * Map I/O buffer for transmit DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @ret rc Return status code + */ +static inline __always_inline int iob_map_tx ( struct io_buffer *iobuf, + struct dma_device *dma ) { + return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), + iob_len ( iobuf ), DMA_TX ); +} + +/** + * Map empty I/O buffer for receive DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @ret rc Return status code + */ +static inline __always_inline int iob_map_rx ( struct io_buffer *iobuf, + struct dma_device *dma ) { + assert ( iob_len ( iobuf ) == 0 ); + return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), + iob_tailroom ( iobuf ), DMA_RX ); +} + +/** + * Get I/O buffer DMA address + * + * @v iobuf I/O buffer + * @ret addr DMA address + */ +static inline __always_inline physaddr_t iob_dma ( struct io_buffer *iobuf ) { + return dma ( &iobuf->map, iobuf->data ); +} + +/** + * Unmap I/O buffer for DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @ret rc Return status code + */ +static inline __always_inline void iob_unmap ( struct io_buffer *iobuf ) { + dma_unmap ( &iobuf->map ); +} + extern struct io_buffer * __malloc alloc_iob_raw ( size_t len, size_t align, size_t offset ); extern struct io_buffer * __malloc alloc_iob ( size_t len ); extern void free_iob ( struct io_buffer *iobuf ); +extern struct io_buffer * __malloc alloc_rx_iob ( size_t len, + struct dma_device *dma ); +extern void free_rx_iob ( struct io_buffer *iobuf ); extern void iob_pad ( struct io_buffer *iobuf, size_t min_len ); extern int iob_ensure_headroom ( struct io_buffer *iobuf, size_t len ); extern struct io_buffer * iob_concatenate ( struct list_head *list ); diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index d498ab697..b9c651c71 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -246,6 +246,10 @@ struct net_device_operations { * * This method is guaranteed to be called only when the device * is open. + * + * If the network device has an associated DMA device, then + * the I/O buffer will be automatically mapped for transmit + * DMA. */ int ( * transmit ) ( struct net_device *netdev, struct io_buffer *iobuf ); @@ -358,6 +362,8 @@ struct net_device { char name[NETDEV_NAME_LEN]; /** Underlying hardware device */ struct device *dev; + /** DMA device */ + struct dma_device *dma; /** Network device operations */ struct net_device_operations *op; diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 7687ffb43..8c30c9514 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -335,6 +335,7 @@ static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map, int rc; /* Sanity check */ + assert ( map->dma == NULL ); assert ( map->offset == 0 ); assert ( map->token == NULL ); @@ -409,6 +410,7 @@ static void efipci_dma_unmap ( struct dma_device *dma, pci_io->Unmap ( pci_io, map->token ); /* Clear mapping */ + map->dma = NULL; map->offset = 0; map->token = NULL; diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 3b02e64bd..f3feca26b 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -307,6 +307,12 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { if ( ( rc = inject_fault ( NETDEV_DISCARD_RATE ) ) != 0 ) goto err; + /* Map for DMA, if required */ + if ( netdev->dma && ( ! dma_mapped ( &iobuf->map ) ) ) { + if ( ( rc = iob_map_tx ( iobuf, netdev->dma ) ) != 0 ) + goto err; + } + /* Transmit packet */ if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 ) goto err; @@ -340,6 +346,9 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { * Failure to do this will cause the retransmitted packet to be * immediately redeferred (which will result in out-of-order * transmissions and other nastiness). + * + * I/O buffers that have been mapped for DMA will remain mapped while + * present in the deferred transmit queue. */ void netdev_tx_defer ( struct net_device *netdev, struct io_buffer *iobuf ) { @@ -365,6 +374,9 @@ void netdev_tx_defer ( struct net_device *netdev, struct io_buffer *iobuf ) { * * The packet is discarded and a TX error is recorded. This function * takes ownership of the I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_tx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { @@ -379,6 +391,10 @@ void netdev_tx_err ( struct net_device *netdev, netdev->name, iobuf, strerror ( rc ) ); } + /* Unmap I/O buffer, if required */ + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Discard packet */ free_iob ( iobuf ); } @@ -466,6 +482,9 @@ static void netdev_tx_flush ( struct net_device *netdev ) { * * The packet is added to the network device's RX queue. This * function takes ownership of the I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { int rc; @@ -479,6 +498,10 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { return; } + /* Unmap I/O buffer, if required */ + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Enqueue packet */ list_add_tail ( &iobuf->list, &netdev->rx_queue ); @@ -497,6 +520,9 @@ void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ) { * takes ownership of the I/O buffer. @c iobuf may be NULL if, for * example, the net device wishes to report an error due to being * unable to allocate an I/O buffer. + * + * The I/O buffer will be automatically unmapped for DMA, if + * applicable. */ void netdev_rx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ) { @@ -504,6 +530,10 @@ void netdev_rx_err ( struct net_device *netdev, DBGC ( netdev, "NETDEV %s failed to receive %p: %s\n", netdev->name, iobuf, strerror ( rc ) ); + /* Unmap I/O buffer, if required */ + if ( iobuf && dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); + /* Discard packet */ free_iob ( iobuf ); @@ -1178,6 +1208,8 @@ static unsigned int net_discard ( void ) { /* Discard first deferred packet */ list_del ( &iobuf->list ); + if ( dma_mapped ( &iobuf->map ) ) + iob_unmap ( iobuf ); free_iob ( iobuf ); /* Report discard */ -- cgit v1.2.3-55-g7522 From 6e01b74a8ac6a3c3c6806ae286df033f71962f9a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 29 Nov 2020 10:55:14 +0000 Subject: [dma] Provide dma_umalloc() for allocating large DMA-coherent buffers Some devices (e.g. xHCI USB host controllers) may require the use of large areas of host memory for private use by the device. These allocations cannot be satisfied from iPXE's limited heap space, and so are currently allocated using umalloc() which will allocate external system memory (and alter the system memory map as needed). Provide dma_umalloc() to provide such allocations as part of the DMA API, since there is otherwise no way to guarantee that the allocated regions are usable for coherent DMA. Signed-off-by: Michael Brown --- src/core/dma.c | 39 +++++++++++++++++++ src/include/ipxe/dma.h | 93 +++++++++++++++++++++++++++++++++++++++++++++ src/interface/efi/efi_pci.c | 34 +++++++++++++++++ 3 files changed, 166 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/core/dma.c b/src/core/dma.c index e5fa3f323..5d6868216 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -44,6 +44,8 @@ PROVIDE_DMAAPI_INLINE ( flat, dma_map ); PROVIDE_DMAAPI_INLINE ( flat, dma_unmap ); PROVIDE_DMAAPI_INLINE ( flat, dma_alloc ); PROVIDE_DMAAPI_INLINE ( flat, dma_free ); +PROVIDE_DMAAPI_INLINE ( flat, dma_umalloc ); +PROVIDE_DMAAPI_INLINE ( flat, dma_ufree ); PROVIDE_DMAAPI_INLINE ( flat, dma_set_mask ); PROVIDE_DMAAPI_INLINE ( flat, dma_phys ); @@ -119,6 +121,41 @@ static void dma_op_free ( struct dma_mapping *map, void *addr, size_t len ) { dma->op->free ( dma, map, addr, len ); } +/** + * Allocate and map DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping to fill in + * @v len Length of buffer + * @v align Physical alignment + * @ret addr Buffer address, or NULL on error + */ +static userptr_t dma_op_umalloc ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align ) { + struct dma_operations *op = dma->op; + + if ( ! op ) + return UNULL; + return op->umalloc ( dma, map, len, align ); +} + +/** + * Unmap and free DMA-coherent buffer from external (user) memory + * + * @v map DMA mapping + * @v addr Buffer address + * @v len Length of buffer + */ +static void dma_op_ufree ( struct dma_mapping *map, userptr_t addr, + size_t len ) { + struct dma_device *dma = map->dma; + + assert ( dma != NULL ); + assert ( dma->op != NULL ); + dma->op->ufree ( dma, map, addr, len ); +} + /** * Set addressable space mask * @@ -136,5 +173,7 @@ PROVIDE_DMAAPI ( op, dma_map, dma_op_map ); PROVIDE_DMAAPI ( op, dma_unmap, dma_op_unmap ); PROVIDE_DMAAPI ( op, dma_alloc, dma_op_alloc ); PROVIDE_DMAAPI ( op, dma_free, dma_op_free ); +PROVIDE_DMAAPI ( op, dma_umalloc, dma_op_umalloc ); +PROVIDE_DMAAPI ( op, dma_ufree, dma_op_ufree ); PROVIDE_DMAAPI ( op, dma_set_mask, dma_op_set_mask ); PROVIDE_DMAAPI_INLINE ( op, dma_phys ); diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index b3fa24e47..385e4baf7 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -13,6 +13,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #ifdef DMAAPI_OP @@ -96,6 +97,28 @@ struct dma_operations { */ void ( * free ) ( struct dma_device *dma, struct dma_mapping *map, void *addr, size_t len ); + /** + * Allocate and map DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping to fill in + * @v len Length of buffer + * @v align Physical alignment + * @ret addr Buffer address, or NULL on error + */ + userptr_t ( * umalloc ) ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align ); + /** + * Unmap and free DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping + * @v addr Buffer address + * @v len Length of buffer + */ + void ( * ufree ) ( struct dma_device *dma, struct dma_mapping *map, + userptr_t addr, size_t len ); /** * Set addressable space mask * @@ -233,6 +256,55 @@ DMAAPI_INLINE ( flat, dma_free ) ( struct dma_mapping *map, } } +/** + * Allocate and map DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping to fill in + * @v len Length of buffer + * @v align Physical alignment + * @ret addr Buffer address, or NULL on error + */ +static inline __always_inline userptr_t +DMAAPI_INLINE ( flat, dma_umalloc ) ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align __unused ) { + userptr_t addr; + + /* Allocate buffer */ + addr = umalloc ( len ); + + /* Increment mapping count (for debugging) */ + if ( DBG_LOG && addr ) { + map->dma = dma; + dma->mapped++; + } + + return addr; +} + +/** + * Unmap and free DMA-coherent buffer from external (user) memory + * + * @v map DMA mapping + * @v addr Buffer address + * @v len Length of buffer + */ +static inline __always_inline void +DMAAPI_INLINE ( flat, dma_ufree ) ( struct dma_mapping *map, + userptr_t addr, size_t len __unused ) { + + /* Free buffer */ + ufree ( addr ); + + /* Decrement mapping count (for debugging) */ + if ( DBG_LOG ) { + assert ( map->dma != NULL ); + map->dma->mapped--; + map->dma = NULL; + } +} + /** * Set addressable space mask * @@ -316,6 +388,27 @@ void * dma_alloc ( struct dma_device *dma, struct dma_mapping *map, */ void dma_free ( struct dma_mapping *map, void *addr, size_t len ); +/** + * Allocate and map DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping to fill in + * @v len Length of buffer + * @v align Physical alignment + * @ret addr Buffer address, or NULL on error + */ +userptr_t dma_umalloc ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ); + +/** + * Unmap and free DMA-coherent buffer from external (user) memory + * + * @v map DMA mapping + * @v addr Buffer address + * @v len Length of buffer + */ +void dma_ufree ( struct dma_mapping *map, userptr_t addr, size_t len ); + /** * Set addressable space mask * diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 9f6bf952b..6b32fd6a9 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -504,6 +504,38 @@ static void efipci_dma_free ( struct dma_device *dma, struct dma_mapping *map, dma->allocated--; } +/** + * Allocate and map DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping to fill in + * @v len Length of buffer + * @v align Physical alignment + * @ret addr Buffer address, or NULL on error + */ +static userptr_t efipci_dma_umalloc ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align ) { + void *addr; + + addr = efipci_dma_alloc ( dma, map, len, align ); + return virt_to_user ( addr ); +} + +/** + * Unmap and free DMA-coherent buffer from external (user) memory + * + * @v dma DMA device + * @v map DMA mapping + * @v addr Buffer address + * @v len Length of buffer + */ +static void efipci_dma_ufree ( struct dma_device *dma, struct dma_mapping *map, + userptr_t addr, size_t len ) { + + efipci_dma_free ( dma, map, user_to_virt ( addr, 0 ), len ); +} + /** * Set addressable space mask * @@ -542,6 +574,8 @@ static struct dma_operations efipci_dma_operations = { .unmap = efipci_dma_unmap, .alloc = efipci_dma_alloc, .free = efipci_dma_free, + .umalloc = efipci_dma_umalloc, + .ufree = efipci_dma_ufree, .set_mask = efipci_dma_set_mask, }; -- cgit v1.2.3-55-g7522 From 13a6d172964667646b1b3ad382470aca141c2d42 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 25 Nov 2020 11:24:41 +0000 Subject: [xhci] Update driver to use DMA API Signed-off-by: Michael Brown --- src/drivers/usb/xhci.c | 223 +++++++++++++++++++++++++++++------------------ src/drivers/usb/xhci.h | 43 +++++++-- src/include/ipxe/iobuf.h | 22 ++++- 3 files changed, 193 insertions(+), 95 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index 7f55a90f2..7bc2e356e 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -31,7 +31,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include #include @@ -294,9 +293,9 @@ static void xhci_init ( struct xhci_device *xhci, void *regs ) { /* Read structural parameters 2 */ hcsparams2 = readl ( xhci->cap + XHCI_CAP_HCSPARAMS2 ); - xhci->scratchpads = XHCI_HCSPARAMS2_SCRATCHPADS ( hcsparams2 ); + xhci->scratch.count = XHCI_HCSPARAMS2_SCRATCHPADS ( hcsparams2 ); DBGC2 ( xhci, "XHCI %s needs %d scratchpads\n", - xhci->name, xhci->scratchpads ); + xhci->name, xhci->scratch.count ); /* Read capability parameters 1 */ hccparams1 = readl ( xhci->cap + XHCI_CAP_HCCPARAMS1 ); @@ -918,27 +917,29 @@ static int xhci_dcbaa_alloc ( struct xhci_device *xhci ) { * align on its own size (rounded up to a power of two and * with a minimum of 64 bytes). */ - len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) ); - xhci->dcbaa = malloc_phys ( len, xhci_align ( len ) ); - if ( ! xhci->dcbaa ) { + len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) ); + xhci->dcbaa.context = dma_alloc ( xhci->dma, &xhci->dcbaa.map, len, + xhci_align ( len ) ); + if ( ! xhci->dcbaa.context ) { DBGC ( xhci, "XHCI %s could not allocate DCBAA\n", xhci->name ); rc = -ENOMEM; goto err_alloc; } - memset ( xhci->dcbaa, 0, len ); + memset ( xhci->dcbaa.context, 0, len ); /* Program DCBAA pointer */ - dcbaap = virt_to_phys ( xhci->dcbaa ); + dcbaap = dma ( &xhci->dcbaa.map, xhci->dcbaa.context ); if ( ( rc = xhci_writeq ( xhci, dcbaap, xhci->op + XHCI_OP_DCBAAP ) ) != 0 ) goto err_writeq; - DBGC2 ( xhci, "XHCI %s DCBAA at [%08lx,%08lx)\n", - xhci->name, dcbaap, ( dcbaap + len ) ); + DBGC2 ( xhci, "XHCI %s DCBAA at [%08lx,%08lx)\n", xhci->name, + virt_to_phys ( xhci->dcbaa.context ), + ( virt_to_phys ( xhci->dcbaa.context ) + len ) ); return 0; err_writeq: - free_phys ( xhci->dcbaa, len ); + dma_free ( &xhci->dcbaa.map, xhci->dcbaa.context, len ); err_alloc: return rc; } @@ -954,14 +955,14 @@ static void xhci_dcbaa_free ( struct xhci_device *xhci ) { /* Sanity check */ for ( i = 0 ; i <= xhci->slots ; i++ ) - assert ( xhci->dcbaa[i] == 0 ); + assert ( xhci->dcbaa.context[i] == 0 ); /* Clear DCBAA pointer */ xhci_writeq ( xhci, 0, xhci->op + XHCI_OP_DCBAAP ); /* Free DCBAA */ - len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa[0] ) ); - free_phys ( xhci->dcbaa, len ); + len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) ); + dma_free ( &xhci->dcbaa.map, xhci->dcbaa.context, len ); } /****************************************************************************** @@ -978,32 +979,34 @@ static void xhci_dcbaa_free ( struct xhci_device *xhci ) { * @ret rc Return status code */ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { + struct xhci_scratchpad *scratch = &xhci->scratch; + size_t buffer_len; size_t array_len; - size_t len; - physaddr_t phys; + physaddr_t addr; unsigned int i; int rc; /* Do nothing if no scratchpad buffers are used */ - if ( ! xhci->scratchpads ) + if ( ! scratch->count ) return 0; - /* Allocate scratchpads */ - len = ( xhci->scratchpads * xhci->pagesize ); - xhci->scratchpad = umalloc ( len ); - if ( ! xhci->scratchpad ) { + /* Allocate scratchpad buffers */ + buffer_len = ( scratch->count * xhci->pagesize ); + scratch->buffer = dma_umalloc ( xhci->dma, &scratch->buffer_map, + buffer_len, xhci->pagesize ); + if ( ! scratch->buffer ) { DBGC ( xhci, "XHCI %s could not allocate scratchpad buffers\n", xhci->name ); rc = -ENOMEM; goto err_alloc; } - memset_user ( xhci->scratchpad, 0, 0, len ); + memset_user ( scratch->buffer, 0, 0, buffer_len ); /* Allocate scratchpad array */ - array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] )); - xhci->scratchpad_array = - malloc_phys ( array_len, xhci_align ( array_len ) ); - if ( ! xhci->scratchpad_array ) { + array_len = ( scratch->count * sizeof ( scratch->array[0] ) ); + scratch->array = dma_alloc ( xhci->dma, &scratch->array_map, + array_len, xhci_align ( array_len ) ); + if ( ! scratch->array ) { DBGC ( xhci, "XHCI %s could not allocate scratchpad buffer " "array\n", xhci->name ); rc = -ENOMEM; @@ -1011,25 +1014,28 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { } /* Populate scratchpad array */ - for ( i = 0 ; i < xhci->scratchpads ; i++ ) { - phys = user_to_phys ( xhci->scratchpad, ( i * xhci->pagesize )); - xhci->scratchpad_array[i] = phys; + addr = dma_phys ( &scratch->buffer_map, + user_to_phys ( scratch->buffer, 0 ) ); + for ( i = 0 ; i < scratch->count ; i++ ) { + scratch->array[i] = cpu_to_le64 ( addr ); + addr += xhci->pagesize; } /* Set scratchpad array pointer */ - assert ( xhci->dcbaa != NULL ); - xhci->dcbaa[0] = cpu_to_le64 ( virt_to_phys ( xhci->scratchpad_array )); + assert ( xhci->dcbaa.context != NULL ); + xhci->dcbaa.context[0] = cpu_to_le64 ( dma ( &scratch->array_map, + scratch->array ) ); DBGC2 ( xhci, "XHCI %s scratchpad [%08lx,%08lx) array [%08lx,%08lx)\n", - xhci->name, user_to_phys ( xhci->scratchpad, 0 ), - user_to_phys ( xhci->scratchpad, len ), - virt_to_phys ( xhci->scratchpad_array ), - ( virt_to_phys ( xhci->scratchpad_array ) + array_len ) ); + xhci->name, user_to_phys ( scratch->buffer, 0 ), + user_to_phys ( scratch->buffer, buffer_len ), + virt_to_phys ( scratch->array ), + ( virt_to_phys ( scratch->array ) + array_len ) ); return 0; - free_phys ( xhci->scratchpad_array, array_len ); + dma_free ( &scratch->array_map, scratch->array, array_len ); err_alloc_array: - ufree ( xhci->scratchpad ); + dma_ufree ( &scratch->buffer_map, scratch->buffer, buffer_len ); err_alloc: return rc; } @@ -1040,22 +1046,25 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { * @v xhci xHCI device */ static void xhci_scratchpad_free ( struct xhci_device *xhci ) { + struct xhci_scratchpad *scratch = &xhci->scratch; size_t array_len; + size_t buffer_len; /* Do nothing if no scratchpad buffers are used */ - if ( ! xhci->scratchpads ) + if ( ! scratch->count ) return; /* Clear scratchpad array pointer */ - assert ( xhci->dcbaa != NULL ); - xhci->dcbaa[0] = 0; + assert ( xhci->dcbaa.context != NULL ); + xhci->dcbaa.context[0] = 0; /* Free scratchpad array */ - array_len = ( xhci->scratchpads * sizeof ( xhci->scratchpad_array[0] )); - free_phys ( xhci->scratchpad_array, array_len ); + array_len = ( scratch->count * sizeof ( scratch->array[0] ) ); + dma_free ( &scratch->array_map, scratch->array, array_len ); - /* Free scratchpads */ - ufree ( xhci->scratchpad ); + /* Free scratchpad buffers */ + buffer_len = ( scratch->count * xhci->pagesize ); + dma_ufree ( &scratch->buffer_map, scratch->buffer, buffer_len ); } /****************************************************************************** @@ -1202,7 +1211,8 @@ static int xhci_ring_alloc ( struct xhci_device *xhci, } /* Allocate TRBs */ - ring->trb = malloc_phys ( ring->len, xhci_align ( ring->len ) ); + ring->trb = dma_alloc ( xhci->dma, &ring->map, ring->len, + xhci_align ( ring->len ) ); if ( ! ring->trb ) { rc = -ENOMEM; goto err_alloc_trb; @@ -1211,14 +1221,14 @@ static int xhci_ring_alloc ( struct xhci_device *xhci, /* Initialise Link TRB */ link = &ring->trb[count].link; - link->next = cpu_to_le64 ( virt_to_phys ( ring->trb ) ); + link->next = cpu_to_le64 ( dma ( &ring->map, ring->trb ) ); link->flags = XHCI_TRB_TC; link->type = XHCI_TRB_LINK; ring->link = link; return 0; - free_phys ( ring->trb, ring->len ); + dma_free ( &ring->map, ring->trb, ring->len ); err_alloc_trb: free ( ring->iobuf ); err_alloc_iobuf: @@ -1256,7 +1266,7 @@ static void xhci_ring_free ( struct xhci_trb_ring *ring ) { assert ( ring->iobuf[i] == NULL ); /* Free TRBs */ - free_phys ( ring->trb, ring->len ); + dma_free ( &ring->map, ring->trb, ring->len ); /* Free I/O buffers */ free ( ring->iobuf ); @@ -1422,13 +1432,14 @@ static int xhci_command_alloc ( struct xhci_device *xhci ) { goto err_ring_alloc; /* Program command ring control register */ - crp = virt_to_phys ( xhci->command.trb ); + crp = dma ( &xhci->command.map, xhci->command.trb ); if ( ( rc = xhci_writeq ( xhci, ( crp | XHCI_CRCR_RCS ), xhci->op + XHCI_OP_CRCR ) ) != 0 ) goto err_writeq; - DBGC2 ( xhci, "XHCI %s CRCR at [%08lx,%08lx)\n", - xhci->name, crp, ( crp + xhci->command.len ) ); + DBGC2 ( xhci, "XHCI %s CRCR at [%08lx,%08lx)\n", xhci->name, + virt_to_phys ( xhci->command.trb ), + ( virt_to_phys ( xhci->command.trb ) + xhci->command.len ) ); return 0; err_writeq: @@ -1469,7 +1480,8 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { /* Allocate event ring */ count = ( 1 << XHCI_EVENT_TRBS_LOG2 ); len = ( count * sizeof ( event->trb[0] ) ); - event->trb = malloc_phys ( len, xhci_align ( len ) ); + event->trb = dma_alloc ( xhci->dma, &event->trb_map, len, + xhci_align ( len ) ); if ( ! event->trb ) { rc = -ENOMEM; goto err_alloc_trb; @@ -1477,22 +1489,25 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { memset ( event->trb, 0, len ); /* Allocate event ring segment table */ - event->segment = malloc_phys ( sizeof ( event->segment[0] ), - xhci_align ( sizeof(event->segment[0]))); + event->segment = dma_alloc ( xhci->dma, &event->segment_map, + sizeof ( event->segment[0] ), + xhci_align ( sizeof (event->segment[0]))); if ( ! event->segment ) { rc = -ENOMEM; goto err_alloc_segment; } memset ( event->segment, 0, sizeof ( event->segment[0] ) ); - event->segment[0].base = cpu_to_le64 ( virt_to_phys ( event->trb ) ); + event->segment[0].base = cpu_to_le64 ( dma ( &event->trb_map, + event->trb ) ); event->segment[0].count = cpu_to_le32 ( count ); /* Program event ring registers */ writel ( 1, xhci->run + XHCI_RUN_ERSTSZ ( 0 ) ); - if ( ( rc = xhci_writeq ( xhci, virt_to_phys ( event->trb ), + if ( ( rc = xhci_writeq ( xhci, dma ( &event->trb_map, event->trb ), xhci->run + XHCI_RUN_ERDP ( 0 ) ) ) != 0 ) goto err_writeq_erdp; - if ( ( rc = xhci_writeq ( xhci, virt_to_phys ( event->segment ), + if ( ( rc = xhci_writeq ( xhci, + dma ( &event->segment_map, event->segment ), xhci->run + XHCI_RUN_ERSTBA ( 0 ) ) ) != 0 ) goto err_writeq_erstba; @@ -1501,16 +1516,17 @@ static int xhci_event_alloc ( struct xhci_device *xhci ) { ( virt_to_phys ( event->trb ) + len ), virt_to_phys ( event->segment ), ( virt_to_phys ( event->segment ) + - sizeof (event->segment[0] ) ) ); + sizeof ( event->segment[0] ) ) ); return 0; xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERSTBA ( 0 ) ); err_writeq_erstba: xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) ); err_writeq_erdp: - free_phys ( event->trb, len ); + dma_free ( &event->segment_map, event->segment, + sizeof ( event->segment[0] ) ); err_alloc_segment: - free_phys ( event->segment, sizeof ( event->segment[0] ) ); + dma_free ( &event->trb_map, event->trb, len ); err_alloc_trb: return rc; } @@ -1531,12 +1547,13 @@ static void xhci_event_free ( struct xhci_device *xhci ) { xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) ); /* Free event ring segment table */ - free_phys ( event->segment, sizeof ( event->segment[0] ) ); + dma_free ( &event->segment_map, event->segment, + sizeof ( event->segment[0] ) ); /* Free event ring */ count = ( 1 << XHCI_EVENT_TRBS_LOG2 ); len = ( count * sizeof ( event->trb[0] ) ); - free_phys ( event->trb, len ); + dma_free ( &event->trb_map, event->trb, len ); } /** @@ -1577,6 +1594,9 @@ static void xhci_transfer ( struct xhci_device *xhci, iobuf = xhci_dequeue_multi ( &endpoint->ring ); assert ( iobuf != NULL ); + /* Unmap I/O buffer */ + iob_unmap ( iobuf ); + /* Check for errors */ if ( ! ( ( trb->code == XHCI_CMPLT_SUCCESS ) || ( trb->code == XHCI_CMPLT_SHORT ) ) ) { @@ -1745,7 +1765,7 @@ static void xhci_event_poll ( struct xhci_device *xhci ) { /* Update dequeue pointer if applicable */ if ( consumed ) { - xhci_writeq ( xhci, virt_to_phys ( trb ), + xhci_writeq ( xhci, dma ( &event->trb_map, trb ), xhci->run + XHCI_RUN_ERDP ( 0 ) ); profile_stop ( &xhci_event_profiler ); } @@ -1774,7 +1794,7 @@ static void xhci_abort ( struct xhci_device *xhci ) { /* Reset the command ring control register */ xhci_ring_reset ( &xhci->command ); - crp = virt_to_phys ( xhci->command.trb ); + crp = dma ( &xhci->command.map, xhci->command.trb ); xhci_writeq ( xhci, ( crp | XHCI_CRCR_RCS ), xhci->op + XHCI_OP_CRCR ); } @@ -1942,13 +1962,15 @@ static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot, void *input ) ) { union xhci_trb trb; struct xhci_trb_context *context = &trb.context; + struct dma_mapping map; size_t len; void *input; int rc; /* Allocate an input context */ + memset ( &map, 0, sizeof ( map ) ); len = xhci_input_context_offset ( xhci, XHCI_CTX_END ); - input = malloc_phys ( len, xhci_align ( len ) ); + input = dma_alloc ( xhci->dma, &map, len, xhci_align ( len ) ); if ( ! input ) { rc = -ENOMEM; goto err_alloc; @@ -1961,7 +1983,7 @@ static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot, /* Construct command */ memset ( context, 0, sizeof ( *context ) ); context->type = type; - context->input = cpu_to_le64 ( virt_to_phys ( input ) ); + context->input = cpu_to_le64 ( dma ( &map, input ) ); context->slot = slot->id; /* Issue command and wait for completion */ @@ -1969,7 +1991,7 @@ static int xhci_context ( struct xhci_device *xhci, struct xhci_slot *slot, goto err_command; err_command: - free_phys ( input, len ); + dma_free ( &map, input, len ); err_alloc: return rc; } @@ -1986,6 +2008,7 @@ static void xhci_address_device_input ( struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint, void *input ) { + struct xhci_trb_ring *ring = &endpoint->ring; struct xhci_control_context *control_ctx; struct xhci_slot_context *slot_ctx; struct xhci_endpoint_context *ep_ctx; @@ -2011,7 +2034,7 @@ static void xhci_address_device_input ( struct xhci_device *xhci, ep_ctx->type = XHCI_EP_TYPE_CONTROL; ep_ctx->burst = endpoint->ep->burst; ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu ); - ep_ctx->dequeue = cpu_to_le64 ( virt_to_phys ( endpoint->ring.trb ) | + ep_ctx->dequeue = cpu_to_le64 ( dma ( &ring->map, ring->trb ) | XHCI_EP_DCS ); ep_ctx->trb_len = cpu_to_le16 ( XHCI_EP0_TRB_LEN ); } @@ -2057,6 +2080,7 @@ static void xhci_configure_endpoint_input ( struct xhci_device *xhci, struct xhci_slot *slot, struct xhci_endpoint *endpoint, void *input ) { + struct xhci_trb_ring *ring = &endpoint->ring; struct xhci_control_context *control_ctx; struct xhci_slot_context *slot_ctx; struct xhci_endpoint_context *ep_ctx; @@ -2079,7 +2103,7 @@ static void xhci_configure_endpoint_input ( struct xhci_device *xhci, ep_ctx->type = endpoint->type; ep_ctx->burst = endpoint->ep->burst; ep_ctx->mtu = cpu_to_le16 ( endpoint->ep->mtu ); - ep_ctx->dequeue = cpu_to_le64 ( virt_to_phys ( endpoint->ring.trb ) | + ep_ctx->dequeue = cpu_to_le64 ( dma ( &ring->map, ring->trb ) | XHCI_EP_DCS ); ep_ctx->trb_len = cpu_to_le16 ( endpoint->ep->mtu ); /* best guess */ } @@ -2297,6 +2321,7 @@ xhci_set_tr_dequeue_pointer ( struct xhci_device *xhci, unsigned int mask; unsigned int index; unsigned int dcs; + physaddr_t addr; int rc; /* Construct command */ @@ -2305,8 +2330,8 @@ xhci_set_tr_dequeue_pointer ( struct xhci_device *xhci, mask = ring->mask; dcs = ( ( ~( cons >> ring->shift ) ) & XHCI_EP_DCS ); index = ( cons & mask ); - dequeue->dequeue = - cpu_to_le64 ( virt_to_phys ( &ring->trb[index] ) | dcs ); + addr = dma ( &ring->map, &ring->trb[index] ); + dequeue->dequeue = cpu_to_le64 ( addr | dcs ); dequeue->slot = slot->id; dequeue->endpoint = endpoint->ctx; dequeue->type = XHCI_TRB_SET_TR_DEQUEUE_POINTER; @@ -2425,6 +2450,7 @@ static void xhci_endpoint_close ( struct usb_endpoint *ep ) { /* Cancel any incomplete transfers */ while ( xhci_ring_fill ( &endpoint->ring ) ) { iobuf = xhci_dequeue_multi ( &endpoint->ring ); + iob_unmap ( iobuf ); usb_complete_err ( ep, iobuf, -ECANCELED ); } @@ -2491,6 +2517,7 @@ static int xhci_endpoint_mtu ( struct usb_endpoint *ep ) { static int xhci_endpoint_message ( struct usb_endpoint *ep, struct io_buffer *iobuf ) { struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep ); + struct xhci_device *xhci = endpoint->xhci; struct usb_setup_packet *packet; unsigned int input; size_t len; @@ -2520,10 +2547,15 @@ static int xhci_endpoint_message ( struct usb_endpoint *ep, if ( len ) setup->direction = ( input ? XHCI_SETUP_IN : XHCI_SETUP_OUT ); + /* Map I/O buffer */ + if ( ( rc = iob_map ( iobuf, xhci->dma, len, + ( input ? DMA_RX : DMA_TX ) ) ) != 0 ) + goto err_map; + /* Construct data stage TRB, if applicable */ if ( len ) { data = &(trb++)->data; - data->data = cpu_to_le64 ( virt_to_phys ( iobuf->data ) ); + data->data = cpu_to_le64 ( iob_dma ( iobuf ) ); data->len = cpu_to_le32 ( len ); data->type = XHCI_TRB_DATA; data->direction = ( input ? XHCI_DATA_IN : XHCI_DATA_OUT ); @@ -2539,13 +2571,18 @@ static int xhci_endpoint_message ( struct usb_endpoint *ep, /* Enqueue TRBs */ if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs, ( trb - trbs ) ) ) != 0 ) - return rc; + goto err_enqueue; /* Ring the doorbell */ xhci_doorbell ( &endpoint->ring ); profile_stop ( &xhci_message_profiler ); return 0; + + err_enqueue: + iob_unmap ( iobuf ); + err_map: + return rc; } /** @@ -2579,12 +2616,13 @@ static unsigned int xhci_endpoint_count ( size_t len, int zlp ) { static int xhci_endpoint_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf, int zlp ) { struct xhci_endpoint *endpoint = usb_endpoint_get_hostdata ( ep ); - void *data = iobuf->data; + struct xhci_device *xhci = endpoint->xhci; size_t len = iob_len ( iobuf ); unsigned int count = xhci_endpoint_count ( len, zlp ); union xhci_trb trbs[count]; union xhci_trb *trb = trbs; struct xhci_trb_normal *normal; + physaddr_t data; unsigned int i; size_t trb_len; int rc; @@ -2592,6 +2630,13 @@ static int xhci_endpoint_stream ( struct usb_endpoint *ep, /* Profile stream transfers */ profile_start ( &xhci_stream_profiler ); + /* Map I/O buffer */ + if ( ( rc = iob_map ( iobuf, xhci->dma, len, + ( ( ep->address & USB_DIR_IN ) ? + DMA_RX : DMA_TX ) ) ) != 0 ) + goto err_map; + data = iob_dma ( iobuf ); + /* Construct normal TRBs */ memset ( &trbs, 0, sizeof ( trbs ) ); for ( i = 0 ; i < count ; i ++ ) { @@ -2603,7 +2648,7 @@ static int xhci_endpoint_stream ( struct usb_endpoint *ep, /* Construct normal TRB */ normal = &trb->normal; - normal->data = cpu_to_le64 ( virt_to_phys ( data ) ); + normal->data = cpu_to_le64 ( data ); normal->len = cpu_to_le32 ( trb_len ); normal->type = XHCI_TRB_NORMAL; normal->flags = XHCI_TRB_CH; @@ -2624,13 +2669,18 @@ static int xhci_endpoint_stream ( struct usb_endpoint *ep, /* Enqueue TRBs */ if ( ( rc = xhci_enqueue_multi ( &endpoint->ring, iobuf, trbs, count ) ) != 0 ) - return rc; + goto err_enqueue; /* Ring the doorbell */ xhci_doorbell ( &endpoint->ring ); profile_stop ( &xhci_stream_profiler ); return 0; + + err_enqueue: + iob_unmap ( iobuf ); + err_map: + return rc; } /****************************************************************************** @@ -2693,7 +2743,8 @@ static int xhci_device_open ( struct usb_device *usb ) { /* Allocate a device context */ len = xhci_device_context_offset ( xhci, XHCI_CTX_END ); - slot->context = malloc_phys ( len, xhci_align ( len ) ); + slot->context = dma_alloc ( xhci->dma, &slot->map, len, + xhci_align ( len ) ); if ( ! slot->context ) { rc = -ENOMEM; goto err_alloc_context; @@ -2701,16 +2752,17 @@ static int xhci_device_open ( struct usb_device *usb ) { memset ( slot->context, 0, len ); /* Set device context base address */ - assert ( xhci->dcbaa[id] == 0 ); - xhci->dcbaa[id] = cpu_to_le64 ( virt_to_phys ( slot->context ) ); + assert ( xhci->dcbaa.context[id] == 0 ); + xhci->dcbaa.context[id] = cpu_to_le64 ( dma ( &slot->map, + slot->context ) ); DBGC2 ( xhci, "XHCI %s slot %d device context [%08lx,%08lx) for %s\n", xhci->name, slot->id, virt_to_phys ( slot->context ), ( virt_to_phys ( slot->context ) + len ), usb->name ); return 0; - xhci->dcbaa[id] = 0; - free_phys ( slot->context, len ); + xhci->dcbaa.context[id] = 0; + dma_free ( &slot->map, slot->context, len ); err_alloc_context: xhci->slot[id] = NULL; free ( slot ); @@ -2750,8 +2802,8 @@ static void xhci_device_close ( struct usb_device *usb ) { /* Free slot */ if ( slot->context ) { - free_phys ( slot->context, len ); - xhci->dcbaa[id] = 0; + dma_free ( &slot->map, slot->context, len ); + xhci->dcbaa.context[id] = 0; } xhci->slot[id] = NULL; free ( slot ); @@ -3270,6 +3322,11 @@ static int xhci_probe ( struct pci_device *pci ) { /* Initialise xHCI device */ xhci_init ( xhci, xhci->regs ); + /* Configure DMA device */ + xhci->dma = &pci->dma; + if ( xhci->addr64 ) + dma_set_mask_64bit ( xhci->dma ); + /* Initialise USB legacy support and claim ownership */ xhci_legacy_init ( xhci ); xhci_legacy_claim ( xhci ); diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h index e996363ea..6e02d70e0 100644 --- a/src/drivers/usb/xhci.h +++ b/src/drivers/usb/xhci.h @@ -854,6 +854,8 @@ struct xhci_trb_ring { union xhci_trb *trb; /** Length of transfer request blocks */ size_t len; + /** DMA mapping */ + struct dma_mapping map; /** Link TRB (if applicable) */ struct xhci_trb_link *link; @@ -869,8 +871,12 @@ struct xhci_event_ring { unsigned int cons; /** Event ring segment table */ struct xhci_event_ring_segment *segment; + /** Event ring segment table DMA mapping */ + struct dma_mapping segment_map; /** Transfer request blocks */ union xhci_trb *trb; + /** Transfer request blocks DMA mapping */ + struct dma_mapping trb_map; }; /** @@ -1035,10 +1041,34 @@ struct xhci_pch { /** Invalid protocol speed ID values quirk */ #define XHCI_BAD_PSIV 0x0002 +/** Device context base address array */ +struct xhci_dcbaa { + /** Context base addresses */ + uint64_t *context; + /** DMA mapping */ + struct dma_mapping map; +}; + +/** Scratchpad buffer */ +struct xhci_scratchpad { + /** Number of page-sized scratchpad buffers */ + unsigned int count; + /** Scratchpad buffer area */ + userptr_t buffer; + /** Buffer DMA mapping */ + struct dma_mapping buffer_map; + /** Scratchpad array */ + uint64_t *array; + /** Array DMA mapping */ + struct dma_mapping array_map; +}; + /** An xHCI device */ struct xhci_device { /** Registers */ void *regs; + /** DMA device */ + struct dma_device *dma; /** Name */ const char *name; /** Quirks */ @@ -1060,9 +1090,6 @@ struct xhci_device { /** Number of ports */ unsigned int ports; - /** Number of page-sized scratchpad buffers */ - unsigned int scratchpads; - /** 64-bit addressing capability */ int addr64; /** Context size shift */ @@ -1077,12 +1104,10 @@ struct xhci_device { unsigned int legacy; /** Device context base address array */ - uint64_t *dcbaa; + struct xhci_dcbaa dcbaa; - /** Scratchpad buffer area */ - userptr_t scratchpad; - /** Scratchpad buffer array */ - uint64_t *scratchpad_array; + /** Scratchpad buffer */ + struct xhci_scratchpad scratch; /** Command ring */ struct xhci_trb_ring command; @@ -1111,6 +1136,8 @@ struct xhci_slot { unsigned int id; /** Slot context */ struct xhci_slot_context *context; + /** DMA mapping */ + struct dma_mapping map; /** Route string */ unsigned int route; /** Root hub port number */ diff --git a/src/include/ipxe/iobuf.h b/src/include/ipxe/iobuf.h index 630a7753c..3e079c064 100644 --- a/src/include/ipxe/iobuf.h +++ b/src/include/ipxe/iobuf.h @@ -214,6 +214,22 @@ static inline void iob_populate ( struct io_buffer *iobuf, (iobuf) = NULL; \ __iobuf; } ) +/** + * Map I/O buffer for DMA + * + * @v iobuf I/O buffer + * @v dma DMA device + * @v len Length to map + * @v flags Mapping flags + * @ret rc Return status code + */ +static inline __always_inline int iob_map ( struct io_buffer *iobuf, + struct dma_device *dma, + size_t len, int flags ) { + return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), + len, flags ); +} + /** * Map I/O buffer for transmit DMA * @@ -223,8 +239,7 @@ static inline void iob_populate ( struct io_buffer *iobuf, */ static inline __always_inline int iob_map_tx ( struct io_buffer *iobuf, struct dma_device *dma ) { - return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), - iob_len ( iobuf ), DMA_TX ); + return iob_map ( iobuf, dma, iob_len ( iobuf ), DMA_TX ); } /** @@ -237,8 +252,7 @@ static inline __always_inline int iob_map_tx ( struct io_buffer *iobuf, static inline __always_inline int iob_map_rx ( struct io_buffer *iobuf, struct dma_device *dma ) { assert ( iob_len ( iobuf ) == 0 ); - return dma_map ( dma, &iobuf->map, virt_to_phys ( iobuf->data ), - iob_tailroom ( iobuf ), DMA_RX ); + return iob_map ( iobuf, dma, iob_tailroom ( iobuf ), DMA_RX ); } /** -- cgit v1.2.3-55-g7522 From be49380f55da3d4b4de85e880a089553ce5f3b78 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 30 Nov 2020 16:34:32 +0000 Subject: [efi] Split out dbg_efi_opener() as a standalone function Allow external code to dump the information for an opened protocol information entry via DBG_EFI_OPENER() et al. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi.h | 22 ++++++++++++++++++++++ src/interface/efi/efi_debug.c | 39 ++++++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 15 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index 6d0c25674..c8c069c12 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -242,9 +242,19 @@ efi_devpath_text ( EFI_DEVICE_PATH_PROTOCOL *path ); extern const __attribute__ (( pure )) char * efi_handle_name ( EFI_HANDLE handle ); +extern void dbg_efi_opener ( EFI_HANDLE handle, EFI_GUID *protocol, + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener ); extern void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ); extern void dbg_efi_protocols ( EFI_HANDLE handle ); +#define DBG_EFI_OPENER_IF( level, handle, protocol, \ + opener ) do { \ + if ( DBG_ ## level ) { \ + dbg_efi_opener ( handle, protocol, \ + opener ); \ + } \ + } while ( 0 ) + #define DBG_EFI_OPENERS_IF( level, handle, protocol ) do { \ if ( DBG_ ## level ) { \ dbg_efi_openers ( handle, protocol ); \ @@ -257,6 +267,12 @@ extern void dbg_efi_protocols ( EFI_HANDLE handle ); } \ } while ( 0 ) +#define DBGC_EFI_OPENER_IF( level, id, ... ) do { \ + DBG_AC_IF ( level, id ); \ + DBG_EFI_OPENER_IF ( level, __VA_ARGS__ ); \ + DBG_DC_IF ( level ); \ + } while ( 0 ) + #define DBGC_EFI_OPENERS_IF( level, id, ... ) do { \ DBG_AC_IF ( level, id ); \ DBG_EFI_OPENERS_IF ( level, __VA_ARGS__ ); \ @@ -269,16 +285,22 @@ extern void dbg_efi_protocols ( EFI_HANDLE handle ); DBG_DC_IF ( level ); \ } while ( 0 ) +#define DBGC_EFI_OPENER( ... ) \ + DBGC_EFI_OPENER_IF ( LOG, ##__VA_ARGS__ ) #define DBGC_EFI_OPENERS( ... ) \ DBGC_EFI_OPENERS_IF ( LOG, ##__VA_ARGS__ ) #define DBGC_EFI_PROTOCOLS( ... ) \ DBGC_EFI_PROTOCOLS_IF ( LOG, ##__VA_ARGS__ ) +#define DBGC2_EFI_OPENER( ... ) \ + DBGC_EFI_OPENER_IF ( EXTRA, ##__VA_ARGS__ ) #define DBGC2_EFI_OPENERS( ... ) \ DBGC_EFI_OPENERS_IF ( EXTRA, ##__VA_ARGS__ ) #define DBGC2_EFI_PROTOCOLS( ... ) \ DBGC_EFI_PROTOCOLS_IF ( EXTRA, ##__VA_ARGS__ ) +#define DBGCP_EFI_OPENER( ... ) \ + DBGC_EFI_OPENER_IF ( PROFILE, ##__VA_ARGS__ ) #define DBGCP_EFI_OPENERS( ... ) \ DBGC_EFI_OPENERS_IF ( PROFILE, ##__VA_ARGS__ ) #define DBGCP_EFI_PROTOCOLS( ... ) \ diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index 7cff14614..6515b92c8 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -262,6 +262,28 @@ efi_open_attributes_name ( unsigned int attributes ) { return name; } +/** + * Print opened protocol information + * + * @v handle EFI handle + * @V protocol Protocol GUID + * @v opener Opened protocol information + */ +void dbg_efi_opener ( EFI_HANDLE handle, EFI_GUID *protocol, + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener ) { + + printf ( "HANDLE %s %s opened %dx (%s)", efi_handle_name ( handle ), + efi_guid_ntoa ( protocol ), opener->OpenCount, + efi_open_attributes_name ( opener->Attributes ) ); + printf ( " by %s", efi_handle_name ( opener->AgentHandle ) ); + if ( opener->ControllerHandle == handle ) { + printf ( "\n" ); + } else { + printf ( " for %s\n", + efi_handle_name ( opener->ControllerHandle ) ); + } +} + /** * Print list of openers of a given protocol on a given handle * @@ -271,7 +293,6 @@ efi_open_attributes_name ( unsigned int attributes ) { void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *openers; - EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener; UINTN count; unsigned int i; EFI_STATUS efirc; @@ -296,20 +317,8 @@ void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ) { } /* Dump list of openers */ - for ( i = 0 ; i < count ; i++ ) { - opener = &openers[i]; - printf ( "HANDLE %s %s opened %dx (%s)", - efi_handle_name ( handle ), - efi_guid_ntoa ( protocol ), opener->OpenCount, - efi_open_attributes_name ( opener->Attributes ) ); - printf ( " by %s", efi_handle_name ( opener->AgentHandle ) ); - if ( opener->ControllerHandle == handle ) { - printf ( "\n" ); - } else { - printf ( " for %s\n", - efi_handle_name ( opener->ControllerHandle ) ); - } - } + for ( i = 0 ; i < count ; i++ ) + dbg_efi_opener ( handle, protocol, &openers[i] ); /* Free list */ bs->FreePool ( openers ); -- cgit v1.2.3-55-g7522 From 63625b43e9009833183f1921ed3753ba35d9261f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 30 Nov 2020 17:08:58 +0000 Subject: [efi] Allow vetoing of drivers that cannot be unloaded Some UEFI drivers (observed with the "Usb Xhci Driver" on an HP EliteBook) are particularly badly behaved: they cannot be unloaded and will leave handles opened with BY_DRIVER attributes even after disconnecting the driver, thereby preventing a replacement iPXE driver from opening the handle. Allow such drivers to be vetoed by falling back to a brute-force mechanism that will disconnect the driver from all handles, uninstall the driver binding protocol (to prevent it from attaching to any new handles), and finally close any stray handles that the vetoed driver has left open. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_veto.h | 2 +- src/interface/efi/efi_veto.c | 315 +++++++++++++++++++++++++++++++++++++++- src/interface/efi/efiprefix.c | 4 +- 3 files changed, 312 insertions(+), 9 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_veto.h b/src/include/ipxe/efi/efi_veto.h index f0c225543..c9ecbb05c 100644 --- a/src/include/ipxe/efi/efi_veto.h +++ b/src/include/ipxe/efi/efi_veto.h @@ -8,6 +8,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -extern void efi_veto_unload ( void ); +extern void efi_veto ( void ); #endif /* _IPXE_EFI_VETO_H */ diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c index 79190e219..1f7cc712e 100644 --- a/src/interface/efi/efi_veto.c +++ b/src/interface/efi/efi_veto.c @@ -56,6 +56,310 @@ struct efi_veto { const char *manufacturer, const CHAR16 *name ); }; +/** + * Unload an EFI driver + * + * @v driver Driver binding handle + * @ret rc Return status code + */ +static int efi_veto_unload ( EFI_HANDLE driver ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_STATUS efirc; + int rc; + + /* Unload the driver */ + if ( ( efirc = bs->UnloadImage ( driver ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not unload: %s\n", + efi_handle_name ( driver ), strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Disconnect an EFI driver from all handles + * + * @v driver Driver binding handle + * @ret rc Return status code + */ +static int efi_veto_disconnect ( EFI_HANDLE driver ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE *handles; + EFI_HANDLE handle; + UINTN count; + unsigned int i; + EFI_STATUS efirc; + int rc; + + /* Enumerate all handles */ + if ( ( efirc = bs->LocateHandleBuffer ( AllHandles, NULL, NULL, + &count, &handles ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not enumerate handles: %s\n", + efi_handle_name ( driver ), strerror ( rc ) ); + goto err_list; + } + + /* Disconnect driver from all handles, in reverse order */ + for ( i = 0 ; i < count ; i++ ) { + handle = handles[ count - i - 1 ]; + efirc = bs->DisconnectController ( handle, driver, NULL ); + if ( ( efirc != 0 ) && ( efirc != EFI_NOT_FOUND ) ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not disconnect", + efi_handle_name ( driver ) ); + DBGC ( driver, " %s: %s\n", + efi_handle_name ( handle ), strerror ( rc ) ); + goto err_disconnect; + } + } + + /* Success */ + rc = 0; + DBGC2 ( driver, "EFIVETO %s disconnected all handles\n", + efi_handle_name ( driver ) ); + + err_disconnect: + bs->FreePool ( handles ); + err_list: + return rc; +} + +/** + * Uninstall an EFI driver binding protocol + * + * @v driver Driver binding handle + * @ret rc Return status code + */ +static int efi_veto_uninstall ( EFI_HANDLE driver ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_DRIVER_BINDING_PROTOCOL *binding; + void *interface; + } binding; + EFI_STATUS efirc; + int rc; + + /* Open driver binding protocol */ + if ( ( efirc = bs->OpenProtocol ( + driver, &efi_driver_binding_protocol_guid, + &binding.interface, efi_image_handle, driver, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not open driver binding " + "protocol: %s\n", efi_handle_name ( driver ), + strerror ( rc ) ); + return rc; + } + + /* Close driver binding protocol */ + bs->CloseProtocol ( driver, &efi_driver_binding_protocol_guid, + efi_image_handle, driver ); + + /* Uninstall driver binding protocol */ + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( + driver, &efi_driver_binding_protocol_guid, + binding.binding, NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not uninstall driver " + "binding protocol: %s\n", + efi_handle_name ( driver ), strerror ( rc ) ); + return rc; + } + + DBGC2 ( driver, "EFIVETO %s uninstalled driver binding protocol\n", + efi_handle_name ( driver ) ); + return 0; +} + +/** + * Close protocol on handle potentially opened by an EFI driver + * + * @v driver Driver binding handle + * @v handle Potentially opened handle + * @v protocol Opened protocol + * @ret rc Return status code + */ +static int efi_veto_close_protocol ( EFI_HANDLE driver, EFI_HANDLE handle, + EFI_GUID *protocol ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *openers; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener; + EFI_HANDLE controller; + UINTN count; + unsigned int i; + EFI_STATUS efirc; + int rc; + + /* Retrieve list of openers */ + if ( ( efirc = bs->OpenProtocolInformation ( handle, protocol, &openers, + &count ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not retrieve openers", + efi_handle_name ( driver ) ); + DBGC ( driver, " of %s %s: %s", efi_handle_name ( handle ), + efi_guid_ntoa ( protocol ), strerror ( rc ) ); + goto err_list; + } + + /* Close anything opened by this driver */ + for ( i = 0 ; i < count ; i++ ) { + opener = &openers[i]; + if ( opener->AgentHandle != driver ) + continue; + controller = opener->ControllerHandle; + DBGC_EFI_OPENER ( driver, handle, protocol, opener ); + if ( ( efirc = bs->CloseProtocol ( handle, protocol, driver, + controller ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not close stray open", + efi_handle_name ( driver ) ); + DBGC ( driver, " of %s: %s\n", + efi_handle_name ( handle ), strerror ( rc ) ); + goto err_close; + } + } + + /* Success */ + rc = 0; + + err_close: + bs->FreePool ( openers ); + err_list: + return rc; +} + +/** + * Close handle potentially opened by an EFI driver + * + * @v driver Driver binding handle + * @v handle Potentially opened handle + * @ret rc Return status code + */ +static int efi_veto_close_handle ( EFI_HANDLE driver, EFI_HANDLE handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_GUID **protocols; + UINTN count; + unsigned int i; + EFI_STATUS efirc; + int rc; + + /* Retrieve list of protocols */ + if ( ( efirc = bs->ProtocolsPerHandle ( handle, &protocols, + &count ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not retrieve protocols", + efi_handle_name ( driver ) ); + DBGC ( driver, " for %s: %s\n", + efi_handle_name ( handle ), strerror ( rc ) ); + goto err_list; + } + + /* Close each protocol */ + for ( i = 0 ; i < count ; i++ ) { + if ( ( rc = efi_veto_close_protocol ( driver, handle, + protocols[i] ) ) != 0 ) + goto err_close; + } + + /* Success */ + rc = 0; + + err_close: + bs->FreePool ( protocols ); + err_list: + return rc; +} + +/** + * Close all remaining handles opened by an EFI driver + * + * @v driver Driver binding handle + * @ret rc Return status code + */ +static int efi_veto_close ( EFI_HANDLE driver ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE *handles; + UINTN count; + unsigned int i; + EFI_STATUS efirc; + int rc; + + /* Enumerate all handles */ + if ( ( efirc = bs->LocateHandleBuffer ( AllHandles, NULL, NULL, + &count, &handles ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( driver, "EFIVETO %s could not enumerate handles: %s\n", + efi_handle_name ( driver ), strerror ( rc ) ); + goto err_list; + } + + /* Close each handle */ + for ( i = 0 ; i < count ; i++ ) { + if ( ( rc = efi_veto_close_handle ( driver, + handles[i] ) ) != 0 ) + goto err_close; + } + + /* Success */ + rc = 0; + DBGC2 ( driver, "EFIVETO %s closed all remaining handles\n", + efi_handle_name ( driver ) ); + + err_close: + bs->FreePool ( handles ); + err_list: + return rc; +} + +/** + * Terminate an EFI driver with extreme prejudice + * + * @v driver Driver binding handle + * @ret rc Return status code + */ +static int efi_veto_destroy ( EFI_HANDLE driver ) { + int rc; + + /* Disconnect driver from all handles */ + if ( ( rc = efi_veto_disconnect ( driver ) ) != 0 ) + return rc; + + /* Uninstall driver binding protocol */ + if ( ( rc = efi_veto_uninstall ( driver ) ) != 0 ) + return rc; + + /* Close any remaining opened handles */ + if ( ( rc = efi_veto_close ( driver ) ) != 0 ) + return rc; + + DBGC ( driver, "EFIVETO %s forcibly removed\n", + efi_handle_name ( driver ) ); + return 0; +} + +/** + * Veto an EFI driver + * + * @v driver Driver binding handle + * @ret rc Return status code + */ +static int efi_veto_driver ( EFI_HANDLE driver ) { + int rc; + + /* Try gracefully unloading the driver */ + if ( ( rc = efi_veto_unload ( driver ) ) == 0 ) + return 0; + + /* If that fails, use a hammer */ + if ( ( rc = efi_veto_destroy ( driver ) ) == 0 ) + return 0; + + return rc; +} + /** * Veto Dell Ip4ConfigDxe driver * @@ -201,10 +505,10 @@ static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer, } /** - * Unload any vetoed drivers + * Remove any vetoed drivers * */ -void efi_veto_unload ( void ) { +void efi_veto ( void ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_veto *veto; EFI_HANDLE *drivers; @@ -241,11 +545,10 @@ void efi_veto_unload ( void ) { } if ( ! veto ) continue; - DBGC ( driver, "EFIVETO unloading %s (%s)\n", + DBGC ( driver, "EFIVETO %s is vetoed (%s)\n", efi_handle_name ( driver ), veto->name ); - if ( ( efirc = bs->UnloadImage ( driver ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( driver, "EFIVETO could not unload %s: %s\n", + if ( ( rc = efi_veto_driver ( driver ) ) != 0 ) { + DBGC ( driver, "EFIVETO %s could not veto: %s\n", efi_handle_name ( driver ), strerror ( rc ) ); } } diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c index 14f36661f..3273b79d8 100644 --- a/src/interface/efi/efiprefix.c +++ b/src/interface/efi/efiprefix.c @@ -79,8 +79,8 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle, */ static int efi_probe ( struct root_device *rootdev __unused ) { - /* Unloaded any vetoed drivers */ - efi_veto_unload(); + /* Remove any vetoed drivers */ + efi_veto(); /* Connect our drivers */ return efi_driver_connect_all(); -- cgit v1.2.3-55-g7522 From 09fe2bbd343a46010e89d848e5887bfb5fc3f6f6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 7 Dec 2020 13:49:47 +0000 Subject: [interface] Provide intf_insert() to insert a filter interface Generalise the filter interface insertion logic from block_translate() and expose as intf_insert(), allowing a filter interface to be inserted on any existing interface. Signed-off-by: Michael Brown --- src/core/blocktrans.c | 4 +--- src/core/interface.c | 17 +++++++++++++++++ src/include/ipxe/interface.h | 2 ++ 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/core/blocktrans.c b/src/core/blocktrans.c index 3f32f9cf8..f9dcb95d2 100644 --- a/src/core/blocktrans.c +++ b/src/core/blocktrans.c @@ -242,9 +242,7 @@ int block_translate ( struct interface *block, userptr_t buffer, size_t size ) { } /* Attach to interfaces, mortalise self, and return */ - assert ( block->dest != &null_intf ); - intf_plug_plug ( &blktrans->xfer, block->dest ); - intf_plug_plug ( &blktrans->block, block ); + intf_insert ( block, &blktrans->block, &blktrans->xfer ); ref_put ( &blktrans->refcnt ); DBGC2 ( blktrans, "BLKTRANS %p created", blktrans ); diff --git a/src/core/interface.c b/src/core/interface.c index 05e7e4777..34a4180a5 100644 --- a/src/core/interface.c +++ b/src/core/interface.c @@ -390,6 +390,23 @@ void intfs_restart ( int rc, ... ) { va_end ( intfs ); } +/** + * Insert a filter interface + * + * @v intf Object interface + * @v upper Upper end of filter + * @v lower Lower end of filter + */ +void intf_insert ( struct interface *intf, struct interface *upper, + struct interface *lower ) { + struct interface *dest = intf->dest; + + intf_get ( dest ); + intf_plug_plug ( intf, upper ); + intf_plug_plug ( lower, dest ); + intf_put ( dest ); +} + /** * Poke an object interface * diff --git a/src/include/ipxe/interface.h b/src/include/ipxe/interface.h index 9281aeef5..19f58a4b4 100644 --- a/src/include/ipxe/interface.h +++ b/src/include/ipxe/interface.h @@ -169,6 +169,8 @@ extern void intfs_shutdown ( int rc, ... ) __attribute__ (( sentinel )); extern void intf_restart ( struct interface *intf, int rc ); extern void intfs_vrestart ( va_list intfs, int rc ); extern void intfs_restart ( int rc, ... ) __attribute__ (( sentinel )); +extern void intf_insert ( struct interface *intf, struct interface *upper, + struct interface *lower ); extern void intf_poke ( struct interface *intf, void ( type ) ( struct interface *intf ) ); -- cgit v1.2.3-55-g7522 From 2b6b02ee7eaad2539e26eb9507833aa3c1c9c15e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 7 Dec 2020 13:51:46 +0000 Subject: [tls] Use intf_insert() to add TLS to an interface Restructure the use of add_tls() to insert a TLS filter onto an existing interface. This allows for the possibility of using add_tls() to start TLS on an existing connection (as used in several protocols which will negotiate the choice to use TLS before the ClientHello is sent). Signed-off-by: Michael Brown --- src/include/ipxe/http.h | 4 +--- src/include/ipxe/tls.h | 3 +-- src/net/tcp/httpconn.c | 14 +++++++------- src/net/tcp/syslogs.c | 29 ++++++++++++++--------------- src/net/tls.c | 13 +++++++++---- 5 files changed, 32 insertions(+), 31 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/http.h b/src/include/ipxe/http.h index 0893c9537..117f174af 100644 --- a/src/include/ipxe/http.h +++ b/src/include/ipxe/http.h @@ -45,11 +45,9 @@ struct http_scheme { * * @v xfer Data transfer interface * @v name Host name - * @v next Next interface * @ret rc Return status code */ - int ( * filter ) ( struct interface *xfer, const char *name, - struct interface **next ); + int ( * filter ) ( struct interface *xfer, const char *name ); }; /** HTTP scheme table */ diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index febbdc589..2eaaadf20 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -378,7 +378,6 @@ struct tls_connection { /** RX I/O buffer alignment */ #define TLS_RX_ALIGN 16 -extern int add_tls ( struct interface *xfer, const char *name, - struct interface **next ); +extern int add_tls ( struct interface *xfer, const char *name ); #endif /* _IPXE_TLS_H */ diff --git a/src/net/tcp/httpconn.c b/src/net/tcp/httpconn.c index 5121ff6c2..2804e09d5 100644 --- a/src/net/tcp/httpconn.c +++ b/src/net/tcp/httpconn.c @@ -236,7 +236,6 @@ int http_connect ( struct interface *xfer, struct uri *uri ) { struct http_connection *conn; struct http_scheme *scheme; struct sockaddr_tcpip server; - struct interface *socket; unsigned int port; int rc; @@ -296,15 +295,16 @@ int http_connect ( struct interface *xfer, struct uri *uri ) { /* Open socket */ memset ( &server, 0, sizeof ( server ) ); server.st_port = htons ( port ); - socket = &conn->socket; - if ( scheme->filter && - ( ( rc = scheme->filter ( socket, uri->host, &socket ) ) != 0 ) ) - goto err_filter; - if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM, + if ( ( rc = xfer_open_named_socket ( &conn->socket, SOCK_STREAM, ( struct sockaddr * ) &server, uri->host, NULL ) ) != 0 ) goto err_open; + /* Add filter, if any */ + if ( scheme->filter && + ( ( rc = scheme->filter ( &conn->socket, uri->host ) ) != 0 ) ) + goto err_filter; + /* Attach to parent interface, mortalise self, and return */ intf_plug_plug ( &conn->xfer, xfer ); ref_put ( &conn->refcnt ); @@ -313,8 +313,8 @@ int http_connect ( struct interface *xfer, struct uri *uri ) { conn->scheme->name, conn->uri->host, port ); return 0; - err_open: err_filter: + err_open: DBGC2 ( conn, "HTTPCONN %p could not create %s://%s:%d: %s\n", conn, conn->scheme->name, conn->uri->host, port, strerror ( rc ) ); http_conn_close ( conn, rc ); diff --git a/src/net/tcp/syslogs.c b/src/net/tcp/syslogs.c index 0c07f86d5..b37605272 100644 --- a/src/net/tcp/syslogs.c +++ b/src/net/tcp/syslogs.c @@ -62,9 +62,10 @@ static struct sockaddr_tcpip logserver = { * @v intf Interface * @v rc Reason for close */ -static void syslogs_close ( struct interface *intf __unused, int rc ) { +static void syslogs_close ( struct interface *intf, int rc ) { DBG ( "SYSLOGS console disconnected: %s\n", strerror ( rc ) ); + intf_restart ( intf, rc ); } /** @@ -208,7 +209,6 @@ const struct setting syslogs_setting __setting ( SETTING_MISC, syslogs ) = { static int apply_syslogs_settings ( void ) { static char *old_server; char *server; - struct interface *socket; int rc; /* Fetch log server */ @@ -234,33 +234,32 @@ static int apply_syslogs_settings ( void ) { rc = 0; goto out_no_server; } - - /* Add TLS filter */ - if ( ( rc = add_tls ( &syslogs, server, &socket ) ) != 0 ) { - DBG ( "SYSLOGS cannot create TLS filter: %s\n", - strerror ( rc ) ); - goto err_add_tls; - } + DBG ( "SYSLOGS using log server %s\n", server ); /* Connect to log server */ - if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM, + if ( ( rc = xfer_open_named_socket ( &syslogs, SOCK_STREAM, (( struct sockaddr *) &logserver ), server, NULL ) ) != 0 ) { DBG ( "SYSLOGS cannot connect to log server: %s\n", strerror ( rc ) ); goto err_open_named_socket; } - DBG ( "SYSLOGS using log server %s\n", server ); + + /* Add TLS filter */ + if ( ( rc = add_tls ( &syslogs, server ) ) != 0 ) { + DBG ( "SYSLOGS cannot create TLS filter: %s\n", + strerror ( rc ) ); + goto err_add_tls; + } /* Record log server */ old_server = server; - server = NULL; - /* Success */ - rc = 0; + return 0; - err_open_named_socket: err_add_tls: + err_open_named_socket: + syslogs_close ( &syslogs, rc ); out_no_server: out_no_change: free ( server ); diff --git a/src/net/tls.c b/src/net/tls.c index ea827600f..482200650 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -3088,8 +3088,14 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { ****************************************************************************** */ -int add_tls ( struct interface *xfer, const char *name, - struct interface **next ) { +/** + * Add TLS on an interface + * + * @v xfer Data transfer interface + * @v name Host name + * @ret rc Return status code + */ +int add_tls ( struct interface *xfer, const char *name ) { struct tls_connection *tls; int rc; @@ -3133,8 +3139,7 @@ int add_tls ( struct interface *xfer, const char *name, tls_restart ( tls ); /* Attach to parent interface, mortalise self, and return */ - intf_plug_plug ( &tls->plainstream, xfer ); - *next = &tls->cipherstream; + intf_insert ( xfer, &tls->plainstream, &tls->cipherstream ); ref_put ( &tls->refcnt ); return 0; -- cgit v1.2.3-55-g7522 From 25b53afa5bbd7bc38c3ca060d9c70259db6d118a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 4 Dec 2020 15:56:13 +0000 Subject: [tls] Allow provision of a client certificate chain Use the existing certificate store to automatically append any available issuing certificates to the selected client certificate. Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 4 +- src/net/tls.c | 107 +++++++++++++++++++++++++++++++++++-------------- 2 files changed, 79 insertions(+), 32 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 2eaaadf20..a2d4f475b 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -319,8 +319,8 @@ struct tls_connection { struct digest_algorithm *handshake_digest; /** Digest algorithm context used for handshake verification */ uint8_t *handshake_ctx; - /** Client certificate (if used) */ - struct x509_certificate *cert; + /** Client certificate chain (if used) */ + struct x509_chain *certs; /** Secure renegotiation flag */ int secure_renegotiation; /** Verification data */ diff --git a/src/net/tls.c b/src/net/tls.c index 482200650..c42b4ddc7 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -378,7 +378,7 @@ static void free_tls ( struct refcnt *refcnt ) { list_del ( &iobuf->list ); free_iob ( iobuf ); } - x509_put ( tls->cert ); + x509_chain_put ( tls->certs ); x509_chain_put ( tls->chain ); /* Drop reference to session */ @@ -1148,40 +1148,56 @@ static int tls_send_client_hello ( struct tls_connection *tls ) { */ static int tls_send_certificate ( struct tls_connection *tls ) { struct { - uint32_t type_length; tls24_t length; - struct { - tls24_t length; - uint8_t data[ tls->cert->raw.len ]; - } __attribute__ (( packed )) certificates[1]; + uint8_t data[0]; } __attribute__ (( packed )) *certificate; + struct { + uint32_t type_length; + tls24_t length; + typeof ( *certificate ) certificates[0]; + } __attribute__ (( packed )) *certificates; + struct x509_link *link; + struct x509_certificate *cert; + size_t len; int rc; + /* Calculate length of client certificates */ + len = 0; + list_for_each_entry ( link, &tls->certs->links, list ) { + cert = link->cert; + len += ( sizeof ( *certificate ) + cert->raw.len ); + DBGC ( tls, "TLS %p sending client certificate %s\n", + tls, x509_name ( cert ) ); + } + /* Allocate storage for Certificate record (which may be too * large for the stack). */ - certificate = zalloc ( sizeof ( *certificate ) ); - if ( ! certificate ) + certificates = zalloc ( sizeof ( *certificates ) + len ); + if ( ! certificates ) return -ENOMEM_CERTIFICATE; /* Populate record */ - certificate->type_length = + certificates->type_length = ( cpu_to_le32 ( TLS_CERTIFICATE ) | - htonl ( sizeof ( *certificate ) - - sizeof ( certificate->type_length ) ) ); - tls_set_uint24 ( &certificate->length, - sizeof ( certificate->certificates ) ); - tls_set_uint24 ( &certificate->certificates[0].length, - sizeof ( certificate->certificates[0].data ) ); - memcpy ( certificate->certificates[0].data, - tls->cert->raw.data, - sizeof ( certificate->certificates[0].data ) ); + htonl ( sizeof ( *certificates ) + len - + sizeof ( certificates->type_length ) ) ); + tls_set_uint24 ( &certificates->length, len ); + certificate = &certificates->certificates[0]; + list_for_each_entry ( link, &tls->certs->links, list ) { + cert = link->cert; + tls_set_uint24 ( &certificate->length, cert->raw.len ); + memcpy ( certificate->data, cert->raw.data, cert->raw.len ); + certificate = ( ( ( void * ) certificate->data ) + + cert->raw.len ); + } /* Transmit record */ - rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) ); + rc = tls_send_handshake ( tls, certificates, + ( sizeof ( *certificates ) + len ) ); /* Free record */ - free ( certificate ); + free ( certificates ); return rc; } @@ -1238,7 +1254,7 @@ static int tls_send_client_key_exchange ( struct tls_connection *tls ) { */ static int tls_send_certificate_verify ( struct tls_connection *tls ) { struct digest_algorithm *digest = tls->handshake_digest; - struct x509_certificate *cert = tls->cert; + struct x509_certificate *cert = x509_first ( tls->certs ); struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey; uint8_t digest_out[ digest->digestsize ]; uint8_t ctx[ pubkey->ctxsize ]; @@ -1845,26 +1861,57 @@ static int tls_new_certificate ( struct tls_connection *tls, static int tls_new_certificate_request ( struct tls_connection *tls, const void *data __unused, size_t len __unused ) { + struct x509_certificate *cert; + int rc; /* We can only send a single certificate, so there is no point * in parsing the Certificate Request. */ - /* Free any existing client certificate */ - x509_put ( tls->cert ); + /* Free any existing client certificate chain */ + x509_chain_put ( tls->certs ); + tls->certs = NULL; /* Determine client certificate to be sent */ - tls->cert = certstore_find_key ( &private_key ); - if ( ! tls->cert ) { + cert = certstore_find_key ( &private_key ); + if ( ! cert ) { DBGC ( tls, "TLS %p could not find certificate corresponding " "to private key\n", tls ); - return -EPERM_CLIENT_CERT; + rc = -EPERM_CLIENT_CERT; + goto err_find; + } + x509_get ( cert ); + DBGC ( tls, "TLS %p selected client certificate %s\n", + tls, x509_name ( cert ) ); + + /* Create client certificate chain */ + tls->certs = x509_alloc_chain(); + if ( ! tls->certs ) { + rc = -ENOMEM; + goto err_alloc; } - x509_get ( tls->cert ); - DBGC ( tls, "TLS %p sending client certificate %s\n", - tls, x509_name ( tls->cert ) ); + + /* Append client certificate to chain */ + if ( ( rc = x509_append ( tls->certs, cert ) ) != 0 ) + goto err_append; + + /* Append any relevant issuer certificates */ + if ( ( rc = x509_auto_append ( tls->certs, &certstore ) ) != 0 ) + goto err_auto_append; + + /* Drop local reference to client certificate */ + x509_put ( cert ); return 0; + + err_auto_append: + err_append: + x509_chain_put ( tls->certs ); + tls->certs = NULL; + err_alloc: + x509_put ( cert ); + err_find: + return rc; } /** @@ -2880,7 +2927,7 @@ static void tls_validator_done ( struct tls_connection *tls, int rc ) { tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE | TLS_TX_CHANGE_CIPHER | TLS_TX_FINISHED ); - if ( tls->cert ) { + if ( tls->certs ) { tls->tx_pending |= ( TLS_TX_CERTIFICATE | TLS_TX_CERTIFICATE_VERIFY ); } -- cgit v1.2.3-55-g7522 From e33f5210813d704477eb16b45fbbaec143d8da95 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 7 Dec 2020 13:55:12 +0000 Subject: [asn1] Add constant for UTF-8 string tag Signed-off-by: Michael Brown --- src/include/ipxe/asn1.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 7bfba6066..7b0aacb5d 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -75,6 +75,9 @@ struct asn1_builder_header { /** ASN.1 enumeration */ #define ASN1_ENUMERATED 0x0a +/** ASN.1 UTF-8 string */ +#define ASN1_UTF8_STRING 0x0c + /** ASN.1 UTC time */ #define ASN1_UTC_TIME 0x17 -- cgit v1.2.3-55-g7522 From e4b6328c84cf3dcbb4af9ba42b2e3cbbb2cfbfee Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 8 Dec 2020 12:30:57 +0000 Subject: [asn1] Rename ASN1_OID_CURSOR to ASN1_CURSOR There is nothing OID-specific about the ASN1_OID_CURSOR macro. Rename to allow it to be used for constructing ASN.1 cursors with arbitrary contents. Signed-off-by: Michael Brown --- src/crypto/cms.c | 2 +- src/crypto/mishmash/oid_md4.c | 2 +- src/crypto/mishmash/oid_md5.c | 2 +- src/crypto/mishmash/oid_rsa.c | 2 +- src/crypto/mishmash/oid_sha1.c | 2 +- src/crypto/mishmash/oid_sha224.c | 2 +- src/crypto/mishmash/oid_sha256.c | 2 +- src/crypto/mishmash/oid_sha384.c | 2 +- src/crypto/mishmash/oid_sha512.c | 2 +- src/crypto/mishmash/oid_sha512_224.c | 2 +- src/crypto/mishmash/oid_sha512_256.c | 2 +- src/crypto/mishmash/rsa_md5.c | 2 +- src/crypto/mishmash/rsa_sha1.c | 2 +- src/crypto/mishmash/rsa_sha224.c | 2 +- src/crypto/mishmash/rsa_sha256.c | 2 +- src/crypto/mishmash/rsa_sha384.c | 2 +- src/crypto/mishmash/rsa_sha512.c | 2 +- src/crypto/ocsp.c | 2 +- src/crypto/x509.c | 18 +++++++++--------- src/include/ipxe/asn1.h | 8 ++++---- 20 files changed, 31 insertions(+), 31 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/crypto/cms.c b/src/crypto/cms.c index bc2148e8a..9511cec8a 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -76,7 +76,7 @@ static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA }; /** "pkcs7-signedData" object identifier cursor */ static struct asn1_cursor oid_signeddata_cursor = - ASN1_OID_CURSOR ( oid_signeddata ); + ASN1_CURSOR ( oid_signeddata ); /** * Parse CMS signature content type diff --git a/src/crypto/mishmash/oid_md4.c b/src/crypto/mishmash/oid_md4.c index 1054a79be..d42f2df19 100644 --- a/src/crypto/mishmash/oid_md4.c +++ b/src/crypto/mishmash/oid_md4.c @@ -33,5 +33,5 @@ static uint8_t oid_md4[] = { ASN1_OID_MD4 }; struct asn1_algorithm oid_md4_algorithm __asn1_algorithm = { .name = "md4", .digest = &md4_algorithm, - .oid = ASN1_OID_CURSOR ( oid_md4 ), + .oid = ASN1_CURSOR ( oid_md4 ), }; diff --git a/src/crypto/mishmash/oid_md5.c b/src/crypto/mishmash/oid_md5.c index 96149d096..f56dd8b8d 100644 --- a/src/crypto/mishmash/oid_md5.c +++ b/src/crypto/mishmash/oid_md5.c @@ -33,5 +33,5 @@ static uint8_t oid_md5[] = { ASN1_OID_MD5 }; struct asn1_algorithm oid_md5_algorithm __asn1_algorithm = { .name = "md5", .digest = &md5_algorithm, - .oid = ASN1_OID_CURSOR ( oid_md5 ), + .oid = ASN1_CURSOR ( oid_md5 ), }; diff --git a/src/crypto/mishmash/oid_rsa.c b/src/crypto/mishmash/oid_rsa.c index 1360c3117..582022628 100644 --- a/src/crypto/mishmash/oid_rsa.c +++ b/src/crypto/mishmash/oid_rsa.c @@ -34,5 +34,5 @@ struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm = { .name = "rsaEncryption", .pubkey = &rsa_algorithm, .digest = NULL, - .oid = ASN1_OID_CURSOR ( oid_rsa_encryption ), + .oid = ASN1_CURSOR ( oid_rsa_encryption ), }; diff --git a/src/crypto/mishmash/oid_sha1.c b/src/crypto/mishmash/oid_sha1.c index 0ab3bac61..5dae6d27c 100644 --- a/src/crypto/mishmash/oid_sha1.c +++ b/src/crypto/mishmash/oid_sha1.c @@ -33,5 +33,5 @@ static uint8_t oid_sha1[] = { ASN1_OID_SHA1 }; struct asn1_algorithm oid_sha1_algorithm __asn1_algorithm = { .name = "sha1", .digest = &sha1_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha1 ), + .oid = ASN1_CURSOR ( oid_sha1 ), }; diff --git a/src/crypto/mishmash/oid_sha224.c b/src/crypto/mishmash/oid_sha224.c index 1ff6884a4..ee7ed22e4 100644 --- a/src/crypto/mishmash/oid_sha224.c +++ b/src/crypto/mishmash/oid_sha224.c @@ -33,5 +33,5 @@ static uint8_t oid_sha224[] = { ASN1_OID_SHA224 }; struct asn1_algorithm oid_sha224_algorithm __asn1_algorithm = { .name = "sha224", .digest = &sha224_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha224 ), + .oid = ASN1_CURSOR ( oid_sha224 ), }; diff --git a/src/crypto/mishmash/oid_sha256.c b/src/crypto/mishmash/oid_sha256.c index 51ea585c5..963fddb63 100644 --- a/src/crypto/mishmash/oid_sha256.c +++ b/src/crypto/mishmash/oid_sha256.c @@ -33,5 +33,5 @@ static uint8_t oid_sha256[] = { ASN1_OID_SHA256 }; struct asn1_algorithm oid_sha256_algorithm __asn1_algorithm = { .name = "sha256", .digest = &sha256_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha256 ), + .oid = ASN1_CURSOR ( oid_sha256 ), }; diff --git a/src/crypto/mishmash/oid_sha384.c b/src/crypto/mishmash/oid_sha384.c index 5ba4d60a4..81ff48bbf 100644 --- a/src/crypto/mishmash/oid_sha384.c +++ b/src/crypto/mishmash/oid_sha384.c @@ -33,5 +33,5 @@ static uint8_t oid_sha384[] = { ASN1_OID_SHA384 }; struct asn1_algorithm oid_sha384_algorithm __asn1_algorithm = { .name = "sha384", .digest = &sha384_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha384 ), + .oid = ASN1_CURSOR ( oid_sha384 ), }; diff --git a/src/crypto/mishmash/oid_sha512.c b/src/crypto/mishmash/oid_sha512.c index 38e3c1a3d..78bae48b4 100644 --- a/src/crypto/mishmash/oid_sha512.c +++ b/src/crypto/mishmash/oid_sha512.c @@ -33,5 +33,5 @@ static uint8_t oid_sha512[] = { ASN1_OID_SHA512 }; struct asn1_algorithm oid_sha512_algorithm __asn1_algorithm = { .name = "sha512", .digest = &sha512_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha512 ), + .oid = ASN1_CURSOR ( oid_sha512 ), }; diff --git a/src/crypto/mishmash/oid_sha512_224.c b/src/crypto/mishmash/oid_sha512_224.c index 2300dad66..6f61f9cac 100644 --- a/src/crypto/mishmash/oid_sha512_224.c +++ b/src/crypto/mishmash/oid_sha512_224.c @@ -33,5 +33,5 @@ static uint8_t oid_sha512_224[] = { ASN1_OID_SHA512_224 }; struct asn1_algorithm oid_sha512_224_algorithm __asn1_algorithm = { .name = "sha512/224", .digest = &sha512_224_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha512_224 ), + .oid = ASN1_CURSOR ( oid_sha512_224 ), }; diff --git a/src/crypto/mishmash/oid_sha512_256.c b/src/crypto/mishmash/oid_sha512_256.c index 6af61fea9..bce4762e4 100644 --- a/src/crypto/mishmash/oid_sha512_256.c +++ b/src/crypto/mishmash/oid_sha512_256.c @@ -33,5 +33,5 @@ static uint8_t oid_sha512_256[] = { ASN1_OID_SHA512_256 }; struct asn1_algorithm oid_sha512_256_algorithm __asn1_algorithm = { .name = "sha512/256", .digest = &sha512_256_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha512_256 ), + .oid = ASN1_CURSOR ( oid_sha512_256 ), }; diff --git a/src/crypto/mishmash/rsa_md5.c b/src/crypto/mishmash/rsa_md5.c index ac828ac11..051afe264 100644 --- a/src/crypto/mishmash/rsa_md5.c +++ b/src/crypto/mishmash/rsa_md5.c @@ -36,7 +36,7 @@ struct asn1_algorithm md5_with_rsa_encryption_algorithm __asn1_algorithm = { .name = "md5WithRSAEncryption", .pubkey = &rsa_algorithm, .digest = &md5_algorithm, - .oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ), + .oid = ASN1_CURSOR ( oid_md5_with_rsa_encryption ), }; /** MD5 digestInfo prefix */ diff --git a/src/crypto/mishmash/rsa_sha1.c b/src/crypto/mishmash/rsa_sha1.c index 39424bf2d..264f871f1 100644 --- a/src/crypto/mishmash/rsa_sha1.c +++ b/src/crypto/mishmash/rsa_sha1.c @@ -37,7 +37,7 @@ struct asn1_algorithm sha1_with_rsa_encryption_algorithm __asn1_algorithm = { .name = "sha1WithRSAEncryption", .pubkey = &rsa_algorithm, .digest = &sha1_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ), + .oid = ASN1_CURSOR ( oid_sha1_with_rsa_encryption ), }; /** SHA-1 digestInfo prefix */ diff --git a/src/crypto/mishmash/rsa_sha224.c b/src/crypto/mishmash/rsa_sha224.c index 5e8755aab..1465a033d 100644 --- a/src/crypto/mishmash/rsa_sha224.c +++ b/src/crypto/mishmash/rsa_sha224.c @@ -37,7 +37,7 @@ struct asn1_algorithm sha224_with_rsa_encryption_algorithm __asn1_algorithm = { .name = "sha224WithRSAEncryption", .pubkey = &rsa_algorithm, .digest = &sha224_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha224_with_rsa_encryption ), + .oid = ASN1_CURSOR ( oid_sha224_with_rsa_encryption ), }; /** SHA-224 digestInfo prefix */ diff --git a/src/crypto/mishmash/rsa_sha256.c b/src/crypto/mishmash/rsa_sha256.c index b44af5f19..7283c3e29 100644 --- a/src/crypto/mishmash/rsa_sha256.c +++ b/src/crypto/mishmash/rsa_sha256.c @@ -37,7 +37,7 @@ struct asn1_algorithm sha256_with_rsa_encryption_algorithm __asn1_algorithm = { .name = "sha256WithRSAEncryption", .pubkey = &rsa_algorithm, .digest = &sha256_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ), + .oid = ASN1_CURSOR ( oid_sha256_with_rsa_encryption ), }; /** SHA-256 digestInfo prefix */ diff --git a/src/crypto/mishmash/rsa_sha384.c b/src/crypto/mishmash/rsa_sha384.c index af22a2bf0..6f8c29b29 100644 --- a/src/crypto/mishmash/rsa_sha384.c +++ b/src/crypto/mishmash/rsa_sha384.c @@ -37,7 +37,7 @@ struct asn1_algorithm sha384_with_rsa_encryption_algorithm __asn1_algorithm = { .name = "sha384WithRSAEncryption", .pubkey = &rsa_algorithm, .digest = &sha384_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha384_with_rsa_encryption ), + .oid = ASN1_CURSOR ( oid_sha384_with_rsa_encryption ), }; /** SHA-384 digestInfo prefix */ diff --git a/src/crypto/mishmash/rsa_sha512.c b/src/crypto/mishmash/rsa_sha512.c index 29ee15493..bb4463a5a 100644 --- a/src/crypto/mishmash/rsa_sha512.c +++ b/src/crypto/mishmash/rsa_sha512.c @@ -37,7 +37,7 @@ struct asn1_algorithm sha512_with_rsa_encryption_algorithm __asn1_algorithm = { .name = "sha512WithRSAEncryption", .pubkey = &rsa_algorithm, .digest = &sha512_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha512_with_rsa_encryption ), + .oid = ASN1_CURSOR ( oid_sha512_with_rsa_encryption ), }; /** SHA-512 digestInfo prefix */ diff --git a/src/crypto/ocsp.c b/src/crypto/ocsp.c index 9ced59ea3..51dc939e8 100644 --- a/src/crypto/ocsp.c +++ b/src/crypto/ocsp.c @@ -116,7 +116,7 @@ static const uint8_t oid_basic_response_type[] = { ASN1_OID_OCSP_BASIC }; /** OCSP basic response type cursor */ static struct asn1_cursor oid_basic_response_type_cursor = - ASN1_OID_CURSOR ( oid_basic_response_type ); + ASN1_CURSOR ( oid_basic_response_type ); /** * Free OCSP check diff --git a/src/crypto/x509.c b/src/crypto/x509.c index feb7e4a0a..da0a85825 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -156,7 +156,7 @@ static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME }; /** "commonName" object identifier cursor */ static struct asn1_cursor oid_common_name_cursor = - ASN1_OID_CURSOR ( oid_common_name ); + ASN1_CURSOR ( oid_common_name ); /** * Parse X.509 certificate version @@ -523,12 +523,12 @@ static struct x509_key_purpose x509_key_purposes[] = { { .name = "codeSigning", .bits = X509_CODE_SIGNING, - .oid = ASN1_OID_CURSOR ( oid_code_signing ), + .oid = ASN1_CURSOR ( oid_code_signing ), }, { .name = "ocspSigning", .bits = X509_OCSP_SIGNING, - .oid = ASN1_OID_CURSOR ( oid_ocsp_signing ), + .oid = ASN1_CURSOR ( oid_ocsp_signing ), }, }; @@ -631,7 +631,7 @@ static uint8_t oid_ad_ocsp[] = { ASN1_OID_OCSP }; static struct x509_access_method x509_access_methods[] = { { .name = "OCSP", - .oid = ASN1_OID_CURSOR ( oid_ad_ocsp ), + .oid = ASN1_CURSOR ( oid_ad_ocsp ), .parse = x509_parse_ocsp, }, }; @@ -768,27 +768,27 @@ static uint8_t oid_ce_subject_alt_name[] = static struct x509_extension x509_extensions[] = { { .name = "basicConstraints", - .oid = ASN1_OID_CURSOR ( oid_ce_basic_constraints ), + .oid = ASN1_CURSOR ( oid_ce_basic_constraints ), .parse = x509_parse_basic_constraints, }, { .name = "keyUsage", - .oid = ASN1_OID_CURSOR ( oid_ce_key_usage ), + .oid = ASN1_CURSOR ( oid_ce_key_usage ), .parse = x509_parse_key_usage, }, { .name = "extKeyUsage", - .oid = ASN1_OID_CURSOR ( oid_ce_ext_key_usage ), + .oid = ASN1_CURSOR ( oid_ce_ext_key_usage ), .parse = x509_parse_extended_key_usage, }, { .name = "authorityInfoAccess", - .oid = ASN1_OID_CURSOR ( oid_pe_authority_info_access ), + .oid = ASN1_CURSOR ( oid_pe_authority_info_access ), .parse = x509_parse_authority_info_access, }, { .name = "subjectAltName", - .oid = ASN1_OID_CURSOR ( oid_ce_subject_alt_name ), + .oid = ASN1_CURSOR ( oid_ce_subject_alt_name ), .parse = x509_parse_subject_alt_name, }, }; diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 7b0aacb5d..5b1af02d4 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -291,10 +291,10 @@ struct asn1_builder_header { ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \ ASN1_OID_SINGLE ( 17 ) -/** Define an ASN.1 cursor containing an OID */ -#define ASN1_OID_CURSOR( oid_value ) { \ - .data = oid_value, \ - .len = sizeof ( oid_value ), \ +/** Define an ASN.1 cursor for a static value */ +#define ASN1_CURSOR( value ) { \ + .data = value, \ + .len = sizeof ( value ), \ } /** An ASN.1 OID-identified algorithm */ -- cgit v1.2.3-55-g7522 From 1b112e9d18bb9c874b87ce5feabb7906f62351b3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 8 Dec 2020 12:31:52 +0000 Subject: [asn1] Define ASN1_SHORT() for constructing short tagged values Signed-off-by: Michael Brown --- src/include/ipxe/asn1.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 5b1af02d4..fdf06f109 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include @@ -99,6 +100,10 @@ struct asn1_builder_header { /** ASN.1 "any tag" magic value */ #define ASN1_ANY -1U +/** Construct a short ASN.1 value */ +#define ASN1_SHORT( tag, ... ) \ + (tag), VA_ARG_COUNT ( __VA_ARGS__ ), __VA_ARGS__ + /** Initial OID byte */ #define ASN1_OID_INITIAL( first, second ) ( ( (first) * 40 ) + (second) ) -- cgit v1.2.3-55-g7522 From be47c2c72cd3cdecc146eca5a200d454643bcf06 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 8 Dec 2020 14:55:44 +0000 Subject: [http] Hide HTTP transport-layer filter implementation details Signed-off-by: Michael Brown --- src/include/ipxe/http.h | 6 +++--- src/net/tcp/httpconn.c | 3 +-- src/net/tcp/https.c | 14 +++++++++++++- 3 files changed, 17 insertions(+), 6 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/http.h b/src/include/ipxe/http.h index 117f174af..5a9baddcb 100644 --- a/src/include/ipxe/http.h +++ b/src/include/ipxe/http.h @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include struct http_transaction; +struct http_connection; /****************************************************************************** * @@ -43,11 +44,10 @@ struct http_scheme { unsigned int port; /** Transport-layer filter (if any) * - * @v xfer Data transfer interface - * @v name Host name + * @v conn HTTP connection * @ret rc Return status code */ - int ( * filter ) ( struct interface *xfer, const char *name ); + int ( * filter ) ( struct http_connection *conn ); }; /** HTTP scheme table */ diff --git a/src/net/tcp/httpconn.c b/src/net/tcp/httpconn.c index 2804e09d5..f9221b27e 100644 --- a/src/net/tcp/httpconn.c +++ b/src/net/tcp/httpconn.c @@ -301,8 +301,7 @@ int http_connect ( struct interface *xfer, struct uri *uri ) { goto err_open; /* Add filter, if any */ - if ( scheme->filter && - ( ( rc = scheme->filter ( &conn->socket, uri->host ) ) != 0 ) ) + if ( scheme->filter && ( ( rc = scheme->filter ( conn ) ) != 0 ) ) goto err_filter; /* Attach to parent interface, mortalise self, and return */ diff --git a/src/net/tcp/https.c b/src/net/tcp/https.c index e91000322..5a44bdebf 100644 --- a/src/net/tcp/https.c +++ b/src/net/tcp/https.c @@ -31,12 +31,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include FEATURE ( FEATURE_PROTOCOL, "HTTPS", DHCP_EB_FEATURE_HTTPS, 1 ); +/** + * Add HTTPS filter + * + * @v conn HTTP connection + * @ret rc Return status code + */ +static int https_filter ( struct http_connection *conn ) { + + return add_tls ( &conn->socket, conn->uri->host ); +} + /** HTTPS URI opener */ struct uri_opener https_uri_opener __uri_opener = { .scheme = "https", @@ -47,5 +59,5 @@ struct uri_opener https_uri_opener __uri_opener = { struct http_scheme https_scheme __http_scheme = { .name = "https", .port = HTTPS_PORT, - .filter = add_tls, + .filter = https_filter, }; -- cgit v1.2.3-55-g7522 From 39f5293492f351a274940d0ba2624ecb242b3c9b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 8 Dec 2020 14:58:46 +0000 Subject: [x509] Record root of trust used when validating a certificate Record the root of trust used at the point that a certificate is validated, redefine validation as checking a certificate against a specific root of trust, and pass an explicit root of trust when creating a TLS connection. This allows a custom TLS connection to be used with a custom root of trust, without causing any validated certificates to be treated as valid for normal purposes. Signed-off-by: Michael Brown --- src/crypto/ocsp.c | 6 +++--- src/crypto/x509.c | 23 +++++++++++++++++++---- src/include/ipxe/tls.h | 5 ++++- src/include/ipxe/validator.h | 3 ++- src/include/ipxe/x509.h | 21 +++++++-------------- src/net/tcp/https.c | 2 +- src/net/tcp/syslogs.c | 2 +- src/net/tls.c | 8 ++++++-- src/net/validator.c | 11 ++++++++--- src/tests/ocsp_test.c | 3 ++- src/tests/x509_test.c | 4 ++++ src/usr/certmgmt.c | 2 +- src/usr/imgtrust.c | 3 ++- 13 files changed, 60 insertions(+), 33 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/crypto/ocsp.c b/src/crypto/ocsp.c index 998a0ce2c..cc957b40c 100644 --- a/src/crypto/ocsp.c +++ b/src/crypto/ocsp.c @@ -284,7 +284,7 @@ int ocsp_check ( struct x509_certificate *cert, /* Sanity checks */ assert ( cert != NULL ); assert ( issuer != NULL ); - assert ( x509_is_valid ( issuer ) ); + assert ( issuer->root != NULL ); /* Allocate and initialise check */ *ocsp = zalloc ( sizeof ( **ocsp ) ); @@ -915,7 +915,7 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { */ x509_invalidate ( signer ); if ( ( rc = x509_validate ( signer, ocsp->issuer, time, - NULL ) ) != 0 ) { + ocsp->issuer->root ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not validate ", ocsp, x509_name ( ocsp->cert ) ); DBGC ( ocsp, "signer \"%s\": %s\n", @@ -961,7 +961,7 @@ int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) { /* Validate certificate against issuer */ if ( ( rc = x509_validate ( ocsp->cert, ocsp->issuer, time, - NULL ) ) != 0 ) { + ocsp->issuer->root ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not validate certificate: " "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); return rc; diff --git a/src/crypto/x509.c b/src/crypto/x509.c index da0a85825..fe514e269 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -1295,6 +1295,21 @@ int x509_check_time ( struct x509_certificate *cert, time_t time ) { return 0; } +/** + * Check if X.509 certificate is valid + * + * @v cert X.509 certificate + * @v root Root certificate list, or NULL to use default + */ +int x509_is_valid ( struct x509_certificate *cert, struct x509_root *root ) { + + /* Use default root certificate store if none specified */ + if ( ! root ) + root = &root_certificates; + + return ( cert->root == root ); +} + /** * Validate X.509 certificate * @@ -1321,7 +1336,7 @@ int x509_validate ( struct x509_certificate *cert, root = &root_certificates; /* Return success if certificate has already been validated */ - if ( x509_is_valid ( cert ) ) + if ( x509_is_valid ( cert, root ) ) return 0; /* Fail if certificate is invalid at specified time */ @@ -1330,7 +1345,7 @@ int x509_validate ( struct x509_certificate *cert, /* Succeed if certificate is a trusted root certificate */ if ( x509_check_root ( cert, root ) == 0 ) { - cert->flags |= X509_FL_VALIDATED; + cert->root = root; cert->path_remaining = ( cert->extensions.basic.path_len + 1 ); return 0; } @@ -1343,7 +1358,7 @@ int x509_validate ( struct x509_certificate *cert, } /* Fail unless issuer has already been validated */ - if ( ! x509_is_valid ( issuer ) ) { + if ( ! x509_is_valid ( issuer, root ) ) { DBGC ( cert, "X509 %p \"%s\" ", cert, x509_name ( cert ) ); DBGC ( cert, "issuer %p \"%s\" has not yet been validated\n", issuer, x509_name ( issuer ) ); @@ -1376,7 +1391,7 @@ int x509_validate ( struct x509_certificate *cert, cert->path_remaining = max_path_remaining; /* Mark certificate as valid */ - cert->flags |= X509_FL_VALIDATED; + cert->root = root; DBGC ( cert, "X509 %p \"%s\" successfully validated using ", cert, x509_name ( cert ) ); diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index a2d4f475b..1e1093fde 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -326,6 +326,8 @@ struct tls_connection { /** Verification data */ struct tls_verify_data verify; + /** Root of trust (or NULL to use default) */ + struct x509_root *root; /** Server certificate chain */ struct x509_chain *chain; /** Certificate validator */ @@ -378,6 +380,7 @@ struct tls_connection { /** RX I/O buffer alignment */ #define TLS_RX_ALIGN 16 -extern int add_tls ( struct interface *xfer, const char *name ); +extern int add_tls ( struct interface *xfer, const char *name, + struct x509_root *root ); #endif /* _IPXE_TLS_H */ diff --git a/src/include/ipxe/validator.h b/src/include/ipxe/validator.h index 0aee56eb0..367e4045d 100644 --- a/src/include/ipxe/validator.h +++ b/src/include/ipxe/validator.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -extern int create_validator ( struct interface *job, struct x509_chain *chain ); +extern int create_validator ( struct interface *job, struct x509_chain *chain, + struct x509_root *root ); #endif /* _IPXE_VALIDATOR_H */ diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 78eeafbfb..cac2f19f0 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -191,6 +191,8 @@ struct x509_certificate { /** Flags */ unsigned int flags; + /** Root against which certificate has been validated (if any) */ + struct x509_root *root; /** Maximum number of subsequent certificates in chain */ unsigned int path_remaining; @@ -218,12 +220,10 @@ struct x509_certificate { /** X.509 certificate flags */ enum x509_flags { - /** Certificate has been validated */ - X509_FL_VALIDATED = 0x0001, /** Certificate was added at build time */ - X509_FL_PERMANENT = 0x0002, + X509_FL_PERMANENT = 0x0001, /** Certificate was added explicitly at run time */ - X509_FL_EXPLICIT = 0x0004, + X509_FL_EXPLICIT = 0x0002, }; /** @@ -355,6 +355,8 @@ extern int x509_parse ( struct x509_certificate *cert, const struct asn1_cursor *raw ); extern int x509_certificate ( const void *data, size_t len, struct x509_certificate **cert ); +extern int x509_is_valid ( struct x509_certificate *cert, + struct x509_root *root ); extern int x509_validate ( struct x509_certificate *cert, struct x509_certificate *issuer, time_t time, struct x509_root *root ); @@ -383,22 +385,13 @@ extern int x509_check_root ( struct x509_certificate *cert, struct x509_root *root ); extern int x509_check_time ( struct x509_certificate *cert, time_t time ); -/** - * Check if X.509 certificate is valid - * - * @v cert X.509 certificate - */ -static inline int x509_is_valid ( struct x509_certificate *cert ) { - return ( cert->flags & X509_FL_VALIDATED ); -} - /** * Invalidate X.509 certificate * * @v cert X.509 certificate */ static inline void x509_invalidate ( struct x509_certificate *cert ) { - cert->flags &= ~X509_FL_VALIDATED; + cert->root = NULL; cert->path_remaining = 0; } diff --git a/src/net/tcp/https.c b/src/net/tcp/https.c index 5a44bdebf..eae8ae5dc 100644 --- a/src/net/tcp/https.c +++ b/src/net/tcp/https.c @@ -46,7 +46,7 @@ FEATURE ( FEATURE_PROTOCOL, "HTTPS", DHCP_EB_FEATURE_HTTPS, 1 ); */ static int https_filter ( struct http_connection *conn ) { - return add_tls ( &conn->socket, conn->uri->host ); + return add_tls ( &conn->socket, conn->uri->host, NULL ); } /** HTTPS URI opener */ diff --git a/src/net/tcp/syslogs.c b/src/net/tcp/syslogs.c index b37605272..f91864a44 100644 --- a/src/net/tcp/syslogs.c +++ b/src/net/tcp/syslogs.c @@ -246,7 +246,7 @@ static int apply_syslogs_settings ( void ) { } /* Add TLS filter */ - if ( ( rc = add_tls ( &syslogs, server ) ) != 0 ) { + if ( ( rc = add_tls ( &syslogs, server, NULL ) ) != 0 ) { DBG ( "SYSLOGS cannot create TLS filter: %s\n", strerror ( rc ) ); goto err_add_tls; diff --git a/src/net/tls.c b/src/net/tls.c index c42b4ddc7..c04f0d557 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1938,7 +1938,8 @@ static int tls_new_server_hello_done ( struct tls_connection *tls, } /* Begin certificate validation */ - if ( ( rc = create_validator ( &tls->validator, tls->chain ) ) != 0 ) { + if ( ( rc = create_validator ( &tls->validator, tls->chain, + tls->root ) ) != 0 ) { DBGC ( tls, "TLS %p could not start certificate validation: " "%s\n", tls, strerror ( rc ) ); return rc; @@ -3140,9 +3141,11 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { * * @v xfer Data transfer interface * @v name Host name + * @v root Root of trust (or NULL to use default) * @ret rc Return status code */ -int add_tls ( struct interface *xfer, const char *name ) { +int add_tls ( struct interface *xfer, const char *name, + struct x509_root *root ) { struct tls_connection *tls; int rc; @@ -3160,6 +3163,7 @@ int add_tls ( struct interface *xfer, const char *name ) { intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt ); process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt ); + tls->root = root; tls->version = TLS_VERSION_TLS_1_2; tls_clear_cipher ( tls, &tls->tx_cipherspec ); tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); diff --git a/src/net/validator.c b/src/net/validator.c index f6b03ff41..c407a09b7 100644 --- a/src/net/validator.c +++ b/src/net/validator.c @@ -73,6 +73,8 @@ struct validator { /** Process */ struct process process; + /** Root of trust (or NULL to use default) */ + struct x509_root *root; /** X.509 certificate chain */ struct x509_chain *chain; /** OCSP check */ @@ -554,7 +556,7 @@ static void validator_step ( struct validator *validator ) { */ now = time ( NULL ); if ( ( rc = x509_validate_chain ( validator->chain, now, NULL, - NULL ) ) == 0 ) { + validator->root ) ) == 0 ) { DBGC ( validator, "VALIDATOR %p \"%s\" validated\n", validator, validator_name ( validator ) ); validator_finished ( validator, 0 ); @@ -569,7 +571,7 @@ static void validator_step ( struct validator *validator ) { issuer = link->cert; if ( ! cert ) continue; - if ( ! x509_is_valid ( issuer ) ) + if ( ! x509_is_valid ( issuer, validator->root ) ) continue; /* The issuer is valid, but this certificate is not * yet valid. If OCSP is applicable, start it. @@ -621,9 +623,11 @@ static struct process_descriptor validator_process_desc = * * @v job Job control interface * @v chain X.509 certificate chain + * @v root Root of trust, or NULL to use default * @ret rc Return status code */ -int create_validator ( struct interface *job, struct x509_chain *chain ) { +int create_validator ( struct interface *job, struct x509_chain *chain, + struct x509_root *root ) { struct validator *validator; int rc; @@ -646,6 +650,7 @@ int create_validator ( struct interface *job, struct x509_chain *chain ) { &validator->refcnt ); process_init ( &validator->process, &validator_process_desc, &validator->refcnt ); + validator->root = root; validator->chain = x509_chain_get ( chain ); xferbuf_malloc_init ( &validator->buffer ); diff --git a/src/tests/ocsp_test.c b/src/tests/ocsp_test.c index a3349346a..3d2f556ed 100644 --- a/src/tests/ocsp_test.c +++ b/src/tests/ocsp_test.c @@ -42,6 +42,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include @@ -110,7 +111,7 @@ static void ocsp_prepare_test ( struct ocsp_test *test ) { x509_invalidate ( cert ); /* Force-validate issuer certificate */ - issuer->flags |= X509_FL_VALIDATED; + issuer->root = &root_certificates; issuer->path_remaining = ( issuer->extensions.basic.path_len + 1 ); } diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c index 658d5247c..2915b9068 100644 --- a/src/tests/x509_test.c +++ b/src/tests/x509_test.c @@ -943,6 +943,10 @@ static void x509_validate_chain_okx ( struct x509_test_chain *chn, time_t time, x509_invalidate_chain ( chn->chain ); okx ( x509_validate_chain ( chn->chain, time, store, root ) == 0, file, line ); + okx ( x509_is_valid ( chn->certs[0]->cert, root ), + file, line ); + okx ( ! x509_is_valid ( chn->certs[0]->cert, &dummy_root ), + file, line ); } #define x509_validate_chain_ok( chn, time, store, root ) \ x509_validate_chain_okx ( chn, time, store, root, __FILE__, __LINE__ ) diff --git a/src/usr/certmgmt.c b/src/usr/certmgmt.c index 2f233fe4f..e6bf51fd8 100644 --- a/src/usr/certmgmt.c +++ b/src/usr/certmgmt.c @@ -57,7 +57,7 @@ void certstat ( struct x509_certificate *cert ) { printf ( " [PERMANENT]" ); if ( cert->flags & X509_FL_EXPLICIT ) printf ( " [EXPLICIT]" ); - if ( x509_is_valid ( cert ) ) + if ( x509_is_valid ( cert, NULL ) ) printf ( " [VALIDATED]" ); printf ( "\n" ); } diff --git a/src/usr/imgtrust.c b/src/usr/imgtrust.c index 595ea6b25..e7c2067a0 100644 --- a/src/usr/imgtrust.c +++ b/src/usr/imgtrust.c @@ -77,7 +77,8 @@ int imgverify ( struct image *image, struct image *signature, /* Complete all certificate chains */ list_for_each_entry ( info, &sig->info, list ) { - if ( ( rc = create_validator ( &monojob, info->chain ) ) != 0 ) + if ( ( rc = create_validator ( &monojob, info->chain, + NULL ) ) != 0 ) goto err_create_validator; if ( ( rc = monojob_wait ( NULL, 0 ) ) != 0 ) goto err_validator_wait; -- cgit v1.2.3-55-g7522 From 3475f9162b84ce21327244ebce20ae29db6d7ac8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 9 Dec 2020 16:19:03 +0000 Subject: [x509] Make root of trust a reference-counted structure Signed-off-by: Michael Brown --- src/crypto/rootcert.c | 1 + src/crypto/x509.c | 56 +++++++++++++++++++++++++++++++++++++++---------- src/include/ipxe/x509.h | 27 +++++++++++++++++++++++- src/net/tls.c | 3 ++- src/net/validator.c | 3 ++- src/tests/cms_test.c | 2 ++ src/tests/x509_test.c | 3 +++ 7 files changed, 81 insertions(+), 14 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/crypto/rootcert.c b/src/crypto/rootcert.c index 867ff50e8..0835ff071 100644 --- a/src/crypto/rootcert.c +++ b/src/crypto/rootcert.c @@ -71,6 +71,7 @@ static struct setting trust_setting __setting ( SETTING_CRYPTO, trust ) = { /** Root certificates */ struct x509_root root_certificates = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &sha256_algorithm, .count = ( sizeof ( fingerprints ) / FINGERPRINT_LEN ), .fingerprints = fingerprints, diff --git a/src/crypto/x509.c b/src/crypto/x509.c index fe514e269..892d8f8d5 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -122,6 +122,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define EINFO_EACCES_USELESS \ __einfo_uniqify ( EINFO_EACCES, 0x0b, "No usable certificates" ) +/** + * Free X.509 certificate + * + * @v refcnt Reference count + */ +static void x509_free ( struct refcnt *refcnt ) { + struct x509_certificate *cert = + container_of ( refcnt, struct x509_certificate, refcnt ); + + x509_root_put ( cert->root ); + free ( cert ); +} + /** * Get X.509 certificate display name * @@ -1075,7 +1088,7 @@ int x509_certificate ( const void *data, size_t len, *cert = zalloc ( sizeof ( **cert ) + cursor.len ); if ( ! *cert ) return -ENOMEM; - ref_init ( &(*cert)->refcnt, NULL ); + ref_init ( &(*cert)->refcnt, x509_free ); raw = ( *cert + 1 ); /* Copy raw data */ @@ -1310,6 +1323,35 @@ int x509_is_valid ( struct x509_certificate *cert, struct x509_root *root ) { return ( cert->root == root ); } +/** + * Set X.509 certificate as validated + * + * @v cert X.509 certificate + * @v issuer Issuing X.509 certificate (or NULL) + * @v root Root certificate list + */ +static void x509_set_valid ( struct x509_certificate *cert, + struct x509_certificate *issuer, + struct x509_root *root ) { + unsigned int max_path_remaining; + + /* Sanity checks */ + assert ( root != NULL ); + assert ( ( issuer == NULL ) || ( issuer->path_remaining >= 1 ) ); + + /* Record validation root */ + x509_root_put ( cert->root ); + cert->root = x509_root_get ( root ); + + /* Calculate effective path length */ + cert->path_remaining = ( cert->extensions.basic.path_len + 1 ); + if ( issuer ) { + max_path_remaining = ( issuer->path_remaining - 1 ); + if ( cert->path_remaining > max_path_remaining ) + cert->path_remaining = max_path_remaining; + } +} + /** * Validate X.509 certificate * @@ -1328,7 +1370,6 @@ int x509_is_valid ( struct x509_certificate *cert, struct x509_root *root ) { int x509_validate ( struct x509_certificate *cert, struct x509_certificate *issuer, time_t time, struct x509_root *root ) { - unsigned int max_path_remaining; int rc; /* Use default root certificate store if none specified */ @@ -1345,8 +1386,7 @@ int x509_validate ( struct x509_certificate *cert, /* Succeed if certificate is a trusted root certificate */ if ( x509_check_root ( cert, root ) == 0 ) { - cert->root = root; - cert->path_remaining = ( cert->extensions.basic.path_len + 1 ); + x509_set_valid ( cert, NULL, root ); return 0; } @@ -1384,14 +1424,8 @@ int x509_validate ( struct x509_certificate *cert, return -EACCES_OCSP_REQUIRED; } - /* Calculate effective path length */ - cert->path_remaining = ( issuer->path_remaining - 1 ); - max_path_remaining = ( cert->extensions.basic.path_len + 1 ); - if ( cert->path_remaining > max_path_remaining ) - cert->path_remaining = max_path_remaining; - /* Mark certificate as valid */ - cert->root = root; + x509_set_valid ( cert, issuer, root ); DBGC ( cert, "X509 %p \"%s\" successfully validated using ", cert, x509_name ( cert ) ); diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index cac2f19f0..c703c8f10 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -340,8 +340,10 @@ struct x509_access_method { const struct asn1_cursor *raw ); }; -/** An X.509 root certificate store */ +/** An X.509 root certificate list */ struct x509_root { + /** Reference count */ + struct refcnt refcnt; /** Fingerprint digest algorithm */ struct digest_algorithm *digest; /** Number of certificates */ @@ -350,6 +352,28 @@ struct x509_root { const void *fingerprints; }; +/** + * Get reference to X.509 root certificate list + * + * @v root X.509 root certificate list + * @ret root X.509 root certificate list + */ +static inline __attribute__ (( always_inline )) struct x509_root * +x509_root_get ( struct x509_root *root ) { + ref_get ( &root->refcnt ); + return root; +} + +/** + * Drop reference to X.509 root certificate list + * + * @v root X.509 root certificate list + */ +static inline __attribute__ (( always_inline )) void +x509_root_put ( struct x509_root *root ) { + ref_put ( &root->refcnt ); +} + extern const char * x509_name ( struct x509_certificate *cert ); extern int x509_parse ( struct x509_certificate *cert, const struct asn1_cursor *raw ); @@ -391,6 +415,7 @@ extern int x509_check_time ( struct x509_certificate *cert, time_t time ); * @v cert X.509 certificate */ static inline void x509_invalidate ( struct x509_certificate *cert ) { + x509_root_put ( cert->root ); cert->root = NULL; cert->path_remaining = 0; } diff --git a/src/net/tls.c b/src/net/tls.c index c04f0d557..f5459a2af 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -380,6 +380,7 @@ static void free_tls ( struct refcnt *refcnt ) { } x509_chain_put ( tls->certs ); x509_chain_put ( tls->chain ); + x509_root_put ( tls->root ); /* Drop reference to session */ assert ( list_empty ( &tls->list ) ); @@ -3163,7 +3164,7 @@ int add_tls ( struct interface *xfer, const char *name, intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt ); process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt ); - tls->root = root; + tls->root = x509_root_get ( root ); tls->version = TLS_VERSION_TLS_1_2; tls_clear_cipher ( tls, &tls->tx_cipherspec ); tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); diff --git a/src/net/validator.c b/src/net/validator.c index c407a09b7..693d4464b 100644 --- a/src/net/validator.c +++ b/src/net/validator.c @@ -116,6 +116,7 @@ static void validator_free ( struct refcnt *refcnt ) { DBGC2 ( validator, "VALIDATOR %p \"%s\" freed\n", validator, validator_name ( validator ) ); + x509_root_put ( validator->root ); x509_chain_put ( validator->chain ); ocsp_put ( validator->ocsp ); xferbuf_free ( &validator->buffer ); @@ -650,7 +651,7 @@ int create_validator ( struct interface *job, struct x509_chain *chain, &validator->refcnt ); process_init ( &validator->process, &validator_process_desc, &validator->refcnt ); - validator->root = root; + validator->root = x509_root_get ( root ); validator->chain = x509_chain_get ( chain ); xferbuf_malloc_init ( &validator->buffer ); diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c index b805a9974..f35fa206d 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -1317,6 +1317,7 @@ static struct x509_chain empty_store = { /** Root certificate list containing the iPXE self-test root CA */ static struct x509_root test_root = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &cms_test_algorithm, .count = 1, .fingerprints = root_crt_fingerprint, @@ -1331,6 +1332,7 @@ static uint8_t dummy_fingerprint[] = /** Certificate store containing a dummy fingerprint */ static struct x509_root dummy_root = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &cms_test_algorithm, .count = 1, .fingerprints = dummy_fingerprint, diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c index 2915b9068..256c3e85e 100644 --- a/src/tests/x509_test.c +++ b/src/tests/x509_test.c @@ -674,6 +674,7 @@ static struct x509_chain empty_store = { /** Root certificate list containing the iPXE self-test root CA */ static struct x509_root test_root = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &x509_test_algorithm, .count = 1, .fingerprints = root_crt_fingerprint, @@ -681,6 +682,7 @@ static struct x509_root test_root = { /** Root certificate list containing the iPXE self-test intermediate CA */ static struct x509_root intermediate_root = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &x509_test_algorithm, .count = 1, .fingerprints = intermediate_crt_fingerprint, @@ -695,6 +697,7 @@ static uint8_t dummy_fingerprint[] = /** Certificate store containing a dummy fingerprint */ static struct x509_root dummy_root = { + .refcnt = REF_INIT ( ref_no_free ), .digest = &x509_test_algorithm, .count = 1, .fingerprints = dummy_fingerprint, -- cgit v1.2.3-55-g7522 From 6a8664d9ec8010a717855ca92173c63c3c166c4e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 15 Dec 2020 16:28:33 +0000 Subject: [tls] Include root of trust within definition of TLS session Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 5 ++++- src/net/tls.c | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 1e1093fde..8345c9a26 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -255,6 +255,9 @@ struct tls_session { /** Server name */ const char *name; + /** Root of trust */ + struct x509_root *root; + /** Session ID */ uint8_t id[32]; /** Length of session ID */ @@ -326,7 +329,7 @@ struct tls_connection { /** Verification data */ struct tls_verify_data verify; - /** Root of trust (or NULL to use default) */ + /** Root of trust */ struct x509_root *root; /** Server certificate chain */ struct x509_chain *chain; diff --git a/src/net/tls.c b/src/net/tls.c index f5459a2af..046378392 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -45,6 +45,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -349,7 +350,8 @@ static void free_tls_session ( struct refcnt *refcnt ) { /* Remove from list of sessions */ list_del ( &session->list ); - /* Free session ticket */ + /* Free dynamically-allocated resources */ + x509_root_put ( session->root ); free ( session->ticket ); /* Free session */ @@ -3097,7 +3099,8 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { /* Find existing matching session, if any */ list_for_each_entry ( session, &tls_sessions, list ) { - if ( strcmp ( name, session->name ) == 0 ) { + if ( ( strcmp ( name, session->name ) == 0 ) && + ( tls->root == session->root ) ) { ref_get ( &session->refcnt ); tls->session = session; DBGC ( tls, "TLS %p joining session %s\n", tls, name ); @@ -3116,6 +3119,7 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { name_copy = ( ( ( void * ) session ) + sizeof ( *session ) ); strcpy ( name_copy, name ); session->name = name_copy; + session->root = x509_root_get ( tls->root ); INIT_LIST_HEAD ( &session->conn ); list_add ( &session->list, &tls_sessions ); @@ -3164,7 +3168,7 @@ int add_tls ( struct interface *xfer, const char *name, intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt ); process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt ); - tls->root = x509_root_get ( root ); + tls->root = x509_root_get ( root ? root : &root_certificates ); tls->version = TLS_VERSION_TLS_1_2; tls_clear_cipher ( tls, &tls->tx_cipherspec ); tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); -- cgit v1.2.3-55-g7522 From f43a8f8b9f808fb0a8347663abf6efe6908821ed Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 15 Dec 2020 16:11:34 +0000 Subject: [crypto] Allow private key to be specified as a TLS connection parameter Signed-off-by: Michael Brown --- src/crypto/certstore.c | 4 ++-- src/crypto/privkey.c | 35 ++++++++++++++++++++-------- src/include/ipxe/certstore.h | 3 ++- src/include/ipxe/privkey.h | 55 +++++++++++++++++++++++++++++++++++++++++++- src/include/ipxe/tls.h | 7 +++++- src/net/tcp/https.c | 2 +- src/net/tcp/syslogs.c | 2 +- src/net/tls.c | 16 +++++++++---- 8 files changed, 103 insertions(+), 21 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/crypto/certstore.c b/src/crypto/certstore.c index cdf6fb4dd..2676c7e1e 100644 --- a/src/crypto/certstore.c +++ b/src/crypto/certstore.c @@ -116,13 +116,13 @@ struct x509_certificate * certstore_find ( struct asn1_cursor *raw ) { * @v key Private key * @ret cert X.509 certificate, or NULL if not found */ -struct x509_certificate * certstore_find_key ( struct asn1_cursor *key ) { +struct x509_certificate * certstore_find_key ( struct private_key *key ) { struct x509_certificate *cert; /* Search for certificate within store */ list_for_each_entry ( cert, &certstore.links, store.list ) { if ( pubkey_match ( cert->signature_algorithm->pubkey, - key->data, key->len, + key->builder.data, key->builder.len, cert->subject.public_key.raw.data, cert->subject.public_key.raw.len ) == 0 ) return certstore_found ( cert ); diff --git a/src/crypto/privkey.c b/src/crypto/privkey.c index 7ef04880f..c15edf130 100644 --- a/src/crypto/privkey.c +++ b/src/crypto/privkey.c @@ -64,9 +64,12 @@ __asm__ ( ".section \".rodata\", \"a\", " PROGBITS "\n\t" ".previous\n\t" ); /** Private key */ -struct asn1_cursor private_key = { - .data = private_key_data, - .len = ( ( size_t ) private_key_len ), +struct private_key private_key = { + .refcnt = REF_INIT ( ref_no_free ), + .builder = { + .data = private_key_data, + .len = ( ( size_t ) private_key_len ), + }, }; /** Default private key */ @@ -83,6 +86,19 @@ static struct setting privkey_setting __setting ( SETTING_CRYPTO, privkey ) = { .type = &setting_type_hex, }; +/** + * Free private key + * + * @v refcnt Reference counter + */ +void privkey_free ( struct refcnt *refcnt ) { + struct private_key *key = + container_of ( refcnt, struct private_key, refcnt ); + + free ( key->builder.data ); + free ( key ); +} + /** * Apply private key configuration settings * @@ -98,23 +114,24 @@ static int privkey_apply_settings ( void ) { if ( ALLOW_KEY_OVERRIDE ) { /* Restore default private key */ - memcpy ( &private_key, &default_private_key, - sizeof ( private_key ) ); + memcpy ( &private_key.builder, &default_private_key, + sizeof ( private_key.builder ) ); /* Fetch new private key, if any */ free ( key_data ); if ( ( len = fetch_raw_setting_copy ( NULL, &privkey_setting, &key_data ) ) >= 0 ) { - private_key.data = key_data; - private_key.len = len; + private_key.builder.data = key_data; + private_key.builder.len = len; } } /* Debug */ - if ( private_key.len ) { + if ( private_key.builder.len ) { DBGC ( &private_key, "PRIVKEY using %s private key:\n", ( key_data ? "external" : "built-in" ) ); - DBGC_HDA ( &private_key, 0, private_key.data, private_key.len ); + DBGC_HDA ( &private_key, 0, private_key.builder.data, + private_key.builder.len ); } else { DBGC ( &private_key, "PRIVKEY has no private key\n" ); } diff --git a/src/include/ipxe/certstore.h b/src/include/ipxe/certstore.h index e4c789cfd..ce96666cf 100644 --- a/src/include/ipxe/certstore.h +++ b/src/include/ipxe/certstore.h @@ -11,11 +11,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include extern struct x509_chain certstore; extern struct x509_certificate * certstore_find ( struct asn1_cursor *raw ); -extern struct x509_certificate * certstore_find_key ( struct asn1_cursor *key ); +extern struct x509_certificate * certstore_find_key ( struct private_key *key ); extern void certstore_add ( struct x509_certificate *cert ); extern void certstore_del ( struct x509_certificate *cert ); diff --git a/src/include/ipxe/privkey.h b/src/include/ipxe/privkey.h index 81108b6bf..a65cf6106 100644 --- a/src/include/ipxe/privkey.h +++ b/src/include/ipxe/privkey.h @@ -10,7 +10,60 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include -extern struct asn1_cursor private_key; +/** A private key */ +struct private_key { + /** Reference counter */ + struct refcnt refcnt; + /** ASN.1 object builder */ + struct asn1_builder builder; +}; + +/** + * Get reference to private key + * + * @v key Private key + * @ret key Private key + */ +static inline __attribute__ (( always_inline )) struct private_key * +privkey_get ( struct private_key *key ) { + ref_get ( &key->refcnt ); + return key; +} + +/** + * Drop reference to private key + * + * @v key Private key + */ +static inline __attribute__ (( always_inline )) void +privkey_put ( struct private_key *key ) { + ref_put ( &key->refcnt ); +} + +/** + * Get private key ASN.1 cursor + * + * @v key Private key + * @ret cursor ASN.1 cursor + */ +static inline __attribute__ (( always_inline )) struct asn1_cursor * +privkey_cursor ( struct private_key *key ) { + return asn1_built ( &key->builder ); +} + +extern void privkey_free ( struct refcnt *refcnt ); + +/** + * Initialise empty private key + * + */ +static inline __attribute__ (( always_inline )) void +privkey_init ( struct private_key *key ) { + ref_init ( &key->refcnt, privkey_free ); +} + +extern struct private_key private_key; #endif /* _IPXE_PRIVKEY_H */ diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 8345c9a26..8b03579cc 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -257,6 +258,8 @@ struct tls_session { const char *name; /** Root of trust */ struct x509_root *root; + /** Private key */ + struct private_key *key; /** Session ID */ uint8_t id[32]; @@ -322,6 +325,8 @@ struct tls_connection { struct digest_algorithm *handshake_digest; /** Digest algorithm context used for handshake verification */ uint8_t *handshake_ctx; + /** Private key */ + struct private_key *key; /** Client certificate chain (if used) */ struct x509_chain *certs; /** Secure renegotiation flag */ @@ -384,6 +389,6 @@ struct tls_connection { #define TLS_RX_ALIGN 16 extern int add_tls ( struct interface *xfer, const char *name, - struct x509_root *root ); + struct x509_root *root, struct private_key *key ); #endif /* _IPXE_TLS_H */ diff --git a/src/net/tcp/https.c b/src/net/tcp/https.c index eae8ae5dc..85f1f124f 100644 --- a/src/net/tcp/https.c +++ b/src/net/tcp/https.c @@ -46,7 +46,7 @@ FEATURE ( FEATURE_PROTOCOL, "HTTPS", DHCP_EB_FEATURE_HTTPS, 1 ); */ static int https_filter ( struct http_connection *conn ) { - return add_tls ( &conn->socket, conn->uri->host, NULL ); + return add_tls ( &conn->socket, conn->uri->host, NULL, NULL ); } /** HTTPS URI opener */ diff --git a/src/net/tcp/syslogs.c b/src/net/tcp/syslogs.c index f91864a44..f1f70d59e 100644 --- a/src/net/tcp/syslogs.c +++ b/src/net/tcp/syslogs.c @@ -246,7 +246,7 @@ static int apply_syslogs_settings ( void ) { } /* Add TLS filter */ - if ( ( rc = add_tls ( &syslogs, server, NULL ) ) != 0 ) { + if ( ( rc = add_tls ( &syslogs, server, NULL, NULL ) ) != 0 ) { DBG ( "SYSLOGS cannot create TLS filter: %s\n", strerror ( rc ) ); goto err_add_tls; diff --git a/src/net/tls.c b/src/net/tls.c index 046378392..3c4144450 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -352,6 +352,7 @@ static void free_tls_session ( struct refcnt *refcnt ) { /* Free dynamically-allocated resources */ x509_root_put ( session->root ); + privkey_put ( session->key ); free ( session->ticket ); /* Free session */ @@ -383,6 +384,7 @@ static void free_tls ( struct refcnt *refcnt ) { x509_chain_put ( tls->certs ); x509_chain_put ( tls->chain ); x509_root_put ( tls->root ); + privkey_put ( tls->key ); /* Drop reference to session */ assert ( list_empty ( &tls->list ) ); @@ -1259,6 +1261,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { struct digest_algorithm *digest = tls->handshake_digest; struct x509_certificate *cert = x509_first ( tls->certs ); struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey; + struct asn1_cursor *key = privkey_cursor ( tls->key ); uint8_t digest_out[ digest->digestsize ]; uint8_t ctx[ pubkey->ctxsize ]; struct tls_signature_hash_algorithm *sig_hash = NULL; @@ -1268,8 +1271,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { tls_verify_handshake ( tls, digest_out ); /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, ctx, private_key.data, - private_key.len ) ) != 0 ) { + if ( ( rc = pubkey_init ( pubkey, ctx, key->data, key->len ) ) != 0 ) { DBGC ( tls, "TLS %p could not initialise %s client private " "key: %s\n", tls, pubkey->name, strerror ( rc ) ); goto err_pubkey_init; @@ -1876,7 +1878,7 @@ static int tls_new_certificate_request ( struct tls_connection *tls, tls->certs = NULL; /* Determine client certificate to be sent */ - cert = certstore_find_key ( &private_key ); + cert = certstore_find_key ( tls->key ); if ( ! cert ) { DBGC ( tls, "TLS %p could not find certificate corresponding " "to private key\n", tls ); @@ -3100,7 +3102,8 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { /* Find existing matching session, if any */ list_for_each_entry ( session, &tls_sessions, list ) { if ( ( strcmp ( name, session->name ) == 0 ) && - ( tls->root == session->root ) ) { + ( tls->root == session->root ) && + ( tls->key == session->key ) ) { ref_get ( &session->refcnt ); tls->session = session; DBGC ( tls, "TLS %p joining session %s\n", tls, name ); @@ -3120,6 +3123,7 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { strcpy ( name_copy, name ); session->name = name_copy; session->root = x509_root_get ( tls->root ); + session->key = privkey_get ( tls->key ); INIT_LIST_HEAD ( &session->conn ); list_add ( &session->list, &tls_sessions ); @@ -3147,10 +3151,11 @@ static int tls_session ( struct tls_connection *tls, const char *name ) { * @v xfer Data transfer interface * @v name Host name * @v root Root of trust (or NULL to use default) + * @v key Private key (or NULL to use default) * @ret rc Return status code */ int add_tls ( struct interface *xfer, const char *name, - struct x509_root *root ) { + struct x509_root *root, struct private_key *key ) { struct tls_connection *tls; int rc; @@ -3168,6 +3173,7 @@ int add_tls ( struct interface *xfer, const char *name, intf_init ( &tls->validator, &tls_validator_desc, &tls->refcnt ); process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt ); + tls->key = privkey_get ( key ? key : &private_key ); tls->root = x509_root_get ( root ? root : &root_certificates ); tls->version = TLS_VERSION_TLS_1_2; tls_clear_cipher ( tls, &tls->tx_cipherspec ); -- cgit v1.2.3-55-g7522 From f47a45ea2d4ff0f7b725e0c069948c81ef8b67a1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 16 Dec 2020 13:29:06 +0000 Subject: [iphone] Add iPhone tethering driver USB tethering via an iPhone is unreasonably complicated due to the requirement to perform a pairing operation that involves establishing a TLS session over a completely unrelated USB function that speaks a protocol that is almost, but not quite, entirely unlike TCP. Signed-off-by: Michael Brown --- src/drivers/net/iphone.c | 2268 ++++++++++++++++++++++++++++++++++++++++++++ src/drivers/net/iphone.h | 291 ++++++ src/include/ipxe/errfile.h | 1 + 3 files changed, 2560 insertions(+) create mode 100644 src/drivers/net/iphone.c create mode 100644 src/drivers/net/iphone.h (limited to 'src/include/ipxe') diff --git a/src/drivers/net/iphone.c b/src/drivers/net/iphone.c new file mode 100644 index 000000000..7d0eb4b64 --- /dev/null +++ b/src/drivers/net/iphone.c @@ -0,0 +1,2268 @@ +/* + * Copyright (C) 2020 Michael Brown . + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iphone.h" + +/** @file + * + * iPhone USB Ethernet driver + * + */ + +/* Disambiguate the various error causes */ +#define EPIPE_NO_MUX __einfo_error ( EINFO_EPIPE_NO_MUX ) +#define EINFO_EPIPE_NO_MUX \ + __einfo_uniqify ( EINFO_EPIPE, 0x01, \ + "No USB multiplexer" ) +#define EINPROGRESS_PAIRING __einfo_error ( EINFO_EINPROGRESS_PAIRING ) +#define EINFO_EINPROGRESS_PAIRING \ + __einfo_uniqify ( EINFO_EINPROGRESS, 0x01, \ + "Pairing in progress" ) +#define ENOTCONN_DISABLED __einfo_error ( EINFO_ENOTCONN_DISABLED ) +#define EINFO_ENOTCONN_DISABLED \ + __einfo_uniqify ( EINFO_ENOTCONN, IPHONE_LINK_DISABLED, \ + "Personal Hotspot disabled" ) +#define ENOTCONN_STATUS( status ) \ + EUNIQ ( EINFO_ENOTCONN, ( (status) & 0x1f ), \ + ENOTCONN_DISABLED ) + +static int ipair_create ( struct interface *xfer, unsigned int flags ); + +/** Bulk IN completion profiler */ +static struct profiler iphone_in_profiler __profiler = + { .name = "iphone.in" }; + +/** Bulk OUT profiler */ +static struct profiler iphone_out_profiler __profiler = + { .name = "iphone.out" }; + +/** List of USB multiplexers */ +static LIST_HEAD ( imuxes ); + +/** List of iPhone network devices */ +static LIST_HEAD ( iphones ); + +/****************************************************************************** + * + * iPhone pairing certificates + * + ****************************************************************************** + */ + +/** iPhone root certificate fingerprint */ +static uint8_t icert_root_fingerprint[SHA256_DIGEST_SIZE]; + +/** Root of trust for iPhone certificates */ +static struct x509_root icert_root = { + .refcnt = REF_INIT ( ref_no_free ), + .digest = &sha256_algorithm, + .count = 1, + .fingerprints = icert_root_fingerprint, +}; + +/** Single zero byte used in constructed certificates */ +static const uint8_t icert_nul[] = { 0x00 }; + +/** "RSA algorithm" identifier used in constructed certificates */ +static const uint8_t icert_rsa[] = { + /* algorithm */ + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_RSAENCRYPTION ), + ASN1_NULL, 0x00 ) +}; + +/** "SHA-256 with RSA algorithm" identifier used in constructed certificates */ +static const uint8_t icert_sha256_rsa[] = { + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_SHA256WITHRSAENCRYPTION ), + ASN1_NULL, 0x00 ), +}; + +/** Extensions used in constructed root certificate */ +static const uint8_t icert_root_exts_data[] = { + /* extensions */ + ASN1_SHORT ( ASN1_EXPLICIT_TAG ( 3 ), ASN1_SHORT ( ASN1_SEQUENCE, + /* basicConstraints */ + ASN1_SHORT ( ASN1_SEQUENCE, + /* extnID */ + ASN1_SHORT ( ASN1_OID, ASN1_OID_BASICCONSTRAINTS ), + /* critical */ + ASN1_SHORT ( ASN1_BOOLEAN, 0xff ), + /* extnValue */ + ASN1_SHORT ( ASN1_OCTET_STRING, + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_BOOLEAN, + 0xff ) ) ) ) ) ) +}; + +/** Extensions used in constructed root certificate */ +static struct asn1_cursor icert_root_exts = + ASN1_CURSOR ( icert_root_exts_data ); + +/** Extensions used in constructed leaf certificates */ +static const uint8_t icert_leaf_exts_data[] = { + /* extensions */ + ASN1_SHORT ( ASN1_EXPLICIT_TAG ( 3 ), ASN1_SHORT ( ASN1_SEQUENCE, + /* basicConstraints */ + ASN1_SHORT ( ASN1_SEQUENCE, + /* extnID */ + ASN1_SHORT ( ASN1_OID, ASN1_OID_BASICCONSTRAINTS ), + /* critical */ + ASN1_SHORT ( ASN1_BOOLEAN, 0xff ), + /* extnValue */ + ASN1_SHORT ( ASN1_OCTET_STRING, + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_BOOLEAN, + 0x00 ) ) ) ), + /* keyUsage */ + ASN1_SHORT ( ASN1_SEQUENCE, + /* extnID */ + ASN1_SHORT ( ASN1_OID, ASN1_OID_KEYUSAGE ), + /* critical */ + ASN1_SHORT ( ASN1_BOOLEAN, 0xff ), + /* extnValue */ + ASN1_SHORT ( ASN1_OCTET_STRING, + ASN1_SHORT ( ASN1_BIT_STRING, 0x07, + ( X509_DIGITAL_SIGNATURE | + X509_KEY_ENCIPHERMENT ), + 0x00 ) ) ) ) ) +}; + +/** Extensions used in constructed leaf certificates */ +static struct asn1_cursor icert_leaf_exts = + ASN1_CURSOR ( icert_leaf_exts_data ); + +/** "TBSCertificate" prefix in constructed certificates */ +static const uint8_t icert_tbs_prefix[] = { + /* version */ + ASN1_SHORT ( ASN1_EXPLICIT_TAG ( 0 ), ASN1_SHORT ( ASN1_INTEGER, 2 ) ), + /* serialNumber */ + ASN1_SHORT ( ASN1_INTEGER, 0 ), + /* signature */ + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_SHA256WITHRSAENCRYPTION ), + ASN1_NULL, 0x00 ) +}; + +/** Validity period in constructed certificates */ +static const uint8_t icert_validity[] = { + /* validity */ + ASN1_SHORT ( ASN1_SEQUENCE, + /* notBefore */ + ASN1_SHORT ( ASN1_GENERALIZED_TIME, + '1', '9', '7', '8', '1', '2', '1', '0', + '2', '2', '0', '0', '0', '0', 'Z' ), + /* notAfter */ + ASN1_SHORT ( ASN1_GENERALIZED_TIME, + '2', '9', '9', '9', '0', '1', '0', '1', + '0', '0', '0', '0', '0', '0', 'Z' ) ) +}; + +/** "Root" subject name */ +static const uint8_t icert_name_root_data[] = { + ASN1_SHORT ( ASN1_SEQUENCE, ASN1_SHORT ( ASN1_SET, + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_COMMON_NAME ), + ASN1_SHORT ( ASN1_UTF8_STRING, 'R', 'o', 'o', 't' ) ) ) ) +}; + +/** "Root" subject name */ +static struct asn1_cursor icert_name_root = + ASN1_CURSOR ( icert_name_root_data ); + +/** "iPXE" subject name */ +static const uint8_t icert_name_ipxe_data[] = { + ASN1_SHORT ( ASN1_SEQUENCE, ASN1_SHORT ( ASN1_SET, + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_COMMON_NAME ), + ASN1_SHORT ( ASN1_UTF8_STRING, 'i', 'P', 'X', 'E' ) ) ) ) +}; + +/** "iPXE" subject name */ +static struct asn1_cursor icert_name_ipxe = + ASN1_CURSOR ( icert_name_ipxe_data ); + +/** "iPhone" subject name */ +static const uint8_t icert_name_iphone_data[] = { + ASN1_SHORT ( ASN1_SEQUENCE, ASN1_SHORT ( ASN1_SET, + ASN1_SHORT ( ASN1_SEQUENCE, + ASN1_SHORT ( ASN1_OID, ASN1_OID_COMMON_NAME ), + ASN1_SHORT ( ASN1_UTF8_STRING, + 'i', 'P', 'h', 'o', 'n', 'e' ) ) ) ) +}; + +/** "iPhone" subject name */ +static struct asn1_cursor icert_name_iphone = + ASN1_CURSOR ( icert_name_iphone_data ); + +/** Public key(s) used for pairing */ +static const uint8_t icert_public_a[] __unused = { + 0x02, 0x81, 0x81, 0x00, 0xc9, 0xc0, 0xdd, 0xa6, 0xd5, 0xf9, 0x05, 0x3e, + 0x1d, 0xcb, 0x67, 0x08, 0xa8, 0x50, 0x27, 0x63, 0x95, 0x87, 0x42, 0x7e, + 0xfb, 0xff, 0x55, 0x55, 0xb8, 0xc0, 0x6f, 0x13, 0xcb, 0xf7, 0xc5, 0x1b, + 0xda, 0x44, 0x3c, 0xbc, 0x1a, 0xe1, 0x15, 0x1e, 0xab, 0x56, 0x74, 0x02, + 0x8b, 0xb3, 0xcd, 0x42, 0x56, 0xcd, 0x9c, 0xc3, 0x15, 0xe2, 0x33, 0x97, + 0x6d, 0x77, 0xdd, 0x20, 0x3a, 0x74, 0xb1, 0x4c, 0xee, 0xeb, 0xe8, 0xaa, + 0x20, 0x71, 0x5a, 0xa2, 0x5b, 0xf8, 0x1a, 0xcb, 0xd2, 0x7b, 0x96, 0xb6, + 0x42, 0xb4, 0x7c, 0x7a, 0x13, 0xec, 0x55, 0xd3, 0x36, 0x8b, 0xe3, 0x17, + 0xc5, 0xc4, 0xcc, 0xe0, 0x27, 0x8c, 0xed, 0xa1, 0x4c, 0x8a, 0x50, 0x4a, + 0x1c, 0xc4, 0x58, 0xf6, 0xcd, 0xcc, 0xc3, 0x5f, 0xe6, 0x3c, 0xff, 0x97, + 0x51, 0xed, 0xf5, 0xaa, 0x89, 0xcc, 0x3f, 0x63, 0x67, 0x46, 0x9f, 0xbf, + 0x02, 0x03, 0x01, 0x00, 0x01 +}; +static const uint8_t icert_public_b[] __unused = { + 0x02, 0x81, 0x81, 0x00, 0xcd, 0x96, 0x81, 0x78, 0xbb, 0x2e, 0x64, 0xda, + 0xd3, 0x7e, 0xd7, 0x3a, 0xac, 0x3f, 0x00, 0xe5, 0x41, 0x65, 0x56, 0xac, + 0x2d, 0x77, 0xc0, 0x1a, 0xad, 0x32, 0xca, 0x0c, 0x72, 0xae, 0xdb, 0x57, + 0xc1, 0xc7, 0x79, 0xef, 0xc6, 0x71, 0x9f, 0xad, 0x82, 0x14, 0x94, 0x4b, + 0xf9, 0xd8, 0x78, 0xf1, 0xca, 0x99, 0xf5, 0x71, 0x07, 0x88, 0xd7, 0x55, + 0xc7, 0xcb, 0x36, 0x5d, 0xdb, 0x84, 0x46, 0xac, 0x05, 0xea, 0xf1, 0xe1, + 0xbe, 0x91, 0x50, 0x85, 0x1e, 0x64, 0xab, 0x02, 0x82, 0xab, 0xba, 0x42, + 0x06, 0x5a, 0xe3, 0xc3, 0x25, 0xd0, 0x95, 0x04, 0x54, 0xb4, 0x44, 0x40, + 0x5a, 0x42, 0x06, 0x04, 0x7d, 0x3b, 0x9e, 0xaf, 0x2e, 0xe9, 0xc8, 0xad, + 0x46, 0x3a, 0xff, 0xe2, 0x39, 0xc8, 0x48, 0x0a, 0x49, 0xaa, 0xfe, 0x1f, + 0x6c, 0x91, 0x5d, 0x1d, 0xd6, 0xb0, 0x04, 0xd1, 0x6c, 0xb2, 0x43, 0xaf, + 0x02, 0x03, 0x01, 0x00, 0x01 +}; + +/** + * "Private" key(s) used for pairing + * + * Yes, this publicly visible "private" key completely obviates any + * nominal security provided by the pairing process. Looked at + * another way, this modifies the iPhone to behave like every other + * USB tethering device: if the cable is physically connected and + * tethering is enabled then the device will Just Work. + * + * Unlike Android, the iPhone seems to have no meaningful permissions + * model: any device that is trusted to use the phone for tethering + * seems to also be trusted to use the iPhone for any other purpose + * (e.g. accessing files, reading messages, etc). Apple should + * probably fix this at some point, e.g. via defining extended key + * usages in the root and host certificates. + */ +static const uint8_t icert_private_a[] __unused = { + 0x02, 0x81, 0x80, 0x1d, 0x60, 0xb7, 0x25, 0xdf, 0x0c, 0x76, 0xc5, 0xf7, + 0xc2, 0xb1, 0x8b, 0x22, 0x2f, 0x21, 0xbd, 0x2f, 0x7d, 0xd5, 0xa1, 0xf6, + 0x01, 0xd5, 0x24, 0x39, 0x55, 0xd4, 0x16, 0xd6, 0xe1, 0x8a, 0x53, 0x26, + 0xf2, 0x3e, 0xc1, 0xc9, 0x4c, 0x33, 0x2e, 0x17, 0x16, 0xec, 0xa7, 0x9e, + 0x3e, 0x1d, 0x4a, 0x66, 0xa7, 0x64, 0x07, 0x48, 0x3d, 0x7a, 0xf3, 0xb6, + 0xdd, 0xf8, 0x56, 0x04, 0x0d, 0x0f, 0xef, 0xf8, 0xbd, 0xbc, 0x73, 0xe2, + 0xc2, 0xae, 0x1b, 0x87, 0x90, 0x18, 0x2a, 0x68, 0xff, 0xae, 0x49, 0xdf, + 0x7c, 0xff, 0xe8, 0x44, 0xa8, 0x3e, 0x4e, 0x4f, 0xf5, 0xfa, 0x51, 0x96, + 0xb8, 0x08, 0xf3, 0x18, 0xd6, 0x52, 0xdf, 0x3a, 0x8a, 0xed, 0xda, 0xcd, + 0xb4, 0x06, 0x99, 0x41, 0xcb, 0x23, 0x17, 0xaf, 0xc3, 0x3e, 0xfe, 0xdf, + 0x97, 0xf3, 0xd6, 0x18, 0x7e, 0x03, 0xaf, 0x62, 0xb2, 0xc8, 0xc9 +}; +static const uint8_t icert_private_b[] __unused = { + 0x02, 0x81, 0x80, 0x45, 0xbd, 0xc0, 0xbe, 0x0c, 0x01, 0x79, 0x05, 0x22, + 0xa9, 0xec, 0xa9, 0x62, 0xb5, 0x1c, 0xc0, 0xa8, 0xa6, 0x8f, 0xf8, 0x68, + 0x94, 0x2e, 0xfe, 0xdd, 0xb2, 0x55, 0x08, 0x53, 0xff, 0x2d, 0x39, 0x5f, + 0xeb, 0x23, 0x5a, 0x4b, 0x9f, 0x4f, 0xe3, 0xb4, 0x34, 0xf6, 0xf9, 0xaf, + 0x0f, 0xd8, 0x37, 0x6d, 0xdb, 0x3c, 0x7f, 0xd3, 0x66, 0x80, 0x66, 0x01, + 0x18, 0xd6, 0xa0, 0x90, 0x4f, 0x17, 0x09, 0xb8, 0x68, 0x44, 0xf0, 0xde, + 0x16, 0x4a, 0x8a, 0x0d, 0xa7, 0x5f, 0xb5, 0x4c, 0x53, 0xcc, 0x21, 0xdd, + 0x4f, 0x05, 0x64, 0xa5, 0xc5, 0xac, 0x2c, 0xd8, 0x0a, 0x7b, 0xf5, 0xa4, + 0x63, 0x32, 0xb0, 0x2c, 0xf8, 0xef, 0x8c, 0xf8, 0x2c, 0xba, 0x1c, 0x2c, + 0xc7, 0x0a, 0xf3, 0xe9, 0x8f, 0xfb, 0x0a, 0x61, 0x1b, 0x3a, 0xdd, 0x9f, + 0x74, 0x7d, 0xb3, 0x42, 0x59, 0x52, 0x07, 0x59, 0x8e, 0xb7, 0x41 +}; + +/** Key pair selection + * + * This exists only to allow for testing of the process for handling a + * failed TLS negotiation. + */ +#define icert_key_suffix a +#define icert_key_variable( prefix ) _C2 ( prefix, icert_key_suffix ) +#define icert_public icert_key_variable ( icert_public_ ) +#define icert_private icert_key_variable ( icert_private_ ) + +/** PEM certificate prefix */ +static const char icert_begin[] = "-----BEGIN CERTIFICATE-----\n"; + +/** PEM certificate suffix */ +static const char icert_end[] = "\n-----END CERTIFICATE-----\n"; + +/** + * Free pairing certificates + * + * @v icert Pairing certificates + */ +static void icert_free ( struct icert *icert ) { + + privkey_put ( icert->key ); + x509_put ( icert->root ); + x509_put ( icert->host ); + x509_put ( icert->device ); + memset ( icert, 0, sizeof ( *icert ) ); +} + +/** + * Construct certificate + * + * @v icert Pairing certificates + * @v subject Subject name + * @v issuer Issuer name + * @v private Private key + * @v public Public key + * @v exts Certificate extensions + * @v cert Certificate to fill in + * @ret rc Return status code + * + * On success, the caller is responsible for eventually calling + * x509_put() on the allocated encoded certificate. + */ +static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, + struct asn1_cursor *issuer, struct asn1_cursor *private, + struct asn1_cursor *public, struct asn1_cursor *exts, + struct x509_certificate **cert ) { + struct digest_algorithm *digest = &sha256_algorithm; + struct pubkey_algorithm *pubkey = &rsa_algorithm; + struct asn1_builder spki = { NULL, 0 }; + struct asn1_builder tbs = { NULL, 0 }; + struct asn1_builder raw = { NULL, 0 }; + uint8_t digest_ctx[SHA256_CTX_SIZE]; + uint8_t digest_out[SHA256_DIGEST_SIZE]; + uint8_t pubkey_ctx[RSA_CTX_SIZE]; + int len; + int rc; + + /* Initialise "private" key */ + if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, private->data, + private->len ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not initialise private key: " + "%s\n", icert, strerror ( rc ) ); + goto err_pubkey_init; + } + + /* Construct subjectPublicKeyInfo */ + if ( ( rc = ( asn1_prepend_raw ( &spki, public->data, public->len ), + asn1_prepend_raw ( &spki, icert_nul, + sizeof ( icert_nul ) ), + asn1_wrap ( &spki, ASN1_BIT_STRING ), + asn1_prepend_raw ( &spki, icert_rsa, + sizeof ( icert_rsa ) ), + asn1_wrap ( &spki, ASN1_SEQUENCE ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build subjectPublicKeyInfo: " + "%s\n", icert, strerror ( rc ) ); + goto err_spki; + } + + /* Construct tbsCertificate */ + if ( ( rc = ( asn1_prepend_raw ( &tbs, exts->data, exts->len ), + asn1_prepend_raw ( &tbs, spki.data, spki.len ), + asn1_prepend_raw ( &tbs, subject->data, subject->len ), + asn1_prepend_raw ( &tbs, icert_validity, + sizeof ( icert_validity ) ), + asn1_prepend_raw ( &tbs, issuer->data, issuer->len ), + asn1_prepend_raw ( &tbs, icert_tbs_prefix, + sizeof ( icert_tbs_prefix ) ), + asn1_wrap ( &tbs, ASN1_SEQUENCE ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build tbsCertificate: %s\n", + icert, strerror ( rc ) ); + goto err_tbs; + } + + /* Calculate certificate digest */ + digest_init ( digest, digest_ctx ); + digest_update ( digest, digest_ctx, tbs.data, tbs.len ); + digest_final ( digest, digest_ctx, digest_out ); + + /* Construct signature */ + if ( ( rc = asn1_grow ( &raw, pubkey_max_len ( pubkey, + pubkey_ctx ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build signature: %s\n", + icert, strerror ( rc ) ); + goto err_grow; + } + if ( ( len = pubkey_sign ( pubkey, pubkey_ctx, digest, digest_out, + raw.data ) ) < 0 ) { + rc = len; + DBGC ( icert, "ICERT %p could not sign: %s\n", + icert, strerror ( rc ) ); + goto err_pubkey_sign; + } + assert ( ( ( size_t ) len ) == raw.len ); + + /* Construct raw certificate data */ + if ( ( rc = ( asn1_prepend_raw ( &raw, icert_nul, + sizeof ( icert_nul ) ), + asn1_wrap ( &raw, ASN1_BIT_STRING ), + asn1_prepend_raw ( &raw, icert_sha256_rsa, + sizeof ( icert_sha256_rsa ) ), + asn1_prepend_raw ( &raw, tbs.data, tbs.len ), + asn1_wrap ( &raw, ASN1_SEQUENCE ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build certificate: %s\n", + icert, strerror ( rc ) ); + goto err_raw; + } + + /* Parse certificate */ + if ( ( rc = x509_certificate ( raw.data, raw.len, cert ) ) != 0 ) { + DBGC ( icert, "ICERT %p invalid certificate: %s\n", + icert, strerror ( rc ) ); + DBGC_HDA ( icert, 0, raw.data, raw.len ); + goto err_x509; + } + + err_x509: + err_raw: + err_pubkey_sign: + free ( raw.data ); + err_grow: + free ( tbs.data ); + err_tbs: + free ( spki.data ); + err_spki: + pubkey_final ( pubkey, pubkey_ctx ); + err_pubkey_init: + return rc; +} + +/** + * Construct certificates + * + * @v icert Certificate set + * @v pubkey Device public key + * @ret rc Return status code + */ +static int icert_certs ( struct icert *icert, struct asn1_cursor *key ) { + struct digest_algorithm *digest = icert_root.digest; + struct asn1_builder public = { NULL, 0 }; + struct asn1_builder *private; + int rc; + + /* Free any existing key and certificates */ + icert_free ( icert ); + + /* Allocate "private" key */ + icert->key = zalloc ( sizeof ( *icert->key ) ); + if ( ! icert->key ) { + rc = -ENOMEM; + goto error; + } + privkey_init ( icert->key ); + private = &icert->key->builder; + + /* Construct our "private" key */ + if ( ( rc = ( asn1_prepend_raw ( private, icert_private, + sizeof ( icert_private ) ), + asn1_prepend_raw ( private, icert_public, + sizeof ( icert_public ) ), + asn1_prepend ( private, ASN1_INTEGER, icert_nul, + sizeof ( icert_nul ) ), + asn1_wrap ( private, ASN1_SEQUENCE ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build private key: %s\n", + icert, strerror ( rc ) ); + goto error; + } + + /* Construct our own public key */ + if ( ( rc = ( asn1_prepend_raw ( &public, icert_public, + sizeof ( icert_public ) ), + asn1_wrap ( &public, ASN1_SEQUENCE ) ) ) != 0 ) { + DBGC ( icert, "ICERT %p could not build public key: %s\n", + icert, strerror ( rc ) ); + goto error; + } + + /* Construct root certificate */ + if ( ( rc = icert_cert ( icert, &icert_name_root, &icert_name_root, + asn1_built ( private ), asn1_built ( &public ), + &icert_root_exts, &icert->root ) ) != 0 ) + goto error; + + /* Construct host certificate */ + if ( ( rc = icert_cert ( icert, &icert_name_ipxe, &icert_name_root, + asn1_built ( private ), asn1_built ( &public ), + &icert_leaf_exts, &icert->host ) ) != 0 ) + goto error; + + /* Construct device certificate */ + if ( ( rc = icert_cert ( icert, &icert_name_iphone, &icert_name_root, + asn1_built ( private ), key, + &icert_leaf_exts, &icert->device ) ) != 0 ) + goto error; + + /* Construct root of trust */ + assert ( digest->digestsize == sizeof ( icert_root_fingerprint ) ); + x509_fingerprint ( icert->root, digest, icert_root_fingerprint ); + + /* Free constructed keys */ + free ( public.data ); + return 0; + + error: + icert_free ( icert ); + free ( public.data ); + return rc; +} + +/** + * Construct doubly base64-encoded certificate + * + * @v icert Pairing certificates + * @v cert X.509 certificate + * @v encenc Doubly base64-encoded certificate to construct + * @ret rc Return status code + * + * On success, the caller is responsible for eventually calling free() + * on the allocated doubly encoded encoded certificate. + */ +static int icert_encode ( struct icert *icert, struct x509_certificate *cert, + char **encenc ) { + size_t encencoded_len; + size_t encoded_len; + size_t pem_len; + char *pem; + int rc; + + /* Sanity check */ + assert ( cert != NULL ); + + /* Create PEM */ + encoded_len = ( base64_encoded_len ( cert->raw.len ) + 1 /* NUL */ ); + pem_len = ( ( sizeof ( icert_begin ) - 1 /* NUL */ ) + + ( encoded_len - 1 /* NUL */ ) + + ( sizeof ( icert_end ) - 1 /* NUL */ ) + + 1 /* NUL */ ); + pem = malloc ( pem_len ); + if ( ! pem ) { + rc = -ENOMEM; + goto err_alloc_pem; + } + strcpy ( pem, icert_begin ); + base64_encode ( cert->raw.data, cert->raw.len, + ( pem + sizeof ( icert_begin ) - 1 /* NUL */ ), + encoded_len ); + strcpy ( ( pem + + ( sizeof ( icert_begin ) - 1 /* NUL */ ) + + ( encoded_len - 1 /* NUL */ ) ), icert_end ); + DBGC2 ( icert, "ICERT %p \"%s\" certificate:\n%s", + icert, x509_name ( cert ), pem ); + + /* Base64-encode the PEM (sic) */ + encencoded_len = ( base64_encoded_len ( pem_len - 1 /* NUL */ ) + + 1 /* NUL */ ); + *encenc = malloc ( encencoded_len ); + if ( ! *encenc ) { + rc = -ENOMEM; + goto err_alloc_encenc; + } + base64_encode ( pem, ( pem_len - 1 /* NUL */ ), *encenc, + encencoded_len ); + + /* Success */ + rc = 0; + + err_alloc_encenc: + free ( pem ); + err_alloc_pem: + return rc; +} + +/****************************************************************************** + * + * iPhone USB multiplexer + * + ****************************************************************************** + * + * The iPhone USB multiplexer speaks a protocol that is almost, but + * not quite, entirely unlike TCP. + * + */ + +/** + * Transmit message + * + * @v imux USB multiplexer + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int imux_tx ( struct imux *imux, struct io_buffer *iobuf ) { + struct imux_header *hdr = iobuf->data; + size_t len = iob_len ( iobuf ); + int rc; + + /* Populate header */ + assert ( len >= sizeof ( *hdr ) ); + hdr->len = htonl ( len ); + hdr->in_seq = htons ( imux->in_seq ); + hdr->out_seq = htons ( imux->out_seq ); + DBGCP ( imux, "IMUX %p transmitting:\n", imux ); + DBGCP_HDA ( imux, 0, hdr, len ); + + /* Transmit message */ + if ( ( rc = usb_stream ( &imux->usbnet.out, iobuf, 1 ) ) != 0 ) + goto err; + + /* Increment sequence number */ + imux->out_seq++; + + return 0; + + err: + free_iob ( iobuf ); + return rc; +} + +/** + * Transmit version message + * + * @v imux USB multiplexer + * @ret rc Return status code + */ +static int imux_tx_version ( struct imux *imux ) { + struct io_buffer *iobuf; + struct imux_header_version *vers; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( sizeof ( *vers ) ); + if ( ! iobuf ) + return -ENOMEM; + vers = iob_put ( iobuf, sizeof ( *vers ) ); + + /* Construct version message */ + memset ( vers, 0, sizeof ( *vers ) ); + vers->hdr.protocol = htonl ( IMUX_VERSION ); + + /* Transmit message */ + if ( ( rc = imux_tx ( imux, iob_disown ( iobuf ) ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Transmit pseudo-TCP message + * + * @v imux USB multiplexer + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int imux_tx_tcp ( struct imux *imux, struct io_buffer *iobuf ) { + struct imux_header_tcp *tcp = iobuf->data; + size_t len = iob_len ( iobuf ); + int rc; + + /* Populate TCP header */ + assert ( len >= sizeof ( *tcp ) ); + tcp->hdr.protocol = htonl ( IMUX_TCP ); + tcp->tcp.src = htons ( imux->port ); + tcp->tcp.dest = htons ( IMUX_PORT_LOCKDOWND ); + tcp->tcp.seq = htonl ( imux->tcp_seq ); + tcp->tcp.ack = htonl ( imux->tcp_ack ); + tcp->tcp.hlen = ( ( sizeof ( tcp->tcp ) / 4 ) << 4 ); + tcp->tcp.win = htons ( IMUX_WINDOW ); + + /* Transmit message */ + if ( ( rc = imux_tx ( imux, iob_disown ( iobuf ) ) ) != 0 ) + return rc; + + /* Update TCP sequence */ + imux->tcp_seq += ( len - sizeof ( *tcp ) ); + + return 0; +} + +/** + * Transmit pseudo-TCP SYN + * + * @v imux USB multiplexer + * @ret rc Return status code + */ +static int imux_tx_syn ( struct imux *imux ) { + struct io_buffer *iobuf; + struct imux_header_tcp *syn; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( sizeof ( *syn ) ); + if ( ! iobuf ) + return -ENOMEM; + syn = iob_put ( iobuf, sizeof ( *syn ) ); + + /* Construct TCP SYN message */ + memset ( syn, 0, sizeof ( *syn ) ); + syn->tcp.flags = TCP_SYN; + + /* Transmit message */ + if ( ( rc = imux_tx_tcp ( imux, iob_disown ( iobuf ) ) ) != 0 ) + return rc; + + /* Increment TCP sequence to compensate for SYN */ + imux->tcp_seq++; + + return 0; +} + +/** + * Open pairing client + * + * @v imux USB multiplexer + * @ret rc Return status code + */ +static int imux_start_pair ( struct imux *imux ) { + int rc; + + /* Disconnect any existing pairing client */ + intf_restart ( &imux->tcp, -EPIPE ); + + /* Create pairing client */ + if ( ( rc = ipair_create ( &imux->tcp, imux->flags ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Receive version message + * + * @v imux USB multiplexer + */ +static void imux_rx_version ( struct imux *imux ) { + + /* Reset output sequence */ + imux->out_seq = 0; + + /* Send TCP SYN */ + imux->action = imux_tx_syn; +} + +/** + * Receive log message + * + * @v imux USB multiplexer + * @v hdr Message header + * @v len Length of message + */ +static void imux_rx_log ( struct imux *imux, struct imux_header *hdr, + size_t len ) { + struct imux_header_log *log = + container_of ( hdr, struct imux_header_log, hdr ); + unsigned int level; + size_t msg_len; + char *tmp; + + /* Sanity check */ + if ( len < sizeof ( *log ) ) { + DBGC ( imux, "IMUX %p malformed log message:\n", imux ); + DBGC_HDA ( imux, 0, log, len ); + return; + } + + /* First byte is the log level, followed by a printable + * message with no NUL terminator. Extract the log level, + * then shuffle the message down within the buffer and append + * a NUL terminator. + */ + msg_len = ( len - sizeof ( *hdr ) ); + level = log->level; + tmp = ( ( void * ) &log->level ); + memmove ( tmp, &log->msg, msg_len ); + tmp[msg_len] = '\0'; + + /* Print log message */ + DBGC ( imux, "IMUX %p <%d>: %s\n", imux, level, tmp ); +} + +/** + * Receive pseudo-TCP SYN+ACK + * + * @v imux USB multiplexer + */ +static void imux_rx_syn ( struct imux *imux ) { + + /* Increment TCP acknowledgement to compensate for SYN */ + imux->tcp_ack++; + + /* Start pairing client */ + imux->action = imux_start_pair; +} + +/** + * Receive pseudo-TCP message + * + * @v imux USB multiplexer + * @v iobuf I/O buffer + */ +static void imux_rx_tcp ( struct imux *imux, struct io_buffer *iobuf ) { + struct imux_header_tcp *tcp = iobuf->data; + size_t len = iob_len ( iobuf ); + int rc; + + /* Sanity check */ + if ( len < sizeof ( *tcp ) ) { + DBGC ( imux, "IMUX %p malformed TCP message:\n", imux ); + DBGC_HDA ( imux, 0, tcp, len ); + goto error; + } + + /* Ignore unexpected packets */ + if ( tcp->tcp.dest != htons ( imux->port ) ) { + DBGC ( imux, "IMUX %p ignoring unexpected TCP port %d:\n", + imux, ntohs ( tcp->tcp.dest ) ); + DBGC_HDA ( imux, 0, tcp, len ); + goto error; + } + + /* Ignore resets */ + if ( tcp->tcp.flags & TCP_RST ) { + DBGC ( imux, "IMUX %p ignoring TCP RST\n", imux ); + DBGC2_HDA ( imux, 0, tcp, len ); + goto error; + } + + /* Record ACK number */ + imux->tcp_ack = ( ntohl ( tcp->tcp.seq ) + len - sizeof ( *tcp ) ); + + /* Handle received message */ + if ( tcp->tcp.flags & TCP_SYN ) { + + /* Received SYN+ACK */ + imux_rx_syn ( imux ); + + } else { + + /* Strip header */ + iob_pull ( iobuf, sizeof ( *tcp ) ); + + /* Deliver via socket */ + if ( ( rc = xfer_deliver_iob ( &imux->tcp, + iob_disown ( iobuf ) ) ) != 0 ) + goto error; + } + + error: + free_iob ( iobuf ); +} + +/** + * Complete bulk IN transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void imux_in_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct imux *imux = container_of ( ep, struct imux, usbnet.in ); + struct imux_header *hdr = iobuf->data; + size_t len = iob_len ( iobuf ); + + /* Ignore packets cancelled when the endpoint closes */ + if ( ! ep->open ) + goto drop; + + /* Report USB errors */ + if ( rc != 0 ) { + DBGC ( imux, "IMUX %p bulk IN failed: %s\n", + imux, strerror ( rc ) ); + goto drop; + } + + /* Sanity check */ + if ( len < sizeof ( *hdr ) ) { + DBGC ( imux, "IMUX %p malformed message:\n", imux ); + DBGC_HDA ( imux, 0, hdr, len ); + goto drop; + } + + /* Record input sequence */ + imux->in_seq = ntohs ( hdr->in_seq ); + + /* Handle according to protocol */ + DBGCP ( imux, "IMUX %p received:\n", imux ); + DBGCP_HDA ( imux, 0, hdr, len ); + switch ( hdr->protocol ) { + case htonl ( IMUX_VERSION ): + imux_rx_version ( imux ); + break; + case htonl ( IMUX_LOG ): + imux_rx_log ( imux, hdr, len ); + break; + case htonl ( IMUX_TCP ): + imux_rx_tcp ( imux, iob_disown ( iobuf ) ); + break; + default: + DBGC ( imux, "IMUX %p unknown message type %d:\n", + imux, ntohl ( hdr->protocol ) ); + DBGC_HDA ( imux, 0, hdr, len ); + break; + } + + drop: + free_iob ( iobuf ); +} + +/** Bulk IN endpoint operations */ +static struct usb_endpoint_driver_operations imux_in_operations = { + .complete = imux_in_complete, +}; + +/** + * Complete bulk OUT transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void imux_out_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct imux *imux = container_of ( ep, struct imux, usbnet.out ); + + /* Report USB errors */ + if ( rc != 0 ) { + DBGC ( imux, "IMUX %p bulk OUT failed: %s\n", + imux, strerror ( rc ) ); + goto error; + } + + error: + free_iob ( iobuf ); +} + +/** Bulk OUT endpoint operations */ +static struct usb_endpoint_driver_operations imux_out_operations = { + .complete = imux_out_complete, +}; + +/** + * Shut down USB multiplexer + * + * @v imux USB multiplexer + */ +static void imux_shutdown ( struct imux *imux ) { + + /* Shut down interfaces */ + intf_shutdown ( &imux->tcp, -ECANCELED ); + + /* Close USB network device, if open */ + if ( process_running ( &imux->process ) ) { + process_del ( &imux->process ); + usbnet_close ( &imux->usbnet ); + } +} + +/** + * Close USB multiplexer + * + * @v imux USB multiplexer + * @v rc Reason for close + */ +static void imux_close ( struct imux *imux, int rc ) { + struct iphone *iphone; + + /* Restart interfaces */ + intf_restart ( &imux->tcp, rc ); + + /* Record pairing status */ + imux->rc = rc; + + /* Trigger link check on any associated iPhones */ + list_for_each_entry ( iphone, &iphones, list ) { + if ( iphone->usb == imux->usb ) + start_timer_nodelay ( &iphone->timer ); + } + + /* Retry pairing on any error */ + if ( rc != 0 ) { + + /* Increment port number */ + imux->port++; + + /* Request pairing on any retry attempt */ + imux->flags = IPAIR_REQUEST; + + /* Send new pseudo-TCP SYN */ + imux->action = imux_tx_syn; + + DBGC ( imux, "IMUX %p retrying pairing: %s\n", + imux, strerror ( rc ) ); + return; + } + + /* Shut down multiplexer on pairing success */ + imux_shutdown ( imux ); +} + +/** + * Allocate I/O buffer for pseudo-TCP socket + * + * @v imux USB multiplexer + * @v len I/O buffer payload length + * @ret iobuf I/O buffer + */ +static struct io_buffer * imux_alloc_iob ( struct imux *imux __unused, + size_t len ) { + struct imux_header_tcp *tcp; + struct io_buffer *iobuf; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( sizeof ( *tcp ) + len ); + if ( ! iobuf ) + return NULL; + + /* Reserve space for pseudo-TCP message header */ + iob_reserve ( iobuf, sizeof ( *tcp ) ); + + return iobuf; +} + +/** + * Transmit packet via pseudo-TCP socket + * + * @v imux USB multiplexer + * @v iobuf I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + */ +static int imux_deliver ( struct imux *imux, struct io_buffer *iobuf, + struct xfer_metadata *meta __unused ) { + struct imux_header_tcp *tcp; + + /* Prepend pseudo-TCP header */ + tcp = iob_push ( iobuf, sizeof ( *tcp ) ); + memset ( tcp, 0, sizeof ( *tcp ) ); + tcp->tcp.flags = TCP_ACK; + + /* Transmit pseudo-TCP packet */ + return imux_tx_tcp ( imux, iob_disown ( iobuf ) ); +} + +/** Pseudo-TCP socket interface operations */ +static struct interface_operation imux_tcp_operations[] = { + INTF_OP ( xfer_deliver, struct imux *, imux_deliver ), + INTF_OP ( xfer_alloc_iob, struct imux *, imux_alloc_iob ), + INTF_OP ( intf_close, struct imux *, imux_close ), +}; + +/** Pseudo-TCP socket interface descriptor */ +static struct interface_descriptor imux_tcp_desc = + INTF_DESC ( struct imux, tcp, imux_tcp_operations ); + +/** + * Multiplexer process + * + * @v imux USB multiplexer + */ +static void imux_step ( struct imux *imux ) { + int rc; + + /* Poll USB bus */ + usb_poll ( imux->bus ); + + /* Do nothing more if multiplexer has been closed */ + if ( ! process_running ( &imux->process ) ) + return; + + /* Refill endpoints */ + if ( ( rc = usbnet_refill ( &imux->usbnet ) ) != 0 ) { + /* Wait for next poll */ + return; + } + + /* Perform pending action, if any */ + if ( imux->action ) { + if ( ( rc = imux->action ( imux ) ) != 0 ) + imux_close ( imux, rc ); + imux->action = NULL; + } +} + +/** Multiplexer process descriptor */ +static struct process_descriptor imux_process_desc = + PROC_DESC ( struct imux, process, imux_step ); + +/** + * Probe device + * + * @v func USB function + * @v config Configuration descriptor + * @ret rc Return status code + */ +static int imux_probe ( struct usb_function *func, + struct usb_configuration_descriptor *config ) { + struct usb_device *usb = func->usb; + struct imux *imux; + int rc; + + /* Allocate and initialise structure */ + imux = zalloc ( sizeof ( *imux ) ); + if ( ! imux ) { + rc = -ENOMEM; + goto err_alloc; + } + ref_init ( &imux->refcnt, NULL ); + imux->usb = usb; + imux->bus = usb->port->hub->bus; + usbnet_init ( &imux->usbnet, func, NULL, &imux_in_operations, + &imux_out_operations ); + usb_refill_init ( &imux->usbnet.in, 0, IMUX_IN_MTU, IMUX_IN_MAX_FILL ); + process_init ( &imux->process, &imux_process_desc, &imux->refcnt ); + imux->action = imux_tx_version; + imux->port = IMUX_PORT_LOCAL; + intf_init ( &imux->tcp, &imux_tcp_desc, &imux->refcnt ); + imux->rc = -EINPROGRESS_PAIRING; + + /* Describe USB network device */ + if ( ( rc = usbnet_describe ( &imux->usbnet, config ) ) != 0 ) { + DBGC ( imux, "IMUX %p could not describe: %s\n", + imux, strerror ( rc ) ); + goto err_describe; + } + + /* Open USB network device */ + if ( ( rc = usbnet_open ( &imux->usbnet ) ) != 0 ) { + DBGC ( imux, "IMUX %p could not open: %s\n", + imux, strerror ( rc ) ); + goto err_open; + } + + /* Start polling process */ + process_add ( &imux->process ); + + /* Add to list of multiplexers */ + list_add ( &imux->list, &imuxes ); + + usb_func_set_drvdata ( func, imux ); + return 0; + + list_del ( &imux->list ); + imux_shutdown ( imux ); + err_open: + err_describe: + ref_put ( &imux->refcnt ); + err_alloc: + return rc; +} + +/** + * Remove device + * + * @v func USB function + */ +static void imux_remove ( struct usb_function *func ) { + struct imux *imux = usb_func_get_drvdata ( func ); + + list_del ( &imux->list ); + imux_shutdown ( imux ); + ref_put ( &imux->refcnt ); +} + +/** USB multiplexer device IDs */ +static struct usb_device_id imux_ids[] = { + { + .name = "imux", + .vendor = 0x05ac, + .product = USB_ANY_ID, + }, +}; + +/** USB multiplexer driver */ +struct usb_driver imux_driver __usb_driver = { + .ids = imux_ids, + .id_count = ( sizeof ( imux_ids ) / sizeof ( imux_ids[0] ) ), + .class = USB_CLASS_ID ( 0xff, 0xfe, 0x02 ), + .score = USB_SCORE_NORMAL, + .probe = imux_probe, + .remove = imux_remove, +}; + +/****************************************************************************** + * + * iPhone pairing client + * + ****************************************************************************** + */ + +/** Common prefix for all pairing messages */ +static const char ipair_prefix[] = + "\n" + "\n" + "\n" + "\n" + "Label\n" + "iPXE\n" + "Request\n"; + +/** Common suffix for all pairing messages */ +static const char ipair_suffix[] = + "\n" + "\n"; + +/** Arbitrary system BUID used for pairing */ +static const char ipair_system_buid[] = "E4DB92D2-248A-469A-AC34-92045D07E695"; + +/** Arbitrary host ID used for pairing */ +static const char ipair_host_id[] = "93CEBC27-8457-4804-9108-F42549DF6143"; + +static int ipair_tx_pubkey ( struct ipair *ipair ); +static int ipair_rx_pubkey ( struct ipair *ipair, char *msg ); +static int ipair_tx_pair ( struct ipair *ipair ); +static int ipair_rx_pair ( struct ipair *ipair, char *msg ); +static int ipair_tx_session ( struct ipair *ipair ); +static int ipair_rx_session ( struct ipair *ipair, char *msg ); + +/** + * Free pairing client + * + * @v refcnt Reference counter + */ +static void ipair_free ( struct refcnt *refcnt ) { + struct ipair *ipair = container_of ( refcnt, struct ipair, refcnt ); + + icert_free ( &ipair->icert ); + free ( ipair ); +} + +/** + * Shut down pairing client + * + * @v ipair Pairing client + * @v rc Reason for close + */ +static void ipair_close ( struct ipair *ipair, int rc ) { + + /* Shut down interfaces */ + intf_shutdown ( &ipair->xfer, rc ); + + /* Stop timer */ + stop_timer ( &ipair->timer ); +} + +/** + * Transmit XML message + * + * @v ipair Pairing client + * @v fmt Format string + * @v ... Arguments + * @ret rc Return status code + */ +static int __attribute__ (( format ( printf, 2, 3 ) )) +ipair_tx ( struct ipair *ipair, const char *fmt, ... ) { + struct io_buffer *iobuf; + struct ipair_header *hdr; + va_list args; + size_t len; + char *msg; + int rc; + + /* Calculate length of formatted string */ + va_start ( args, fmt ); + len = ( vsnprintf ( NULL, 0, fmt, args ) + 1 /* NUL */ ); + va_end ( args ); + + /* Allocate I/O buffer */ + iobuf = xfer_alloc_iob ( &ipair->xfer, ( sizeof ( *hdr ) + len ) ); + if ( ! iobuf ) + return -ENOMEM; + hdr = iob_put ( iobuf, sizeof ( *hdr ) ); + + /* Construct XML message */ + memset ( hdr, 0, sizeof ( *hdr ) ); + hdr->len = htonl ( len ); + msg = iob_put ( iobuf, len ); + vsnprintf ( msg, len, fmt, args ); + DBGC2 ( ipair, "IPAIR %p transmitting:\n%s\n", ipair, msg ); + + /* Transmit message */ + if ( ( rc = xfer_deliver_iob ( &ipair->xfer, + iob_disown ( iobuf ) ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Receive XML message payload + * + * @v ipair Pairing client + * @v msg Message payload + * @v len Length of message + * @ret rc Return status code + */ +static int ipair_rx ( struct ipair *ipair, char *msg, size_t len ) { + int ( * rx ) ( struct ipair *ipair, char *msg ); + int rc; + + /* Ignore empty messages */ + if ( ! len ) + return 0; + + /* Sanity check */ + if ( ( msg[ len - 1 ] != '\0' ) && ( msg[ len - 1 ] != '\n' ) ) { + DBGC ( ipair, "IPAIR %p malformed XML:\n", ipair ); + DBGC_HDA ( ipair, 0, msg, len ); + return -EPROTO; + } + + /* Add NUL terminator (potentially overwriting final newline) */ + msg[ len - 1 ] = '\0'; + DBGC2 ( ipair, "IPAIR %p received:\n%s\n\n", ipair, msg ); + + /* Handle according to current state */ + rx = ipair->rx; + if ( ! rx ) { + DBGC ( ipair, "IPAIR %p unexpected XML:\n%s\n", ipair, msg ); + return -EPROTO; + } + ipair->rx = NULL; + if ( ( rc = rx ( ipair, msg ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Locate XML tag + * + * @v ipair Pairing client + * @v msg XML message + * @v tag Tag name + * @ret start Start of tag content + * @ret end End of tag content + * @ret rc Return status code + */ +static int ipair_tag ( struct ipair *ipair, const char *msg, const char *tag, + char **start, char **end ) { + char buf[ 2 /* "" */ + 1 /* NUL */ ]; + + /* Locate opening tag */ + sprintf ( buf, "<%s>", tag ); + *start = strstr ( msg, buf ); + if ( ! *start ) + return -ENOENT; + *start += strlen ( buf ); + + /* Locate closing tag */ + sprintf ( buf, "", tag ); + *end = strstr ( *start, buf ); + if ( ! *end ) { + DBGC ( ipair, "IPAIR %p missing closing tag %s in:\n%s\n", + ipair, buf, msg ); + return -ENOENT; + } + + return 0; +} + +/** + * Locate XML property list dictionary value + * + * @v ipair Pairing client + * @v msg XML message + * @v key Key name + * @v type Key type + * @ret start Start of value content + * @ret end End of value content + * @ret rc Return status code + */ +static int ipair_key ( struct ipair *ipair, const char *msg, const char *key, + const char *type, char **start, char **end ) { + int rc; + + /* Iterate over keys */ + while ( 1 ) { + + /* Locate key */ + if ( ( rc = ipair_tag ( ipair, msg, "key", start, + end ) ) != 0 ) + return rc; + msg = *end; + + /* Check key name */ + if ( memcmp ( *start, key, ( *end - *start ) ) != 0 ) + continue; + + /* Locate value */ + return ipair_tag ( ipair, msg, type, start, end ); + } +} + +/** + * Transmit DevicePublicKey message + * + * @v ipair Pairing client + * @ret rc Return status code + */ +static int ipair_tx_pubkey ( struct ipair *ipair ) { + int rc; + + /* Transmit message */ + if ( ( rc = ipair_tx ( ipair, + "%s" + "GetValue\n" + "Key\n" + "DevicePublicKey\n" + "%s", + ipair_prefix, ipair_suffix ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Receive DevicePublicKey message + * + * @v ipair Pairing client + * @v msg XML message + * @ret rc Return status code + */ +static int ipair_rx_pubkey ( struct ipair *ipair, char *msg ) { + struct asn1_cursor *key; + char *data; + char *end; + char *decoded; + size_t max_len; + int len; + int next; + int rc; + + /* Locate "Value" value */ + if ( ( rc = ipair_key ( ipair, msg, "Value", "data", &data, + &end ) ) != 0 ) { + DBGC ( ipair, "IPAIR %p unexpected public key message:\n%s\n", + ipair, msg ); + goto err_tag; + } + *end = '\0'; + + /* Decode outer layer of Base64 */ + max_len = base64_decoded_max_len ( data ); + decoded = malloc ( max_len ); + if ( ! decoded ) { + rc = -ENOMEM; + goto err_alloc; + } + len = base64_decode ( data, decoded, max_len ); + if ( len < 0 ) { + rc = len; + DBGC ( ipair, "IPAIR %p invalid outer public key:\n%s\n", + ipair, data ); + goto err_decode; + } + + /* Decode inner layer of Base64 */ + next = pem_asn1 ( virt_to_user ( decoded ), len, 0, &key ); + if ( next < 0 ) { + rc = next; + DBGC ( ipair, "IPAIR %p invalid inner public key:\n%s\n", + ipair, decoded ); + goto err_asn1; + } + DBGC ( ipair, "IPAIR %p received public key\n", ipair ); + DBGC2_HDA ( ipair, 0, key->data, key->len ); + + /* Construct certificates */ + if ( ( rc = icert_certs ( &ipair->icert, key ) ) != 0 ) + goto err_certs; + + /* Send session request or pair request as applicable */ + if ( ipair->flags & IPAIR_REQUEST ) { + ipair->tx = ipair_tx_pair; + ipair->rx = ipair_rx_pair; + } else { + ipair->tx = ipair_tx_session; + ipair->rx = ipair_rx_session; + } + start_timer_nodelay ( &ipair->timer ); + + /* Free key */ + free ( key ); + + /* Free intermediate Base64 */ + free ( decoded ); + + return 0; + + err_certs: + free ( key ); + err_asn1: + err_decode: + free ( decoded ); + err_alloc: + err_tag: + return rc; +} + +/** + * Transmit Pair message + * + * @v ipair Pairing client + * @ret rc Return status code + */ +static int ipair_tx_pair ( struct ipair *ipair ) { + char *root; + char *host; + char *device; + int rc; + + /* Construct doubly encoded certificates */ + if ( ( rc = icert_encode ( &ipair->icert, ipair->icert.root, + &root ) ) != 0 ) + goto err_root; + if ( ( rc = icert_encode ( &ipair->icert, ipair->icert.host, + &host ) ) != 0 ) + goto err_host; + if ( ( rc = icert_encode ( &ipair->icert, ipair->icert.device, + &device ) ) != 0 ) + goto err_device; + + /* Transmit message */ + if ( ( rc = ipair_tx ( ipair, + "%s" + "Pair\n" + "PairRecord\n" + "\n" + "RootCertificate\n" + "%s\n" + "HostCertificate\n" + "%s\n" + "DeviceCertificate\n" + "%s\n" + "SystemBUID\n" + "%s\n" + "HostID\n" + "%s\n" + "\n" + "ProtocolVersion\n" + "2\n" + "PairingOptions\n" + "\n" + "ExtendedPairingErrors\n" + "\n" + "\n" + "%s", + ipair_prefix, root, host, device, + ipair_system_buid, ipair_host_id, + ipair_suffix + ) ) != 0 ) + goto err_tx; + + err_tx: + free ( device ); + err_device: + free ( host ); + err_host: + free ( root ); + err_root: + return rc; +} + +/** + * Receive Pair message error + * + * @v ipair Pairing client + * @v error Pairing error + * @ret rc Return status code + */ +static int ipair_rx_pair_error ( struct ipair *ipair, char *error ) { + + /* Check for actual errors */ + if ( strcmp ( error, "PairingDialogResponsePending" ) != 0 ) { + DBGC ( ipair, "IPAIR %p pairing error \"%s\"\n", ipair, error ); + return -EPERM; + } + + /* Retransmit pairing request */ + ipair->tx = ipair_tx_pair; + ipair->rx = ipair_rx_pair; + start_timer_fixed ( &ipair->timer, IPAIR_RETRY_DELAY ); + + DBGC ( ipair, "IPAIR %p waiting for pairing dialog\n", ipair ); + return 0; +} + +/** + * Receive Pair message + * + * @v ipair Pairing client + * @v msg XML message + * @ret rc Return status code + */ +static int ipair_rx_pair ( struct ipair *ipair, char *msg ) { + char *error; + char *escrow; + char *end; + int rc; + + /* Check for pairing errors */ + if ( ( rc = ipair_key ( ipair, msg, "Error", "string", &error, + &end ) ) == 0 ) { + *end = '\0'; + return ipair_rx_pair_error ( ipair, error ); + } + + /* Get EscrowBag */ + if ( ( rc = ipair_key ( ipair, msg, "EscrowBag", "data", &escrow, + &end ) ) != 0 ) { + DBGC ( ipair, "IPAIR %p unexpected pairing response:\n%s\n", + ipair, msg ); + return rc; + } + DBGC ( ipair, "IPAIR %p pairing successful\n", ipair ); + + /* Send session request */ + ipair->tx = ipair_tx_session; + ipair->rx = ipair_rx_session; + start_timer_nodelay ( &ipair->timer ); + + return 0; +} + +/** + * Transmit StartSession message + * + * @v ipair Pairing client + * @ret rc Return status code + */ +static int ipair_tx_session ( struct ipair *ipair ) { + int rc; + + /* Transmit message */ + if ( ( rc = ipair_tx ( ipair, + "%s" + "StartSession\n" + "SystemBUID\n" + "%s\n" + "HostID\n" + "%s\n" + "%s", + ipair_prefix, ipair_system_buid, + ipair_host_id, ipair_suffix + ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Receive StartSession message error + * + * @v ipair Pairing client + * @v error Pairing error + * @ret rc Return status code + */ +static int ipair_rx_session_error ( struct ipair *ipair, char *error ) { + + /* Check for actual errors */ + if ( strcmp ( error, "InvalidHostID" ) != 0 ) { + DBGC ( ipair, "IPAIR %p session error \"%s\"\n", ipair, error ); + return -EPERM; + } + + /* Transmit pairing request */ + ipair->tx = ipair_tx_pair; + ipair->rx = ipair_rx_pair; + start_timer_nodelay ( &ipair->timer ); + + DBGC ( ipair, "IPAIR %p unknown host: requesting pairing\n", ipair ); + return 0; +} + +/** + * Receive StartSession message + * + * @v ipair Pairing client + * @v msg XML message + * @ret rc Return status code + */ +static int ipair_rx_session ( struct ipair *ipair, char *msg ) { + char *error; + char *session; + char *end; + int rc; + + /* Check for session errors */ + if ( ( rc = ipair_key ( ipair, msg, "Error", "string", &error, + &end ) ) == 0 ) { + *end = '\0'; + return ipair_rx_session_error ( ipair, error ); + } + + /* Check for session ID */ + if ( ( rc = ipair_key ( ipair, msg, "SessionID", "string", &session, + &end ) ) != 0 ) { + DBGC ( ipair, "IPAIR %p unexpected session response:\n%s\n", + ipair, msg ); + return rc; + } + *end = '\0'; + DBGC ( ipair, "IPAIR %p starting session \"%s\"\n", ipair, session ); + + /* Start TLS */ + if ( ( rc = add_tls ( &ipair->xfer, "iPhone", &icert_root, + ipair->icert.key ) ) != 0 ) { + DBGC ( ipair, "IPAIR %p could not start TLS: %s\n", + ipair, strerror ( rc ) ); + return rc; + } + + /* Record that TLS has been started */ + ipair->flags |= IPAIR_TLS; + + return 0; +} + +/** + * Handle window change notification + * + * @v ipair Pairing client + */ +static void ipair_window_changed ( struct ipair *ipair ) { + + /* Report pairing as complete once TLS session has been established */ + if ( ( ipair->flags & IPAIR_TLS ) && xfer_window ( &ipair->xfer ) ) { + + /* Sanity checks */ + assert ( x509_is_valid ( ipair->icert.root, &icert_root ) ); + assert ( x509_is_valid ( ipair->icert.device, &icert_root ) ); + assert ( ! x509_is_valid ( ipair->icert.root, NULL ) ); + assert ( ! x509_is_valid ( ipair->icert.host, NULL ) ); + assert ( ! x509_is_valid ( ipair->icert.device, NULL ) ); + + /* Report pairing as complete */ + DBGC ( ipair, "IPAIR %p established TLS session\n", ipair ); + ipair_close ( ipair, 0 ); + return; + } +} + +/** + * Handle received data + * + * @v ipair Pairing client + * @v iobuf I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + */ +static int ipair_deliver ( struct ipair *ipair, struct io_buffer *iobuf, + struct xfer_metadata *meta __unused ) { + struct ipair_header *hdr; + int rc; + + /* Strip header (which may appear in a separate packet) */ + if ( ( ! ( ipair->flags & IPAIR_RX_LEN ) ) && + ( iob_len ( iobuf ) >= sizeof ( *hdr ) ) ) { + iob_pull ( iobuf, sizeof ( *hdr ) ); + ipair->flags |= IPAIR_RX_LEN; + } + + /* Clear received header flag if we have a message */ + if ( iob_len ( iobuf ) ) + ipair->flags &= ~IPAIR_RX_LEN; + + /* Receive message */ + if ( ( rc = ipair_rx ( ipair, iobuf->data, iob_len ( iobuf ) ) ) != 0 ) + goto error; + + /* Free I/O buffer */ + free_iob ( iobuf ); + + return 0; + + error: + ipair_close ( ipair, rc ); + free_iob ( iobuf ); + return rc; +} + +/** + * Pairing transmission timer + * + * @v timer Retransmission timer + * @v over Failure indicator + */ +static void ipair_expired ( struct retry_timer *timer, int over __unused ) { + struct ipair *ipair = container_of ( timer, struct ipair, timer ); + int ( * tx ) ( struct ipair *ipair ); + int rc; + + /* Sanity check */ + tx = ipair->tx; + assert ( tx != NULL ); + + /* Clear pending transmission */ + ipair->tx = NULL; + + /* Transmit data, if applicable */ + if ( ( rc = tx ( ipair ) ) != 0 ) + ipair_close ( ipair, rc ); +} + +/** Pairing client interface operations */ +static struct interface_operation ipair_xfer_operations[] = { + INTF_OP ( xfer_deliver, struct ipair *, ipair_deliver ), + INTF_OP ( xfer_window_changed, struct ipair *, ipair_window_changed ), + INTF_OP ( intf_close, struct ipair *, ipair_close ), +}; + +/** Pairing client interface descriptor */ +static struct interface_descriptor ipair_xfer_desc = + INTF_DESC ( struct ipair, xfer, ipair_xfer_operations ); + +/** + * Create a pairing client + * + * @v xfer Data transfer interface + * @v flags Initial state flags + * @ret rc Return status code + */ +static int ipair_create ( struct interface *xfer, unsigned int flags ) { + struct ipair *ipair; + int rc; + + /* Allocate and initialise structure */ + ipair = zalloc ( sizeof ( *ipair ) ); + if ( ! ipair ) { + rc = -ENOMEM; + goto err_alloc; + } + ref_init ( &ipair->refcnt, ipair_free ); + intf_init ( &ipair->xfer, &ipair_xfer_desc, &ipair->refcnt ); + timer_init ( &ipair->timer, ipair_expired, &ipair->refcnt ); + ipair->tx = ipair_tx_pubkey; + ipair->rx = ipair_rx_pubkey; + ipair->flags = flags; + + /* Schedule initial transmission */ + start_timer_nodelay ( &ipair->timer ); + + /* Attach to parent interface, mortalise self, and return */ + intf_plug_plug ( &ipair->xfer, xfer ); + ref_put ( &ipair->refcnt ); + return 0; + + ref_put ( &ipair->refcnt ); + err_alloc: + return rc; +} + +/****************************************************************************** + * + * iPhone USB networking + * + ****************************************************************************** + */ + +/** + * Complete bulk IN transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void iphone_in_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct iphone *iphone = container_of ( ep, struct iphone, usbnet.in ); + struct net_device *netdev = iphone->netdev; + + /* Profile receive completions */ + profile_start ( &iphone_in_profiler ); + + /* Ignore packets cancelled when the endpoint closes */ + if ( ! ep->open ) + goto ignore; + + /* Record USB errors against the network device */ + if ( rc != 0 ) { + DBGC ( iphone, "IPHONE %p bulk IN failed: %s\n", + iphone, strerror ( rc ) ); + goto error; + } + + /* Strip padding */ + if ( iob_len ( iobuf ) < IPHONE_IN_PAD ) { + DBGC ( iphone, "IPHONE %p malformed bulk IN:\n", iphone ); + DBGC_HDA ( iphone, 0, iobuf->data, iob_len ( iobuf ) ); + rc = -EINVAL; + goto error; + } + iob_pull ( iobuf, IPHONE_IN_PAD ); + + /* Hand off to network stack */ + netdev_rx ( netdev, iob_disown ( iobuf ) ); + + profile_stop ( &iphone_in_profiler ); + return; + + error: + netdev_rx_err ( netdev, iob_disown ( iobuf ), rc ); + ignore: + free_iob ( iobuf ); +} + +/** Bulk IN endpoint operations */ +static struct usb_endpoint_driver_operations iphone_in_operations = { + .complete = iphone_in_complete, +}; + +/** + * Transmit packet + * + * @v iphone iPhone device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int iphone_out_transmit ( struct iphone *iphone, + struct io_buffer *iobuf ) { + int rc; + + /* Profile transmissions */ + profile_start ( &iphone_out_profiler ); + + /* Enqueue I/O buffer */ + if ( ( rc = usb_stream ( &iphone->usbnet.out, iobuf, 1 ) ) != 0 ) + return rc; + + profile_stop ( &iphone_out_profiler ); + return 0; +} + +/** + * Complete bulk OUT transfer + * + * @v ep USB endpoint + * @v iobuf I/O buffer + * @v rc Completion status code + */ +static void iphone_out_complete ( struct usb_endpoint *ep, + struct io_buffer *iobuf, int rc ) { + struct iphone *iphone = container_of ( ep, struct iphone, usbnet.out ); + struct net_device *netdev = iphone->netdev; + + /* Report TX completion */ + netdev_tx_complete_err ( netdev, iobuf, rc ); +} + +/** Bulk OUT endpoint operations */ +static struct usb_endpoint_driver_operations iphone_out_operations = { + .complete = iphone_out_complete, +}; + +/** + * Check pairing status + * + * @v iphone iPhone device + * @ret rc Return status code + */ +static int iphone_check_pair ( struct iphone *iphone ) { + struct imux *imux; + + /* Find corresponding USB multiplexer */ + list_for_each_entry ( imux, &imuxes, list ) { + if ( imux->usb == iphone->usb ) + return imux->rc; + } + + return -EPIPE_NO_MUX; +} + +/** + * Check link status + * + * @v netdev Network device + */ +static void iphone_check_link ( struct net_device *netdev ) { + struct iphone *iphone = netdev->priv; + struct usb_device *usb = iphone->usb; + uint8_t status; + int rc; + + /* Check pairing status */ + if ( ( rc = iphone_check_pair ( iphone ) ) != 0 ) + goto err_pair; + + /* Get link status */ + if ( ( rc = usb_control ( usb, IPHONE_GET_LINK, 0, 0, &status, + sizeof ( status ) ) ) != 0 ) { + DBGC ( iphone, "IPHONE %p could not get link status: %s\n", + iphone, strerror ( rc ) ); + goto err_control; + } + + /* Check link status */ + if ( status != IPHONE_LINK_UP ) { + rc = -ENOTCONN_STATUS ( status ); + goto err_status; + } + + /* Success */ + rc = 0; + + err_status: + err_control: + err_pair: + /* Report link status. Since we have to check the link + * periodically (due to an absence of an interrupt endpoint), + * do this only if the link status has actually changed. + */ + if ( rc != netdev->link_rc ) { + if ( rc == 0 ) { + DBGC ( iphone, "IPHONE %p link up\n", iphone ); + } else { + DBGC ( iphone, "IPHONE %p link down: %s\n", + iphone, strerror ( rc ) ); + } + netdev_link_err ( netdev, rc ); + } +} + +/** + * Periodically update link status + * + * @v timer Link status timer + * @v over Failure indicator + */ +static void iphone_expired ( struct retry_timer *timer, int over __unused ) { + struct iphone *iphone = container_of ( timer, struct iphone, timer ); + struct net_device *netdev = iphone->netdev; + + /* Check link status */ + iphone_check_link ( netdev ); + + /* Restart timer, if device is open */ + if ( netdev_is_open ( netdev ) ) + start_timer_fixed ( timer, IPHONE_LINK_CHECK_INTERVAL ); +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int iphone_open ( struct net_device *netdev ) { + struct iphone *iphone = netdev->priv; + int rc; + + /* Open USB network device */ + if ( ( rc = usbnet_open ( &iphone->usbnet ) ) != 0 ) { + DBGC ( iphone, "IPHONE %p could not open: %s\n", + iphone, strerror ( rc ) ); + goto err_open; + } + + /* Start the link status check timer */ + start_timer_nodelay ( &iphone->timer ); + + return 0; + + usbnet_close ( &iphone->usbnet ); + err_open: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void iphone_close ( struct net_device *netdev ) { + struct iphone *iphone = netdev->priv; + + /* Stop the link status check timer */ + stop_timer ( &iphone->timer ); + + /* Close USB network device */ + usbnet_close ( &iphone->usbnet ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int iphone_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct iphone *iphone = netdev->priv; + int rc; + + /* Transmit packet */ + if ( ( rc = iphone_out_transmit ( iphone, iobuf ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void iphone_poll ( struct net_device *netdev ) { + struct iphone *iphone = netdev->priv; + int rc; + + /* Poll USB bus */ + usb_poll ( iphone->bus ); + + /* Refill endpoints */ + if ( ( rc = usbnet_refill ( &iphone->usbnet ) ) != 0 ) + netdev_rx_err ( netdev, NULL, rc ); +} + +/** iPhone network device operations */ +static struct net_device_operations iphone_operations = { + .open = iphone_open, + .close = iphone_close, + .transmit = iphone_transmit, + .poll = iphone_poll, +}; + +/** + * Probe device + * + * @v func USB function + * @v config Configuration descriptor + * @ret rc Return status code + */ +static int iphone_probe ( struct usb_function *func, + struct usb_configuration_descriptor *config ) { + struct usb_device *usb = func->usb; + struct net_device *netdev; + struct iphone *iphone; + int rc; + + /* Allocate and initialise structure */ + netdev = alloc_etherdev ( sizeof ( *iphone ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &iphone_operations ); + netdev->dev = &func->dev; + iphone = netdev->priv; + memset ( iphone, 0, sizeof ( *iphone ) ); + iphone->usb = usb; + iphone->bus = usb->port->hub->bus; + iphone->netdev = netdev; + usbnet_init ( &iphone->usbnet, func, NULL, &iphone_in_operations, + &iphone_out_operations ); + usb_refill_init ( &iphone->usbnet.in, 0, IPHONE_IN_MTU, + IPHONE_IN_MAX_FILL ); + timer_init ( &iphone->timer, iphone_expired, &netdev->refcnt ); + DBGC ( iphone, "IPHONE %p on %s\n", iphone, func->name ); + + /* Describe USB network device */ + if ( ( rc = usbnet_describe ( &iphone->usbnet, config ) ) != 0 ) { + DBGC ( iphone, "IPHONE %p could not describe: %s\n", + iphone, strerror ( rc ) ); + goto err_describe; + } + + /* Fetch MAC address */ + if ( ( rc = usb_control ( usb, IPHONE_GET_MAC, 0, 0, netdev->hw_addr, + ETH_ALEN ) ) != 0 ) { + DBGC ( iphone, "IPHONE %p could not fetch MAC address: %s\n", + iphone, strerror ( rc ) ); + goto err_fetch_mac; + } + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register; + + /* Set initial link status */ + iphone_check_link ( netdev ); + + /* Add to list of iPhone network devices */ + list_add ( &iphone->list, &iphones ); + + usb_func_set_drvdata ( func, iphone ); + return 0; + + list_del ( &iphone->list ); + unregister_netdev ( netdev ); + err_register: + err_fetch_mac: + err_describe: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove device + * + * @v func USB function + */ +static void iphone_remove ( struct usb_function *func ) { + struct iphone *iphone = usb_func_get_drvdata ( func ); + struct net_device *netdev = iphone->netdev; + + list_del ( &iphone->list ); + unregister_netdev ( netdev ); + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** iPhone device IDs */ +static struct usb_device_id iphone_ids[] = { + { + .name = "iphone", + .vendor = 0x05ac, + .product = USB_ANY_ID, + }, +}; + +/** iPhone driver */ +struct usb_driver iphone_driver __usb_driver = { + .ids = iphone_ids, + .id_count = ( sizeof ( iphone_ids ) / sizeof ( iphone_ids[0] ) ), + .class = USB_CLASS_ID ( 0xff, 0xfd, 0x01 ), + .score = USB_SCORE_NORMAL, + .probe = iphone_probe, + .remove = iphone_remove, +}; + +/* Drag in objects via iphone_driver */ +REQUIRING_SYMBOL ( iphone_driver ); + +/* Drag in RSA-with-SHA256 OID prefixes */ +REQUIRE_OBJECT ( rsa_sha256 ); diff --git a/src/drivers/net/iphone.h b/src/drivers/net/iphone.h new file mode 100644 index 000000000..2db6da7bd --- /dev/null +++ b/src/drivers/net/iphone.h @@ -0,0 +1,291 @@ +#ifndef _IPHONE_H +#define _IPHONE_H + +/** @file + * + * iPhone USB Ethernet driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****************************************************************************** + * + * iPhone pairing certificates + * + ****************************************************************************** + */ + +/** An iPhone pairing certificate set */ +struct icert { + /** "Private" key */ + struct private_key *key; + /** Root certificate */ + struct x509_certificate *root; + /** Host certificate */ + struct x509_certificate *host; + /** Device certificate */ + struct x509_certificate *device; +}; + +/****************************************************************************** + * + * iPhone USB multiplexer + * + ****************************************************************************** + */ + +/** An iPhone USB multiplexed packet header */ +struct imux_header { + /** Protocol */ + uint32_t protocol; + /** Length (including this header) */ + uint32_t len; + /** Reserved */ + uint32_t reserved; + /** Output sequence number */ + uint16_t out_seq; + /** Input sequence number */ + uint16_t in_seq; +} __attribute__ (( packed )); + +/** iPhone USB multiplexer protocols */ +enum imux_protocol { + /** Version number */ + IMUX_VERSION = 0, + /** Log message */ + IMUX_LOG = 1, + /** TCP packet */ + IMUX_TCP = IP_TCP, +}; + +/** An iPhone USB multiplexed version message header */ +struct imux_header_version { + /** Multiplexed packet header */ + struct imux_header hdr; + /** Reserved */ + uint32_t reserved; +} __attribute__ (( packed )); + +/** An iPhone USB multiplexed log message header */ +struct imux_header_log { + /** Multiplexed packet header */ + struct imux_header hdr; + /** Log level */ + uint8_t level; + /** Message */ + char msg[0]; +} __attribute__ (( packed )); + +/** An iPhone USB multiplexed pseudo-TCP message header */ +struct imux_header_tcp { + /** Multiplexed packet header */ + struct imux_header hdr; + /** Pseudo-TCP header */ + struct tcp_header tcp; +} __attribute__ (( packed )); + +/** Local port number + * + * This is a policy decision. + */ +#define IMUX_PORT_LOCAL 0x18ae + +/** Lockdown daemon port number */ +#define IMUX_PORT_LOCKDOWND 62078 + +/** Advertised TCP window + * + * This is a policy decision. + */ +#define IMUX_WINDOW 0x0200 + +/** An iPhone USB multiplexer */ +struct imux { + /** Reference counter */ + struct refcnt refcnt; + /** USB device */ + struct usb_device *usb; + /** USB bus */ + struct usb_bus *bus; + /** USB network device */ + struct usbnet_device usbnet; + /** List of USB multiplexers */ + struct list_head list; + + /** Polling process */ + struct process process; + /** Pending action + * + * @v imux USB multiplexer + * @ret rc Return status code + */ + int ( * action ) ( struct imux *imux ); + + /** Input sequence */ + uint16_t in_seq; + /** Output sequence */ + uint16_t out_seq; + /** Pseudo-TCP sequence number */ + uint32_t tcp_seq; + /** Pseudo-TCP acknowledgement number */ + uint32_t tcp_ack; + /** Pseudo-TCP local port number */ + uint16_t port; + + /** Pseudo-TCP lockdown socket interface */ + struct interface tcp; + /** Pairing flags */ + unsigned int flags; + /** Pairing status */ + int rc; +}; + +/** Multiplexer bulk IN maximum fill level + * + * This is a policy decision. + */ +#define IMUX_IN_MAX_FILL 1 + +/** Multiplexer bulk IN buffer size + * + * This is a policy decision. + */ +#define IMUX_IN_MTU 4096 + +/****************************************************************************** + * + * iPhone pairing client + * + ****************************************************************************** + */ + +/** An iPhone USB multiplexed pseudo-TCP XML message header */ +struct ipair_header { + /** Message length */ + uint32_t len; + /** Message */ + char msg[0]; +} __attribute__ (( packed )); + +/** An iPhone pairing client */ +struct ipair { + /** Reference counter */ + struct refcnt refcnt; + /** Data transfer interface */ + struct interface xfer; + + /** Pairing timer */ + struct retry_timer timer; + /** Transmit message + * + * @v ipair Pairing client + * @ret rc Return status code + */ + int ( * tx ) ( struct ipair *ipair ); + /** Receive message + * + * @v ipair Pairing client + * @v msg XML message + * @ret rc Return status code + */ + int ( * rx ) ( struct ipair *ipair, char *msg ); + /** State flags */ + unsigned int flags; + + /** Pairing certificates */ + struct icert icert; +}; + +/** Pairing client state flags */ +enum ipair_flags { + /** Request a new pairing */ + IPAIR_REQUEST = 0x0001, + /** Standalone length has been received */ + IPAIR_RX_LEN = 0x0002, + /** TLS session has been started */ + IPAIR_TLS = 0x0004, +}; + +/** Pairing retry delay + * + * This is a policy decision. + */ +#define IPAIR_RETRY_DELAY ( 1 * TICKS_PER_SEC ) + +/****************************************************************************** + * + * iPhone USB networking + * + ****************************************************************************** + */ + +/** Get MAC address */ +#define IPHONE_GET_MAC \ + ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \ + USB_REQUEST_TYPE ( 0x00 ) ) + +/** Get link status */ +#define IPHONE_GET_LINK \ + ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \ + USB_REQUEST_TYPE ( 0x45 ) ) + +/** An iPhone link status */ +enum iphone_link_status { + /** Personal Hotspot is disabled */ + IPHONE_LINK_DISABLED = 0x03, + /** Link up */ + IPHONE_LINK_UP = 0x04, + /** Link not yet determined */ + IPHONE_LINK_UNKNOWN = -1U, +}; + +/** An iPhone network device */ +struct iphone { + /** USB device */ + struct usb_device *usb; + /** USB bus */ + struct usb_bus *bus; + /** Network device */ + struct net_device *netdev; + /** USB network device */ + struct usbnet_device usbnet; + + /** List of iPhone network devices */ + struct list_head list; + /** Link status check timer */ + struct retry_timer timer; +}; + +/** Bulk IN padding */ +#define IPHONE_IN_PAD 2 + +/** Bulk IN buffer size + * + * This is a policy decision. + */ +#define IPHONE_IN_MTU ( ETH_FRAME_LEN + IPHONE_IN_PAD ) + +/** Bulk IN maximum fill level + * + * This is a policy decision. + */ +#define IPHONE_IN_MAX_FILL 8 + +/** Link check interval + * + * This is a policy decision. + */ +#define IPHONE_LINK_CHECK_INTERVAL ( 5 * TICKS_PER_SEC ) + +#endif /* _IPHONE_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 7c98909d1..3437a5217 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -210,6 +210,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_pcimsix ( ERRFILE_DRIVER | 0x00cc0000 ) #define ERRFILE_intelxlvf ( ERRFILE_DRIVER | 0x00cd0000 ) #define ERRFILE_usbblk ( ERRFILE_DRIVER | 0x00ce0000 ) +#define ERRFILE_iphone ( ERRFILE_DRIVER | 0x00cf0000 ) #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) -- cgit v1.2.3-55-g7522 From 47098d7cb1fb00f92dbee5e5de7ab335f0f30076 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 17 Dec 2020 21:46:52 +0000 Subject: [efi] Allow EFI_USB_IO_PROTOCOL interfaces to be nullified and leaked Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_null.h | 2 + src/interface/efi/efi_null.c | 140 ++++++++++++++++++++++++++++++++++++++++ src/interface/efi/efi_usb.c | 48 +++++++++++--- 3 files changed, 181 insertions(+), 9 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_null.h b/src/include/ipxe/efi/efi_null.h index cc91e09bb..297457081 100644 --- a/src/include/ipxe/efi/efi_null.h +++ b/src/include/ipxe/efi/efi_null.h @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include extern void efi_nullify_snp ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ); extern void efi_nullify_nii ( EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *nii ); @@ -27,5 +28,6 @@ extern void efi_nullify_hii ( EFI_HII_CONFIG_ACCESS_PROTOCOL *hii ); extern void efi_nullify_block ( EFI_BLOCK_IO_PROTOCOL *block ); extern void efi_nullify_pxe ( EFI_PXE_BASE_CODE_PROTOCOL *pxe ); extern void efi_nullify_apple ( EFI_APPLE_NET_BOOT_PROTOCOL *apple ); +extern void efi_nullify_usbio ( EFI_USB_IO_PROTOCOL *usbio ); #endif /* _IPXE_EFI_NULL_H */ diff --git a/src/interface/efi/efi_null.c b/src/interface/efi/efi_null.c index aa27ab674..29ca5b9b6 100644 --- a/src/interface/efi/efi_null.c +++ b/src/interface/efi/efi_null.c @@ -530,3 +530,143 @@ void efi_nullify_apple ( EFI_APPLE_NET_BOOT_PROTOCOL *apple ) { memcpy ( apple, &efi_null_apple, sizeof ( *apple ) ); } + +/****************************************************************************** + * + * USB I/O Protocol + * + ****************************************************************************** + */ + +static EFI_STATUS EFIAPI +efi_null_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused, + EFI_USB_DEVICE_REQUEST *packet __unused, + EFI_USB_DATA_DIRECTION direction __unused, + UINT32 timeout __unused, VOID *data __unused, + UINTN len __unused, UINT32 *status __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_bulk_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused, + UINT8 endpoint __unused, VOID *data __unused, + UINTN *len __unused, UINTN timeout __unused, + UINT32 *status __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_sync_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused, + UINT8 endpoint __unused, + VOID *data __unused, + UINTN *len __unused, + UINTN timeout __unused, + UINT32 *status __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_async_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused, + UINT8 endpoint __unused, + BOOLEAN start __unused, + UINTN interval __unused, + UINTN len __unused, + EFI_ASYNC_USB_TRANSFER_CALLBACK + callback __unused, + VOID *context __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_isochronous_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused, + UINT8 endpoint __unused, + VOID *data __unused, UINTN len __unused, + UINT32 *status __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_async_isochronous_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused, + UINT8 endpoint __unused, + VOID *data __unused, + UINTN len __unused, + EFI_ASYNC_USB_TRANSFER_CALLBACK + callback __unused, + VOID *context __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_get_device_descriptor ( EFI_USB_IO_PROTOCOL *usbio __unused, + EFI_USB_DEVICE_DESCRIPTOR + *efidesc __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_get_config_descriptor ( EFI_USB_IO_PROTOCOL *usbio __unused, + EFI_USB_CONFIG_DESCRIPTOR + *efidesc __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_get_interface_descriptor ( EFI_USB_IO_PROTOCOL *usbio __unused, + EFI_USB_INTERFACE_DESCRIPTOR + *efidesc __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_get_endpoint_descriptor ( EFI_USB_IO_PROTOCOL *usbio __unused, + UINT8 index __unused, + EFI_USB_ENDPOINT_DESCRIPTOR + *efidesc __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio __unused, + UINT16 language __unused, + UINT8 index __unused, + CHAR16 **string __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_get_supported_languages ( EFI_USB_IO_PROTOCOL *usbio __unused, + UINT16 **languages __unused, + UINT16 *len __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_STATUS EFIAPI +efi_null_usb_port_reset ( EFI_USB_IO_PROTOCOL *usbio __unused ) { + return EFI_UNSUPPORTED; +} + +static EFI_USB_IO_PROTOCOL efi_null_usbio = { + .UsbControlTransfer = efi_null_usb_control_transfer, + .UsbBulkTransfer = efi_null_usb_bulk_transfer, + .UsbAsyncInterruptTransfer = efi_null_usb_async_interrupt_transfer, + .UsbSyncInterruptTransfer = efi_null_usb_sync_interrupt_transfer, + .UsbIsochronousTransfer = efi_null_usb_isochronous_transfer, + .UsbAsyncIsochronousTransfer = efi_null_usb_async_isochronous_transfer, + .UsbGetDeviceDescriptor = efi_null_usb_get_device_descriptor, + .UsbGetConfigDescriptor = efi_null_usb_get_config_descriptor, + .UsbGetInterfaceDescriptor = efi_null_usb_get_interface_descriptor, + .UsbGetEndpointDescriptor = efi_null_usb_get_endpoint_descriptor, + .UsbGetStringDescriptor = efi_null_usb_get_string_descriptor, + .UsbGetSupportedLanguages = efi_null_usb_get_supported_languages, + .UsbPortReset = efi_null_usb_port_reset, +}; + +/** + * Nullify USB I/O protocol + * + * @v usbio USB I/O protocol + */ +void efi_nullify_usbio ( EFI_USB_IO_PROTOCOL *usbio ) { + + memcpy ( usbio, &efi_null_usbio, sizeof ( *usbio ) ); +} diff --git a/src/interface/efi/efi_usb.c b/src/interface/efi/efi_usb.c index bcf156999..df66df45f 100644 --- a/src/interface/efi/efi_usb.c +++ b/src/interface/efi/efi_usb.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include @@ -1106,6 +1107,7 @@ static int efi_usb_install ( struct efi_usb_device *usbdev, EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct usb_function *func = usbdev->func; struct efi_usb_interface *usbintf; + int leak = 0; EFI_STATUS efirc; int rc; @@ -1148,19 +1150,30 @@ static int efi_usb_install ( struct efi_usb_device *usbdev, usbintf->name, efi_handle_name ( usbintf->handle ) ); return 0; - bs->UninstallMultipleProtocolInterfaces ( + if ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( usbintf->handle, &efi_usb_io_protocol_guid, &usbintf->usbio, &efi_device_path_protocol_guid, usbintf->path, - NULL ); + NULL ) ) != 0 ) { + DBGC ( usbdev, "USBDEV %s could not uninstall: %s\n", + usbintf->name, strerror ( -EEFI ( efirc ) ) ); + leak = 1; + } + efi_nullify_usbio ( &usbintf->usbio ); err_install_protocol: efi_usb_close_all ( usbintf ); efi_usb_free_all ( usbintf ); list_del ( &usbintf->list ); - free ( usbintf->path ); + if ( ! leak ) + free ( usbintf->path ); err_path: - free ( usbintf ); + if ( ! leak ) + free ( usbintf ); err_alloc: + if ( leak ) { + DBGC ( usbdev, "USBDEV %s nullified and leaked\n", + usbintf->name ); + } return rc; } @@ -1172,6 +1185,8 @@ static int efi_usb_install ( struct efi_usb_device *usbdev, static void efi_usb_uninstall ( struct efi_usb_interface *usbintf ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_usb_device *usbdev = usbintf->usbdev; + int leak = efi_shutdown_in_progress; + EFI_STATUS efirc; DBGC ( usbdev, "USBDEV %s uninstalling %s\n", usbintf->name, efi_handle_name ( usbintf->handle ) ); @@ -1180,14 +1195,21 @@ static void efi_usb_uninstall ( struct efi_usb_interface *usbintf ) { * seems to be required on some platforms to avoid failures * when uninstalling protocols. */ - bs->DisconnectController ( usbintf->handle, NULL, NULL ); + if ( ! efi_shutdown_in_progress ) + bs->DisconnectController ( usbintf->handle, NULL, NULL ); /* Uninstall protocols */ - bs->UninstallMultipleProtocolInterfaces ( + if ( ( ! efi_shutdown_in_progress ) && + ( ( efirc = bs->UninstallMultipleProtocolInterfaces ( usbintf->handle, &efi_usb_io_protocol_guid, &usbintf->usbio, &efi_device_path_protocol_guid, usbintf->path, - NULL ); + NULL ) ) != 0 ) ) { + DBGC ( usbdev, "USBDEV %s could not uninstall: %s\n", + usbintf->name, strerror ( -EEFI ( efirc ) ) ); + leak = 1; + } + efi_nullify_usbio ( &usbintf->usbio ); /* Close and free all endpoints */ efi_usb_close_all ( usbintf ); @@ -1197,10 +1219,18 @@ static void efi_usb_uninstall ( struct efi_usb_interface *usbintf ) { list_del ( &usbintf->list ); /* Free device path */ - free ( usbintf->path ); + if ( ! leak ) + free ( usbintf->path ); /* Free interface */ - free ( usbintf ); + if ( ! leak ) + free ( usbintf ); + + /* Report leakage, if applicable */ + if ( leak && ( ! efi_shutdown_in_progress ) ) { + DBGC ( usbdev, "USBDEV %s nullified and leaked\n", + usbintf->name ); + } } /** -- cgit v1.2.3-55-g7522 From dced22d6dee346ac4d98502c9008fd3d5c6197d2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 29 Dec 2020 14:37:54 +0000 Subject: [smbios] Add support for the 64-bit SMBIOS3 entry point Support UEFI systems that provide only 64-bit versions of the SMBIOS entry point. Signed-off-by: Michael Brown --- src/include/ipxe/smbios.h | 51 ++++++++++++++++++++++++++++++++++++++---- src/interface/efi/efi_smbios.c | 44 +++++++++++++++++++++++------------- src/interface/smbios/smbios.c | 9 ++++++-- 3 files changed, 82 insertions(+), 22 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/smbios.h b/src/include/ipxe/smbios.h index c1d8fea3e..53fbd8cb8 100644 --- a/src/include/ipxe/smbios.h +++ b/src/include/ipxe/smbios.h @@ -31,15 +31,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /* Include all architecture-dependent SMBIOS API headers */ #include -/** Signature for SMBIOS entry point */ +/** Signature for 32-bit SMBIOS entry point */ #define SMBIOS_SIGNATURE \ ( ( '_' << 0 ) + ( 'S' << 8 ) + ( 'M' << 16 ) + ( '_' << 24 ) ) +/** Signature for 64-bit SMBIOS entry point */ +#define SMBIOS3_SIGNATURE \ + ( ( '_' << 0 ) + ( 'S' << 8 ) + ( 'M' << 16 ) + ( '3' << 24 ) ) + /** - * SMBIOS entry point + * SMBIOS 32-bit entry point * - * This is the single table which describes the list of SMBIOS - * structures. It is located by scanning through the BIOS segment. + * This is the 32-bit version of the table which describes the list of + * SMBIOS structures. It may be located by scanning through the BIOS + * segment or via an EFI configuration table. */ struct smbios_entry { /** Signature @@ -75,6 +80,41 @@ struct smbios_entry { uint8_t bcd_revision; } __attribute__ (( packed )); +/** + * SMBIOS 64-bit entry point + * + * This is the 64-bit version of the table which describes the list of + * SMBIOS structures. It may be located by scanning through the BIOS + * segment or via an EFI configuration table. + */ +struct smbios3_entry { + /** Signature + * + * Must be equal to SMBIOS3_SIGNATURE + */ + uint32_t signature; + /** Signature extra byte */ + uint8_t extra; + /** Checksum */ + uint8_t checksum; + /** Length */ + uint8_t len; + /** Major version */ + uint8_t major; + /** Minor version */ + uint8_t minor; + /** Documentation revision */ + uint8_t docrev; + /** Entry point revision */ + uint8_t revision; + /** Reserved */ + uint8_t reserved; + /** Structure table length */ + uint32_t smbios_len; + /** Structure table address */ + uint64_t smbios_address; +} __attribute__ (( packed )); + /** An SMBIOS structure header */ struct smbios_header { /** Type */ @@ -155,6 +195,9 @@ struct smbios_enclosure_information { /** SMBIOS OEM strings structure type */ #define SMBIOS_TYPE_OEM_STRINGS 11 +/** SMBIOS end of table type */ +#define SMBIOS_TYPE_END 127 + /** * SMBIOS entry point descriptor * diff --git a/src/interface/efi/efi_smbios.c b/src/interface/efi/efi_smbios.c index 304f95a56..d7877b0aa 100644 --- a/src/interface/efi/efi_smbios.c +++ b/src/interface/efi/efi_smbios.c @@ -34,6 +34,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); static struct smbios_entry *smbios_entry; EFI_USE_TABLE ( SMBIOS_TABLE, &smbios_entry, 0 ); +/** SMBIOS configuration table */ +static struct smbios3_entry *smbios3_entry; +EFI_USE_TABLE ( SMBIOS3_TABLE, &smbios3_entry, 0 ); + /** * Find SMBIOS * @@ -42,26 +46,34 @@ EFI_USE_TABLE ( SMBIOS_TABLE, &smbios_entry, 0 ); */ static int efi_find_smbios ( struct smbios *smbios ) { - if ( ! smbios_entry ) { - DBG ( "No SMBIOS table provided\n" ); - return -ENODEV; + /* Use 64-bit table if present */ + if ( smbios3_entry && ( smbios3_entry->signature == SMBIOS3_SIGNATURE ) ) { + smbios->address = phys_to_user ( smbios3_entry->smbios_address ); + smbios->len = smbios3_entry->smbios_len; + smbios->count = 0; + smbios->version = + SMBIOS_VERSION ( smbios3_entry->major, smbios3_entry->minor ); + DBG ( "Found 64-bit SMBIOS v%d.%d entry point at %p (%lx+%zx)\n", + smbios3_entry->major, smbios3_entry->minor, smbios3_entry, + user_to_phys ( smbios->address, 0 ), smbios->len ); + return 0; } - if ( smbios_entry->signature != SMBIOS_SIGNATURE ) { - DBG ( "Invalid SMBIOS signature\n" ); - return -ENODEV; + /* Otherwise, use 32-bit table if present */ + if ( smbios_entry && ( smbios_entry->signature == SMBIOS_SIGNATURE ) ) { + smbios->address = phys_to_user ( smbios_entry->smbios_address ); + smbios->len = smbios_entry->smbios_len; + smbios->count = smbios_entry->smbios_count; + smbios->version = + SMBIOS_VERSION ( smbios_entry->major, smbios_entry->minor ); + DBG ( "Found 32-bit SMBIOS v%d.%d entry point at %p (%lx+%zx)\n", + smbios_entry->major, smbios_entry->minor, smbios_entry, + user_to_phys ( smbios->address, 0 ), smbios->len ); + return 0; } - smbios->address = phys_to_user ( smbios_entry->smbios_address ); - smbios->len = smbios_entry->smbios_len; - smbios->count = smbios_entry->smbios_count; - smbios->version = - SMBIOS_VERSION ( smbios_entry->major, smbios_entry->minor ); - DBG ( "Found SMBIOS v%d.%d entry point at %p (%x+%zx)\n", - smbios_entry->major, smbios_entry->minor, smbios_entry, - smbios_entry->smbios_address, smbios->len ); - - return 0; + DBG ( "No SMBIOS table provided\n" ); + return -ENODEV; } PROVIDE_SMBIOS ( efi, find_smbios, efi_find_smbios ); diff --git a/src/interface/smbios/smbios.c b/src/interface/smbios/smbios.c index 1dcf819c2..5bd76f16a 100644 --- a/src/interface/smbios/smbios.c +++ b/src/interface/smbios/smbios.c @@ -130,8 +130,8 @@ int find_smbios_structure ( unsigned int type, unsigned int instance, assert ( smbios.address != UNULL ); /* Scan through list of structures */ - while ( ( ( offset + sizeof ( structure->header ) ) < smbios.len ) - && ( count < smbios.count ) ) { + while ( ( ( offset + sizeof ( structure->header ) ) < smbios.len ) && + ( ( smbios.count == 0 ) || ( count < smbios.count ) ) ) { /* Read next SMBIOS structure header */ copy_from_user ( &structure->header, smbios.address, offset, @@ -157,6 +157,11 @@ int find_smbios_structure ( unsigned int type, unsigned int instance, "strings length %zx\n", offset, structure->header.type, structure->header.len, structure->strings_len ); + /* Stop if we have reached an end-of-table marker */ + if ( ( smbios.count == 0 ) && + ( structure->header.type == SMBIOS_TYPE_END ) ) + break; + /* If this is the structure we want, return */ if ( ( structure->header.type == type ) && ( instance-- == 0 ) ) { -- cgit v1.2.3-55-g7522 From 988d2c13cdf0f0b4140685af35ced70ac5b3283c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 31 Dec 2020 20:41:49 +0000 Subject: [efi] Use segment and bus number to identify PCI root bridge I/O protocol There may be multiple instances of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL for a single PCI segment. Use the bus number range descriptor from the ACPI resource list to identify the correct protocol instance. There is some discrepancy between the ACPI and UEFI specifications regarding the interpretation of values within the ACPI resource list. The ACPI specification defines the min/max field values to be within the secondary (device-side) address space, and defines the offset field value as "the offset that must be added to the address on the secondary side to obtain the address on the primary side". The UEFI specification states instead that the offset field value is the "offset to apply to the starting address to convert it to a PCI address", helpfully omitting to clarify whether "to apply" in this context means "to add" or "to subtract". The implication of the wording is also that the "starting address" is not already a "PCI address" and must therefore be a host-side address rather than the ACPI-defined device-side address. Code comments in the EDK2 codebase seem to support the latter (non-ACPI) interpretation of these ACPI structures. For example, in the PciHostBridgeDxe driver there can be found the comment Macros to translate device address to host address and vice versa. According to UEFI 2.7, device address = host address + translation offset. along with a pair of macros TO_HOST_ADDRESS() and TO_DEVICE_ADDRESS() which similarly negate the sense of the "translation offset" from the definition found in the ACPI specification. The existing logic in efipci_ioremap() (based on a presumed-working externally contributed patch) applies the non-ACPI interpretation: it assumes that min/max field values are host-side addresses and that the offset field value is negated. Match this existing logic by assuming that min/max field values are host-side bus numbers. (The bus number offset value is therefore not required and so can be ignored.) As noted in commit 9b25f6e ("[efi] Fall back to assuming identity mapping of MMIO address space"), some systems seem to fail to provide MMIO address space descriptors. Assume that some systems may similarly fail to provide bus number range descriptors, and fall back in this situation to assuming that matching on segment number alone is sufficient. Testing any of this is unfortunately impossible without access to esoteric hardware that actually uses non-zero translation offsets. Originally-implemented-by: Thomas Walker Signed-off-by: Michael Brown --- src/include/ipxe/acpi.h | 3 ++ src/interface/efi/efi_pci.c | 72 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 4 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index e41bd2890..f979ace45 100644 --- a/src/include/ipxe/acpi.h +++ b/src/include/ipxe/acpi.h @@ -78,6 +78,9 @@ struct acpi_qword_address_space_resource { /** A memory address space type */ #define ACPI_ADDRESS_TYPE_MEM 0x00 +/** A bus number address space type */ +#define ACPI_ADDRESS_TYPE_BUS 0x02 + /** An ACPI resource descriptor */ union acpi_resource { /** Tag byte */ diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 6b32fd6a9..4adee0fd8 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -62,6 +62,70 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); ****************************************************************************** */ +/** + * Check for a matching PCI root bridge I/O protocol + * + * @v pci PCI device + * @v handle EFI PCI root bridge handle + * @v root EFI PCI root bridge I/O protocol + * @ret rc Return status code + */ +static int efipci_root_match ( struct pci_device *pci, EFI_HANDLE handle, + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root ) { + union { + union acpi_resource *res; + void *raw; + } u; + unsigned int segment = PCI_SEG ( pci->busdevfn ); + unsigned int bus = PCI_BUS ( pci->busdevfn ); + unsigned int start; + unsigned int end; + unsigned int tag; + EFI_STATUS efirc; + int rc; + + /* Check segment number */ + if ( root->SegmentNumber != segment ) + return -ENOENT; + + /* Get ACPI resource descriptors */ + if ( ( efirc = root->Configuration ( root, &u.raw ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( pci, "EFIPCI " PCI_FMT " cannot get configuration for " + "%s: %s\n", PCI_ARGS ( pci ), + efi_handle_name ( handle ), strerror ( rc ) ); + return rc; + } + + /* Assume success if no bus number range descriptors are found */ + rc = 0; + + /* Parse resource descriptors */ + for ( ; ( ( tag = acpi_resource_tag ( u.res ) ) != ACPI_END_RESOURCE ) ; + u.res = acpi_resource_next ( u.res ) ) { + + /* Ignore anything other than a bus number range descriptor */ + if ( tag != ACPI_QWORD_ADDRESS_SPACE_RESOURCE ) + continue; + if ( u.res->qword.type != ACPI_ADDRESS_TYPE_BUS ) + continue; + + /* Check for a matching bus number */ + start = le64_to_cpu ( u.res->qword.min ); + end = ( start + le64_to_cpu ( u.res->qword.len ) ); + if ( ( bus >= start ) && ( bus < end ) ) + return 0; + + /* We have seen at least one non-matching range + * descriptor, so assume failure unless we find a + * subsequent match. + */ + rc = -ENOENT; + } + + return rc; +} + /** * Open EFI PCI root bridge I/O protocol * @@ -106,7 +170,7 @@ static int efipci_root_open ( struct pci_device *pci, EFI_HANDLE *handle, strerror ( rc ) ); continue; } - if ( u.root->SegmentNumber == PCI_SEG ( pci->busdevfn ) ) { + if ( efipci_root_match ( pci, *handle, u.root ) == 0 ) { *root = u.root; bs->FreePool ( handles ); return 0; @@ -263,13 +327,13 @@ void * efipci_ioremap ( struct pci_device *pci, unsigned long bus_addr, for ( ; ( ( tag = acpi_resource_tag ( u.res ) ) != ACPI_END_RESOURCE ) ; u.res = acpi_resource_next ( u.res ) ) { - /* Ignore anything other than an address space descriptor */ + /* Ignore anything other than a memory range descriptor */ if ( tag != ACPI_QWORD_ADDRESS_SPACE_RESOURCE ) continue; - - /* Ignore descriptors that do not cover this memory range */ if ( u.res->qword.type != ACPI_ADDRESS_TYPE_MEM ) continue; + + /* Ignore descriptors that do not cover this memory range */ offset = le64_to_cpu ( u.res->qword.offset ); start = ( offset + le64_to_cpu ( u.res->qword.min ) ); end = ( start + le64_to_cpu ( u.res->qword.len ) ); -- cgit v1.2.3-55-g7522 From 274ad690120620df718144556687a05e2f371e66 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 19 Jan 2021 12:34:10 +0000 Subject: [eapol] Replace EAPoL code Replace the GPL2+-only EAPoL code (currently used only for WPA) with new code licensed under GPL2+-or-UBDL. Signed-off-by: Michael Brown --- src/include/ipxe/eapol.h | 124 +++++++++++++---------------------------------- src/net/80211/wpa.c | 25 +++++----- src/net/eapol.c | 106 +++++++++++++++++++++++----------------- 3 files changed, 109 insertions(+), 146 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/eapol.h b/src/include/ipxe/eapol.h index 5ca9c2815..612dd36e0 100644 --- a/src/include/ipxe/eapol.h +++ b/src/include/ipxe/eapol.h @@ -1,114 +1,58 @@ -/* - * Copyright (c) 2009 Joshua Oreman . - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - #ifndef _IPXE_EAPOL_H #define _IPXE_EAPOL_H /** @file * - * Definitions for EAPOL (Extensible Authentication Protocol over - * LANs) frames. Definitions for the packets usually encapsulated in - * them are elsewhere. - */ - -#include -#include - -FILE_LICENCE ( GPL2_OR_LATER ); - - -/** - * @defgroup eapol_type EAPOL archetype identifiers - * @{ - */ -#define EAPOL_TYPE_EAP 0 /**< EAP authentication handshake packet */ -#define EAPOL_TYPE_START 1 /**< Request by Peer to begin (no data) */ -#define EAPOL_TYPE_LOGOFF 2 /**< Request by Peer to terminate (no data) */ -#define EAPOL_TYPE_KEY 3 /**< EAPOL-Key packet */ -/** @} */ - -/** Expected EAPOL version field value - * - * Version 2 is often seen and has no format differences from version 1; - * however, many older APs will completely drop version-2 packets, so - * we advertise ourselves as version 1. - */ -#define EAPOL_THIS_VERSION 1 - -/** Length of an EAPOL frame header */ -#define EAPOL_HDR_LEN 4 - -/** An EAPOL frame + * Extensible Authentication Protocol over LAN (EAPoL) * - * This may encapsulate an eap_pkt, an eapol_key_pkt, or a Start or - * Logoff request with no data attached. It is transmitted directly in - * an Ethernet frame, with no IP packet header. */ -struct eapol_frame -{ - /** EAPOL version identifier, always 1 */ - u8 version; - /** EAPOL archetype identifier indicating format of payload */ - u8 type; +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - /** Length of payload, in network byte order */ - u16 length; +#include +#include +#include - /** Payload, if @a type is EAP or EAPOL-Key */ - u8 data[0]; +/** EAPoL header */ +struct eapol_header { + /** Version */ + uint8_t version; + /** Type */ + uint8_t type; + /** Payload length */ + uint16_t len; } __attribute__ (( packed )); +/** 802.1X-2001 */ +#define EAPOL_VERSION_2001 1 -/** An EAPOL frame type handler - * - * Normally there will be at most two of these, one for EAP and one - * for EAPOL-Key frames. The EAPOL interface code handles Start and - * Logoff directly. - */ -struct eapol_handler -{ - /** EAPOL archetype identifier for payload this handler will handle */ - u8 type; +/** EAPoL key */ +#define EAPOL_TYPE_KEY 5 - /** Receive EAPOL-encapsulated packet of specified type - * - * @v iob I/O buffer containing packet payload - * @v netdev Network device from which packet was received - * @V ll_dest Destination link-layer address - * @v ll_source Source link-layer address - * @ret rc Return status code +/** An EAPoL handler */ +struct eapol_handler { + /** Type */ + uint8_t type; + /** + * Process received packet * - * The I/O buffer will have the EAPOL header pulled off it, so - * @c iob->data points to the first byte of the payload. + * @v iobuf I/O buffer + * @v netdev Network device + * @v ll_source Link-layer source address + * @ret rc Return status code * - * This function takes ownership of the I/O buffer passed to it. + * This method takes ownership of the I/O buffer. */ - int ( * rx ) ( struct io_buffer *iob, struct net_device *netdev, - const void *ll_dest, const void *ll_source ); + int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev, + const void *ll_source ); }; -#define EAPOL_HANDLERS __table ( struct eapol_handler, "eapol_handlers" ) -#define __eapol_handler __table_entry ( EAPOL_HANDLERS, 01 ) +/** EAPoL handler table */ +#define EAPOL_HANDLERS __table ( struct eapol_handler, "eapol_handlers" ) +/** Declare an EAPoL handler */ +#define __eapol_handler __table_entry ( EAPOL_HANDLERS, 01 ) extern struct net_protocol eapol_protocol __net_protocol; - #endif /* _IPXE_EAPOL_H */ diff --git a/src/net/80211/wpa.c b/src/net/80211/wpa.c index 5ec5005bf..1484d0e80 100644 --- a/src/net/80211/wpa.c +++ b/src/net/80211/wpa.c @@ -414,12 +414,13 @@ static int wpa_maybe_install_gtk ( struct wpa_common_ctx *ctx, static struct io_buffer * wpa_alloc_frame ( int kdlen ) { struct io_buffer *ret = alloc_iob ( sizeof ( struct eapol_key_pkt ) + - kdlen + EAPOL_HDR_LEN + + kdlen + + sizeof ( struct eapol_header ) + MAX_LL_HEADER_LEN ); if ( ! ret ) return NULL; - iob_reserve ( ret, MAX_LL_HEADER_LEN + EAPOL_HDR_LEN ); + iob_reserve ( ret, MAX_LL_HEADER_LEN + sizeof ( struct eapol_header ) ); memset ( iob_put ( ret, sizeof ( struct eapol_key_pkt ) ), 0, sizeof ( struct eapol_key_pkt ) ); @@ -442,19 +443,19 @@ static int wpa_send_eapol ( struct io_buffer *iob, struct wpa_common_ctx *ctx, struct wpa_kie *kie ) { struct eapol_key_pkt *pkt = iob->data; - struct eapol_frame *eapol = iob_push ( iob, EAPOL_HDR_LEN ); + struct eapol_header *eapol = iob_push ( iob, sizeof ( *eapol ) ); pkt->info = htons ( pkt->info ); pkt->keysize = htons ( pkt->keysize ); pkt->datalen = htons ( pkt->datalen ); pkt->replay = cpu_to_be64 ( pkt->replay ); - eapol->version = EAPOL_THIS_VERSION; + eapol->version = EAPOL_VERSION_2001; eapol->type = EAPOL_TYPE_KEY; - eapol->length = htons ( iob->tail - iob->data - sizeof ( *eapol ) ); + eapol->len = htons ( iob->tail - iob->data - sizeof ( *eapol ) ); memset ( pkt->mic, 0, sizeof ( pkt->mic ) ); if ( kie ) - kie->mic ( &ctx->ptk.kck, eapol, EAPOL_HDR_LEN + + kie->mic ( &ctx->ptk.kck, eapol, sizeof ( *eapol ) + sizeof ( *pkt ) + ntohs ( pkt->datalen ), pkt->mic ); @@ -762,21 +763,23 @@ static int wpa_handle_1_of_2 ( struct wpa_common_ctx *ctx, * * @v iob I/O buffer * @v netdev Network device - * @v ll_dest Link-layer destination address * @v ll_source Source link-layer address */ static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev, - const void *ll_dest __unused, const void *ll_source ) { struct net80211_device *dev = net80211_get ( netdev ); - struct eapol_key_pkt *pkt = iob->data; + struct eapol_header *eapol; + struct eapol_key_pkt *pkt; int is_rsn, found_ctx; struct wpa_common_ctx *ctx; int rc = 0; struct wpa_kie *kie; u8 their_mic[16], our_mic[16]; + eapol = iob->data; + pkt = ( ( ( void * ) eapol ) + sizeof ( *eapol ) ); + if ( pkt->type != EAPOL_KEY_TYPE_WPA && pkt->type != EAPOL_KEY_TYPE_RSN ) { DBG ( "EAPOL-Key: packet not of 802.11 type\n" ); @@ -840,8 +843,8 @@ static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev, if ( ntohs ( pkt->info ) & EAPOL_KEY_INFO_KEY_MIC ) { memcpy ( their_mic, pkt->mic, sizeof ( pkt->mic ) ); memset ( pkt->mic, 0, sizeof ( pkt->mic ) ); - kie->mic ( &ctx->ptk.kck, ( void * ) pkt - EAPOL_HDR_LEN, - EAPOL_HDR_LEN + sizeof ( *pkt ) + + kie->mic ( &ctx->ptk.kck, eapol, + sizeof ( *eapol ) + sizeof ( *pkt ) + ntohs ( pkt->datalen ), our_mic ); DBGC2 ( ctx, "WPA %p MIC comparison (theirs, ours):\n", ctx ); DBGC2_HD ( ctx, their_mic, 16 ); diff --git a/src/net/eapol.c b/src/net/eapol.c index eb0362994..91119d379 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Joshua Oreman . + * Copyright (C) 2021 Michael Brown . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -15,74 +15,90 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. */ -FILE_LICENCE ( GPL2_OR_LATER ); +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include /** @file * - * 802.1X Extensible Authentication Protocol over LANs demultiplexer + * Extensible Authentication Protocol over LAN (EAPoL) * */ -#include -#include -#include -#include -#include -#include - /** - * Receive EAPOL network-layer packet + * Process EAPoL packet * - * @v iob I/O buffer - * @v netdev Network device - * @v ll_dest Link-layer destination address - * @v ll_source Link-layer source address - * @v flags Packet flags - * - * This function takes ownership of the I/O buffer passed to it. + * @v iobuf I/O buffer + * @v netdev Network device + * @v ll_dest Link-layer destination address + * @v ll_source Link-layer source address + * @v flags Packet flags + * @ret rc Return status code */ -static int eapol_rx ( struct io_buffer *iob, struct net_device *netdev, - const void *ll_dest, const void *ll_source, +static int eapol_rx ( struct io_buffer *iobuf, struct net_device *netdev, + const void *ll_dest __unused, const void *ll_source, unsigned int flags __unused ) { - struct eapol_frame *eapol = iob->data; + struct eapol_header *eapol; struct eapol_handler *handler; + size_t remaining; + size_t len; + int rc; - if ( iob_len ( iob ) < EAPOL_HDR_LEN ) { - free_iob ( iob ); - return -EINVAL; + /* Sanity checks */ + if ( iob_len ( iobuf ) < sizeof ( *eapol ) ) { + DBGC ( netdev, "EAPOL %s underlength header:\n", + netdev->name ); + DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); + rc = -EINVAL; + goto drop; + } + eapol = iobuf->data; + remaining = ( iob_len ( iobuf ) - sizeof ( *eapol ) ); + len = ntohs ( eapol->len ); + if ( len > remaining ) { + DBGC ( netdev, "EAPOL %s v%d type %d len %zd underlength " + "payload:\n", netdev->name, eapol->version, + eapol->type, len ); + DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); + rc = -EINVAL; + goto drop; } + /* Strip any trailing padding */ + iob_unput ( iobuf, ( len - remaining ) ); + + /* Handle according to type */ for_each_table_entry ( handler, EAPOL_HANDLERS ) { if ( handler->type == eapol->type ) { - iob_pull ( iob, EAPOL_HDR_LEN ); - return handler->rx ( iob, netdev, ll_dest, ll_source ); + return handler->rx ( iob_disown ( iobuf ) , netdev, + ll_source ); } } + rc = -ENOTSUP; + DBGC ( netdev, "EAPOL %s v%d type %d unsupported\n", + netdev->name, eapol->version, eapol->type ); + DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); - free_iob ( iob ); - return -( ENOTSUP | ( ( eapol->type & 0x1f ) << 8 ) ); + drop: + free_iob ( iobuf ); + return rc; } -/** - * Transcribe EAPOL network-layer address - * - * @v net_addr Network-layer address - * @ret str String representation of network-layer address - * - * EAPOL doesn't have network-layer addresses, so we just return the - * string @c "". - */ -static const char * eapol_ntoa ( const void *net_addr __unused ) -{ - return ""; -} - -/** EAPOL network protocol */ +/** EAPoL protocol */ struct net_protocol eapol_protocol __net_protocol = { .name = "EAPOL", - .rx = eapol_rx, - .ntoa = eapol_ntoa, .net_proto = htons ( ETH_P_EAPOL ), + .rx = eapol_rx, }; -- cgit v1.2.3-55-g7522 From 9c2e8bad1143e1095205d67dbe6b3032d39af0ab Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 19 Jan 2021 12:37:50 +0000 Subject: [eap] Treat an EAP Request-Identity as indicating a blocked link A switch port using 802.1x authentication will send EAP Request-Identity packets once the physical link is up, and will not be forwarding packets until the port identity has been established. We do not currently support 802.1x authentication. However, a reasonably common configuration involves using a preset list of permitted MAC addresses, with the "authentication" taking place between the switch and a RADIUS server. In this configuration, the end device does not need to perform any authentication step, but does need to be prepared for the switch port to fail to forward packets for a substantial time after physical link-up. This exactly matches the "blocked link" semantics already used when detecting a non-forwarding switch port via LACP or STP. Treat a received EAP Request-Identity as indicating a blocked link. Unlike LACP or STP, there is no way to determine the expected time until the next EAP packet and so we must choose a fixed timeout. Erroneously assuming that the link is blocked is relatively harmless since we will still attempt to transmit and receive data even over a link that is marked as blocked, and so the net effect is merely to prolong DHCP attempts. In contrast, erroneously assuming that the link is unblocked will potentially cause DHCP to time out and give up, resulting in a failed boot. The default EAP Request-Identity interval in Cisco switches (where this is most likely to be encountered in practice) is 30 seconds, so choose 45 seconds as a timeout that is likely to avoid gaps during which we falsely assume that the link is unblocked. Signed-off-by: Michael Brown --- src/config/config_ethernet.c | 3 + src/config/general.h | 1 + src/include/ipxe/eap.h | 69 +++++++++++++++++++++ src/include/ipxe/eapol.h | 3 + src/include/ipxe/errfile.h | 1 + src/net/eap.c | 142 +++++++++++++++++++++++++++++++++++++++++++ src/net/eapol.c | 37 +++++++++++ 7 files changed, 256 insertions(+) create mode 100644 src/include/ipxe/eap.h create mode 100644 src/net/eap.c (limited to 'src/include/ipxe') diff --git a/src/config/config_ethernet.c b/src/config/config_ethernet.c index b5f7ddc9d..8a663c923 100644 --- a/src/config/config_ethernet.c +++ b/src/config/config_ethernet.c @@ -46,3 +46,6 @@ REQUIRE_OBJECT ( stp ); #ifdef NET_PROTO_LACP REQUIRE_OBJECT ( eth_slow ); #endif +#ifdef NET_PROTO_EAPOL +REQUIRE_OBJECT ( eapol ); +#endif diff --git a/src/config/general.h b/src/config/general.h index 0c99bcbb6..9edf93b5a 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -39,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #undef NET_PROTO_FCOE /* Fibre Channel over Ethernet protocol */ #define NET_PROTO_STP /* Spanning Tree protocol */ #define NET_PROTO_LACP /* Link Aggregation control protocol */ +#define NET_PROTO_EAPOL /* EAP over LAN protocol */ /* * PXE support diff --git a/src/include/ipxe/eap.h b/src/include/ipxe/eap.h new file mode 100644 index 000000000..6fe70189b --- /dev/null +++ b/src/include/ipxe/eap.h @@ -0,0 +1,69 @@ +#ifndef _IPXE_EAP_H +#define _IPXE_EAP_H + +/** @file + * + * Extensible Authentication Protocol + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include + +/** EAP header */ +struct eap_header { + /** Code */ + uint8_t code; + /** Identifier */ + uint8_t id; + /** Length */ + uint16_t len; +} __attribute__ (( packed )); + +/** EAP request */ +#define EAP_CODE_REQUEST 1 + +/** EAP request */ +struct eap_request { + /** Header */ + struct eap_header hdr; + /** Type */ + uint8_t type; +} __attribute__ (( packed )); + +/** EAP identity */ +#define EAP_TYPE_IDENTITY 1 + +/** EAP success */ +#define EAP_CODE_SUCCESS 3 + +/** EAP failure */ +#define EAP_CODE_FAILURE 4 + +/** EAP packet */ +union eap_packet { + /** Header */ + struct eap_header hdr; + /** Request */ + struct eap_request req; +}; + +/** Link block timeout + * + * We mark the link as blocked upon receiving a Request-Identity, on + * the basis that this most likely indicates that the switch will not + * yet be forwarding packets. + * + * There is no way to tell how frequently the Request-Identity packet + * will be retransmitted by the switch. The default value for Cisco + * switches seems to be 30 seconds, so treat the link as blocked for + * 45 seconds. + */ +#define EAP_BLOCK_TIMEOUT ( 45 * TICKS_PER_SEC ) + +extern int eap_rx ( struct net_device *netdev, const void *data, size_t len ); + +#endif /* _IPXE_EAP_H */ diff --git a/src/include/ipxe/eapol.h b/src/include/ipxe/eapol.h index 612dd36e0..952d6c752 100644 --- a/src/include/ipxe/eapol.h +++ b/src/include/ipxe/eapol.h @@ -26,6 +26,9 @@ struct eapol_header { /** 802.1X-2001 */ #define EAPOL_VERSION_2001 1 +/** EAPoL-encapsulated EAP packets */ +#define EAPOL_TYPE_EAP 0 + /** EAPoL key */ #define EAPOL_TYPE_KEY 5 diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 3437a5217..d317ce5be 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -287,6 +287,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_xsigo ( ERRFILE_NET | 0x00480000 ) #define ERRFILE_ntp ( ERRFILE_NET | 0x00490000 ) #define ERRFILE_httpntlm ( ERRFILE_NET | 0x004a0000 ) +#define ERRFILE_eap ( ERRFILE_NET | 0x004b0000 ) #define ERRFILE_image ( ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_elf ( ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/net/eap.c b/src/net/eap.c new file mode 100644 index 000000000..8d1d540fb --- /dev/null +++ b/src/net/eap.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2021 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include + +/** @file + * + * Extensible Authentication Protocol + * + */ + +/** + * Handle EAP Request-Identity + * + * @v netdev Network device + * @ret rc Return status code + */ +static int eap_rx_request_identity ( struct net_device *netdev ) { + + /* Treat Request-Identity as blocking the link */ + DBGC ( netdev, "EAP %s Request-Identity blocking link\n", + netdev->name ); + netdev_link_block ( netdev, EAP_BLOCK_TIMEOUT ); + + return 0; +} + +/** + * Handle EAP Request + * + * @v netdev Network device + * @v req EAP request + * @v len Length of EAP request + * @ret rc Return status code + */ +static int eap_rx_request ( struct net_device *netdev, + const struct eap_request *req, size_t len ) { + + /* Sanity check */ + if ( len < sizeof ( *req ) ) { + DBGC ( netdev, "EAP %s underlength request:\n", netdev->name ); + DBGC_HDA ( netdev, 0, req, len ); + return -EINVAL; + } + + /* Handle according to type */ + switch ( req->type ) { + case EAP_TYPE_IDENTITY: + return eap_rx_request_identity ( netdev ); + default: + DBGC ( netdev, "EAP %s requested type %d unknown:\n", + netdev->name, req->type ); + DBGC_HDA ( netdev, 0, req, len ); + return -ENOTSUP; + } +} + +/** + * Handle EAP Success + * + * @v netdev Network device + * @ret rc Return status code + */ +static int eap_rx_success ( struct net_device *netdev ) { + + /* Mark link as unblocked */ + DBGC ( netdev, "EAP %s Success\n", netdev->name ); + netdev_link_unblock ( netdev ); + + return 0; +} + +/** + * Handle EAP Failure + * + * @v netdev Network device + * @ret rc Return status code + */ +static int eap_rx_failure ( struct net_device *netdev ) { + + /* Record error */ + DBGC ( netdev, "EAP %s Failure\n", netdev->name ); + return -EPERM; +} + +/** + * Handle EAP packet + * + * @v netdev Network device + * @v data EAP packet + * @v len Length of EAP packet + * @ret rc Return status code + */ +int eap_rx ( struct net_device *netdev, const void *data, size_t len ) { + const union eap_packet *eap = data; + + /* Sanity check */ + if ( len < sizeof ( eap->hdr ) ) { + DBGC ( netdev, "EAP %s underlength header:\n", netdev->name ); + DBGC_HDA ( netdev, 0, eap, len ); + return -EINVAL; + } + + /* Handle according to code */ + switch ( eap->hdr.code ) { + case EAP_CODE_REQUEST: + return eap_rx_request ( netdev, &eap->req, len ); + case EAP_CODE_SUCCESS: + return eap_rx_success ( netdev ); + case EAP_CODE_FAILURE: + return eap_rx_failure ( netdev ); + default: + DBGC ( netdev, "EAP %s unsupported code %d\n", + netdev->name, eap->hdr.code ); + DBGC_HDA ( netdev, 0, eap, len ); + return -ENOTSUP; + } +} diff --git a/src/net/eapol.c b/src/net/eapol.c index 91119d379..3578f0e37 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include /** @file @@ -102,3 +103,39 @@ struct net_protocol eapol_protocol __net_protocol = { .net_proto = htons ( ETH_P_EAPOL ), .rx = eapol_rx, }; + +/** + * Process EAPoL-encapsulated EAP packet + * + * @v netdev Network device + * @v ll_source Link-layer source address + * @ret rc Return status code + */ +static int eapol_eap_rx ( struct io_buffer *iobuf, struct net_device *netdev, + const void *ll_source __unused ) { + struct eapol_header *eapol; + int rc; + + /* Sanity check */ + assert ( iob_len ( iobuf ) >= sizeof ( *eapol ) ); + + /* Strip EAPoL header */ + eapol = iob_pull ( iobuf, sizeof ( *eapol ) ); + + /* Process EAP packet */ + if ( ( rc = eap_rx ( netdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 ) { + DBGC ( netdev, "EAPOL %s v%d EAP failed: %s\n", + netdev->name, eapol->version, strerror ( rc ) ); + goto drop; + } + + drop: + free_iob ( iobuf ); + return rc; +} + +/** EAPoL handler for EAP packets */ +struct eapol_handler eapol_eap __eapol_handler = { + .type = EAPOL_TYPE_EAP, + .rx = eapol_eap_rx, +}; -- cgit v1.2.3-55-g7522 From 99ac69b8a9a48207913e98ac6b357c029b0eef81 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 20 Jan 2021 18:03:16 +0000 Subject: [image] Provide image_set_data() Extract part of the logic in initrd_init() to a standalone function image_set_data(). Signed-off-by: Michael Brown --- src/arch/x86/core/runtime.c | 21 +++++++++------------ src/core/image.c | 24 ++++++++++++++++++++++++ src/include/ipxe/image.h | 1 + 3 files changed, 34 insertions(+), 12 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/arch/x86/core/runtime.c b/src/arch/x86/core/runtime.c index f96b23af4..4de3bfafe 100644 --- a/src/arch/x86/core/runtime.c +++ b/src/arch/x86/core/runtime.c @@ -38,7 +38,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include /** Command line physical address @@ -202,23 +201,21 @@ static int initrd_init ( void ) { rc = -ENOMEM; goto err_alloc_image; } + + /* Set image name */ if ( ( rc = image_set_name ( image, "" ) ) != 0 ) { DBGC ( colour, "RUNTIME could not set image name: %s\n", strerror ( rc ) ); goto err_set_name; } - /* Allocate and copy initrd content */ - image->data = umalloc ( initrd_len ); - if ( ! image->data ) { - DBGC ( colour, "RUNTIME could not allocate %d bytes for " - "initrd\n", initrd_len ); - rc = -ENOMEM; - goto err_umalloc; + /* Set image content */ + if ( ( rc = image_set_data ( image, phys_to_user ( initrd_phys ), + initrd_len ) ) != 0 ) { + DBGC ( colour, "RUNTIME could not set image data: %s\n", + strerror ( rc ) ); + goto err_set_data; } - image->len = initrd_len; - memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0, - initrd_len ); /* Mark initrd as consumed */ initrd_phys = 0; @@ -236,7 +233,7 @@ static int initrd_init ( void ) { return 0; err_register_image: - err_umalloc: + err_set_data: err_set_name: image_put ( image ); err_alloc_image: diff --git a/src/core/image.c b/src/core/image.c index 078ce1bb9..54b998025 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -175,6 +175,30 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) { return 0; } +/** + * Set image data + * + * @v image Image + * @v data Image data + * @v len Length of image data + * @ret rc Return status code + */ +int image_set_data ( struct image *image, userptr_t data, size_t len ) { + userptr_t new; + + /* (Re)allocate image data */ + new = urealloc ( image->data, len ); + if ( ! new ) + return -ENOMEM; + image->data = new; + + /* Copy in new image data */ + memcpy_user ( image->data, 0, data, 0, len ); + image->len = len; + + return 0; +} + /** * Determine image type * diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index 2e7eb4cee..4c3877607 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -175,6 +175,7 @@ extern struct image * alloc_image ( struct uri *uri ); extern int image_set_uri ( struct image *image, struct uri *uri ); extern int image_set_name ( struct image *image, const char *name ); extern int image_set_cmdline ( struct image *image, const char *cmdline ); +extern int image_set_data ( struct image *image, userptr_t data, size_t len ); extern int register_image ( struct image *image ); extern void unregister_image ( struct image *image ); struct image * find_image ( const char *name ); -- cgit v1.2.3-55-g7522 From 989a7a8032db02eb0524bd78a674d3b087dea3a6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 25 Jan 2021 16:18:28 +0000 Subject: [image] Provide image_memory() Consolidate the remaining logic common to initrd_init() and imgmem() into a shared image_memory() function. Signed-off-by: Michael Brown --- src/arch/x86/core/runtime.c | 44 +++++----------------------------------- src/core/image.c | 44 ++++++++++++++++++++++++++++++++++++++++ src/hci/commands/image_mem_cmd.c | 4 +--- src/include/ipxe/image.h | 2 ++ src/include/usr/imgmgmt.h | 3 +-- src/usr/imgmgmt.c | 41 ++++++++----------------------------- 6 files changed, 62 insertions(+), 76 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/arch/x86/core/runtime.c b/src/arch/x86/core/runtime.c index 4de3bfafe..02072b5bf 100644 --- a/src/arch/x86/core/runtime.c +++ b/src/arch/x86/core/runtime.c @@ -179,7 +179,6 @@ static int cmdline_init ( void ) { */ static int initrd_init ( void ) { struct image *image; - int rc; /* Do nothing if no initrd was specified */ if ( ! initrd_phys ) { @@ -193,51 +192,18 @@ static int initrd_init ( void ) { DBGC ( colour, "RUNTIME found initrd at [%x,%x)\n", initrd_phys, ( initrd_phys + initrd_len ) ); - /* Allocate image */ - image = alloc_image ( NULL ); + /* Create initrd image */ + image = image_memory ( "", phys_to_user ( initrd_phys ), + initrd_len ); if ( ! image ) { - DBGC ( colour, "RUNTIME could not allocate image for " - "initrd\n" ); - rc = -ENOMEM; - goto err_alloc_image; - } - - /* Set image name */ - if ( ( rc = image_set_name ( image, "" ) ) != 0 ) { - DBGC ( colour, "RUNTIME could not set image name: %s\n", - strerror ( rc ) ); - goto err_set_name; - } - - /* Set image content */ - if ( ( rc = image_set_data ( image, phys_to_user ( initrd_phys ), - initrd_len ) ) != 0 ) { - DBGC ( colour, "RUNTIME could not set image data: %s\n", - strerror ( rc ) ); - goto err_set_data; + DBGC ( colour, "RUNTIME could not create initrd image\n" ); + return -ENOMEM; } /* Mark initrd as consumed */ initrd_phys = 0; - /* Register image */ - if ( ( rc = register_image ( image ) ) != 0 ) { - DBGC ( colour, "RUNTIME could not register initrd: %s\n", - strerror ( rc ) ); - goto err_register_image; - } - - /* Drop our reference to the image */ - image_put ( image ); - return 0; - - err_register_image: - err_set_data: - err_set_name: - image_put ( image ); - err_alloc_image: - return rc; } /** diff --git a/src/core/image.c b/src/core/image.c index 54b998025..9fe77c54c 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -505,3 +505,47 @@ int image_set_trust ( int require_trusted, int permanent ) { return 0; } + +/** + * Create registered image from block of memory + * + * @v name Name + * @v data Image data + * @v len Length + * @ret image Image, or NULL on error + */ +struct image * image_memory ( const char *name, userptr_t data, size_t len ) { + struct image *image; + int rc; + + /* Allocate image */ + image = alloc_image ( NULL ); + if ( ! image ) { + rc = -ENOMEM; + goto err_alloc_image; + } + + /* Set name */ + if ( ( rc = image_set_name ( image, name ) ) != 0 ) + goto err_set_name; + + /* Set data */ + if ( ( rc = image_set_data ( image, data, len ) ) != 0 ) + goto err_set_data; + + /* Register image */ + if ( ( rc = register_image ( image ) ) != 0 ) + goto err_register; + + /* Drop local reference to image */ + image_put ( image ); + + return image; + + err_register: + err_set_data: + err_set_name: + image_put ( image ); + err_alloc_image: + return NULL; +} diff --git a/src/hci/commands/image_mem_cmd.c b/src/hci/commands/image_mem_cmd.c index 61d50534d..c8bfab1ad 100644 --- a/src/hci/commands/image_mem_cmd.c +++ b/src/hci/commands/image_mem_cmd.c @@ -60,7 +60,6 @@ static struct command_descriptor imgmem_cmd = */ static int imgmem_exec ( int argc, char **argv ) { struct imgmem_options opts; - struct image *image; unsigned int data; unsigned int len; int rc; @@ -82,8 +81,7 @@ static int imgmem_exec ( int argc, char **argv ) { return rc; /* Create image */ - if ( ( rc = imgmem ( phys_to_user ( data ), len, opts.name, - &image ) ) != 0 ) + if ( ( rc = imgmem ( opts.name, phys_to_user ( data ), len ) ) != 0 ) return rc; return 0; diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index 4c3877607..4fd270081 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -184,6 +184,8 @@ extern int image_replace ( struct image *replacement ); extern int image_select ( struct image *image ); extern struct image * image_find_selected ( void ); extern int image_set_trust ( int require_trusted, int permanent ); +extern struct image * image_memory ( const char *name, userptr_t data, + size_t len ); extern int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf ); extern int image_asn1 ( struct image *image, size_t offset, struct asn1_cursor **cursor ); diff --git a/src/include/usr/imgmgmt.h b/src/include/usr/imgmgmt.h index c59cf1a0b..14fb7cbc6 100644 --- a/src/include/usr/imgmgmt.h +++ b/src/include/usr/imgmgmt.h @@ -18,7 +18,6 @@ extern int imgdownload_string ( const char *uri_string, unsigned long timeout, extern int imgacquire ( const char *name, unsigned long timeout, struct image **image ); extern void imgstat ( struct image *image ); -extern int imgmem ( userptr_t data, size_t len, const char *name, - struct image **image ); +extern int imgmem ( const char *name, userptr_t data, size_t len ); #endif /* _USR_IMGMGMT_H */ diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index bf4c745ea..f8d149153 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -173,43 +173,20 @@ void imgstat ( struct image *image ) { /** * Create image from block of memory * + * @v name Name * @v data Image data * @v len Length - * @v name Name - * @v image Image to fill in * @ret rc Return status code */ -int imgmem ( userptr_t data, size_t len, const char *name, - struct image **image ) { - int rc; - - /* Allocate image */ - *image = alloc_image ( NULL ); - if ( ! *image ) { - rc = -ENOMEM; - goto err_alloc_image; - } - - /* Set name */ - if ( ( rc = image_set_name ( *image, name ) ) != 0 ) - goto err_set_name; +int imgmem ( const char *name, userptr_t data, size_t len ) { + struct image *image; - /* Set data */ - if ( ( rc = image_set_data ( *image, data, len ) ) != 0 ) { - printf ( "Could not set image data: %s\n", strerror ( rc ) ); - goto err_set_data; - } - - /* Register image */ - if ( ( rc = register_image ( *image ) ) != 0 ) { - printf ( "Could not register image: %s\n", strerror ( rc ) ); - goto err_register_image; + /* Create image */ + image = image_memory ( name, data, len ); + if ( ! image ) { + printf ( "Could not create image\n" ); + return -ENOMEM; } - err_register_image: - err_set_data: - err_set_name: - image_put ( *image ); - err_alloc_image: - return rc; + return 0; } -- cgit v1.2.3-55-g7522 From a3f1e8fb6707811e6eb90e339d7ebe813fd89a63 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 25 Jan 2021 16:34:22 +0000 Subject: [efi] Automatically load "/autoexec.ipxe" when booted from a filesystem When booting iPXE from a filesystem (e.g. a FAT-formatted USB key) it can be useful to have an iPXE script loaded automatically from the same filesystem. Compared to using an embedded script, this has the advantage that the script can be edited without recompiling the iPXE binary. For the BIOS version of iPXE, loading from a filesystem is handled using syslinux (or isolinux) which allows the script to be passed to the iPXE .lkrn image as an initrd. For the UEFI version of iPXE, the platform firmware loads the iPXE .efi image directly and there is currently no equivalent of the BIOS initrd mechanism. Add support for automatically loading a file "autoexec.ipxe" (if present) from the root of the filesystem containing the UEFI iPXE binary. A combined BIOS and UEFI image for a USB key can be created using e.g. ./util/genfsimg -o usbkey.img -s myscript.ipxe \ bin-x86_64-efi/ipxe.efi bin/ipxe.lkrn The file "myscript.ipxe" would appear as "autoexec.ipxe" on the USB key, and would be loaded automatically on both BIOS and UEFI systems. Signed-off-by: Michael Brown --- src/include/ipxe/errfile.h | 1 + src/interface/efi/efi_autoboot.c | 210 +++++++++++++++++++++++++++++++++++++-- src/util/genfsimg | 3 + 3 files changed, 204 insertions(+), 10 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index d317ce5be..f14cb8619 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -383,6 +383,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_acpi_settings ( ERRFILE_OTHER | 0x00500000 ) #define ERRFILE_ntlm ( ERRFILE_OTHER | 0x00510000 ) #define ERRFILE_efi_veto ( ERRFILE_OTHER | 0x00520000 ) +#define ERRFILE_efi_autoboot ( ERRFILE_OTHER | 0x00530000 ) /** @} */ diff --git a/src/interface/efi/efi_autoboot.c b/src/interface/efi/efi_autoboot.c index a9e807e23..33a780f5b 100644 --- a/src/interface/efi/efi_autoboot.c +++ b/src/interface/efi/efi_autoboot.c @@ -23,22 +23,42 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include +#include +#include +#include #include #include #include +#include +#include #include /** @file * - * EFI autoboot device + * EFI automatic booting * */ +/** Autoexec script filename */ +#define AUTOEXEC_FILENAME L"autoexec.ipxe" + +/** Autoexec script image name */ +#define AUTOEXEC_NAME "autoexec.ipxe" + +/** Autoexec script (if any) */ +static void *efi_autoexec; + +/** Autoexec script length */ +static size_t efi_autoexec_len; + /** * Identify autoboot device * + * @v device Device handle + * @ret rc Return status code */ -void efi_set_autoboot ( void ) { +static int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; union { EFI_SIMPLE_NETWORK_PROTOCOL *snp; @@ -46,26 +66,196 @@ void efi_set_autoboot ( void ) { } snp; EFI_SIMPLE_NETWORK_MODE *mode; EFI_STATUS efirc; + int rc; /* Look for an SNP instance on the image's device handle */ - if ( ( efirc = bs->OpenProtocol ( efi_loaded_image->DeviceHandle, + if ( ( efirc = bs->OpenProtocol ( device, &efi_simple_network_protocol_guid, &snp.interface, efi_image_handle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - DBGC ( efi_loaded_image, "EFI found no autoboot device\n" ); - return; + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s has no SNP instance: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + return rc; } /* Record autoboot device */ mode = snp.snp->Mode; set_autoboot_ll_addr ( &mode->CurrentAddress, mode->HwAddressSize ); - DBGC ( efi_loaded_image, "EFI found autoboot link-layer address:\n" ); - DBGC_HDA ( efi_loaded_image, 0, &mode->CurrentAddress, - mode->HwAddressSize ); + DBGC ( device, "EFI %s found autoboot link-layer address:\n", + efi_handle_name ( device ) ); + DBGC_HDA ( device, 0, &mode->CurrentAddress, mode->HwAddressSize ); /* Close protocol */ - bs->CloseProtocol ( efi_loaded_image->DeviceHandle, - &efi_simple_network_protocol_guid, + bs->CloseProtocol ( device, &efi_simple_network_protocol_guid, efi_image_handle, NULL ); + + return 0; } + +/** + * Load autoexec script + * + * @v device Device handle + * @ret rc Return status code + */ +static int efi_load_autoexec ( EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + static wchar_t name[] = AUTOEXEC_FILENAME; + union { + void *interface; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs; + } u; + struct { + EFI_FILE_INFO info; + CHAR16 name[ sizeof ( name ) / sizeof ( name[0] ) ]; + } info; + EFI_FILE_PROTOCOL *root; + EFI_FILE_PROTOCOL *file; + UINTN size; + VOID *data; + EFI_STATUS efirc; + int rc; + + /* Sanity check */ + assert ( efi_autoexec == UNULL ); + assert ( efi_autoexec_len == 0 ); + + /* Open simple file system protocol */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_simple_file_system_protocol_guid, + &u.interface, efi_image_handle, + device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s has no filesystem instance: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_filesystem; + } + + /* Open root directory */ + if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not open volume: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_volume; + } + + /* Open autoexec script */ + if ( ( efirc = root->Open ( root, &file, name, + EFI_FILE_MODE_READ, 0 ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s has no %ls: %s\n", + efi_handle_name ( device ), name, strerror ( rc ) ); + goto err_open; + } + + /* Get file information */ + size = sizeof ( info ); + if ( ( efirc = file->GetInfo ( file, &efi_file_info_id, &size, + &info ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not get %ls info: %s\n", + efi_handle_name ( device ), name, strerror ( rc ) ); + goto err_getinfo; + } + size = info.info.FileSize; + + /* Ignore zero-length files */ + if ( ! size ) { + rc = -EINVAL; + DBGC ( device, "EFI %s has zero-length %ls\n", + efi_handle_name ( device ), name ); + goto err_empty; + } + + /* Allocate temporary copy */ + if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, size, + &data ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not allocate %ls: %s\n", + efi_handle_name ( device ), name, strerror ( rc ) ); + goto err_alloc; + } + + /* Read file */ + if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not read %ls: %s\n", + efi_handle_name ( device ), name, strerror ( rc ) ); + goto err_read; + } + + /* Record autoexec script */ + efi_autoexec = data; + efi_autoexec_len = size; + data = NULL; + DBGC ( device, "EFI %s found %ls\n", + efi_handle_name ( device ), name ); + + err_read: + if ( data ) + bs->FreePool ( data ); + err_alloc: + err_empty: + err_getinfo: + file->Close ( file ); + err_open: + root->Close ( root ); + err_volume: + bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid, + efi_image_handle, device ); + err_filesystem: + return rc; +} + +/** + * Configure automatic booting + * + */ +void efi_set_autoboot ( void ) { + EFI_HANDLE device = efi_loaded_image->DeviceHandle; + + /* Identify autoboot device, if any */ + efi_set_autoboot_ll_addr ( device ); + + /* Load autoexec script, if any */ + efi_load_autoexec ( device ); +} + +/** + * Register automatic boot image + * + */ +static void efi_autoboot_startup ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE device = efi_loaded_image->DeviceHandle; + const char *name = AUTOEXEC_NAME; + struct image *image; + + /* Do nothing if we have no autoexec script */ + if ( ! efi_autoexec ) + return; + + /* Create autoexec image */ + image = image_memory ( name, virt_to_user ( efi_autoexec ), + efi_autoexec_len ); + if ( ! image ) { + DBGC ( device, "EFI %s could not create %s\n", + efi_handle_name ( device ), name ); + return; + } + DBGC ( device, "EFI %s registered %s\n", + efi_handle_name ( device ), name ); + + /* Free temporary copy */ + bs->FreePool ( efi_autoexec ); + efi_autoexec = NULL; +} + +/** Automatic boot startup function */ +struct startup_fn efi_autoboot_startup_fn __startup_fn ( STARTUP_NORMAL ) = { + .name = "efi_autoboot", + .startup = efi_autoboot_startup, +}; diff --git a/src/util/genfsimg b/src/util/genfsimg index 345673460..d31e4995d 100755 --- a/src/util/genfsimg +++ b/src/util/genfsimg @@ -203,6 +203,9 @@ for FILENAME ; do DESTFILE=$(efi_boot_name "${FILENAME}") if [ -z "${EFI}" ] ; then mkdir -p "${DESTDIR}" + if [ -n "${SCRIPT}" ] ; then + cp "${SCRIPT}" "${FATDIR}/autoexec.ipxe" + fi fi EFI=1 ;; -- cgit v1.2.3-55-g7522 From b9de7e6eda04cecaff6735a60c7fe7f488fdccf1 Mon Sep 17 00:00:00 2001 From: Christian Iversen Date: Wed, 27 Jan 2021 00:43:51 +0100 Subject: [infiniband] Require drivers to specify the number of ports Require drivers to report the total number of Infiniband ports. This is necessary to report the correct number of ports on devices with dynamic port types. For example, dual-port Mellanox cards configured for (eth, ib) would be rejected by the subnet manager, because they report using "port 2, out of 1". Signed-off-by: Christian Iversen --- src/drivers/infiniband/arbel.c | 1 + src/drivers/infiniband/flexboot_nodnic.c | 1 + src/drivers/infiniband/golan.c | 1 + src/drivers/infiniband/hermon.c | 1 + src/drivers/infiniband/linda.c | 1 + src/drivers/infiniband/qib7322.c | 1 + src/include/ipxe/infiniband.h | 3 ++- src/net/infiniband.c | 20 -------------------- src/net/infiniband/ib_sma.c | 2 +- 9 files changed, 9 insertions(+), 22 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/drivers/infiniband/arbel.c b/src/drivers/infiniband/arbel.c index fb48487f3..fbef3f8a6 100644 --- a/src/drivers/infiniband/arbel.c +++ b/src/drivers/infiniband/arbel.c @@ -3061,6 +3061,7 @@ static int arbel_probe ( struct pci_device *pci ) { ibdev->op = &arbel_ib_operations; ibdev->dev = &pci->dev; ibdev->port = ( ARBEL_PORT_BASE + i ); + ibdev->ports = ARBEL_NUM_PORTS; ib_set_drvdata ( ibdev, arbel ); } diff --git a/src/drivers/infiniband/flexboot_nodnic.c b/src/drivers/infiniband/flexboot_nodnic.c index 54b858406..c6e19b955 100644 --- a/src/drivers/infiniband/flexboot_nodnic.c +++ b/src/drivers/infiniband/flexboot_nodnic.c @@ -1165,6 +1165,7 @@ flexboot_nodnic_allocate_infiniband_devices( struct flexboot_nodnic *flexboot_no ibdev->op = &flexboot_nodnic_ib_operations; ibdev->dev = &pci->dev; ibdev->port = ( FLEXBOOT_NODNIC_PORT_BASE + i); + ibdev->ports = device_priv->device_cap.num_ports; ib_set_drvdata(ibdev, flexboot_nodnic_priv); } return status; diff --git a/src/drivers/infiniband/golan.c b/src/drivers/infiniband/golan.c index 441d3b73f..2f1ab2357 100755 --- a/src/drivers/infiniband/golan.c +++ b/src/drivers/infiniband/golan.c @@ -2386,6 +2386,7 @@ static int golan_probe_normal ( struct pci_device *pci ) { ibdev->op = &golan_ib_operations; ibdev->dev = &pci->dev; ibdev->port = (GOLAN_PORT_BASE + i); + ibdev->ports = golan->caps.num_ports; ib_set_drvdata( ibdev, golan ); } diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index fdf2d9dd8..7537d83c2 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -3829,6 +3829,7 @@ static int hermon_probe ( struct pci_device *pci ) { ibdev->op = &hermon_ib_operations; ibdev->dev = &pci->dev; ibdev->port = ( HERMON_PORT_BASE + i ); + ibdev->ports = hermon->cap.num_ports; ib_set_drvdata ( ibdev, hermon ); } diff --git a/src/drivers/infiniband/linda.c b/src/drivers/infiniband/linda.c index b275268a2..8c5912660 100644 --- a/src/drivers/infiniband/linda.c +++ b/src/drivers/infiniband/linda.c @@ -2330,6 +2330,7 @@ static int linda_probe ( struct pci_device *pci ) { ibdev->op = &linda_ib_operations; ibdev->dev = &pci->dev; ibdev->port = 1; + ibdev->ports = 1; /* Fix up PCI device */ adjust_pci_device ( pci ); diff --git a/src/drivers/infiniband/qib7322.c b/src/drivers/infiniband/qib7322.c index e3250147d..a4b51db05 100644 --- a/src/drivers/infiniband/qib7322.c +++ b/src/drivers/infiniband/qib7322.c @@ -2348,6 +2348,7 @@ static int qib7322_probe ( struct pci_device *pci ) { ibdev->dev = &pci->dev; ibdev->op = &qib7322_ib_operations; ibdev->port = ( QIB7322_PORT_BASE + i ); + ibdev->ports = QIB7322_MAX_PORTS; ibdev->link_width_enabled = ibdev->link_width_supported = IB_LINK_WIDTH_4X; /* 1x does not work */ ibdev->link_speed_enabled = ibdev->link_speed_supported = diff --git a/src/include/ipxe/infiniband.h b/src/include/ipxe/infiniband.h index 6f4951f17..379bc109e 100644 --- a/src/include/ipxe/infiniband.h +++ b/src/include/ipxe/infiniband.h @@ -416,6 +416,8 @@ struct ib_device { struct ib_device_operations *op; /** Port number */ unsigned int port; + /** Total ports on device */ + unsigned int ports; /** Port open request counter */ unsigned int open_count; @@ -538,7 +540,6 @@ extern int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp, union ib_gid *gid ); extern void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, union ib_gid *gid ); -extern int ib_count_ports ( struct ib_device *ibdev ); extern int ib_set_port_info ( struct ib_device *ibdev, union ib_mad *mad ); extern int ib_set_pkey_table ( struct ib_device *ibdev, union ib_mad *mad ); extern struct ib_device * alloc_ibdev ( size_t priv_size ); diff --git a/src/net/infiniband.c b/src/net/infiniband.c index 3b79a660c..e19e121c1 100644 --- a/src/net/infiniband.c +++ b/src/net/infiniband.c @@ -813,26 +813,6 @@ void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, *************************************************************************** */ -/** - * Count Infiniband HCA ports - * - * @v ibdev Infiniband device - * @ret num_ports Number of ports - */ -int ib_count_ports ( struct ib_device *ibdev ) { - struct ib_device *tmp; - int num_ports = 0; - - /* Search for IB devices with the same physical device to - * identify port count. - */ - for_each_ibdev ( tmp ) { - if ( tmp->dev == ibdev->dev ) - num_ports++; - } - return num_ports; -} - /** * Set port information * diff --git a/src/net/infiniband/ib_sma.c b/src/net/infiniband/ib_sma.c index 24ec9f4e0..b553e66b1 100644 --- a/src/net/infiniband/ib_sma.c +++ b/src/net/infiniband/ib_sma.c @@ -63,7 +63,7 @@ static void ib_sma_node_info ( struct ib_device *ibdev, node_info->base_version = IB_MGMT_BASE_VERSION; node_info->class_version = IB_SMP_CLASS_VERSION; node_info->node_type = IB_NODE_TYPE_HCA; - node_info->num_ports = ib_count_ports ( ibdev ); + node_info->num_ports = ibdev->ports; memcpy ( &node_info->sys_guid, &ibdev->node_guid, sizeof ( node_info->sys_guid ) ); memcpy ( &node_info->node_guid, &ibdev->node_guid, -- cgit v1.2.3-55-g7522 From b539e9a7e95c3a481c686ffcf310c87bc1e19707 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 12 Feb 2021 21:56:53 +0000 Subject: [build] Remove support for building with the Intel C compiler Support for building with the Intel C compiler (icc) was added in 2009 in the expectation that UEFI support would eventually involve compiling iPXE to EFI Byte Code. EFI Byte Code has never found any widespread use: no widely available compilers can emit it, Microsoft refuses to sign EFI Byte Code binaries for UEFI Secure Boot, and I have personally never encountered any examples of EFI Byte Code in the wild. The support for using the Intel C compiler has not been tested in over a decade, and would almost certainly require modification to work with current releases of the compiler. Simplify the build process by removing this old legacy code. Signed-off-by: Michael Brown --- src/Makefile | 1 - src/Makefile.housekeeping | 57 ++-------------- src/include/ipxe/efi/efi.h | 5 -- src/include/ipxe/tables.h | 71 -------------------- src/util/.gitignore | 1 - src/util/iccfix.c | 157 --------------------------------------------- 6 files changed, 5 insertions(+), 287 deletions(-) delete mode 100644 src/util/iccfix.c (limited to 'src/include/ipxe') diff --git a/src/Makefile b/src/Makefile index 758db7e1f..60be873fb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -48,7 +48,6 @@ ELF2EFI32 := ./util/elf2efi32 ELF2EFI64 := ./util/elf2efi64 EFIROM := ./util/efirom EFIFATBIN := ./util/efifatbin -ICCFIX := ./util/iccfix EINFO := ./util/einfo GENKEYMAP := ./util/genkeymap.pl DOXYGEN := doxygen diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index bade2da3f..8e769c6af 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -76,9 +76,7 @@ CCDEFS := $(shell $(CC) -E -x c -c /dev/null -dM | cut -d" " -f2) ccdefs: @$(ECHO) $(CCDEFS) -ifeq ($(filter __ICC,$(CCDEFS)),__ICC) -CCTYPE := icc -else +ifeq ($(filter __GNUC__,$(CCDEFS)),__GNUC__) CCTYPE := gcc endif cctype: @@ -466,32 +464,6 @@ CFLAGS += -fcommon CFLAGS += -Wall -W -Wformat-nonliteral HOST_CFLAGS += -Wall -W -Wformat-nonliteral endif -ifeq ($(CCTYPE),icc) -CFLAGS += -fno-builtin -CFLAGS += -no-ip -CFLAGS += -no-gcc -CFLAGS += -diag-disable 111 # Unreachable code -CFLAGS += -diag-disable 128 # Unreachable loop -CFLAGS += -diag-disable 170 # Array boundary checks -CFLAGS += -diag-disable 177 # Unused functions -CFLAGS += -diag-disable 181 # printf() format checks -CFLAGS += -diag-disable 188 # enum strictness -CFLAGS += -diag-disable 193 # Undefined preprocessor identifiers -CFLAGS += -diag-disable 280 # switch ( constant ) -CFLAGS += -diag-disable 310 # K&R parameter lists -CFLAGS += -diag-disable 424 # Extra semicolon -CFLAGS += -diag-disable 589 # Declarations mid-code -CFLAGS += -diag-disable 593 # Unused variables -CFLAGS += -diag-disable 810 # Casting ints to smaller ints -CFLAGS += -diag-disable 981 # Sequence point violations -CFLAGS += -diag-disable 1292 # Ignored attributes -CFLAGS += -diag-disable 1338 # void pointer arithmetic -CFLAGS += -diag-disable 1361 # Variable-length arrays -CFLAGS += -diag-disable 1418 # Missing prototypes -CFLAGS += -diag-disable 1419 # Missing prototypes -CFLAGS += -diag-disable 1599 # Hidden variables -CFLAGS += -Wall -Wmissing-declarations -endif CFLAGS += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS) ASFLAGS += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS) LDFLAGS += $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS) @@ -555,16 +527,6 @@ OBJ_CFLAGS = $(CFLAGS_$(OBJECT)) -DOBJECT=$(subst -,_,$(OBJECT)) $(BIN)/%.flags : @$(ECHO) $(OBJ_CFLAGS) -# ICC requires postprocessing objects to fix up table alignments -# -ifeq ($(CCTYPE),icc) -POST_O = && $(ICCFIX) $@ -POST_O_DEPS := $(ICCFIX) -else -POST_O := -POST_O_DEPS := -endif - # Debug level calculations # DBGLVL_MAX = -DDBGLVL_MAX=$(firstword $(subst ., ,$(1))) @@ -574,9 +536,9 @@ DBGLVL = $(call DBGLVL_MAX,$(1)) $(call DBGLVL_DFLT,$(1)) # Rules for specific object types. # COMPILE_c = $(CC) $(CFLAGS) $(CFLAGS_c) $(OBJ_CFLAGS) -RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ $(POST_O) +RULE_c = $(Q)$(COMPILE_c) -c $< -o $@ RULE_c_to_ids.o = $(Q)$(ECHO_E) '$(OBJ_IDS_ASM_NL)' | $(ASSEMBLE_S) -o $@ -RULE_c_to_dbg%.o= $(Q)$(COMPILE_c) $(call DBGLVL,$*) -c $< -o $@ $(POST_O) +RULE_c_to_dbg%.o= $(Q)$(COMPILE_c) $(call DBGLVL,$*) -c $< -o $@ RULE_c_to_c = $(Q)$(COMPILE_c) -E -c $< > $@ RULE_c_to_s = $(Q)$(COMPILE_c) -S -g0 -c $< -o $@ @@ -919,7 +881,7 @@ endef # $(3) is the source base name (e.g. "rtl8139") # define rules_template_parts -$$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS) +$$(BIN)/$(3).o : $(1) $$(MAKEDEPS) $$($(3)_DEPS) $$(QM)$(ECHO) " [BUILD] $$@" $$(RULE_$(2)) BOBJS += $$(BIN)/$(3).o @@ -934,7 +896,7 @@ endef # $(4) is the destination type (e.g. "dbg%.o") # define rules_template_target -$$(BIN)/$(3).$(4) : $(1) $$(MAKEDEPS) $$(POST_O_DEPS) $$($(3)_DEPS) +$$(BIN)/$(3).$(4) : $(1) $$(MAKEDEPS) $$($(3)_DEPS) $$(QM)$(ECHO) " [BUILD] $$@" $$(RULE_$(2)_to_$(4)) $(TGT)_OBJS += $$(BIN)/$(3).$(4) @@ -1473,15 +1435,6 @@ $(EFIFATBIN) : util/efifatbin.c $(MAKEDEPS) $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< CLEANUP += $(EFIFATBIN) -############################################################################### -# -# The ICC fixup utility -# -$(ICCFIX) : util/iccfix.c $(MAKEDEPS) - $(QM)$(ECHO) " [HOSTCC] $@" - $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< -CLEANUP += $(ICCFIX) - ############################################################################### # # The error usage information utility diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index c8c069c12..a83fa0f27 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -29,11 +29,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* EFI headers redefine ARRAY_SIZE */ #undef ARRAY_SIZE -/* EFI headers expect ICC to define __GNUC__ */ -#if defined ( __ICC ) && ! defined ( __GNUC__ ) -#define __GNUC__ 1 -#endif - /* EFI headers think your compiler uses the MS ABI by default on X64 */ #if __x86_64__ #define EFIAPI __attribute__((ms_abi)) diff --git a/src/include/ipxe/tables.h b/src/include/ipxe/tables.h index 60f8efdea..28a87da96 100644 --- a/src/include/ipxe/tables.h +++ b/src/include/ipxe/tables.h @@ -444,75 +444,4 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); pointer >= table_start ( table ) ; \ pointer-- ) -/****************************************************************************** - * - * Intel's C compiler chokes on several of the constructs used in this - * file. The workarounds are ugly, so we use them only for an icc - * build. - * - */ -#define ICC_ALIGN_HACK_FACTOR 128 -#ifdef __ICC - -/* - * icc miscompiles zero-length arrays by inserting padding to a length - * of two array elements. We therefore have to generate the - * __table_entries() symbols by hand in asm. - * - */ -#undef __table_entries -#define __table_entries( table, idx ) ( { \ - extern __table_type ( table ) \ - __table_temp_sym ( idx, __LINE__ ) [] \ - __table_entry ( table, idx ) \ - asm ( __table_entries_sym ( table, idx ) ); \ - __asm__ ( ".ifndef %c0\n\t" \ - ".section " __table_section ( table, idx ) "\n\t" \ - ".align %c1\n\t" \ - "\n%c0:\n\t" \ - ".previous\n\t" \ - ".endif\n\t" \ - : : "i" ( __table_temp_sym ( idx, __LINE__ ) ), \ - "i" ( __table_alignment ( table ) ) ); \ - __table_temp_sym ( idx, __LINE__ ); } ) -#define __table_entries_sym( table, idx ) \ - "__tbl_" __table_name ( table ) "_" #idx -#define __table_temp_sym( a, b ) \ - ___table_temp_sym( __table_, a, _, b ) -#define ___table_temp_sym( a, b, c, d ) a ## b ## c ## d - -/* - * icc ignores __attribute__ (( aligned (x) )) when it is used to - * decrease the compiler's default choice of alignment (which may be - * higher than the alignment actually required by the structure). We - * work around this by forcing the alignment to a large multiple of - * the required value (so that we are never attempting to decrease the - * default alignment) and then postprocessing the object file to - * reduce the alignment back down to the "real" value. - * - */ -#undef __table_alignment -#define __table_alignment( table ) \ - ( ICC_ALIGN_HACK_FACTOR * __alignof__ ( __table_type ( table ) ) ) - -/* - * Because of the alignment hack, we must ensure that the compiler - * never tries to place multiple objects within the same section, - * otherwise the assembler will insert padding to the (incorrect) - * alignment boundary. Do this by appending the line number to table - * section names. - * - * Note that we don't need to worry about padding between array - * elements, since the alignment is declared on the variable (i.e. the - * whole array) rather than on the type (i.e. on all individual array - * elements). - */ -#undef __table_section -#define __table_section( table, idx ) \ - ".tbl." __table_name ( table ) "." __table_str ( idx ) \ - "." __table_xstr ( __LINE__ ) -#define __table_xstr( x ) __table_str ( x ) - -#endif /* __ICC */ - #endif /* _IPXE_TABLES_H */ diff --git a/src/util/.gitignore b/src/util/.gitignore index 33bedefd0..b4cb13601 100644 --- a/src/util/.gitignore +++ b/src/util/.gitignore @@ -6,5 +6,4 @@ elf2efi32 elf2efi64 efirom efifatbin -iccfix einfo diff --git a/src/util/iccfix.c b/src/util/iccfix.c deleted file mode 100644 index 528bf4b26..000000000 --- a/src/util/iccfix.c +++ /dev/null @@ -1,157 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG 0 - -#define eprintf(...) fprintf ( stderr, __VA_ARGS__ ) - -#define dprintf(...) do { \ - if ( DEBUG ) \ - fprintf ( stderr, __VA_ARGS__ ); \ - } while ( 0 ) - -#ifdef SELF_INCLUDED - -/** - * Fix up ICC alignments - * - * @v elf ELF header - * @ret rc Return status code - * - * See comments in tables.h for an explanation of why this monstrosity - * is necessary. - */ -static int ICCFIX ( void *elf ) { - ELF_EHDR *ehdr = elf; - ELF_SHDR *shdr = ( elf + ehdr->e_shoff ); - size_t shentsize = ehdr->e_shentsize; - unsigned int shnum = ehdr->e_shnum; - ELF_SHDR *strtab = ( ( ( void * ) shdr ) + - ( ehdr->e_shstrndx * shentsize ) ); - char *strings = ( elf + strtab->sh_offset ); - - for ( ; shnum-- ; shdr = ( ( ( void * ) shdr ) + shentsize ) ) { - char *name = ( strings + shdr->sh_name ); - unsigned long align = shdr->sh_addralign; - unsigned long new_align; - - if ( ( strncmp ( name, ".tbl.", 5 ) == 0 ) && - ( align >= ICC_ALIGN_HACK_FACTOR ) ) { - new_align = ( align / ICC_ALIGN_HACK_FACTOR ); - shdr->sh_addralign = new_align; - dprintf ( "Section \"%s\": alignment %ld->%ld\n", - name, align, new_align ); - } - } - return 0; -} - -#else /* SELF_INCLUDED */ - -#define SELF_INCLUDED - -/* Include iccfix32() function */ -#define ELF_EHDR Elf32_Ehdr -#define ELF_SHDR Elf32_Shdr -#define ICCFIX iccfix32 -#include "iccfix.c" -#undef ELF_EHDR -#undef ELF_SHDR -#undef ICCFIX - -/* Include iccfix64() function */ -#define ELF_EHDR Elf64_Ehdr -#define ELF_SHDR Elf64_Shdr -#define ICCFIX iccfix64 -#include "iccfix.c" -#undef ELF_EHDR -#undef ELF_SHDR -#undef ICCFIX - -static int iccfix ( const char *filename ) { - int fd; - struct stat stat; - void *elf; - unsigned char *eident; - int rc; - - /* Open and mmap file */ - fd = open ( filename, O_RDWR ); - if ( fd < 0 ) { - eprintf ( "Could not open %s: %s\n", - filename, strerror ( errno ) ); - rc = -1; - goto err_open; - } - if ( fstat ( fd, &stat ) < 0 ) { - eprintf ( "Could not determine size of %s: %s\n", - filename, strerror ( errno ) ); - rc = -1; - goto err_fstat; - } - elf = mmap ( NULL, stat.st_size, ( PROT_READ | PROT_WRITE ), - MAP_SHARED, fd, 0 ); - if ( elf == MAP_FAILED ) { - eprintf ( "Could not map %s: %s\n", - filename, strerror ( errno ) ); - rc = -1; - goto err_mmap; - } - - /* Perform fixups */ - eident = elf; - switch ( eident[EI_CLASS] ) { - case ELFCLASS32: - rc = iccfix32 ( elf ); - break; - case ELFCLASS64: - rc = iccfix64 ( elf ); - break; - default: - eprintf ( "Unknown ELF class %d in %s\n", - eident[EI_CLASS], filename ); - rc = -1; - break; - } - - munmap ( elf, stat.st_size ); - err_mmap: - err_fstat: - close ( fd ); - err_open: - return rc; -} - -int main ( int argc, char **argv ) { - int i; - int rc; - - /* Parse command line */ - if ( argc < 2 ) { - eprintf ( "Syntax: %s ...\n", argv[0] ); - exit ( 1 ); - } - - /* Process each object in turn */ - for ( i = 1 ; i < argc ; i++ ) { - if ( ( rc = iccfix ( argv[i] ) ) != 0 ) { - eprintf ( "Could not fix up %s\n", argv[i] ); - exit ( 1 ); - } - } - - return 0; -} - -#endif /* SELF_INCLUDED */ -- cgit v1.2.3-55-g7522 From 057674bb1f766db8b4c6593dc238ea68e4f38028 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 17 Feb 2021 15:59:52 +0000 Subject: [pxe] Split out platform-independent portions of cachedhcp.c Split out the portions of cachedhcp.c that can be shared between BIOS and UEFI (both of which can provide a buffer containing a previously obtained DHCP packet, and neither of which provide a means to determine the length of this DHCP packet). Signed-off-by: Michael Brown --- src/arch/x86/core/cachedhcp.c | 179 ------------------------- src/arch/x86/interface/pcbios/bios_cachedhcp.c | 76 +++++++++++ src/core/cachedhcp.c | 158 ++++++++++++++++++++++ src/include/ipxe/cachedhcp.h | 17 +++ src/include/ipxe/errfile.h | 1 + 5 files changed, 252 insertions(+), 179 deletions(-) delete mode 100644 src/arch/x86/core/cachedhcp.c create mode 100644 src/arch/x86/interface/pcbios/bios_cachedhcp.c create mode 100644 src/core/cachedhcp.c create mode 100644 src/include/ipxe/cachedhcp.h (limited to 'src/include/ipxe') diff --git a/src/arch/x86/core/cachedhcp.c b/src/arch/x86/core/cachedhcp.c deleted file mode 100644 index dffafe3c9..000000000 --- a/src/arch/x86/core/cachedhcp.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (C) 2013 Michael Brown . - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * You can also choose to distribute this program under the terms of - * the Unmodified Binary Distribution Licence (as given in the file - * COPYING.UBDL), provided that you have satisfied its requirements. - */ - -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include -#include -#include -#include -#include -#include -#include - -/** @file - * - * Cached DHCP packet - * - */ - -/** Cached DHCPACK physical address - * - * This can be set by the prefix. - */ -uint32_t __bss16 ( cached_dhcpack_phys ); -#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys ) - -/** Colour for debug messages */ -#define colour &cached_dhcpack_phys - -/** Cached DHCPACK */ -static struct dhcp_packet *cached_dhcpack; - -/** - * Cached DHCPACK startup function - * - */ -static void cachedhcp_init ( void ) { - struct dhcp_packet *dhcppkt; - struct dhcp_packet *tmp; - struct dhcphdr *dhcphdr; - size_t max_len; - size_t len; - - /* Do nothing if no cached DHCPACK is present */ - if ( ! cached_dhcpack_phys ) { - DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" ); - return; - } - - /* No reliable way to determine length before parsing packet; - * start by assuming maximum length permitted by PXE. - */ - max_len = sizeof ( BOOTPLAYER_t ); - - /* Allocate and populate DHCP packet */ - dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len ); - if ( ! dhcppkt ) { - DBGC ( colour, "CACHEDHCP could not allocate copy\n" ); - return; - } - dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); - copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0, - max_len ); - dhcppkt_init ( dhcppkt, dhcphdr, max_len ); - - /* Shrink packet to required length. If reallocation fails, - * just continue to use the original packet and waste the - * unused space. - */ - len = dhcppkt_len ( dhcppkt ); - assert ( len <= max_len ); - tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) ); - if ( tmp ) - dhcppkt = tmp; - - /* Reinitialise packet at new address */ - dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); - dhcppkt_init ( dhcppkt, dhcphdr, len ); - - /* Store as cached DHCPACK, and mark original copy as consumed */ - DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n", - cached_dhcpack_phys, len ); - cached_dhcpack = dhcppkt; - cached_dhcpack_phys = 0; -} - -/** - * Cached DHCPACK startup function - * - */ -static void cachedhcp_startup ( void ) { - - /* If cached DHCP packet was not claimed by any network device - * during startup, then free it. - */ - if ( cached_dhcpack ) { - DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" ); - dhcppkt_put ( cached_dhcpack ); - cached_dhcpack = NULL; - } -} - -/** Cached DHCPACK initialisation function */ -struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = { - .initialise = cachedhcp_init, -}; - -/** Cached DHCPACK startup function */ -struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = { - .name = "cachedhcp", - .startup = cachedhcp_startup, -}; - -/** - * Apply cached DHCPACK to network device, if applicable - * - * @v netdev Network device - * @ret rc Return status code - */ -static int cachedhcp_probe ( struct net_device *netdev ) { - struct ll_protocol *ll_protocol = netdev->ll_protocol; - int rc; - - /* Do nothing unless we have a cached DHCPACK */ - if ( ! cached_dhcpack ) - return 0; - - /* Do nothing unless cached DHCPACK's MAC address matches this - * network device. - */ - if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr, - ll_protocol->ll_addr_len ) != 0 ) { - DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n", - netdev->name ); - return 0; - } - DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name ); - - /* Register as DHCP settings for this network device */ - if ( ( rc = register_settings ( &cached_dhcpack->settings, - netdev_settings ( netdev ), - DHCP_SETTINGS_NAME ) ) != 0 ) { - DBGC ( colour, "CACHEDHCP could not register settings: %s\n", - strerror ( rc ) ); - return rc; - } - - /* Claim cached DHCPACK */ - dhcppkt_put ( cached_dhcpack ); - cached_dhcpack = NULL; - - return 0; -} - -/** Cached DHCP packet network device driver */ -struct net_driver cachedhcp_driver __net_driver = { - .name = "cachedhcp", - .probe = cachedhcp_probe, -}; diff --git a/src/arch/x86/interface/pcbios/bios_cachedhcp.c b/src/arch/x86/interface/pcbios/bios_cachedhcp.c new file mode 100644 index 000000000..3d38699f7 --- /dev/null +++ b/src/arch/x86/interface/pcbios/bios_cachedhcp.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include + +/** @file + * + * Cached DHCP packet + * + */ + +/** Cached DHCPACK physical address + * + * This can be set by the prefix. + */ +uint32_t __bss16 ( cached_dhcpack_phys ); +#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys ) + +/** Colour for debug messages */ +#define colour &cached_dhcpack_phys + +/** + * Cached DHCPACK initialisation function + * + */ +static void cachedhcp_init ( void ) { + int rc; + + /* Do nothing if no cached DHCPACK is present */ + if ( ! cached_dhcpack_phys ) { + DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" ); + return; + } + + /* Record cached DHCPACK */ + if ( ( rc = cachedhcp_record ( phys_to_user ( cached_dhcpack_phys ), + sizeof ( BOOTPLAYER_t ) ) ) != 0 ) { + DBGC ( colour, "CACHEDHCP could not record DHCPACK: %s\n", + strerror ( rc ) ); + return; + } + + /* Mark as consumed */ + cached_dhcpack_phys = 0; +} + +/** Cached DHCPACK initialisation function */ +struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = cachedhcp_init, +}; diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c new file mode 100644 index 000000000..0e7da4bf2 --- /dev/null +++ b/src/core/cachedhcp.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2013 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Cached DHCP packet + * + */ + +/** Cached DHCPACK */ +static struct dhcp_packet *cached_dhcpack; + +/** Colour for debug messages */ +#define colour &cached_dhcpack + +/** + * Record cached DHCPACK + * + * @v data DHCPACK packet buffer + * @v max_len Maximum possible length + * @ret rc Return status code + */ +int cachedhcp_record ( userptr_t data, size_t max_len ) { + struct dhcp_packet *dhcppkt; + struct dhcp_packet *tmp; + struct dhcphdr *dhcphdr; + size_t len; + + /* Allocate and populate DHCP packet */ + dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len ); + if ( ! dhcppkt ) { + DBGC ( colour, "CACHEDHCP could not allocate copy\n" ); + return -ENOMEM; + } + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + copy_from_user ( dhcphdr, data, 0, max_len ); + dhcppkt_init ( dhcppkt, dhcphdr, max_len ); + + /* Shrink packet to required length. If reallocation fails, + * just continue to use the original packet and waste the + * unused space. + */ + len = dhcppkt_len ( dhcppkt ); + assert ( len <= max_len ); + tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) ); + if ( tmp ) + dhcppkt = tmp; + + /* Reinitialise packet at new address */ + dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); + dhcppkt_init ( dhcppkt, dhcphdr, len ); + + /* Store as cached DHCPACK, and mark original copy as consumed */ + DBGC ( colour, "CACHEDHCP found cached DHCPACK at %#08lx+%#zx/%#zx\n", + user_to_phys ( data, 0 ), len, max_len ); + cached_dhcpack = dhcppkt; + + return 0; +} + +/** + * Cached DHCPACK startup function + * + */ +static void cachedhcp_startup ( void ) { + + /* If cached DHCP packet was not claimed by any network device + * during startup, then free it. + */ + if ( cached_dhcpack ) { + DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" ); + dhcppkt_put ( cached_dhcpack ); + cached_dhcpack = NULL; + } +} + +/** Cached DHCPACK startup function */ +struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = { + .name = "cachedhcp", + .startup = cachedhcp_startup, +}; + +/** + * Apply cached DHCPACK to network device, if applicable + * + * @v netdev Network device + * @ret rc Return status code + */ +static int cachedhcp_probe ( struct net_device *netdev ) { + struct ll_protocol *ll_protocol = netdev->ll_protocol; + int rc; + + /* Do nothing unless we have a cached DHCPACK */ + if ( ! cached_dhcpack ) + return 0; + + /* Do nothing unless cached DHCPACK's MAC address matches this + * network device. + */ + if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr, + ll_protocol->ll_addr_len ) != 0 ) { + DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n", + netdev->name ); + return 0; + } + DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name ); + + /* Register as DHCP settings for this network device */ + if ( ( rc = register_settings ( &cached_dhcpack->settings, + netdev_settings ( netdev ), + DHCP_SETTINGS_NAME ) ) != 0 ) { + DBGC ( colour, "CACHEDHCP could not register settings: %s\n", + strerror ( rc ) ); + return rc; + } + + /* Claim cached DHCPACK */ + dhcppkt_put ( cached_dhcpack ); + cached_dhcpack = NULL; + + return 0; +} + +/** Cached DHCP packet network device driver */ +struct net_driver cachedhcp_driver __net_driver = { + .name = "cachedhcp", + .probe = cachedhcp_probe, +}; diff --git a/src/include/ipxe/cachedhcp.h b/src/include/ipxe/cachedhcp.h new file mode 100644 index 000000000..7765c6455 --- /dev/null +++ b/src/include/ipxe/cachedhcp.h @@ -0,0 +1,17 @@ +#ifndef _IPXE_CACHEDHCP_H +#define _IPXE_CACHEDHCP_H + +/** @file + * + * Cached DHCP packet + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +extern int cachedhcp_record ( userptr_t data, size_t max_len ); + +#endif /* _IPXE_CACHEDHCP_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index f14cb8619..4c1c334d8 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -76,6 +76,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_dummy_sanboot ( ERRFILE_CORE | 0x00240000 ) #define ERRFILE_fdt ( ERRFILE_CORE | 0x00250000 ) #define ERRFILE_dma ( ERRFILE_CORE | 0x00260000 ) +#define ERRFILE_cachedhcp ( ERRFILE_CORE | 0x00270000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) -- cgit v1.2.3-55-g7522 From e39cd79a00b1b353f47836f1144d28268c541ed6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 17 Feb 2021 16:57:19 +0000 Subject: [efi] Split out autoexec script portions of efi_autoboot.c The "autoboot device" and "autoexec script" functionalities in efi_autoboot.c are unrelated except in that they both need to be invoked by efiprefix.c before device drivers are loaded. Split out the autoexec script portions to a separate file to avoid potential confusion. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_autoboot.h | 4 +- src/include/ipxe/efi/efi_autoexec.h | 16 +++ src/include/ipxe/errfile.h | 1 + src/interface/efi/efi_autoboot.c | 189 +-------------------------------- src/interface/efi/efi_autoexec.c | 206 ++++++++++++++++++++++++++++++++++++ src/interface/efi/efiprefix.c | 8 +- 6 files changed, 234 insertions(+), 190 deletions(-) create mode 100644 src/include/ipxe/efi/efi_autoexec.h create mode 100644 src/interface/efi/efi_autoexec.c (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_autoboot.h b/src/include/ipxe/efi/efi_autoboot.h index 1d5ddc8c3..706885e28 100644 --- a/src/include/ipxe/efi/efi_autoboot.h +++ b/src/include/ipxe/efi/efi_autoboot.h @@ -9,6 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -extern void efi_set_autoboot ( void ); +#include + +extern int efi_set_autoboot_ll_addr ( EFI_HANDLE device ); #endif /* _IPXE_EFI_AUTOBOOT_H */ diff --git a/src/include/ipxe/efi/efi_autoexec.h b/src/include/ipxe/efi/efi_autoexec.h new file mode 100644 index 000000000..1f93b41cd --- /dev/null +++ b/src/include/ipxe/efi/efi_autoexec.h @@ -0,0 +1,16 @@ +#ifndef _IPXE_EFI_AUTOEXEC_H +#define _IPXE_EFI_AUTOEXEC_H + +/** @file + * + * EFI autoexec script + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +extern int efi_autoexec_load ( EFI_HANDLE device ); + +#endif /* _IPXE_EFI_AUTOEXEC_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 4c1c334d8..a0b7618cc 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -385,6 +385,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_ntlm ( ERRFILE_OTHER | 0x00510000 ) #define ERRFILE_efi_veto ( ERRFILE_OTHER | 0x00520000 ) #define ERRFILE_efi_autoboot ( ERRFILE_OTHER | 0x00530000 ) +#define ERRFILE_efi_autoexec ( ERRFILE_OTHER | 0x00540000 ) /** @} */ diff --git a/src/interface/efi/efi_autoboot.c b/src/interface/efi/efi_autoboot.c index f7993b068..08d67f761 100644 --- a/src/interface/efi/efi_autoboot.c +++ b/src/interface/efi/efi_autoboot.c @@ -25,40 +25,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include -#include #include #include #include -#include -#include #include /** @file * - * EFI automatic booting + * EFI autoboot device * */ -/** Autoexec script filename */ -#define AUTOEXEC_FILENAME L"autoexec.ipxe" - -/** Autoexec script image name */ -#define AUTOEXEC_NAME "autoexec.ipxe" - -/** Autoexec script (if any) */ -static void *efi_autoexec; - -/** Autoexec script length */ -static size_t efi_autoexec_len; - /** * Identify autoboot device * * @v device Device handle * @ret rc Return status code */ -static int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) { +int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; union { EFI_SIMPLE_NETWORK_PROTOCOL *snp; @@ -93,172 +77,3 @@ static int efi_set_autoboot_ll_addr ( EFI_HANDLE device ) { return 0; } - -/** - * Load autoexec script - * - * @v device Device handle - * @ret rc Return status code - */ -static int efi_load_autoexec ( EFI_HANDLE device ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - static wchar_t name[] = AUTOEXEC_FILENAME; - union { - void *interface; - EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs; - } u; - struct { - EFI_FILE_INFO info; - CHAR16 name[ sizeof ( name ) / sizeof ( name[0] ) ]; - } info; - EFI_FILE_PROTOCOL *root; - EFI_FILE_PROTOCOL *file; - UINTN size; - VOID *data; - EFI_STATUS efirc; - int rc; - - /* Sanity check */ - assert ( efi_autoexec == NULL ); - assert ( efi_autoexec_len == 0 ); - - /* Open simple file system protocol */ - if ( ( efirc = bs->OpenProtocol ( device, - &efi_simple_file_system_protocol_guid, - &u.interface, efi_image_handle, - device, - EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ - rc = -EEFI ( efirc ); - DBGC ( device, "EFI %s has no filesystem instance: %s\n", - efi_handle_name ( device ), strerror ( rc ) ); - goto err_filesystem; - } - - /* Open root directory */ - if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( device, "EFI %s could not open volume: %s\n", - efi_handle_name ( device ), strerror ( rc ) ); - goto err_volume; - } - - /* Open autoexec script */ - if ( ( efirc = root->Open ( root, &file, name, - EFI_FILE_MODE_READ, 0 ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( device, "EFI %s has no %ls: %s\n", - efi_handle_name ( device ), name, strerror ( rc ) ); - goto err_open; - } - - /* Get file information */ - size = sizeof ( info ); - if ( ( efirc = file->GetInfo ( file, &efi_file_info_id, &size, - &info ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( device, "EFI %s could not get %ls info: %s\n", - efi_handle_name ( device ), name, strerror ( rc ) ); - goto err_getinfo; - } - size = info.info.FileSize; - - /* Ignore zero-length files */ - if ( ! size ) { - rc = -EINVAL; - DBGC ( device, "EFI %s has zero-length %ls\n", - efi_handle_name ( device ), name ); - goto err_empty; - } - - /* Allocate temporary copy */ - if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, size, - &data ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( device, "EFI %s could not allocate %ls: %s\n", - efi_handle_name ( device ), name, strerror ( rc ) ); - goto err_alloc; - } - - /* Read file */ - if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( device, "EFI %s could not read %ls: %s\n", - efi_handle_name ( device ), name, strerror ( rc ) ); - goto err_read; - } - - /* Record autoexec script */ - efi_autoexec = data; - efi_autoexec_len = size; - data = NULL; - DBGC ( device, "EFI %s found %ls\n", - efi_handle_name ( device ), name ); - - /* Success */ - rc = 0; - - err_read: - if ( data ) - bs->FreePool ( data ); - err_alloc: - err_empty: - err_getinfo: - file->Close ( file ); - err_open: - root->Close ( root ); - err_volume: - bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid, - efi_image_handle, device ); - err_filesystem: - return rc; -} - -/** - * Configure automatic booting - * - */ -void efi_set_autoboot ( void ) { - EFI_HANDLE device = efi_loaded_image->DeviceHandle; - - /* Identify autoboot device, if any */ - efi_set_autoboot_ll_addr ( device ); - - /* Load autoexec script, if any */ - efi_load_autoexec ( device ); -} - -/** - * Register automatic boot image - * - */ -static void efi_autoboot_startup ( void ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_HANDLE device = efi_loaded_image->DeviceHandle; - const char *name = AUTOEXEC_NAME; - struct image *image; - - /* Do nothing if we have no autoexec script */ - if ( ! efi_autoexec ) - return; - - /* Create autoexec image */ - image = image_memory ( name, virt_to_user ( efi_autoexec ), - efi_autoexec_len ); - if ( ! image ) { - DBGC ( device, "EFI %s could not create %s\n", - efi_handle_name ( device ), name ); - return; - } - DBGC ( device, "EFI %s registered %s\n", - efi_handle_name ( device ), name ); - - /* Free temporary copy */ - bs->FreePool ( efi_autoexec ); - efi_autoexec = NULL; -} - -/** Automatic boot startup function */ -struct startup_fn efi_autoboot_startup_fn __startup_fn ( STARTUP_NORMAL ) = { - .name = "efi_autoboot", - .startup = efi_autoboot_startup, -}; diff --git a/src/interface/efi/efi_autoexec.c b/src/interface/efi/efi_autoexec.c new file mode 100644 index 000000000..88eb379bb --- /dev/null +++ b/src/interface/efi/efi_autoexec.c @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2021 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * EFI autoexec script + * + */ + +/** Autoexec script filename */ +#define AUTOEXEC_FILENAME L"autoexec.ipxe" + +/** Autoexec script image name */ +#define AUTOEXEC_NAME "autoexec.ipxe" + +/** Autoexec script (if any) */ +static void *efi_autoexec; + +/** Autoexec script length */ +static size_t efi_autoexec_len; + +/** + * Load autoexec script + * + * @v device Device handle + * @ret rc Return status code + */ +int efi_autoexec_load ( EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + static wchar_t name[] = AUTOEXEC_FILENAME; + union { + void *interface; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs; + } u; + struct { + EFI_FILE_INFO info; + CHAR16 name[ sizeof ( name ) / sizeof ( name[0] ) ]; + } info; + EFI_FILE_PROTOCOL *root; + EFI_FILE_PROTOCOL *file; + UINTN size; + VOID *data; + EFI_STATUS efirc; + int rc; + + /* Sanity check */ + assert ( efi_autoexec == NULL ); + assert ( efi_autoexec_len == 0 ); + + /* Open simple file system protocol */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_simple_file_system_protocol_guid, + &u.interface, efi_image_handle, + device, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s has no filesystem instance: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_filesystem; + } + + /* Open root directory */ + if ( ( efirc = u.fs->OpenVolume ( u.fs, &root ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not open volume: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_volume; + } + + /* Open autoexec script */ + if ( ( efirc = root->Open ( root, &file, name, + EFI_FILE_MODE_READ, 0 ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s has no %ls: %s\n", + efi_handle_name ( device ), name, strerror ( rc ) ); + goto err_open; + } + + /* Get file information */ + size = sizeof ( info ); + if ( ( efirc = file->GetInfo ( file, &efi_file_info_id, &size, + &info ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not get %ls info: %s\n", + efi_handle_name ( device ), name, strerror ( rc ) ); + goto err_getinfo; + } + size = info.info.FileSize; + + /* Ignore zero-length files */ + if ( ! size ) { + rc = -EINVAL; + DBGC ( device, "EFI %s has zero-length %ls\n", + efi_handle_name ( device ), name ); + goto err_empty; + } + + /* Allocate temporary copy */ + if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, size, + &data ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not allocate %ls: %s\n", + efi_handle_name ( device ), name, strerror ( rc ) ); + goto err_alloc; + } + + /* Read file */ + if ( ( efirc = file->Read ( file, &size, data ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s could not read %ls: %s\n", + efi_handle_name ( device ), name, strerror ( rc ) ); + goto err_read; + } + + /* Record autoexec script */ + efi_autoexec = data; + efi_autoexec_len = size; + data = NULL; + DBGC ( device, "EFI %s found %ls\n", + efi_handle_name ( device ), name ); + + /* Success */ + rc = 0; + + err_read: + if ( data ) + bs->FreePool ( data ); + err_alloc: + err_empty: + err_getinfo: + file->Close ( file ); + err_open: + root->Close ( root ); + err_volume: + bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid, + efi_image_handle, device ); + err_filesystem: + return rc; +} + +/** + * Register autoexec script + * + */ +static void efi_autoexec_startup ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE device = efi_loaded_image->DeviceHandle; + const char *name = AUTOEXEC_NAME; + struct image *image; + + /* Do nothing if we have no autoexec script */ + if ( ! efi_autoexec ) + return; + + /* Create autoexec image */ + image = image_memory ( name, virt_to_user ( efi_autoexec ), + efi_autoexec_len ); + if ( ! image ) { + DBGC ( device, "EFI %s could not create %s\n", + efi_handle_name ( device ), name ); + return; + } + DBGC ( device, "EFI %s registered %s\n", + efi_handle_name ( device ), name ); + + /* Free temporary copy */ + bs->FreePool ( efi_autoexec ); + efi_autoexec = NULL; +} + +/** Autoexec script startup function */ +struct startup_fn efi_autoexec_startup_fn __startup_fn ( STARTUP_NORMAL ) = { + .name = "efi_autoexec", + .startup = efi_autoexec_startup, +}; diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c index 3273b79d8..928f41c72 100644 --- a/src/interface/efi/efiprefix.c +++ b/src/interface/efi/efiprefix.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include @@ -48,8 +49,11 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle, if ( ( efirc = efi_init ( image_handle, systab ) ) != 0 ) goto err_init; - /* Record autoboot device (if any) */ - efi_set_autoboot(); + /* Identify autoboot device, if any */ + efi_set_autoboot_ll_addr ( efi_loaded_image->DeviceHandle ); + + /* Load autoexec script, if any */ + efi_autoexec_load ( efi_loaded_image->DeviceHandle ); /* Claim SNP devices for use by iPXE */ efi_snp_claim(); -- cgit v1.2.3-55-g7522 From cd3de55ea54d709bb89d97977257dbbd723424e9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 17 Feb 2021 18:11:43 +0000 Subject: [efi] Record cached DHCPACK from loaded image's device handle, if present Record the cached DHCPACK obtained from the EFI_PXE_BASE_CODE_PROTOCOL instance installed on the loaded image's device handle, if present. This allows a chainloaded UEFI iPXE to reuse the IPv4 address and DHCP options previously obtained by the built-in PXE stack, as is already done for a chainloaded BIOS iPXE. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_cachedhcp.h | 16 ++++++ src/include/ipxe/errfile.h | 1 + src/interface/efi/efi_cachedhcp.c | 94 ++++++++++++++++++++++++++++++++++++ src/interface/efi/efiprefix.c | 4 ++ 4 files changed, 115 insertions(+) create mode 100644 src/include/ipxe/efi/efi_cachedhcp.h create mode 100644 src/interface/efi/efi_cachedhcp.c (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/efi/efi_cachedhcp.h b/src/include/ipxe/efi/efi_cachedhcp.h new file mode 100644 index 000000000..cd60d4095 --- /dev/null +++ b/src/include/ipxe/efi/efi_cachedhcp.h @@ -0,0 +1,16 @@ +#ifndef _IPXE_EFI_CACHEDHCP_H +#define _IPXE_EFI_CACHEDHCP_H + +/** @file + * + * EFI cached DHCP packet + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +extern int efi_cachedhcp_record ( EFI_HANDLE device ); + +#endif /* _IPXE_EFI_CACHEDHCP_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index a0b7618cc..e3fc8fa09 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -386,6 +386,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_efi_veto ( ERRFILE_OTHER | 0x00520000 ) #define ERRFILE_efi_autoboot ( ERRFILE_OTHER | 0x00530000 ) #define ERRFILE_efi_autoexec ( ERRFILE_OTHER | 0x00540000 ) +#define ERRFILE_efi_cachedhcp ( ERRFILE_OTHER | 0x00550000 ) /** @} */ diff --git a/src/interface/efi/efi_cachedhcp.c b/src/interface/efi/efi_cachedhcp.c new file mode 100644 index 000000000..14b531d09 --- /dev/null +++ b/src/interface/efi/efi_cachedhcp.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2021 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include + +/** @file + * + * EFI cached DHCP packet + * + */ + +/** + * Record cached DHCP packet + * + * @v device Device handle + * @ret rc Return status code + */ +int efi_cachedhcp_record ( EFI_HANDLE device ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_PXE_BASE_CODE_PROTOCOL *pxe; + void *interface; + } pxe; + EFI_PXE_BASE_CODE_MODE *mode; + EFI_STATUS efirc; + int rc; + + /* Look for a PXE base code instance on the image's device handle */ + if ( ( efirc = bs->OpenProtocol ( device, + &efi_pxe_base_code_protocol_guid, + &pxe.interface, efi_image_handle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( device, "EFI %s has no PXE base code instance: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_open; + } + + /* Do not attempt to cache IPv6 packets */ + mode = pxe.pxe->Mode; + if ( mode->UsingIpv6 ) { + rc = -ENOTSUP; + DBGC ( device, "EFI %s has IPv6 PXE base code\n", + efi_handle_name ( device ) ); + goto err_ipv6; + } + + /* Record DHCPACK, if present */ + if ( mode->DhcpAckReceived && + ( ( rc = cachedhcp_record ( virt_to_user ( &mode->DhcpAck ), + sizeof ( mode->DhcpAck ) ) ) != 0 ) ) { + DBGC ( device, "EFI %s could not record DHCPACK: %s\n", + efi_handle_name ( device ), strerror ( rc ) ); + goto err_record; + } + + /* Success */ + rc = 0; + + err_record: + err_ipv6: + bs->CloseProtocol ( device, &efi_pxe_base_code_protocol_guid, + efi_image_handle, NULL ); + err_open: + return rc; +} diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c index 47fbe79aa..126c813d7 100644 --- a/src/interface/efi/efiprefix.c +++ b/src/interface/efi/efiprefix.c @@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include @@ -81,6 +82,9 @@ static void efi_init_application ( void ) { /* Identify autoboot device, if any */ efi_set_autoboot_ll_addr ( device ); + /* Store cached DHCP packet, if any */ + efi_cachedhcp_record ( device ); + /* Load autoexec script, if any */ efi_autoexec_load ( device ); } -- cgit v1.2.3-55-g7522 From f309d7a7b78eec10621bc71f9401d5b9257f9f39 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 28 Feb 2021 13:45:58 +0000 Subject: [linux] Use host glibc system call wrappers When building as a Linux userspace application, iPXE currently implements its own system calls to the host kernel rather than relying on the host's C library. The output binary is statically linked and has no external dependencies. This matches the general philosophy of other platforms on which iPXE runs, since there are no external libraries available on either BIOS or UEFI bare metal. However, it would be useful for the Linux userspace application to be able to link against host libraries such as libslirp. Modify the build process to perform a two-stage link: first picking out the requested objects in the usual way from blib.a but with relocations left present, then linking again with a helper object to create a standard hosted application. The helper object provides the standard main() entry point and wrappers for the Linux system calls required by the iPXE Linux drivers and interface code. Signed-off-by: Michael Brown --- .github/workflows/build.yml | 4 +- src/Makefile.linux | 39 +++ src/arch/i386/Makefile.linux | 10 +- src/arch/i386/core/linux/linux_syscall.S | 45 --- src/arch/i386/core/linux/linuxprefix.S | 28 -- src/arch/i386/include/bits/linux_api.h | 6 - src/arch/x86/Makefile.linux | 19 +- src/arch/x86/core/linux/linux_api.c | 149 ---------- src/arch/x86/core/linux/linux_strerror.c | 169 ----------- src/arch/x86/include/bits/linux_api_platform.h | 6 - src/arch/x86_64/Makefile.linux | 8 +- src/arch/x86_64/core/linux/linux_syscall.S | 33 --- src/arch/x86_64/core/linux/linuxprefix.S | 25 -- src/arch/x86_64/include/bits/linux_api.h | 6 - src/drivers/linux/af_packet.c | 2 +- src/drivers/linux/tap.c | 2 +- src/hci/linux_args.c | 20 +- src/include/hci/linux_args.h | 31 -- src/include/ipxe/linux_api.h | 86 ++++++ src/include/linux_api.h | 81 ------ src/interface/linux/linux_api.c | 373 +++++++++++++++++++++++++ src/interface/linux/linux_console.c | 2 +- src/interface/linux/linux_entropy.c | 2 +- src/interface/linux/linux_nap.c | 2 +- src/interface/linux/linux_pci.c | 2 +- src/interface/linux/linux_smbios.c | 2 +- src/interface/linux/linux_time.c | 2 +- src/interface/linux/linux_timer.c | 2 +- src/interface/linux/linux_umalloc.c | 2 +- src/interface/linux/linuxprefix.c | 38 +++ 30 files changed, 574 insertions(+), 622 deletions(-) create mode 100644 src/Makefile.linux delete mode 100644 src/arch/i386/core/linux/linux_syscall.S delete mode 100644 src/arch/i386/core/linux/linuxprefix.S delete mode 100644 src/arch/i386/include/bits/linux_api.h delete mode 100644 src/arch/x86/core/linux/linux_api.c delete mode 100644 src/arch/x86/core/linux/linux_strerror.c delete mode 100644 src/arch/x86/include/bits/linux_api_platform.h delete mode 100644 src/arch/x86_64/core/linux/linux_syscall.S delete mode 100644 src/arch/x86_64/core/linux/linuxprefix.S delete mode 100644 src/arch/x86_64/include/bits/linux_api.h delete mode 100644 src/include/hci/linux_args.h create mode 100644 src/include/ipxe/linux_api.h delete mode 100644 src/include/linux_api.h create mode 100644 src/interface/linux/linux_api.c create mode 100644 src/interface/linux/linuxprefix.c (limited to 'src/include/ipxe') diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d890dfb13..6dc577ef1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,9 +14,11 @@ jobs: fetch-depth: 0 - name: Install packages run: | + sudo dpkg --add-architecture i386 sudo apt update sudo apt install -y -o Acquire::Retries=50 \ - mtools syslinux isolinux libc6-dev-i386 valgrind + mtools syslinux isolinux \ + libc6-dev-i386 libc6-dbg:i386 valgrind - name: Build (BIOS) run: | make -j 4 -C src diff --git a/src/Makefile.linux b/src/Makefile.linux new file mode 100644 index 000000000..4a7837916 --- /dev/null +++ b/src/Makefile.linux @@ -0,0 +1,39 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Prefix all iPXE symbols to avoid collisions with platform libraries +# +SYMBOL_PREFIX = _ipxe__ + +# Enable valgrind +# +CFLAGS += -UNVALGRIND + +# Use a two-stage link +# +LDFLAGS += -r -d + +# Source directories +# +SRCDIRS += drivers/linux +SRCDIRS += interface/linux +NON_AUTO_SRCS += interface/linux/linux_api.c + +# Media types +# +NON_AUTO_MEDIA = linux + +# Compiler flags for building host API wrapper +# +LINUX_CFLAGS += -Os -idirafter include -DSYMBOL_PREFIX=$(SYMBOL_PREFIX) + +# Host API wrapper +# +$(BIN)/linux_api.o : interface/linux/linux_api.c $(MAKEDEPS) + $(QM)$(ECHO) " [BUILD] $@" + $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) -o $@ -c $< + +# Rule to generate final binary +# +$(BIN)/%.linux : $(BIN)/%.linux.tmp $(BIN)/linux_api.o + $(QM)$(ECHO) " [FINISH] $@" + $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) -o $@ $^ diff --git a/src/arch/i386/Makefile.linux b/src/arch/i386/Makefile.linux index 46328c83b..fe4229e94 100644 --- a/src/arch/i386/Makefile.linux +++ b/src/arch/i386/Makefile.linux @@ -1,6 +1,14 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Linker script +# LDSCRIPT = arch/i386/scripts/linux.lds -SRCDIRS += arch/i386/core/linux +# Compiler flags for building host API wrapper +# +LINUX_CFLAGS += -m32 +# Include generic Linux Makefile +# MAKEDEPS += arch/x86/Makefile.linux include arch/x86/Makefile.linux diff --git a/src/arch/i386/core/linux/linux_syscall.S b/src/arch/i386/core/linux/linux_syscall.S deleted file mode 100644 index 38a3e74bd..000000000 --- a/src/arch/i386/core/linux/linux_syscall.S +++ /dev/null @@ -1,45 +0,0 @@ - - .section ".data" - .globl linux_errno - -linux_errno: .int 0 - - .section ".text" - .code32 - .globl linux_syscall - .type linux_syscall, @function - -linux_syscall: - /* Save registers */ - pushl %ebx - pushl %esi - pushl %edi - pushl %ebp - - movl 20(%esp), %eax // C arg1 -> syscall number - movl 24(%esp), %ebx // C arg2 -> syscall arg1 - movl 28(%esp), %ecx // C arg3 -> syscall arg2 - movl 32(%esp), %edx // C arg4 -> syscall arg3 - movl 36(%esp), %esi // C arg5 -> syscall arg4 - movl 40(%esp), %edi // C arg6 -> syscall arg5 - movl 44(%esp), %ebp // C arg7 -> syscall arg6 - - int $0x80 - - /* Restore registers */ - popl %ebp - popl %edi - popl %esi - popl %ebx - - cmpl $-4095, %eax - jae 1f - ret - -1: - negl %eax - movl %eax, linux_errno - movl $-1, %eax - ret - - .size linux_syscall, . - linux_syscall diff --git a/src/arch/i386/core/linux/linuxprefix.S b/src/arch/i386/core/linux/linuxprefix.S deleted file mode 100644 index 398d3cb21..000000000 --- a/src/arch/i386/core/linux/linuxprefix.S +++ /dev/null @@ -1,28 +0,0 @@ -#include - - .section ".text" - .code32 - .globl _linux_start - .type _linux_start, @function - -_linux_start: - xorl %ebp, %ebp - - popl %esi // save argc - movl %esp, %edi // save argv - - andl $~15, %esp // 16-byte align the stack - - pushl %edi // argv -> C arg2 - pushl %esi // argc -> C arg1 - - call save_args - - /* Our main doesn't use any arguments */ - call main - - movl %eax, %ebx // rc -> syscall arg1 - movl $__NR_exit, %eax - int $0x80 - - .size _linux_start, . - _linux_start diff --git a/src/arch/i386/include/bits/linux_api.h b/src/arch/i386/include/bits/linux_api.h deleted file mode 100644 index dc6e7416e..000000000 --- a/src/arch/i386/include/bits/linux_api.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _I386_LINUX_API_H -#define _I386_LINUX_API_H - -#define __SYSCALL_mmap __NR_mmap2 - -#endif /* _I386_LINUX_API_H */ diff --git a/src/arch/x86/Makefile.linux b/src/arch/x86/Makefile.linux index 3740cc81a..b60065567 100644 --- a/src/arch/x86/Makefile.linux +++ b/src/arch/x86/Makefile.linux @@ -1,15 +1,10 @@ -MEDIA = linux - -# enable valgrind -CFLAGS += -UNVALGRIND - -SYMBOL_PREFIX = _ipxe__ +# -*- makefile -*- : Force emacs to use Makefile mode +# Include x86 Linux headers +# INCDIRS += arch/x86/include/linux -SRCDIRS += interface/linux -SRCDIRS += drivers/linux -SRCDIRS += arch/x86/core/linux -$(BIN)/%.linux : $(BIN)/%.linux.tmp - $(QM)$(ECHO) " [FINISH] $@" - $(Q)$(CP) $< $@ +# Include generic Linux Makefile +# +MAKEDEPS += Makefile.linux +include Makefile.linux diff --git a/src/arch/x86/core/linux/linux_api.c b/src/arch/x86/core/linux/linux_api.c deleted file mode 100644 index 17b1f3fd4..000000000 --- a/src/arch/x86/core/linux/linux_api.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/** @file - * - * Implementation of most of the linux API. - */ - -#include - -#include -#include -#include - -int linux_open ( const char *pathname, int flags ) { - return linux_syscall ( __NR_open, pathname, flags ); -} - -int linux_close ( int fd ) { - return linux_syscall ( __NR_close, fd ); -} - -off_t linux_lseek ( int fd, off_t offset, int whence ) { - return linux_syscall ( __NR_lseek, fd, offset, whence ); -} - -__kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count ) { - return linux_syscall ( __NR_read, fd, buf, count ); -} - -__kernel_ssize_t linux_write ( int fd, const void *buf, - __kernel_size_t count ) { - return linux_syscall ( __NR_write, fd, buf, count ); -} - -int linux_fcntl ( int fd, int cmd, ... ) { - long arg; - va_list list; - - va_start ( list, cmd ); - arg = va_arg ( list, long ); - va_end ( list ); - - return linux_syscall ( __NR_fcntl, fd, cmd, arg ); -} - -int linux_ioctl ( int fd, int request, ... ) { - void *arg; - va_list list; - - va_start ( list, request ); - arg = va_arg ( list, void * ); - va_end ( list ); - - return linux_syscall ( __NR_ioctl, fd, request, arg ); -} - -int linux_poll ( struct pollfd *fds, nfds_t nfds, int timeout ) { - return linux_syscall ( __NR_poll, fds, nfds, timeout ); -} - -int linux_nanosleep ( const struct timespec *req, struct timespec *rem ) { - return linux_syscall ( __NR_nanosleep, req, rem ); -} - -int linux_usleep ( useconds_t usec ) { - struct timespec ts = { - .tv_sec = ( ( long ) ( usec / 1000000 ) ), - .tv_nsec = ( ( long ) ( usec % 1000000 ) * 1000UL ), - }; - - return linux_nanosleep ( &ts, NULL ); -} - -int linux_gettimeofday ( struct timeval *tv, struct timezone *tz ) { - return linux_syscall ( __NR_gettimeofday, tv, tz ); -} - -void * linux_mmap ( void *addr, __kernel_size_t length, int prot, int flags, - int fd, __kernel_off_t offset ) { - return ( void * ) linux_syscall ( __SYSCALL_mmap, addr, length, prot, - flags, fd, offset ); -} - -void * linux_mremap ( void *old_address, __kernel_size_t old_size, - __kernel_size_t new_size, int flags ) { - return ( void * ) linux_syscall ( __NR_mremap, old_address, old_size, - new_size, flags ); -} - -int linux_munmap ( void *addr, __kernel_size_t length ) { - return linux_syscall ( __NR_munmap, addr, length ); -} - -int linux_socket ( int domain, int type_, int protocol ) { -#ifdef __NR_socket - return linux_syscall ( __NR_socket, domain, type_, protocol ); -#else -#ifndef SOCKOP_socket -# define SOCKOP_socket 1 -#endif - unsigned long sc_args[] = { domain, type_, protocol }; - return linux_syscall ( __NR_socketcall, SOCKOP_socket, sc_args ); -#endif -} - -int linux_bind ( int fd, const struct sockaddr *addr, socklen_t addrlen ) { -#ifdef __NR_bind - return linux_syscall ( __NR_bind, fd, addr, addrlen ); -#else -#ifndef SOCKOP_bind -# define SOCKOP_bind 2 -#endif - unsigned long sc_args[] = { fd, (unsigned long)addr, addrlen }; - return linux_syscall ( __NR_socketcall, SOCKOP_bind, sc_args ); -#endif -} - -ssize_t linux_sendto ( int fd, const void *buf, size_t len, int flags, - const struct sockaddr *daddr, socklen_t addrlen ) { -#ifdef __NR_sendto - return linux_syscall ( __NR_sendto, fd, buf, len, flags, - daddr, addrlen ); -#else -#ifndef SOCKOP_sendto -# define SOCKOP_sendto 11 -#endif - unsigned long sc_args[] = { fd, (unsigned long)buf, len, - flags, (unsigned long)daddr, addrlen }; - return linux_syscall ( __NR_socketcall, SOCKOP_sendto, sc_args ); -#endif -} diff --git a/src/arch/x86/core/linux/linux_strerror.c b/src/arch/x86/core/linux/linux_strerror.c deleted file mode 100644 index 24c9b7738..000000000 --- a/src/arch/x86/core/linux/linux_strerror.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -FILE_LICENCE(GPL2_OR_LATER); - -/** @file - * - * linux_strerror implementation - */ - -#include -#include - -/** Error names from glibc */ -static const char *errors[] = { - "Success", - "Operation not permitted", - "No such file or directory", - "No such process", - "Interrupted system call", - "Input/output error", - "No such device or address", - "Argument list too long", - "Exec format error", - "Bad file descriptor", - "No child processes", - "Resource temporarily unavailable", - "Cannot allocate memory", - "Permission denied", - "Bad address", - "Block device required", - "Device or resource busy", - "File exists", - "Invalid cross-device link", - "No such device", - "Not a directory", - "Is a directory", - "Invalid argument", - "Too many open files in system", - "Too many open files", - "Inappropriate ioctl for device", - "Text file busy", - "File too large", - "No space left on device", - "Illegal seek", - "Read-only file system", - "Too many links", - "Broken pipe", - "Numerical argument out of domain", - "Numerical result out of range", - "Resource deadlock avoided", - "File name too long", - "No locks available", - "Function not implemented", - "Directory not empty", - "Too many levels of symbolic links", - "", - "No message of desired type", - "Identifier removed", - "Channel number out of range", - "Level 2 not synchronized", - "Level 3 halted", - "Level 3 reset", - "Link number out of range", - "Protocol driver not attached", - "No CSI structure available", - "Level 2 halted", - "Invalid exchange", - "Invalid request descriptor", - "Exchange full", - "No anode", - "Invalid request code", - "Invalid slot", - "", - "Bad font file format", - "Device not a stream", - "No data available", - "Timer expired", - "Out of streams resources", - "Machine is not on the network", - "Package not installed", - "Object is remote", - "Link has been severed", - "Advertise error", - "Srmount error", - "Communication error on send", - "Protocol error", - "Multihop attempted", - "RFS specific error", - "Bad message", - "Value too large for defined data type", - "Name not unique on network", - "File descriptor in bad state", - "Remote address changed", - "Can not access a needed shared library", - "Accessing a corrupted shared library", - ".lib section in a.out corrupted", - "Attempting to link in too many shared libraries", - "Cannot exec a shared library directly", - "Invalid or incomplete multibyte or wide character", - "Interrupted system call should be restarted", - "Streams pipe error", - "Too many users", - "Socket operation on non-socket", - "Destination address required", - "Message too long", - "Protocol wrong type for socket", - "Protocol not available", - "Protocol not supported", - "Socket type not supported", - "Operation not supported", - "Protocol family not supported", - "Address family not supported by protocol", - "Address already in use", - "Cannot assign requested address", - "Network is down", - "Network is unreachable", - "Network dropped connection on reset", - "Software caused connection abort", - "Connection reset by peer", - "No buffer space available", - "Transport endpoint is already connected", - "Transport endpoint is not connected", - "Cannot send after transport endpoint shutdown", - "Too many references: cannot splice", - "Connection timed out", - "Connection refused", - "Host is down", - "No route to host", - "Operation already in progress", - "Operation now in progress", - "Stale NFS file handle", - "Structure needs cleaning", - "Not a XENIX named type file", - "No XENIX semaphores available", - "Is a named type file", - "Remote I/O error", - "Disk quota exceeded", - "No medium found", - "Wrong medium type", -}; - -const char *linux_strerror(int errnum) -{ - static char errbuf[64]; - static int errors_size = sizeof(errors) / sizeof(*errors); - - if (errnum >= errors_size || errnum < 0) { - snprintf(errbuf, sizeof(errbuf), "Error %#08x", errnum); - return errbuf; - } else { - return errors[errnum]; - } -} diff --git a/src/arch/x86/include/bits/linux_api_platform.h b/src/arch/x86/include/bits/linux_api_platform.h deleted file mode 100644 index 4a9ced5e2..000000000 --- a/src/arch/x86/include/bits/linux_api_platform.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _LINUX_API_PLATFORM_H -#define _LINUX_API_PLATFORM_H - -extern int linux_errno; - -#endif /* _LINUX_API_PLATFORM_H */ diff --git a/src/arch/x86_64/Makefile.linux b/src/arch/x86_64/Makefile.linux index 154f9d40d..c41ee49df 100644 --- a/src/arch/x86_64/Makefile.linux +++ b/src/arch/x86_64/Makefile.linux @@ -1,6 +1,10 @@ -LDSCRIPT = arch/x86_64/scripts/linux.lds +# -*- makefile -*- : Force emacs to use Makefile mode -SRCDIRS += arch/x86_64/core/linux +# Linker script +# +LDSCRIPT = arch/x86_64/scripts/linux.lds +# Include generic Linux Makefile +# MAKEDEPS += arch/x86/Makefile.linux include arch/x86/Makefile.linux diff --git a/src/arch/x86_64/core/linux/linux_syscall.S b/src/arch/x86_64/core/linux/linux_syscall.S deleted file mode 100644 index d2805f94c..000000000 --- a/src/arch/x86_64/core/linux/linux_syscall.S +++ /dev/null @@ -1,33 +0,0 @@ - - .section ".data" - .globl linux_errno - -linux_errno: .int 0 - - .section ".text" - .code64 - .globl linux_syscall - .type linux_syscall, @function - -linux_syscall: - movq %rdi, %rax // C arg1 -> syscall number - movq %rsi, %rdi // C arg2 -> syscall arg1 - movq %rdx, %rsi // C arg3 -> syscall arg2 - movq %rcx, %rdx // C arg4 -> syscall arg3 - movq %r8, %r10 // C arg5 -> syscall arg4 - movq %r9, %r8 // C arg6 -> syscall arg5 - movq 8(%rsp), %r9 // C arg7 -> syscall arg6 - - syscall - - cmpq $-4095, %rax - jae 1f - ret - -1: - negq %rax - movl %eax, linux_errno - movq $-1, %rax - ret - - .size linux_syscall, . - linux_syscall diff --git a/src/arch/x86_64/core/linux/linuxprefix.S b/src/arch/x86_64/core/linux/linuxprefix.S deleted file mode 100644 index ec8a9decd..000000000 --- a/src/arch/x86_64/core/linux/linuxprefix.S +++ /dev/null @@ -1,25 +0,0 @@ -#include - - .section ".text" - .code64 - .globl _linux_start - .type _linux_start, @function - -_linux_start: - xorq %rbp, %rbp - - popq %rdi // argc -> C arg1 - movq %rsp, %rsi // argv -> C arg2 - - andq $~15, %rsp // 16-byte align the stack - - call save_args - - /* Our main doesn't use any arguments */ - call main - - movq %rax, %rdi // rc -> syscall arg1 - movq $__NR_exit, %rax - syscall - - .size _linux_start, . - _linux_start diff --git a/src/arch/x86_64/include/bits/linux_api.h b/src/arch/x86_64/include/bits/linux_api.h deleted file mode 100644 index 589fb5808..000000000 --- a/src/arch/x86_64/include/bits/linux_api.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _X86_64_LINUX_API_H -#define _X86_64_LINUX_API_H - -#define __SYSCALL_mmap __NR_mmap - -#endif /* _X86_64_LINUX_API_H */ diff --git a/src/drivers/linux/af_packet.c b/src/drivers/linux/af_packet.c index 65aafc5b1..9fa6ef2a5 100644 --- a/src/drivers/linux/af_packet.c +++ b/src/drivers/linux/af_packet.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/drivers/linux/tap.c b/src/drivers/linux/tap.c index db3b7955b..ff1e08bdb 100644 --- a/src/drivers/linux/tap.c +++ b/src/drivers/linux/tap.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/hci/linux_args.c b/src/hci/linux_args.c index 5f903e3b6..12020bd0b 100644 --- a/src/hci/linux_args.c +++ b/src/hci/linux_args.c @@ -18,7 +18,6 @@ FILE_LICENCE(GPL2_OR_LATER); -#include #include #include #include @@ -27,21 +26,8 @@ FILE_LICENCE(GPL2_OR_LATER); #include #include -/** Saved argc */ -static int saved_argc = 0; -/** Saved argv */ -static char ** saved_argv; - -/** - * Save argc and argv for later access. - * - * To be called by linuxprefix - */ -__asmcall void save_args(int argc, char **argv) -{ - saved_argc = argc; - saved_argv = argv; -} +int linux_argc; +char **linux_argv; /** Supported command-line options */ static struct option options[] = { @@ -138,7 +124,7 @@ void linux_args_parse() while (1) { int option_index = 0; - c = getopt_long(saved_argc, saved_argv, "", options, &option_index); + c = getopt_long(linux_argc, linux_argv, "", options, &option_index); if (c == -1) break; diff --git a/src/include/hci/linux_args.h b/src/include/hci/linux_args.h deleted file mode 100644 index ae1ed0526..000000000 --- a/src/include/hci/linux_args.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _HCI_LINUX_ARGS_H -#define _HCI_LINUX_ARGS_H - -FILE_LICENCE(GPL2_OR_LATER); - -/** - * Save argc and argv for later access. - * - * To be called by linuxprefix - */ -extern __asmcall void save_args(int argc, char **argv); - -#endif /* _HCI_LINUX_ARGS_H */ diff --git a/src/include/ipxe/linux_api.h b/src/include/ipxe/linux_api.h new file mode 100644 index 000000000..ea247a613 --- /dev/null +++ b/src/include/ipxe/linux_api.h @@ -0,0 +1,86 @@ +#ifndef _IPXE_LINUX_API_H +#define _IPXE_LINUX_API_H + +/* + * Copyright (C) 2010 Piotr Jaroszyński . + * Copyright (C) 2021 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/** @file + * + * Linux host API + * + * This file is included from both the iPXE build environment and the + * host build environment. + * + */ + +#if __STDC_HOSTED__ +#define __asmcall +#define FILE_LICENCE(x) +#endif + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +#if ! __STDC_HOSTED__ +#define __KERNEL_STRICT_NAMES +#include +#include +#include +#include +#include +#include +#define MAP_FAILED ( ( void * ) -1 ) +#endif + +struct sockaddr; + +extern int linux_errno; +extern int linux_argc; +extern char **linux_argv; + +extern int __asmcall linux_open ( const char *pathname, int flags, ... ); +extern int __asmcall linux_close ( int fd ); +extern off_t __asmcall linux_lseek ( int fd, off_t offset, int whence ); +extern ssize_t __asmcall linux_read ( int fd, void *buf, size_t count ); +extern ssize_t __asmcall linux_write ( int fd, const void *buf, size_t count ); +extern int __asmcall linux_fcntl ( int fd, int cmd, ... ); +extern int __asmcall linux_ioctl ( int fd, unsigned long request, ... ); +extern int __asmcall linux_poll ( struct pollfd *fds, unsigned int nfds, + int timeout ); +extern int __asmcall linux_nanosleep ( const struct timespec *req, + struct timespec *rem ); +extern int __asmcall linux_usleep ( unsigned int usec ); +extern int __asmcall linux_gettimeofday ( struct timeval *tv, + struct timezone *tz ); +extern void * __asmcall linux_mmap ( void *addr, size_t length, int prot, + int flags, int fd, off_t offset ); +extern void * __asmcall linux_mremap ( void *old_address, size_t old_size, + size_t new_size, int flags, ... ); +extern int __asmcall linux_munmap ( void *addr, size_t length ); +extern int __asmcall linux_socket ( int domain, int type, int protocol ); +extern int __asmcall linux_bind ( int sockfd, const struct sockaddr *addr, + size_t addrlen ); +extern ssize_t __asmcall linux_sendto ( int sockfd, const void *buf, + size_t len, int flags, + const struct sockaddr *dest_addr, + size_t addrlen ); +extern const char * __asmcall linux_strerror ( int linux_errno ); + +#endif /* _IPXE_LINUX_API_H */ diff --git a/src/include/linux_api.h b/src/include/linux_api.h deleted file mode 100644 index fe9fa910f..000000000 --- a/src/include/linux_api.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2010 Piotr Jaroszyński - * - * 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 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef _LINUX_API_H -#define _LINUX_API_H - -/** * @file - * - * Linux API prototypes. - * Most of the functions map directly to linux syscalls and are the equivalent - * of POSIX functions with the linux_ prefix removed. - */ - -FILE_LICENCE(GPL2_OR_LATER); - -#include -#include - -#include - -#define __KERNEL_STRICT_NAMES -#include -#include -typedef __kernel_pid_t pid_t; -typedef __kernel_suseconds_t suseconds_t; -typedef __kernel_loff_t loff_t; -#include -#include -#include -#include -#include -typedef unsigned long nfds_t; -typedef uint32_t useconds_t; -typedef uint32_t socklen_t; -struct sockaddr; -#define MAP_FAILED ( ( void * ) -1 ) -#define SEEK_SET 0 - -extern long linux_syscall ( int number, ... ); - -extern int linux_open ( const char *pathname, int flags ); -extern int linux_close ( int fd ); -extern off_t linux_lseek ( int fd, off_t offset, int whence ); -extern __kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count ); -extern __kernel_ssize_t linux_write ( int fd, const void *buf, - __kernel_size_t count ); -extern int linux_fcntl ( int fd, int cmd, ... ); -extern int linux_ioctl ( int fd, int request, ... ); -extern int linux_poll ( struct pollfd *fds, nfds_t nfds, int timeout ); -extern int linux_nanosleep ( const struct timespec *req, struct timespec *rem ); -extern int linux_usleep ( useconds_t usec ); -extern int linux_gettimeofday ( struct timeval *tv, struct timezone *tz ); -extern void * linux_mmap ( void *addr, __kernel_size_t length, int prot, - int flags, int fd, off_t offset ); -extern void * linux_mremap ( void *old_address, __kernel_size_t old_size, - __kernel_size_t new_size, int flags ); -extern int linux_munmap ( void *addr, __kernel_size_t length ); -extern int linux_socket ( int domain, int type_, int protocol ); -extern int linux_bind ( int fd, const struct sockaddr *addr, - socklen_t addrlen ); -extern ssize_t linux_sendto ( int fd, const void *buf, size_t len, int flags, - const struct sockaddr *daddr, socklen_t addrlen ); - -extern const char * linux_strerror ( int errnum ); - -#endif /* _LINUX_API_H */ diff --git a/src/interface/linux/linux_api.c b/src/interface/linux/linux_api.c new file mode 100644 index 000000000..4ab3c6603 --- /dev/null +++ b/src/interface/linux/linux_api.c @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2010 Piotr Jaroszyński . + * Copyright (C) 2021 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Linux host API + * + */ + +/** Construct prefixed symbol name */ +#define _C1( x, y ) x ## y +#define _C2( x, y ) _C1 ( x, y ) + +/** Construct prefixed symbol name for iPXE symbols */ +#define IPXE_SYM( symbol ) _C2 ( SYMBOL_PREFIX, symbol ) + +/** Provide a prefixed symbol alias visible to iPXE code */ +#define PROVIDE_IPXE_SYM( symbol ) \ + extern typeof ( symbol ) IPXE_SYM ( symbol ) \ + __attribute__ (( alias ( #symbol) )) + +/** Most recent system call error */ +int linux_errno __attribute__ (( nocommon )); + +/****************************************************************************** + * + * Host entry point + * + ****************************************************************************** + */ + +extern int IPXE_SYM ( _linux_start ) ( int argc, char **argv ); + +/** + * Main entry point + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Exit status + */ +int main ( int argc, char **argv ) { + + return IPXE_SYM ( _linux_start ) ( argc, argv ); +} + +/****************************************************************************** + * + * System call wrappers + * + ****************************************************************************** + */ + +/** + * Wrap open() + * + */ +int __asmcall linux_open ( const char *pathname, int flags, ... ) { + va_list args; + mode_t mode; + int ret; + + va_start ( args, flags ); + mode = va_arg ( args, mode_t ); + va_end ( args ); + ret = open ( pathname, flags, mode ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap close() + * + */ +int __asmcall linux_close ( int fd ) { + int ret; + + ret = close ( fd ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap lseek() + * + */ +off_t __asmcall linux_lseek ( int fd, off_t offset, int whence ) { + off_t ret; + + ret = lseek ( fd, offset, whence ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap read() + * + */ +ssize_t __asmcall linux_read ( int fd, void *buf, size_t count ) { + ssize_t ret; + + ret = read ( fd, buf, count ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap write() + * + */ +ssize_t __asmcall linux_write ( int fd, const void *buf, size_t count ) { + ssize_t ret; + + ret = write ( fd, buf, count ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap fcntl() + * + */ +int __asmcall linux_fcntl ( int fd, int cmd, ... ) { + va_list args; + long arg; + int ret; + + va_start ( args, cmd ); + arg = va_arg ( args, long ); + va_end ( args ); + ret = fcntl ( fd, cmd, arg ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap ioctl() + * + */ +int __asmcall linux_ioctl ( int fd, unsigned long request, ... ) { + va_list args; + void *arg; + int ret; + + va_start ( args, request ); + arg = va_arg ( args, void * ); + va_end ( args ); + ret = ioctl ( fd, request, arg ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap poll() + * + */ +int __asmcall linux_poll ( struct pollfd *fds, unsigned int nfds, + int timeout ) { + int ret; + + ret = poll ( fds, nfds, timeout ); + if ( ret == -1 ) + linux_errno = errno; +} + +/** + * Wrap nanosleep() + * + */ +int __asmcall linux_nanosleep ( const struct timespec *req, + struct timespec *rem ) { + int ret; + + ret = nanosleep ( req, rem ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap usleep() + * + */ +int __asmcall linux_usleep ( unsigned int usec ) { + int ret; + + ret = usleep ( usec ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap gettimeofday() + * + */ +int __asmcall linux_gettimeofday ( struct timeval *tv, struct timezone *tz ) { + int ret; + + ret = gettimeofday ( tv, tz ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap mmap() + * +*/ +void * __asmcall linux_mmap ( void *addr, size_t length, int prot, int flags, + int fd, off_t offset ) { + void *ret; + + ret = mmap ( addr, length, prot, flags, fd, offset ); + if ( ret == MAP_FAILED ) + linux_errno = errno; + return ret; +} + +/** + * Wrap mremap() + * + */ +void * __asmcall linux_mremap ( void *old_address, size_t old_size, + size_t new_size, int flags, ... ) { + va_list args; + void *new_address; + void *ret; + + va_start ( args, flags ); + new_address = va_arg ( args, void * ); + va_end ( args ); + ret = mremap ( old_address, old_size, new_size, flags, new_address ); + if ( ret == MAP_FAILED ) + linux_errno = errno; + return ret; +} + +/** + * Wrap munmap() + * + */ +int __asmcall linux_munmap ( void *addr, size_t length ) { + int ret; + + ret = munmap ( addr, length ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap socket() + * + */ +int __asmcall linux_socket ( int domain, int type, int protocol ) { + int ret; + + ret = socket ( domain, type, protocol ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap bind() + * + */ +int __asmcall linux_bind ( int sockfd, const struct sockaddr *addr, + size_t addrlen ) { + int ret; + + ret = bind ( sockfd, addr, addrlen ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/** + * Wrap sendto() + * + */ +ssize_t __asmcall linux_sendto ( int sockfd, const void *buf, size_t len, + int flags, const struct sockaddr *dest_addr, + size_t addrlen ) { + ssize_t ret; + + ret = sendto ( sockfd, buf, len, flags, dest_addr, addrlen ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + +/****************************************************************************** + * + * C library wrappers + * + ****************************************************************************** + */ + +/** + * Wrap strerror() + * + */ +const char * __asmcall linux_strerror ( int linux_errno ) { + + return strerror ( linux_errno ); +} + +/****************************************************************************** + * + * Symbol aliases + * + ****************************************************************************** + */ + +PROVIDE_IPXE_SYM ( linux_errno ); +PROVIDE_IPXE_SYM ( linux_open ); +PROVIDE_IPXE_SYM ( linux_close ); +PROVIDE_IPXE_SYM ( linux_lseek ); +PROVIDE_IPXE_SYM ( linux_read ); +PROVIDE_IPXE_SYM ( linux_write ); +PROVIDE_IPXE_SYM ( linux_fcntl ); +PROVIDE_IPXE_SYM ( linux_ioctl ); +PROVIDE_IPXE_SYM ( linux_poll ); +PROVIDE_IPXE_SYM ( linux_nanosleep ); +PROVIDE_IPXE_SYM ( linux_usleep ); +PROVIDE_IPXE_SYM ( linux_gettimeofday ); +PROVIDE_IPXE_SYM ( linux_mmap ); +PROVIDE_IPXE_SYM ( linux_mremap ); +PROVIDE_IPXE_SYM ( linux_munmap ); +PROVIDE_IPXE_SYM ( linux_socket ); +PROVIDE_IPXE_SYM ( linux_bind ); +PROVIDE_IPXE_SYM ( linux_sendto ); +PROVIDE_IPXE_SYM ( linux_strerror ); diff --git a/src/interface/linux/linux_console.c b/src/interface/linux/linux_console.c index 5294fca79..d5415b61c 100644 --- a/src/interface/linux/linux_console.c +++ b/src/interface/linux/linux_console.c @@ -28,7 +28,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include #include -#include +#include #include #include diff --git a/src/interface/linux/linux_entropy.c b/src/interface/linux/linux_entropy.c index 0f8e45d36..257e993a0 100644 --- a/src/interface/linux/linux_entropy.c +++ b/src/interface/linux/linux_entropy.c @@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include +#include #include /** Entropy source filename */ diff --git a/src/interface/linux/linux_nap.c b/src/interface/linux/linux_nap.c index f1d3cd962..3e77bc7f1 100644 --- a/src/interface/linux/linux_nap.c +++ b/src/interface/linux/linux_nap.c @@ -21,7 +21,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include -#include +#include /** @file * diff --git a/src/interface/linux/linux_pci.c b/src/interface/linux/linux_pci.c index 0c140cb89..99c629c19 100644 --- a/src/interface/linux/linux_pci.c +++ b/src/interface/linux/linux_pci.c @@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include #include diff --git a/src/interface/linux/linux_smbios.c b/src/interface/linux/linux_smbios.c index 6e5174d23..494a60bd9 100644 --- a/src/interface/linux/linux_smbios.c +++ b/src/interface/linux/linux_smbios.c @@ -20,7 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -#include +#include #include #include diff --git a/src/interface/linux/linux_time.c b/src/interface/linux/linux_time.c index 9e99fe9cd..9d410f8e0 100644 --- a/src/interface/linux/linux_time.c +++ b/src/interface/linux/linux_time.c @@ -32,7 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include +#include #include /** diff --git a/src/interface/linux/linux_timer.c b/src/interface/linux/linux_timer.c index 9c5e96f2b..418fd046a 100644 --- a/src/interface/linux/linux_timer.c +++ b/src/interface/linux/linux_timer.c @@ -21,7 +21,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include #include -#include +#include /** @file * diff --git a/src/interface/linux/linux_umalloc.c b/src/interface/linux/linux_umalloc.c index aa0052c53..a7250fa5b 100644 --- a/src/interface/linux/linux_umalloc.c +++ b/src/interface/linux/linux_umalloc.c @@ -29,7 +29,7 @@ FILE_LICENCE(GPL2_OR_LATER); #include #include -#include +#include /** Special address returned for empty allocations */ #define NOWHERE ((void *)-1) diff --git a/src/interface/linux/linuxprefix.c b/src/interface/linux/linuxprefix.c new file mode 100644 index 000000000..f38236202 --- /dev/null +++ b/src/interface/linux/linuxprefix.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2021 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include + +/** + * Linux entry point + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +int __asmcall _linux_start ( int argc, char **argv ) { + + /* Store command-line arguments */ + linux_argc = argc; + linux_argv = argv; + + /* Run iPXE */ + return main(); +} -- cgit v1.2.3-55-g7522 From 9776f6ece1104cc32de3249844a8a7387112f32f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 1 Mar 2021 00:08:23 +0000 Subject: [acpi] Allow for platforms that provide ACPI tables individually The ACPI API currently expects platforms to provide access to a single contiguous ACPI table. Some platforms (e.g. Linux userspace) do not provide a convenient way to obtain the entire ACPI table, but do provide access to individual tables. All iPXE consumers of the ACPI API require access only to individual tables. Redefine the internal API to make acpi_find() an API method, with all existing implementations delegating to the current RSDT-based implementation. Signed-off-by: Michael Brown --- src/arch/x86/include/ipxe/rsdp.h | 13 +++++++++++++ src/arch/x86/interface/pcbios/rsdp.c | 1 + src/core/acpi.c | 4 ++-- src/core/null_acpi.c | 2 +- src/include/ipxe/acpi.h | 12 +++++++++++- src/include/ipxe/efi/efi_acpi.h | 13 +++++++++++++ src/include/ipxe/null_acpi.h | 6 ++++-- src/interface/efi/efi_acpi.c | 1 + 8 files changed, 46 insertions(+), 6 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/arch/x86/include/ipxe/rsdp.h b/src/arch/x86/include/ipxe/rsdp.h index 7e32c0011..14afcd774 100644 --- a/src/arch/x86/include/ipxe/rsdp.h +++ b/src/arch/x86/include/ipxe/rsdp.h @@ -15,4 +15,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ACPI_PREFIX_rsdp __rsdp_ #endif +/** + * Locate ACPI table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +static inline __attribute__ (( always_inline )) userptr_t +ACPI_INLINE ( rsdp, acpi_find ) ( uint32_t signature, unsigned int index ) { + + return acpi_find_via_rsdt ( signature, index ); +} + #endif /* _IPXE_RSDP_H */ diff --git a/src/arch/x86/interface/pcbios/rsdp.c b/src/arch/x86/interface/pcbios/rsdp.c index 8da0b5588..3c67b7525 100644 --- a/src/arch/x86/interface/pcbios/rsdp.c +++ b/src/arch/x86/interface/pcbios/rsdp.c @@ -123,3 +123,4 @@ static userptr_t rsdp_find_rsdt ( void ) { } PROVIDE_ACPI ( rsdp, acpi_find_rsdt, rsdp_find_rsdt ); +PROVIDE_ACPI_INLINE ( rsdp, acpi_find ); diff --git a/src/core/acpi.c b/src/core/acpi.c index 75511736d..52eb63a04 100644 --- a/src/core/acpi.c +++ b/src/core/acpi.c @@ -83,13 +83,13 @@ void acpi_fix_checksum ( struct acpi_header *acpi ) { } /** - * Locate ACPI table + * Locate ACPI table via RSDT * * @v signature Requested table signature * @v index Requested index of table with this signature * @ret table Table, or UNULL if not found */ -userptr_t acpi_find ( uint32_t signature, unsigned int index ) { +userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) { struct acpi_header acpi; struct acpi_rsdt *rsdtab; typeof ( rsdtab->entry[0] ) entry; diff --git a/src/core/null_acpi.c b/src/core/null_acpi.c index 90c784855..acca37872 100644 --- a/src/core/null_acpi.c +++ b/src/core/null_acpi.c @@ -1,3 +1,3 @@ #include -PROVIDE_ACPI_INLINE ( null, acpi_find_rsdt ); +PROVIDE_ACPI_INLINE ( null, acpi_find ); diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index f979ace45..6d19f05fa 100644 --- a/src/include/ipxe/acpi.h +++ b/src/include/ipxe/acpi.h @@ -355,6 +355,8 @@ struct acpi_model { #define PROVIDE_ACPI_INLINE( _subsys, _api_func ) \ PROVIDE_SINGLE_API_INLINE ( ACPI_PREFIX_ ## _subsys, _api_func ) +extern userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ); + /* Include all architecture-independent ACPI API headers */ #include #include @@ -369,13 +371,21 @@ struct acpi_model { */ userptr_t acpi_find_rsdt ( void ); +/** + * Locate ACPI table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +userptr_t acpi_find ( uint32_t signature, unsigned int index ); + extern struct acpi_descriptor * acpi_describe ( struct interface *interface ); #define acpi_describe_TYPE( object_type ) \ typeof ( struct acpi_descriptor * ( object_type ) ) extern void acpi_fix_checksum ( struct acpi_header *acpi ); -extern userptr_t acpi_find ( uint32_t signature, unsigned int index ); extern int acpi_sx ( uint32_t signature ); extern void acpi_add ( struct acpi_descriptor *desc ); extern void acpi_del ( struct acpi_descriptor *desc ); diff --git a/src/include/ipxe/efi/efi_acpi.h b/src/include/ipxe/efi/efi_acpi.h index 01456f137..a698863a6 100644 --- a/src/include/ipxe/efi/efi_acpi.h +++ b/src/include/ipxe/efi/efi_acpi.h @@ -15,4 +15,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ACPI_PREFIX_efi __efi_ #endif +/** + * Locate ACPI table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +static inline __attribute__ (( always_inline )) userptr_t +ACPI_INLINE ( efi, acpi_find ) ( uint32_t signature, unsigned int index ) { + + return acpi_find_via_rsdt ( signature, index ); +} + #endif /* _IPXE_EFI_ACPI_H */ diff --git a/src/include/ipxe/null_acpi.h b/src/include/ipxe/null_acpi.h index 1e469e33d..cedb02839 100644 --- a/src/include/ipxe/null_acpi.h +++ b/src/include/ipxe/null_acpi.h @@ -15,8 +15,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ACPI_PREFIX_null __null_ #endif -static inline __always_inline userptr_t -ACPI_INLINE ( null, acpi_find_rsdt ) ( void ) { +static inline __attribute__ (( always_inline )) userptr_t +ACPI_INLINE ( null, acpi_find ) ( uint32_t signature __unused, + unsigned int index __unused ) { + return UNULL; } diff --git a/src/interface/efi/efi_acpi.c b/src/interface/efi/efi_acpi.c index a347eaf3a..07a225632 100644 --- a/src/interface/efi/efi_acpi.c +++ b/src/interface/efi/efi_acpi.c @@ -54,3 +54,4 @@ static userptr_t efi_find_rsdt ( void ) { } PROVIDE_ACPI ( efi, acpi_find_rsdt, efi_find_rsdt ); +PROVIDE_ACPI_INLINE ( efi, acpi_find ); -- cgit v1.2.3-55-g7522 From c09b627973d9362caba39de09f7d2c6990eb9701 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 1 Mar 2021 01:38:54 +0000 Subject: [linux] Provide ACPI settings via /sys/firmware/acpi/tables Signed-off-by: Michael Brown --- src/config/defaults/linux.h | 1 + src/include/ipxe/acpi.h | 1 + src/include/ipxe/linux/linux_acpi.h | 18 ++++ src/interface/linux/linux_acpi.c | 173 ++++++++++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+) create mode 100644 src/include/ipxe/linux/linux_acpi.h create mode 100644 src/interface/linux/linux_acpi.c (limited to 'src/include/ipxe') diff --git a/src/config/defaults/linux.h b/src/config/defaults/linux.h index 98d2dafec..5c4106d30 100644 --- a/src/config/defaults/linux.h +++ b/src/config/defaults/linux.h @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define REBOOT_NULL #define PCIAPI_LINUX #define DMAAPI_FLAT +#define ACPI_LINUX #define DRIVERS_LINUX diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index 6d19f05fa..81ef7ff76 100644 --- a/src/include/ipxe/acpi.h +++ b/src/include/ipxe/acpi.h @@ -360,6 +360,7 @@ extern userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ); /* Include all architecture-independent ACPI API headers */ #include #include +#include /* Include all architecture-dependent ACPI API headers */ #include diff --git a/src/include/ipxe/linux/linux_acpi.h b/src/include/ipxe/linux/linux_acpi.h new file mode 100644 index 000000000..a2c33ce2c --- /dev/null +++ b/src/include/ipxe/linux/linux_acpi.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_LINUX_ACPI_H +#define _IPXE_LINUX_ACPI_H + +/** @file + * + * iPXE ACPI API for Linux + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#ifdef ACPI_LINUX +#define ACPI_PREFIX_linux +#else +#define ACPI_PREFIX_linux __linux_ +#endif + +#endif /* _IPXE_LINUX_ACPI_H */ diff --git a/src/interface/linux/linux_acpi.c b/src/interface/linux/linux_acpi.c new file mode 100644 index 000000000..0f369bdaa --- /dev/null +++ b/src/interface/linux/linux_acpi.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2021 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include + +/** ACPI sysfs directory */ +#define ACPI_SYSFS_PREFIX "/sys/firmware/acpi/tables/" + +/** A cached ACPI table */ +struct linux_acpi_table { + /** List of cached tables */ + struct list_head list; + /** Signature */ + uint32_t signature; + /** Index */ + unsigned int index; + /** Cached data */ + void *data; +}; + +/** List of cached ACPI tables */ +static LIST_HEAD ( linux_acpi_tables ); + +/** + * Locate ACPI table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +static userptr_t linux_acpi_find ( uint32_t signature, unsigned int index ) { + struct linux_acpi_table *table; + struct acpi_header header; + union { + uint32_t signature; + char filename[5]; + } u; + static const char prefix[] = ACPI_SYSFS_PREFIX; + char filename[ sizeof ( prefix ) - 1 /* NUL */ + 4 /* signature */ + + 3 /* "999" */ + 1 /* NUL */ ]; + ssize_t rlen; + size_t len; + void *data; + int fd; + + /* Check for existing table */ + list_for_each_entry ( table, &linux_acpi_tables, list ) { + if ( ( table->signature == signature ) && + ( table->index == index ) ) + return virt_to_user ( table->data ); + } + + /* Allocate a new table */ + table = malloc ( sizeof ( *table ) ); + if ( ! table ) + goto err_alloc; + table->signature = signature; + table->index = index; + + /* Construct filename */ + memset ( &u, 0, sizeof ( u ) ); + u.signature = le32_to_cpu ( signature ); + snprintf ( filename, sizeof ( filename ), "%s%s%d", prefix, + u.filename, ( index + 1 ) ); + + /* Open file */ + fd = linux_open ( filename, O_RDONLY ); + if ( ( fd < 0 ) && ( index == 0 ) ) { + filename[ sizeof ( prefix ) - 1 /* NUL */ + + 4 /* signature */ ] = '\0'; + fd = linux_open ( filename, O_RDONLY ); + } + if ( fd < 0 ) { + DBGC ( &linux_acpi_tables, "ACPI could not open %s: %s\n", + filename, linux_strerror ( linux_errno ) ); + goto err_open; + } + + /* Read header */ + rlen = linux_read ( fd, &header, sizeof ( header ) ); + if ( rlen < 0 ) { + DBGC ( &linux_acpi_tables, "ACPI could not read %s header: " + "%s\n", filename, linux_strerror ( linux_errno ) ); + goto err_header; + } + if ( ( ( size_t ) rlen ) != sizeof ( header ) ) { + DBGC ( &linux_acpi_tables, "ACPI underlength %s header\n", + filename ); + goto err_header_len; + } + + /* Parse header */ + len = le32_to_cpu ( header.length ); + if ( len < sizeof ( header ) ) { + DBGC ( &linux_acpi_tables, "ACPI malformed %s header\n", + filename ); + goto err_malformed; + } + + /* Allocate data */ + table->data = malloc ( len ); + if ( ! table->data ) + goto err_data; + + /* Read table */ + memcpy ( table->data, &header, sizeof ( header ) ); + data = ( table->data + sizeof ( header ) ); + len -= sizeof ( header ); + while ( len ) { + rlen = linux_read ( fd, data, len ); + if ( rlen < 0 ) { + DBGC ( &linux_acpi_tables, "ACPI could not read %s: " + "%s\n", filename, + linux_strerror ( linux_errno ) ); + goto err_body; + } + if ( rlen == 0 ) { + DBGC ( &linux_acpi_tables, "ACPI underlength %s\n", + filename ); + goto err_body_len; + } + data += rlen; + len -= rlen; + } + + /* Close file */ + linux_close ( fd ); + + /* Add to list of tables */ + list_add ( &table->list, &linux_acpi_tables ); + DBGC ( &linux_acpi_tables, "ACPI cached %s\n", filename ); + + return virt_to_user ( table->data ); + + err_body_len: + err_body: + free ( table->data ); + err_data: + err_malformed: + err_header_len: + err_header: + linux_close ( fd ); + err_open: + free ( table ); + err_alloc: + return UNULL; +} + +PROVIDE_ACPI ( linux, acpi_find, linux_acpi_find ); -- cgit v1.2.3-55-g7522 From 2b5d3f582f718ca11488fb6d92ea39dd22b8ffed Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 2 Mar 2021 10:20:55 +0000 Subject: [slirp] Add libslirp driver for Linux Add a driver using libslirp to provide a virtual network interface without requiring root permissions on the host. This simplifies the process of running iPXE as a Linux userspace application with network access. For example: make bin-x86_64-linux/slirp.linux ./bin-x86_64-linux/slirp.linux --net slirp libslirp will provide a built-in emulated DHCP server and NAT router. Settings such as the boot filename may be controlled via command-line options. For example: ./bin-x86_64-linux/slirp.linux \ --net slirp,filename=http://192.168.0.1/boot.ipxe Signed-off-by: Michael Brown --- src/Makefile.linux | 17 +- src/drivers/linux/slirp.c | 552 ++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/linux_api.h | 19 ++ src/include/ipxe/slirp.h | 155 +++++++++++ src/interface/linux/linux_api.c | 158 ++++++++++++ 6 files changed, 900 insertions(+), 2 deletions(-) create mode 100644 src/drivers/linux/slirp.c create mode 100644 src/include/ipxe/slirp.h (limited to 'src/include/ipxe') diff --git a/src/Makefile.linux b/src/Makefile.linux index 4a7837916..09b2b1577 100644 --- a/src/Makefile.linux +++ b/src/Makefile.linux @@ -26,9 +26,21 @@ NON_AUTO_MEDIA = linux # LINUX_CFLAGS += -Os -idirafter include -DSYMBOL_PREFIX=$(SYMBOL_PREFIX) +# Check for libslirp +# +LIBSLIRP_TEST = $(CC) $(LINUX_CFLAGS) -x c /dev/null -nostartfiles \ + -include slirp/libslirp.h -lslirp \ + -o /dev/null >/dev/null 2>&1 +WITH_LIBSLIRP := $(shell $(LIBSLIRP_TEST) && $(ECHO) yes) +ifneq ($(WITH_LIBSLIRP),) +LINUX_CFLAGS += -DHAVE_LIBSLIRP +LINUX_LDFLAGS += -lslirp +endif + # Host API wrapper # -$(BIN)/linux_api.o : interface/linux/linux_api.c $(MAKEDEPS) +$(BIN)/linux_api.o : interface/linux/linux_api.c include/ipxe/linux_api.h \ + include/ipxe/slirp.h $(MAKEDEPS) $(QM)$(ECHO) " [BUILD] $@" $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) -o $@ -c $< @@ -36,4 +48,5 @@ $(BIN)/linux_api.o : interface/linux/linux_api.c $(MAKEDEPS) # $(BIN)/%.linux : $(BIN)/%.linux.tmp $(BIN)/linux_api.o $(QM)$(ECHO) " [FINISH] $@" - $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) -o $@ $^ + $(Q)$(CC) $(LINUX_CFLAGS) $(WORKAROUND_CFLAGS) $(LINUX_LDFLAGS) \ + -o $@ $^ diff --git a/src/drivers/linux/slirp.c b/src/drivers/linux/slirp.c new file mode 100644 index 000000000..8341c9676 --- /dev/null +++ b/src/drivers/linux/slirp.c @@ -0,0 +1,552 @@ +/* + * Copyright (C) 2021 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Linux Slirp network driver + * + */ + +/** Maximum number of open file descriptors */ +#define SLIRP_MAX_FDS 128 + +/** A Slirp network interface */ +struct slirp_nic { + /** The libslirp device object */ + struct Slirp *slirp; + /** Polling file descriptor list */ + struct pollfd pollfds[SLIRP_MAX_FDS]; + /** Number of file descriptors */ + unsigned int numfds; +}; + +/** A Slirp alarm timer */ +struct slirp_alarm { + /** Slirp network interface */ + struct slirp_nic *slirp; + /** Retry timer */ + struct retry_timer timer; + /** Callback function */ + void ( __asmcall * callback ) ( void *opaque ); + /** Opaque value for callback function */ + void *opaque; +}; + +/** Default MAC address */ +static const uint8_t slirp_default_mac[ETH_ALEN] = + { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 }; + +/****************************************************************************** + * + * Slirp interface + * + ****************************************************************************** + */ + +/** + * Send packet + * + * @v buf Data buffer + * @v len Length of data + * @v device Device opaque pointer + * @ret len Consumed length (or negative on error) + */ +static ssize_t __asmcall slirp_send_packet ( const void *buf, size_t len, + void *device ) { + struct net_device *netdev = device; + struct io_buffer *iobuf; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) + return -1; + + /* Populate I/O buffer */ + memcpy ( iob_put ( iobuf, len ), buf, len ); + + /* Hand off to network stack */ + netdev_rx ( netdev, iobuf ); + + return len; +} + +/** + * Print an error message + * + * @v msg Error message + * @v device Device opaque pointer + */ +static void __asmcall slirp_guest_error ( const char *msg, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + + DBGC ( slirp, "SLIRP %p error: %s\n", slirp, msg ); +} + +/** + * Get virtual clock + * + * @v device Device opaque pointer + * @ret clock_ns Clock time in nanoseconds + */ +static int64_t __asmcall slirp_clock_get_ns ( void *device __unused ) { + int64_t time; + + time = currticks(); + return ( time * ( 1000000 / TICKS_PER_MS ) ); +} + +/** + * Handle timer expiry + * + * @v timer Retry timer + * @v over Failure indicator + */ +static void slirp_expired ( struct retry_timer *timer, int over __unused ) { + struct slirp_alarm *alarm = + container_of ( timer, struct slirp_alarm, timer ); + struct slirp_nic *slirp = alarm->slirp; + + /* Notify callback */ + DBGC ( slirp, "SLIRP %p timer fired\n", slirp ); + alarm->callback ( alarm->opaque ); +} + +/** + * Create a new timer + * + * @v callback Timer callback + * @v opaque Timer opaque pointer + * @v device Device opaque pointer + * @ret timer Timer + */ +static void * __asmcall +slirp_timer_new ( void ( __asmcall * callback ) ( void *opaque ), + void *opaque, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + struct slirp_alarm *alarm; + + /* Allocate timer */ + alarm = malloc ( sizeof ( *alarm ) ); + if ( ! alarm ) { + DBGC ( slirp, "SLIRP %p could not allocate timer\n", slirp ); + return NULL; + } + + /* Initialise timer */ + memset ( alarm, 0, sizeof ( *alarm ) ); + alarm->slirp = slirp; + timer_init ( &alarm->timer, slirp_expired, NULL ); + alarm->callback = callback; + alarm->opaque = opaque; + DBGC ( slirp, "SLIRP %p timer %p has callback %p (%p)\n", + slirp, alarm, alarm->callback, alarm->opaque ); + + return alarm; +} + +/** + * Delete a timer + * + * @v timer Timer + * @v device Device opaque pointer + */ +static void __asmcall slirp_timer_free ( void *timer, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + struct slirp_alarm *alarm = timer; + + /* Ignore timers that failed to allocate */ + if ( ! alarm ) + return; + + /* Stop timer */ + stop_timer ( &alarm->timer ); + + /* Free timer */ + free ( alarm ); + DBGC ( slirp, "SLIRP %p timer %p freed\n", slirp, alarm ); +} + +/** + * Set timer expiry time + * + * @v timer Timer + * @v expire Expiry time + * @v device Device opaque pointer + */ +static void __asmcall slirp_timer_mod ( void *timer, int64_t expire, + void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + struct slirp_alarm *alarm = timer; + int64_t timeout_ms; + unsigned long timeout; + + /* Ignore timers that failed to allocate */ + if ( ! alarm ) + return; + + /* (Re)start timer */ + timeout_ms = ( expire - ( currticks() / TICKS_PER_MS ) ); + if ( timeout_ms < 0 ) + timeout_ms = 0; + timeout = ( timeout_ms * TICKS_PER_MS ); + start_timer_fixed ( &alarm->timer, timeout ); + DBGC ( slirp, "SLIRP %p timer %p set for %ld ticks\n", + slirp, alarm, timeout ); +} + +/** + * Register file descriptor for polling + * + * @v fd File descriptor + * @v device Device opaque pointer + */ +static void __asmcall slirp_register_poll_fd ( int fd, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + + DBGC ( slirp, "SLIRP %p registered FD %d\n", slirp, fd ); +} + +/** + * Unregister file descriptor + * + * @v fd File descriptor + * @v device Device opaque pointer + */ +static void __asmcall slirp_unregister_poll_fd ( int fd, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + + DBGC ( slirp, "SLIRP %p unregistered FD %d\n", slirp, fd ); +} + +/** + * Notify that new events are ready + * + * @v device Device opaque pointer + */ +static void __asmcall slirp_notify ( void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + + DBGC2 ( slirp, "SLIRP %p notified\n", slirp ); +} + +/** Slirp callbacks */ +static struct slirp_callbacks slirp_callbacks = { + .send_packet = slirp_send_packet, + .guest_error = slirp_guest_error, + .clock_get_ns = slirp_clock_get_ns, + .timer_new = slirp_timer_new, + .timer_free = slirp_timer_free, + .timer_mod = slirp_timer_mod, + .register_poll_fd = slirp_register_poll_fd, + .unregister_poll_fd = slirp_unregister_poll_fd, + .notify = slirp_notify, +}; + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int slirp_open ( struct net_device *netdev ) { + struct slirp_nic *slirp = netdev->priv; + + /* Nothing to do */ + DBGC ( slirp, "SLIRP %p opened\n", slirp ); + + return 0; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void slirp_close ( struct net_device *netdev ) { + struct slirp_nic *slirp = netdev->priv; + + /* Nothing to do */ + DBGC ( slirp, "SLIRP %p closed\n", slirp ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int slirp_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct slirp_nic *slirp = netdev->priv; + + /* Transmit packet */ + linux_slirp_input ( slirp->slirp, iobuf->data, iob_len ( iobuf ) ); + netdev_tx_complete ( netdev, iobuf ); + + return 0; +} + +/** + * Add polling file descriptor + * + * @v fd File descriptor + * @v events Events of interest + * @v device Device opaque pointer + * @ret index File descriptor index + */ +static int __asmcall slirp_add_poll ( int fd, int events, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + struct pollfd *pollfd; + unsigned int index; + + /* Fail if too many descriptors are registered */ + if ( slirp->numfds >= SLIRP_MAX_FDS ) { + DBGC ( slirp, "SLIRP %p too many file descriptors\n", slirp ); + return -1; + } + + /* Populate polling file descriptor */ + index = slirp->numfds++; + pollfd = &slirp->pollfds[index]; + pollfd->fd = fd; + pollfd->events = 0; + if ( events & SLIRP_EVENT_IN ) + pollfd->events |= POLLIN; + if ( events & SLIRP_EVENT_OUT ) + pollfd->events |= POLLOUT; + if ( events & SLIRP_EVENT_PRI ) + pollfd->events |= POLLPRI; + if ( events & SLIRP_EVENT_ERR ) + pollfd->events |= POLLERR; + if ( events & SLIRP_EVENT_HUP ) + pollfd->events |= ( POLLHUP | POLLRDHUP ); + DBGCP ( slirp, "SLIRP %p polling FD %d event mask %#04x(%#04x)\n", + slirp, fd, events, pollfd->events ); + + return index; +} + +/** + * Get returned events for a file descriptor + * + * @v index File descriptor index + * @v device Device opaque pointer + * @ret events Returned events + */ +static int __asmcall slirp_get_revents ( int index, void *device ) { + struct net_device *netdev = device; + struct slirp_nic *slirp = netdev->priv; + int revents; + int events; + + /* Ignore failed descriptors */ + if ( index < 0 ) + return 0; + + /* Collect events */ + revents = slirp->pollfds[index].revents; + events = 0; + if ( revents & POLLIN ) + events |= SLIRP_EVENT_IN; + if ( revents & POLLOUT ) + events |= SLIRP_EVENT_OUT; + if ( revents & POLLPRI ) + events |= SLIRP_EVENT_PRI; + if ( revents & POLLERR ) + events |= SLIRP_EVENT_ERR; + if ( revents & ( POLLHUP | POLLRDHUP ) ) + events |= SLIRP_EVENT_HUP; + if ( events ) { + DBGC2 ( slirp, "SLIRP %p polled FD %d events %#04x(%#04x)\n", + slirp, slirp->pollfds[index].fd, events, revents ); + } + + return events; +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void slirp_poll ( struct net_device *netdev ) { + struct slirp_nic *slirp = netdev->priv; + uint32_t timeout = 0; + int ready; + int error; + + /* Rebuild polling file descriptor list */ + slirp->numfds = 0; + linux_slirp_pollfds_fill ( slirp->slirp, &timeout, + slirp_add_poll, netdev ); + + /* Poll descriptors */ + ready = linux_poll ( slirp->pollfds, slirp->numfds, 0 ); + error = ( ready == -1 ); + linux_slirp_pollfds_poll ( slirp->slirp, error, slirp_get_revents, + netdev ); + + /* Record polling errors */ + if ( error ) { + DBGC ( slirp, "SLIRP %p poll failed: %s\n", + slirp, linux_strerror ( linux_errno ) ); + netdev_rx_err ( netdev, NULL, -ELINUX ( linux_errno ) ); + } +} + +/** Network device operations */ +static struct net_device_operations slirp_operations = { + .open = slirp_open, + .close = slirp_close, + .transmit = slirp_transmit, + .poll = slirp_poll, +}; + +/****************************************************************************** + * + * Linux driver interface + * + ****************************************************************************** + */ + +/** + * Probe device + * + * @v linux Linux device + * @v request Device creation request + * @ret rc Return status code + */ +static int slirp_probe ( struct linux_device *linux, + struct linux_device_request *request ) { + struct net_device *netdev; + struct slirp_nic *slirp; + struct slirp_config config; + int rc; + + /* Allocate device */ + netdev = alloc_etherdev ( sizeof ( *slirp ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &slirp_operations ); + linux_set_drvdata ( linux, netdev ); + snprintf ( linux->dev.name, sizeof ( linux->dev.name ), "host" ); + netdev->dev = &linux->dev; + memcpy ( netdev->hw_addr, slirp_default_mac, ETH_ALEN ); + slirp = netdev->priv; + memset ( slirp, 0, sizeof ( *slirp ) ); + + /* Apply requested settings */ + linux_apply_settings ( &request->settings, + netdev_settings ( netdev ) ); + + /* Initialise default configuration (matching qemu) */ + memset ( &config, 0, sizeof ( config ) ); + config.version = 1; + config.in_enabled = true; + config.vnetwork.s_addr = htonl ( 0x0a000200 ); /* 10.0.2.0 */ + config.vnetmask.s_addr = htonl ( 0xffffff00 ); /* 255.255.255.0 */ + config.vhost.s_addr = htonl ( 0x0a000202 ); /* 10.0.2.2 */ + config.in6_enabled = true; + config.vdhcp_start.s_addr = htonl ( 0x0a00020f ); /* 10.0.2.15 */ + config.vnameserver.s_addr = htonl ( 0x0a000203 ); /* 10.0.2.3 */ + + /* Instantiate device */ + slirp->slirp = linux_slirp_new ( &config, &slirp_callbacks, netdev ); + if ( ! slirp->slirp ) { + DBGC ( slirp, "SLIRP could not instantiate\n" ); + rc = -ENODEV; + goto err_new; + } + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register; + + /* Set link up since there is no concept of link state */ + netdev_link_up ( netdev ); + + return 0; + + unregister_netdev ( netdev ); + err_register: + linux_slirp_cleanup ( slirp->slirp ); + err_new: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove device + * + * @v linux Linux device + */ +static void slirp_remove ( struct linux_device *linux ) { + struct net_device *netdev = linux_get_drvdata ( linux ); + struct slirp_nic *slirp = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Shut down device */ + linux_slirp_cleanup ( slirp->slirp ); + + /* Free network device */ + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Slirp driver */ +struct linux_driver slirp_driver __linux_driver = { + .name = "slirp", + .probe = slirp_probe, + .remove = slirp_remove, + .can_probe = 1, +}; diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index e3fc8fa09..b5c5d185e 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -212,6 +212,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_intelxlvf ( ERRFILE_DRIVER | 0x00cd0000 ) #define ERRFILE_usbblk ( ERRFILE_DRIVER | 0x00ce0000 ) #define ERRFILE_iphone ( ERRFILE_DRIVER | 0x00cf0000 ) +#define ERRFILE_slirp ( ERRFILE_DRIVER | 0x00d00000 ) #define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 ) #define ERRFILE_arp ( ERRFILE_NET | 0x00010000 ) diff --git a/src/include/ipxe/linux_api.h b/src/include/ipxe/linux_api.h index ea247a613..040b52f8c 100644 --- a/src/include/ipxe/linux_api.h +++ b/src/include/ipxe/linux_api.h @@ -50,6 +50,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #endif struct sockaddr; +struct slirp_config; +struct slirp_callbacks; +struct Slirp; extern int linux_errno; extern int linux_argc; @@ -82,5 +85,21 @@ extern ssize_t __asmcall linux_sendto ( int sockfd, const void *buf, const struct sockaddr *dest_addr, size_t addrlen ); extern const char * __asmcall linux_strerror ( int linux_errno ); +extern struct Slirp * __asmcall +linux_slirp_new ( const struct slirp_config *config, + const struct slirp_callbacks *callbacks, void *opaque ); +extern void __asmcall linux_slirp_cleanup ( struct Slirp *slirp ); +extern void __asmcall linux_slirp_input ( struct Slirp *slirp, + const uint8_t *pkt, int pkt_len ); +extern void __asmcall +linux_slirp_pollfds_fill ( struct Slirp *slirp, uint32_t *timeout, + int ( __asmcall * add_poll ) ( int fd, int events, + void *opaque ), + void *opaque ); +extern void __asmcall +linux_slirp_pollfds_poll ( struct Slirp *slirp, int select_error, + int ( __asmcall * get_revents ) ( int idx, + void *opaque ), + void *opaque ); #endif /* _IPXE_LINUX_API_H */ diff --git a/src/include/ipxe/slirp.h b/src/include/ipxe/slirp.h new file mode 100644 index 000000000..4fb13b934 --- /dev/null +++ b/src/include/ipxe/slirp.h @@ -0,0 +1,155 @@ +#ifndef _IPXE_SLIRP_H +#define _IPXE_SLIRP_H + +/** @file + * + * Linux Slirp network driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** Ready to be read */ +#define SLIRP_EVENT_IN 0x01 + +/** Ready to be written */ +#define SLIRP_EVENT_OUT 0x02 + +/** Exceptional condition */ +#define SLIRP_EVENT_PRI 0x04 + +/** Error condition */ +#define SLIRP_EVENT_ERR 0x08 + +/** Hang up */ +#define SLIRP_EVENT_HUP 0x10 + +/** Slirp device configuration */ +struct slirp_config { + /** Configuration version */ + uint32_t version; + /** Restrict to host loopback connections only */ + int restricted; + /** IPv4 is enabled */ + bool in_enabled; + /** IPv4 network */ + struct in_addr vnetwork; + /** IPv4 netmask */ + struct in_addr vnetmask; + /** IPv4 host server address */ + struct in_addr vhost; + /** IPv6 is enabled */ + bool in6_enabled; + /** IPv6 prefix */ + struct in6_addr vprefix_addr6; + /** IPv6 prefix length */ + uint8_t vprefix_len; + /** IPv6 host server address */ + struct in6_addr vhost6; + /** Client hostname */ + const char *vhostname; + /** TFTP server name */ + const char *tftp_server_name; + /** TFTP path prefix */ + const char *tftp_path; + /** Boot filename */ + const char *bootfile; + /** DHCPv4 start address */ + struct in_addr vdhcp_start; + /** DNS IPv4 address */ + struct in_addr vnameserver; + /** DNS IPv6 address */ + struct in_addr vnameserver6; + /** DNS search list */ + const char **vdnssearch; + /** Domain name */ + const char *vdomainname; + /** Interface MTU */ + size_t if_mtu; + /** Interface MRU */ + size_t if_mru; + /** Disable host loopback connections */ + bool disable_host_loopback; + /** Enable emulation (apparently unsafe) */ + bool enable_emu; +}; + +/** Slirp device callbacks */ +struct slirp_callbacks { + /** + * Send packet + * + * @v buf Data buffer + * @v len Length of data + * @v device Device opaque pointer + * @ret len Consumed length (or negative on error) + */ + ssize_t ( __asmcall * send_packet ) ( const void *buf, size_t len, + void *device ); + /** + * Print an error message + * + * @v msg Error message + * @v device Device opaque pointer + */ + void ( __asmcall * guest_error ) ( const char *msg, void *device ); + /** + * Get virtual clock + * + * @v device Device opaque pointer + * @ret clock_ns Clock time in nanoseconds + */ + int64_t ( __asmcall * clock_get_ns ) ( void *device ); + /** + * Create a new timer + * + * @v callback Timer callback + * @v opaque Timer opaque pointer + * @v device Device opaque pointer + * @ret timer Timer + */ + void * ( __asmcall * timer_new ) ( void ( __asmcall * callback ) + ( void *opaque ), + void *opaque, void *device ); + /** + * Delete a timer + * + * @v timer Timer + * @v device Device opaque pointer + */ + void ( __asmcall * timer_free ) ( void *timer, void *device ); + /** + * Set timer expiry time + * + * @v timer Timer + * @v expire Expiry time + * @v device Device opaque pointer + */ + void ( __asmcall * timer_mod ) ( void *timer, int64_t expire, + void *device ); + /** + * Register file descriptor for polling + * + * @v fd File descriptor + * @v device Device opaque pointer + */ + void ( __asmcall * register_poll_fd ) ( int fd, void *device ); + /** + * Unregister file descriptor + * + * @v fd File descriptor + * @v device Device opaque pointer + */ + void ( __asmcall * unregister_poll_fd ) ( int fd, void *device ); + /** + * Notify that new events are ready + * + * @v device Device opaque pointer + */ + void ( __asmcall * notify ) ( void *device ); +}; + +#endif /* _IPXE_SLIRP_H */ diff --git a/src/interface/linux/linux_api.c b/src/interface/linux/linux_api.c index 4ab3c6603..1f44b532b 100644 --- a/src/interface/linux/linux_api.c +++ b/src/interface/linux/linux_api.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,13 @@ #include #include #include +#include #include +#include + +#ifdef HAVE_LIBSLIRP +#include +#endif /** @file * @@ -345,6 +352,152 @@ const char * __asmcall linux_strerror ( int linux_errno ) { return strerror ( linux_errno ); } +/****************************************************************************** + * + * libslirp wrappers + * + ****************************************************************************** + */ + +#ifdef HAVE_LIBSLIRP + +/** + * Wrap slirp_new() + * + */ +struct Slirp * __asmcall +linux_slirp_new ( const struct slirp_config *config, + const struct slirp_callbacks *callbacks, void *opaque ) { + const union { + struct slirp_callbacks callbacks; + SlirpCb cb; + } *u = ( ( typeof ( u ) ) callbacks ); + SlirpConfig cfg; + Slirp *slirp; + + /* Translate configuration */ + memset ( &cfg, 0, sizeof ( cfg ) ); + cfg.version = config->version; + cfg.restricted = config->restricted; + cfg.in_enabled = config->in_enabled; + cfg.vnetwork = config->vnetwork; + cfg.vnetmask = config->vnetmask; + cfg.vhost = config->vhost; + cfg.in6_enabled = config->in6_enabled; + memcpy ( &cfg.vprefix_addr6, &config->vprefix_addr6, + sizeof ( cfg.vprefix_addr6 ) ); + cfg.vprefix_len = config->vprefix_len; + memcpy ( &cfg.vhost6, &config->vhost6, sizeof ( cfg.vhost6 ) ); + cfg.vhostname = config->vhostname; + cfg.tftp_server_name = config->tftp_server_name; + cfg.tftp_path = config->tftp_path; + cfg.bootfile = config->bootfile; + cfg.vdhcp_start = config->vdhcp_start; + cfg.vnameserver = config->vnameserver; + memcpy ( &cfg.vnameserver6, &config->vnameserver6, + sizeof ( cfg.vnameserver6 ) ); + cfg.vdnssearch = config->vdnssearch; + cfg.vdomainname = config->vdomainname; + cfg.if_mtu = config->if_mtu; + cfg.if_mru = config->if_mru; + cfg.disable_host_loopback = config->disable_host_loopback; + cfg.enable_emu = config->enable_emu; + + /* Validate callback structure */ + static_assert ( &u->cb.send_packet == &u->callbacks.send_packet ); + static_assert ( &u->cb.guest_error == &u->callbacks.guest_error ); + static_assert ( &u->cb.clock_get_ns == &u->callbacks.clock_get_ns ); + static_assert ( &u->cb.timer_new == &u->callbacks.timer_new ); + static_assert ( &u->cb.timer_free == &u->callbacks.timer_free ); + static_assert ( &u->cb.timer_mod == &u->callbacks.timer_mod ); + static_assert ( &u->cb.register_poll_fd == + &u->callbacks.register_poll_fd ); + static_assert ( &u->cb.unregister_poll_fd == + &u->callbacks.unregister_poll_fd ); + static_assert ( &u->cb.notify == &u->callbacks.notify ); + + /* Create device */ + slirp = slirp_new ( &cfg, &u->cb, opaque ); + + return slirp; +} + +/** + * Wrap slirp_cleanup() + * + */ +void __asmcall linux_slirp_cleanup ( struct Slirp *slirp ) { + + slirp_cleanup ( slirp ); +} + +/** + * Wrap slirp_input() + * + */ +void __asmcall linux_slirp_input ( struct Slirp *slirp, const uint8_t *pkt, + int pkt_len ) { + + slirp_input ( slirp, pkt, pkt_len ); +} + +/** + * Wrap slirp_pollfds_fill() + * + */ +void __asmcall +linux_slirp_pollfds_fill ( struct Slirp *slirp, uint32_t *timeout, + int ( __asmcall * add_poll ) ( int fd, int events, + void *opaque ), + void *opaque ) { + + slirp_pollfds_fill ( slirp, timeout, add_poll, opaque ); +} + +/** + * Wrap slirp_pollfds_poll() + * + */ +void __asmcall +linux_slirp_pollfds_poll ( struct Slirp *slirp, int select_error, + int ( __asmcall * get_revents ) ( int idx, + void *opaque ), + void *opaque ) { + + slirp_pollfds_poll ( slirp, select_error, get_revents, opaque ); +} + +#else /* HAVE_LIBSLIRP */ + +struct Slirp * __asmcall +linux_slirp_new ( const struct slirp_config *config, + const struct slirp_callbacks *callbacks, void *opaque ) { + return NULL; +} + +void __asmcall linux_slirp_cleanup ( struct Slirp *slirp ) { +} + +void __asmcall linux_slirp_input ( struct Slirp *slirp, const uint8_t *pkt, + int pkt_len ) { +} + +void __asmcall +linux_slirp_pollfds_fill ( struct Slirp *slirp, uint32_t *timeout, + int ( __asmcall * add_poll ) ( int fd, int events, + void *opaque ), + void *opaque ) { +} + +void __asmcall +linux_slirp_pollfds_poll ( struct Slirp *slirp, int select_error, + int ( __asmcall * get_revents ) ( int idx, + void *opaque ), + void *opaque ) { +} + +#endif /* HAVE_LIBSLIRP */ + /****************************************************************************** * * Symbol aliases @@ -371,3 +524,8 @@ PROVIDE_IPXE_SYM ( linux_socket ); PROVIDE_IPXE_SYM ( linux_bind ); PROVIDE_IPXE_SYM ( linux_sendto ); PROVIDE_IPXE_SYM ( linux_strerror ); +PROVIDE_IPXE_SYM ( linux_slirp_new ); +PROVIDE_IPXE_SYM ( linux_slirp_cleanup ); +PROVIDE_IPXE_SYM ( linux_slirp_input ); +PROVIDE_IPXE_SYM ( linux_slirp_pollfds_fill ); +PROVIDE_IPXE_SYM ( linux_slirp_pollfds_poll ); -- cgit v1.2.3-55-g7522 From 8055d5c48b4194f24c1705fd6a15e7125e8ef4c5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 2 Mar 2021 18:02:21 +0000 Subject: [linux] Add missing pci_num_bus() stub Signed-off-by: Michael Brown --- src/include/ipxe/linux/linux_pci.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/linux/linux_pci.h b/src/include/ipxe/linux/linux_pci.h index 76ed8f252..de42f766b 100644 --- a/src/include/ipxe/linux/linux_pci.h +++ b/src/include/ipxe/linux/linux_pci.h @@ -22,6 +22,17 @@ extern int linux_pci_read ( struct pci_device *pci, unsigned long where, extern int linux_pci_write ( struct pci_device *pci, unsigned long where, unsigned long value, size_t len ); +/** + * Determine number of PCI buses within system + * + * @ret num_bus Number of buses + */ +static inline __always_inline int +PCIAPI_INLINE ( linux, pci_num_bus ) ( void ) { + /* Assume all buses may exist */ + return 0x100; +} + /** * Read byte from PCI configuration space * -- cgit v1.2.3-55-g7522 From 5c8a9905ce3b04a4317d356d5481552fd17b63cb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 2 Mar 2021 23:37:41 +0000 Subject: [linux] Add a generic function for reading files from sysfs Signed-off-by: Michael Brown --- src/include/ipxe/errfile.h | 1 + src/include/ipxe/linux_api.h | 3 ++ src/include/ipxe/linux_sysfs.h | 16 ++++++ src/interface/linux/linux_api.c | 16 ++++++ src/interface/linux/linux_sysfs.c | 107 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+) create mode 100644 src/include/ipxe/linux_sysfs.h create mode 100644 src/interface/linux/linux_sysfs.c (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index b5c5d185e..3daf7bde7 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -388,6 +388,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_efi_autoboot ( ERRFILE_OTHER | 0x00530000 ) #define ERRFILE_efi_autoexec ( ERRFILE_OTHER | 0x00540000 ) #define ERRFILE_efi_cachedhcp ( ERRFILE_OTHER | 0x00550000 ) +#define ERRFILE_linux_sysfs ( ERRFILE_OTHER | 0x00560000 ) /** @} */ diff --git a/src/include/ipxe/linux_api.h b/src/include/ipxe/linux_api.h index 040b52f8c..ab2e8014d 100644 --- a/src/include/ipxe/linux_api.h +++ b/src/include/ipxe/linux_api.h @@ -46,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #define MAP_FAILED ( ( void * ) -1 ) #endif @@ -65,6 +66,8 @@ extern ssize_t __asmcall linux_read ( int fd, void *buf, size_t count ); extern ssize_t __asmcall linux_write ( int fd, const void *buf, size_t count ); extern int __asmcall linux_fcntl ( int fd, int cmd, ... ); extern int __asmcall linux_ioctl ( int fd, unsigned long request, ... ); +extern int __asmcall linux_statx ( int dirfd, const char *pathname, int flags, + unsigned int mask, struct statx *statxbuf ); extern int __asmcall linux_poll ( struct pollfd *fds, unsigned int nfds, int timeout ); extern int __asmcall linux_nanosleep ( const struct timespec *req, diff --git a/src/include/ipxe/linux_sysfs.h b/src/include/ipxe/linux_sysfs.h new file mode 100644 index 000000000..d97b649c0 --- /dev/null +++ b/src/include/ipxe/linux_sysfs.h @@ -0,0 +1,16 @@ +#ifndef _IPXE_LINUX_SYSFS_H +#define _IPXE_LINUX_SYSFS_H + +/** @file + * + * Linux sysfs files + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +extern int linux_sysfs_read ( const char *filename, userptr_t *data ); + +#endif /* _IPXE_LINUX_SYSFS_H */ diff --git a/src/interface/linux/linux_api.c b/src/interface/linux/linux_api.c index fa694330e..6fa2b0e76 100644 --- a/src/interface/linux/linux_api.c +++ b/src/interface/linux/linux_api.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +199,20 @@ int __asmcall linux_ioctl ( int fd, unsigned long request, ... ) { return ret; } +/** + * Wrap statx() + * + */ +int __asmcall linux_statx ( int dirfd, const char *pathname, int flags, + unsigned int mask, struct statx *statxbuf ) { + int ret; + + ret = statx ( dirfd, pathname, flags, mask, statxbuf ); + if ( ret == -1 ) + linux_errno = errno; + return ret; +} + /** * Wrap poll() * @@ -516,6 +531,7 @@ PROVIDE_IPXE_SYM ( linux_read ); PROVIDE_IPXE_SYM ( linux_write ); PROVIDE_IPXE_SYM ( linux_fcntl ); PROVIDE_IPXE_SYM ( linux_ioctl ); +PROVIDE_IPXE_SYM ( linux_statx ); PROVIDE_IPXE_SYM ( linux_poll ); PROVIDE_IPXE_SYM ( linux_nanosleep ); PROVIDE_IPXE_SYM ( linux_usleep ); diff --git a/src/interface/linux/linux_sysfs.c b/src/interface/linux/linux_sysfs.c new file mode 100644 index 000000000..0b9f1f5d9 --- /dev/null +++ b/src/interface/linux/linux_sysfs.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2021 Michael Brown . + * + * 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 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include + +/** @file + * + * Linux sysfs files + * + */ + +/** + * Read file from sysfs + * + * @v filename Filename + * @v data Data to fill in + * @ret len Length read, or negative error + */ +int linux_sysfs_read ( const char *filename, userptr_t *data ) { + struct statx statx; + size_t offset; + size_t len; + ssize_t read; + int fd; + int rc; + + /* Open file */ + fd = linux_open ( filename, O_RDONLY ); + if ( fd < 0 ) { + rc = -ELINUX ( linux_errno ); + DBGC ( filename, "LINUX could not open %s: %s\n", + filename, linux_strerror ( linux_errno ) ); + goto err_open; + } + + /* Get file length */ + if ( linux_statx ( fd, "", AT_EMPTY_PATH, STATX_SIZE, &statx ) == -1 ) { + rc = -ELINUX ( linux_errno ); + DBGC ( filename, "LINUX could not stat %s: %s\n", + filename, linux_strerror ( linux_errno ) ); + goto err_stat; + } + len = statx.stx_size; + + /* Allocate buffer */ + *data = umalloc ( len ); + if ( ! *data ) { + rc = -ENOMEM; + DBGC ( filename, "LINUX could not allocate %zd bytes for %s\n", + len, filename ); + goto err_alloc; + } + + /* Read file */ + for ( offset = 0 ; offset < len ; offset += read ) { + read = linux_read ( fd, user_to_virt ( *data, offset ), len ); + if ( read < 0 ) { + DBGC ( filename, "LINUX could not read %s: %s\n", + filename, linux_strerror ( linux_errno ) ); + goto err_read; + } + if ( read == 0 ) { + rc = -EIO; + DBGC ( filename, "LINUX read underlength %s\n", + filename ); + goto err_eof; + } + } + + /* Close file */ + linux_close ( fd ); + + DBGC ( filename, "LINUX read %s\n", filename ); + return len; + + err_eof: + err_read: + ufree ( *data ); + err_alloc: + err_stat: + linux_close ( fd ); + err_open: + return rc; +} -- cgit v1.2.3-55-g7522 From 2a2909cd1f55b2110bf8ef48b65816c9fae4637f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 2 Mar 2021 23:43:21 +0000 Subject: [linux] Use generic sysfs mechanism to read SMBIOS table Signed-off-by: Michael Brown --- src/include/ipxe/smbios.h | 1 + src/interface/linux/linux_smbios.c | 140 ++++++++++++++++++++----------------- src/interface/smbios/smbios.c | 10 +++ 3 files changed, 87 insertions(+), 64 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/smbios.h b/src/include/ipxe/smbios.h index 53fbd8cb8..42278fb24 100644 --- a/src/include/ipxe/smbios.h +++ b/src/include/ipxe/smbios.h @@ -235,5 +235,6 @@ extern int read_smbios_string ( struct smbios_structure *structure, unsigned int index, void *data, size_t len ); extern int smbios_version ( void ); +extern void smbios_clear ( void ); #endif /* _IPXE_SMBIOS_H */ diff --git a/src/interface/linux/linux_smbios.c b/src/interface/linux/linux_smbios.c index 494a60bd9..981873943 100644 --- a/src/interface/linux/linux_smbios.c +++ b/src/interface/linux/linux_smbios.c @@ -21,20 +21,21 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include +#include +#include #include -/** SMBIOS filename */ -static const char smbios_filename[] = "/dev/mem"; - -/** SMBIOS entry point scan region start address */ -#define SMBIOS_ENTRY_START 0xf0000 +/** SMBIOS entry point filename */ +static const char smbios_entry_filename[] = + "/sys/firmware/dmi/tables/smbios_entry_point"; -/** SMBIOS entry point scan region length */ -#define SMBIOS_ENTRY_LEN 0x10000 +/** SMBIOS filename */ +static const char smbios_filename[] = "/sys/firmware/dmi/tables/DMI"; -/** SMBIOS mapping alignment */ -#define SMBIOS_ALIGN 0x1000 +/** Cache SMBIOS data */ +static userptr_t smbios_data; /** * Find SMBIOS @@ -43,73 +44,84 @@ static const char smbios_filename[] = "/dev/mem"; * @ret rc Return status code */ static int linux_find_smbios ( struct smbios *smbios ) { - struct smbios_entry entry; - void *entry_mem; - void *smbios_mem; - size_t smbios_offset; - size_t smbios_indent; - size_t smbios_len; - int fd; + struct smbios3_entry *smbios3_entry; + struct smbios_entry *smbios_entry; + userptr_t entry; + void *data; + int len; int rc; - /* Open SMBIOS file */ - fd = linux_open ( smbios_filename, O_RDONLY ); - if ( fd < 0 ) { - rc = -ELINUX ( linux_errno ); - DBGC ( smbios, "SMBIOS could not open %s: %s\n", - smbios_filename, linux_strerror ( linux_errno ) ); - goto err_open; + /* Read entry point file */ + len = linux_sysfs_read ( smbios_entry_filename, &entry ); + if ( len < 0 ) { + rc = len; + DBGC ( smbios, "SMBIOS could not read %s: %s\n", + smbios_entry_filename, strerror ( rc ) ); + goto err_entry; } - - /* Map the region potentially containing the SMBIOS entry point */ - entry_mem = linux_mmap ( NULL, SMBIOS_ENTRY_LEN, PROT_READ, MAP_SHARED, - fd, SMBIOS_ENTRY_START ); - if ( entry_mem == MAP_FAILED ) { - rc = -ELINUX ( linux_errno ); - DBGC ( smbios, "SMBIOS could not mmap %s (%#x+%#x): %s\n", - smbios_filename, SMBIOS_ENTRY_START, SMBIOS_ENTRY_LEN, - linux_strerror ( linux_errno ) ); - goto err_mmap_entry; + data = user_to_virt ( entry, 0 ); + smbios3_entry = data; + smbios_entry = data; + if ( ( len >= ( ( int ) sizeof ( *smbios3_entry ) ) ) && + ( smbios3_entry->signature == SMBIOS3_SIGNATURE ) ) { + smbios->version = SMBIOS_VERSION ( smbios3_entry->major, + smbios3_entry->minor ); + } else if ( ( len >= ( ( int ) sizeof ( *smbios_entry ) ) ) && + ( smbios_entry->signature == SMBIOS_SIGNATURE ) ) { + smbios->version = SMBIOS_VERSION ( smbios_entry->major, + smbios_entry->minor ); + } else { + DBGC ( smbios, "SMBIOS invalid entry point %s:\n", + smbios_entry_filename ); + DBGC_HDA ( smbios, 0, data, len ); + rc = -EINVAL; + goto err_version; } - /* Scan for the SMBIOS entry point */ - if ( ( rc = find_smbios_entry ( virt_to_user ( entry_mem ), - SMBIOS_ENTRY_LEN, &entry ) ) != 0 ) - goto err_find_entry; - - /* Map the region containing the SMBIOS structures */ - smbios_indent = ( entry.smbios_address & ( SMBIOS_ALIGN - 1 ) ); - smbios_offset = ( entry.smbios_address - smbios_indent ); - smbios_len = ( entry.smbios_len + smbios_indent ); - smbios_mem = linux_mmap ( NULL, smbios_len, PROT_READ, MAP_SHARED, - fd, smbios_offset ); - if ( smbios_mem == MAP_FAILED ) { - rc = -ELINUX ( linux_errno ); - DBGC ( smbios, "SMBIOS could not mmap %s (%#zx+%#zx): %s\n", - smbios_filename, smbios_offset, smbios_len, - linux_strerror ( linux_errno ) ); - goto err_mmap_smbios; + /* Read SMBIOS file */ + len = linux_sysfs_read ( smbios_filename, &smbios_data ); + if ( len < 0 ) { + rc = len; + DBGC ( smbios, "SMBIOS could not read %s: %s\n", + smbios_filename, strerror ( rc ) ); + goto err_read; } - /* Fill in entry point descriptor structure */ - smbios->address = virt_to_user ( smbios_mem + smbios_indent ); - smbios->len = entry.smbios_len; - smbios->count = entry.smbios_count; - smbios->version = SMBIOS_VERSION ( entry.major, entry.minor ); + /* Populate SMBIOS descriptor */ + smbios->address = smbios_data; + smbios->len = len; + smbios->count = 0; - /* Unmap the entry point region (no longer required) */ - linux_munmap ( entry_mem, SMBIOS_ENTRY_LEN ); + /* Free entry point */ + ufree ( entry ); return 0; - linux_munmap ( smbios_mem, smbios_len ); - err_mmap_smbios: - err_find_entry: - linux_munmap ( entry_mem, SMBIOS_ENTRY_LEN ); - err_mmap_entry: - linux_close ( fd ); - err_open: + ufree ( smbios_data ); + err_read: + err_version: + ufree ( entry ); + err_entry: return rc; } +/** + * Free cached SMBIOS data + * + */ +static void linux_smbios_shutdown ( int booting __unused ) { + + /* Clear SMBIOS data pointer */ + smbios_clear(); + + /* Free SMBIOS data */ + ufree ( smbios_data ); +} + +/** SMBIOS shutdown function */ +struct startup_fn linux_smbios_startup_fn __startup_fn ( STARTUP_NORMAL ) = { + .name = "linux_smbios", + .shutdown = linux_smbios_shutdown, +}; + PROVIDE_SMBIOS ( linux, find_smbios, linux_find_smbios ); diff --git a/src/interface/smbios/smbios.c b/src/interface/smbios/smbios.c index 5bd76f16a..12a080da2 100644 --- a/src/interface/smbios/smbios.c +++ b/src/interface/smbios/smbios.c @@ -255,3 +255,13 @@ int smbios_version ( void ) { return smbios.version; } + +/** + * Clear SMBIOS entry point descriptor + * + */ +void smbios_clear ( void ) { + + /* Clear address */ + smbios.address = UNULL; +} -- cgit v1.2.3-55-g7522 From 69ecab2634d3f5a825e0baaa310ba048d5aed3b5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 3 Mar 2021 00:34:02 +0000 Subject: [linux] Use fstat() rather than statx() The statx() system call has a clean header file and a consistent layout, but was unfortunately added only in kernel 4.11. Using stat() or fstat() directly is extremely messy since glibc does not necessarily use the kernel native data structures. However, as the only current use case is to obtain the length of an open file, we can merely provide a wrapper that does precisely this. Signed-off-by: Michael Brown --- src/include/ipxe/linux_api.h | 4 +--- src/interface/linux/linux_api.c | 11 ++++++----- src/interface/linux/linux_sysfs.c | 4 +--- 3 files changed, 8 insertions(+), 11 deletions(-) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/linux_api.h b/src/include/ipxe/linux_api.h index ab2e8014d..5b0b242d1 100644 --- a/src/include/ipxe/linux_api.h +++ b/src/include/ipxe/linux_api.h @@ -46,7 +46,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include #define MAP_FAILED ( ( void * ) -1 ) #endif @@ -66,8 +65,7 @@ extern ssize_t __asmcall linux_read ( int fd, void *buf, size_t count ); extern ssize_t __asmcall linux_write ( int fd, const void *buf, size_t count ); extern int __asmcall linux_fcntl ( int fd, int cmd, ... ); extern int __asmcall linux_ioctl ( int fd, unsigned long request, ... ); -extern int __asmcall linux_statx ( int dirfd, const char *pathname, int flags, - unsigned int mask, struct statx *statxbuf ); +extern int __asmcall linux_fstat_size ( int fd, size_t *size ); extern int __asmcall linux_poll ( struct pollfd *fds, unsigned int nfds, int timeout ); extern int __asmcall linux_nanosleep ( const struct timespec *req, diff --git a/src/interface/linux/linux_api.c b/src/interface/linux/linux_api.c index 6fa2b0e76..d1f969aa7 100644 --- a/src/interface/linux/linux_api.c +++ b/src/interface/linux/linux_api.c @@ -200,14 +200,15 @@ int __asmcall linux_ioctl ( int fd, unsigned long request, ... ) { } /** - * Wrap statx() + * Wrap part of fstat() * */ -int __asmcall linux_statx ( int dirfd, const char *pathname, int flags, - unsigned int mask, struct statx *statxbuf ) { +int __asmcall linux_fstat_size ( int fd, size_t *size ) { + struct stat stat; int ret; - ret = statx ( dirfd, pathname, flags, mask, statxbuf ); + ret = fstat ( fd, &stat ); + *size = stat.st_size; if ( ret == -1 ) linux_errno = errno; return ret; @@ -531,7 +532,7 @@ PROVIDE_IPXE_SYM ( linux_read ); PROVIDE_IPXE_SYM ( linux_write ); PROVIDE_IPXE_SYM ( linux_fcntl ); PROVIDE_IPXE_SYM ( linux_ioctl ); -PROVIDE_IPXE_SYM ( linux_statx ); +PROVIDE_IPXE_SYM ( linux_fstat_size ); PROVIDE_IPXE_SYM ( linux_poll ); PROVIDE_IPXE_SYM ( linux_nanosleep ); PROVIDE_IPXE_SYM ( linux_usleep ); diff --git a/src/interface/linux/linux_sysfs.c b/src/interface/linux/linux_sysfs.c index 0b9f1f5d9..463bc2ab9 100644 --- a/src/interface/linux/linux_sysfs.c +++ b/src/interface/linux/linux_sysfs.c @@ -40,7 +40,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @ret len Length read, or negative error */ int linux_sysfs_read ( const char *filename, userptr_t *data ) { - struct statx statx; size_t offset; size_t len; ssize_t read; @@ -57,13 +56,12 @@ int linux_sysfs_read ( const char *filename, userptr_t *data ) { } /* Get file length */ - if ( linux_statx ( fd, "", AT_EMPTY_PATH, STATX_SIZE, &statx ) == -1 ) { + if ( linux_fstat_size ( fd, &len ) == -1 ) { rc = -ELINUX ( linux_errno ); DBGC ( filename, "LINUX could not stat %s: %s\n", filename, linux_strerror ( linux_errno ) ); goto err_stat; } - len = statx.stx_size; /* Allocate buffer */ *data = umalloc ( len ); -- cgit v1.2.3-55-g7522 From 1c4917b6a739c887acbf6f7631b1f74084430ee7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 3 Mar 2021 01:55:07 +0000 Subject: [linux] Validate length of ACPI table read from sysfs Consumers of acpi_find() will assume that returned structures include a valid table header and that the length in the table header is correct. These assumptions are necessary when dealing with raw ACPI tables, since there exists no independent source of length information. Ensure that these assumptions are also valid for ACPI tables read from sysfs. Signed-off-by: Michael Brown --- src/include/ipxe/errfile.h | 1 + src/interface/linux/linux_acpi.c | 10 ++++++++++ 2 files changed, 11 insertions(+) (limited to 'src/include/ipxe') diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 3daf7bde7..e3bf9f565 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -389,6 +389,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_efi_autoexec ( ERRFILE_OTHER | 0x00540000 ) #define ERRFILE_efi_cachedhcp ( ERRFILE_OTHER | 0x00550000 ) #define ERRFILE_linux_sysfs ( ERRFILE_OTHER | 0x00560000 ) +#define ERRFILE_linux_acpi ( ERRFILE_OTHER | 0x00570000 ) /** @} */ diff --git a/src/interface/linux/linux_acpi.c b/src/interface/linux/linux_acpi.c index 851cc54e6..e658936f2 100644 --- a/src/interface/linux/linux_acpi.c +++ b/src/interface/linux/linux_acpi.c @@ -57,6 +57,7 @@ static LIST_HEAD ( linux_acpi_tables ); */ static userptr_t linux_acpi_find ( uint32_t signature, unsigned int index ) { struct linux_acpi_table *table; + struct acpi_header *header; union { uint32_t signature; char filename[5]; @@ -100,6 +101,14 @@ static userptr_t linux_acpi_find ( uint32_t signature, unsigned int index ) { filename, strerror ( rc ) ); goto err_read; } + header = user_to_virt ( table->data, 0 ); + if ( ( ( ( size_t ) len ) < sizeof ( *header ) ) || + ( ( ( size_t ) len ) < le32_to_cpu ( header->length ) ) ) { + rc = -ENOENT; + DBGC ( &linux_acpi_tables, "ACPI underlength %s (%d bytes)\n", + filename, len ); + goto err_len; + } /* Add to list of tables */ list_add ( &table->list, &linux_acpi_tables ); @@ -107,6 +116,7 @@ static userptr_t linux_acpi_find ( uint32_t signature, unsigned int index ) { return table->data; + err_len: ufree ( table->data ); err_read: free ( table ); -- cgit v1.2.3-55-g7522