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