mirror of
https://github.com/ipxe/ipxe
synced 2025-12-20 20:10:18 +03:00
[linux] Use generic sysfs mechanism to read SMBIOS table
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -235,5 +235,6 @@ extern int read_smbios_string ( struct smbios_structure *structure,
|
|||||||
unsigned int index,
|
unsigned int index,
|
||||||
void *data, size_t len );
|
void *data, size_t len );
|
||||||
extern int smbios_version ( void );
|
extern int smbios_version ( void );
|
||||||
|
extern void smbios_clear ( void );
|
||||||
|
|
||||||
#endif /* _IPXE_SMBIOS_H */
|
#endif /* _IPXE_SMBIOS_H */
|
||||||
|
|||||||
@@ -21,20 +21,21 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ipxe/linux_api.h>
|
#include <ipxe/linux_api.h>
|
||||||
|
#include <ipxe/linux_sysfs.h>
|
||||||
#include <ipxe/linux.h>
|
#include <ipxe/linux.h>
|
||||||
|
#include <ipxe/umalloc.h>
|
||||||
|
#include <ipxe/init.h>
|
||||||
#include <ipxe/smbios.h>
|
#include <ipxe/smbios.h>
|
||||||
|
|
||||||
|
/** SMBIOS entry point filename */
|
||||||
|
static const char smbios_entry_filename[] =
|
||||||
|
"/sys/firmware/dmi/tables/smbios_entry_point";
|
||||||
|
|
||||||
/** SMBIOS filename */
|
/** SMBIOS filename */
|
||||||
static const char smbios_filename[] = "/dev/mem";
|
static const char smbios_filename[] = "/sys/firmware/dmi/tables/DMI";
|
||||||
|
|
||||||
/** SMBIOS entry point scan region start address */
|
/** Cache SMBIOS data */
|
||||||
#define SMBIOS_ENTRY_START 0xf0000
|
static userptr_t smbios_data;
|
||||||
|
|
||||||
/** SMBIOS entry point scan region length */
|
|
||||||
#define SMBIOS_ENTRY_LEN 0x10000
|
|
||||||
|
|
||||||
/** SMBIOS mapping alignment */
|
|
||||||
#define SMBIOS_ALIGN 0x1000
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find SMBIOS
|
* Find SMBIOS
|
||||||
@@ -43,73 +44,84 @@ static const char smbios_filename[] = "/dev/mem";
|
|||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int linux_find_smbios ( struct smbios *smbios ) {
|
static int linux_find_smbios ( struct smbios *smbios ) {
|
||||||
struct smbios_entry entry;
|
struct smbios3_entry *smbios3_entry;
|
||||||
void *entry_mem;
|
struct smbios_entry *smbios_entry;
|
||||||
void *smbios_mem;
|
userptr_t entry;
|
||||||
size_t smbios_offset;
|
void *data;
|
||||||
size_t smbios_indent;
|
int len;
|
||||||
size_t smbios_len;
|
|
||||||
int fd;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Open SMBIOS file */
|
/* Read entry point file */
|
||||||
fd = linux_open ( smbios_filename, O_RDONLY );
|
len = linux_sysfs_read ( smbios_entry_filename, &entry );
|
||||||
if ( fd < 0 ) {
|
if ( len < 0 ) {
|
||||||
rc = -ELINUX ( linux_errno );
|
rc = len;
|
||||||
DBGC ( smbios, "SMBIOS could not open %s: %s\n",
|
DBGC ( smbios, "SMBIOS could not read %s: %s\n",
|
||||||
smbios_filename, linux_strerror ( linux_errno ) );
|
smbios_entry_filename, strerror ( rc ) );
|
||||||
goto err_open;
|
goto err_entry;
|
||||||
|
}
|
||||||
|
data = user_to_virt ( entry, 0 );
|
||||||
|
smbios3_entry = data;
|
||||||
|
smbios_entry = data;
|
||||||
|
if ( ( len >= ( ( int ) sizeof ( *smbios3_entry ) ) ) &&
|
||||||
|
( smbios3_entry->signature == SMBIOS3_SIGNATURE ) ) {
|
||||||
|
smbios->version = SMBIOS_VERSION ( smbios3_entry->major,
|
||||||
|
smbios3_entry->minor );
|
||||||
|
} else if ( ( len >= ( ( int ) sizeof ( *smbios_entry ) ) ) &&
|
||||||
|
( smbios_entry->signature == SMBIOS_SIGNATURE ) ) {
|
||||||
|
smbios->version = SMBIOS_VERSION ( smbios_entry->major,
|
||||||
|
smbios_entry->minor );
|
||||||
|
} else {
|
||||||
|
DBGC ( smbios, "SMBIOS invalid entry point %s:\n",
|
||||||
|
smbios_entry_filename );
|
||||||
|
DBGC_HDA ( smbios, 0, data, len );
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto err_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Map the region potentially containing the SMBIOS entry point */
|
/* Read SMBIOS file */
|
||||||
entry_mem = linux_mmap ( NULL, SMBIOS_ENTRY_LEN, PROT_READ, MAP_SHARED,
|
len = linux_sysfs_read ( smbios_filename, &smbios_data );
|
||||||
fd, SMBIOS_ENTRY_START );
|
if ( len < 0 ) {
|
||||||
if ( entry_mem == MAP_FAILED ) {
|
rc = len;
|
||||||
rc = -ELINUX ( linux_errno );
|
DBGC ( smbios, "SMBIOS could not read %s: %s\n",
|
||||||
DBGC ( smbios, "SMBIOS could not mmap %s (%#x+%#x): %s\n",
|
smbios_filename, strerror ( rc ) );
|
||||||
smbios_filename, SMBIOS_ENTRY_START, SMBIOS_ENTRY_LEN,
|
goto err_read;
|
||||||
linux_strerror ( linux_errno ) );
|
|
||||||
goto err_mmap_entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan for the SMBIOS entry point */
|
/* Populate SMBIOS descriptor */
|
||||||
if ( ( rc = find_smbios_entry ( virt_to_user ( entry_mem ),
|
smbios->address = smbios_data;
|
||||||
SMBIOS_ENTRY_LEN, &entry ) ) != 0 )
|
smbios->len = len;
|
||||||
goto err_find_entry;
|
smbios->count = 0;
|
||||||
|
|
||||||
/* Map the region containing the SMBIOS structures */
|
/* Free entry point */
|
||||||
smbios_indent = ( entry.smbios_address & ( SMBIOS_ALIGN - 1 ) );
|
ufree ( entry );
|
||||||
smbios_offset = ( entry.smbios_address - smbios_indent );
|
|
||||||
smbios_len = ( entry.smbios_len + smbios_indent );
|
|
||||||
smbios_mem = linux_mmap ( NULL, smbios_len, PROT_READ, MAP_SHARED,
|
|
||||||
fd, smbios_offset );
|
|
||||||
if ( smbios_mem == MAP_FAILED ) {
|
|
||||||
rc = -ELINUX ( linux_errno );
|
|
||||||
DBGC ( smbios, "SMBIOS could not mmap %s (%#zx+%#zx): %s\n",
|
|
||||||
smbios_filename, smbios_offset, smbios_len,
|
|
||||||
linux_strerror ( linux_errno ) );
|
|
||||||
goto err_mmap_smbios;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fill in entry point descriptor structure */
|
|
||||||
smbios->address = virt_to_user ( smbios_mem + smbios_indent );
|
|
||||||
smbios->len = entry.smbios_len;
|
|
||||||
smbios->count = entry.smbios_count;
|
|
||||||
smbios->version = SMBIOS_VERSION ( entry.major, entry.minor );
|
|
||||||
|
|
||||||
/* Unmap the entry point region (no longer required) */
|
|
||||||
linux_munmap ( entry_mem, SMBIOS_ENTRY_LEN );
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
linux_munmap ( smbios_mem, smbios_len );
|
ufree ( smbios_data );
|
||||||
err_mmap_smbios:
|
err_read:
|
||||||
err_find_entry:
|
err_version:
|
||||||
linux_munmap ( entry_mem, SMBIOS_ENTRY_LEN );
|
ufree ( entry );
|
||||||
err_mmap_entry:
|
err_entry:
|
||||||
linux_close ( fd );
|
|
||||||
err_open:
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free cached SMBIOS data
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void linux_smbios_shutdown ( int booting __unused ) {
|
||||||
|
|
||||||
|
/* Clear SMBIOS data pointer */
|
||||||
|
smbios_clear();
|
||||||
|
|
||||||
|
/* Free SMBIOS data */
|
||||||
|
ufree ( smbios_data );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** SMBIOS shutdown function */
|
||||||
|
struct startup_fn linux_smbios_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
|
||||||
|
.name = "linux_smbios",
|
||||||
|
.shutdown = linux_smbios_shutdown,
|
||||||
|
};
|
||||||
|
|
||||||
PROVIDE_SMBIOS ( linux, find_smbios, linux_find_smbios );
|
PROVIDE_SMBIOS ( linux, find_smbios, linux_find_smbios );
|
||||||
|
|||||||
@@ -255,3 +255,13 @@ int smbios_version ( void ) {
|
|||||||
|
|
||||||
return smbios.version;
|
return smbios.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear SMBIOS entry point descriptor
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void smbios_clear ( void ) {
|
||||||
|
|
||||||
|
/* Clear address */
|
||||||
|
smbios.address = UNULL;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user