X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=lib_i386%2Frealmode.c;h=6cf273885b838ed55d1c2d02710a722ee4bc0f98;hb=b4983e16d150ab7d039704c310aacbd2f4dc1e0f;hp=372147cf246afee0adbdb05021ce0140792bcb4b;hpb=2262cfeef91458b01a1bfe3812ccbbfdf8b82807;p=u-boot diff --git a/lib_i386/realmode.c b/lib_i386/realmode.c index 372147cf24..6cf273885b 100644 --- a/lib_i386/realmode.c +++ b/lib_i386/realmode.c @@ -1,7 +1,7 @@ /* * (C) Copyright 2002 * Daniel Engström, Omicron Ceti AB, daniel@omicron.se - * + * * See file CREDITS for list of people who contributed to this * project. * @@ -24,6 +24,7 @@ #include #include #include +#include #define REALMODE_BASE ((char*)0x7c0) @@ -32,38 +33,63 @@ extern char realmode_enter; +int realmode_setup(void) +{ + /* copy the realmode switch code */ + if (i386boot_realmode_size > (REALMODE_MAILBOX-REALMODE_BASE)) { + printf("realmode switch too large (%ld bytes, max is %d)\n", + i386boot_realmode_size, (REALMODE_MAILBOX-REALMODE_BASE)); + return -1; + } + + memcpy(REALMODE_BASE, (void*)i386boot_realmode, i386boot_realmode_size); + asm("wbinvd\n"); + + return 0; +} int enter_realmode(u16 seg, u16 off, struct pt_regs *in, struct pt_regs *out) { - + /* setup out thin bios emulation */ if (bios_setup()) { return -1; } - - /* copy the realmode switch code */ - if (i386boot_realmode_size > (REALMODE_MAILBOX-REALMODE_BASE)) { - printf("realmode switch too large (%ld bytes, max is %d)\n", - i386boot_realmode_size, (REALMODE_MAILBOX-REALMODE_BASE)); + + if (realmode_setup()) { return -1; } - - memcpy(REALMODE_BASE, i386boot_realmode, i386boot_realmode_size); - - + in->eip = off; in->xcs = seg; - if (3>in->esp & 0xffff) { + if (3>(in->esp & 0xffff)) { printf("Warning: entering realmode with sp < 4 will fail\n"); } - + memcpy(REALMODE_MAILBOX, in, sizeof(struct pt_regs)); - - __asm__ volatile ( + asm("wbinvd\n"); + + __asm__ volatile ( "lcall $0x20,%0\n" : : "i" (&realmode_enter) ); + asm("wbinvd\n"); memcpy(out, REALMODE_MAILBOX, sizeof(struct pt_regs)); return out->eax; } + +/* This code is supposed to access a realmode interrupt + * it does currently not work for me */ +int enter_realmode_int(u8 lvl, struct pt_regs *in, struct pt_regs *out) +{ + /* place two instructions at 0x700 */ + writeb(0xcd, 0x700); /* int $lvl */ + writeb(lvl, 0x701); + writeb(0xcb, 0x702); /* lret */ + asm("wbinvd\n"); + + enter_realmode(0x00, 0x700, in, out); + + return out->eflags&1; +}