diff --git a/headers/private/kernel/arch/x86/bios.h b/headers/private/kernel/arch/x86/bios.h new file mode 100644 index 0000000000..c88fe772dd --- /dev/null +++ b/headers/private/kernel/arch/x86/bios.h @@ -0,0 +1,32 @@ +/* + * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ARCH_x86_BIOS_H +#define ARCH_x86_BIOS_H + + +#include + + +#define BIOS32_PCI_SERVICE 'ICP$' + +struct bios32_service { + uint32 base; + uint32 size; + uint32 offset; +}; + + +#ifdef __cplusplus +extern "C" { +#endif + +status_t get_bios32_service(uint32 identifier, struct bios32_service *service); +status_t bios_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ARCH_x86_BIOS_H */ diff --git a/src/kernel/core/arch/x86/Jamfile b/src/kernel/core/arch/x86/Jamfile index d5288c7b5e..f9837708b2 100644 --- a/src/kernel/core/arch/x86/Jamfile +++ b/src/kernel/core/arch/x86/Jamfile @@ -19,6 +19,7 @@ KernelStaticLibrary libx86 : arch_vm_translation_map.c arch_x86.S arch_interrupts.S + bios.cpp : -fno-pic -Wno-unused ; diff --git a/src/kernel/core/arch/x86/arch_vm.c b/src/kernel/core/arch/x86/arch_vm.c index 40b3a1d3cb..d679a5d326 100755 --- a/src/kernel/core/arch/x86/arch_vm.c +++ b/src/kernel/core/arch/x86/arch_vm.c @@ -1,10 +1,10 @@ /* -** Copyright 2002-2004, The Haiku Team. All rights reserved. -** Distributed under the terms of the Haiku License. -** -** Copyright 2001, Travis Geiselbrecht. All rights reserved. -** Distributed under the terms of the NewOS License. -*/ + * Copyright 2002-2004, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ #include @@ -17,6 +17,8 @@ #include #include +#include + //#define TRACE_ARCH_VM #ifdef TRACE_ARCH_VM @@ -53,7 +55,7 @@ arch_vm_init_post_area(kernel_args *args) return B_NO_MEMORY; } - return B_OK; + return bios_init(); } diff --git a/src/kernel/core/arch/x86/bios.cpp b/src/kernel/core/arch/x86/bios.cpp new file mode 100644 index 0000000000..9a01b3cd73 --- /dev/null +++ b/src/kernel/core/arch/x86/bios.cpp @@ -0,0 +1,168 @@ +/* + * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#include + + +//#define TRACE_BIOS +#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]; + + // this part is the legacy DMI compatible structure + 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; // in "paragraph" (16 byte) units + uint8 checksum; + uint8 _reserved[5]; +}; + +enum { + BIOS32 = '_23_', + SMBIOS = '_MS_', + DMI = '_IMD', +}; + + +static addr_t sBiosBase; +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; +} + + +// #pragma mark - +// public functions + + +/** This function fills the provided bios32_service structure with + * 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; " // set service parameters + "xorl %%ebx, %%ebx; " + "movl %5, %%ecx; " + "pushl %%cs; " // emulate far call by register + "call *%%ecx; " + "movl %%eax, %0; " // save return values + "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) +{ + // map BIOS area 0xe0000 - 0xfffff + area_id biosArea = map_physical_memory("pc bios", (void *)0xe0000, 0x20000, + B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&sBiosBase); + if (biosArea < 0) + return biosArea; + + TRACE(("PC BIOS mapped to %p\n", (void *)sBiosBase)); + + // ToDo: add driver settings support to disable the services below + + // search for available BIOS services + + addr_t base = sBiosBase; + 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 = sBiosBase - 0xe0000 + bios32->service_directory; + } + break; + case SMBIOS: + // SMBIOS contains the legacy DMI structure, so we have to + // make sure it won't be found + base += 16; + TRACE(("probably found SMBIOS structure.\n")); + break; + case DMI: + TRACE(("probably found DMI legacy structure.\n")); + break; + } + + // get on to next "paragraph" + base += 16; + } + + return B_OK; +} +