generic.c revision 05b261ec
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
20#define ALLOC_ENTRIES(x) ((V_RAM / x) - 1)
21
22static CARD8 read_b(xf86Int10InfoPtr pInt,int addr);
23static CARD16 read_w(xf86Int10InfoPtr pInt,int addr);
24static CARD32 read_l(xf86Int10InfoPtr pInt,int addr);
25static void write_b(xf86Int10InfoPtr pInt,int addr, CARD8 val);
26static void write_w(xf86Int10InfoPtr pInt,int addr, CARD16 val);
27static void write_l(xf86Int10InfoPtr pInt,int addr, CARD32 val);
28
29/*
30 * the emulator cannot pass a pointer to the current xf86Int10InfoRec
31 * to the memory access functions therefore store it here.
32 */
33
34typedef struct {
35    int shift;
36    int entries;
37    void* base;
38    void* vRam;
39    int highMemory;
40    void* sysMem;
41    char* alloc;
42} genericInt10Priv;
43
44#define INTPriv(x) ((genericInt10Priv*)x->private)
45
46int10MemRec genericMem = {
47    read_b,
48    read_w,
49    read_l,
50    write_b,
51    write_w,
52    write_l
53};
54
55static void MapVRam(xf86Int10InfoPtr pInt);
56static void UnmapVRam(xf86Int10InfoPtr pInt);
57#ifdef _PC
58#define GET_HIGH_BASE(x) (((V_BIOS + size + getpagesize() - 1)/getpagesize()) \
59                             * getpagesize())
60#endif
61
62static void *sysMem = NULL;
63
64xf86Int10InfoPtr
65xf86ExtendedInitInt10(int entityIndex, int Flags)
66{
67    xf86Int10InfoPtr pInt;
68    void* base = 0;
69    void* vbiosMem = 0;
70    void* options = NULL;
71    pciVideoPtr pvp;
72    int screen;
73    legacyVGARec vga;
74
75#ifdef _PC
76    int size;
77    CARD32 cs;
78#endif
79
80    screen = (xf86FindScreenForEntity(entityIndex))->scrnIndex;
81
82    options = xf86HandleInt10Options(xf86Screens[screen],entityIndex);
83
84    if (int10skip(options)) {
85	xfree(options);
86	return NULL;
87    }
88
89    pInt = (xf86Int10InfoPtr)xnfcalloc(1, sizeof(xf86Int10InfoRec));
90    pInt->entityIndex = entityIndex;
91    if (!xf86Int10ExecSetup(pInt))
92	goto error0;
93    pInt->mem = &genericMem;
94    pInt->private = (pointer)xnfcalloc(1, sizeof(genericInt10Priv));
95    INTPriv(pInt)->alloc = (pointer)xnfcalloc(1, ALLOC_ENTRIES(getpagesize()));
96    pInt->scrnIndex = screen;
97    base = INTPriv(pInt)->base = xnfalloc(SYS_BIOS);
98
99    pvp = xf86GetPciInfoForEntity(entityIndex);
100    if (pvp) pInt->Tag = pciTag(pvp->bus, pvp->device, pvp->func);
101
102    /*
103     * we need to map video RAM MMIO as some chipsets map mmio
104     * registers into this range.
105     */
106    MapVRam(pInt);
107#ifdef _PC
108    if (!sysMem)
109	sysMem = xf86MapVidMem(screen, VIDMEM_MMIO, V_BIOS,
110			       BIOS_SIZE + SYS_BIOS - V_BIOS);
111    INTPriv(pInt)->sysMem = sysMem;
112
113    if (xf86ReadBIOS(0, 0, base, LOW_PAGE_SIZE) < 0) {
114	xf86DrvMsg(screen, X_ERROR, "Cannot read int vect\n");
115	goto error1;
116    }
117
118    /*
119     * Retrieve everything between V_BIOS and SYS_BIOS as some system BIOSes
120     * have executable code there.  Note that xf86ReadBIOS() can only read in
121     * 64kB at a time.
122     */
123    (void)memset((char *)base + V_BIOS, 0, SYS_BIOS - V_BIOS);
124#if 0
125    for (cs = V_BIOS;  cs < SYS_BIOS;  cs += V_BIOS_SIZE)
126	if (xf86ReadBIOS(cs, 0, (unsigned char *)base + cs, V_BIOS_SIZE) <
127		V_BIOS_SIZE)
128	    xf86DrvMsg(screen, X_WARNING,
129		       "Unable to retrieve all of segment 0x%06X.\n", cs);
130#endif
131    INTPriv(pInt)->highMemory = V_BIOS;
132
133    if (xf86IsEntityPrimary(entityIndex) && !(initPrimary(options))) {
134	if (!xf86int10GetBiosSegment(pInt, (unsigned char *)sysMem - V_BIOS))
135	    goto error1;
136
137	set_return_trap(pInt);
138
139	pInt->Flags = Flags & (SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
140	if (! (pInt->Flags & SET_BIOS_SCRATCH))
141	    pInt->Flags &= ~RESTORE_BIOS_SCRATCH;
142	xf86Int10SaveRestoreBIOSVars(pInt, TRUE);
143
144    } else {
145	const BusType location_type = xf86int10GetBiosLocationType(pInt);
146	int bios_location = V_BIOS;
147
148        reset_int_vect(pInt);
149	set_return_trap(pInt);
150
151	switch (location_type) {
152	case BUS_PCI: {
153	    const int pci_entity = pInt->entityIndex;
154
155	    vbiosMem = (unsigned char *)base + bios_location;
156	    if (!(size = mapPciRom(pci_entity,(unsigned char *)(vbiosMem)))) {
157		xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (3)\n");
158		goto error1;
159	    }
160	    INTPriv(pInt)->highMemory = GET_HIGH_BASE(size);
161	    break;
162	}
163	case BUS_ISA:
164	    vbiosMem = (unsigned char *)sysMem + bios_location;
165#if 0
166	    (void)memset(vbiosMem, 0, V_BIOS_SIZE);
167	    if (xf86ReadBIOS(bios_location, 0, vbiosMem, V_BIOS_SIZE)
168		< V_BIOS_SIZE)
169		xf86DrvMsg(screen, X_WARNING,
170		    "Unable to retrieve all of segment 0x%x.\n",bios_location);
171#endif
172	    if (!int10_check_bios(screen, bios_location >> 4, vbiosMem)) {
173	        xf86DrvMsg(screen,X_ERROR,"Cannot read V_BIOS (4)\n");
174		goto error1;
175	    }
176	default:
177	    goto error1;
178	}
179	pInt->BIOSseg = V_BIOS >> 4;
180	pInt->num = 0xe6;
181	LockLegacyVGA(pInt, &vga);
182	xf86ExecX86int10(pInt);
183	UnlockLegacyVGA(pInt, &vga);
184    }
185#else
186    if (!sysMem) {
187	sysMem = xnfalloc(BIOS_SIZE);
188	setup_system_bios(sysMem);
189    }
190    INTPriv(pInt)->sysMem = sysMem;
191    setup_int_vect(pInt);
192    set_return_trap(pInt);
193
194    /*
195     * Retrieve two segments:  one at V_BIOS, the other 64kB beyond the first.
196     * This'll catch any BIOS that might have been initialised before server
197     * entry.
198     */
199    vbiosMem = (char *)base + V_BIOS;
200    (void)memset(vbiosMem, 0, 2 * V_BIOS_SIZE);
201    if (xf86ReadDomainMemory(pInt->Tag, V_BIOS, V_BIOS_SIZE, vbiosMem) <
202	V_BIOS_SIZE)
203	xf86DrvMsg(screen, X_WARNING,
204	    "Unable to retrieve all of segment 0x0C0000.\n");
205    else if ((((unsigned char *)vbiosMem)[0] == 0x55) &&
206	     (((unsigned char *)vbiosMem)[1] == 0xAA) &&
207	     (((unsigned char *)vbiosMem)[2] > 0x80))
208    if (xf86ReadDomainMemory(pInt->Tag, V_BIOS + V_BIOS_SIZE, V_BIOS_SIZE,
209	    (unsigned char *)vbiosMem + V_BIOS_SIZE) < V_BIOS_SIZE)
210	xf86DrvMsg(screen, X_WARNING,
211	    "Unable to retrieve all of segment 0x0D0000.\n");
212
213    /*
214     * If this adapter is the primary, use its post-init BIOS (if we can find
215     * it).
216     */
217    {
218	int bios_location = V_BIOS;
219	Bool done = FALSE;
220	vbiosMem = (unsigned char *)base + bios_location;
221
222	if (xf86IsEntityPrimary(entityIndex)) {
223	    if (int10_check_bios(screen, bios_location >> 4, vbiosMem))
224		done = TRUE;
225	    else
226		xf86DrvMsg(screen,X_INFO,
227			"No legacy BIOS found -- trying PCI\n");
228	}
229	if (!done) {
230	    if (!mapPciRom(pInt->entityIndex, vbiosMem)) {
231		    xf86DrvMsg(screen, X_ERROR, "Cannot read V_BIOS (5)\n");
232		    goto error1;
233	    }
234	}
235    }
236
237    pInt->BIOSseg = V_BIOS >> 4;
238    pInt->num = 0xe6;
239    LockLegacyVGA(pInt, &vga);
240    xf86ExecX86int10(pInt);
241    UnlockLegacyVGA(pInt, &vga);
242#endif
243    xfree(options);
244    return pInt;
245
246 error1:
247    xfree(base);
248    UnmapVRam(pInt);
249    xfree(INTPriv(pInt)->alloc);
250    xfree(pInt->private);
251 error0:
252    xfree(pInt);
253    xfree(options);
254
255    return NULL;
256}
257
258static void
259MapVRam(xf86Int10InfoPtr pInt)
260{
261    int pagesize = getpagesize();
262    int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize;
263
264    INTPriv(pInt)->vRam = xf86MapDomainMemory(pInt->scrnIndex, VIDMEM_MMIO,
265					      pInt->Tag, V_RAM, size);
266
267    pInt->ioBase = xf86Screens[pInt->scrnIndex]->domainIOBase;
268}
269
270static void
271UnmapVRam(xf86Int10InfoPtr pInt)
272{
273    int screen = pInt->scrnIndex;
274    int pagesize = getpagesize();
275    int size = ((VRAM_SIZE + pagesize - 1)/pagesize) * pagesize;
276
277    xf86UnMapVidMem(screen, INTPriv(pInt)->vRam, size);
278}
279
280Bool
281MapCurrentInt10(xf86Int10InfoPtr pInt)
282{
283    /* nothing to do here */
284    return TRUE;
285}
286
287void
288xf86FreeInt10(xf86Int10InfoPtr pInt)
289{
290    if (!pInt)
291      return;
292#if defined (_PC)
293    xf86Int10SaveRestoreBIOSVars(pInt, FALSE);
294#endif
295    if (Int10Current == pInt)
296	Int10Current = NULL;
297    xfree(INTPriv(pInt)->base);
298    UnmapVRam(pInt);
299    xfree(INTPriv(pInt)->alloc);
300    xfree(pInt->private);
301    xfree(pInt);
302}
303
304void *
305xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off)
306{
307    int pagesize = getpagesize();
308    int num_pages = ALLOC_ENTRIES(pagesize);
309    int i,j;
310
311    for (i = 0; i < (num_pages - num); i++) {
312	if (INTPriv(pInt)->alloc[i] == 0) {
313	    for (j = i; j < (num + i); j++)
314		if (INTPriv(pInt)->alloc[j] != 0)
315		    break;
316	    if (j == (num + i))
317		break;
318	    i += num;
319	}
320    }
321    if (i == (num_pages - num))
322	return NULL;
323
324    for (j = i; j < (i + num); j++)
325	INTPriv(pInt)->alloc[j] = 1;
326
327    *off = (i + 1) * pagesize;
328
329    return (char *)INTPriv(pInt)->base + *off;
330}
331
332void
333xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num)
334{
335    int pagesize = getpagesize();
336    int first = (((char *)pbase - (char *)INTPriv(pInt)->base) / pagesize) - 1;
337    int i;
338
339    for (i = first; i < (first + num); i++)
340	INTPriv(pInt)->alloc[i] = 0;
341}
342
343#define OFF(addr) ((addr) & 0xffff)
344#if defined _PC
345# define HIGH_OFFSET (INTPriv(pInt)->highMemory)
346# define HIGH_BASE   V_BIOS
347#else
348# define HIGH_OFFSET SYS_BIOS
349# define HIGH_BASE   SYS_BIOS
350#endif
351# define SYS(addr) ((addr) >= HIGH_OFFSET)
352#define V_ADDR(addr) \
353	  (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \
354	   : (((char*)(INTPriv(pInt)->base) + addr)))
355#define VRAM_ADDR(addr) (addr - V_RAM)
356#define VRAM_BASE (INTPriv(pInt)->vRam)
357
358#define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE)))
359#define V_ADDR_RB(addr) \
360	(VRAM(addr)) ? MMIO_IN8((CARD8*)VRAM_BASE,VRAM_ADDR(addr)) \
361	   : *(CARD8*) V_ADDR(addr)
362#define V_ADDR_RW(addr) \
363	(VRAM(addr)) ? MMIO_IN16((CARD16*)VRAM_BASE,VRAM_ADDR(addr)) \
364	   : ldw_u((pointer)V_ADDR(addr))
365#define V_ADDR_RL(addr) \
366	(VRAM(addr)) ? MMIO_IN32((CARD32*)VRAM_BASE,VRAM_ADDR(addr)) \
367	   : ldl_u((pointer)V_ADDR(addr))
368
369#define V_ADDR_WB(addr,val) \
370	if(VRAM(addr)) \
371	    MMIO_OUT8((CARD8*)VRAM_BASE,VRAM_ADDR(addr),val); \
372	else \
373	    *(CARD8*) V_ADDR(addr) = val;
374#define V_ADDR_WW(addr,val) \
375	if(VRAM(addr)) \
376	    MMIO_OUT16((CARD16*)VRAM_BASE,VRAM_ADDR(addr),val); \
377	else \
378	    stw_u((val),(pointer)(V_ADDR(addr)));
379
380#define V_ADDR_WL(addr,val) \
381	if (VRAM(addr)) \
382	    MMIO_OUT32((CARD32*)VRAM_BASE,VRAM_ADDR(addr),val); \
383	else \
384	    stl_u(val,(pointer)(V_ADDR(addr)));
385
386static CARD8
387read_b(xf86Int10InfoPtr pInt, int addr)
388{
389    return V_ADDR_RB(addr);
390}
391
392static CARD16
393read_w(xf86Int10InfoPtr pInt, int addr)
394{
395#if X_BYTE_ORDER == X_LITTLE_ENDIAN
396    if (OFF(addr + 1) > 0)
397	return V_ADDR_RW(addr);
398#endif
399    return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8);
400}
401
402static CARD32
403read_l(xf86Int10InfoPtr pInt, int addr)
404{
405#if X_BYTE_ORDER == X_LITTLE_ENDIAN
406    if (OFF(addr + 3) > 2)
407	return V_ADDR_RL(addr);
408#endif
409    return V_ADDR_RB(addr) |
410	   (V_ADDR_RB(addr + 1) << 8) |
411	   (V_ADDR_RB(addr + 2) << 16) |
412	   (V_ADDR_RB(addr + 3) << 24);
413}
414
415static void
416write_b(xf86Int10InfoPtr pInt, int addr, CARD8 val)
417{
418    V_ADDR_WB(addr,val);
419}
420
421static void
422write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val)
423{
424#if X_BYTE_ORDER == X_LITTLE_ENDIAN
425    if (OFF(addr + 1) > 0)
426      { V_ADDR_WW(addr, val); }
427#endif
428    V_ADDR_WB(addr, val);
429    V_ADDR_WB(addr + 1, val >> 8);
430}
431
432static void
433write_l(xf86Int10InfoPtr pInt, int addr, CARD32 val)
434{
435#if X_BYTE_ORDER == X_LITTLE_ENDIAN
436    if (OFF(addr + 3) > 2)
437      { V_ADDR_WL(addr, val); }
438#endif
439    V_ADDR_WB(addr, val);
440    V_ADDR_WB(addr + 1, val >> 8);
441    V_ADDR_WB(addr + 2, val >> 16);
442    V_ADDR_WB(addr + 3, val >> 24);
443}
444
445pointer
446xf86int10Addr(xf86Int10InfoPtr pInt, CARD32 addr)
447{
448    return V_ADDR(addr);
449}
450