See patch
On Wed, Jun 09, 2010 at 09:46:27AM +0200, Stefan Reinauer wrote:
See patch
Thanks Stefan! It looks very useful.
I haven't had a chance to review the patch fully. One thing I did note is that the new file jpeg.c needs a copyright statement.
At a quick glance I also noticed a couple of minor things:
* It looks like you want malloc_tmplow/tmphigh instead of malloc_low/high - using the permanent allocations has an impact on reserved space even if they are eventually freed.
* I'd guess we'd want to malloc_tmp and cbfs_copyfile instead of cbfs_getfile - doing the jpeg uncompression with the rom as source could be slow.
* there seems to be some tab/space corruption in optionrom.c - seabios uses all spaces
* Do the vga changes justify a new file instead of an addition to optionrom.c?
-Kevin
On 6/10/10 4:57 AM, Kevin O'Connor wrote:
On Wed, Jun 09, 2010 at 09:46:27AM +0200, Stefan Reinauer wrote:
See patch
Thanks Stefan! It looks very useful.
I haven't had a chance to review the patch fully.
Thanks for the input so far. Here's an updated patch
One thing I did note is that the new file jpeg.c needs a copyright statement.
Still working on that.
At a quick glance I also noticed a couple of minor things:
- It looks like you want malloc_tmplow/tmphigh instead of malloc_low/high - using the permanent allocations has an impact on reserved space even if they are eventually freed.
There is no malloc_tmplow so I used malloc_tmphigh all along.
- I'd guess we'd want to malloc_tmp and cbfs_copyfile instead of cbfs_getfile - doing the jpeg uncompression with the rom as source could be slow.
Ok, I changed the code. This significantly increases the required heap though (by the size of the compressed jpeg image)
- there seems to be some tab/space corruption in optionrom.c - seabios uses all spaces
Sorry, didn't know that. I hope I got it fixed.
- Do the vga changes justify a new file instead of an addition to optionrom.c?
Look at the attached patch to decide if you like it more. Maybe some more functions could be moved from optionroms.c to vga.c?
Another thing you mentioned on IRC is it would be nice to reduce the 18kb BSS requirement of the jpeg.c code. I didn't work on that yet. If you see any obvious low hanging fruits, please grab them.
Stefan
Another attempt, this time with (temporary) GPLv2 headers (will hopefully be relicensed to LGPLv3 by Michael) and with a config option in config.h
On Mon, Jun 14, 2010 at 12:52:36AM +0200, Stefan Reinauer wrote:
On 6/10/10 4:57 AM, Kevin O'Connor wrote:
One thing I did note is that the new file jpeg.c needs a copyright statement.
Still working on that.
Thanks. I think we can commit once we have that. (We can continue to improve the code once committed.)
A couple of random notes:
I like the separation of the code to "vga.c". However, I think I'd prefer something like "bootsplash.c" over "vga.c" - just so there is no confusion with the handle_10 vga callback implementation.
The changes to ulzma wont work. The malloc_X calls only work in POST, however ulzma can be called during boot (when seabios boots a payload). As far as I can tell it shouldn't be necessary though. SeaBIOS has a 24K stack (at 0x7000) for the "main thread" during both post and boot (each "thread" only has a 4K stack, but no thread calls ulzma).
BTW, I think it should be straight forward to use this code in qemu also.
-Kevin
On 6/14/10 3:07 AM, Kevin O'Connor wrote:
On Mon, Jun 14, 2010 at 12:52:36AM +0200, Stefan Reinauer wrote:
On 6/10/10 4:57 AM, Kevin O'Connor wrote:
One thing I did note is that the new file jpeg.c needs a copyright statement.
Still working on that.
Thanks. I think we can commit once we have that. (We can continue to improve the code once committed.)
A couple of random notes:
I like the separation of the code to "vga.c". However, I think I'd prefer something like "bootsplash.c" over "vga.c" - just so there is no confusion with the handle_10 vga callback implementation.
That's what I initially had and I changed it because it contains non-bootsplash specific code, too. (enable_vga_console) - If you think we should, I'll rename it back to bootsplash.c Or maybe vesa.c?
The changes to ulzma wont work. The malloc_X calls only work in POST, however ulzma can be called during boot (when seabios boots a payload). As far as I can tell it shouldn't be necessary though. SeaBIOS has a 24K stack (at 0x7000) for the "main thread" during both post and boot (each "thread" only has a 4K stack, but no thread calls ulzma).
ulzma may take more than those 15kb, and the code is theoretically able to find out how much it needs... Is there a malloc that could be used here?
Is there some documentation on what each malloc version does? It's quite confusing for beginners :-)
BTW, I think it should be straight forward to use this code in qemu also.
With some way to get hold of the jpg file, certainly.
Stefan
This version of the bootsplash patch should have all urgent issues resolved. Especially the license issue has been clarified. Michael Schroeder relicensed the code to the GPL compatible 3 clause BSD license; I updated the headers accordingly.
It still requires 18k of BSS for the JPEG code, but that's good for a later patch.
Stefan
On 6/14/10 12:15 PM, Stefan Reinauer wrote:
This version of the bootsplash patch should have all urgent issues resolved. Especially the license issue has been clarified. Michael Schroeder relicensed the code to the GPL compatible 3 clause BSD license; I updated the headers accordingly.
It still requires 18k of BSS for the JPEG code, but that's good for a later patch.
Stefan
Any further things to do, or can this be merged?
Stefan
On Fri, Jun 18, 2010 at 02:04:52PM +0200, Stefan Reinauer wrote:
On 6/14/10 12:15 PM, Stefan Reinauer wrote:
This version of the bootsplash patch should have all urgent issues resolved.
Any further things to do, or can this be merged?
Sorry - I got pulled away for a couple of days. I think it can be merged (with some changes - see my other mail).
On a separate note, I have been thinking a bit on the compatibility impact of using the boot splash code. Right now, the code returns to a text console just before launching the OS to ensure that legacy code (which may not work correctly in 1024x768 mode) will still work.
However, the boot code isn't necessarily run - a legacy option rom could hook int 0x19. Also, the option roms themselves may try to write to the screen (eg, a scsi boot config menu), and they may get confused by the video mode.
One way to solve this would be to only show the bootsplash during the boot menu (after option roms and before boot). The machines I have show the boot splash only before option roms, but coreboot+seabios boots so fast it would be pointless to show it then. However, even the boot menu is only shown for 2.5 seconds (CONFIG_BOOTMENU_WAIT). Also, switching resolutions before and after the boot menu might be annoying for users.
One possibility would be to try to use the same resolution for the bootsplash as the text console (720x400).
I'm not sure this is even a real problem. Any thoughts?
-Kevin
On Mon, Jun 14, 2010 at 12:15:45PM +0200, Stefan Reinauer wrote:
This version of the bootsplash patch should have all urgent issues resolved. Especially the license issue has been clarified. Michael Schroeder relicensed the code to the GPL compatible 3 clause BSD license; I updated the headers accordingly.
It still requires 18k of BSS for the JPEG code, but that's good for a later patch.
Stefan
I think it needs a couple of minor changes. How about the attached?
The changes I made - lets default bootsplash to off until the BSS is fixed up, when bootsplash is disabled the vga console setup should not change, and I don't think jpeg.h needs that lengthy copyright.
-Kevin
diff --git a/Makefile b/Makefile index 927999c..3798ca6 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ SRCBOTH=misc.c pmm.c stacks.c output.c util.c block.c floppy.c ata.c mouse.c \ SRC16=$(SRCBOTH) system.c disk.c apm.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ - lzmadecode.c usb-hub.c paravirt.c + lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \ diff --git a/TODO b/TODO index 81fc962..d49aeb8 100644 --- a/TODO +++ b/TODO @@ -26,6 +26,4 @@ Possibly add option to eliminate tsc based delays on emulators. Add a kconfig style configuration program instead of requiring users to modify config.h.
-Add a graphical boot splash screen? - Possibly support sending debug information over EHCI debug port. diff --git a/src/boot.c b/src/boot.c index d2ac703..814dee1 100644 --- a/src/boot.c +++ b/src/boot.c @@ -345,6 +345,9 @@ call_boot_entry(u16 bootseg, u16 bootip, u8 bootdrv) { dprintf(1, "Booting from %04x:%04x\n", bootseg, bootip);
+ /* Go back to text, the OS might expect it... (Can't do this any later) */ + disable_bootsplash(); + struct bregs br; memset(&br, 0, sizeof(br)); br.flags = F_IF; diff --git a/src/bootsplash.c b/src/bootsplash.c new file mode 100644 index 0000000..0b550ad --- /dev/null +++ b/src/bootsplash.c @@ -0,0 +1,262 @@ +// Option rom scanning code. +// +// Copyright (C) 2009-2010 coresystems GmbH +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "bregs.h" // struct bregs +#include "farptr.h" // FLATPTR_TO_SEG +#include "config.h" // CONFIG_* +#include "util.h" // dprintf +#include "jpeg.h" // splash + +/**************************************************************** + * Definitions + ****************************************************************/ + +/**************************************************************** + * VESA structures + ****************************************************************/ + +struct vesa_info +{ + u8 vesa_signature[4]; + u16 vesa_version; + u32 oem_string_ptr; + u8 capabilities[4]; + u32 video_mode_ptr; + u16 total_memory; + u16 oem_software_rev; + u32 oem_vendor_name_ptr; + u32 oem_product_name_ptr; + u32 oem_product_rev_ptr; + u8 reserved[222]; + u8 oem_data[256]; +} PACKED; + +struct vesa_mode_info +{ + u16 mode_attributes; + u8 win_a_attributes; + u8 win_b_attributes; + u16 win_granularity; + u16 win_size; + u16 win_a_segment; + u16 win_b_segment; + u32 win_func_ptr; + u16 bytes_per_scanline; + u16 x_resolution; + u16 y_resolution; + u8 x_charsize; + u8 y_charsize; + u8 number_of_planes; + u8 bits_per_pixel; + u8 number_of_banks; + u8 memory_model; + u8 bank_size; + u8 number_of_image_pages; + 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]; +} PACKED; + +/**************************************************************** + * Helper functions + ****************************************************************/ + +/**************************************************************** + * VGA text / graphics console + ****************************************************************/ +static void enable_vga_text_console(void) +{ + dprintf(1, "Turning on vga text mode console\n"); + struct bregs br; + + /* Enable VGA text mode */ + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.ax = 0x0003; + start_preempt(); + call16_int(0x10, &br); + finish_preempt(); + + if (CONFIG_BOOTSPLASH) { + /* Switch back to start of the framebuffer + * (disable "double buffering") + */ + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.ax = 0x4f07; + br.bl = 0x02; + br.ecx = 0; + + start_preempt(); + call16_int(0x10, &br); + finish_preempt(); + } + + // Write to screen. + printf("Starting SeaBIOS (version %s)\n\n", VERSION); +} + +void enable_vga_console(void) +{ + /* Needs coreboot support for CBFS */ + if (!CONFIG_BOOTSPLASH || !CONFIG_COREBOOT) { + enable_vga_text_console(); + return; + } + + struct bregs br; + struct vesa_info *vesa_info; + struct vesa_mode_info *mode_info; + struct jpeg_decdata *decdata; + + vesa_info = malloc_tmphigh(sizeof(*vesa_info)); + mode_info = malloc_tmphigh(sizeof(*mode_info)); + decdata = malloc_tmphigh(sizeof(*decdata)); + + /* Check whether we have a VESA 2.0 compliant BIOS */ + memset(vesa_info, 0, sizeof(struct vesa_info)); + memcpy(vesa_info, "VBE2", 4); + + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.ax = 0x4f00; + br.di = FLATPTR_TO_OFFSET(vesa_info); + br.es = FLATPTR_TO_SEG(vesa_info); + start_preempt(); + call16_int(0x10, &br); + finish_preempt(); + + if(strcmp("VESA", (char *)vesa_info) != 0) { + dprintf(1,"No VBE2 found.\n"); + goto cleanup; + } + + /* Print some debugging information about our card. */ + char *vendor, *product; + vendor = (char *)(((vesa_info->oem_vendor_name_ptr & 0xffff0000) >> 12) | + (vesa_info->oem_vendor_name_ptr & 0xffff)); + + product = (char *)(((vesa_info->oem_product_name_ptr & 0xffff0000) >> 12) | + (vesa_info->oem_product_name_ptr & 0xffff)); + + dprintf(8, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n", + vesa_info->vesa_version>>8,vesa_info->vesa_version&0xff, + vendor, product); + + /* Get information about our graphics mode, like the + * framebuffer start address + */ + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.ax = 0x4f01; + br.cx = (1 << 14) | CONFIG_BOOTSPLASH_VESA_MODE; + br.di = FLATPTR_TO_OFFSET(mode_info); + br.es = FLATPTR_TO_SEG(mode_info); + start_preempt(); + call16_int(0x10, &br); + finish_preempt(); + if (br.ax != 0x4f) { + dprintf(1, "get_mode failed.\n"); + enable_vga_text_console(); + goto cleanup; + } + unsigned char *framebuffer = (unsigned char *) (mode_info->phys_base_ptr); + + /* Switch to graphics mode */ + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.ax = 0x4f02; + br.bx = (1 << 14) | CONFIG_BOOTSPLASH_VESA_MODE; + start_preempt(); + call16_int(0x10, &br); + finish_preempt(); + if (br.ax != 0x4f) { + dprintf(1, "set_mode failed.\n"); + enable_vga_text_console(); + goto cleanup; + } + + /* Switching Intel IGD to 1MB video memory will break this. Who cares. */ + int imagesize = CONFIG_BOOTSPLASH_X * CONFIG_BOOTSPLASH_Y * + (CONFIG_BOOTSPLASH_DEPTH / 8); + + /* We use "double buffering" to make things look nicer */ + framebuffer += imagesize; + + dprintf(9, "framebuffer: %x\n", (u32)framebuffer); + dprintf(9, "bytes per scanline: %d\n", mode_info->bytes_per_scanline); + dprintf(9, "bits per pixel: %d\n", mode_info->bits_per_pixel); + + /* Look for bootsplash.jpg in CBFS and decompress it... */ + int ret = 0; + unsigned char *jpeg = NULL; + + struct cbfs_file *file = cbfs_finddatafile("bootsplash.jpg"); + int filesize = 0; + + if (file) { + filesize = cbfs_datasize(file); + jpeg = malloc_tmphigh(filesize); + } else { + dprintf(1, "Could not find boot splash screen "bootsplash.jpg"\n"); + } + if(jpeg) { + dprintf(9, "Copying boot splash screen...\n"); + cbfs_copyfile(file, jpeg, filesize); + dprintf(9, "Decompressing boot splash screen...\n"); + start_preempt(); + ret = jpeg_decode(jpeg, framebuffer, CONFIG_BOOTSPLASH_X, + CONFIG_BOOTSPLASH_Y, CONFIG_BOOTSPLASH_DEPTH, decdata); + finish_preempt(); + if (ret) + dprintf(1, "Failed with return code %x...\n", ret); + } else { + ret = -1; + } + free(jpeg); + if (ret) { + enable_vga_text_console(); + goto cleanup; + } + + /* Show the picture */ + memset(&br, 0, sizeof(br)); + br.flags = F_IF; + br.ax = 0x4f07; + br.bl = 0x02; + br.ecx = imagesize; + start_preempt(); + call16_int(0x10, &br); + finish_preempt(); + if (br.ax != 0x4f) { + dprintf(1, "display_start failed.\n"); + enable_vga_text_console(); + } + +cleanup: + free (vesa_info); + free (mode_info); + free (decdata); +} + +void +disable_bootsplash(void) +{ + if (! CONFIG_BOOTSPLASH) + return; + enable_vga_text_console(); +} diff --git a/src/config.h b/src/config.h index ad569c6..238a286 100644 --- a/src/config.h +++ b/src/config.h @@ -121,6 +121,16 @@ #define CONFIG_S3_RESUME 1 // Run the vga rom during S3 resume. #define CONFIG_S3_RESUME_VGA_INIT 0 +// Support boot splash +#define CONFIG_BOOTSPLASH 0 +// boot splash X resolution +#define CONFIG_BOOTSPLASH_X 1024 +// boot splash Y resolution +#define CONFIG_BOOTSPLASH_Y 768 +// boot splash color depth +#define CONFIG_BOOTSPLASH_DEPTH 16 +// boot splash VESA mode (could be generated) +#define CONFIG_BOOTSPLASH_VESA_MODE 0x117 // define it if the (emulated) hardware supports SMM mode #define CONFIG_USE_SMM 1 // Maximum number of map entries in the e820 map diff --git a/src/jpeg.c b/src/jpeg.c new file mode 100644 index 0000000..711f810 --- /dev/null +++ b/src/jpeg.c @@ -0,0 +1,1018 @@ +/* + * Copyright (C) 2001, Novell Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of Novell nor the names of the contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * a tiny jpeg decoder. + * + * written in August 2001 by Michael Schroeder mls@suse.de + * + */ + +#define __LITTLE_ENDIAN +#include "util.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/jpeg.h b/src/jpeg.h new file mode 100644 index 0000000..d55f1a7 --- /dev/null +++ b/src/jpeg.h @@ -0,0 +1,36 @@ +/* + * 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]; +}; + +extern int jpeg_decode(unsigned char *, unsigned char *, int, int, int, + struct jpeg_decdata *); +extern int jpeg_check_size(unsigned char *, int, int); + +#endif diff --git a/src/optionroms.c b/src/optionroms.c index 0b0f396..cde5b4d 100644 --- a/src/optionroms.c +++ b/src/optionroms.c @@ -449,17 +449,7 @@ vga_setup(void) return; }
- dprintf(1, "Turning on vga console\n"); - struct bregs br; - memset(&br, 0, sizeof(br)); - br.flags = F_IF; - br.ax = 0x0003; - start_preempt(); - call16_int(0x10, &br); - finish_preempt(); - - // Write to screen. - printf("Starting SeaBIOS (version %s)\n\n", VERSION); + enable_vga_console(); }
void diff --git a/src/util.h b/src/util.h index a630bc1..9f3a3f4 100644 --- a/src/util.h +++ b/src/util.h @@ -359,6 +359,10 @@ void vga_setup(void); void s3_resume_vga_init(void); extern u32 RomEnd;
+// bootsplash.c +void enable_vga_console(void); +void disable_bootsplash(void); + // resume.c void init_dma(void);
On Sat, Jun 19, 2010 at 12:31:03PM -0400, Kevin O'Connor wrote:
On Mon, Jun 14, 2010 at 12:15:45PM +0200, Stefan Reinauer wrote:
This version of the bootsplash patch should have all urgent issues resolved. Especially the license issue has been clarified. Michael Schroeder relicensed the code to the GPL compatible 3 clause BSD license; I updated the headers accordingly.
It still requires 18k of BSS for the JPEG code, but that's good for a later patch.
Stefan
I think it needs a couple of minor changes. How about the attached?
FYI - the modified patch was committed (commit afbed1bd).
-Kevin
On Mon, Jun 14, 2010 at 10:21:43AM +0200, Stefan Reinauer wrote:
On 6/14/10 3:07 AM, Kevin O'Connor wrote:
The changes to ulzma wont work. The malloc_X calls only work in POST, however ulzma can be called during boot (when seabios boots a payload). As far as I can tell it shouldn't be necessary though. SeaBIOS has a 24K stack (at 0x7000) for the "main thread" during both post and boot (each "thread" only has a 4K stack, but no thread calls ulzma).
ulzma may take more than those 15kb, and the code is theoretically able to find out how much it needs... Is there a malloc that could be used here?
Unfortunately - no. Even if we implemented another way to grab memory, it could conflict with the location that the payload is deployed at (currently, the code assumes the payload wont be placed over the e/f segment or below 0x7000).
Is there some documentation on what each malloc version does? It's quite confusing for beginners :-)
Bah - real men use 10 different memory allocators!
There are 5 memory zones - tmplow, low, fseg, tmphigh, and high. Each of these has its own non-overlapping memory space. All allocations to these spaces are done through the pmm_malloc() call - but a number of wrappers (eg, malloc_tmphigh, memalign_high) are implemented to make the code more readable. The "pmm" in pmm_malloc stands for POST Memory Manager (a BIOS standard) - the call is only available during the POST phase of SeaBIOS.
The main reason for the different zones is to handle the different memory models that the BIOS must support (16 bit real mode, 16 bit "big real" mode, 16 bit protected mode, and 32 bit segmented mode). Each of these modes has restrictions on what and how memory can be accessed. Also, a further complication is that the BIOS standards call for some memory between 0xc0000-0x100000 to be marked as read-only after POST.
The tmplow zone is for allocations under 1Meg (available by real mode code) and is reserved only during the POST phase. This zone is actually zero'd at the end of POST.
The low zone is for allocations under 1Meg (available by real mode code) that is reserved after POST - the memory is no longer available for OS use. It's useful for scratch space needed by device drivers that support real-mode calls - the memory returned is read/writable even after POST.
The fseg zone is for allocations in the f-segment. This zone is useful for bios tables that need to be located in the f-segment. It is also useful for BIOS data (eg, drive descriptions) because the data can be reliably and efficiently accessed with the GET_GLOBALFLAT() macro (which is available in all calling modes). However, the f-segment is nominally made read-only at the end of POST, so it can't be used for variables needed at runtime.
The tmphigh zone is for allocations above 1Meg and is reserved only during the POST phase. Use of memory obtained here after POST is risky - it certainly can't be used by the BIOS after an OS starts.
The high zone is for allocations above 1Meg that are reserved from the OS. Currently, SeaBIOS places this zone at the very top of available 32bit memory. The memory is read/writable and available to device drivers. However, since no memory mode calling convention (except "big real" mode, which is unused after POST) supports access to this memory, it is really only useful for DMA scratch areas and for some BIOS tables.
Space from these zones (all except fseg) can also be allocated by option roms if they invoke the PMM interface.
There are a few other memory areas that don't have malloc calls - the bda (0-0x1000), the ebda, and the option rom space (0xc0000-0xf0000). The bda is rife with legacy programs assuming a certain layout, and so can't really be used for dynamic allocations. The ebda is very similar to the "low zone", but it can be relocated which makes it difficult to use (on the up side, it has a better chance of being available during 16bit protected mode calls). Finally, the option rom space is also very similar to the "low zone", but part of the space (those used by option roms) is nominally marked read-only after POST.
Anyway, this would probably make a good wiki page.
-Kevin