From: Billy Laws blaws05@gmail.com
This defines a wine-specific SMBIOS table format ontop of the standard additional processor information block to pass ID registers to wineboot. The index of each table within the SMBIOS directly maps to the core it corresponds to and registers are passed using their numerical IDs to match Windows' registry format and avoid needing to map between names and IDs on both ends (the unix side needs to manually encode the msr's anyway). --- dlls/ntdll/unix/system.c | 140 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 136 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 9343d13262c..42067b5b41c 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -196,6 +196,30 @@ struct smbios_boot_info BYTE boot_status[10]; };
+struct smbios_processor_specific_block +{ + BYTE length; + BYTE processor_type; + BYTE data[]; +}; + +struct smbios_processor_additional_info +{ + struct smbios_header hdr; + WORD ref_handle; + struct smbios_processor_specific_block info_block; +}; + +struct smbios_wine_core_id_regs_arm64 +{ + WORD num_regs; + struct smbios_wine_id_reg_value_arm64 + { + WORD reg; + UINT64 value; + } regs[]; +}; + #include "poppack.h"
enum smbios_type @@ -206,6 +230,7 @@ enum smbios_type SMBIOS_TYPE_CHASSIS = 3, SMBIOS_TYPE_PROCESSOR = 4, SMBIOS_TYPE_BOOTINFO = 32, + SMBIOS_TYPE_PROCESSOR_ADDITIONAL_INFO = 44, SMBIOS_TYPE_END = 127 };
@@ -1630,6 +1655,99 @@ static WORD append_smbios_boot_info( struct smbios_buffer *buf ) return append_smbios( buf, &boot.hdr, NULL, 0 ); }
+#ifdef __aarch64__ +#ifdef linux + +static DWORD get_core_id_regs_arm64( struct smbios_wine_id_reg_value_arm64 *regs, + WORD logical_thread_id ) +{ + static const char midr_el1_path[] = "/sys/devices/system/cpu/cpu%u/regs/identification/midr_el1"; + char path_buf[0x100]; + unsigned long value; + DWORD regidx = 0; + FILE *fp; + + /* MIDR_EL1 can vary across cores, so read it from sysfs. */ + snprintf( path_buf, sizeof(path_buf), midr_el1_path, logical_thread_id ); + if ((fp = fopen( path_buf, "r" ))) + { + fscanf( fp, "%lx", &value ); + fclose( fp ); + regs[regidx++] = (struct smbios_wine_id_reg_value_arm64){ 0x4000, value }; + } + +#define STR(a) #a +#define READ_ID_REG(reg_id) \ + /* mrs x0, #reg_id */ \ + __asm__ __volatile__( ".inst " STR(0xd5300000 | reg_id << 5) "\n\t" \ + "mov %0, x0" : "=r"(value) :: "x0" ); \ + regs[regidx++] = (struct smbios_wine_id_reg_value_arm64){ reg_id, value }; + + /* Linux traps reads to these ID registers and emulates them. They do not vary across cores, + * if the kernel doesn't support a specific ID register it will read as zero. */ + READ_ID_REG( 0x4020 ); /* ID_AA64PFR0_EL1 */ + READ_ID_REG( 0x4021 ); /* ID_AA64PFR1_EL1 */ + READ_ID_REG( 0x4024 ); /* ID_AA64ZFR0_EL1 */ + READ_ID_REG( 0x4025 ); /* ID_AA64SMFR0_EL1 */ + READ_ID_REG( 0x4028 ); /* ID_AA64DFR0_EL1 */ + READ_ID_REG( 0x4029 ); /* ID_AA64DFR1_EL1 */ + READ_ID_REG( 0x402c ); /* ID_AA64AFR0_EL1 */ + READ_ID_REG( 0x402d ); /* ID_AA64AFR1_EL1 */ + READ_ID_REG( 0x4030 ); /* ID_AA64ISAR0_EL1 */ + READ_ID_REG( 0x4031 ); /* ID_AA64ISAR1_EL1 */ + READ_ID_REG( 0x4032 ); /* ID_AA64ISAR2_EL1 */ + READ_ID_REG( 0x4038 ); /* ID_AA64MMFR0_EL1 */ + READ_ID_REG( 0x4039 ); /* ID_AA64MMFR1_EL1 */ + READ_ID_REG( 0x403a ); /* ID_AA64MMFR2_EL1 */ + READ_ID_REG( 0x5801 ); /* CTR_EL0 */ + /* Windows exposes SCTLR_EL1, ACTLR_EL1, TTBR0_EL1 and MAIR_EL1, but these are inaccessible under + * linux so leave them unpopulated. */ + +#undef READ_ID_REG +#undef STR + return regidx; +} + +#else + +static DWORD get_core_id_regs_arm64( struct smbios_wine_core_id_regs_arm64 *core_id_regs, + WORD logical_thread_id ) +{ + FIXME("stub\n"); + return 0; +} + +#endif + +static WORD append_smbios_wine_core_id_regs_arm64( struct smbios_buffer *buf, WORD ref_handle, + WORD logical_thread_id ) +{ + + WORD length; + BYTE info_buf[0xff]; + struct smbios_processor_additional_info *proc_additional_info = + (struct smbios_processor_additional_info *)info_buf; + struct smbios_wine_core_id_regs_arm64 *core_id_regs = + (struct smbios_wine_core_id_regs_arm64 *)proc_additional_info->info_block.data; + + proc_additional_info->hdr.type = SMBIOS_TYPE_PROCESSOR_ADDITIONAL_INFO; + proc_additional_info->ref_handle = ref_handle; + proc_additional_info->info_block.processor_type = 5; /* 64 bit ARM */ + + core_id_regs->num_regs = get_core_id_regs_arm64( core_id_regs->regs, logical_thread_id ); + + length = sizeof(struct smbios_processor_additional_info) + + sizeof(struct smbios_wine_core_id_regs_arm64) + + core_id_regs->num_regs * sizeof(struct smbios_wine_id_reg_value_arm64); + + proc_additional_info->hdr.length = length; + proc_additional_info->info_block.length = length - 6; + + return append_smbios( buf, &proc_additional_info->hdr, NULL, 0 ); +} + +#endif + static void append_smbios_end( struct smbios_buffer *buf ) { struct smbios_header end = { .type = SMBIOS_TYPE_END, .length = sizeof(end) }; @@ -1642,6 +1760,10 @@ static void create_smbios_processors( struct smbios_buffer *buf ) char socket[20], name[49]; SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *p = logical_proc_info_ex; UINT i, family = 0, core_count = 0, thread_count = 0, pkg_count = 0; +#ifdef __aarch64__ + UINT logical_thread_id = 0; +#endif + WORD proc_handle;
strcpy( name, cpu_name ); for (i = strlen(name); i > 0 && name[i - 1] == ' '; i--) name[i - 1] = 0; @@ -1653,8 +1775,12 @@ static void create_smbios_processors( struct smbios_buffer *buf ) case RelationProcessorPackage: if (!pkg_count++) break; snprintf( socket, sizeof(socket), "Socket #%u", pkg_count - 1 ); - append_smbios_processor( buf, core_count, thread_count, family, - socket, cpu_vendor, name, "", "" ); + proc_handle = append_smbios_processor( buf, core_count, thread_count, family, + socket, cpu_vendor, name, "", "" ); +#ifdef __aarch64__ + for (i = 0; i < thread_count; logical_thread_id++, i++) + append_smbios_wine_core_id_regs_arm64( buf, proc_handle, logical_thread_id ); +#endif core_count = thread_count = 0; break; case RelationProcessorCore: @@ -1668,8 +1794,14 @@ static void create_smbios_processors( struct smbios_buffer *buf ) p = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)p + p->Size); } snprintf( socket, sizeof(socket), "Socket #%u", pkg_count - 1 ); - append_smbios_processor( buf, core_count, thread_count, family, - socket, cpu_vendor, name, "", "" ); + proc_handle = append_smbios_processor( buf, core_count, thread_count, family, + socket, cpu_vendor, name, "", "" ); +#ifdef __aarch64__ + /* Create these in order so they can be looked up by indexing all additional processor + * info structures by the logical thread id. */ + for (i = 0; i < thread_count; logical_thread_id++, i++) + append_smbios_wine_core_id_regs_arm64( buf, proc_handle, logical_thread_id ); +#endif }
#undef ADD_STR