#include <sys/types.h>
#include <sys/ucode.h>
#include <sys/ucode_intel.h>
#ifdef _KERNEL
#include <sys/systm.h>
#else
#include <strings.h>
#endif
ucode_errno_t
ucode_header_validate_intel(ucode_header_intel_t *uhp)
{
uint32_t header_size, body_size, total_size;
if (uhp == NULL)
return (EM_HEADER);
if (uhp->uh_header_ver != 0x1)
return (EM_HEADER);
header_size = UCODE_HEADER_SIZE_INTEL;
total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
if ((body_size % sizeof (int)) != 0 ||
(total_size < header_size + body_size) ||
(total_size % UCODE_KB(1)) != 0) {
return (EM_HEADER);
}
if (total_size < UCODE_MIN_SIZE || total_size > UCODE_MAX_SIZE)
return (EM_HEADER);
if (total_size > (header_size + body_size)) {
if ((total_size - body_size - header_size -
UCODE_EXT_TABLE_SIZE_INTEL) % UCODE_EXT_SIG_SIZE_INTEL) {
return (EM_HEADER);
}
}
return (EM_OK);
}
uint32_t
ucode_checksum_intel(uint32_t sum, uint32_t size, uint8_t *code)
{
int i;
uint32_t *lcode = (uint32_t *)(intptr_t)code;
i = size >> 2;
while (i--)
sum += lcode[i];
return (sum);
}
uint32_t
ucode_checksum_intel_extsig(ucode_header_intel_t *uhp,
ucode_ext_sig_intel_t *uesp)
{
uint32_t diff;
diff = uesp->ues_signature + uesp->ues_proc_flags + uesp->ues_checksum;
diff -= uhp->uh_signature + uhp->uh_proc_flags + uhp->uh_checksum;
return (diff);
}
ucode_errno_t
ucode_validate_intel(uint8_t *ucodep, size_t size)
{
uint32_t header_size = UCODE_HEADER_SIZE_INTEL;
size_t remaining;
if (ucodep == NULL || size <= 0)
return (EM_INVALIDARG);
for (remaining = size; remaining > 0; ) {
uint32_t total_size, body_size, ext_size;
uint8_t *curbuf = &ucodep[size - remaining];
ucode_header_intel_t *uhp = (ucode_header_intel_t *)curbuf;
ucode_errno_t rc;
if ((rc = ucode_header_validate_intel(uhp)) != EM_OK)
return (rc);
total_size = UCODE_TOTAL_SIZE_INTEL(uhp->uh_total_size);
if (ucode_checksum_intel(0, total_size, curbuf) != 0)
return (EM_CHECKSUM);
body_size = UCODE_BODY_SIZE_INTEL(uhp->uh_body_size);
ext_size = total_size - (header_size + body_size);
if (ext_size > 0) {
ucode_ext_table_intel_t *ext;
uint32_t i;
ext = (ucode_ext_table_intel_t *)
&curbuf[header_size + body_size];
if (ucode_checksum_intel(0, ext_size, (uint8_t *)ext))
return (EM_EXTCHECKSUM);
for (i = 0; i < ext->uet_count; i++) {
ucode_ext_sig_intel_t *sig =
&ext->uet_ext_sig[i];
if (ucode_checksum_intel_extsig(uhp, sig) != 0)
return (EM_SIGCHECKSUM);
}
}
remaining -= total_size;
}
return (EM_OK);
}