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