xref: /aosp_15_r20/external/coreboot/util/vgabios/device.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 
3 #include <stdtypes.h>
4 
5 #include <arch/byteorder.h>
6 #include "device.h"
7 #include "compat/rtas.h"
8 #include <string.h>
9 #include "debug.h"
10 
11 #include <device/device.h>
12 #include <device/pci.h>
13 #include <device/pci_ops.h>
14 
15 /* the device we are working with... */
16 biosemu_device_t bios_device;
17 //max. 6 BARs and 1 Exp.ROM plus CfgSpace and 3 legacy ranges, plus 2 "special" memory ranges
18 translate_address_t translate_address_array[13];
19 u8 taa_last_entry;
20 
21 typedef struct {
22 	u8 info;
23 	u8 bus;
24 	u8 devfn;
25 	u8 cfg_space_offset;
26 	u64 address;
27 	u64 size;
28 } __attribute__ ((__packed__)) assigned_address_t;
29 
30 #if CONFIG_PCI_OPTION_ROM_RUN_YABEL
31 /* coreboot version */
32 
33 static void
biosemu_dev_get_addr_info(void)34 biosemu_dev_get_addr_info(void)
35 {
36 #if 0
37 	int taa_index = 0;
38 	struct resource *r;
39 	u8 bus = bios_device.dev->bus->secondary;
40 	u16 devfn = bios_device.dev->path.pci.devfn;
41 
42 	bios_device.bus =  bus;
43 	bios_device.devfn = devfn;
44 
45 	DEBUG_PRINTF("bus: %x, devfn: %x\n", bus, devfn);
46 	for (r = bios_device.dev->resource_list; r; r = r->next) {
47 		translate_address_array[taa_index].info = r->flags;
48 		translate_address_array[taa_index].bus = bus;
49 		translate_address_array[taa_index].devfn = devfn;
50 		translate_address_array[taa_index].cfg_space_offset =
51 		    r->index;
52 		translate_address_array[taa_index].address = r->base;
53 		translate_address_array[taa_index].size = r->size;
54 		/* don't translate addresses... all addresses are 1:1 */
55 		translate_address_array[taa_index].address_offset = 0;
56 		taa_index++;
57 	}
58 	/* Expansion ROM */
59 	translate_address_array[taa_index].info = IORESOURCE_MEM | IORESOURCE_READONLY;
60 	translate_address_array[taa_index].bus = bus;
61 	translate_address_array[taa_index].devfn = devfn;
62 	translate_address_array[taa_index].cfg_space_offset = 0x30;
63 	translate_address_array[taa_index].address = bios_device.img_addr;
64 	translate_address_array[taa_index].size = 0; /* TODO: do we need the size? */
65 	/* don't translate addresses... all addresses are 1:1 */
66 	translate_address_array[taa_index].address_offset = 0;
67 	taa_index++;
68 	/* legacy ranges if its a VGA card... */
69 	if ((bios_device.dev->class & 0xFF0000) == 0x030000) {
70 		DEBUG_PRINTF("%s: VGA device found, adding legacy resources..."
71 			     "\n", __func__);
72 		/* I/O 0x3B0-0x3BB */
73 		translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_IO;
74 		translate_address_array[taa_index].bus = bus;
75 		translate_address_array[taa_index].devfn = devfn;
76 		translate_address_array[taa_index].cfg_space_offset = 0;
77 		translate_address_array[taa_index].address = 0x3b0;
78 		translate_address_array[taa_index].size = 0xc;
79 		/* don't translate addresses... all addresses are 1:1 */
80 		translate_address_array[taa_index].address_offset = 0;
81 		taa_index++;
82 		/* I/O 0x3C0-0x3DF */
83 		translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_IO;
84 		translate_address_array[taa_index].bus = bus;
85 		translate_address_array[taa_index].devfn = devfn;
86 		translate_address_array[taa_index].cfg_space_offset = 0;
87 		translate_address_array[taa_index].address = 0x3c0;
88 		translate_address_array[taa_index].size = 0x20;
89 		/* don't translate addresses... all addresses are 1:1 */
90 		translate_address_array[taa_index].address_offset = 0;
91 		taa_index++;
92 		/* Mem 0xA0000-0xBFFFF */
93 		translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_MEM;
94 		translate_address_array[taa_index].bus = bus;
95 		translate_address_array[taa_index].devfn = devfn;
96 		translate_address_array[taa_index].cfg_space_offset = 0;
97 		translate_address_array[taa_index].address = 0xa0000;
98 		translate_address_array[taa_index].size = 0x20000;
99 		/* don't translate addresses... all addresses are 1:1 */
100 		translate_address_array[taa_index].address_offset = 0;
101 		taa_index++;
102 	}
103 	// store last entry index of translate_address_array
104 	taa_last_entry = taa_index - 1;
105 #if CONFIG_X86EMU_DEBUG
106 	//dump translate_address_array
107 	printf("translate_address_array:\n");
108 	translate_address_t ta;
109 	int i;
110 	for (i = 0; i <= taa_last_entry; i++) {
111 		ta = translate_address_array[i];
112 		printf
113 		    ("%d: info: %08lx bus: %02x devfn: %02x cfg_space_offset: %02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
114 		     i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
115 		     ta.address, ta.address_offset, ta.size);
116 	}
117 #endif
118 #endif
119 }
120 #else
121 // use translate_address_dev and get_puid from net-snk's net_support.c
122 void translate_address_dev(u64 *, phandle_t);
123 u64 get_puid(phandle_t node);
124 
125 
126 // scan all addresses assigned to the device ("assigned-addresses" and "reg")
127 // store in translate_address_array for faster translation using dev_translate_address
128 void
biosemu_dev_get_addr_info(void)129 biosemu_dev_get_addr_info(void)
130 {
131 	// get bus/dev/fn from assigned-addresses
132 	int32_t len;
133 	//max. 6 BARs and 1 Exp.ROM plus CfgSpace and 3 legacy ranges
134 	assigned_address_t buf[11];
135 	len =
136 	    of_getprop(bios_device.phandle, "assigned-addresses", buf,
137 		       sizeof(buf));
138 	bios_device.bus = buf[0].bus;
139 	bios_device.devfn = buf[0].devfn;
140 	DEBUG_PRINTF("bus: %x, devfn: %x\n", bios_device.bus,
141 		     bios_device.devfn);
142 	//store address translations for all assigned-addresses and regs in
143 	//translate_address_array for faster translation later on...
144 	int i = 0;
145 	// index to insert data into translate_address_array
146 	int taa_index = 0;
147 	u64 address_offset;
148 	for (i = 0; i < (len / sizeof(assigned_address_t)); i++, taa_index++) {
149 		//copy all info stored in assigned-addresses
150 		translate_address_array[taa_index].info = buf[i].info;
151 		translate_address_array[taa_index].bus = buf[i].bus;
152 		translate_address_array[taa_index].devfn = buf[i].devfn;
153 		translate_address_array[taa_index].cfg_space_offset =
154 		    buf[i].cfg_space_offset;
155 		translate_address_array[taa_index].address = buf[i].address;
156 		translate_address_array[taa_index].size = buf[i].size;
157 		// translate first address and store it as address_offset
158 		address_offset = buf[i].address;
159 		translate_address_dev(&address_offset, bios_device.phandle);
160 		translate_address_array[taa_index].address_offset =
161 		    address_offset - buf[i].address;
162 	}
163 	//get "reg" property
164 	len = of_getprop(bios_device.phandle, "reg", buf, sizeof(buf));
165 	for (i = 0; i < (len / sizeof(assigned_address_t)); i++) {
166 		if ((buf[i].size == 0) || (buf[i].cfg_space_offset != 0)) {
167 			// we don't care for ranges with size 0 and
168 			// BARs and Expansion ROM must be in assigned-addresses... so in reg
169 			// we only look for those without config space offset set...
170 			// i.e. the legacy ranges
171 			continue;
172 		}
173 		//copy all info stored in assigned-addresses
174 		translate_address_array[taa_index].info = buf[i].info;
175 		translate_address_array[taa_index].bus = buf[i].bus;
176 		translate_address_array[taa_index].devfn = buf[i].devfn;
177 		translate_address_array[taa_index].cfg_space_offset =
178 		    buf[i].cfg_space_offset;
179 		translate_address_array[taa_index].address = buf[i].address;
180 		translate_address_array[taa_index].size = buf[i].size;
181 		// translate first address and store it as address_offset
182 		address_offset = buf[i].address;
183 		translate_address_dev(&address_offset, bios_device.phandle);
184 		translate_address_array[taa_index].address_offset =
185 		    address_offset - buf[i].address;
186 		taa_index++;
187 	}
188 	// store last entry index of translate_address_array
189 	taa_last_entry = taa_index - 1;
190 #if CONFIG_X86EMU_DEBUG
191 	//dump translate_address_array
192 	printf("translate_address_array:\n");
193 	translate_address_t ta;
194 	for (i = 0; i <= taa_last_entry; i++) {
195 		ta = translate_address_array[i];
196 		printf
197 		    ("%d: %02x%02x%02x%02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
198 		     i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
199 		     ta.address, ta.address_offset, ta.size);
200 	}
201 #endif
202 }
203 #endif
204 
205 // "special memory" is a hack to make some parts of memory fall through to real memory
206 // (ie. no translation). Necessary if option ROMs attempt DMA there, map registers or
207 // do similarly crazy things.
208 void
biosemu_add_special_memory(u32 start,u32 size)209 biosemu_add_special_memory(u32 start, u32 size)
210 {
211 #if 0
212 	int taa_index = ++taa_last_entry;
213 	translate_address_array[taa_index].info = IORESOURCE_FIXED | IORESOURCE_MEM;
214 	translate_address_array[taa_index].bus = 0;
215 	translate_address_array[taa_index].devfn = 0;
216 	translate_address_array[taa_index].cfg_space_offset = 0;
217 	translate_address_array[taa_index].address = start;
218 	translate_address_array[taa_index].size = size;
219 	/* don't translate addresses... all addresses are 1:1 */
220 	translate_address_array[taa_index].address_offset = 0;
221 #endif
222 	printf("TODO: Add special memory handler for %x[%x]\n", start, size);
223 }
224 
225 #if !CONFIG_PCI_OPTION_ROM_RUN_YABEL
226 // to simulate accesses to legacy VGA Memory (0xA0000-0xBFFFF)
227 // we look for the first prefetchable memory BAR, if no prefetchable BAR found,
228 // we use the first memory BAR
229 // dev_translate_addr will translate accesses to the legacy VGA Memory into the found vmem BAR
230 static void
biosemu_dev_find_vmem_addr(void)231 biosemu_dev_find_vmem_addr(void)
232 {
233 	int i = 0;
234 	translate_address_t ta;
235 	s8 tai_np = -1, tai_p = -1;	// translate_address_array index for non-prefetchable and prefetchable memory
236 	//search backwards to find first entry
237 	for (i = taa_last_entry; i >= 0; i--) {
238 		ta = translate_address_array[i];
239 		if ((ta.cfg_space_offset >= 0x10)
240 		    && (ta.cfg_space_offset <= 0x24)) {
241 			//only BARs
242 			if ((ta.info & 0x03) >= 0x02) {
243 				//32/64bit memory
244 				tai_np = i;
245 				if ((ta.info & 0x40) != 0) {
246 					// prefetchable
247 					tai_p = i;
248 				}
249 			}
250 		}
251 	}
252 	if (tai_p != -1) {
253 		ta = translate_address_array[tai_p];
254 		bios_device.vmem_addr = ta.address;
255 		bios_device.vmem_size = ta.size;
256 		DEBUG_PRINTF
257 		    ("%s: Found prefetchable Virtual Legacy Memory BAR: %llx, size: %llx\n",
258 		     __func__, bios_device.vmem_addr,
259 		     bios_device.vmem_size);
260 	} else if (tai_np != -1) {
261 		ta = translate_address_array[tai_np];
262 		bios_device.vmem_addr = ta.address;
263 		bios_device.vmem_size = ta.size;
264 		DEBUG_PRINTF
265 		    ("%s: Found non-prefetchable Virtual Legacy Memory BAR: %llx, size: %llx",
266 		     __func__, bios_device.vmem_addr,
267 		     bios_device.vmem_size);
268 	}
269 	// disable vmem
270 	//bios_device.vmem_size = 0;
271 }
272 
273 void
biosemu_dev_get_puid(void)274 biosemu_dev_get_puid(void)
275 {
276 	// get puid
277 	bios_device.puid = get_puid(bios_device.phandle);
278 	DEBUG_PRINTF("puid: 0x%llx\n", bios_device.puid);
279 }
280 #endif
281 
282 static void
biosemu_dev_get_device_vendor_id(void)283 biosemu_dev_get_device_vendor_id(void)
284 {
285 
286 	u32 pci_config_0;
287 #if CONFIG_PCI_OPTION_ROM_RUN_YABEL
288 	pci_config_0 = pci_read_config32(bios_device.dev, 0x0);
289 #else
290 	pci_config_0 =
291 	    rtas_pci_config_read(bios_device.puid, 4, bios_device.bus,
292 				 bios_device.devfn, 0x0);
293 #endif
294 	bios_device.pci_device_id =
295 	    (u16) ((pci_config_0 & 0xFFFF0000) >> 16);
296 	bios_device.pci_vendor_id = (u16) (pci_config_0 & 0x0000FFFF);
297 	DEBUG_PRINTF("PCI Device ID: %04x, PCI Vendor ID: %x\n",
298 		     bios_device.pci_device_id, bios_device.pci_vendor_id);
299 }
300 
301 /* Check whether the device has a valid Expansion ROM and search the PCI Data
302  * Structure and any Expansion ROM Header (using dev_scan_exp_header()) for
303  * needed information.  If the rom_addr parameter is != 0, it is the address of
304  * the Expansion ROM image and will be used, if it is == 0, the Expansion ROM
305  * BAR address will be used.
306  */
307 u8
biosemu_dev_check_exprom(unsigned long rom_base_addr)308 biosemu_dev_check_exprom(unsigned long rom_base_addr)
309 {
310 #if 0
311 	int i = 0;
312 	translate_address_t ta;
313 	u16 pci_ds_offset;
314 	pci_data_struct_t pci_ds;
315 	if (rom_base_addr == 0) {
316 		// check for ExpROM Address (Offset 30) in taa
317 		for (i = 0; i <= taa_last_entry; i++) {
318 			ta = translate_address_array[i];
319 			if (ta.cfg_space_offset == 0x30) {
320 				//translated address
321 				rom_base_addr = ta.address + ta.address_offset;
322 				break;
323 			}
324 		}
325 	}
326 	/* In the ROM there could be multiple Expansion ROM Images... start
327 	 * searching them for an x86 image.
328 	 */
329 	do {
330 		if (rom_base_addr == 0) {
331 			printf("Error: no Expansion ROM address found!\n");
332 			return -1;
333 		}
334 		set_ci();
335 		u16 rom_signature = in16le((void *) rom_base_addr);
336 		clr_ci();
337 		if (rom_signature != 0xaa55) {
338 			printf
339 			    ("Error: invalid Expansion ROM signature: %02x!\n",
340 			     *((u16 *) rom_base_addr));
341 			return -1;
342 		}
343 		set_ci();
344 		// at offset 0x18 is the (16bit little-endian) pointer to the PCI Data Structure
345 		pci_ds_offset = in16le((void *) (rom_base_addr + 0x18));
346 		//copy the PCI Data Structure
347 		memcpy(&pci_ds, (void *) (rom_base_addr + pci_ds_offset),
348 		       sizeof(pci_ds));
349 		clr_ci();
350 #if CONFIG_X86EMU_DEBUG
351 		DEBUG_PRINTF("PCI Data Structure @%lx:\n",
352 			     rom_base_addr + pci_ds_offset);
353 		dump((void *) &pci_ds, sizeof(pci_ds));
354 #endif
355 		if (strncmp((const char *) pci_ds.signature, "PCIR", 4) != 0) {
356 			printf("Invalid PCI Data Structure found!\n");
357 			break;
358 		}
359 		//little-endian conversion
360 		pci_ds.vendor_id = in16le(&pci_ds.vendor_id);
361 		pci_ds.device_id = in16le(&pci_ds.device_id);
362 		pci_ds.img_length = in16le(&pci_ds.img_length);
363 		pci_ds.pci_ds_length = in16le(&pci_ds.pci_ds_length);
364 #ifdef DO_THIS_TEST_TWICE
365 		if (pci_ds.vendor_id != bios_device.pci_vendor_id) {
366 			printf
367 			    ("Image has invalid Vendor ID: %04x, expected: %04x\n",
368 			     pci_ds.vendor_id, bios_device.pci_vendor_id);
369 			break;
370 		}
371 		if (pci_ds.device_id != bios_device.pci_device_id) {
372 			printf
373 			    ("Image has invalid Device ID: %04x, expected: %04x\n",
374 			     pci_ds.device_id, bios_device.pci_device_id);
375 			break;
376 		}
377 #endif
378 		DEBUG_PRINTF("Image Length: %d\n", pci_ds.img_length * 512);
379 		DEBUG_PRINTF("Image Code Type: %d\n", pci_ds.code_type);
380 		if (pci_ds.code_type == 0) {
381 			//x86 image
382 			//store image address and image length in bios_device struct
383 			bios_device.img_addr = rom_base_addr;
384 			bios_device.img_size = pci_ds.img_length * 512;
385 			// we found the image, exit the loop
386 			break;
387 		} else {
388 			// no x86 image, check next image (if any)
389 			rom_base_addr += pci_ds.img_length * 512;
390 		}
391 		if ((pci_ds.indicator & 0x80) == 0x80) {
392 			//last image found, exit the loop
393 			DEBUG_PRINTF("Last PCI Expansion ROM Image found.\n");
394 			break;
395 		}
396 	}
397 	while (bios_device.img_addr == 0);
398 	// in case we did not find a valid x86 Expansion ROM Image
399 	if (bios_device.img_addr == 0) {
400 		printf("Error: no valid x86 Expansion ROM Image found!\n");
401 		return -1;
402 	}
403 #endif
404 	return 0;
405 
406 }
407 
408 u8
biosemu_dev_init(struct device * device)409 biosemu_dev_init(struct device * device)
410 {
411 	u8 rval = 0;
412 	//init bios_device struct
413 	DEBUG_PRINTF("%s\n", __func__);
414 	memset(&bios_device, 0, sizeof(bios_device));
415 
416 #if !CONFIG_PCI_OPTION_ROM_RUN_YABEL
417 	bios_device.ihandle = of_open(device_name);
418 	if (bios_device.ihandle == 0) {
419 		DEBUG_PRINTF("%s is no valid device!\n", device_name);
420 		return -1;
421 	}
422 	bios_device.phandle = of_finddevice(device_name);
423 #else
424 	bios_device.dev = device;
425 #endif
426 	biosemu_dev_get_addr_info();
427 #if !CONFIG_PCI_OPTION_ROM_RUN_YABEL
428 	biosemu_dev_find_vmem_addr();
429 	biosemu_dev_get_puid();
430 #endif
431 	biosemu_dev_get_device_vendor_id();
432 	return rval;
433 }
434 
435 // translate address function using translate_address_array assembled
436 // by dev_get_addr_info... MUCH faster than calling translate_address_dev
437 // and accessing client interface for every translation...
438 // returns: 0 if addr not found in translate_address_array, 1 if found.
439 u8
biosemu_dev_translate_address(int type,unsigned long * addr)440 biosemu_dev_translate_address(int type, unsigned long * addr)
441 {
442 	int i = 0;
443 	translate_address_t ta;
444 #if !CONFIG_PCI_OPTION_ROM_RUN_YABEL
445 	/* we don't need this hack for coreboot... we can access legacy areas */
446 	//check if it is an access to legacy VGA Mem... if it is, map the address
447 	//to the vmem BAR and then translate it...
448 	// (translation info provided by Ben Herrenschmidt)
449 	// NOTE: the translation seems to only work for NVIDIA cards... but it is needed
450 	// to make some NVIDIA cards work at all...
451 	if ((bios_device.vmem_size > 0)
452 	    && ((*addr >= 0xA0000) && (*addr < 0xB8000))) {
453 		*addr = (*addr - 0xA0000) * 4 + 2 + bios_device.vmem_addr;
454 	}
455 	if ((bios_device.vmem_size > 0)
456 	    && ((*addr >= 0xB8000) && (*addr < 0xC0000))) {
457 		u8 shift = *addr & 1;
458 		*addr &= 0xfffffffe;
459 		*addr = (*addr - 0xB8000) * 4 + shift + bios_device.vmem_addr;
460 	}
461 #endif
462 	for (i = 0; i <= taa_last_entry; i++) {
463 		ta = translate_address_array[i];
464 		if ((*addr >= ta.address) && (*addr <= (ta.address + ta.size)) && (ta.info & type)) {
465 			*addr += ta.address_offset;
466 			return 1;
467 		}
468 	}
469 	return 0;
470 }
471