From d650e9934ff8da9b9cb69e42e642c0ee6d390bf6 Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Mon, 22 Feb 2010 04:33:13 +0000 Subject: YABEL update - drop x86emu + old biosemu in favor of YABEL - Add YABEL_DIRECTHW to get the old biosemu behavior - add support for vesa console using YABEL - add coreboot table entry with console information - add bootsplash support (reads /bootsplash.jpg from CBFS) Signed-off-by: Stefan Reinauer Acked-by: Pattrick Hueper git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5135 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- src/arch/i386/boot/coreboot_table.c | 15 + src/arch/i386/include/arch/byteorder.h | 3 + src/devices/Kconfig | 123 ++-- src/include/boot/coreboot_tables.h | 32 +- src/lib/Makefile.inc | 2 + src/lib/cbfs.c | 10 +- src/lib/fallback_boot.c | 5 + src/lib/jpeg.c | 988 +++++++++++++++++++++++++++++++++ src/lib/jpeg.h | 56 ++ util/x86emu/Makefile | 72 --- util/x86emu/Makefile.inc | 8 +- util/x86emu/biosemu.c | 580 ------------------- util/x86emu/yabel/Makefile.inc | 1 + util/x86emu/yabel/biosemu.c | 11 +- util/x86emu/yabel/compat/functions.c | 25 +- util/x86emu/yabel/io.c | 71 +++ util/x86emu/yabel/mem.c | 38 ++ util/x86emu/yabel/vbe.c | 282 ++++++---- 18 files changed, 1506 insertions(+), 816 deletions(-) create mode 100644 src/lib/jpeg.c create mode 100644 src/lib/jpeg.h diff --git a/src/arch/i386/boot/coreboot_table.c b/src/arch/i386/boot/coreboot_table.c index e766463..f3b7f6d 100644 --- a/src/arch/i386/boot/coreboot_table.c +++ b/src/arch/i386/boot/coreboot_table.c @@ -148,6 +148,19 @@ static void lb_console(struct lb_header *header) #endif } +static void lb_framebuffer(struct lb_header *header) +{ +#if defined(CONFIG_BOOTSPLASH) && CONFIG_BOOTSPLASH && CONFIG_COREBOOT_KEEP_FRAMEBUFFER + void fill_lb_framebuffer(struct lb_framebuffer *framebuffer); + + struct lb_framebuffer *framebuffer; + framebuffer = (struct lb_framebuffer *)lb_new_record(header); + framebuffer->tag = LB_TAG_FRAMEBUFFER; + framebuffer->size = sizeof(*framebuffer); + fill_lb_framebuffer(framebuffer); +#endif +} + static struct lb_mainboard *lb_mainboard(struct lb_header *header) { struct lb_record *rec; @@ -565,6 +578,8 @@ unsigned long write_coreboot_table( lb_console(head); /* Record our various random string information */ lb_strings(head); + /* Record our framebuffer */ + lb_framebuffer(head); /* Remember where my valid memory ranges are */ return lb_table_fini(head, 1); diff --git a/src/arch/i386/include/arch/byteorder.h b/src/arch/i386/include/arch/byteorder.h index eecd02c..ab344e6 100644 --- a/src/arch/i386/include/arch/byteorder.h +++ b/src/arch/i386/include/arch/byteorder.h @@ -14,4 +14,7 @@ #define cpu_to_be16(x) swab16((x)) #define be16_to_cpu(x) swab16((x)) +#define ntohl(x) be32_to_cpu(x) +#define htonl(x) cpu_to_be32(x) + #endif /* _BYTEORDER_H */ diff --git a/src/devices/Kconfig b/src/devices/Kconfig index 42c47bc..8211bf3 100644 --- a/src/devices/Kconfig +++ b/src/devices/Kconfig @@ -1,7 +1,7 @@ ## ## This file is part of the coreboot project. ## -## Copyright (C) 2007 coresystems GmbH +## Copyright (C) 2007-2010 coresystems GmbH ## (Written by Stefan Reinauer for coresystems GmbH) ## ## This program is free software; you can redistribute it and/or modify @@ -49,7 +49,7 @@ choice depends on PCI_ROM_RUN || VGA_ROM_RUN config PCI_OPTION_ROM_RUN_REALMODE - prompt "Real mode" + prompt "Native mode" bool depends on ARCH_X86 help @@ -58,36 +58,59 @@ config PCI_OPTION_ROM_RUN_REALMODE so this is the fastest, but also the least secure option. (only works on x86/x64 systems) -config PCI_OPTION_ROM_RUN_X86EMU - prompt "x86emu" +config PCI_OPTION_ROM_RUN_YABEL + prompt "Secure Mode" bool help If you select this option, the x86emu CPU emulator will be used to - execute PCI option ROMs. - When choosing this option, x86emu will pass through all hardware - accesses to memory and IO devices to the underlying memory and IO - addresses. While this option prevents option ROMs from doing dirty - tricks with the CPU (such as installing SMM modules or hypervisors), - they can still access all devices in the system. - Choosing x86emu, option ROM execution is slower than native execution - in real mode, but faster than the full system emulation YABEL + execute PCI option ROMs. + This option prevents option ROMs from doing dirty tricks with the + system (such as installing SMM modules or hypervisors), but it is also + significantly slower than the native option ROM initialization method. This is the default choice for non-x86 systems. +endchoice -config PCI_OPTION_ROM_RUN_YABEL - prompt "YABEL" - bool +# TODO: Describe better, and/or make a "choice" selection for this. +config YABEL_DEBUG_FLAGS + prompt "Hex value for YABEL debug flags" + hex + default 0x0 + depends on PCI_OPTION_ROM_RUN_YABEL help - If you select this option, the YABEL system emulator will be used to - execute PCI option ROMs. - YABEL consists of two parts: It uses x86emu for the CPU emulation and - additionally provides a PC system emulation that filters bad device and - memory access (such as PCI config space access to other devices than the - initialized one). - This option best prevents option ROMs from doing dirty tricks with the - system (such as installing SMM modules or hypervisors), but it is also - significantly slower than the other option ROM initialization methods. + Set CONFIG_YABEL_DEBUG_FLAGS is a binary switch that allows you + to select the following items to debug. 1=on 0=off. After you + decide what you want to debug create the binary value, convert to hex + and set the Option (Ex. CONFIG_YABEL_DEBUG_FLAGS = 0x31FF //Debug All). + + |-DEBUG_JMP - print info about JMP and RETF opcodes from x86emu + ||-DEBUG_TRACE_X86EMU - print _all_ opcodes that are executed by x86emu (WARNING: this will produce a LOT of output) + |||-Currently unused + ||||-Currently unused + |||||-Currently unused + ||||||-DEBUG_PNP - Print Plug And Play access made by option rom + |||||||-DEBUG_DISK - Print Disk I/O related messages, currently unused + ||||||||-DEBUG_PMM - Print messages related to POST Memory Manager (PMM) + |||||||||-DEBUG_VBE - Print messages related to VESA BIOS Extension (VBE) functions + ||||||||||-DEBUG_PRINT_INT10 - let INT10 (i.e. character output) calls print messages to Debug output + |||||||||||-DEBUG_INTR - Print messages related to interrupt handling + ||||||||||||-DEBUG_CHECK_VMEM_ACCESS - Print messages related to accesse to certain areas of the virtual Memory (e.g. BDA (BIOS Data Area) or Interrupt Vectors) + |||||||||||||-DEBUG_MEM - Print memory access made by option rom (NOTE: this also includes accesses to fetch instructions) + ||||||||||||||-DEBUG_IO - Print I/O access made by option rom + 11000111111111 - Max Binary Value, Debug All (WARNING: - This could run for hours) + + DEBUG_IO 0x0001 + DEBUG_MEM 0x0002 + DEBUG_CHECK_VMEM_ACCESS 0x0004 + DEBUG_INTR 0x0008 + DEBUG_PRINT_INT10 0x0010 + DEBUG_VBE 0x0020 + DEBUG_PMM 0x0040 + DEBUG_DISK 0x0080 + DEBUG_PNP 0x0100 + DEBUG_TRACE_X86EMU 0x1000 + DEBUG_JMP 0x2000 -endchoice + See debug.h for values 0 is no debug output, 0x31ff is _verbose_. config YABEL_PCI_ACCESS_OTHER_DEVICES prompt "Allow option roms to acces other devices" @@ -102,20 +125,56 @@ config YABEL_PCI_ACCESS_OTHER_DEVICES config YABEL_VIRTMEM_LOCATION prompt "Location of YABEL's virtual memory" hex - depends on EXPERT + depends on PCI_OPTION_ROM_RUN_YABEL && EXPERT default 0x1000000 help YABEL requires 1MB memory for its CPU emulation. This memory is normally located at 16MB. -# TODO: Describe better, and/or make a "choice" selection for this. -config YABEL_DEBUG_FLAGS - prompt "Hex value for YABEL debug flags" - hex - default 0x0 +config YABEL_DIRECTHW + prompt "Direct Hardware Access" + bool depends on PCI_OPTION_ROM_RUN_YABEL help - See debug.h for values 0 is no debug output, 0x31ff is _verbose_. + YABEL consists of two parts: It uses x86emu for the CPU emulation and + additionally provides a PC system emulation that filters bad device and + memory access (such as PCI config space access to other devices than the + initialized one). + When choosing this option, x86emu will pass through all hardware + accesses to memory and IO devices to the underlying memory and IO + addresses. While this option prevents option ROMs from doing dirty + tricks with the CPU (such as installing SMM modules or hypervisors), + they can still access all devices in the system. + Enable this option for a good compromise between security and speed. + +config BOOTSPLASH + prompt "Show graphical bootsplash" + bool + depends on PCI_OPTION_ROM_RUN_YABEL + help + This option shows a graphical bootsplash screen. The grapics are + loaded from the CBFS file bootsplash.jpg + +config FRAMEBUFFER_VESA_MODE + prompt "VESA framebuffer video mode" + hex + default 0x117 + depends on BOOTSPLASH + help + This option sets the resolution used for the coreboot framebuffer and + bootsplash screen. Set to 0x117 for 1024x768x16. A diligent soul will + some day make this a "choice". + +config COREBOOT_KEEP_FRAMEBUFFER + prompt "Keep VESA framebuffer" + bool + depends on BOOTSPLASH + help + This option keeps the framebuffer mode set after coreboot finishes + execution. If this option is enabled, coreboot will pass a framebuffer + entry in its coreboot table and the payload will need a framebuffer + driver. If this option is disabled, coreboot will switch back to + text mode before handing control to a payload. config CONSOLE_VGA_MULTI bool diff --git a/src/include/boot/coreboot_tables.h b/src/include/boot/coreboot_tables.h index 2ba6126..476a374 100644 --- a/src/include/boot/coreboot_tables.h +++ b/src/include/boot/coreboot_tables.h @@ -159,6 +159,13 @@ struct lb_console { uint16_t type; }; +#define LB_TAG_CONSOLE_SERIAL8250 0 +#define LB_TAG_CONSOLE_VGA 1 +#define LB_TAG_CONSOLE_BTEXT 2 +#define LB_TAG_CONSOLE_LOGBUF 3 +#define LB_TAG_CONSOLE_SROM 4 +#define LB_TAG_CONSOLE_EHCI 5 + #define LB_TAG_FORWARD 0x0011 struct lb_forward { uint32_t tag; @@ -166,12 +173,25 @@ struct lb_forward { uint64_t forward; }; -#define LB_TAG_CONSOLE_SERIAL8250 0 -#define LB_TAG_CONSOLE_VGA 1 -#define LB_TAG_CONSOLE_BTEXT 2 -#define LB_TAG_CONSOLE_LOGBUF 3 -#define LB_TAG_CONSOLE_SROM 4 -#define LB_TAG_CONSOLE_EHCI 5 +#define LB_TAG_FRAMEBUFFER 0x0012 +struct lb_framebuffer { + uint32_t tag; + uint32_t size; + + uint64_t physical_address; + uint32_t x_resolution; + uint32_t y_resolution; + uint32_t bytes_per_line; + uint8_t bits_per_pixel; + uint8_t red_mask_pos; + uint8_t red_mask_size; + uint8_t green_mask_pos; + uint8_t green_mask_size; + uint8_t blue_mask_pos; + uint8_t blue_mask_size; + uint8_t reserved_mask_pos; + uint8_t reserved_mask_size; +}; /* The following structures are for the cmos definitions table */ #define LB_TAG_CMOS_OPTION_TABLE 200 diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index b94906b..cbff717 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -26,6 +26,8 @@ initobj-y += lzma.o obj-$(CONFIG_USBDEBUG_DIRECT) += usbdebug_direct.o obj-$(CONFIG_COMPRESSED_PAYLOAD_LZMA) += lzma.o +obj-$(CONFIG_BOOTSPLASH) += jpeg.o + ifdef POST_EVALUATION $(obj)/lib/version.o :: $(obj)/build.h endif diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index f99f666..0bb6e83 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -22,13 +22,7 @@ #include #include #include - -#ifndef CONFIG_BIG_ENDIAN -#define ntohl(x) ( ((x&0xff)<<24) | ((x&0xff00)<<8) | \ - ((x&0xff0000) >> 8) | ((x&0xff000000) >> 24) ) -#else -#define ntohl(x) (x) -#endif +#include int cbfs_decompress(int algo, void *src, void *dst, int len) { @@ -213,7 +207,7 @@ void * cbfs_load_stage(const char *name) void * cbfs_get_file(const char *name) { - return cbfs_find(name); + return (void *) cbfs_find(name); } int cbfs_execute_stage(const char *name) diff --git a/src/lib/fallback_boot.c b/src/lib/fallback_boot.c index 59476fd..b969b6b 100644 --- a/src/lib/fallback_boot.c +++ b/src/lib/fallback_boot.c @@ -30,6 +30,11 @@ void set_boot_successful(void) void boot_successful(void) { +#if defined(CONFIG_BOOTSPLASH) && CONFIG_BOOTSPLASH && !CONFIG_COREBOOT_KEEP_FRAMEBUFFER + void vbe_textmode_console(void); + + vbe_textmode_console(); +#endif /* Remember this was a successful boot */ set_boot_successful(); diff --git a/src/lib/jpeg.c b/src/lib/jpeg.c new file mode 100644 index 0000000..b7c0004 --- /dev/null +++ b/src/lib/jpeg.c @@ -0,0 +1,988 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2001 by Michael Schroeder + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +/* + * a tiny jpeg decoder. + * + * written in August 2001 by Michael Schroeder + * + */ + +#define __LITTLE_ENDIAN +#include +#include "jpeg.h" +#define ISHIFT 11 + +#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5)) +#define IMULT(a, b) (((a) * (b)) >> ISHIFT) +#define ITOINT(a) ((a) >> ISHIFT) + +#ifndef __P +# define __P(x) x +#endif + +/* special markers */ +#define M_BADHUFF -1 +#define M_EOF 0x80 + +struct in { + unsigned char *p; + unsigned int bits; + int left; + int marker; + + int (*func) __P((void *)); + void *data; +}; + +/*********************************/ +struct dec_hufftbl; +struct enc_hufftbl; + +union hufftblp { + struct dec_hufftbl *dhuff; + struct enc_hufftbl *ehuff; +}; + +struct scan { + int dc; /* old dc value */ + + union hufftblp hudc; + union hufftblp huac; + int next; /* when to switch to next scan */ + + int cid; /* component id */ + int hv; /* horiz/vert, copied from comp */ + int tq; /* quant tbl, copied from comp */ +}; + +/*********************************/ + +#define DECBITS 10 /* seems to be the optimum */ + +struct dec_hufftbl { + int maxcode[17]; + int valptr[16]; + unsigned char vals[256]; + unsigned int llvals[1 << DECBITS]; +}; + +static void decode_mcus __P((struct in *, int *, int, struct scan *, int *)); +static int dec_readmarker __P((struct in *)); +static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *)); + +static void setinput __P((struct in *, unsigned char *)); +/*********************************/ + +#undef PREC +#define PREC int + +static void idctqtab __P((unsigned char *, PREC *)); +static void idct __P((int *, int *, PREC *, PREC, int)); +static void scaleidctqtab __P((PREC *, PREC)); + +/*********************************/ + +static void initcol __P((PREC[][64])); + +static void col221111 __P((int *, unsigned char *, int)); +static void col221111_16 __P((int *, unsigned char *, int)); +static void col221111_32 __P((int *, unsigned char *, int)); + +/*********************************/ + +#define M_SOI 0xd8 +#define M_APP0 0xe0 +#define M_DQT 0xdb +#define M_SOF0 0xc0 +#define M_DHT 0xc4 +#define M_DRI 0xdd +#define M_SOS 0xda +#define M_RST0 0xd0 +#define M_EOI 0xd9 +#define M_COM 0xfe + +static unsigned char *datap; + +static int getbyte(void) +{ + return *datap++; +} + +static int getword(void) +{ + int c1, c2; + c1 = *datap++; + c2 = *datap++; + return c1 << 8 | c2; +} + +struct comp { + int cid; + int hv; + int tq; +}; + +#define MAXCOMP 4 +struct jpginfo { + int nc; /* number of components */ + int ns; /* number of scans */ + int dri; /* restart interval */ + int nm; /* mcus til next marker */ + int rm; /* next restart marker */ +}; + +static struct jpginfo info; +static struct comp comps[MAXCOMP]; + +static struct scan dscans[MAXCOMP]; + +static unsigned char quant[4][64]; + +static struct dec_hufftbl dhuff[4]; + +#define dec_huffdc (dhuff + 0) +#define dec_huffac (dhuff + 2) + +static struct in in; + +static int readtables(int till) +{ + int m, l, i, j, lq, pq, tq; + int tc, th, tt; + + for (;;) { + if (getbyte() != 0xff) + return -1; + if ((m = getbyte()) == till) + break; + + switch (m) { + case 0xc2: + return 0; + + case M_DQT: + lq = getword(); + while (lq > 2) { + pq = getbyte(); + tq = pq & 15; + if (tq > 3) + return -1; + pq >>= 4; + if (pq != 0) + return -1; + for (i = 0; i < 64; i++) + quant[tq][i] = getbyte(); + lq -= 64 + 1; + } + break; + + case M_DHT: + l = getword(); + while (l > 2) { + int hufflen[16], k; + unsigned char huffvals[256]; + + tc = getbyte(); + th = tc & 15; + tc >>= 4; + tt = tc * 2 + th; + if (tc > 1 || th > 1) + return -1; + for (i = 0; i < 16; i++) + hufflen[i] = getbyte(); + l -= 1 + 16; + k = 0; + for (i = 0; i < 16; i++) { + for (j = 0; j < hufflen[i]; j++) + huffvals[k++] = getbyte(); + l -= hufflen[i]; + } + dec_makehuff(dhuff + tt, hufflen, + huffvals); + } + break; + + case M_DRI: + l = getword(); + info.dri = getword(); + break; + + default: + l = getword(); + while (l-- > 2) + getbyte(); + break; + } + } + return 0; +} + +static void dec_initscans(void) +{ + int i; + + info.nm = info.dri + 1; + info.rm = M_RST0; + for (i = 0; i < info.ns; i++) + dscans[i].dc = 0; +} + +static int dec_checkmarker(void) +{ + int i; + + if (dec_readmarker(&in) != info.rm) + return -1; + info.nm = info.dri; + info.rm = (info.rm + 1) & ~0x08; + for (i = 0; i < info.ns; i++) + dscans[i].dc = 0; + return 0; +} + +int jpeg_check_size(unsigned char *buf, int width, int height) +{ + datap = buf; + getbyte(); + getbyte(); + readtables(M_SOF0); + getword(); + getbyte(); + if (height != getword() || width != getword()) + return 0; + return 1; +} + +int jpeg_decode(unsigned char *buf, unsigned char *pic, + int width, int height, int depth, struct jpeg_decdata *decdata) +{ + int i, j, m, tac, tdc; + int mcusx, mcusy, mx, my; + int max[6]; + + if (!decdata || !buf || !pic) + return -1; + datap = buf; + if (getbyte() != 0xff) + return ERR_NO_SOI; + if (getbyte() != M_SOI) + return ERR_NO_SOI; + if (readtables(M_SOF0)) + return ERR_BAD_TABLES; + getword(); + i = getbyte(); + if (i != 8) + return ERR_NOT_8BIT; + if (((getword() + 15) & ~15) != height) + return ERR_HEIGHT_MISMATCH; + if (((getword() + 15) & ~15) != width) + return ERR_WIDTH_MISMATCH; + if ((height & 15) || (width & 15)) + return ERR_BAD_WIDTH_OR_HEIGHT; + info.nc = getbyte(); + if (info.nc > MAXCOMP) + return ERR_TOO_MANY_COMPPS; + for (i = 0; i < info.nc; i++) { + int h, v; + comps[i].cid = getbyte(); + comps[i].hv = getbyte(); + v = comps[i].hv & 15; + h = comps[i].hv >> 4; + comps[i].tq = getbyte(); + if (h > 3 || v > 3) + return ERR_ILLEGAL_HV; + if (comps[i].tq > 3) + return ERR_QUANT_TABLE_SELECTOR; + } + if (readtables(M_SOS)) + return ERR_BAD_TABLES; + getword(); + info.ns = getbyte(); + if (info.ns != 3) + return ERR_NOT_YCBCR_221111; + for (i = 0; i < 3; i++) { + dscans[i].cid = getbyte(); + tdc = getbyte(); + tac = tdc & 15; + tdc >>= 4; + if (tdc > 1 || tac > 1) + return ERR_QUANT_TABLE_SELECTOR; + for (j = 0; j < info.nc; j++) + if (comps[j].cid == dscans[i].cid) + break; + if (j == info.nc) + return ERR_UNKNOWN_CID_IN_SCAN; + dscans[i].hv = comps[j].hv; + dscans[i].tq = comps[j].tq; + dscans[i].hudc.dhuff = dec_huffdc + tdc; + dscans[i].huac.dhuff = dec_huffac + tac; + } + + i = getbyte(); + j = getbyte(); + m = getbyte(); + + if (i != 0 || j != 63 || m != 0) + return ERR_NOT_SEQUENTIAL_DCT; + + if (dscans[0].cid != 1 || dscans[1].cid != 2 || dscans[2].cid != 3) + return ERR_NOT_YCBCR_221111; + + if (dscans[0].hv != 0x22 || dscans[1].hv != 0x11 || dscans[2].hv != 0x11) + return ERR_NOT_YCBCR_221111; + + mcusx = width >> 4; + mcusy = height >> 4; + + + idctqtab(quant[dscans[0].tq], decdata->dquant[0]); + idctqtab(quant[dscans[1].tq], decdata->dquant[1]); + idctqtab(quant[dscans[2].tq], decdata->dquant[2]); + initcol(decdata->dquant); + setinput(&in, datap); + +#if 0 + /* landing zone */ + img[len] = 0; + img[len + 1] = 0xff; + img[len + 2] = M_EOF; +#endif + + dec_initscans(); + + dscans[0].next = 6 - 4; + dscans[1].next = 6 - 4 - 1; + dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */ + for (my = 0; my < mcusy; my++) { + for (mx = 0; mx < mcusx; mx++) { + if (info.dri && !--info.nm) + if (dec_checkmarker()) + return ERR_WRONG_MARKER; + + decode_mcus(&in, decdata->dcts, 6, dscans, max); + idct(decdata->dcts, decdata->out, decdata->dquant[0], IFIX(128.5), max[0]); + idct(decdata->dcts + 64, decdata->out + 64, decdata->dquant[0], IFIX(128.5), max[1]); + idct(decdata->dcts + 128, decdata->out + 128, decdata->dquant[0], IFIX(128.5), max[2]); + idct(decdata->dcts + 192, decdata->out + 192, decdata->dquant[0], IFIX(128.5), max[3]); + idct(decdata->dcts + 256, decdata->out + 256, decdata->dquant[1], IFIX(0.5), max[4]); + idct(decdata->dcts + 320, decdata->out + 320, decdata->dquant[2], IFIX(0.5), max[5]); + + switch (depth) { + case 32: + col221111_32(decdata->out, pic + (my * 16 * mcusx + mx) * 16 * 4, mcusx * 16 * 4); + break; + case 24: + col221111(decdata->out, pic + (my * 16 * mcusx + mx) * 16 * 3, mcusx * 16 * 3); + break; + case 16: + col221111_16(decdata->out, pic + (my * 16 * mcusx + mx) * (16 * 2), mcusx * (16 * 2)); + break; + default: + return ERR_DEPTH_MISMATCH; + break; + } + } + } + + m = dec_readmarker(&in); + if (m != M_EOI) + return ERR_NO_EOI; + + return 0; +} + +/****************************************************************/ +/************** huffman decoder ***************/ +/****************************************************************/ + +static int fillbits __P((struct in *, int, unsigned int)); +static int dec_rec2 +__P((struct in *, struct dec_hufftbl *, int *, int, int)); + +static void setinput(struct in *in, unsigned char *p) +{ + in->p = p; + in->left = 0; + in->bits = 0; + in->marker = 0; +} + +static int fillbits(struct in *in, int le, unsigned int bi) +{ + int b, m; + + if (in->marker) { + if (le <= 16) + in->bits = bi << 16, le += 16; + return le; + } + while (le <= 24) { + b = *in->p++; + if (b == 0xff && (m = *in->p++) != 0) { + if (m == M_EOF) { + if (in->func && (m = in->func(in->data)) == 0) + continue; + } + in->marker = m; + if (le <= 16) + bi = bi << 16, le += 16; + break; + } + bi = bi << 8 | b; + le += 8; + } + in->bits = bi; /* tmp... 2 return values needed */ + return le; +} + +static int dec_readmarker(struct in *in) +{ + int m; + + in->left = fillbits(in, in->left, in->bits); + if ((m = in->marker) == 0) + return 0; + in->left = 0; + in->marker = 0; + return m; +} + +#define LEBI_DCL int le, bi +#define LEBI_GET(in) (le = in->left, bi = in->bits) +#define LEBI_PUT(in) (in->left = le, in->bits = bi) + +#define GETBITS(in, n) ( \ + (le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \ + (le -= (n)), \ + bi >> le & ((1 << (n)) - 1) \ +) + +#define UNGETBITS(in, n) ( \ + le += (n) \ +) + + +static int dec_rec2(struct in *in, struct dec_hufftbl *hu, int *runp, int c, + int i) +{ + LEBI_DCL; + + LEBI_GET(in); + if (i) { + UNGETBITS(in, i & 127); + *runp = i >> 8 & 15; + i >>= 16; + } else { + for (i = DECBITS; (c = ((c << 1) | GETBITS(in, 1))) >= (hu->maxcode[i]); i++); + if (i >= 16) { + in->marker = M_BADHUFF; + return 0; + } + i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2]; + *runp = i >> 4; + i &= 15; + } + if (i == 0) { /* sigh, 0xf0 is 11 bit */ + LEBI_PUT(in); + return 0; + } + /* receive part */ + c = GETBITS(in, i); + if (c < (1 << (i - 1))) + c += (-1 << i) + 1; + LEBI_PUT(in); + return c; +} + +#define DEC_REC(in, hu, r, i) ( \ + r = GETBITS(in, DECBITS), \ + i = hu->llvals[r], \ + i & 128 ? \ + ( \ + UNGETBITS(in, i & 127), \ + r = i >> 8 & 15, \ + i >> 16 \ + ) \ + : \ + ( \ + LEBI_PUT(in), \ + i = dec_rec2(in, hu, &r, r, i), \ + LEBI_GET(in), \ + i \ + ) \ +) + +static void decode_mcus(struct in *in, int *dct, int n, struct scan *sc, int *maxp) +{ + struct dec_hufftbl *hu; + int i, r, t; + LEBI_DCL; + + memset(dct, 0, n * 64 * sizeof(*dct)); + LEBI_GET(in); + while (n-- > 0) { + hu = sc->hudc.dhuff; + *dct++ = (sc->dc += DEC_REC(in, hu, r, t)); + + hu = sc->huac.dhuff; + i = 63; + while (i > 0) { + t = DEC_REC(in, hu, r, t); + if (t == 0 && r == 0) { + dct += i; + break; + } + dct += r; + *dct++ = t; + i -= r + 1; + } + *maxp++ = 64 - i; + if (n == sc->next) + sc++; + } + LEBI_PUT(in); +} + +static void dec_makehuff(struct dec_hufftbl *hu, int *hufflen, unsigned char *huffvals) +{ + int code, k, i, j, d, x, c, v; + for (i = 0; i < (1 << DECBITS); i++) + hu->llvals[i] = 0; + +/* + * llvals layout: + * + * value v already known, run r, backup u bits: + * vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu + * value unknown, size b bits, run r, backup u bits: + * 000000000000bbbb 0000 rrrr 0 uuuuuuu + * value and size unknown: + * 0000000000000000 0000 0000 0 0000000 + */ + code = 0; + k = 0; + for (i = 0; i < 16; i++, code <<= 1) { /* sizes */ + hu->valptr[i] = k; + for (j = 0; j < hufflen[i]; j++) { + hu->vals[k] = *huffvals++; + if (i < DECBITS) { + c = code << (DECBITS - 1 - i); + v = hu->vals[k] & 0x0f; /* size */ + for (d = 1 << (DECBITS - 1 - i); --d >= 0;) { + if (v + i < DECBITS) { /* both fit in table */ + x = d >> (DECBITS - 1 - v - + i); + if (v && x < (1 << (v - 1))) + x += (-1 << v) + 1; + x = x << 16 | (hu-> vals[k] & 0xf0) << 4 | + (DECBITS - (i + 1 + v)) | 128; + } else + x = v << 16 | (hu-> vals[k] & 0xf0) << 4 | + (DECBITS - (i + 1)); + hu->llvals[c | d] = x; + } + } + code++; + k++; + } + hu->maxcode[i] = code; + } + hu->maxcode[16] = 0x20000; /* always terminate decode */ +} + +/****************************************************************/ +/************** idct ***************/ +/****************************************************************/ + +#define ONE ((PREC)IFIX(1.)) +#define S2 ((PREC)IFIX(0.382683432)) +#define C2 ((PREC)IFIX(0.923879532)) +#define C4 ((PREC)IFIX(0.707106781)) + +#define S22 ((PREC)IFIX(2 * 0.382683432)) +#define C22 ((PREC)IFIX(2 * 0.923879532)) +#define IC4 ((PREC)IFIX(1 / 0.707106781)) + +#define C3IC1 ((PREC)IFIX(0.847759065)) /* c3/c1 */ +#define C5IC1 ((PREC)IFIX(0.566454497)) /* c5/c1 */ +#define C7IC1 ((PREC)IFIX(0.198912367)) /* c7/c1 */ + +#define XPP(a,b) (t = a + b, b = a - b, a = t) +#define XMP(a,b) (t = a - b, b = a + b, a = t) +#define XPM(a,b) (t = a + b, b = b - a, a = t) + +#define ROT(a,b,s,c) ( t = IMULT(a + b, s), \ + a = IMULT(a, c - s) + t, \ + b = IMULT(b, c + s) - t) + +#define IDCT \ +( \ + XPP(t0, t1), \ + XMP(t2, t3), \ + t2 = IMULT(t2, IC4) - t3, \ + XPP(t0, t3), \ + XPP(t1, t2), \ + XMP(t4, t7), \ + XPP(t5, t6), \ + XMP(t5, t7), \ + t5 = IMULT(t5, IC4), \ + ROT(t4, t6, S22, C22),\ + t6 -= t7, \ + t5 -= t6, \ + t4 -= t5, \ + XPP(t0, t7), \ + XPP(t1, t6), \ + XPP(t2, t5), \ + XPP(t3, t4) \ +) + +static unsigned char zig2[64] = { + 0, 2, 3, 9, 10, 20, 21, 35, + 14, 16, 25, 31, 39, 46, 50, 57, + 5, 7, 12, 18, 23, 33, 37, 48, + 27, 29, 41, 44, 52, 55, 59, 62, + 15, 26, 30, 40, 45, 51, 56, 58, + 1, 4, 8, 11, 19, 22, 34, 36, + 28, 42, 43, 53, 54, 60, 61, 63, + 6, 13, 17, 24, 32, 38, 47, 49 +}; + +void idct(int *in, int *out, PREC *quant, PREC off, int max) +{ + PREC t0, t1, t2, t3, t4, t5, t6, t7, t; + PREC tmp[64], *tmpp; + int i, j; + unsigned char *zig2p; + + t0 = off; + if (max == 1) { + t0 += in[0] * quant[0]; + for (i = 0; i < 64; i++) + out[i] = ITOINT(t0); + return; + } + zig2p = zig2; + tmpp = tmp; + for (i = 0; i < 8; i++) { + j = *zig2p++; + t0 += in[j] * quant[j]; + j = *zig2p++; + t5 = in[j] * quant[j]; + j = *zig2p++; + t2 = in[j] * quant[j]; + j = *zig2p++; + t7 = in[j] * quant[j]; + j = *zig2p++; + t1 = in[j] * quant[j]; + j = *zig2p++; + t4 = in[j] * quant[j]; + j = *zig2p++; + t3 = in[j] * quant[j]; + j = *zig2p++; + t6 = in[j] * quant[j]; + IDCT; + tmpp[0 * 8] = t0; + tmpp[1 * 8] = t1; + tmpp[2 * 8] = t2; + tmpp[3 * 8] = t3; + tmpp[4 * 8] = t4; + tmpp[5 * 8] = t5; + tmpp[6 * 8] = t6; + tmpp[7 * 8] = t7; + tmpp++; + t0 = 0; + } + for (i = 0; i < 8; i++) { + t0 = tmp[8 * i + 0]; + t1 = tmp[8 * i + 1]; + t2 = tmp[8 * i + 2]; + t3 = tmp[8 * i + 3]; + t4 = tmp[8 * i + 4]; + t5 = tmp[8 * i + 5]; + t6 = tmp[8 * i + 6]; + t7 = tmp[8 * i + 7]; + IDCT; + out[8 * i + 0] = ITOINT(t0); + out[8 * i + 1] = ITOINT(t1); + out[8 * i + 2] = ITOINT(t2); + out[8 * i + 3] = ITOINT(t3); + out[8 * i + 4] = ITOINT(t4); + out[8 * i + 5] = ITOINT(t5); + out[8 * i + 6] = ITOINT(t6); + out[8 * i + 7] = ITOINT(t7); + } +} + +static unsigned char zig[64] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63 +}; + +static PREC aaidct[8] = { + IFIX(0.3535533906), IFIX(0.4903926402), + IFIX(0.4619397663), IFIX(0.4157348062), + IFIX(0.3535533906), IFIX(0.2777851165), + IFIX(0.1913417162), IFIX(0.0975451610) +}; + + +static void idctqtab(unsigned char *qin, PREC *qout) +{ + int i, j; + + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] * + IMULT(aaidct[i], aaidct[j]); +} + +static void scaleidctqtab(PREC *q, PREC sc) +{ + int i; + + for (i = 0; i < 64; i++) + q[i] = IMULT(q[i], sc); +} + +/****************************************************************/ +/************** color decoder ***************/ +/****************************************************************/ + +#define ROUND + +/* + * YCbCr Color transformation: + * + * y:0..255 Cb:-128..127 Cr:-128..127 + * + * R = Y + 1.40200 * Cr + * G = Y - 0.34414 * Cb - 0.71414 * Cr + * B = Y + 1.77200 * Cb + * + * => + * Cr *= 1.40200; + * Cb *= 1.77200; + * Cg = 0.19421 * Cb + .50937 * Cr; + * R = Y + Cr; + * G = Y - Cg; + * B = Y + Cb; + * + * => + * Cg = (50 * Cb + 130 * Cr + 128) >> 8; + */ + +static void initcol(PREC q[][64]) +{ + scaleidctqtab(q[1], IFIX(1.77200)); + scaleidctqtab(q[2], IFIX(1.40200)); +} + +/* This is optimized for the stupid sun SUNWspro compiler. */ +#define STORECLAMP(a,x) \ +( \ + (a) = (x), \ + (unsigned int)(x) >= 256 ? \ + ((a) = (x) < 0 ? 0 : 255) \ + : \ + 0 \ +) + +#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x)) + +#ifdef ROUND + +#define CBCRCG(yin, xin) \ +( \ + cb = outc[0 +yin*8+xin], \ + cr = outc[64+yin*8+xin], \ + cg = (50 * cb + 130 * cr + 128) >> 8 \ +) + +#else + +#define CBCRCG(yin, xin) \ +( \ + cb = outc[0 +yin*8+xin], \ + cr = outc[64+yin*8+xin], \ + cg = (3 * cb + 8 * cr) >> 4 \ +) + +#endif + +#define PIC(yin, xin, p, xout) \ +( \ + y = outy[(yin) * 8 + xin], \ + STORECLAMP(p[(xout) * 3 + 0], y + cr), \ + STORECLAMP(p[(xout) * 3 + 1], y - cg), \ + STORECLAMP(p[(xout) * 3 + 2], y + cb) \ +) + +#ifdef __LITTLE_ENDIAN +#define PIC_16(yin, xin, p, xout, add) \ +( \ + y = outy[(yin) * 8 + xin], \ + y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \ + ((CLAMP(y - cg + add ) & 0xfc) << 3) | \ + ((CLAMP(y + cb + add*2+1) ) >> 3), \ + p[(xout) * 2 + 0] = y & 0xff, \ + p[(xout) * 2 + 1] = y >> 8 \ +) +#else +#ifdef CONFIG_PPC +#define PIC_16(yin, xin, p, xout, add) \ +( \ + y = outy[(yin) * 8 + xin], \ + y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 7) | \ + ((CLAMP(y - cg + add*2+1) & 0xf8) << 2) | \ + ((CLAMP(y + cb + add*2+1) ) >> 3), \ + p[(xout) * 2 + 0] = y >> 8, \ + p[(xout) * 2 + 1] = y & 0xff \ +) +#else +#define PIC_16(yin, xin, p, xout, add) \ +( \ + y = outy[(yin) * 8 + xin], \ + y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \ + ((CLAMP(y - cg + add ) & 0xfc) << 3) | \ + ((CLAMP(y + cb + add*2+1) ) >> 3), \ + p[(xout) * 2 + 0] = y >> 8, \ + p[(xout) * 2 + 1] = y & 0xff \ +) +#endif +#endif + +#define PIC_32(yin, xin, p, xout) \ +( \ + y = outy[(yin) * 8 + xin], \ + STORECLAMP(p[(xout) * 4 + 0], y + cr), \ + STORECLAMP(p[(xout) * 4 + 1], y - cg), \ + STORECLAMP(p[(xout) * 4 + 2], y + cb), \ + p[(xout) * 4 + 3] = 0 \ +) + +#define PIC221111(xin) \ +( \ + CBCRCG(0, xin), \ + PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \ + PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \ + PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \ + PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \ +) + +#define PIC221111_16(xin) \ +( \ + CBCRCG(0, xin), \ + PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0, 3), \ + PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1, 0), \ + PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0, 1), \ + PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1, 2) \ +) + +#define PIC221111_32(xin) \ +( \ + CBCRCG(0, xin), \ + PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0),\ + PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1),\ + PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0),\ + PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \ +) + +static void col221111(int *out, unsigned char *pic, int width) +{ + int i, j, k; + unsigned char *pic0, *pic1; + int *outy, *outc; + int cr, cg, cb, y; + + pic0 = pic; + pic1 = pic + width; + outy = out; + outc = out + 64 * 4; + for (i = 2; i > 0; i--) { + for (j = 4; j > 0; j--) { + for (k = 0; k < 8; k++) { + PIC221111(k); + } + outc += 8; + outy += 16; + pic0 += 2 * width; + pic1 += 2 * width; + } + outy += 64 * 2 - 16 * 4; + } +} + +static void col221111_16(int *out, unsigned char *pic, int width) +{ + int i, j, k; + unsigned char *pic0, *pic1; + int *outy, *outc; + int cr, cg, cb, y; + + pic0 = pic; + pic1 = pic + width; + outy = out; + outc = out + 64 * 4; + for (i = 2; i > 0; i--) { + for (j = 4; j > 0; j--) { + for (k = 0; k < 8; k++) { + PIC221111_16(k); + } + outc += 8; + outy += 16; + pic0 += 2 * width; + pic1 += 2 * width; + } + outy += 64 * 2 - 16 * 4; + } +} + +static void col221111_32(int *out, unsigned char *pic, int width) +{ + int i, j, k; + unsigned char *pic0, *pic1; + int *outy, *outc; + int cr, cg, cb, y; + + pic0 = pic; + pic1 = pic + width; + outy = out; + outc = out + 64 * 4; + for (i = 2; i > 0; i--) { + for (j = 4; j > 0; j--) { + for (k = 0; k < 8; k++) { + PIC221111_32(k); + } + outc += 8; + outy += 16; + pic0 += 2 * width; + pic1 += 2 * width; + } + outy += 64 * 2 - 16 * 4; + } +} diff --git a/src/lib/jpeg.h b/src/lib/jpeg.h new file mode 100644 index 0000000..12e8e9f --- /dev/null +++ b/src/lib/jpeg.h @@ -0,0 +1,56 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2001 by Michael Schroeder + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of + * the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +/* + * a tiny jpeg decoder. + * + * written in August 2001 by Michael Schroeder + */ + +#ifndef __JPEG_H +#define __JPEG_H + +#define ERR_NO_SOI 1 +#define ERR_NOT_8BIT 2 +#define ERR_HEIGHT_MISMATCH 3 +#define ERR_WIDTH_MISMATCH 4 +#define ERR_BAD_WIDTH_OR_HEIGHT 5 +#define ERR_TOO_MANY_COMPPS 6 +#define ERR_ILLEGAL_HV 7 +#define ERR_QUANT_TABLE_SELECTOR 8 +#define ERR_NOT_YCBCR_221111 9 +#define ERR_UNKNOWN_CID_IN_SCAN 10 +#define ERR_NOT_SEQUENTIAL_DCT 11 +#define ERR_WRONG_MARKER 12 +#define ERR_NO_EOI 13 +#define ERR_BAD_TABLES 14 +#define ERR_DEPTH_MISMATCH 15 + +struct jpeg_decdata { + int dcts[6 * 64 + 16]; + int out[64 * 6]; + int dquant[3][64]; +}; + +int jpeg_decode(unsigned char *, unsigned char *, int, int, int, struct jpeg_decdata *); +int jpeg_check_size(unsigned char *, int, int); + +#endif diff --git a/util/x86emu/Makefile b/util/x86emu/Makefile index a7b21d1..e69de29 100644 --- a/util/x86emu/Makefile +++ b/util/x86emu/Makefile @@ -1,72 +0,0 @@ -## -## This file is part of the coreboot project. -## -## Copyright (C) 2007 coresystems GmbH -## -## This program is free software; you can redistribute it and/or modify -## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with this program; if not, write to the Free Software -## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -## - -#X86EMU_INCLUDE = -I $(src)/util/x86emu/include - -X86EMU_SRC = debug.c decode.c fpu.c ops.c ops2.c prim_ops.c sys.c -ifeq ($(CONFIG_PCI_OPTION_ROM_RUN_X86EMU),y) -BIOSEMU_SRC = biosemu.c -endif - -ifeq ($(CONFIG_PCI_OPTION_ROM_RUN_YABEL),y) -BIOSEMU_SRC = biosemu.c debug.c device.c mem.c io.c interrupt.c -#TODO: add vbe.c, currently not needed... -#BIOSEMU_SRC +=vbe.c -BIOSEMU_SRC +=pmm.c -#PH: TODO: remove the compat files?? -BIOSEMU_SRC += compat/functions.c -X86EMU_INCLUDE += -I $(src)/util/x86emu/yabel -X86EMU_INCLUDE += -I $(src)/util/x86emu -#TODO: remove these, these are .h files from slof, to make the merge easier... -X86EMU_INCLUDE += -I $(src)/util/x86emu/yabel/compat -endif -REALMODE_SRC = x86.c x86_asm.S - -ifeq ($(CONFIG_PCI_OPTION_ROM_RUN_X86EMU),y) -LIBX86EMU_SRC=$(patsubst %,x86emu/%,$(X86EMU_SRC)) $(BIOSEMU_SRC) -endif - -ifeq ($(CONFIG_PCI_OPTION_ROM_RUN_YABEL),y) -LIBX86EMU_SRC=$(patsubst %,x86emu/%,$(X86EMU_SRC)) $(patsubst %,yabel/%,$(BIOSEMU_SRC)) -endif - -ifeq ($(CONFIG_PCI_OPTION_ROM_RUN_REALMODE),y) -LIBX86EMU_SRC=$(REALMODE_SRC) -endif - -LIBX86EMU_OBJS = $(patsubst %.c,$(obj)/util/x86emu/%.o,$(LIBX86EMU_SRC)) -# needed for kscope -PCIROM_SRC += $(patsubst %,$(src)/util/x86emu/%,$(LIBX86EMU_SRC)) - - -$(obj)/util/x86emu/libx86emu.a: $(LIBX86EMU_OBJS) $(src)/.config - @printf " AR $(subst $(shell pwd)/,,$(@))\n" - $(Q)rm -f $@ # otherwise we always add to the archive - $(Q)$(AR) qcs $@ $(LIBX86EMU_OBJS) - -# -# This rule is also valid for all subdirectories -# - -$(obj)/util/x86emu/%.o: $(src)/util/x86emu/%.c - @printf " CC $(subst $(shell pwd)/,,$(@))\n" - $(Q)mkdir -p $(dir $@) - $(Q)$(CC) -Werror $(INITCFLAGS) $(X86EMU_INCLUDE) -I$(src)/util/x86emu/include -c $< -o $@ - diff --git a/util/x86emu/Makefile.inc b/util/x86emu/Makefile.inc index d71d3c7..3d5f1a6 100644 --- a/util/x86emu/Makefile.inc +++ b/util/x86emu/Makefile.inc @@ -1,12 +1,11 @@ ## ## This file is part of the coreboot project. ## -## Copyright (C) 2007 coresystems GmbH +## Copyright (C) 2007-2010 coresystems GmbH ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 2 of the License, or -## (at your option) any later version. +## the Free Software Foundation; version 2 of the License. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,9 +17,6 @@ ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ## -subdirs-$(CONFIG_PCI_OPTION_ROM_RUN_X86EMU) += x86emu -obj-$(CONFIG_PCI_OPTION_ROM_RUN_X86EMU) += biosemu.o - obj-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86.o obj-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86_asm.o obj-$(CONFIG_PCI_OPTION_ROM_RUN_REALMODE) += x86_interrupts.o diff --git a/util/x86emu/biosemu.c b/util/x86emu/biosemu.c index 7c5e3d7..e69de29 100644 --- a/util/x86emu/biosemu.c +++ b/util/x86emu/biosemu.c @@ -1,580 +0,0 @@ -/* - * This software and ancillary information (herein called SOFTWARE ) - * called LinuxBIOS is made available under the terms described - * here. The SOFTWARE has been approved for release with associated - * LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has - * been authored by an employee or employees of the University of - * California, operator of the Los Alamos National Laboratory under - * Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The - * U.S. Government has rights to use, reproduce, and distribute this - * SOFTWARE. The public may copy, distribute, prepare derivative works - * and publicly display this SOFTWARE without charge, provided that this - * Notice and any statement of authorship are reproduced on all copies. - * Neither the Government nor the University makes any warranty, express - * or implied, or assumes any liability or responsibility for the use of - * this SOFTWARE. If SOFTWARE is modified to produce derivative works, - * such modified SOFTWARE should be clearly marked, so as not to confuse - * it with the version available from LANL. - */ - /* - * This file is part of the coreboot project. - * - * (c) Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL - * Copyright (C) 2009 coresystems GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "x86emu/prim_ops.h" - -#define DATA_SEGMENT 0x2000 -#define STACK_SEGMENT 0x1000 //1000:xxxx -#define STACK_START_OFFSET 0xfffe -#define INITIAL_EBDA_SEGMENT 0xF600 // segment of the Extended BIOS Data Area -#define INITIAL_EBDA_SIZE 0x400 // size of the EBDA (at least 1KB!! since size is stored in KB!) - -enum { - PCI_BIOS_PRESENT = 0xB101, - FIND_PCI_DEVICE = 0xB102, - FIND_PCI_CLASS_CODE = 0xB103, - GENERATE_SPECIAL_CYCLE = 0xB106, - READ_CONFIG_BYTE = 0xB108, - READ_CONFIG_WORD = 0xB109, - READ_CONFIG_DWORD = 0xB10A, - WRITE_CONFIG_BYTE = 0xB10B, - WRITE_CONFIG_WORD = 0xB10C, - WRITE_CONFIG_DWORD = 0xB10D, - GET_IRQ_ROUTING_OPTIONS = 0xB10E, - SET_PCI_IRQ = 0xB10F -}; - -enum { - SUCCESSFUL = 0x00, - FUNC_NOT_SUPPORTED = 0x81, - BAD_VENDOR_ID = 0x83, - DEVICE_NOT_FOUND = 0x86, - BAD_REGISTER_NUMBER = 0x87, - SET_FAILED = 0x88, - BUFFER_TOO_SMALL = 0x89 -}; - -#define MEM_WB(where, what) wrb(where, what) -#define MEM_WW(where, what) wrw(where, what) -#define MEM_WL(where, what) wrl(where, what) - -#define MEM_RB(where) rdb(where) -#define MEM_RW(where) rdw(where) -#define MEM_RL(where) rdl(where) - -static u8 biosemu_inb(u16 port) -{ - u8 val; - - val = inb(port); -#ifdef DEBUG - if (port != 0x40) - printk("inb(0x%04x) = 0x%02x\n", port, val); -#endif - - return val; -} - -static u16 biosemu_inw(u16 port) -{ - u16 val; - - val = inw(port); - -#ifdef DEBUG - printk("inw(0x%04x) = 0x%04x\n", port, val); -#endif - return val; -} - -static u32 biosemu_inl(u16 port) -{ - u32 val; - - val = inl(port); - -#ifdef DEBUG - printk("inl(0x%04x) = 0x%08x\n", port, val); -#endif - return val; -} - -static void biosemu_outb(u16 port, u8 val) -{ -#ifdef DEBUG - if (port != 0x43) - printk("outb(0x%02x, 0x%04x)\n", val, port); -#endif - outb(val, port); -} - -static void biosemu_outw(u16 port, u16 val) -{ -#ifdef DEBUG - printk("outw(0x%04x, 0x%04x)\n", val, port); -#endif - outw(val, port); -} - -static void biosemu_outl(u16 port, u32 val) -{ -#ifdef DEBUG - printk("outl(0x%08x, 0x%04x)\n", val, port); -#endif - outl(val, port); -} - -static X86EMU_pioFuncs biosemu_piofuncs = { - biosemu_inb, biosemu_inw, biosemu_inl, - biosemu_outb, biosemu_outw, biosemu_outl -}; - -/* Interrupt Handlers */ - -static int int15_handler(void) -{ - /* This int15 handler is VIA Tech. and Intel specific. Other chipsets need other - * handlers. The right way to do this is to move this handler code into - * the mainboard or northbridge code. - */ - switch (X86_AX) { - case 0x5f19: - X86_EFLAGS |= FB_CF; /* set carry flag */ - break; - case 0x5f18: - X86_EAX = 0x5f; - // MCLK = 133, 32M frame buffer, 256 M main memory - X86_EBX = 0x545; - X86_ECX = 0x060; - X86_EFLAGS &= ~FB_CF; - break; - case 0x5f00: - X86_EAX = 0x8600; - X86_EFLAGS |= FB_CF; /* set carry flag */ - break; - case 0x5f01: - X86_EAX = 0x5f; - X86_ECX = (X86_ECX & 0xffffff00 ) | 2; // panel type = 2 = 1024 * 768 - X86_EFLAGS &= ~FB_CF; - break; - case 0x5f02: - X86_EAX = 0x5f; - X86_EBX = (X86_EBX & 0xffff0000) | 2; - X86_ECX = (X86_ECX & 0xffff0000) | 0x401; // PAL + crt only - X86_EDX = (X86_EDX & 0xffff0000) | 0; // TV Layout - default - X86_EFLAGS &= ~FB_CF; - break; - case 0x5f0f: - X86_EAX = 0x860f; - X86_EFLAGS |= FB_CF; /* set carry flag */ - break; - /* And now Intel IGD code */ -#define BOOT_DISPLAY_DEFAULT 0 -#define BOOT_DISPLAY_CRT (1 << 0) -#define BOOT_DISPLAY_TV (1 << 1) -#define BOOT_DISPLAY_EFP (1 << 2) -#define BOOT_DISPLAY_LCD (1 << 3) -#define BOOT_DISPLAY_CRT2 (1 << 4) -#define BOOT_DISPLAY_TV2 (1 << 5) -#define BOOT_DISPLAY_EFP2 (1 << 6) -#define BOOT_DISPLAY_LCD2 (1 << 7) - - case 0x5f35: - X86_EAX = 0x5f; - X86_ECX = BOOT_DISPLAY_DEFAULT; - X86_EFLAGS &= ~FB_CF; - break; - case 0x5f40: - X86_EAX = 0x5f; - X86_ECX = 3; // This is mainboard specific - printk("DISPLAY=%x\n", X86_ECX); - X86_EFLAGS &= ~FB_CF; - break; - default: - printk("Unknown INT15 function %04x!\n", X86_AX); - X86_EFLAGS |= FB_CF; /* set carry flag */ - } - - return 1; -} - -static int int1a_handler(void) -{ - int ret = 0; - struct device *dev = 0; - - switch (X86_AX) { - case PCI_BIOS_PRESENT: - X86_AH = 0x00; /* no config space/special cycle support */ - X86_AL = 0x01; /* config mechanism 1 */ - X86_EDX = 'P' | 'C' << 8 | 'I' << 16 | ' ' << 24; - X86_EBX = 0x0210; /* Version 2.10 */ - X86_ECX = 0xFF00; /* FIXME: Max bus number */ - X86_EFLAGS &= ~FB_CF; /* clear carry flag */ - ret = 1; - break; - case FIND_PCI_DEVICE: - /* FIXME: support SI != 0 */ - dev = dev_find_device(X86_DX, X86_CX, dev); - if (dev != 0) { - X86_BH = dev->bus->secondary; - X86_BL = dev->path.pci.devfn; - X86_AH = SUCCESSFUL; - X86_EFLAGS &= ~FB_CF; /* clear carry flag */ - ret = 1; - } else { - X86_AH = DEVICE_NOT_FOUND; - X86_EFLAGS |= FB_CF; /* set carry flag */ - ret = 0; - } - break; - case FIND_PCI_CLASS_CODE: - /* FixME: support SI != 0 */ - dev = dev_find_class(X86_ECX, dev); - if (dev != 0) { - X86_BH = dev->bus->secondary; - X86_BL = dev->path.pci.devfn; - X86_AH = SUCCESSFUL; - X86_EFLAGS &= ~FB_CF; /* clear carry flag */ - ret = 1; - } else { - X86_AH = DEVICE_NOT_FOUND; - X86_EFLAGS |= FB_CF; /* set carry flag */ - ret = 0; - } - break; - case READ_CONFIG_BYTE: - dev = dev_find_slot(X86_BH, X86_BL); - if (dev != 0) { - X86_CL = pci_read_config8(dev, X86_DI); - X86_AH = SUCCESSFUL; - X86_EFLAGS &= ~FB_CF; /* clear carry flag */ - ret = 1; - } else { - X86_AH = DEVICE_NOT_FOUND; - X86_EFLAGS |= FB_CF; /* set carry flag */ - ret = 0; - } - break; - case READ_CONFIG_WORD: - dev = dev_find_slot(X86_BH, X86_BL); - if (dev != 0) { - X86_CX = pci_read_config16(dev, X86_DI); - X86_AH = SUCCESSFUL; - X86_EFLAGS &= ~FB_CF; /* clear carry flag */ - ret = 1; - } else { - X86_AH = DEVICE_NOT_FOUND; - X86_EFLAGS |= FB_CF; /* set carry flag */ - ret = 0; - } - break; - case READ_CONFIG_DWORD: - dev = dev_find_slot(X86_BH, X86_BL); - if (dev != 0) { - X86_ECX = pci_read_config32(dev, X86_DI); - X86_AH = SUCCESSFUL; - X86_EFLAGS &= ~FB_CF; /* clear carry flag */ - ret = 1; - } else { - X86_AH = DEVICE_NOT_FOUND; - X86_EFLAGS |= FB_CF; /* set carry flag */ - ret = 0; - } - break; - case WRITE_CONFIG_BYTE: - dev = dev_find_slot(X86_BH, X86_BL); - if (dev != 0) { - pci_write_config8(dev, X86_DI, X86_CL); - X86_AH = SUCCESSFUL; - X86_EFLAGS &= ~FB_CF; /* clear carry flag */ - ret = 1; - } else { - X86_AH = DEVICE_NOT_FOUND; - X86_EFLAGS |= FB_CF; /* set carry flag */ - ret = 0; - } - break; - case WRITE_CONFIG_WORD: - dev = dev_find_slot(X86_BH, X86_BL); - if (dev != 0) { - pci_write_config16(dev, X86_DI, X86_CX); - X86_AH = SUCCESSFUL; - X86_EFLAGS &= ~FB_CF; /* clear carry flag */ - ret = 1; - } else { - X86_AH = DEVICE_NOT_FOUND; - X86_EFLAGS |= FB_CF; /* set carry flag */ - ret = 0; - } - break; - case WRITE_CONFIG_DWORD: - dev = dev_find_slot(X86_BH, X86_BL); - if (dev != 0) { - pci_write_config16(dev, X86_DI, X86_ECX); - X86_AH = SUCCESSFUL; - X86_EFLAGS &= ~FB_CF; /* clear carry flag */ - ret = 1; - } else { - X86_AH = DEVICE_NOT_FOUND; - X86_EFLAGS |= FB_CF; /* set carry flag */ - ret = 0; - } - break; - default: - X86_AH = FUNC_NOT_SUPPORTED; - X86_EFLAGS |= FB_CF; - break; - } - - return ret; -} - -/* Interrupt multiplexer */ - -/* Find base address of interrupt handler */ -static u32 getIntVect(int num) -{ - return MEM_RW(num << 2) + (MEM_RW((num << 2) + 2) << 4); -} - -static int run_bios_int(int num) -{ - u32 eflags; - - eflags = X86_EFLAGS; - push_word(eflags); - push_word(X86_CS); - push_word(X86_IP); - X86_CS = MEM_RW((num << 2) + 2); - X86_IP = MEM_RW(num << 2); - - return 1; -} - -static void do_int(int num) -{ - int ret = 0; - - printk("int%x (AX=%04x) vector at %x\n", num, X86_AX, getIntVect(num)); - - switch (num) { - case 0x10: - case 0x42: - case 0x6D: - if (getIntVect(num) == 0x0000) { - printk("uninitialized interrupt vector\n"); - ret = 1; - } - if (getIntVect(num) == 0xFF065) { - //ret = int42_handler(); - ret = 1; - } - break; - case 0x15: - ret = int15_handler(); - ret = 1; - break; - case 0x16: - //ret = int16_handler(); - ret = 0; - break; - case 0x1A: - ret = int1a_handler(); - ret = 1; - break; - case 0xe6: - //ret = intE6_handler(); - ret = 0; - break; - default: - break; - } - - if (!ret) - ret = run_bios_int(num); - -} - -/* - * here we are really paranoid about faking a "real" - * BIOS. Most of this information was pulled from - * dosemu. - */ -static void setup_system_bios(void) -{ - int i; - - /* Set up Interrupt Vectors. The IVT starts at 0x0000:0x0000 - * Additionally, we put some stub code into the F segment for - * those pesky little buggers that jmp to the hard coded addresses - * instead of calling int XX. This stub code looks like this - * - * CD XX int 0xXX - * C3 ret - * F4 hlt - */ - - /* int 05 default location (Bound Exceeded) */ - MEM_WL(0x05 << 2, 0xf000ff54); - MEM_WL(0xfff54, 0xf4c305cd); - /* int 08 default location (Double Fault) */ - MEM_WL(0x08 << 2, 0xf000fea5); - MEM_WL(0xffea5, 0xf4c308cd); - /* int 0E default location (Page Fault) */ - MEM_WL(0x0e << 2, 0xf000ef57); - MEM_WL(0xfef57, 0xf4c30ecd); - /* int 10 default location */ - MEM_WL(0x10 << 2, 0xf000f065); - MEM_WL(0xff065, 0xf4c310cd); - /* int 11 default location (Get Equipment Configuration) */ - MEM_WL(0x11 << 2, 0xf000f84d); - MEM_WL(0xff84d, 0xf4c311cd); - /* int 12 default location (Get Conventional Memory Size) */ - MEM_WL(0x12 << 2, 0xf000f841); - MEM_WL(0xff841, 0xf4c312cd); - /* int 13 default location (Disk) */ - MEM_WL(0x13 << 2, 0xf000ec59); - MEM_WL(0xfec59, 0xf4c313cd); - /* int 14 default location (Disk) */ - MEM_WL(0x14 << 2, 0xf000e739); - MEM_WL(0xfe739, 0xf4c314cd); - /* int 15 default location (I/O System Extensions) */ - MEM_WL(0x15 << 2, 0xf000f859); - MEM_WL(0xf859, 0xf4c315cd); - /* int 16 default location */ - MEM_WL(0x16 << 2, 0xf000e82e); - MEM_WL(0xfe82e, 0xf4c316cd); - /* int 17 default location (Parallel Port) */ - MEM_WL(0x17 << 2, 0xf000efd2); - MEM_WL(0xfefd2, 0xf4c317cd); - /* int 1A default location (RTC, PCI and others) */ - MEM_WL(0x1a << 2, 0xf000fe6e); - MEM_WL(0xffe6e, 0xf4c31acd); - /* int 1E default location (FDD table) */ - MEM_WL(0x1e << 2, 0xf000efc7); - MEM_WL(0xfefc7, 0xf4c31ecd); - /* font tables default location (int 1F) */ - MEM_WL(0x1f << 2, 0xf000fa6e); - MEM_WL(0xffa6e, 0xf4c31fcd); - /* int 42 default location */ - MEM_WL(0x42 << 2, 0xf000f065); - /* int 6D default location */ - MEM_WL(0x6D << 2, 0xf000f065); - - /* Clear EBDA */ - for (i=(INITIAL_EBDA_SEGMENT << 4); - i<(INITIAL_EBDA_SEGMENT << 4) + INITIAL_EBDA_SIZE; i++) - MEM_WB(i, 0); - /* at offset 0h in EBDA is the size of the EBDA in KB */ - MEM_WW((INITIAL_EBDA_SEGMENT << 4) + 0x0, INITIAL_EBDA_SIZE / 1024); - - /* Clear BDA */ - for (i=0x400; i<0x500; i+=4) - MEM_WL(i, 0); - - /* Set up EBDA */ - MEM_WW(0x40e, INITIAL_EBDA_SEGMENT); - - /* Set RAM size to 16MB (fake) */ - MEM_WW(0x413, 16384); - - // TODO Set up more of BDA here - - /* setup original ROM BIOS Area (F000:xxxx) */ - const char *date = "06/23/99"; - for (i = 0; date[i]; i++) - MEM_WB(0xffff5 + i, date[i]); - /* set up eisa ident string */ - const char *ident = "PCI_ISA"; - for (i = 0; ident[i]; i++) - MEM_WB(0xfffd9 + i, ident[i]); - - // write system model id for IBM-AT - // according to "Ralf Browns Interrupt List" Int15 AH=C0 Table 515, - // model FC is the original AT and also used in all DOSEMU Versions. - MEM_WB(0xFFFFE, 0xfc); -} - -#define BIOSEMU_MEM_BASE 0x00000000 -#define BIOSEMU_MEM_SIZE 0x00100000 -void run_bios(struct device * dev, unsigned long addr) -{ - int i; - u16 initialcs = (addr & 0xF0000) >> 4; - u16 initialip = (addr + 3) & 0xFFFF; - u16 devfn = (dev->bus->secondary << 8) | dev->path.pci.devfn; - X86EMU_intrFuncs intFuncs[256]; - - X86EMU_setMemBase(BIOSEMU_MEM_BASE, BIOSEMU_MEM_SIZE); - X86EMU_setupPioFuncs(&biosemu_piofuncs); - for (i = 0; i < 256; i++) - intFuncs[i] = do_int; - X86EMU_setupIntrFuncs(intFuncs); - - setup_system_bios(); - - /* cpu setup */ - X86_AX = devfn ? devfn : 0xff; - X86_DX = 0x80; - X86_EIP = initialip; - X86_CS = initialcs; - - /* Initialize stack and data segment */ - X86_SS = STACK_SEGMENT; - X86_SP = STACK_START_OFFSET;; - X86_DS = DATA_SEGMENT; - - /* We need a sane way to return from bios - * execution. A hlt instruction and a pointer - * to it, both kept on the stack, will do. - */ - push_word(0xf4f4); /* hlt; hlt */ - push_word(X86_SS); - push_word(X86_SP + 2); - -#ifdef DEBUG - //X86EMU_trace_on(); -#endif - - printk("Executing Initialization Vector...\n"); - X86EMU_exec(); - printk("Option ROM Exit Status: %04x\n", X86_AX); - - /* Check whether the stack is "clean" i.e. containing the HLT - * instruction we pushed before executing and pointing to the original - * stack address... indicating that the initialization probably was - * successful - */ - if ((pop_word() == 0xf4f4) && (X86_SS == STACK_SEGMENT) - && (X86_SP == STACK_START_OFFSET)) { - printk("Stack is clean, initialization successfull!\n"); - } else { - printk("Stack unclean, initialization probably NOT COMPLETE!!\n"); - printk("SS:SP = %04x:%04x, expected: %04x:%04x\n", - X86_SS, X86_SP, STACK_SEGMENT, STACK_START_OFFSET); - } -} diff --git a/util/x86emu/yabel/Makefile.inc b/util/x86emu/yabel/Makefile.inc index fc6a8a0..f89de9b 100644 --- a/util/x86emu/yabel/Makefile.inc +++ b/util/x86emu/yabel/Makefile.inc @@ -5,4 +5,5 @@ obj-y += interrupt.o obj-y += io.o obj-y += mem.o obj-y += pmm.o +obj-y += vbe.o subdirs-y += compat diff --git a/util/x86emu/yabel/biosemu.c b/util/x86emu/yabel/biosemu.c index df20281..09a98b5 100644 --- a/util/x86emu/yabel/biosemu.c +++ b/util/x86emu/yabel/biosemu.c @@ -86,10 +86,15 @@ biosemu(u8 *biosmem, u32 biosmem_size, struct device * dev, unsigned long rom_ad // in case we jump somewhere unexpected, or execution is finished, // fill the biosmem with hlt instructions (0xf4) - memset(biosmem, 0xf4, biosmem_size); + // But we have to be careful: If biosmem is 0x00000000 we're running + // in the lower 1MB and we must not wipe memory like that. + if (biosmem) { + DEBUG_PRINTF("Clearing biosmem\n"); + memset(biosmem, 0xf4, biosmem_size); + } + + X86EMU_setMemBase(biosmem, biosmem_size); - M.mem_base = (long) biosmem; - M.mem_size = biosmem_size; DEBUG_PRINTF("membase set: %08x, size: %08x\n", (int) M.mem_base, (int) M.mem_size); diff --git a/util/x86emu/yabel/compat/functions.c b/util/x86emu/yabel/compat/functions.c index 600b0ba..599e82e 100644 --- a/util/x86emu/yabel/compat/functions.c +++ b/util/x86emu/yabel/compat/functions.c @@ -16,24 +16,41 @@ #include #include #include +#include "../debug.h" -#define VMEM_SIZE 1024 *1024 /* 1 MB */ +#define VMEM_SIZE (1024 * 1024) /* 1 MB */ +#if !defined(CONFIG_YABEL_DIRECTHW) || (!CONFIG_YABEL_DIRECTHW) #ifdef CONFIG_YABEL_VIRTMEM_LOCATION u8* vmem = (u8 *) CONFIG_YABEL_VIRTMEM_LOCATION; #else u8* vmem = (u8 *) (16*1024*1024); /* default to 16MB */ #endif +#else +u8* vmem = NULL; +#endif u32 biosemu(u8 *biosmem, u32 biosmem_size, struct device *dev, unsigned long rom_addr); +#if CONFIG_BOOTSPLASH +void vbe_set_graphics(void); +#endif void run_bios(struct device * dev, unsigned long addr) { + biosemu(vmem, VMEM_SIZE, dev, addr); - memcpy(0x0, vmem + 0x0, 0x400); - memcpy(0x400, vmem + 0x400, 0x100); - memcpy(0xc0000, vmem + 0xc0000, 0x10000); + +#if CONFIG_BOOTSPLASH + vbe_set_graphics(); +#endif + + if (vmem != NULL) { + printf("Copying legacy memory from 0x%08x to the lower 1MB\n", vmem); + memcpy(0x00000, vmem + 0x00000, 0x400); // IVT + memcpy(0x00400, vmem + 0x00400, 0x100); // BDA + memcpy(0xc0000, vmem + 0xc0000, 0x10000); // VGA OPROM + } } u64 get_time(void) diff --git a/util/x86emu/yabel/io.c b/util/x86emu/yabel/io.c index fd205e4..9bb2df4 100644 --- a/util/x86emu/yabel/io.c +++ b/util/x86emu/yabel/io.c @@ -80,6 +80,76 @@ inl(u16 port) return 0; } #endif + +#if defined(CONFIG_YABEL_DIRECTHW) && (CONFIG_YABEL_DIRECTHW == 1) +u8 my_inb(X86EMU_pioAddr addr) +{ + u8 val; + + val = inb(addr); +#ifdef CONFIG_DEBUG + if ((debug_flags & DEBUG_IO) && (addr != 0x40)) + printk("inb(0x%04x) = 0x%02x\n", addr, val); +#endif + + return val; +} + +u16 my_inw(X86EMU_pioAddr addr) +{ + u16 val; + + val = inw(addr); + +#ifdef CONFIG_DEBUG + if (debug_flags & DEBUG_IO) + printk("inw(0x%04x) = 0x%04x\n", addr, val); +#endif + return val; +} + +u32 my_inl(X86EMU_pioAddr addr) +{ + u32 val; + + val = inl(addr); + +#ifdef CONFIG_DEBUG + if (debug_flags & DEBUG_IO) + printk("inl(0x%04x) = 0x%08x\n", addr, val); +#endif + return val; +} + +void my_outb(X86EMU_pioAddr addr, u8 val) +{ +#ifdef CONFIG_DEBUG + if ((debug_flags & DEBUG_IO) && (addr != 0x43)) + printk("outb(0x%02x, 0x%04x)\n", val, addr); +#endif + outb(val, addr); +} + +void my_outw(X86EMU_pioAddr addr, u16 val) +{ +#ifdef CONFIG_DEBUG + if (debug_flags & DEBUG_IO) + printk("outw(0x%04x, 0x%04x)\n", val, addr); +#endif + outw(val, addr); +} + +void my_outl(X86EMU_pioAddr addr, u32 val) +{ +#ifdef CONFIG_DEBUG + if (debug_flags & DEBUG_IO) + printk("outl(0x%08x, 0x%04x)\n", val, addr); +#endif + outl(val, addr); +} + +#else + u32 pci_cfg_read(X86EMU_pioAddr addr, u8 size); void pci_cfg_write(X86EMU_pioAddr addr, u32 val, u8 size); u8 handle_port_61h(void); @@ -479,3 +549,4 @@ handle_port_61h(void) //finally read the value from the io_buffer return *((u8 *) (bios_device.io_buffer + 0x61)); } +#endif diff --git a/util/x86emu/yabel/mem.c b/util/x86emu/yabel/mem.c index 294e76d..1cf66dd 100644 --- a/util/x86emu/yabel/mem.c +++ b/util/x86emu/yabel/mem.c @@ -168,6 +168,7 @@ extern u64 get_time(void); void update_time(u32); +#if !defined(CONFIG_YABEL_DIRECTHW) || (!CONFIG_YABEL_DIRECTHW) // read byte from memory u8 my_rdb(u32 addr) @@ -436,6 +437,43 @@ my_wrl(u32 addr, u32 val) out32le((void *) (M.mem_base + addr), val); } } +#else +u8 +my_rdb(u32 addr) +{ + return rdb(addr); +} + +u16 +my_rdw(u32 addr) +{ + return rdw(addr); +} + +u32 +my_rdl(u32 addr) +{ + return rdl(addr); +} + +void +my_wrb(u32 addr, u8 val) +{ + wrb(addr, val); +} + +void +my_wrw(u32 addr, u16 val) +{ + wrw(addr, val); +} + +void +my_wrl(u32 addr, u32 val) +{ + wrl(addr, val); +} +#endif //update time in BIOS Data Area //DWord at offset 0x6c is the timer ticks since midnight, timer is running at 18Hz diff --git a/util/x86emu/yabel/vbe.c b/util/x86emu/yabel/vbe.c index db60630..90b468b 100644 --- a/util/x86emu/yabel/vbe.c +++ b/util/x86emu/yabel/vbe.c @@ -13,6 +13,12 @@ #include #include +#if CONFIG_BOOTSPLASH +#include +#endif + +#include +#define ntohl(x) be32_to_cpu(x) #include "debug.h" @@ -26,18 +32,14 @@ #include "interrupt.h" #include "device.h" -static X86EMU_memFuncs my_mem_funcs = { - my_rdb, my_rdw, my_rdl, - my_wrb, my_wrw, my_wrl -}; +#include -static X86EMU_pioFuncs my_pio_funcs = { - my_inb, my_inw, my_inl, - my_outb, my_outw, my_outl -}; +#include +#include "../../src/lib/jpeg.h" // pointer to VBEInfoBuffer, set by vbe_prepare u8 *vbe_info_buffer = 0; + // virtual BIOS Memory u8 *biosmem; u32 biosmem_size; @@ -73,17 +75,57 @@ typedef struct { } vbe_info_t; typedef struct { + u16 mode_attributes; // 00 + u8 win_a_attributes; // 02 + u8 win_b_attributes; // 03 + u16 win_granularity; // 04 + u16 win_size; // 06 + u16 win_a_segment; // 08 + u16 win_b_segment; // 0a + u32 win_func_ptr; // 0c + u16 bytes_per_scanline; // 10 + u16 x_resolution; // 12 + u16 y_resolution; // 14 + u8 x_charsize; // 16 + u8 y_charsize; // 17 + u8 number_of_planes; // 18 + u8 bits_per_pixel; // 19 + u8 number_of_banks; // 20 + u8 memory_model; // 21 + u8 bank_size; // 22 + u8 number_of_image_pages; // 23 + u8 reserved_page; + u8 red_mask_size; + u8 red_mask_pos; + u8 green_mask_size; + u8 green_mask_pos; + u8 blue_mask_size; + u8 blue_mask_pos; + u8 reserved_mask_size; + u8 reserved_mask_pos; + u8 direct_color_mode_info; + u32 phys_base_ptr; + u32 offscreen_mem_offset; + u16 offscreen_mem_size; + u8 reserved[206]; +} __attribute__ ((__packed__)) vesa_mode_info_t; + +typedef struct { u16 video_mode; - u8 mode_info_block[256]; - u16 attributes; - u16 linebytes; - u16 x_resolution; - u16 y_resolution; - u8 x_charsize; - u8 y_charsize; - u8 bits_per_pixel; - u8 memory_model; - u32 framebuffer_address; + union { + vesa_mode_info_t vesa; + u8 mode_info_block[256]; + }; + // our crap + //u16 attributes; + //u16 linebytes; + //u16 x_resolution; + //u16 y_resolution; + //u8 x_charsize; + //u8 y_charsize; + //u8 bits_per_pixel; + //u8 memory_model; + //u32 framebuffer_address; } vbe_mode_info_t; typedef struct { @@ -94,7 +136,7 @@ typedef struct { } vbe_ddc_info_t; static inline u8 -vbe_prepare() +vbe_prepare(void) { vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area //clear buffer @@ -209,6 +251,7 @@ vbe_get_mode_info(vbe_mode_info_t * mode_info) __func__, mode_info->video_mode, M.x86.R_AH); return M.x86.R_AH; } + //pointer to mode_info_block is in ES:DI memcpy(mode_info->mode_info_block, biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI), @@ -217,34 +260,6 @@ vbe_get_mode_info(vbe_mode_info_t * mode_info) //printf("Mode Info Dump:"); //dump(mode_info_block, 64); - // offset 0: 16bit le mode attributes - mode_info->attributes = in16le(mode_info->mode_info_block); - - // offset 16: 16bit le bytes per scan line - mode_info->linebytes = in16le(mode_info->mode_info_block + 16); - - // offset 18: 16bit le x resolution - mode_info->x_resolution = in16le(mode_info->mode_info_block + 18); - - // offset 20: 16bit le y resolution - mode_info->y_resolution = in16le(mode_info->mode_info_block + 20); - - // offset 22: 8bit le x charsize - mode_info->x_charsize = *(mode_info->mode_info_block + 22); - - // offset 23: 8bit le y charsize - mode_info->y_charsize = *(mode_info->mode_info_block + 23); - - // offset 25: 8bit le bits per pixel - mode_info->bits_per_pixel = *(mode_info->mode_info_block + 25); - - // offset 27: 8bit le memory model - mode_info->memory_model = *(mode_info->mode_info_block + 27); - - // offset 40: 32bit le containg offset of frame buffer memory ptr - mode_info->framebuffer_address = - in32le(mode_info->mode_info_block + 40); - return 0; } @@ -482,56 +497,22 @@ vbe_get_ddc_info(vbe_ddc_info_t * ddc_info) } u32 -vbe_get_info(u8 argc, char ** argv) +vbe_get_info(void) { u8 rval; - u32 i; - if (argc < 4) { - printf - ("Usage %s
\n", - argv[0]); - int i = 0; - for (i = 0; i < argc; i++) { - printf("argv[%d]: %s\n", i, argv[i]); - } - return -1; - } + int i; + + // XXX FIXME these need to be filled with sane values + // get a copy of input struct... - screen_info_input_t input = - *((screen_info_input_t *) strtoul((char *) argv[4], 0, 16)); + screen_info_input_t input; // output is pointer to the address passed as argv[4] - screen_info_t *output = - (screen_info_t *) strtoul((char *) argv[4], 0, 16); + screen_info_t local_output; + screen_info_t *output = &local_output; + // zero input + memset(&input, 0, sizeof(screen_info_input_t)); // zero output - memset(output, 0, sizeof(screen_info_t)); - - // argv[1] is address of virtual BIOS mem... - // argv[2] is the size - biosmem = (u8 *) strtoul(argv[1], 0, 16); - biosmem_size = strtoul(argv[2], 0, 16);; - if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) { - printf("Error: Not enough virtual memory: %x, required: %x!\n", - biosmem_size, MIN_REQUIRED_VMEM_SIZE); - return -1; - } - // argv[3] is the device to open and use... - if (dev_init((char *) argv[3]) != 0) { - printf("Error initializing device!\n"); - return -1; - } - //setup interrupt handler - X86EMU_intrFuncs intrFuncs[256]; - for (i = 0; i < 256; i++) - intrFuncs[i] = handleInterrupt; - X86EMU_setupIntrFuncs(intrFuncs); - X86EMU_setupPioFuncs(&my_pio_funcs); - X86EMU_setupMemFuncs(&my_mem_funcs); - - // set mem_base - M.mem_base = (long) biosmem; - M.mem_size = biosmem_size; - DEBUG_PRINTF_VBE("membase set: %08x, size: %08x\n", (int) M.mem_base, - (int) M.mem_size); + memset(&output, 0, sizeof(screen_info_t)); vbe_info_t info; rval = vbe_info(&info); @@ -613,7 +594,9 @@ vbe_get_info(u8 argc, char ** argv) while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) { //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode); vbe_get_mode_info(&mode_info); -#if 0 + + // FIXME all these values are little endian! + DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n", mode_info.video_mode, (mode_info.attributes & 0x1) == @@ -646,13 +629,13 @@ vbe_get_info(u8 argc, char ** argv) mode_info.memory_model); DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n", mode_info.framebuffer_address); -#endif - if ((mode_info.bits_per_pixel == input.color_depth) - && (mode_info.x_resolution <= input.max_screen_width) - && ((mode_info.attributes & 0x80) != 0) // framebuffer mode - && ((mode_info.attributes & 0x10) != 0) // graphics - && ((mode_info.attributes & 0x8) != 0) // color - && (mode_info.x_resolution > best_mode_info.x_resolution)) // better than previous best_mode + + if ((mode_info.vesa.bits_per_pixel == input.color_depth) + && (le16_to_cpu(mode_info.vesa.x_resolution) <= input.max_screen_width) + && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x80) != 0) // framebuffer mode + && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x10) != 0) // graphics + && ((le16_to_cpu(mode_info.vesa.mode_attributes) & 0x8) != 0) // color + && (le16_to_cpu(mode_info.vesa.x_resolution) > le16_to_cpu(best_mode_info.vesa.x_resolution))) // better than previous best_mode { // yiiiihaah... we found a new best mode memcpy(&best_mode_info, &mode_info, sizeof(mode_info)); @@ -757,12 +740,12 @@ vbe_get_info(u8 argc, char ** argv) vbe_set_color(0x00, 0x00000000); vbe_set_color(0xFF, 0x00FFFFFF); - output->screen_width = best_mode_info.x_resolution; - output->screen_height = best_mode_info.y_resolution; - output->screen_linebytes = best_mode_info.linebytes; - output->color_depth = best_mode_info.bits_per_pixel; + output->screen_width = le16_to_cpu(best_mode_info.vesa.x_resolution); + output->screen_height = le16_to_cpu(best_mode_info.vesa.y_resolution); + output->screen_linebytes = le16_to_cpu(best_mode_info.vesa.bytes_per_scanline); + output->color_depth = best_mode_info.vesa.bits_per_pixel; output->framebuffer_address = - best_mode_info.framebuffer_address; + le32_to_cpu(best_mode_info.vesa.phys_base_ptr); } else { printf("%s: No suitable video mode found!\n", __func__); //unset display_type... @@ -770,3 +753,92 @@ vbe_get_info(u8 argc, char ** argv) } return 0; } + +#if CONFIG_BOOTSPLASH +vbe_mode_info_t mode_info; + +void vbe_set_graphics(void) +{ + u8 rval; + int i; + + vbe_info_t info; + rval = vbe_info(&info); + if (rval != 0) + return; + + DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature); + DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version); + DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr); + DEBUG_PRINTF_VBE("Capabilities:\n"); + DEBUG_PRINTF_VBE("\tDAC: %s\n", + (info.capabilities & 0x1) == + 0 ? "fixed 6bit" : "switchable 6/8bit"); + DEBUG_PRINTF_VBE("\tVGA: %s\n", + (info.capabilities & 0x2) == + 0 ? "compatible" : "not compatible"); + DEBUG_PRINTF_VBE("\tRAMDAC: %s\n", + (info.capabilities & 0x4) == + 0 ? "normal" : "use blank bit in Function 09h"); + + mode_info.video_mode = (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE; + vbe_get_mode_info(&mode_info); + unsigned char *framebuffer = + (unsigned char *) le32_to_cpu(mode_info.vesa.phys_base_ptr); + DEBUG_PRINTF_VBE("FRAMEBUFFER: 0x%08x\n", framebuffer); + vbe_set_mode(&mode_info); + + struct jpeg_decdata *decdata; + decdata = malloc(sizeof(*decdata)); + + /* Switching Intel IGD to 1MB video memory will break this. Who + * cares. */ + int imagesize = 1024*768*2; + + struct cbfs_file *file = cbfs_find("bootsplash.jpg"); + if (!file) { + DEBUG_PRINTF_VBE("Could not find bootsplash.jpg\n"); + return; + } + unsigned char *jpeg = ((unsigned char *)file) + ntohl(file->offset); + DEBUG_PRINTF_VBE("Splash at %08x ...\n", jpeg); + dump(jpeg, 64); + + int ret = 0; + DEBUG_PRINTF_VBE("Decompressing boot splash screen...\n"); + ret = jpeg_decode(jpeg, framebuffer, 1024, 768, 16, decdata); + DEBUG_PRINTF_VBE("returns %x\n", ret); +} + +void fill_lb_framebuffer(struct lb_framebuffer *framebuffer) +{ + framebuffer->physical_address = le32_to_cpu(mode_info.vesa.phys_base_ptr); + + framebuffer->x_resolution = le16_to_cpu(mode_info.vesa.x_resolution); + framebuffer->y_resolution = le16_to_cpu(mode_info.vesa.y_resolution); + framebuffer->bytes_per_line = le16_to_cpu(mode_info.vesa.bytes_per_scanline); + framebuffer->bits_per_pixel = mode_info.vesa.bits_per_pixel; + + framebuffer->red_mask_pos = mode_info.vesa.red_mask_pos; + framebuffer->red_mask_size = mode_info.vesa.red_mask_size; + + framebuffer->green_mask_pos = mode_info.vesa.green_mask_pos; + framebuffer->green_mask_size = mode_info.vesa.green_mask_size; + + framebuffer->blue_mask_pos = mode_info.vesa.blue_mask_pos; + framebuffer->blue_mask_size = mode_info.vesa.blue_mask_size; + + framebuffer->reserved_mask_pos = mode_info.vesa.reserved_mask_pos; + framebuffer->reserved_mask_size = mode_info.vesa.reserved_mask_size; +} + +void vbe_textmode_console(void) +{ + /* Wait, just a little bit more, pleeeease ;-) */ + delay(2); + + M.x86.R_EAX = 0x0003; + runInt10(); +} + +#endif -- cgit v1.1