* Copyright 2004-2006, Axel DΓΆrfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h>
#include <vm/vm_types.h>
#include <arch/x86/bios.h>
#ifdef TRACE_BIOS
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
struct smbios {
uint32 anchor_string;
uint8 entry_point_checksum;
uint8 entry_point_length;
struct {
uint8 major;
uint8 minor;
} version;
uint16 maximum_size;
uint8 formatted_area[5];
uint8 dmi_anchor_string[5];
uint8 intermediate_checksum;
uint16 structure_table_size;
uint32 structure_table;
uint16 num_structures;
uint8 bcd_revision;
} _PACKED;
struct bios32 {
uint32 anchor_string;
uint32 service_directory;
uint8 revision;
uint8 size;
uint8 checksum;
uint8 _reserved[5];
};
enum {
BIOS32 = '_23_',
SMBIOS = '_MS_',
DMI = '_IMD',
};
addr_t gBiosBase;
static addr_t sBios32ServiceDirectory;
static bool
check_checksum(addr_t base, size_t length)
{
uint8 *bytes = (uint8 *)base;
uint8 sum = 0;
for (uint32 i = 0; i < length; i++)
sum += bytes[i];
return sum == 0;
}
* the values that identify BIOS service.
* Returns B_OK on successful completion, otherwise B_ERROR if
* the BIOS32 service directory is not available, or B_BAD_VALUE
* in case the identifier is not known or present.
*/
extern "C" status_t
get_bios32_service(uint32 identifier, struct bios32_service *service)
{
TRACE(("get_bios32_service(identifier = %#lx)\n", identifier));
if (sBios32ServiceDirectory == 0)
return B_ERROR;
uint32 eax = 0, ebx = 0, ecx = 0, edx = 0;
asm("movl %4, %%eax; "
"xorl %%ebx, %%ebx; "
"movl %5, %%ecx; "
"pushl %%cs; "
"call *%%ecx; "
"movl %%eax, %0; "
"movl %%ebx, %1; "
"movl %%ecx, %2; "
"movl %%edx, %3; "
: "=m" (eax), "=m" (ebx), "=m" (ecx), "=m" (edx)
: "m" (identifier), "m" (sBios32ServiceDirectory)
: "eax", "ebx", "ecx", "edx", "memory");
if ((eax & 0xff) != 0)
return B_BAD_VALUE;
service->base = ebx;
service->size = ecx;
service->offset = edx;
return B_OK;
}
extern "C" status_t
bios_init(void)
{
area_id biosArea = map_physical_memory("pc bios", 0xe0000, 0x20000,
B_ANY_KERNEL_ADDRESS | B_WRITE_BACK_MEMORY,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gBiosBase);
if (biosArea < 0)
return biosArea;
TRACE(("PC BIOS mapped to %p\n", (void *)gBiosBase));
addr_t base = gBiosBase;
addr_t end = base + 0x20000;
while (base < end) {
switch (*(uint32 *)base) {
case BIOS32:
if (check_checksum(base, sizeof(struct bios32))) {
struct bios32 *bios32 = (struct bios32 *)base;
TRACE(("bios32 revision %d\n", bios32->revision));
TRACE(("bios32 service directory at: %lx\n", bios32->service_directory));
if (bios32->service_directory >= 0xe0000
&& bios32->service_directory <= 0xfffff)
sBios32ServiceDirectory = gBiosBase - 0xe0000 + bios32->service_directory;
}
break;
case SMBIOS:
base += 16;
TRACE(("probably found SMBIOS structure.\n"));
break;
case DMI:
TRACE(("probably found DMI legacy structure.\n"));
break;
}
base += 16;
}
return B_OK;
}