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 
25 static __inline__ uint32_t
ldl_u(uint32_t * p)26 ldl_u(uint32_t * p)
27 {
28     uint32_t ret;
29 
30     memmove(&ret, p, sizeof(*p));
31     return ret;
32 }
33 
34 static __inline__ uint16_t
ldw_u(uint16_t * p)35 ldw_u(uint16_t * p)
36 {
37     uint16_t ret;
38 
39     memmove(&ret, p, sizeof(*p));
40     return ret;
41 }
42 
43 static __inline__ void
stl_u(uint32_t val,uint32_t * p)44 stl_u(uint32_t val, uint32_t * p)
45 {
46     uint32_t tmp = val;
47 
48     memmove(p, &tmp, sizeof(*p));
49 }
50 
51 static __inline__ void
stw_u(uint16_t val,uint16_t * p)52 stw_u(uint16_t val, uint16_t * p)
53 {
54     uint16_t tmp = val;
55 
56     memmove(p, &tmp, sizeof(*p));
57 }
58 
59 static uint8_t read_b(xf86Int10InfoPtr pInt, int addr);
60 static uint16_t read_w(xf86Int10InfoPtr pInt, int addr);
61 static uint32_t read_l(xf86Int10InfoPtr pInt, int addr);
62 static void write_b(xf86Int10InfoPtr pInt, int addr, uint8_t val);
63 static void write_w(xf86Int10InfoPtr pInt, int addr, uint16_t val);
64 static 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 
71 typedef 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 
83 int10MemRec genericMem = {
84     read_b,
85     read_w,
86     read_l,
87     write_b,
88     write_w,
89     write_l
90 };
91 
92 static void MapVRam(xf86Int10InfoPtr pInt);
93 static 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 
100 static void *sysMem = NULL;
101 
102 static Bool
readIntVec(struct pci_device * dev,unsigned char * buf,int len)103 readIntVec(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 
116 xf86Int10InfoPtr
xf86ExtendedInitInt10(int entityIndex,int Flags)117 xf86ExtendedInitInt10(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         }
266     }
267 
268     pInt->BIOSseg = V_BIOS >> 4;
269     pInt->num = 0xe6;
270     LockLegacyVGA(pInt, &vga);
271     xf86ExecX86int10(pInt);
272     UnlockLegacyVGA(pInt, &vga);
273 #endif
274     free(options);
275     return pInt;
276 
277  error1:
278     free(base);
279     UnmapVRam(pInt);
280     free(INTPriv(pInt)->alloc);
281     free(pInt->private);
282  error0:
283     free(pInt);
284     free(options);
285 
286     return NULL;
287 }
288 
289 static void
MapVRam(xf86Int10InfoPtr pInt)290 MapVRam(xf86Int10InfoPtr pInt)
291 {
292     int pagesize = getpagesize();
293     int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize;
294 
295     pci_device_map_legacy(pInt->dev, V_RAM, size, PCI_DEV_MAP_FLAG_WRITABLE,
296                           &(INTPriv(pInt)->vRam));
297     pInt->io = pci_legacy_open_io(pInt->dev, 0, 64 * 1024);
298 }
299 
300 static void
UnmapVRam(xf86Int10InfoPtr pInt)301 UnmapVRam(xf86Int10InfoPtr pInt)
302 {
303     int pagesize = getpagesize();
304     int size = ((VRAM_SIZE + pagesize - 1) / pagesize) * pagesize;
305 
306     pci_device_unmap_legacy(pInt->dev, INTPriv(pInt)->vRam, size);
307     pci_device_close_io(pInt->dev, pInt->io);
308     pInt->io = NULL;
309 }
310 
311 Bool
MapCurrentInt10(xf86Int10InfoPtr pInt)312 MapCurrentInt10(xf86Int10InfoPtr pInt)
313 {
314     /* nothing to do here */
315     return TRUE;
316 }
317 
318 void
xf86FreeInt10(xf86Int10InfoPtr pInt)319 xf86FreeInt10(xf86Int10InfoPtr pInt)
320 {
321     if (!pInt)
322         return;
323 #if defined (_PC)
324     xf86Int10SaveRestoreBIOSVars(pInt, FALSE);
325 #endif
326     if (Int10Current == pInt)
327         Int10Current = NULL;
328     free(INTPriv(pInt)->base);
329     UnmapVRam(pInt);
330     free(INTPriv(pInt)->alloc);
331     free(pInt->private);
332     free(pInt);
333 }
334 
335 void *
xf86Int10AllocPages(xf86Int10InfoPtr pInt,int num,int * off)336 xf86Int10AllocPages(xf86Int10InfoPtr pInt, int num, int *off)
337 {
338     int pagesize = getpagesize();
339     int num_pages = ALLOC_ENTRIES(pagesize);
340     int i, j;
341 
342     for (i = 0; i < (num_pages - num); i++) {
343         if (INTPriv(pInt)->alloc[i] == 0) {
344             for (j = i; j < (num + i); j++)
345                 if (INTPriv(pInt)->alloc[j] != 0)
346                     break;
347             if (j == (num + i))
348                 break;
349             i += num;
350         }
351     }
352     if (i == (num_pages - num))
353         return NULL;
354 
355     for (j = i; j < (i + num); j++)
356         INTPriv(pInt)->alloc[j] = 1;
357 
358     *off = (i + 1) * pagesize;
359 
360     return (char *) INTPriv(pInt)->base + *off;
361 }
362 
363 void
xf86Int10FreePages(xf86Int10InfoPtr pInt,void * pbase,int num)364 xf86Int10FreePages(xf86Int10InfoPtr pInt, void *pbase, int num)
365 {
366     int pagesize = getpagesize();
367     int first =
368         (((char *) pbase - (char *) INTPriv(pInt)->base) / pagesize) - 1;
369     int i;
370 
371     for (i = first; i < (first + num); i++)
372         INTPriv(pInt)->alloc[i] = 0;
373 }
374 
375 #define OFF(addr) ((addr) & 0xffff)
376 #if defined _PC
377 #define HIGH_OFFSET (INTPriv(pInt)->highMemory)
378 #define HIGH_BASE   V_BIOS
379 #else
380 #define HIGH_OFFSET SYS_BIOS
381 #define HIGH_BASE   SYS_BIOS
382 #endif
383 #define SYS(addr) ((addr) >= HIGH_OFFSET)
384 #define V_ADDR(addr) \
385 	  (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - HIGH_BASE) \
386 	   : (((char*)(INTPriv(pInt)->base) + addr)))
387 #define VRAM_ADDR(addr) (addr - V_RAM)
388 #define VRAM_BASE (INTPriv(pInt)->vRam)
389 
390 #define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE)))
391 #define V_ADDR_RB(addr) \
392 	(VRAM(addr)) ? MMIO_IN8((uint8_t*)VRAM_BASE,VRAM_ADDR(addr)) \
393 	   : *(uint8_t*) V_ADDR(addr)
394 #define V_ADDR_RW(addr) \
395 	(VRAM(addr)) ? MMIO_IN16((uint16_t*)VRAM_BASE,VRAM_ADDR(addr)) \
396 	   : ldw_u((void *)V_ADDR(addr))
397 #define V_ADDR_RL(addr) \
398 	(VRAM(addr)) ? MMIO_IN32((uint32_t*)VRAM_BASE,VRAM_ADDR(addr)) \
399 	   : ldl_u((void *)V_ADDR(addr))
400 
401 #define V_ADDR_WB(addr,val) \
402 	if(VRAM(addr)) \
403 	    MMIO_OUT8((uint8_t*)VRAM_BASE,VRAM_ADDR(addr),val); \
404 	else \
405 	    *(uint8_t*) V_ADDR(addr) = val;
406 #define V_ADDR_WW(addr,val) \
407 	if(VRAM(addr)) \
408 	    MMIO_OUT16((uint16_t*)VRAM_BASE,VRAM_ADDR(addr),val); \
409 	else \
410 	    stw_u((val),(void *)(V_ADDR(addr)));
411 
412 #define V_ADDR_WL(addr,val) \
413 	if (VRAM(addr)) \
414 	    MMIO_OUT32((uint32_t*)VRAM_BASE,VRAM_ADDR(addr),val); \
415 	else \
416 	    stl_u(val,(void *)(V_ADDR(addr)));
417 
418 static uint8_t
read_b(xf86Int10InfoPtr pInt,int addr)419 read_b(xf86Int10InfoPtr pInt, int addr)
420 {
421     return V_ADDR_RB(addr);
422 }
423 
424 static uint16_t
read_w(xf86Int10InfoPtr pInt,int addr)425 read_w(xf86Int10InfoPtr pInt, int addr)
426 {
427 #if X_BYTE_ORDER == X_LITTLE_ENDIAN
428     if (OFF(addr + 1) > 0)
429         return V_ADDR_RW(addr);
430 #endif
431     return V_ADDR_RB(addr) | (V_ADDR_RB(addr + 1) << 8);
432 }
433 
434 static uint32_t
read_l(xf86Int10InfoPtr pInt,int addr)435 read_l(xf86Int10InfoPtr pInt, int addr)
436 {
437 #if X_BYTE_ORDER == X_LITTLE_ENDIAN
438     if (OFF(addr + 3) > 2)
439         return V_ADDR_RL(addr);
440 #endif
441     return V_ADDR_RB(addr) |
442         (V_ADDR_RB(addr + 1) << 8) |
443         (V_ADDR_RB(addr + 2) << 16) | (V_ADDR_RB(addr + 3) << 24);
444 }
445 
446 static void
write_b(xf86Int10InfoPtr pInt,int addr,uint8_t val)447 write_b(xf86Int10InfoPtr pInt, int addr, uint8_t val)
448 {
449     V_ADDR_WB(addr, val);
450 }
451 
452 static void
write_w(xf86Int10InfoPtr pInt,int addr,CARD16 val)453 write_w(xf86Int10InfoPtr pInt, int addr, CARD16 val)
454 {
455 #if X_BYTE_ORDER == X_LITTLE_ENDIAN
456     if (OFF(addr + 1) > 0) {
457         V_ADDR_WW(addr, val);
458     }
459 #endif
460     V_ADDR_WB(addr, val);
461     V_ADDR_WB(addr + 1, val >> 8);
462 }
463 
464 static void
write_l(xf86Int10InfoPtr pInt,int addr,uint32_t val)465 write_l(xf86Int10InfoPtr pInt, int addr, uint32_t val)
466 {
467 #if X_BYTE_ORDER == X_LITTLE_ENDIAN
468     if (OFF(addr + 3) > 2) {
469         V_ADDR_WL(addr, val);
470     }
471 #endif
472     V_ADDR_WB(addr, val);
473     V_ADDR_WB(addr + 1, val >> 8);
474     V_ADDR_WB(addr + 2, val >> 16);
475     V_ADDR_WB(addr + 3, val >> 24);
476 }
477 
478 void *
xf86int10Addr(xf86Int10InfoPtr pInt,uint32_t addr)479 xf86int10Addr(xf86Int10InfoPtr pInt, uint32_t addr)
480 {
481     return V_ADDR(addr);
482 }
483