1*4ebc6dfaSAlex Smith /* 2*4ebc6dfaSAlex Smith * Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3*4ebc6dfaSAlex Smith * Distributed under the terms of the MIT License. 4*4ebc6dfaSAlex Smith */ 5*4ebc6dfaSAlex Smith 6*4ebc6dfaSAlex Smith 7*4ebc6dfaSAlex Smith #include <KernelExport.h> 8*4ebc6dfaSAlex Smith #include <vm/vm_types.h> 9*4ebc6dfaSAlex Smith 10*4ebc6dfaSAlex Smith #include <arch/x86/bios.h> 11*4ebc6dfaSAlex Smith 12*4ebc6dfaSAlex Smith 13*4ebc6dfaSAlex Smith //#define TRACE_BIOS 14*4ebc6dfaSAlex Smith #ifdef TRACE_BIOS 15*4ebc6dfaSAlex Smith # define TRACE(x) dprintf x 16*4ebc6dfaSAlex Smith #else 17*4ebc6dfaSAlex Smith # define TRACE(x) ; 18*4ebc6dfaSAlex Smith #endif 19*4ebc6dfaSAlex Smith 20*4ebc6dfaSAlex Smith 21*4ebc6dfaSAlex Smith struct smbios { 22*4ebc6dfaSAlex Smith uint32 anchor_string; 23*4ebc6dfaSAlex Smith uint8 entry_point_checksum; 24*4ebc6dfaSAlex Smith uint8 entry_point_length; 25*4ebc6dfaSAlex Smith struct { 26*4ebc6dfaSAlex Smith uint8 major; 27*4ebc6dfaSAlex Smith uint8 minor; 28*4ebc6dfaSAlex Smith } version; 29*4ebc6dfaSAlex Smith uint16 maximum_size; 30*4ebc6dfaSAlex Smith uint8 formatted_area[5]; 31*4ebc6dfaSAlex Smith 32*4ebc6dfaSAlex Smith // this part is the legacy DMI compatible structure 33*4ebc6dfaSAlex Smith uint8 dmi_anchor_string[5]; 34*4ebc6dfaSAlex Smith uint8 intermediate_checksum; 35*4ebc6dfaSAlex Smith uint16 structure_table_size; 36*4ebc6dfaSAlex Smith uint32 structure_table; 37*4ebc6dfaSAlex Smith uint16 num_structures; 38*4ebc6dfaSAlex Smith uint8 bcd_revision; 39*4ebc6dfaSAlex Smith } _PACKED; 40*4ebc6dfaSAlex Smith 41*4ebc6dfaSAlex Smith struct bios32 { 42*4ebc6dfaSAlex Smith uint32 anchor_string; 43*4ebc6dfaSAlex Smith uint32 service_directory; 44*4ebc6dfaSAlex Smith uint8 revision; 45*4ebc6dfaSAlex Smith uint8 size; // in "paragraph" (16 byte) units 46*4ebc6dfaSAlex Smith uint8 checksum; 47*4ebc6dfaSAlex Smith uint8 _reserved[5]; 48*4ebc6dfaSAlex Smith }; 49*4ebc6dfaSAlex Smith 50*4ebc6dfaSAlex Smith enum { 51*4ebc6dfaSAlex Smith BIOS32 = '_23_', 52*4ebc6dfaSAlex Smith SMBIOS = '_MS_', 53*4ebc6dfaSAlex Smith DMI = '_IMD', 54*4ebc6dfaSAlex Smith }; 55*4ebc6dfaSAlex Smith 56*4ebc6dfaSAlex Smith 57*4ebc6dfaSAlex Smith addr_t gBiosBase; 58*4ebc6dfaSAlex Smith static addr_t sBios32ServiceDirectory; 59*4ebc6dfaSAlex Smith 60*4ebc6dfaSAlex Smith 61*4ebc6dfaSAlex Smith static bool 62*4ebc6dfaSAlex Smith check_checksum(addr_t base, size_t length) 63*4ebc6dfaSAlex Smith { 64*4ebc6dfaSAlex Smith uint8 *bytes = (uint8 *)base; 65*4ebc6dfaSAlex Smith uint8 sum = 0; 66*4ebc6dfaSAlex Smith 67*4ebc6dfaSAlex Smith for (uint32 i = 0; i < length; i++) 68*4ebc6dfaSAlex Smith sum += bytes[i]; 69*4ebc6dfaSAlex Smith 70*4ebc6dfaSAlex Smith return sum == 0; 71*4ebc6dfaSAlex Smith } 72*4ebc6dfaSAlex Smith 73*4ebc6dfaSAlex Smith 74*4ebc6dfaSAlex Smith // #pragma mark - 75*4ebc6dfaSAlex Smith // public functions 76*4ebc6dfaSAlex Smith 77*4ebc6dfaSAlex Smith 78*4ebc6dfaSAlex Smith /** This function fills the provided bios32_service structure with 79*4ebc6dfaSAlex Smith * the values that identify BIOS service. 80*4ebc6dfaSAlex Smith * Returns B_OK on successful completion, otherwise B_ERROR if 81*4ebc6dfaSAlex Smith * the BIOS32 service directory is not available, or B_BAD_VALUE 82*4ebc6dfaSAlex Smith * in case the identifier is not known or present. 83*4ebc6dfaSAlex Smith */ 84*4ebc6dfaSAlex Smith 85*4ebc6dfaSAlex Smith extern "C" status_t 86*4ebc6dfaSAlex Smith get_bios32_service(uint32 identifier, struct bios32_service *service) 87*4ebc6dfaSAlex Smith { 88*4ebc6dfaSAlex Smith TRACE(("get_bios32_service(identifier = %#lx)\n", identifier)); 89*4ebc6dfaSAlex Smith 90*4ebc6dfaSAlex Smith if (sBios32ServiceDirectory == 0) 91*4ebc6dfaSAlex Smith return B_ERROR; 92*4ebc6dfaSAlex Smith 93*4ebc6dfaSAlex Smith uint32 eax = 0, ebx = 0, ecx = 0, edx = 0; 94*4ebc6dfaSAlex Smith 95*4ebc6dfaSAlex Smith asm("movl %4, %%eax; " // set service parameters 96*4ebc6dfaSAlex Smith "xorl %%ebx, %%ebx; " 97*4ebc6dfaSAlex Smith "movl %5, %%ecx; " 98*4ebc6dfaSAlex Smith "pushl %%cs; " // emulate far call by register 99*4ebc6dfaSAlex Smith "call *%%ecx; " 100*4ebc6dfaSAlex Smith "movl %%eax, %0; " // save return values 101*4ebc6dfaSAlex Smith "movl %%ebx, %1; " 102*4ebc6dfaSAlex Smith "movl %%ecx, %2; " 103*4ebc6dfaSAlex Smith "movl %%edx, %3; " 104*4ebc6dfaSAlex Smith : "=m" (eax), "=m" (ebx), "=m" (ecx), "=m" (edx) 105*4ebc6dfaSAlex Smith : "m" (identifier), "m" (sBios32ServiceDirectory) 106*4ebc6dfaSAlex Smith : "eax", "ebx", "ecx", "edx", "memory"); 107*4ebc6dfaSAlex Smith 108*4ebc6dfaSAlex Smith if ((eax & 0xff) != 0) 109*4ebc6dfaSAlex Smith return B_BAD_VALUE; 110*4ebc6dfaSAlex Smith 111*4ebc6dfaSAlex Smith service->base = ebx; 112*4ebc6dfaSAlex Smith service->size = ecx; 113*4ebc6dfaSAlex Smith service->offset = edx; 114*4ebc6dfaSAlex Smith 115*4ebc6dfaSAlex Smith return B_OK; 116*4ebc6dfaSAlex Smith } 117*4ebc6dfaSAlex Smith 118*4ebc6dfaSAlex Smith 119*4ebc6dfaSAlex Smith extern "C" status_t 120*4ebc6dfaSAlex Smith bios_init(void) 121*4ebc6dfaSAlex Smith { 122*4ebc6dfaSAlex Smith // map BIOS area 0xe0000 - 0xfffff 123*4ebc6dfaSAlex Smith area_id biosArea = map_physical_memory("pc bios", 0xe0000, 0x20000, 124*4ebc6dfaSAlex Smith B_ANY_KERNEL_ADDRESS | B_MTR_WB, 125*4ebc6dfaSAlex Smith B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&gBiosBase); 126*4ebc6dfaSAlex Smith if (biosArea < 0) 127*4ebc6dfaSAlex Smith return biosArea; 128*4ebc6dfaSAlex Smith 129*4ebc6dfaSAlex Smith TRACE(("PC BIOS mapped to %p\n", (void *)gBiosBase)); 130*4ebc6dfaSAlex Smith 131*4ebc6dfaSAlex Smith // ToDo: add driver settings support to disable the services below 132*4ebc6dfaSAlex Smith 133*4ebc6dfaSAlex Smith // search for available BIOS services 134*4ebc6dfaSAlex Smith 135*4ebc6dfaSAlex Smith addr_t base = gBiosBase; 136*4ebc6dfaSAlex Smith addr_t end = base + 0x20000; 137*4ebc6dfaSAlex Smith 138*4ebc6dfaSAlex Smith while (base < end) { 139*4ebc6dfaSAlex Smith switch (*(uint32 *)base) { 140*4ebc6dfaSAlex Smith case BIOS32: 141*4ebc6dfaSAlex Smith if (check_checksum(base, sizeof(struct bios32))) { 142*4ebc6dfaSAlex Smith struct bios32 *bios32 = (struct bios32 *)base; 143*4ebc6dfaSAlex Smith 144*4ebc6dfaSAlex Smith TRACE(("bios32 revision %d\n", bios32->revision)); 145*4ebc6dfaSAlex Smith TRACE(("bios32 service directory at: %lx\n", bios32->service_directory)); 146*4ebc6dfaSAlex Smith 147*4ebc6dfaSAlex Smith if (bios32->service_directory >= 0xe0000 148*4ebc6dfaSAlex Smith && bios32->service_directory <= 0xfffff) 149*4ebc6dfaSAlex Smith sBios32ServiceDirectory = gBiosBase - 0xe0000 + bios32->service_directory; 150*4ebc6dfaSAlex Smith } 151*4ebc6dfaSAlex Smith break; 152*4ebc6dfaSAlex Smith case SMBIOS: 153*4ebc6dfaSAlex Smith // SMBIOS contains the legacy DMI structure, so we have to 154*4ebc6dfaSAlex Smith // make sure it won't be found 155*4ebc6dfaSAlex Smith base += 16; 156*4ebc6dfaSAlex Smith TRACE(("probably found SMBIOS structure.\n")); 157*4ebc6dfaSAlex Smith break; 158*4ebc6dfaSAlex Smith case DMI: 159*4ebc6dfaSAlex Smith TRACE(("probably found DMI legacy structure.\n")); 160*4ebc6dfaSAlex Smith break; 161*4ebc6dfaSAlex Smith } 162*4ebc6dfaSAlex Smith 163*4ebc6dfaSAlex Smith // get on to next "paragraph" 164*4ebc6dfaSAlex Smith base += 16; 165*4ebc6dfaSAlex Smith } 166*4ebc6dfaSAlex Smith 167*4ebc6dfaSAlex Smith return B_OK; 168*4ebc6dfaSAlex Smith } 169*4ebc6dfaSAlex Smith 170