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