generic.c revision 6747b715
1/*
2 *                   XFree86 int10 module
3 *   execute BIOS int 10h calls in x86 real mode environment
4 *                 Copyright 1999 Egbert Eich
5 */
6#ifdef HAVE_XORG_CONFIG_H
7#include <xorg-config.h>
8#endif
9
10#include <string.h>
11#include <unistd.h>
12
13#include "xf86.h"
14#include "xf86_OSproc.h"
15#include "compiler.h"
16#define _INT10_PRIVATE
17#include "xf86int10.h"
18#include "int10Defines.h"
19#include "Pci.h"
20
21#define ALLOC_ENTRIES(x) ((V_RAM / x) - 1)
22
23static CARD8 read_b(xf86Int10InfoPtr pInt,int addr);
24static CARD16 read_w(xf86Int10InfoPtr pInt,int addr);
25static CARD32 read_l(xf86Int10InfoPtr pInt,int addr);
26static void write_b(xf86Int10InfoPtr pInt,int addr, CARD8 val);
27static void write_w(xf86Int10InfoPtr pInt,int addr, CARD16 val);
28static void write_l(xf86Int10InfoPtr pInt,int addr, CARD32 val);
29
30/*
31 * the emulator cannot pass a pointer to the current xf86Int10InfoRec
32 * to the memory access functions therefore store it here.
33 */
34
35typedef struct {
36    int shift;
37    int entries;
38    void* base;
39    void* vRam;
40    int highMemory;
41    void* sysMem;
42    char* alloc;
43} genericInt10Priv;
44
45#define INTPriv(x) ((genericInt10Priv*)x->private)
46
47int10MemRec genericMem = {
48    read_b,
49    read_w,
50    read_l,
51    write_b,
52    write_w,
53    write_l
54};
55
56static void MapVRam(xf86Int10InfoPtr pInt);
57static void UnmapVRam(xf86Int10InfoPtr pInt);
58#ifdef _PC
59#define GET_HIGH_BASE(x) (((V_BIOS + (x) + getpagesize() - 1)/getpagesize()) \
60                              * getpagesize())
61#endif
62
63static void *sysMem = NULL;
64
65/**
66 * Read legacy VGA video BIOS associated with specified domain.
67 *
68 * Attempts to read up to 128KiB of legacy VGA video BIOS.
69 *
70 * \return
71 * The number of bytes read on success or -1 on failure.
72 *
73 * \bug
74 * PCI ROMs can contain multiple BIOS images (e.g., OpenFirmware, x86 VGA,
75 * etc.).  How do we know that \c pci_device_read_rom will return the
76 * legacy VGA BIOS image?
77 */
78#ifndef _PC
79static int
80read_legacy_video_BIOS(struct pci_device *dev, unsigned char *Buf)
81{
82    const ADDRESS Base = 0xC0000;
83    const int Len = 0x10000 * 2;
84    const int pagemask = getpagesize() - 1;
85    const ADDRESS offset = Base & ~pagemask;
86    const unsigned long size = ((Base + Len + pagemask) & ~pagemask) - offset;
87    unsigned char *ptr, *src;
88    int len;
89
90
91    /* Try to use the civilized PCI interface first.
92     */
93    if (pci_device_read_rom(dev, Buf) == 0) {
94	return dev->rom_size;
95    }
96
97    ptr = xf86MapDomainMemory(-1, VIDMEM_READONLY, dev, offset, size);
98
99    if (!ptr)
100	return -1;
101
102    /* Using memcpy() here can hang the system */
103    src = ptr + (Base - offset);
104    for (len = 0; len < (Len / 2); len++) {
105	Buf[len] = src[len];
106    }
107
108    if ((Buf[0] == 0x55) && (Buf[1] == 0xAA) && (Buf[2] > 0x80)) {
109	for ( /* empty */ ; len < Len; len++) {
110	    Buf[len] = src[len];
111	}
112    }
113
114    xf86UnMapVidMem(-1, ptr, size);
115
116    return Len;
117}
118#endif /* _PC */
119
120
121xf86Int10InfoPtr
122xf86ExtendedInitInt10(int entityIndex, int Flags)
123{
124    xf86Int10InfoPtr pInt;
125    void* base = 0;
126    void* vbiosMem = 0;
127    void* options = NULL;
128    int screen;
129    legacyVGARec vga;
130
131#if 0
132    CARD32 cs;
133#endif
134
135    screen = (xf86FindScreenForEntity(entityIndex))->scrnIndex;
136
137    options = xf86HandleInt10Options(xf86Screens[screen],entityIndex);
138
139    if (int10skip(options)) {
140	free(options);
141	return NULL;
142    }
143
144    pInt = (xf86Int10InfoPtr)xnfcalloc(1, sizeof(xf86Int10InfoRec));
145    pInt->entityIndex = entityIndex;
146    if (!xf86Int10ExecSetup(pInt))
147	goto error0;
148    pInt->mem = &genericMem;
149    pInt->private = (pointer)xnfcalloc(1, sizeof(genericInt10Priv));
150    INTPriv(pInt)->alloc = (pointer)xnfcalloc(1, ALLOC_ENTRIES(getpagesize()));
151    pInt->scrnIndex = screen;
152    base = INTPriv(pInt)->base = xnfalloc(SYS_BIOS);
153
154    /* FIXME: Shouldn't this be a failure case?  Leaving dev as NULL seems like
155     * FIXME: an error
156     */
157    pInt->dev = xf86GetPciInfoForEntity(entityIndex);
158
159    /*
160     * we need to map video RAM MMIO as some chipsets map mmio
161     * registers into this range.
162     */
163    MapVRam(pInt);
164#ifdef _PC
165    if (!sysMem)
166	sysMem = xf86MapVidMem(screen, VIDMEM_MMIO, V_BIOS,
167			       BIOS_SIZE + SYS_BIOS - V_BIOS);
168    INTPriv(pInt)->sysMem = sysMem;
169
170    if (xf86ReadBIOS(0, 0, base, LOW_PAGE_SIZE) < 0) {
171	xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n");
172	goto error1;
173    }
174
175    /*
176     * Retrieve everything between V_BIOS and SYS_BIOS as some system BIOSes
177     * have executable code there.  Note that xf86ReadBIOS() can only read in
178     * 64kB at a time.
179     */
180    memset((char *)base + V_BIOS, 0, SYS_BIOS - V_BIOS);
181#if 0
182    for (cs = V_BIOS;  cs < SYS_BIOS;  cs += V_BIOS_SIZE)
183	if (xf86ReadBIOS(cs, 0, (unsigned char *)base + cs, V_BIOS_SIZE) <
184		V_BIOS_SIZE)
185	    xf86DrvMsg(screen, X_WARNING,
186		       "Unable to retrieve all of segment 0x%06X.\n", cs);
187#endif
188    INTPriv(pInt)->highMemory = V_BIOS;
189
190    if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) {
191	if (!xf86int10GetBiosSegment(pInt, (unsigned char *)sysMem - V_BIOS))
192	    goto error1;
193
194	set_return_trap(pInt);
195
196	pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
197	if (! (pInt->Flags & SET_BIOS_SCRATCH))
198	    pInt->Flags &= ~RESTORE_BIOS_SCRATCH;
199	xf86Int10SaveRestoreBIOSVars(pInt, TRUE);
200
201    } else {
202	const BusType location_type = xf86int10GetBiosLocationType(pInt);
203	int bios_location = V_BIOS;
204
205        reset_int_vect(pInt);
206	set_return_trap(pInt);
207
208	switch (location_type) {
209	case BUS_PCI: {
210	    int err;
211	    struct pci_device *rom_device =
212		xf86GetPciInfoForEntity(pInt->entityIndex);
213
214	    vbiosMem = (unsigned char *)base + bios_location;
215	    err = pci_device_read_rom(rom_device, vbiosMem);
216	    if (err) {
217		xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (3) %s\n",
218			   strerror(err));
219		goto error1;
220	    }
221	    INTPriv(pInt)->highMemory = GET_HIGH_BASE(rom_device->rom_size);
222	    break;
223	}
224	default:
225	    goto error1;
226	}
227	pInt->BIOSseg = V_BIOS >> 4;
228	pInt->num = 0xe6;
229	LockLegacyVGA(pInt, &vga);
230	xf86ExecX86int10(pInt);
231	UnlockLegacyVGA(pInt, &vga);
232    }
233#else
234    if (!sysMem) {
235	sysMem = xnfalloc(BIOS_SIZE);
236	setup_system_bios(sysMem);
237    }
238    INTPriv(pInt)->sysMem = sysMem;
239    setup_int_vect(pInt);
240    set_return_trap(pInt);
241
242    /* Retrieve the entire legacy video BIOS segment.  This can be upto
243     * 128KiB.
244     */
245    vbiosMem = (char *)base + V_BIOS;
246    memset(vbiosMem, 0, 2 * V_BIOS_SIZE);
247    if (read_legacy_video_BIOS(pInt->dev, vbiosMem) < V_BIOS_SIZE) {
248	xf86DrvMsg(screen, X_WARNING,
249		   "Unable to retrieve all of segment 0x0C0000.\n");
250    }
251
252    /*
253     * If this adapter is the primary, use its post-init BIOS (if we can find
254     * it).
255     */
256    {
257	int bios_location = V_BIOS;
258	Bool done = FALSE;
259	vbiosMem = (unsigned char *)base + bios_location;
260
261	if (xf86IsEntityPrimary(entityIndex)) {
262	    if (int10_check_bios(screen, bios_location >> 4, vbiosMem))
263		done = TRUE;
264	    else
265		xf86DrvMsg(screen,X_INFO,
266			"No legacy BIOS found -- trying PCI\n");
267	}
268	if (!done) {
269	    int err;
270	    struct pci_device *rom_device =
271		xf86GetPciInfoForEntity(pInt->entityIndex);
272
273	    err = pci_device_read_rom(rom_device, vbiosMem);
274	    if (err) {
275		xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (5) %s\n",
276			   strerror(err));
277		goto error1;
278	    }
279	}
280    }
281
282    pInt->BIOSseg = V_BIOS >> 4;
283    pInt->num = 0xe6;
284    LockLegacyVGA(pInt, &vga);
285    xf86ExecX86int10(pInt);
286    UnlockLegacyVGA(pInt, &vga);
287#endif
288    free(options);
289    return pInt;
290
291 error1:
292    free(base);
293    UnmapVRam(pInt);
294    free(INTPriv(pInt)->alloc);
295    free(pInt->private);
296 error0:
297    free(pInt);
298    free(options);
299
300    return NULL;
301}
302
303static void
304MapVRam(xf86Int10InfoPtr pInt)
305{
306    int pagesize = getpagesize();
307    int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize;
308
309    INTPriv(pInt)->vRam = xf86MapDomainMemory(pInt->scrnIndex, VIDMEM_MMIO,
310					      pInt->dev, V_RAM, size);
311
312    pInt->ioBase = xf86Screens[pInt->scrnIndex]->domainIOBase;
313}
314
315static void
316UnmapVRam(xf86Int10InfoPtr pInt)
317{
318    int screen = pInt->scrnIndex;
319    int pagesize = getpagesize();
320    int size = ((VRAM_SIZE + pagesize - 1)/pagesize) * pagesize;
321
322    xf86UnMapVidMem(screen, INTPriv(pInt)->vRam, size);
323}
324
325Bool
326MapCurrentInt10(xf86Int10InfoPtr pInt)
327{
328    /* nothing to do here */
329    return TRUE;
330}
331
332void
333xf86FreeInt10(xf86Int10InfoPtr pInt)
334{
335    if (!pInt)
336      return;
337#if defined (_PC)
338    xf86Int10SaveRestoreBIOSVars(pInt, FALSE);
339#endif
340    if (Int10Current == pInt)
341	Int10Current = NULL;
342    free(INTPriv(pInt)->base);
343    UnmapVRam(pInt);
344    free(INTPriv(pInt)->alloc);
345    free(pInt->private);
346    free(pInt);
347}
348
349void *
350xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off)
351{
352    int pagesize = getpagesize();
353    int num_pages = ALLOC_ENTRIES(pagesize);
354    int i,j;
355
356    for (i = 0; i < (num_pages - num); i++) {
357	if (INTPriv(pInt)->alloc[i] == 0) {
358	    for (j = i; j < (num + i); j++)
359		if (INTPriv(pInt)->alloc[j] != 0)
360		    break;
361	    if (j == (num + i))
362		break;
363	    i += num;
364	}
365    }
366    if (i == (num_pages - num))
367	return NULL;
368
369    for (j = i; j < (i + num); j++)
370	INTPriv(pInt)->alloc[j] = 1;
371
372    *off = (i + 1) * pagesize;
373
374    return (char *)INTPriv(pInt)->base + *off;
375}
376
377void
378xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num)
379{
380    int pagesize = getpagesize();
381    int first = (((char *)pbase - (char *)INTPriv(pInt)->base) / pagesize) - 1;
382    int i;
383
384    for (i = first; i < (first + num); i++)
385	INTPriv(pInt)->alloc[i] = 0;
386}
387
388#define OFF(addr) ((addr) & 0xffff)
389#if defined _PC
390# define HIGH_OFFSET (INTPriv(pInt)->highMemory)
391# define HIGH_BASE   V_BIOS
392#else
393# define HIGH_OFFSET SYS_BIOS
394# define HIGH_BASE   SYS_BIOS
395#endif
396# define SYS(addr) ((addr) >= HIGH_OFFSET)
397#define V_ADDR(addr) \
398	  (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \
399	   : (((char*)(INTPriv(pInt)->base) + addr)))
400#define VRAM_ADDR(addr) (addr - V_RAM)
401#define VRAM_BASE (INTPriv(pInt)->vRam)
402
403#define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE)))
404#define V_ADDR_RB(addr) \
405	(VRAM(addr)) ? MMIO_IN8((CARD8*)VRAM_BASE,VRAM_ADDR(addr)) \
406	   : *(CARD8*) V_ADDR(addr)
407#define V_ADDR_RW(addr) \
408	(VRAM(addr)) ? MMIO_IN16((CARD16*)VRAM_BASE,VRAM_ADDR(addr)) \
409	   : ldw_u((pointer)V_ADDR(addr))
410#define V_ADDR_RL(addr) \
411	(VRAM(addr)) ? MMIO_IN32((CARD32*)VRAM_BASE,VRAM_ADDR(addr)) \
412	   : ldl_u((pointer)V_ADDR(addr))
413
414#define V_ADDR_WB(addr,val) \
415	if(VRAM(addr)) \
416	    MMIO_OUT8((CARD8*)VRAM_BASE,VRAM_ADDR(addr),val); \
417	else \
418	    *(CARD8*) V_ADDR(addr) = val;
419#define V_ADDR_WW(addr,val) \
420	if(VRAM(addr)) \
421	    MMIO_OUT16((CARD16*)VRAM_BASE,VRAM_ADDR(addr),val); \
422	else \
423	    stw_u((val),(pointer)(V_ADDR(addr)));
424
425#define V_ADDR_WL(addr,val) \
426	if (VRAM(addr)) \
427	    MMIO_OUT32((CARD32*)VRAM_BASE,VRAM_ADDR(addr),val); \
428	else \
429	    stl_u(val,(pointer)(V_ADDR(addr)));
430
431static CARD8
432read_b(xf86Int10InfoPtr pInt, int addr)
433{
434    return V_ADDR_RB(addr);
435}
436
437static CARD16
438read_w(xf86Int10InfoPtr pInt, int addr)
439{
440#if X_BYTE_ORDER == X_LITTLE_ENDIAN
441    if (OFF(addr + 1) > 0)
442	return V_ADDR_RW(addr);
443#endif
444    return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8);
445}
446
447static CARD32
448read_l(xf86Int10InfoPtr pInt, int addr)
449{
450#if X_BYTE_ORDER == X_LITTLE_ENDIAN
451    if (OFF(addr + 3) > 2)
452	return V_ADDR_RL(addr);
453#endif
454    return V_ADDR_RB(addr) |
455	   (V_ADDR_RB(addr + 1) << 8) |
456	   (V_ADDR_RB(addr + 2) << 16) |
457	   (V_ADDR_RB(addr + 3) << 24);
458}
459
460static void
461write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val)
462{
463    V_ADDR_WB(addr,val);
464}
465
466static void
467write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val)
468{
469#if X_BYTE_ORDER == X_LITTLE_ENDIAN
470    if (OFF(addr + 1) > 0)
471      { V_ADDR_WW(addr, val); }
472#endif
473    V_ADDR_WB(addr, val);
474    V_ADDR_WB(addr + 1, val >> 8);
475}
476
477static void
478write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val)
479{
480#if X_BYTE_ORDER == X_LITTLE_ENDIAN
481    if (OFF(addr + 3) > 2)
482      { V_ADDR_WL(addr, val); }
483#endif
484    V_ADDR_WB(addr, val);
485    V_ADDR_WB(addr + 1, val >> 8);
486    V_ADDR_WB(addr + 2, val >> 16);
487    V_ADDR_WB(addr + 3, val >> 24);
488}
489
490pointer
491xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr)
492{
493    return V_ADDR(addr);
494}
495