Ticket #7172: vesa3.c

File vesa3.c, 27.2 KB (added by stargatefan, 13 years ago)
Line 
1/*
2** Copyright 2002-2005, Michael Noisternig. All rights reserved.
3** Distributed under the terms of the NewOS License.
4*/
5#include "vesa3.h"
6#include "gtf.h"
7#include "video_param_table.h"
8
9#include <kernel/debug.h>
10#include <kernel/fs/devfs.h>
11#include <kernel/arch/i386/selector.h>
12#include <kernel/vm.h>
13#include <kernel/heap.h>
14#include <string.h>
15#include <stdio.h>
16#include <newos/errors.h>
17#include <newos/drivers.h>
18
19//-----------------------------------------------------------------------------
20
21// set for reading the BIOS from array biosdata - useful for debugging
22//#define FAKE_VESA
23
24// NOTE: many VESA VBE 3.0 implementations are broken
25// I try to address these problems by patching the copy of the BIOS in RAM
26
27//----------------------------------------------------------------------------
28
29#ifdef FAKE_VESA
30//#include "sapphire9200.h"
31#include "nv4193e.h"
32//#include "vivid!81.h"
33//#include "prophet3.h"
34#endif
35
36#define STRING2(s) #s
37#define STRING(s) STRING2(s)
38
39struct s_regs {
40 uint16 ax;
41 uint16 bx;
42 uint16 cx;
43 uint16 dx;
44 uint16 si;
45 uint16 di;
46 uint16 es;
47} _PACKED;
48
49static devfs_framebuffer_info fb_info;
50
51static vesa3_infoblock infoblock;
52static vesa3_mode_infoblock mode_infoblock;
53
54static selector_id sel_infoblock;
55
56static unsigned char *video_bios;
57static unsigned char *bios_data;
58static unsigned char *bios_stack;
59
60static selector_id sel_code;
61static selector_id sel_stack;
62
63static int retn; // for 16-bit far return or 32-bit near return
64
65extern void vesa3_dummy_retf();
66extern void vesa3_call_retf();
67asm(
68".global vesa3_call_retf;"
69"vesa3_call_retf:;"
70//"pushl %ds;"
71//"popl %gs;"
72//"pushl $0x40;"
73//"popl %ds;"
74" addr16;"
75" lcall *retn;"
76//" lcall %gs:*retn;"
77" data16;"
78".global vesa3_dummy_retf;"
79"vesa3_dummy_retf:;"
80" lret;"
81);
82
83static struct s_farcall {
84 uint32 offset;
85 uint32 seg;
86} farcall = { (uint32)vesa3_dummy_retf, KERNEL_CODE_SEG };
87
88static void vesa_call( struct s_regs *regs )
89{
90 asm("pushf;"
91 "cli;"
92 "pushl %%es;"
93 "pushal;"
94 "movl %%esp,%%esi;"
95 "pushl sel_stack;"
96 "pushl $("STRING(VESA_STACK_SIZE)"-4);"
97 "call i386_stack_switch;"
98 "pushl $"STRING(KERNEL_DATA_SEG)";"
99 "pushl %%esi;"
100 "pushl %%edi;"
101 "pushl %%ds;"
102 "movw 12(%%edi),%%dx;"
103 "movw %%dx,%%es;"
104 "movw (%%edi),%%ax;"
105 "movw 2(%%edi),%%bx;"
106 "movw 4(%%edi),%%cx;"
107 "movw 6(%%edi),%%dx;"
108 "movw 8(%%edi),%%si;"
109 "movw 10(%%edi),%%di;"
110 "lcall *farcall;"
111 "popl %%ds;"
112 "popl %%ebp;"
113 "movw %%ax,%%ds:(%%ebp);"
114 "movl %%ebp,%%eax;"
115 "movw %%bx,2(%%eax);"
116 "movw %%cx,4(%%eax);"
117 "movw %%dx,6(%%eax);"
118 "movw %%si,8(%%eax);"
119 "movw %%di,10(%%eax);"
120 "movw %%es,%%bx;"
121 "movw %%bx,12(%%eax);"
122 "call i386_stack_switch;"
123 "popal;"
124 "popl %%es;"
125 "popf;"
126 : : "D" (regs) );
127}
128
129//----------------------------------------------------------------------------
130
131#if 0
132static void *linear( void *ptr )
133{
134 return (void *)( *(unsigned short *)ptr + ((int)(((unsigned short *)ptr)[1])<<4) );
135}
136#endif
137
138static void *memmem( const void *mem, size_t len, const void *submem, size_t sublen )
139{
140 const char *m = mem;
141 const char *max = &m[len-sublen];
142
143 for ( ; m < max; m++ ) {
144 m = memchr( m, *(char *)submem, max-m );
145 if ( m == NULL )
146 break;
147 if ( memcmp(m, submem, sublen) == 0 )
148 return (void *)m;
149 }
150
151 return NULL;
152}
153
154static void resolve_farptr( uint32 *string_farptr )
155{
156 if ( (*string_farptr >> 16) == sel_infoblock && (*string_farptr &= 0xffff) < sizeof(vesa3_infoblock) )
157 *string_farptr += (uint32)&infoblock;
158 else
159 *string_farptr = 0;
160}
161
162//----------------------------------------------------------------------------
163
164static uint16 vesa3_get_mode_infoblock( uint16 mode )
165{
166 struct s_regs regs;
167
168 regs.ax = 0x4f01;
169 regs.cx = mode;
170 regs.es = i386_selector_add( SELECTOR(&mode_infoblock,sizeof(mode_infoblock)-1,DATA_w,false) );
171 regs.di = 0;
172 vesa_call( &regs );
173 i386_selector_remove( regs.es );
174
175 return regs.ax;
176}
177
178static uint16 vesa3_set_mode_CRTC_generic( uint16 mode, vesa3_CRTC_infoblock *crtc )
179{
180/* vesa3_CRTC_infoblock CRTC_info_block = {
181 640+16+64+80, 640+16, 640+16+64,
182 480+3+4+13, 480+3, 480+3+4,
183 VESA3_CRTC_HSYNC_NEGATIVE, 23750000, 5938, {} };*/
184 struct s_regs regs;
185
186 regs.ax = 0x4f02;
187 regs.bx = mode | 0xc000; //| 0xc800;
188 regs.es = 0;
189/* regs.es = i386_selector_add( SELECTOR(&CRTC_info_block,sizeof(CRTC_info_block)-1,DATA_w,false) );
190 regs.di = 0;*/
191 vesa_call( &regs );
192
193 return regs.ax;
194}
195
196struct s_edid {
197 uint16 dot_clock; // pixel clock / 10000
198 uint8 xres_lo;
199 uint16 hblank : 12; // blank = front porch + sync width + back porch
200 uint8 xres_hi : 4;
201 uint8 yres_lo;
202 uint16 vblank : 12;
203 uint8 yres_hi : 4;
204 uint8 hoverplus_lo; // overplus = front porch
205 uint8 hsyncwidth_lo;
206 uint8 vsyncwidth_lo : 4;
207 uint8 voverplus_lo : 4;
208 uint8 vsyncwidth_hi : 2;
209 uint8 voverplus_hi : 2;
210 uint8 hsyncwidth_hi : 2;
211 uint8 hoverplus_hi : 2;
212 uint8 _reserved[6];
213} _PACKED;
214
215static struct s_edid *ati_edid_dest;
216
217static uint16 vesa3_set_mode_CRTC_ATI( uint16 mode, vesa3_CRTC_infoblock *crtc )
218{
219/* static const struct s_edid default_edid = {
220 2375, 640&0xff, 160, 640>>8, 480&0xff, 20, 480>>8,
221 16&0xff, 64&0xff, 4, 3&0xff, 4>>4, 3>>4, 64>>8, 16>>8, {}
222 };*/
223 struct s_regs regs;
224 unsigned hoverplus = crtc->horizontal_sync_start - mode_infoblock.x_resolution;
225 unsigned voverplus = crtc->vertical_sync_start - mode_infoblock.y_resolution;
226 unsigned hsyncwidth = crtc->horizontal_sync_end - crtc->horizontal_sync_start;
227 unsigned vsyncwidth = crtc->vertical_sync_end - crtc->vertical_sync_start;
228
229 dprintf( "vesa3: ATI: writing EDID data\n" );
230
231 ati_edid_dest->dot_clock = crtc->pixel_clock / 10000;
232 ati_edid_dest->xres_lo = mode_infoblock.x_resolution & 0xff;
233 ati_edid_dest->hblank = crtc->horizontal_total - mode_infoblock.x_resolution;
234 ati_edid_dest->xres_hi = mode_infoblock.x_resolution >> 8;
235 ati_edid_dest->yres_lo = mode_infoblock.y_resolution & 0xff;
236 ati_edid_dest->vblank = crtc->vertical_total - mode_infoblock.y_resolution;
237 ati_edid_dest->yres_hi = mode_infoblock.y_resolution >> 8;
238 ati_edid_dest->hoverplus_lo = hoverplus & 0xff;
239 ati_edid_dest->hsyncwidth_lo = hsyncwidth & 0xff;
240 ati_edid_dest->vsyncwidth_lo = vsyncwidth & 0xf;
241 ati_edid_dest->voverplus_lo = voverplus & 0xf;
242 ati_edid_dest->vsyncwidth_hi = vsyncwidth >> 4;
243 ati_edid_dest->voverplus_hi = voverplus >> 4;
244 ati_edid_dest->hsyncwidth_hi = hsyncwidth >> 8;
245 ati_edid_dest->hoverplus_hi = hoverplus >> 8;
246
247// memcpy( ati_edid_dest, &default_edid, sizeof(struct s_edid) );
248// memcpy( &video_bios[0x9b8e], &video_bios[0x9f26+9*0x12], 0x12 );
249
250 dprintf( "vesa3: ATI: EDID: dot_clock %u, xres %u, yres %u, hblank %u, vblank %u, hsyncwidth %u, vsyncwidth %u, hoverplus %u, voverplus %u\n",
251 ati_edid_dest->dot_clock,
252 ati_edid_dest->xres_lo+(ati_edid_dest->xres_hi<<8),
253 ati_edid_dest->yres_lo+(ati_edid_dest->yres_hi<<8),
254 ati_edid_dest->hblank,
255 ati_edid_dest->vblank,
256 ati_edid_dest->hsyncwidth_lo+(ati_edid_dest->hsyncwidth_hi<<8),
257 ati_edid_dest->vsyncwidth_lo+(ati_edid_dest->vsyncwidth_hi<<4),
258 ati_edid_dest->hoverplus_lo+(ati_edid_dest->hoverplus_hi<<8),
259 ati_edid_dest->voverplus_lo+(ati_edid_dest->voverplus_hi<<4)
260 );
261
262 regs.ax = 0x4f02;
263 regs.bx = mode | 0xc000;
264 regs.es = 0;
265 vesa_call( &regs );
266
267 return regs.ax;
268}
269
270static uint16 vesa3_set_mode_CRTC_nVidia( uint16 mode, vesa3_CRTC_infoblock *crtc )
271{
272 struct s_regs regs;
273
274 regs.ax = 0x4f02;
275 regs.bx = mode | 0xc000;
276 regs.di = 0;
277 regs.es = 0;
278 vesa_call( &regs );
279
280 return regs.ax;
281}
282
283static uint16 (*vesa3_set_mode_CRTC)(uint16, vesa3_CRTC_infoblock *) = vesa3_set_mode_CRTC_generic;
284
285static uint16 vesa3_set_mode( unsigned int xres, unsigned int yres, unsigned int bpp, unsigned int refresh_rate )
286{
287 uint16 err = 0xffff;
288 uint16 *mode = (uint16 *)infoblock.video_mode_ptr;
289
290 if ( mode ) {
291 dprintf( "vesa3: searching mode %ux%ux%u...\n", xres, yres, bpp );
292 while ( *mode != 0xffff ) {
293 err = vesa3_get_mode_infoblock( *mode );
294 if ( err == 0x004f
295 && mode_infoblock.x_resolution == xres
296 && mode_infoblock.y_resolution == yres
297 && mode_infoblock.bits_per_pixel == bpp ) {
298 struct vesa3_CRTC_infoblock crtc;
299 gtf_compute_CRTC_data( &crtc, xres, yres, refresh_rate<<10, false, false );
300 if ( crtc.pixel_clock > mode_infoblock.max_pixel_clock && mode_infoblock.max_pixel_clock > 0 ) {
301 dprintf( "vesa3: pixel clock too high (max. is %u Hz)!\n", mode_infoblock.max_pixel_clock );
302 return -1;
303 }
304 dprintf( "vesa3: switching to video mode 0x%x...\n", *mode );
305 err = vesa3_set_mode_CRTC( *mode, &crtc );
306 break;
307 }
308 mode++;
309 }
310 }
311
312 return err;
313}
314
315//----------------------------------------------------------------------------
316/* For compatibility with the vesa (2.0) driver and demonstration purposes
317 this driver goes to VESA VBE mode 640x480x32/15 when opened.
318 Note that for going back to text mode you have to utilize a standard VGA
319 driver as VESA VBE 3.0 does NOT support text modes.
320*/
321static int vesa3_open( dev_ident ident, dev_cookie *cookie )
322{
323 int err = vesa3_set_mode( 640, 480, 32, 60 );
324
325 dprintf( "vesa3: open(): vesa3_set_mode() returned 0x%x\n", err );
326
327 if ( err != 0x004f ) {
328 err = vesa3_set_mode( 640, 480, 15, 60 ); // let's try 15 bit mode instead
329 dprintf( "vesa3: open(): vesa3_set_mode() returned 0x%x\n", err );
330 if ( err != 0x004f )
331 return ERR_GENERAL;
332 }
333
334 dprintf( "vesa3: physical video memory at 0x%x\n", mode_infoblock.phys_base_ptr );
335
336 fb_info.width = mode_infoblock.x_resolution;
337 fb_info.height = mode_infoblock.y_resolution;
338 fb_info.bit_depth = mode_infoblock.bits_per_pixel;
339 switch ( fb_info.bit_depth ) {
340 case 8: fb_info.color_space = COLOR_SPACE_8BIT; break;
341 case 15: fb_info.color_space = COLOR_SPACE_RGB555; break;
342 case 24: fb_info.color_space = COLOR_SPACE_RGB888; break;
343 case 32: fb_info.color_space = COLOR_SPACE_RGB888+1; // COLOR_SPACE_RGB8888
344 }
345
346#if 0
347 {
348 unsigned i, x, y, rgb1, rgb2;
349 void *video_mem;
350
351 //draw a color-fading rectangle on screen
352 vm_map_physical_memory( vm_get_kernel_aspace_id(), "linear_video_mem", (void**)&video_mem, REGION_ADDR_ANY_ADDRESS,
353 mode_infoblock.x_resolution * mode_infoblock.y_resolution * ((mode_infoblock.bits_per_pixel+7)/8),
354 LOCK_RW | LOCK_KERNEL, (addr_t)mode_infoblock.phys_base_ptr );
355
356#define PIXEL8888(x,y,c) \
357*(uint32*)&((char*)video_mem)[((y)*640+(x))*4] = (c);
358
359#define PIXEL888(x,y,c) \
360*(uint16*)&((char*)video_mem)[((y)*640+(x))*3] = (c)&0xffff; \
361*(uint8*)&((char*)video_mem)[((y)*640+(x))*3+2] = (c)>>16;
362
363#define PIXEL555(x,y,c) \
364((uint16*)video_mem)[((y)*640+(x))] = (((c)>>3)&0x1f) | (((c)>>6)&0x3e0) | (((c)>>9)&0x7c00);
365
366#define PIXEL PIXEL8888
367
368#if 1
369 for ( i = 0; i < 20; i++ ) {
370 for ( x = 0; x < 640*480; x++ ) {
371 if ( (x/640)%30 < 10 ) {
372 PIXEL( x, 0, 0xff*(640-(x+i))/640 + ((0xff*(x+i)/640) << 8) );
373 }
374 else if ( (x/640)%30 < 20 ) {
375 PIXEL( x, 0, ((0xff*(640-(x+i))/640) << 8) + ((0xff*(x+i)/640) << 16) );
376 }
377 else {
378 PIXEL( x, 0, ((0xff*(640-(x+i))/640) << 16) + 0xff*(x+i)/640 );
379 }
380 }
381/* for ( y = 0; y < 256; y++ ) {
382 rgb1 = ((255-y)<<8)+(y<<16);
383 rgb2 = ((y*(i&255)>>8)<<16)+((y*(i&255)>>8)<<8)+(255-y)+(y*(i&255)>>8);
384 for ( x = 0; x < 256; x++ )
385 ((unsigned*)video_mem)[y*640+x] =
386 (((rgb1&0xff)*(255-x)>>8)+((rgb2&0xff)*x)>>8) |
387 ((((((rgb1&0xff00)>>8)*(255-x)>>8)+(((rgb2&0xff00)>>8)*x>>8)))<<8) |
388 (((((rgb1>>16)*(255-x)>>8)+((rgb2>>16)*x>>8)))<<16);
389 }*/
390 for ( x = 0; x < 1<<20; x++ ) y++; // dummy loop
391 }
392#endif
393 for ( y = 0; y < 20; y++ )
394 for ( x = 0; x < 20; x++ )
395 PIXEL( x, y, 0x1f );
396 }
397#endif
398
399 return NO_ERROR;
400}
401
402//----------------------------------------------------------------------------
403static int vesa3_close( dev_cookie cookie )
404{
405 return NO_ERROR;
406}
407
408//----------------------------------------------------------------------------
409static int vesa3_free_cookie( dev_cookie cookie )
410{
411 return NO_ERROR;
412}
413
414//----------------------------------------------------------------------------
415static int vesa3_seek( dev_cookie cookie, off_t pos, seek_type st)
416{
417 return ERR_NOT_ALLOWED;
418}
419
420//----------------------------------------------------------------------------
421static int vesa3_ioctl( dev_cookie cookie, int op, void *buf, size_t len )
422{
423 int err = ERR_INVALID_ARGS;
424
425 switch ( op ) {
426
427 case 0xfb:
428 err = user_memcpy( buf, &mode_infoblock.phys_base_ptr, 4 );
429 break;
430
431 case IOCTL_DEVFS_GET_FRAMEBUFFER_INFO:
432 dprintf( "vesa3: IOCTL_DEVFS_GET_FRAMEBUFFER_INFO\n" );
433
434 if ( is_kernel_address(buf) )
435 return ERR_VM_BAD_USER_MEMORY;
436
437 if ( len == sizeof(fb_info) )
438 err = user_memcpy( buf, &fb_info, sizeof(fb_info) );
439 break;
440
441 case IOCTL_DEVFS_MAP_FRAMEBUFFER:
442 {
443 aspace_id aid = vm_get_current_user_aspace_id();
444 region_id rid;
445 void *linear_video_mem;
446
447 dprintf( "vesa3: IOCTL_DEVFS_MAP_FRAMEBUFFER\n" );
448
449 if ( is_kernel_address(buf) )
450 return ERR_VM_BAD_USER_MEMORY;
451
452 if ( len != sizeof(linear_video_mem) )
453 break;
454
455 err = rid = vm_map_physical_memory( aid, "linear_video_mem", &linear_video_mem, REGION_ADDR_ANY_ADDRESS,
456 mode_infoblock.x_resolution * mode_infoblock.y_resolution * ((mode_infoblock.bits_per_pixel+7)/8),
457 LOCK_RW, (addr_t)mode_infoblock.phys_base_ptr );
458 if ( err < 0 )
459 break;
460
461 err = user_memcpy( buf, &linear_video_mem, sizeof(linear_video_mem) );
462 if ( err < 0 ) {
463 vm_delete_region( aid, rid );
464 break;
465 }
466
467 err = rid; // return region id
468 }
469 }
470
471 dprintf( "vesa3: ioctl returns 0x%x\n", err );
472
473 return err;
474}
475
476//----------------------------------------------------------------------------
477static ssize_t vesa3_read( dev_cookie cookie, void *buf, off_t pos, ssize_t len )
478{
479 return ERR_UNIMPLEMENTED;
480}
481
482//----------------------------------------------------------------------------
483static ssize_t vesa3_write( dev_cookie cookie, const void *buf, off_t pos, ssize_t len )
484{
485 return ERR_UNIMPLEMENTED;
486}
487
488//----------------------------------------------------------------------------
489static struct dev_calls vesa3_hooks = {
490 vesa3_open,
491 vesa3_close,
492 vesa3_free_cookie,
493 vesa3_seek,
494 vesa3_ioctl,
495 vesa3_read,
496 vesa3_write,
497 /* no paging here */
498 NULL,
499 NULL,
500 NULL
501};
502
503//----------------------------------------------------------------------------
504int dev_bootstrap(void);
505
506int dev_bootstrap(void)
507{
508 struct s_regs regs;
509 struct vesa3_pm_infoblock *pm_info;
510 unsigned char *ptr;
511 unsigned char checksum = 0;
512 unsigned int i;
513 enum { BIOS_ANY, BIOS_NVIDIA, BIOS_ATI } bios_vendor = BIOS_ANY;
514 int vesa_data_size = VESA_DATA_SIZE;
515 region_id id;
516 aspace_id sp = vm_get_kernel_aspace_id();
517 unsigned char *video_mem;
518 int ret_val;
519
520 dprintf( "vesa3: setting up VBE 3.0...\n" );
521
522 // copy video BIOS to RAM
523 video_bios = (unsigned char *)kmalloc( VESA_CODE_SIZE );
524 if ( video_bios == NULL )
525 return ERR_NO_MEMORY;
526
527#ifdef FAKE_VESA
528 memcpy( video_bios, biosdata, sizeof(biosdata) );
529#else
530 ret_val = vm_map_physical_memory( sp, "video_bios", (void**)&ptr,
531 REGION_ADDR_ANY_ADDRESS, VESA_CODE_SIZE, LOCK_RO | LOCK_KERNEL, (addr_t)0xc0000 );
532 if ( ret_val < 0 )
533 goto no_vesa1;
534
535 memcpy( video_bios, ptr, VESA_CODE_SIZE );
536
537 vm_delete_region( sp, ret_val );
538#endif
539
540 // find VESA VBE protected mode info block signature
541 ptr = video_bios;
542 while ( ptr <= video_bios+VESA_CODE_SIZE-sizeof(struct vesa3_pm_infoblock) && ((struct vesa3_pm_infoblock*)ptr)->signature != VESA_MAGIC )
543 ptr++;
544
545 pm_info = (struct vesa3_pm_infoblock*)ptr;
546
547 ret_val = ERR_GENERAL;
548 if ( pm_info->signature != VESA_MAGIC ) {
549 dprintf( "vesa3: VBE 3.0 not available!\n" );
550 goto no_vesa1;
551 }
552
553 dprintf( "vesa3: VBE 3.0 protected mode info block found...\n" );
554
555 // calculate checksum
556 for ( i = 0; i < sizeof(struct vesa3_pm_infoblock); i++ )
557 checksum += *ptr++;
558
559 if ( checksum == 0 )
560 dprintf( "vesa3: checksum ok...\n" );
561 else {
562 // find out if we have a broken ATI BIOS
563 static const char *const ati_vendor = "ATI Technologies Inc.";
564/* static const char edid_640x480x60[18] = {
565 0xd6,0x09,0x80,0xa0,0x20,0xe0,0x2d,0x10,0x10,0x60,0xa2,0x00,0x00,0x00,0x00,0x08,0x08,0x18
566 };*/
567
568 ptr = memmem( video_bios, VESA_CODE_SIZE, ati_vendor, strlen(ati_vendor) );
569 if ( ptr != NULL ) {
570 dprintf( "vesa3: ATI: checksum wrong, but broken ATI BIOS detected... trying to fix it...\n" );
571 bios_vendor = BIOS_ATI;
572 vesa3_set_mode_CRTC = vesa3_set_mode_CRTC_ATI;
573
574/* // find EDID source data
575 ptr = memmem( video_bios, VESA_CODE_SIZE, edid_640x480x60, sizeof(edid_640x480x60) );
576 if ( ptr == NULL ) {
577 dprintf( "vesa3: ATI: could not find EDID data in BIOS!\n" );
578 goto no_vesa1;
579 }
580 dprintf( "vesa3: ATI: EDID data found at 0x%x\n", ptr-video_bios );*/
581
582 // find EDID destination block
583 i = *(uint16*)&video_bios[*(uint16*)&video_bios[*(uint16*)&video_bios[0x48]+0x34]+0x2];
584 dprintf( "vesa3: ATI: EDID destination at 0x%x\n", i );
585 ati_edid_dest = (struct s_edid *)&video_bios[i];
586
587 //*(uint16*)(&video_bios[6]) = pm_info->sel_code;
588 *(uint32*)(&video_bios[4]) = 0;
589 }
590 else {
591 dprintf( "vesa3: checksum wrong!\n" );
592 goto no_vesa1;
593 }
594 }
595
596 // VBE 3.0 pm block found!
597
598 // we start with the init function
599 retn = pm_info->init_offs;
600
601 // now analyze the bios to find out if it is a nVidia derived broken one
602 if ( video_bios[retn] == 0xe9 ) { // jmp
603 ptr = (unsigned char*)(video_bios+retn+3) + *(uint16*)&(video_bios[retn+1]);
604 // look for "mov ds,[cs:0x6e]; call ?; mov ax,[cs:0x66]"
605 if ( *(uint32*)ptr == 0x6e1e8e2e && *(uint16*)(ptr+4) == 0xe800 && *(uint32*)(ptr+8) == 0x0066a12e ) {
606 // look for "o32 retn" (broken bios) or "retf" (repaired bios)
607 ptr += 12;
608 while ( ptr <= video_bios+0x8000-2 && *ptr != 0xcb && *(uint16*)ptr != 0xc366 )
609 ptr++;
610 // ok, this bios is quite certainly broken, so we patch it
611 if ( *(uint16*)ptr == 0xc366 ) {
612 dprintf( "vesa3: nVidia: detected broken nVidia BIOS... trying to fix it...\n" );
613 bios_vendor = BIOS_NVIDIA;
614 vesa3_set_mode_CRTC = vesa3_set_mode_CRTC_nVidia;
615 vesa_data_size += 0x800; // account for copy of bios video tables
616 // we can't call directly so we write a stub code
617 // at the end of the bios code
618 ptr = video_bios+0xf000;
619 dprintf( "vesa3: nVidia: creating stub code at %x...\n", (int)ptr );
620 *((uint16*)ptr)++ = 0xbe66; // mov esi,retn
621 *((int32*)ptr)++ = (int32)&retn;
622 *((uint32*)ptr)++ = 0x68368b67; // mov si,[esi]
623 *((uint16*)ptr)++ = 0x0000; // push 0
624 *((uint32*)ptr)++ = 0xcb66d6ff; // call si; o32 retf
625 // the other places we need to fix is where they try to load
626 // the video parameter tables at address 0x4a8
627 for ( ptr = video_bios+0x5b; ptr <= video_bios+0x8000-10; ptr++ )
628 // these are either "les ?,[es:?...]"
629 if ( *((uint16*)ptr) == 0xc426 ) {
630 // sub bx,bx; mov es,bx; les bx,[es:0x4a8]; les bx,[es:bx+0x10]; les bx,[es:bx+0x16]
631 // -> sub bx,bx; mov es,bx; 13 x nop;
632 if ( *(uint32*)(ptr-4) == 0xc38edb2b
633 && *(uint32*)(ptr+1) == 0x04a81ec4
634 && *(uint32*)(ptr+5) == 0x105fc426
635 && *(uint32*)(ptr+9) == 0x165fc426 ) {
636 dprintf( "vesa3: patching %x...\n", (int)ptr );
637 for ( i = 0; i < 13; i++ ) *ptr++ = 0x90;
638 }
639/* else if ( *(uint32*)(ptr-4) == 0x04a83ec4 ) {
640 // les di,[0x4a8]; les di,[es:di]
641 // -> push ds; pop es; mov di,0x600; nop; nop
642 if ( *(ptr+2) == 0x3d ) {
643 dprintf( "vesa3: patching %x...\n", (int)(ptr-4) );
644 *(uint32*)(ptr-4) = 0x00bf071e;
645 *(uint16*)ptr = 0x9006;
646 *(ptr+2) = 0x90;
647 }
648 // les di,[0x4a8]; les di,[es:di+0x10] || les di,[es:di+0x4]
649 // -> xor di,di; mov es,di; 4 x nop;
650 else if ( *(uint16*)(ptr+2) == 0x107d || *(uint16*)(ptr+2) == 0x047d ) {
651 dprintf( "vesa3: patching %x...\n", (int)(ptr-4) );
652 *(uint32*)(ptr-4) = 0xc78eff31;
653 *(uint32*)ptr = 0x90909090;
654 }
655 }*/
656 }
657/* // or "lds si,[0x4a8]; lds si,[si]"
658 // -> mov esi,0x600
659 else if ( *(uint32*)ptr == 0x04a836c5 && *(uint16*)(ptr+4) == 0x34c5 ) {
660 dprintf( "vesa3: patching %x...\n", (int)ptr );
661 *(uint32*)ptr = 0x0600be66;
662 *(uint16*)(ptr+4) = 0x0000;
663 }*/
664 }
665 }
666 }
667
668 // setup structure (provide selectors, map video mem, ...)
669 ret_val = ERR_NO_MEMORY;
670 bios_data = (char *)kmalloc( vesa_data_size );
671 if ( bios_data == NULL )
672 goto no_vesa1;
673 bios_stack = (char *)kmalloc( VESA_STACK_SIZE );
674 if ( bios_stack == NULL )
675 goto no_vesa2;
676 memset( bios_data, 0, VESA_DATA_SIZE );
677
678 pm_info->sel_bios_data = i386_selector_add( SELECTOR(bios_data,vesa_data_size-1,DATA_w,false) );
679 pm_info->sel_code = i386_selector_add( SELECTOR(video_bios,VESA_CODE_SIZE-1,DATA_w,false) );
680
681 sel_code = i386_selector_add( SELECTOR(video_bios,VESA_CODE_SIZE-1,CODE_r,false) );
682 sel_stack = i386_selector_add( SELECTOR(bios_stack,VESA_STACK_SIZE-1,DATA_w,false) );
683
684 if ( bios_vendor == BIOS_NVIDIA ) {
685 farcall.offset = 0xf000;
686 farcall.seg = sel_code;
687#if 0
688 // copy video tables to local memory
689 ret_val = vm_map_physical_memory( sp, "video_tables", (void**)&ptr,
690 REGION_ADDR_ANY_ADDRESS, 0x100000, LOCK_RW | LOCK_KERNEL, (addr_t)0x0 );
691 if ( ret_val < 0 )
692 goto no_vesa3;
693 dprintf("vesa3: nVidia: (int)linear(ptr+0x4a8) = 0x%x\n", (int)linear(ptr+0x4a8) );
694 memcpy( bios_data+VESA_DATA_SIZE, ptr+(int)linear(ptr+(int)linear(ptr+0x4a8)), 29*64 ); // video parameter table
695 vm_delete_region( sp, ret_val );
696#else
697 dprintf( "vesa3: nVidia: setting up fake video parameter table...\n" );
698 memcpy( bios_data+VESA_DATA_SIZE, video_param_table, 29*64 ); // VGA video parameter table
699 ptr = bios_data+VESA_DATA_SIZE+29*64; // video save pointer table
700 memset( ptr, 0, 0x1c ); // make sure it is zeroed out
701 *(uint16 *)ptr = VESA_DATA_SIZE; // first entry is pointer to video parameter table
702 *(uint16 *)(ptr+2) = pm_info->sel_bios_data;
703 *(uint16*)(bios_data+0x4a8) = VESA_DATA_SIZE+29*64; // 0x4a8 is pointer to video save pointer table
704 *(uint16*)(bios_data+0x4a8+2) = pm_info->sel_bios_data;
705/**ptr1 = 0x68;
706*(uint16*)(ptr1+1) = pm_info->sel_code;
707*(uint32*)(ptr1+3) = 0x0798bf07;
708*(uint32*)ptr2 = 0x0798be66;
709*(uint16*)(ptr2+4) = 0x0000;*/
710/*memcpy( bios_data+0x449, video_table1, sizeof(video_table1) );
711memcpy( bios_data+0x484, video_table2, sizeof(video_table2) );
712*(uint16*)(bios_data+0x4a8) = 0x2878;
713*(uint16*)(bios_data+0x4a8+2) = pm_info->sel_code;*/
714#endif
715 dprintf( "vesa3: nVidia: patching done.\n" );
716 }
717 else {
718 farcall.offset = 0;
719 farcall.seg = i386_selector_add( SELECTOR(vesa3_call_retf,0x20-1,CODE_r,false) );
720 retn |= sel_code<<16;
721 }
722
723 ret_val = id = vm_map_physical_memory( sp, "video_mem", (void**)&video_mem,
724 REGION_ADDR_ANY_ADDRESS, 0x20000, LOCK_RW | LOCK_KERNEL, (addr_t)0xa0000 );
725 if ( ret_val < 0 )
726 goto no_vesa3;
727
728 pm_info->sel_a0000 = i386_selector_add( SELECTOR(video_mem,0x10000-1,DATA_w,false) );
729 pm_info->sel_b0000 = i386_selector_add( SELECTOR(video_mem+0x10000,0x10000-1,DATA_w,false) );
730 pm_info->sel_b8000 = i386_selector_add( SELECTOR(video_mem+0x18000,0x8000-1,DATA_w,false) );
731/*
732 pm_info->sel_a0000 = i386_selector_add( SELECTOR(0xa0000,0x10000-1,DATA_w,false) );
733 pm_info->sel_b0000 = i386_selector_add( SELECTOR(0xb0000,0x8000-1,DATA_w,false) );
734 pm_info->sel_b8000 = i386_selector_add( SELECTOR(0xb8000,0x8000-1,DATA_w,false) );*/
735
736 pm_info->in_pm = 1;
737
738/* // print some debug info
739 dprintf( "vesa3: video_bios: 0x%x\n", (int)video_bios );
740 dprintf( "vesa3: init_offs: 0x%x\n", (int)video_bios+(int)pm_info->init_offs );
741 dprintf( "vesa3: call_offs: 0x%x\n", (int)video_bios+(int)pm_info->call_offs );
742 dprintf( "vesa3: vesa_call: 0x%x\n", (int)vesa_call );
743 dprintf( "vesa3: vesa3_call_retf: 0x%x\n", (int)vesa3_call_retf );*/
744
745/*#ifdef DIAMOND_VIPER_V550_1_93E
746 // patch
747 ptr = (char *)((int)video_bios+0x4885);
748 *ptr++ = 0xeb; // jmp
749 *ptr++ = 0x17; // +0x17
750 ptr = (char *)((int)video_bios+0x2f9d);
751 *ptr++ = 0x1e; // push ds
752 *ptr++ = 0x07; // pop es
753 *ptr++ = 0xbf; // mov di,0x600
754 *ptr++ = 0x00;
755 *ptr++ = 0x06;
756 *ptr++ = 0x90; // nop
757 *ptr++ = 0x90; // nop
758 ptr = (char *)((int)video_bios+0x3388);
759 *ptr++ = 0x1f; // pop ds
760 *ptr++ = 0xeb; // jmp
761 *ptr++ = 0x15; // +0x15
762 ptr = (char *)((int)video_bios+0x3085);
763 *ptr++ = 0xeb; // jmp
764 *ptr++ = 0x41; // +0x41
765 ptr = video_bios+0x69ac;
766 *(uint32*)ptr = 0x0600be66; // mov esi,0x600
767 *(uint16*)(ptr+4) = 0x0000;
768
769 ptr = video_bios+0xf000;
770 *ptr++ = 0x66; // mov esi,retn
771 *ptr++ = 0xbe;
772 *((int32*)ptr)++ = &retn;
773 *ptr++ = 0x67; // mov si,[esi]
774 *ptr++ = 0x8b;
775 *ptr++ = 0x36;
776 *ptr++ = 0x68; // push 0
777 *ptr++ = 0x00;
778 *ptr++ = 0x00;
779 *ptr++ = 0xff; // call si
780 *ptr++ = 0xd6;
781 *ptr++ = 0x66; // o32
782 *ptr++ = 0xcb; // retf
783#else
784#endif*/
785
786 dprintf( "vesa3: calling init...\n" );
787
788 regs.es = 0;
789 vesa_call( &regs ); // init
790 retn = (retn & 0xffff0000) | pm_info->call_offs;
791
792 dprintf( "vesa3: reading controller information...\n" );
793
794 regs.ax = 0x4f00;
795 regs.es = sel_infoblock = i386_selector_add( SELECTOR(&infoblock,sizeof(infoblock)-1,DATA_w,false) );
796 regs.di = 0;
797 infoblock.signature = 'V'|('B'<<8)|('E'<<16)|('2'<<24);
798 vesa_call( &regs ); // get VBE controller information
799 i386_selector_remove( sel_infoblock );
800
801 dprintf( "vesa3: signature: %4s, version: 0x%x\n", (char*)&infoblock.signature, infoblock.version );
802
803 resolve_farptr( &infoblock.oem_string_ptr );
804 if ( infoblock.oem_string_ptr )
805 dprintf( "vesa3: OEM string: %s\n", (char*)infoblock.oem_string_ptr );
806
807 resolve_farptr( &infoblock.oem_vendor_name_ptr );
808 if ( infoblock.oem_vendor_name_ptr )
809 dprintf( "vesa3: OEM vendor name: %s\n", (char*)infoblock.oem_vendor_name_ptr );
810
811 resolve_farptr( &infoblock.oem_product_name_ptr );
812 if ( infoblock.oem_product_name_ptr )
813 dprintf( "vesa3: OEM product name: %s\n", (char*)infoblock.oem_product_name_ptr );
814
815 resolve_farptr( &infoblock.video_mode_ptr );
816#if 0 // broken ATI bios
817 {
818 struct s_farcall farcall_bak = farcall;
819 int retn_bak = retn;
820
821 farcall.offset = 0xf000;
822 farcall.seg = sel_code;
823 retn = 0x9ba0;
824
825 video_bios[0x9bd7] = 0x00; //0x21;
826
827 ptr = video_bios+0xf000;
828 dprintf( "vesa3: creating stub code at %x...\n", (int)ptr );
829 *((uint16*)ptr)++ = 0xbe66; // mov esi,retn
830 *((int32*)ptr)++ = (int32)&retn;
831 *((uint32*)ptr)++ = 0xff368b67; // mov si,[esi]
832 *((uint32*)ptr)++ = 0xcb66d6; // call si; o32 retf
833
834 for ( i = 0; ; i++ ) {
835 regs.bx = i<<8;
836 regs.es = pm_info->sel_code;
837 regs.di = 0x9b8e; //0x1f32
838 vesa_call( &regs ); // init
839 }
840
841 farcall = farcall_bak;
842 retn = retn_bak;
843 }
844#endif
845
846 dprintf( "vesa3: successfully initialized!\n" );
847
848 ret_val = devfs_publish_indexed_device( "graphics/vesa3/fb", NULL, &vesa3_hooks );
849 if ( ret_val >= 0 )
850 return NO_ERROR;
851//ret_val = devfs_publish_indexed_device( "graphics/fb", NULL, &vesa3_hooks );
852
853 vm_delete_region( sp, id );
854 no_vesa3:
855 kfree( bios_stack );
856 no_vesa2:
857 kfree( bios_data );
858 no_vesa1:
859 kfree( video_bios );
860 dprintf( "vesa3: failed.\n" );
861
862 return ret_val;
863}