Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51557 Signed-off-by: Brendan Shanks bshanks@codeweavers.com --- dlls/ntdll/unix/system.c | 105 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 70636020489..960a737028f 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -1262,7 +1262,7 @@ static NTSTATUS create_cpuset_info(SYSTEM_CPU_SET_INFORMATION *info) return STATUS_SUCCESS; }
-#ifdef linux +#if defined(linux) || defined(__APPLE__)
static void copy_smbios_string( char **buffer, const char *s, size_t len ) { @@ -1458,6 +1458,10 @@ static NTSTATUS create_smbios_tables( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, U return STATUS_SUCCESS; }
+#endif + +#ifdef linux + static size_t get_smbios_string( const char *path, char *str, size_t size ) { FILE *file; @@ -1640,6 +1644,103 @@ static NTSTATUS get_smbios_from_iokit( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, return STATUS_SUCCESS; }
+static size_t cf_to_string( CFTypeRef type_ref, char *buffer, size_t buffer_size ) +{ + size_t length = 0; + + if (!type_ref) + return 0; + + if (CFGetTypeID(type_ref) == CFDataGetTypeID()) + { + length = MIN(CFDataGetLength(type_ref), buffer_size); + CFDataGetBytes(type_ref, CFRangeMake(0, length), (UInt8*)buffer); + buffer[length] = 0; + length = strlen(buffer); + } + else if (CFGetTypeID(type_ref) == CFStringGetTypeID()) + { + if (CFStringGetCString(type_ref, buffer, buffer_size, kCFStringEncodingASCII)) + length = strlen(buffer); + } + + CFRelease(type_ref); + return length; +} + +static NTSTATUS generate_smbios( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len, + ULONG *required_len ) +{ + /* Apple Silicon Macs don't have SMBIOS, we need to generate it. + * Use strings and data from IOKit when available. + */ + io_service_t platform_expert; + CFDataRef cf_manufacturer, cf_model; + CFStringRef cf_serial_number, cf_uuid_string; + char manufacturer[128], model[128], serial_number[128]; + size_t manufacturer_len = 0, model_len = 0, serial_number_len = 0; + GUID system_uuid = {0}; + + platform_expert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); + if (!platform_expert) + return STATUS_NO_MEMORY; + + cf_manufacturer = IORegistryEntryCreateCFProperty(platform_expert, CFSTR("manufacturer"), kCFAllocatorDefault, 0); + cf_model = IORegistryEntryCreateCFProperty(platform_expert, CFSTR("model"), kCFAllocatorDefault, 0); + cf_serial_number = IORegistryEntryCreateCFProperty(platform_expert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0); + cf_uuid_string = IORegistryEntryCreateCFProperty(platform_expert, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); + + manufacturer_len = cf_to_string(cf_manufacturer, manufacturer, sizeof(manufacturer)); + model_len = cf_to_string(cf_model, model, sizeof(model)); + serial_number_len = cf_to_string(cf_serial_number, serial_number, sizeof(serial_number)); + + if (cf_uuid_string) + { + CFUUIDRef cf_uuid; + CFUUIDBytes bytes; + + cf_uuid = CFUUIDCreateFromString(kCFAllocatorDefault, cf_uuid_string); + bytes = CFUUIDGetUUIDBytes(cf_uuid); + + system_uuid.Data1 = (bytes.byte0 << 24) | (bytes.byte1 << 16) | (bytes.byte2 << 8) | bytes.byte3; + system_uuid.Data2 = (bytes.byte4 << 8) | bytes.byte5; + system_uuid.Data3 = (bytes.byte6 << 8) | bytes.byte7; + memcpy(&system_uuid.Data4, &bytes.byte8, sizeof(system_uuid.Data4)); + + CFRelease(cf_uuid); + CFRelease(cf_uuid_string); + } + + IOObjectRelease(platform_expert); + +#define S(s) s, s ## _len +#define STR(s) s, sizeof(s)-1 + return create_smbios_tables( sfti, available_len, required_len, + S(manufacturer), /* BIOS vendor */ + STR("1.0"), /* BIOS version (required) */ + STR("01/01/2021"), /* BIOS date (required) */ + S(manufacturer), /* system vendor */ + S(model), /* system product */ + STR("1.0"), /* system version */ + S(serial_number), /* system serial number */ + &system_uuid, /* system UUID */ + NULL, 0, /* system SKU */ + S(model), /* system family */ + S(manufacturer), /* board vendor */ + S(model), /* board product */ + S(model), /* board version */ + S(serial_number), /* board serial number */ + NULL, 0, /* board asset tag */ + S(manufacturer), /* chassis vendor */ + 2, /* chassis type: unknown */ + NULL, 0, /* chassis version */ + S(serial_number), /* chassis serial number */ + NULL, 0 /* chassis asset tag */ + ); +#undef STR +#undef S +} + static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len, ULONG *required_len ) { @@ -1649,6 +1750,8 @@ static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULON { NTSTATUS ret; ret = get_smbios_from_iokit(sfti, available_len, required_len); + if (ret == STATUS_NO_MEMORY) + ret = generate_smbios(sfti, available_len, required_len); return ret; } default: