Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/x86/ucode_subr.c
| Show First 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | |||||
| #define AMD_10H_uCODE_TYPE 1 | #define AMD_10H_uCODE_TYPE 1 | ||||
| /* | /* | ||||
| * NB: the format of microcode update files is not documented by AMD. | * NB: the format of microcode update files is not documented by AMD. | ||||
| * It has been reverse engineered from studying Coreboot, illumos and Linux | * It has been reverse engineered from studying Coreboot, illumos and Linux | ||||
| * source code. | * source code. | ||||
| */ | */ | ||||
| const void * | const void * | ||||
| ucode_amd_find(const char *path, uint32_t signature, uint32_t revision, | ucode_amd_find(const char *path, uint32_t signature, uint32_t *revision, | ||||
| const uint8_t *fw_data, size_t fw_size, size_t *selected_sizep) | const uint8_t *fw_data, size_t fw_size, size_t *selected_sizep) | ||||
| { | { | ||||
| const amd_10h_fw_header_t *fw_header; | const amd_10h_fw_header_t *fw_header; | ||||
| const amd_10h_fw_header_t *selected_fw; | const amd_10h_fw_header_t *selected_fw; | ||||
| const equiv_cpu_entry_t *equiv_cpu_table; | const equiv_cpu_entry_t *equiv_cpu_table; | ||||
| const section_header_t *section_header; | const section_header_t *section_header; | ||||
| const container_header_t *container_header; | const container_header_t *container_header; | ||||
| size_t selected_size; | size_t selected_size; | ||||
| uint16_t equiv_id; | uint16_t equiv_id; | ||||
| int i; | int i; | ||||
| WARNX(1, "found cpu family %#x model %#x " | WARNX(1, "found cpu family %#x model %#x " | ||||
| "stepping %#x extfamily %#x extmodel %#x.", | "stepping %#x extfamily %#x extmodel %#x.", | ||||
| ((signature >> 8) & 0x0f) + ((signature >> 20) & 0xff), | ((signature >> 8) & 0x0f) + ((signature >> 20) & 0xff), | ||||
| (signature >> 4) & 0x0f, | (signature >> 4) & 0x0f, | ||||
| (signature >> 0) & 0x0f, (signature >> 20) & 0xff, | (signature >> 0) & 0x0f, (signature >> 20) & 0xff, | ||||
| (signature >> 16) & 0x0f); | (signature >> 16) & 0x0f); | ||||
| WARNX(1, "microcode revision %#x", revision); | WARNX(1, "microcode revision %#x", *revision); | ||||
| nextfile: | nextfile: | ||||
| WARNX(1, "checking %s for update.", path); | WARNX(1, "checking %s for update.", path); | ||||
| WARNX(3, "processing next container file"); | WARNX(3, "processing next container file"); | ||||
| if (fw_size < | if (fw_size < | ||||
| (sizeof(*container_header) + sizeof(*section_header))) { | (sizeof(*container_header) + sizeof(*section_header))) { | ||||
| WARNX(2, "file too short: %s", path); | WARNX(2, "file too short: %s", path); | ||||
| return (NULL); | return (NULL); | ||||
| ▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | while (fw_size >= sizeof(*section_header)) { | ||||
| fw_data += section_header->size; | fw_data += section_header->size; | ||||
| fw_size -= section_header->size; | fw_size -= section_header->size; | ||||
| if (fw_header->processor_rev_id != equiv_id) { | if (fw_header->processor_rev_id != equiv_id) { | ||||
| WARNX(1, "firmware processor_rev_id %x, equiv_id %x", | WARNX(1, "firmware processor_rev_id %x, equiv_id %x", | ||||
| fw_header->processor_rev_id, equiv_id); | fw_header->processor_rev_id, equiv_id); | ||||
| continue; /* different cpu */ | continue; /* different cpu */ | ||||
| } | } | ||||
| if (fw_header->patch_id <= revision) { | if (fw_header->patch_id <= *revision) { | ||||
| WARNX(1, "patch_id %x, revision %x", | WARNX(1, "patch_id %x, revision %x", | ||||
| fw_header->patch_id, revision); | fw_header->patch_id, *revision); | ||||
| continue; /* not newer revision */ | continue; /* not newer revision */ | ||||
| } | } | ||||
| if (fw_header->nb_dev_id != 0 || fw_header->sb_dev_id != 0) { | if (fw_header->nb_dev_id != 0 || fw_header->sb_dev_id != 0) { | ||||
| WARNX(2, "Chipset-specific microcode is not supported"); | WARNX(2, "Chipset-specific microcode is not supported"); | ||||
| } | } | ||||
| WARNX(3, "selecting revision: %x", fw_header->patch_id); | WARNX(3, "selecting revision: %x", fw_header->patch_id); | ||||
| revision = fw_header->patch_id; | *revision = fw_header->patch_id; | ||||
| selected_fw = fw_header; | selected_fw = fw_header; | ||||
| selected_size = section_header->size; | selected_size = section_header->size; | ||||
| } | } | ||||
| if (fw_size != 0) { | if (fw_size != 0) { | ||||
| WARNX(2, "%s is not a valid amd firmware: " | WARNX(2, "%s is not a valid amd firmware: " | ||||
| "file is truncated", path); | "file is truncated", path); | ||||
| selected_fw = NULL; | selected_fw = NULL; | ||||
| } | } | ||||
| found: | found: | ||||
| *selected_sizep = selected_size; | *selected_sizep = selected_size; | ||||
| return (selected_fw); | return (selected_fw); | ||||
| } | } | ||||