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