xref: /haiku/src/system/kernel/arch/x86/32/bios.cpp (revision 4ebc6dfa682fa199a88ec06f0930df04369f34ac)
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