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 (unsigned long)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
149    pInt->mem = &genericMem;
150    pInt->private = (pointer)xnfcalloc(1, sizeof(genericInt10Priv));
151    INTPriv(pInt)->alloc = (pointer)xnfcalloc(1, ALLOC_ENTRIES(getpagesize()));
152    pInt->scrnIndex = screen;
153    base = INTPriv(pInt)->base = xnfalloc(SYS_BIOS);
154
155    /* FIXME: Shouldn't this be a failure case?  Leaving dev as NULL seems like
156     * FIXME: an error
157     */
158
159   pInt->dev = xf86GetPciInfoForEntity(entityIndex);
160
161    /*
162     * we need to map video RAM MMIO as some chipsets map mmio
163     * registers into this range.
164     */
165    MapVRam(pInt);
166#ifdef _PC
167    if (!sysMem)
168	sysMem = xf86MapVidMem(screen, VIDMEM_MMIO, V_BIOS,
169			       BIOS_SIZE + SYS_BIOS - V_BIOS);
170    INTPriv(pInt)->sysMem = sysMem;
171
172    if (xf86ReadBIOS(0, 0, base, LOW_PAGE_SIZE) < 0) {
173	xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n");
174	goto error1;
175    }
176
177    /*
178     * Retrieve everything between V_BIOS and SYS_BIOS as some system BIOSes
179     * have executable code there.  Note that xf86ReadBIOS() can only read in
180     * 64kB at a time.
181     */
182    memset((char *)base + V_BIOS, 0, SYS_BIOS - V_BIOS);
183#if 0
184    for (cs = V_BIOS;  cs < SYS_BIOS;  cs += V_BIOS_SIZE)
185	if (xf86ReadBIOS(cs, 0, (unsigned char *)base + cs, V_BIOS_SIZE) <
186		V_BIOS_SIZE)
187	    xf86DrvMsg(screen, X_WARNING,
188		       "Unable to retrieve all of segment 0x%06X.\n", cs);
189#endif
190    INTPriv(pInt)->highMemory = V_BIOS;
191
192    if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) {
193	if (!xf86int10GetBiosSegment(pInt, (unsigned char *)sysMem - V_BIOS))
194	    goto error1;
195
196	set_return_trap(pInt);
197
198	pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
199	if (! (pInt->Flags & SET_BIOS_SCRATCH))
200	    pInt->Flags &= ~RESTORE_BIOS_SCRATCH;
201	xf86Int10SaveRestoreBIOSVars(pInt, TRUE);
202
203    } else {
204	const BusType location_type = xf86int10GetBiosLocationType(pInt);
205	int bios_location = V_BIOS;
206
207        reset_int_vect(pInt);
208	set_return_trap(pInt);
209
210	switch (location_type) {
211	case BUS_PCI: {
212	    int err;
213	    struct pci_device *rom_device =
214		xf86GetPciInfoForEntity(pInt->entityIndex);
215
216	    vbiosMem = (unsigned char *)base + bios_location;
217	    err = pci_device_read_rom(rom_device, vbiosMem);
218	    if (err) {
219		xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (3) %s\n",
220			   strerror(err));
221		goto error1;
222	    }
223	    INTPriv(pInt)->highMemory = GET_HIGH_BASE(rom_device->rom_size);
224	    break;
225	}
226	default:
227	    goto error1;
228	}
229	pInt->BIOSseg = V_BIOS >> 4;
230	pInt->num = 0xe6;
231	LockLegacyVGA(pInt, &vga);
232	xf86ExecX86int10(pInt);
233	UnlockLegacyVGA(pInt, &vga);
234    }
235#else
236    if (!sysMem) {
237	sysMem = xnfalloc(BIOS_SIZE);
238	setup_system_bios(sysMem);
239    }
240    INTPriv(pInt)->sysMem = sysMem;
241    setup_int_vect(pInt);
242    set_return_trap(pInt);
243
244    /* Retrieve the entire legacy video BIOS segment.  This can be upto
245     * 128KiB.
246     */
247    vbiosMem = (char *)base + V_BIOS;
248    memset(vbiosMem, 0, 2 * V_BIOS_SIZE);
249    if (read_legacy_video_BIOS(pInt->dev, vbiosMem) < V_BIOS_SIZE) {
250	xf86DrvMsg(screen, X_WARNING,
251		   "Unable to retrieve all of segment 0x0C0000.\n");
252    }
253
254    /*
255     * If this adapter is the primary, use its post-init BIOS (if we can find
256     * it).
257     */
258    {
259	int bios_location = V_BIOS;
260	Bool done = FALSE;
261	vbiosMem = (unsigned char *)base + bios_location;
262
263	if (xf86IsEntityPrimary(entityIndex)) {
264	    if (int10_check_bios(screen, bios_location >> 4, vbiosMem))
265		done = TRUE;
266	    else
267		xf86DrvMsg(screen,X_INFO,
268			"No legacy BIOS found -- trying PCI\n");
269	}
270
271	if (!done) {
272	    int err;
273	    struct pci_device *rom_device =
274		xf86GetPciInfoForEntity(pInt->entityIndex);
275
276	    err = pci_device_read_rom(rom_device, vbiosMem);
277
278	    if (err) {
279		xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (5) %s\n",
280			   strerror(err));
281		goto error1;
282	    }
283	    if (!int10_check_bios(screen, bios_location >> 4, vbiosMem)) {
284	        xf86Msg(X_INFO, "No BIOS found\n");
285		goto error1;
286	    }
287	}
288    }
289
290    pInt->BIOSseg = V_BIOS >> 4;
291    pInt->num = 0xe6;
292    LockLegacyVGA(pInt, &vga);
293    xf86ExecX86int10(pInt);
294    UnlockLegacyVGA(pInt, &vga);
295#endif
296    free(options);
297    return pInt;
298
299 error1:
300    free(base);
301    UnmapVRam(pInt);
302    free(INTPriv(pInt)->alloc);
303    free(pInt->private);
304 error0:
305    free(pInt);
306    free(options);
307
308    return NULL;
309}
310
311static void
312MapVRam(xf86Int10InfoPtr pInt)
313{
314    int pagesize = getpagesize();
315    int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize;
316
317    INTPriv(pInt)->vRam = xf86MapDomainMemory(pInt->scrnIndex, VIDMEM_MMIO,
318					      pInt->dev, V_RAM, size);
319
320    pInt->ioBase = xf86Screens[pInt->scrnIndex]->domainIOBase;
321}
322
323static void
324UnmapVRam(xf86Int10InfoPtr pInt)
325{
326    int screen = pInt->scrnIndex;
327    int pagesize = getpagesize();
328    int size = ((VRAM_SIZE + pagesize - 1)/pagesize) * pagesize;
329
330    xf86UnMapVidMem(screen, INTPriv(pInt)->vRam, size);
331}
332
333Bool
334MapCurrentInt10(xf86Int10InfoPtr pInt)
335{
336    /* nothing to do here */
337    return TRUE;
338}
339
340void
341xf86FreeInt10(xf86Int10InfoPtr pInt)
342{
343    if (!pInt)
344      return;
345#if defined (_PC)
346    xf86Int10SaveRestoreBIOSVars(pInt, FALSE);
347#endif
348    if (Int10Current == pInt)
349	Int10Current = NULL;
350    free(INTPriv(pInt)->base);
351    UnmapVRam(pInt);
352    free(INTPriv(pInt)->alloc);
353    free(pInt->private);
354    free(pInt);
355}
356
357void *
358xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off)
359{
360    int pagesize = getpagesize();
361    int num_pages = ALLOC_ENTRIES(pagesize);
362    int i,j;
363
364    for (i = 0; i < (num_pages - num); i++) {
365	if (INTPriv(pInt)->alloc[i] == 0) {
366	    for (j = i; j < (num + i); j++)
367		if (INTPriv(pInt)->alloc[j] != 0)
368		    break;
369	    if (j == (num + i))
370		break;
371	    i += num;
372	}
373    }
374    if (i == (num_pages - num))
375	return NULL;
376
377    for (j = i; j < (i + num); j++)
378	INTPriv(pInt)->alloc[j] = 1;
379
380    *off = (i + 1) * pagesize;
381
382    return (char *)INTPriv(pInt)->base + *off;
383}
384
385void
386xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num)
387{
388    int pagesize = getpagesize();
389    int first = (((char *)pbase - (char *)INTPriv(pInt)->base) / pagesize) - 1;
390    int i;
391
392    for (i = first; i < (first + num); i++)
393	INTPriv(pInt)->alloc[i] = 0;
394}
395
396#define OFF(addr) ((addr) & 0xffff)
397#if defined _PC
398# define HIGH_OFFSET (INTPriv(pInt)->highMemory)
399# define HIGH_BASE   V_BIOS
400#else
401# define HIGH_OFFSET SYS_BIOS
402# define HIGH_BASE   SYS_BIOS
403#endif
404# define SYS(addr) ((addr) >= HIGH_OFFSET)
405#define V_ADDR(addr) \
406	  (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \
407	   : (((char*)(INTPriv(pInt)->base) + addr)))
408#define VRAM_ADDR(addr) (addr - V_RAM)
409#define VRAM_BASE (INTPriv(pInt)->vRam)
410
411#define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE)))
412#define V_ADDR_RB(addr) \
413	(VRAM(addr)) ? MMIO_IN8((CARD8*)VRAM_BASE,VRAM_ADDR(addr)) \
414	   : *(CARD8*) V_ADDR(addr)
415#define V_ADDR_RW(addr) \
416	(VRAM(addr)) ? MMIO_IN16((CARD16*)VRAM_BASE,VRAM_ADDR(addr)) \
417	   : ldw_u((pointer)V_ADDR(addr))
418#define V_ADDR_RL(addr) \
419	(VRAM(addr)) ? MMIO_IN32((CARD32*)VRAM_BASE,VRAM_ADDR(addr)) \
420	   : ldl_u((pointer)V_ADDR(addr))
421
422#define V_ADDR_WB(addr,val) \
423	if(VRAM(addr)) \
424	    MMIO_OUT8((CARD8*)VRAM_BASE,VRAM_ADDR(addr),val); \
425	else \
426	    *(CARD8*) V_ADDR(addr) = val;
427#define V_ADDR_WW(addr,val) \
428	if(VRAM(addr)) \
429	    MMIO_OUT16((CARD16*)VRAM_BASE,VRAM_ADDR(addr),val); \
430	else \
431	    stw_u((val),(pointer)(V_ADDR(addr)));
432
433#define V_ADDR_WL(addr,val) \
434	if (VRAM(addr)) \
435	    MMIO_OUT32((CARD32*)VRAM_BASE,VRAM_ADDR(addr),val); \
436	else \
437	    stl_u(val,(pointer)(V_ADDR(addr)));
438
439static CARD8
440read_b(xf86Int10InfoPtr pInt, int addr)
441{
442    return V_ADDR_RB(addr);
443}
444
445static CARD16
446read_w(xf86Int10InfoPtr pInt, int addr)
447{
448#if X_BYTE_ORDER == X_LITTLE_ENDIAN
449    if (OFF(addr + 1) > 0)
450	return V_ADDR_RW(addr);
451#endif
452    return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8);
453}
454
455static CARD32
456read_l(xf86Int10InfoPtr pInt, int addr)
457{
458#if X_BYTE_ORDER == X_LITTLE_ENDIAN
459    if (OFF(addr + 3) > 2)
460	return V_ADDR_RL(addr);
461#endif
462    return V_ADDR_RB(addr) |
463	   (V_ADDR_RB(addr + 1) << 8) |
464	   (V_ADDR_RB(addr + 2) << 16) |
465	   (V_ADDR_RB(addr + 3) << 24);
466}
467
468static void
469write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val)
470{
471    V_ADDR_WB(addr,val);
472}
473
474static void
475write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val)
476{
477#if X_BYTE_ORDER == X_LITTLE_ENDIAN
478    if (OFF(addr + 1) > 0)
479      { V_ADDR_WW(addr, val); }
480#endif
481    V_ADDR_WB(addr, val);
482    V_ADDR_WB(addr + 1, val >> 8);
483}
484
485static void
486write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val)
487{
488#if X_BYTE_ORDER == X_LITTLE_ENDIAN
489    if (OFF(addr + 3) > 2)
490      { V_ADDR_WL(addr, val); }
491#endif
492    V_ADDR_WB(addr, val);
493    V_ADDR_WB(addr + 1, val >> 8);
494    V_ADDR_WB(addr + 2, val >> 16);
495    V_ADDR_WB(addr + 3, val >> 24);
496}
497
498pointer
499xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr)
500{
501    return V_ADDR(addr);
502}
503