share decompression code.
[coreboot.git] / src / cpu / amd / model_gx2 / vsmsetup.c
1 #include <console/console.h>
2 #include <device/pci.h>
3 #include <device/pci_ids.h>
4 #include <device/pci_ops.h>
5 #undef __KERNEL__
6 #include <arch/io.h>
7 #include <string.h>
8 #include <cpu/amd/gx2def.h>
9
10 /* what a mess this uncompress thing is. I am not at all happy about how this 
11  * was done, but can't fix it yet. RGM
12  */
13 #warning "Fix the uncompress once linuxbios knows how to do it"
14 #include "../lib/nrv2b.c"
15
16 /* vsmsetup.c derived from vgabios.c. Derived from: */
17
18 /*------------------------------------------------------------ -*- C -*-
19  *  2 Kernel Monte a.k.a. Linux loading Linux on x86
20  *
21  *  Erik Arjan Hendriks <hendriks@lanl.gov>
22  *
23  *  This version is a derivative of the original two kernel monte
24  *  which is (C) 2000 Scyld.
25  *
26  *  Copyright (C) 2000 Scyld Computing Corporation
27  *
28  *  This program is free software; you can redistribute it and/or modify
29  *  it under the terms of the GNU General Public License as published by
30  *  the Free Software Foundation; either version 2 of the License, or
31  *  (at your option) any later version.
32  *
33  *  This program is distributed in the hope that it will be useful,
34  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
35  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  *  GNU General Public License for more details.
37  *
38  *  You should have received a copy of the GNU General Public License
39  *  along with this program; if not, write to the Free Software
40  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41  *
42  * Portions related to the alpha architecture are:
43  *
44  *  Copyright(C) 2001 University of California.  LA-CC Number 01-67.
45  *  This software has been authored by an employee or employees of the
46  *  University of California, operator of the Los Alamos National
47  *  Laboratory under Contract No.  W-7405-ENG-36 with the U.S.
48  *  Department of Energy.  The U.S. Government has rights to use,
49  *  reproduce, and distribute this software. If the software is
50  *  modified to produce derivative works, such modified software should
51  *  be clearly marked, so as not to confuse it with the version
52  *  available from LANL.
53  *
54  *  This software may be used and distributed according to the terms
55  *  of the GNU General Public License, incorporated herein by
56  *  reference to http://www.gnu.org/licenses/gpl.html.
57  *
58  *  This software is provided by the author(s) "as is" and any express
59  *  or implied warranties, including, but not limited to, the implied
60  *  warranties of merchantability and fitness for a particular purpose
61  *  are disclaimed.  In no event shall the author(s) be liable for any
62  *  direct, indirect, incidental, special, exemplary, or consequential
63  *  damages (including, but not limited to, procurement of substitute
64  *  goods or services; loss of use, data, or profits; or business
65  *  interruption) however caused and on any theory of liability,
66  *  whether in contract, strict liability, or tort (including
67  *  negligence or otherwise) arising in any way out of the use of this
68  *  software, even if advised of the possibility of such damage.
69  *
70  *  $Id: Exp $
71  *--------------------------------------------------------------------*/
72
73 /* Modified to be a self sufficient plug in so that it can be used 
74    without reliance on other parts of core Linuxbios 
75    (C) 2005 Nick.Barker9@btinternet.com
76
77   Used initially for epia-m where there are problems getting the bios
78   emulator to successfully run this bios.
79 */
80
81 /* Declare a temporary global descriptor table - necessary because the
82    Core part of the bios no longer sets up any 16 bit segments */
83 __asm__ (
84         /* pointer to original gdt */
85         "gdtarg:                        \n"
86         "       .word   gdt_limit       \n"
87         "       .long   gdt             \n"             
88
89         /* compute the table limit */
90         "__mygdt_limit = __mygdt_end - __mygdt - 1      \n"
91
92         "__mygdtaddr:                   \n"
93         "       .word   __mygdt_limit   \n"
94         "       .long   __mygdt         \n"
95
96         "__mygdt:                       \n"
97         /* selgdt 0, unused */
98         "       .word   0x0000, 0x0000  \n"
99         "       .byte   0x00, 0x00, 0x00, 0x00  \n"
100
101         /* selgdt 8, unused */
102         "       .word   0x0000, 0x0000          \n"
103         "       .byte   0x00, 0x00, 0x00, 0x00  \n"
104
105         /* selgdt 0x10, flat code segment */
106         "       .word   0xffff, 0x0000          \n"
107         "       .byte   0x00, 0x9b, 0xcf, 0x00  \n"     
108
109         /* selgdt 0x18, flat data segment */
110         "       .word   0xffff, 0x0000          \n"
111         "       .byte   0x00, 0x93, 0xcf, 0x00  \n"
112
113         /* selgdt 0x20, unused */
114         "       .word   0x0000, 0x0000          \n"
115         "       .byte   0x00, 0x00, 0x00, 0x00  \n"
116
117         /* selgdt 0x28 16-bit 64k code at 0x00000000 */
118         "       .word   0xffff, 0x0000          \n"
119         "       .byte   0, 0x9a, 0, 0           \n"
120
121         /* selgdt 0x30 16-bit 64k data at 0x00000000 */
122         "       .word   0xffff, 0x0000          \n"
123         "       .byte   0, 0x92, 0, 0           \n"
124
125         "__mygdt_end:                           \n"
126 );
127
128 /* Declare a pointer to where our idt is going to be i.e. at mem zero */
129 __asm__ ("__myidt:              \n"
130          /* 16-bit limit */
131          "      .word 1023      \n"
132          /* 24-bit base */
133          "      .long 0         \n"
134          "      .word 0         \n"
135 );
136
137 /* The address arguments to this function are PHYSICAL ADDRESSES */ 
138 static void real_mode_switch_call_vsm(unsigned long smm, unsigned long sysm)
139 {
140         __asm__ __volatile__ (
141                 // paranoia -- does ecx get saved? not sure. This is 
142                 // the easiest safe thing to do.
143                 "       pushal                  \n"
144                 /* save the stack */
145                 "       mov     %esp, __stack   \n"
146                 "       jmp     1f              \n"
147                 "__stack: .long 0               \n"
148                 "1:\n"
149                 /* get devfn into %ecx */
150                 "       movl    %esp, %ebp      \n"
151 #if 0
152                 /* I'm not happy about that pushal followed by esp-relative references. 
153                   * just do hard-codes for now
154                   */
155                 "       movl    8(%ebp), %ecx   \n"
156                 "       movl    12(%ebp), %edx  \n"
157 #endif
158                 "       movl    $0x10000026, %ecx       \n"
159                 "       movl    $0x10000028, %edx       \n"
160
161                 /* load 'our' gdt */
162                 "       lgdt    %cs:__mygdtaddr \n"
163
164                 /*  This configures CS properly for real mode. */
165                 "       ljmp    $0x28, $__rms_16bit\n"
166                 "__rms_16bit:                   \n"
167                 "       .code16                 \n"
168                 /* 16 bit code from here on... */
169
170                 /* Load the segment registers w/ properly configured segment
171                  * descriptors.  They will retain these configurations (limits,
172                  * writability, etc.) once protected mode is turned off. */
173                 "       mov     $0x30, %ax      \n"
174                 "       mov     %ax, %ds        \n"
175                 "       mov     %ax, %es        \n"
176                 "       mov     %ax, %fs        \n"
177                 "       mov     %ax, %gs        \n"
178                 "       mov     %ax, %ss        \n"
179
180                 /* Turn off protection (bit 0 in CR0) */
181                 "       movl    %cr0, %eax      \n"
182                 "       andl    $0xFFFFFFFE, %eax \n"
183                 "       movl    %eax, %cr0      \n"
184
185                 /* Now really going into real mode */
186                 "       ljmp    $0,  $__rms_real\n"
187                 "__rms_real:                    \n"
188
189                 /* put the stack at the end of page zero. 
190                  * that way we can easily share it between real and protected, 
191                  * since the 16-bit ESP at segment 0 will work for any case. */
192                 /* Setup a stack */
193                 "       mov     $0x0, %ax       \n"
194                 "       mov     %ax, %ss        \n"
195                 "       movl    $0x1000, %eax   \n"
196                 "       movl    %eax, %esp      \n"
197
198                 /* Load our 16 it idt */
199                 "       xor     %ax, %ax        \n"
200                 "       mov     %ax, %ds        \n"
201                 "       lidt    __myidt         \n"
202
203                 /* Dump zeros in the other segregs */
204                 "       mov     %ax, %es        \n"
205                 /* FixMe: Big real mode for gs, fs? */
206                 "       mov     %ax, %fs        \n"
207                 "       mov     %ax, %gs        \n"
208                 "       mov     $0x40, %ax      \n"
209                 "       mov     %ax, %ds        \n"
210                 //"     mov     %cx, %ax        \n"
211                 "       movl    $0x10000026, %ecx       \n"
212                 "       movl    $0x10000028, %edx       \n"
213
214                 /* run VGA BIOS at 0x6000:0020 */
215                 "       lcall   $0x6000, $0x0020\n"
216
217                 /* if we got here, just about done. 
218                  * Need to get back to protected mode */
219                 "       movl    %cr0, %eax      \n"
220                 "       orl     $0x0000001, %eax\n" /* PE = 1 */
221                 "       movl    %eax, %cr0      \n"
222
223                 /* Now that we are in protected mode jump to a 32 bit code segment. */
224                 "       data32  ljmp    $0x10, $vsmrestart\n"
225                 "vsmrestart:\n"
226                 "       .code32\n"
227                 "       movw    $0x18, %ax      \n"
228                 "       mov     %ax, %ds        \n"
229                 "       mov     %ax, %es        \n"
230                 "       mov     %ax, %fs        \n"
231                 "       mov     %ax, %gs        \n"
232                 "       mov     %ax, %ss        \n"
233
234                 /* restore proper gdt and idt */
235                 "       lgdt    %cs:gdtarg      \n"
236                 "       lidt    idtarg          \n"
237
238                 ".globl vsm_exit                \n"
239                 "vsm_exit:                      \n"
240                 "       mov     __stack, %esp   \n"
241                 "       popal                   \n"
242                 );
243 }
244
245 __asm__ (".text\n""real_mode_switch_end:\n");
246 extern char real_mode_switch_end[];
247
248
249 void do_vsmbios(void)
250 {
251         device_t dev;
252         unsigned long busdevfn;
253         unsigned int rom = 0;
254         unsigned char *buf;
255         unsigned int size = SMM_SIZE*1024;
256         int i;
257         
258         printk_err("do_vsmbios\n");
259         /* clear vsm bios data area */
260         for (i = 0x400; i < 0x500; i++) {
261                 *(unsigned char *) i = 0;
262         }
263
264         /* declare rom address here - keep any config data out of the way
265          * of core LXB stuff */
266
267         /* this is the base of rom on the GX2 at present. At some point, this has to be 
268           * much better parameterized 
269           */
270         //rom = 0xfff80000;
271         //rom = 0xfffc0000;
272         /* the VSA starts at the base of rom - 64 */
273         rom = ((unsigned long) 0) - (ROM_SIZE  + 64*1024);
274
275         buf = (unsigned char *) 0x60000;
276         unrv2b((uint8_t *)rom, buf);
277         printk_debug("buf %p *buf %d buf[256k] %d\n",
278                      buf, buf[0], buf[SMM_SIZE*1024]);
279         printk_debug("buf[0x20] signature is %x:%x:%x:%x\n",
280                      buf[0x20] ,buf[0x21] ,buf[0x22],buf[0x23]);
281         /* check for post code at start of vsainit.bin. If you don't see it,
282            don't bother. */
283         if ((buf[0x20] != 0xb0) || (buf[0x21] != 0x10) ||
284             (buf[0x22] != 0xe6) || (buf[0x23] != 0x80)) {
285                 printk_err("do_vsmbios: no vsainit.bin signature, skipping!\n");
286                 return;
287         }
288
289         //memcpy((void *) 0x60000, buf, size);
290
291         //for (i = 0; i < 0x800000; i++)
292         //      outb(0xaa, 0x80);
293
294         /* ecx gets smm, edx gets sysm */
295         printk_err("Call real_mode_switch_call_vsm\n");
296         real_mode_switch_call_vsm(0x10000026, 0x10000028);
297
298         /* restart timer 1 */
299         outb(0x56, 0x43);
300         outb(0x12, 0x41);
301 }
302
303
304 // we had hoped to avoid this. 
305 // this is a stub IDT only. It's main purpose is to ignore calls 
306 // to the BIOS. 
307 // no longer. Dammit. We have to respond to these.
308 struct realidt {
309         unsigned short offset, cs;
310 }; 
311
312 // from a handy writeup that andrey found.
313
314 // handler. 
315 // There are some assumptions we can make here. 
316 // First, the Top Of Stack (TOS) is located on the top of page zero. 
317 // we can share this stack between real and protected mode. 
318 // that simplifies a lot of things ...
319 // we'll just push all the registers on the stack as longwords, 
320 // and pop to protected mode. 
321 // second, since this only ever runs as part of linuxbios, 
322 // we know all the segment register values -- so we don't save any.
323 // keep the handler that calls things small. It can do a call to 
324 // more complex code in linuxbios itself. This helps a lot as we don't
325 // have to do address fixup in this little stub, and calls are absolute
326 // so the handler is relocatable.
327 void handler(void)
328 {
329         __asm__ __volatile__ ( 
330                 "       .code16         \n"
331                 "idthandle:             \n"
332                 "       pushal          \n"
333                 "       movb    $0, %al \n"
334                 "       ljmp    $0, $callbiosint16\n"
335                 "end_idthandle:         \n"
336                 "       .code32         \n"
337                 );
338 }
339
340 void debughandler(void)
341 {
342         __asm__ __volatile__ ( 
343                 "       .code16         \n"
344                 "debughandle:           \n"
345                 "       pushw   %cx     \n"
346                 "       movw    $250, %cx \n"
347                 "dbh1:                  \n"
348                 "       loop    dbh1    \n"
349                 "       popw    %cx     \n"
350                 "       iret            \n"
351                 "end_debughandle:       \n"
352                 ".code32                \n"
353                 );
354 }
355
356 // Calling conventions. The first C function is called with this stuff
357 // on the stack. They look like value parameters, but note that if you
358 // modify them they will go back to the INTx function modified. 
359 // the C function will call the biosint function with these as
360 // REFERENCE parameters. In this way, we can easily get 
361 // returns back to the INTx caller (i.e. vgabios)
362 void callbiosint(void)
363 {
364         __asm__ __volatile__ (
365                 "       .code16         \n"
366                 "callbiosint16:         \n"
367                 "       push    %ds     \n"
368                 "       push    %es     \n"
369                 "       push    %fs     \n"
370                 "       push    %gs     \n"
371                 // clean up the int #. To save space we put it in the lower
372                 // byte. But the top 24 bits are junk. 
373                 "       andl    $0xff, %eax\n"
374                 // this push does two things:
375                 // - put the INT # on the stack as a parameter
376                 // - provides us with a temp for the %cr0 mods.
377                 "       pushl   %eax    \n"
378                 "       movb    $0xbb, %al\n"
379                 "       outb    %al, $0x80\n"
380                 "       movl    %cr0, %eax\n"
381                 "       orl     $0x00000001, %eax\n" /* PE = 1 */
382                 "       movl    %eax, %cr0\n"
383                 /* Now that we are in protected mode jump to a 32 bit code segment. */
384                 "       data32  ljmp    $0x10, $biosprotect\n"
385                 "biosprotect:           \n"
386                 "       .code32         \n"
387                 "       movw    $0x18, %ax          \n"
388                 "       mov     %ax, %ds          \n"
389                 "       mov     %ax, %es          \n"
390                 "       mov     %ax, %fs          \n"
391                 "       mov     %ax, %gs          \n"
392                 "       mov     %ax, %ss          \n"
393                 "       lidt    idtarg          \n"
394                 "       call    biosint         \n"
395                 // back to real mode ...
396                 "       ljmp    $0x28, $__rms_16bit2\n"
397                 "__rms_16bit2:                  \n"
398                 "       .code16                 \n"
399                 /* 16 bit code from here on... */
400                 /* Load the segment registers w/ properly configured segment
401                  * descriptors.  They will retain these configurations (limits,
402                  * writability, etc.) once protected mode is turned off. */
403                 "       mov     $0x30, %ax      \n"
404                 "       mov     %ax, %ds        \n"
405                 "       mov     %ax, %es        \n"
406                 "       mov     %ax, %fs        \n"
407                 "       mov     %ax, %gs        \n"
408                 "       mov     %ax, %ss        \n"
409                 
410                 /* Turn off protection (bit 0 in CR0) */
411                 "       movl    %cr0, %eax              \n"
412                 "       andl    $0xFFFFFFFE, %eax       \n"
413                 "       movl    %eax, %cr0              \n"
414
415                 /* Now really going into real mode */
416                 "       ljmp $0,  $__rms_real2  \n"
417                 "__rms_real2:                   \n"
418
419                 /* Setup a stack
420                  * FixME: where is esp? */
421                 /* no need for a fix here. The esp is shared from 32-bit and 16-bit mode. 
422                   * you have to hack on the ss, but the esp remains the same across 
423                   * modes. 
424                   */
425                 "       mov     $0x0, %ax       \n"
426                 "       mov     %ax, %ss        \n"
427
428                 /* debugging for RGM */
429                 "       mov     $0x11, %al      \n"
430                 "       outb    %al, $0x80      \n"
431
432                 /* Load our 16 bit idt */
433                 "       xor     %ax, %ax        \n"
434                 "       mov     %ax, %ds        \n"
435                 "       lidt    __myidt         \n"
436
437                 /* Dump zeros in the other segregs */
438                 "       mov     %ax, %es        \n"
439                 "       mov     %ax, %fs        \n"
440                 "       mov     %ax, %gs        \n"
441                 "       mov     $0x40, %ax      \n"
442                 "       mov     %ax, %ds        \n"
443
444                 /* pop the INT # that you pushed earlier */
445                 "       popl    %eax            \n"
446                 "       pop     %gs             \n"
447                 "       pop     %fs             \n"
448                 "       pop     %es             \n"
449                 "       pop     %ds             \n"
450                 "       popal                   \n"
451                 "       iret                    \n"
452                 "       .code32                 \n"
453                 );
454 }
455
456 enum {
457         PCIBIOS = 0x1a, 
458         MEMSIZE = 0x12
459 };
460
461 int pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp,
462             unsigned long *pesp, unsigned long *pebx, unsigned long *pedx,
463             unsigned long *pecx, unsigned long *peax, unsigned long *pflags);
464
465 int handleint21(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp,
466                 unsigned long *pesp, unsigned long *pebx, unsigned long *pedx,
467                 unsigned long *pecx, unsigned long *peax, unsigned long *pflags
468         );
469
470 int biosint(unsigned long intnumber,
471             unsigned long gsfs, unsigned long dses,
472             unsigned long edi, unsigned long esi,
473             unsigned long ebp, unsigned long esp, 
474             unsigned long ebx, unsigned long edx, 
475             unsigned long ecx, unsigned long eax, 
476             unsigned long cs_ip, unsigned short stackflags)
477 {
478         unsigned long ip; 
479         unsigned long cs; 
480         unsigned long flags;
481         int ret = -1;
482
483         ip = cs_ip & 0xffff;
484         cs = cs_ip >> 16;
485         flags = stackflags;
486         
487         printk_debug("biosint: INT# 0x%lx\n", intnumber);
488         printk_debug("biosint: eax 0x%lx ebx 0x%lx ecx 0x%lx edx 0x%lx\n", 
489                       eax, ebx, ecx, edx);
490         printk_debug("biosint: ebp 0x%lx esp 0x%lx edi 0x%lx esi 0x%lx\n",
491                      ebp, esp, edi, esi);
492         printk_debug("biosint:  ip 0x%x   cs 0x%x  flags 0x%x\n",
493                      ip, cs, flags);
494         printk_debug("biosint: gs 0x%x fs 0x%x ds 0x%x es 0x%x\n",
495                      gsfs >> 16, gsfs & 0xffff, dses >> 16, dses & 0xffff);
496
497         // cases in a good compiler are just as good as your own tables. 
498         switch (intnumber) {
499         case 0 ... 15:
500                 // These are not BIOS service, but the CPU-generated exceptions
501                 printk_info("biosint: Oops, exception %u\n", intnumber);
502                 if (esp < 0x1000) {
503                         printk_debug("Stack contents: ");
504                         while (esp < 0x1000) {
505                                 printk_debug("0x%04x ", *(unsigned short *) esp);
506                                 esp += 2;
507                         }
508                         printk_debug("\n");
509                 }
510                 printk_debug("biosint: Bailing out ... not now\n");
511                 // "longjmp"
512                 //vga_exit();
513                 break;
514                 
515         case PCIBIOS:
516                 ret = pcibios( &edi, &esi, &ebp, &esp, 
517                                &ebx, &edx, &ecx, &eax, &flags);
518                 break;
519         case MEMSIZE: 
520                 // who cares. 
521                 eax = 64 * 1024;
522                 ret = 0;
523                 break;
524         case 0x15:
525                 ret=handleint21( &edi, &esi, &ebp, &esp, 
526                                 &ebx, &edx, &ecx, &eax, &flags);
527                 break;
528         default:
529                 printk_info("BIOSINT: Unsupport int #0x%x\n", 
530                             intnumber);
531                 break;
532         }
533         if (ret)
534                 flags |= 1; // carry flags
535         else
536                 flags &= ~1;
537         stackflags = flags;
538         return ret;
539
540
541
542 void setup_realmode_idt(void) 
543 {
544         extern unsigned char idthandle, end_idthandle;
545         extern unsigned char debughandle, end_debughandle;
546
547         int i;
548         struct realidt *idts = (struct realidt *) 0;
549         int codesize = &end_idthandle - &idthandle;
550         unsigned char *intbyte, *codeptr;
551         
552         // for each int, we create a customized little handler
553         // that just pushes %ax, puts the int # in %al, 
554         // then calls the common interrupt handler. 
555         // this necessitated because intel didn't know much about 
556         // architecture when they did the 8086 (it shows)
557         // (hmm do they know anymore even now :-)
558         // obviously you can see I don't really care about memory 
559         // efficiency. If I did I would probe back through the stack
560         // and get it that way. But that's really disgusting.
561         for (i = 0; i < 256; i++) {
562                 idts[i].cs = 0;
563                 codeptr = (char*) 4096 + i * codesize;
564                 idts[i].offset = (unsigned) codeptr;
565                 memcpy(codeptr, &idthandle, codesize);
566                 intbyte = codeptr + 3;
567                 *intbyte = i;
568         }
569         
570         // fixed entry points
571         
572         // VGA BIOSes tend to hardcode f000:f065 as the previous handler of
573         // int10. 
574         // calling convention here is the same as INTs, we can reuse
575         // the int entry code.
576         codeptr = (char*) 0xff065;
577         memcpy(codeptr, &idthandle, codesize);
578         intbyte = codeptr + 3;
579         *intbyte = 0x42; /* int42 is the relocated int10 */
580
581         /* debug handler - useful to set a programmable delay between instructions if the
582            TF bit is set upon call to real mode */
583         idts[1].cs = 0;
584         idts[1].offset = 16384;
585         memcpy(16384, &debughandle, &end_debughandle - &debughandle);
586 }
587
588
589
590 enum {
591         CHECK = 0xb001,
592         FINDDEV = 0xb102,
593         READCONFBYTE = 0xb108,
594         READCONFWORD = 0xb109,
595         READCONFDWORD = 0xb10a,
596         WRITECONFBYTE = 0xb10b,
597         WRITECONFWORD = 0xb10c,
598         WRITECONFDWORD = 0xb10d
599 };
600
601 // errors go in AH. Just set these up so that word assigns
602 // will work. KISS. 
603 enum {
604         PCIBIOS_NODEV = 0x8600,
605         PCIBIOS_BADREG = 0x8700
606 };
607
608 int
609 pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp, 
610         unsigned long *pesp, unsigned long *pebx, unsigned long *pedx, 
611         unsigned long *pecx, unsigned long *peax, unsigned long *pflags)
612 {
613         unsigned long edi = *pedi;
614         unsigned long esi = *pesi;
615         unsigned long ebp = *pebp;
616         unsigned long esp = *pesp;
617         unsigned long ebx = *pebx;
618         unsigned long edx = *pedx;
619         unsigned long ecx = *pecx;
620         unsigned long eax = *peax;
621         unsigned long flags = *pflags;
622         unsigned short func = (unsigned short) eax;
623         int retval = 0;
624         unsigned short devid, vendorid, devfn;
625         short devindex; /* Use short to get rid of gabage in upper half of 32-bit register */
626         unsigned char bus;
627         device_t dev;
628         
629         switch(func) {
630         case  CHECK:
631                 *pedx = 0x4350;
632                 *pecx = 0x2049;
633                 retval = 0;
634                 break;
635         case FINDDEV:
636         {
637                 devid = *pecx;
638                 vendorid = *pedx;
639                 devindex = *pesi;
640                 dev = 0;
641                 while ((dev = dev_find_device(vendorid, devid, dev))) {
642                         if (devindex <= 0)
643                                 break;
644                         devindex--;
645                 }
646                 if (dev) {
647                         unsigned short busdevfn;
648                         *peax = 0;
649                         // busnum is an unsigned char;
650                         // devfn is an int, so we mask it off. 
651                         busdevfn = (dev->bus->secondary << 8)
652                                 | (dev->path.u.pci.devfn & 0xff);
653                         printk_debug("0x%x: return 0x%x\n", func, busdevfn);
654                         *pebx = busdevfn;
655                         retval = 0;
656                 } else {
657                         *peax = PCIBIOS_NODEV;
658                         retval = -1;
659                 }
660         }
661         break;
662         case READCONFDWORD:
663         case READCONFWORD:
664         case READCONFBYTE:
665         case WRITECONFDWORD:
666         case WRITECONFWORD:
667         case WRITECONFBYTE:
668         {
669                 unsigned long dword;
670                 unsigned short word;
671                 unsigned char byte;
672                 unsigned char reg;
673                 
674                 devfn = *pebx & 0xff;
675                 bus = *pebx >> 8;
676                 reg = *pedi;
677                 dev = dev_find_slot(bus, devfn);
678                 if (! dev) {
679                         printk_debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
680                         // idiots. the pcibios guys assumed you'd never pass a bad bus/devfn!
681                         *peax = PCIBIOS_BADREG;
682                         retval = -1;
683                 }
684                 switch(func) {
685                 case READCONFBYTE:
686                         byte = pci_read_config8(dev, reg);
687                         *pecx = byte;
688                         break;
689                 case READCONFWORD:
690                         word = pci_read_config16(dev, reg);
691                         *pecx = word;
692                         break;
693                 case READCONFDWORD:
694                         dword = pci_read_config32(dev, reg);
695                         *pecx = dword;
696                         break;
697                 case WRITECONFBYTE:
698                         byte = *pecx;
699                         pci_write_config8(dev, reg, byte);
700                         break;
701                 case WRITECONFWORD:
702                         word = *pecx;
703                         pci_write_config16(dev, reg, word);
704                         break;
705                 case WRITECONFDWORD:
706                         dword = *pecx;
707                         pci_write_config32(dev, reg, dword);
708                         break;
709                 }
710                 
711                 if (retval) 
712                         retval = PCIBIOS_BADREG;
713                 printk_debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%lx\n",
714                              func, bus, devfn, reg, *pecx);
715                 *peax = 0;
716                 retval = 0;
717         }
718         break;
719         default:
720                 printk_err("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n",  func);
721                 break;
722         }
723         
724         return retval;
725
726
727 int handleint21(unsigned long *edi, unsigned long *esi, unsigned long *ebp,
728                 unsigned long *esp, unsigned long *ebx, unsigned long *edx,
729                 unsigned long *ecx, unsigned long *eax, unsigned long *flags)
730 {
731         int res=-1;
732         printk_debug("handleint21, eax 0x%x\n", *eax);
733         switch(*eax&0xffff)
734         {
735         case 0x5f19:
736                 break;
737         case 0x5f18:
738                 *eax=0x5f;
739                 *ebx=0x545; // MCLK = 133, 32M frame buffer, 256 M main memory
740                 *ecx=0x060;
741                 res=0;
742                 break;
743         case 0x5f00:
744                 *eax = 0x8600;
745                 break;
746         case 0x5f01:
747                 *eax = 0x5f;
748                 *ecx = (*ecx & 0xffffff00 ) | 2; // panel type =  2 = 1024 * 768
749                 res = 0;
750                 break;
751         case 0x5f02:
752                 *eax=0x5f;
753                 *ebx= (*ebx & 0xffff0000) | 2;
754                 *ecx= (*ecx & 0xffff0000) | 0x401;  // PAL + crt only 
755                 *edx= (*edx & 0xffff0000) | 0;  // TV Layout - default
756                 res=0;
757                 break;
758         case 0x5f0f:
759                 *eax=0x860f;
760                 break;
761         case 0xBEA7:
762                 *eax=33;
763                 break;
764         case 0xBEA4:
765                 *eax=333;
766                 break;
767         }
768         return res;
769 }