14ebc6dfaSAlex Smith /*
24ebc6dfaSAlex Smith * Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
34ebc6dfaSAlex Smith * Distributed under the terms of the MIT License.
44ebc6dfaSAlex Smith */
54ebc6dfaSAlex Smith
64ebc6dfaSAlex Smith
74ebc6dfaSAlex Smith #include <KernelExport.h>
84ebc6dfaSAlex Smith #include <vm/vm_types.h>
94ebc6dfaSAlex Smith
104ebc6dfaSAlex Smith #include <arch/x86/bios.h>
114ebc6dfaSAlex Smith
124ebc6dfaSAlex Smith
134ebc6dfaSAlex Smith //#define TRACE_BIOS
144ebc6dfaSAlex Smith #ifdef TRACE_BIOS
154ebc6dfaSAlex Smith # define TRACE(x) dprintf x
164ebc6dfaSAlex Smith #else
174ebc6dfaSAlex Smith # define TRACE(x) ;
184ebc6dfaSAlex Smith #endif
194ebc6dfaSAlex Smith
204ebc6dfaSAlex Smith
214ebc6dfaSAlex Smith struct smbios {
224ebc6dfaSAlex Smith uint32 anchor_string;
234ebc6dfaSAlex Smith uint8 entry_point_checksum;
244ebc6dfaSAlex Smith uint8 entry_point_length;
254ebc6dfaSAlex Smith struct {
264ebc6dfaSAlex Smith uint8 major;
274ebc6dfaSAlex Smith uint8 minor;
284ebc6dfaSAlex Smith } version;
294ebc6dfaSAlex Smith uint16 maximum_size;
304ebc6dfaSAlex Smith uint8 formatted_area[5];
314ebc6dfaSAlex Smith
324ebc6dfaSAlex Smith // this part is the legacy DMI compatible structure
334ebc6dfaSAlex Smith uint8 dmi_anchor_string[5];
344ebc6dfaSAlex Smith uint8 intermediate_checksum;
354ebc6dfaSAlex Smith uint16 structure_table_size;
364ebc6dfaSAlex Smith uint32 structure_table;
374ebc6dfaSAlex Smith uint16 num_structures;
384ebc6dfaSAlex Smith uint8 bcd_revision;
394ebc6dfaSAlex Smith } _PACKED;
404ebc6dfaSAlex Smith
414ebc6dfaSAlex Smith struct bios32 {
424ebc6dfaSAlex Smith uint32 anchor_string;
434ebc6dfaSAlex Smith uint32 service_directory;
444ebc6dfaSAlex Smith uint8 revision;
454ebc6dfaSAlex Smith uint8 size; // in "paragraph" (16 byte) units
464ebc6dfaSAlex Smith uint8 checksum;
474ebc6dfaSAlex Smith uint8 _reserved[5];
484ebc6dfaSAlex Smith };
494ebc6dfaSAlex Smith
504ebc6dfaSAlex Smith enum {
514ebc6dfaSAlex Smith BIOS32 = '_23_',
524ebc6dfaSAlex Smith SMBIOS = '_MS_',
534ebc6dfaSAlex Smith DMI = '_IMD',
544ebc6dfaSAlex Smith };
554ebc6dfaSAlex Smith
564ebc6dfaSAlex Smith
574ebc6dfaSAlex Smith addr_t gBiosBase;
584ebc6dfaSAlex Smith static addr_t sBios32ServiceDirectory;
594ebc6dfaSAlex Smith
604ebc6dfaSAlex Smith
614ebc6dfaSAlex Smith static bool
check_checksum(addr_t base,size_t length)624ebc6dfaSAlex Smith check_checksum(addr_t base, size_t length)
634ebc6dfaSAlex Smith {
644ebc6dfaSAlex Smith uint8 *bytes = (uint8 *)base;
654ebc6dfaSAlex Smith uint8 sum = 0;
664ebc6dfaSAlex Smith
674ebc6dfaSAlex Smith for (uint32 i = 0; i < length; i++)
684ebc6dfaSAlex Smith sum += bytes[i];
694ebc6dfaSAlex Smith
704ebc6dfaSAlex Smith return sum == 0;
714ebc6dfaSAlex Smith }
724ebc6dfaSAlex Smith
734ebc6dfaSAlex Smith
744ebc6dfaSAlex Smith // #pragma mark -
754ebc6dfaSAlex Smith // public functions
764ebc6dfaSAlex Smith
774ebc6dfaSAlex Smith
784ebc6dfaSAlex Smith /** This function fills the provided bios32_service structure with
794ebc6dfaSAlex Smith * the values that identify BIOS service.
804ebc6dfaSAlex Smith * Returns B_OK on successful completion, otherwise B_ERROR if
814ebc6dfaSAlex Smith * the BIOS32 service directory is not available, or B_BAD_VALUE
824ebc6dfaSAlex Smith * in case the identifier is not known or present.
834ebc6dfaSAlex Smith */
844ebc6dfaSAlex Smith
854ebc6dfaSAlex Smith extern "C" status_t
get_bios32_service(uint32 identifier,struct bios32_service * service)864ebc6dfaSAlex Smith get_bios32_service(uint32 identifier, struct bios32_service *service)
874ebc6dfaSAlex Smith {
884ebc6dfaSAlex Smith TRACE(("get_bios32_service(identifier = %#lx)\n", identifier));
894ebc6dfaSAlex Smith
904ebc6dfaSAlex Smith if (sBios32ServiceDirectory == 0)
914ebc6dfaSAlex Smith return B_ERROR;
924ebc6dfaSAlex Smith
934ebc6dfaSAlex Smith uint32 eax = 0, ebx = 0, ecx = 0, edx = 0;
944ebc6dfaSAlex Smith
954ebc6dfaSAlex Smith asm("movl %4, %%eax; " // set service parameters
964ebc6dfaSAlex Smith "xorl %%ebx, %%ebx; "
974ebc6dfaSAlex Smith "movl %5, %%ecx; "
984ebc6dfaSAlex Smith "pushl %%cs; " // emulate far call by register
994ebc6dfaSAlex Smith "call *%%ecx; "
1004ebc6dfaSAlex Smith "movl %%eax, %0; " // save return values
1014ebc6dfaSAlex Smith "movl %%ebx, %1; "
1024ebc6dfaSAlex Smith "movl %%ecx, %2; "
1034ebc6dfaSAlex Smith "movl %%edx, %3; "
1044ebc6dfaSAlex Smith : "=m" (eax), "=m" (ebx), "=m" (ecx), "=m" (edx)
1054ebc6dfaSAlex Smith : "m" (identifier), "m" (sBios32ServiceDirectory)
1064ebc6dfaSAlex Smith : "eax", "ebx", "ecx", "edx", "memory");
1074ebc6dfaSAlex Smith
1084ebc6dfaSAlex Smith if ((eax & 0xff) != 0)
1094ebc6dfaSAlex Smith return B_BAD_VALUE;
1104ebc6dfaSAlex Smith
1114ebc6dfaSAlex Smith service->base = ebx;
1124ebc6dfaSAlex Smith service->size = ecx;
1134ebc6dfaSAlex Smith service->offset = edx;
1144ebc6dfaSAlex Smith
1154ebc6dfaSAlex Smith return B_OK;
1164ebc6dfaSAlex Smith }
1174ebc6dfaSAlex Smith
1184ebc6dfaSAlex Smith
1194ebc6dfaSAlex Smith extern "C" status_t
bios_init(void)1204ebc6dfaSAlex Smith bios_init(void)
1214ebc6dfaSAlex Smith {
1224ebc6dfaSAlex Smith // map BIOS area 0xe0000 - 0xfffff
1234ebc6dfaSAlex Smith area_id biosArea = map_physical_memory("pc bios", 0xe0000, 0x20000,
124*5c1f2319SAugustin Cavalier B_ANY_KERNEL_ADDRESS | B_WRITE_BACK_MEMORY,
1254ebc6dfaSAlex Smith B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gBiosBase);
1264ebc6dfaSAlex Smith if (biosArea < 0)
1274ebc6dfaSAlex Smith return biosArea;
1284ebc6dfaSAlex Smith
1294ebc6dfaSAlex Smith TRACE(("PC BIOS mapped to %p\n", (void *)gBiosBase));
1304ebc6dfaSAlex Smith
1314ebc6dfaSAlex Smith // ToDo: add driver settings support to disable the services below
1324ebc6dfaSAlex Smith
1334ebc6dfaSAlex Smith // search for available BIOS services
1344ebc6dfaSAlex Smith
1354ebc6dfaSAlex Smith addr_t base = gBiosBase;
1364ebc6dfaSAlex Smith addr_t end = base + 0x20000;
1374ebc6dfaSAlex Smith
1384ebc6dfaSAlex Smith while (base < end) {
1394ebc6dfaSAlex Smith switch (*(uint32 *)base) {
1404ebc6dfaSAlex Smith case BIOS32:
1414ebc6dfaSAlex Smith if (check_checksum(base, sizeof(struct bios32))) {
1424ebc6dfaSAlex Smith struct bios32 *bios32 = (struct bios32 *)base;
1434ebc6dfaSAlex Smith
1444ebc6dfaSAlex Smith TRACE(("bios32 revision %d\n", bios32->revision));
1454ebc6dfaSAlex Smith TRACE(("bios32 service directory at: %lx\n", bios32->service_directory));
1464ebc6dfaSAlex Smith
1474ebc6dfaSAlex Smith if (bios32->service_directory >= 0xe0000
1484ebc6dfaSAlex Smith && bios32->service_directory <= 0xfffff)
1494ebc6dfaSAlex Smith sBios32ServiceDirectory = gBiosBase - 0xe0000 + bios32->service_directory;
1504ebc6dfaSAlex Smith }
1514ebc6dfaSAlex Smith break;
1524ebc6dfaSAlex Smith case SMBIOS:
1534ebc6dfaSAlex Smith // SMBIOS contains the legacy DMI structure, so we have to
1544ebc6dfaSAlex Smith // make sure it won't be found
1554ebc6dfaSAlex Smith base += 16;
1564ebc6dfaSAlex Smith TRACE(("probably found SMBIOS structure.\n"));
1574ebc6dfaSAlex Smith break;
1584ebc6dfaSAlex Smith case DMI:
1594ebc6dfaSAlex Smith TRACE(("probably found DMI legacy structure.\n"));
1604ebc6dfaSAlex Smith break;
1614ebc6dfaSAlex Smith }
1624ebc6dfaSAlex Smith
1634ebc6dfaSAlex Smith // get on to next "paragraph"
1644ebc6dfaSAlex Smith base += 16;
1654ebc6dfaSAlex Smith }
1664ebc6dfaSAlex Smith
1674ebc6dfaSAlex Smith return B_OK;
1684ebc6dfaSAlex Smith }
1694ebc6dfaSAlex Smith
170