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