diff options
author | Stefan Reinauer <stepan@coresystems.de> | 2010-02-22 04:33:13 +0000 |
---|---|---|
committer | Stefan Reinauer <stepan@openbios.org> | 2010-02-22 04:33:13 +0000 |
commit | d650e9934ff8da9b9cb69e42e642c0ee6d390bf6 (patch) | |
tree | 8c6982efa868e828c21d4d427d2678e7e0804668 /src | |
parent | 30b90fe4f0b31aa6676f507d3913579453942ba8 (diff) | |
download | coreboot-d650e9934ff8da9b9cb69e42e642c0ee6d390bf6.tar.xz |
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 <stepan@coresystems.de>
Acked-by: Pattrick Hueper <phueper@hueper.net>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5135 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/i386/boot/coreboot_table.c | 15 | ||||
-rw-r--r-- | src/arch/i386/include/arch/byteorder.h | 3 | ||||
-rw-r--r-- | src/devices/Kconfig | 123 | ||||
-rw-r--r-- | src/include/boot/coreboot_tables.h | 32 | ||||
-rw-r--r-- | src/lib/Makefile.inc | 2 | ||||
-rw-r--r-- | src/lib/cbfs.c | 10 | ||||
-rw-r--r-- | src/lib/fallback_boot.c | 5 | ||||
-rw-r--r-- | src/lib/jpeg.c | 988 | ||||
-rw-r--r-- | src/lib/jpeg.h | 56 |
9 files changed, 1188 insertions, 46 deletions
diff --git a/src/arch/i386/boot/coreboot_table.c b/src/arch/i386/boot/coreboot_table.c index e766463255..f3b7f6daca 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 eecd02cf2b..ab344e6394 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 42c47bc19c..8211bf30f5 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 <stepan@coresystems.de> 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 2ba61266c6..476a374cb3 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 b94906b30f..cbff717c32 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 f99f666d3c..0bb6e838fb 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -22,13 +22,7 @@ #include <console/console.h> #include <cbfs.h> #include <lib.h> - -#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 <arch/byteorder.h> 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 59476fdf2a..b969b6b5cf 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 0000000000..b7c0004708 --- /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 <mls@suse.de> + * + */ + +#define __LITTLE_ENDIAN +#include <string.h> +#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 0000000000..12e8e9f989 --- /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 <mls@suse.de> + */ + +#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 |