Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ipmi/ipmi_smbios.c
Show First 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | |||||
static struct ipmi_get_info ipmi_info; | static struct ipmi_get_info ipmi_info; | ||||
static int ipmi_probed; | static int ipmi_probed; | ||||
static struct mtx ipmi_info_mtx; | static struct mtx ipmi_info_mtx; | ||||
MTX_SYSINIT(ipmi_info, &ipmi_info_mtx, "ipmi info", MTX_DEF); | MTX_SYSINIT(ipmi_info, &ipmi_info_mtx, "ipmi info", MTX_DEF); | ||||
static void ipmi_smbios_probe(struct ipmi_get_info *); | static void ipmi_smbios_probe(struct ipmi_get_info *); | ||||
static int smbios_cksum(struct smbios_eps *); | static int smbios_cksum(struct smbios_eps *); | ||||
static void smbios_walk_table(uint8_t *, int, smbios_callback_t, | static void smbios_walk_table(uint8_t *, vm_size_t, smbios_callback_t, | ||||
void *); | void *); | ||||
static void smbios_ipmi_info(struct smbios_structure_header *, void *); | static void smbios_ipmi_info(struct smbios_structure_header *, void *); | ||||
static void | static void | ||||
smbios_ipmi_info(struct smbios_structure_header *h, void *arg) | smbios_ipmi_info(struct smbios_structure_header *h, void *arg) | ||||
{ | { | ||||
struct ipmi_get_info *info; | struct ipmi_get_info *info; | ||||
struct ipmi_entry *s; | struct ipmi_entry *s; | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | if (s->interrupt_number > 15) | ||||
s->interrupt_number); | s->interrupt_number); | ||||
else | else | ||||
info->irq = s->interrupt_number; | info->irq = s->interrupt_number; | ||||
} | } | ||||
info->iface_type = s->interface_type; | info->iface_type = s->interface_type; | ||||
} | } | ||||
static void | static void | ||||
smbios_walk_table(uint8_t *p, int entries, smbios_callback_t cb, void *arg) | smbios_walk_table(uint8_t *table, vm_size_t size, smbios_callback_t cb, void *arg) | ||||
{ | { | ||||
struct smbios_structure_header *s; | struct smbios_structure_header *s; | ||||
uint8_t *p; | |||||
while (entries--) { | for (p = table; p < table + size;) { | ||||
s = (struct smbios_structure_header *)p; | s = (struct smbios_structure_header *)p; | ||||
cb(s, arg); | cb(s, arg); | ||||
/* | /* | ||||
* Look for a double-nul after the end of the | * Look for a double-nul after the end of the | ||||
* formatted area of this structure. | * formatted area of this structure. | ||||
*/ | */ | ||||
p += s->length; | p += s->length; | ||||
while (!(p[0] == 0 && p[1] == 0)) | while (!(p[0] == 0 && p[1] == 0)) { | ||||
p++; | p++; | ||||
if (p >= table + size) | |||||
return; | |||||
} | |||||
/* | /* | ||||
* Skip over the double-nul to the start of the next | * Skip over the double-nul to the start of the next | ||||
* structure. | * structure. | ||||
*/ | */ | ||||
p += 2; | p += 2; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Walk the SMBIOS table looking for an IPMI (type 38) entry. If we find | * Walk the SMBIOS table looking for an IPMI (type 38) entry. If we find | ||||
* one, return the parsed data in the passed in ipmi_get_info structure and | * one, return the parsed data in the passed in ipmi_get_info structure and | ||||
* return true. If we don't find one, return false. | * return true. If we don't find one, return false. | ||||
*/ | */ | ||||
static void | static void | ||||
ipmi_smbios_probe(struct ipmi_get_info *info) | ipmi_smbios_probe(struct ipmi_get_info *info) | ||||
{ | { | ||||
struct smbios_eps *header; | |||||
void *table; | void *table; | ||||
u_int32_t addr; | vm_paddr_t table_paddr; | ||||
vm_size_t table_size; | |||||
int err; | |||||
bzero(info, sizeof(struct ipmi_get_info)); | bzero(info, sizeof(struct ipmi_get_info)); | ||||
/* Find the SMBIOS table header. */ | err = smbios_get_structure_table(&table_paddr, &table_size); | ||||
addr = bios_sigsearch(SMBIOS_START, SMBIOS_SIG, SMBIOS_LEN, | if (err != 0) | ||||
SMBIOS_STEP, SMBIOS_OFF); | |||||
if (addr == 0) | |||||
return; | return; | ||||
/* | table = pmap_mapbios(table_paddr, table_size); | ||||
* Map the header. We first map a fixed size to get the actual | |||||
* length and then map it a second time with the actual length so | |||||
* we can verify the checksum. | |||||
*/ | |||||
header = pmap_mapbios(addr, sizeof(struct smbios_eps)); | |||||
table = pmap_mapbios(addr, header->length); | |||||
pmap_unmapbios((vm_offset_t)header, sizeof(struct smbios_eps)); | |||||
header = table; | |||||
if (smbios_cksum(header) != 0) { | |||||
pmap_unmapbios((vm_offset_t)header, header->length); | |||||
return; | |||||
} | |||||
/* Now map the actual table and walk it looking for an IPMI entry. */ | smbios_walk_table(table, table_size, smbios_ipmi_info, info); | ||||
table = pmap_mapbios(header->structure_table_address, | |||||
header->structure_table_length); | |||||
smbios_walk_table(table, header->number_structures, smbios_ipmi_info, | |||||
info); | |||||
/* Unmap everything. */ | /* Unmap everything. */ | ||||
pmap_unmapbios((vm_offset_t)table, header->structure_table_length); | pmap_unmapbios((vm_offset_t)table, table_size); | ||||
pmap_unmapbios((vm_offset_t)header, header->length); | |||||
} | } | ||||
/* | /* | ||||
* Return the SMBIOS IPMI table entry info to the caller. If we haven't | * Return the SMBIOS IPMI table entry info to the caller. If we haven't | ||||
* searched the IPMI table yet, search it. Otherwise, return a cached | * searched the IPMI table yet, search it. Otherwise, return a cached | ||||
* copy of the data. | * copy of the data. | ||||
*/ | */ | ||||
int | int | ||||
▲ Show 20 Lines • Show All 45 Lines • Show Last 20 Lines |