--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * initvesa.c
+ *
+ * Query the VESA BIOS and select a 640x480x32 mode with local mapping
+ * support, if one exists.
+ */
+
+#include <inttypes.h>
+#include <com32.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "vesa.h"
+#include "mboot.h"
+
+struct vesa_info vesa_info;
+
+void set_graphics_mode(const struct multiboot_header *mbh,
+ struct multiboot_info *mbi)
+{
+ com32sys_t rm;
+ uint16_t mode, bestmode, *mode_ptr;
+ struct vesa_general_info *gi;
+ struct vesa_mode_info *mi;
+ int pxf, bestpxf;
+ int wantx, wanty;
+ int err, besterr;
+ bool better;
+ addr_t viaddr;
+
+ /* Only do this if requested by the OS image */
+ if (!(mbh->flags & MULTIBOOT_VIDEO_MODE) || mbh->mode_type != 0)
+ return;
+
+ /* Allocate space in the bounce buffer for these structures */
+ gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
+ mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+
+ memset(&rm, 0, sizeof rm);
+ memset(gi, 0, sizeof *gi);
+
+ gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
+ rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
+ rm.edi.w[0] = OFFS(gi);
+ rm.es = SEG(gi);
+ __intcall(0x10, &rm, &rm);
+
+ if (rm.eax.w[0] != 0x004F)
+ return; /* Function call failed */
+ if (gi->signature != VESA_MAGIC)
+ return; /* No magic */
+ if (gi->version < 0x0102)
+ return; /* VESA 1.2+ required */
+
+ memcpy(&vesa_info.gi, gi, sizeof *gi);
+
+ /* Search for a suitable mode with a suitable color and memory model... */
+
+ mode_ptr = GET_PTR(gi->video_mode_ptr);
+ bestmode = 0;
+ bestpxf = 0;
+ wantx = mbh->width ? mbh->width : 0xffff;
+ wanty = mbh->height ? mbh->height : 0xffff;
+ besterr = wantx + wanty;
+
+ while ((mode = *mode_ptr++) != 0xFFFF) {
+ mode &= 0x1FF; /* The rest are attributes of sorts */
+
+ memset(mi, 0, sizeof *mi);
+ rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */
+ rm.ecx.w[0] = mode;
+ rm.edi.w[0] = OFFS(mi);
+ rm.es = SEG(mi);
+ __intcall(0x10, &rm, &rm);
+
+ /* Must be a supported mode */
+ if (rm.eax.w[0] != 0x004f)
+ continue;
+
+ /* Must be an LFB color graphics mode supported by the hardware.
+
+ The bits tested are:
+ 7 - linear frame buffer
+ 4 - graphics mode
+ 3 - color mode
+ 1 - mode information available (mandatory in VBE 1.2+)
+ 0 - mode supported by hardware
+ */
+ if ((mi->mode_attr & 0x009b) != 0x009b)
+ continue;
+
+ /* We don't support multibank (interlaced memory) modes */
+ /*
+ * Note: The Bochs VESA BIOS (vbe.c 1.58 2006/08/19) violates the
+ * specification which states that banks == 1 for unbanked modes;
+ * fortunately it does report bank_size == 0 for those.
+ */
+ if (mi->banks > 1 && mi->bank_size)
+ continue;
+
+ /* Must either be a packed-pixel mode or a direct color mode
+ (depending on VESA version ); must be a supported pixel format */
+ pxf = 0; /* Not usable */
+
+ if (mi->bpp == 32 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
+ mi->bpos == 0)))
+ pxf = 32;
+ else if (mi->bpp == 24 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
+ mi->bpos == 0)))
+ pxf = 24;
+ else if (mi->bpp == 16 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 11 && mi->gpos == 5 &&
+ mi->bpos == 0)))
+ pxf = 16;
+ else if (mi->bpp == 15 &&
+ (mi->memory_layout == 4 ||
+ (mi->memory_layout == 6 && mi->rpos == 10 && mi->gpos == 5 &&
+ mi->bpos == 0)))
+ pxf = 15;
+
+ better = false;
+
+ err = abs(mi->h_res - wantx) + abs(mi->v_res - wanty);
+
+ if (!bestpxf)
+ better = true;
+ else if ((vesa_info.mi.h_res < wantx || vesa_info.mi.v_res < wantx) &&
+ mi->h_res >= wantx && mi->v_res >= wanty)
+ /* This matches criteria, which the previous one didn't */
+ better = true;
+ else if (err < besterr)
+ better = true;
+ else if (err == besterr && (pxf == (int)mbh->depth || pxf > bestpxf))
+ better = true;
+
+ if (better) {
+ bestmode = mode;
+ bestpxf = pxf;
+ memcpy(&vesa_info.mi, mi, sizeof *mi);
+ }
+ }
+
+ if (!bestpxf)
+ return; /* No mode found */
+
+ mi = &vesa_info.mi;
+ mode = bestmode;
+
+ /* Now set video mode */
+ rm.eax.w[0] = 0x4F02; /* Set SVGA video mode */
+ mode |= 0x4000; /* Request linear framebuffer */
+ rm.ebx.w[0] = mode;
+ __intcall(0x10, &rm, &rm);
+ if (rm.eax.w[0] != 0x004F)
+ return; /* Failed to set mode */
+
+ mbi->flags |= MB_INFO_VIDEO_INFO;
+ mbi->vbe_mode = mode;
+ viaddr = map_data(&vesa_info, sizeof vesa_info, 4, 0);
+ mbi->vbe_control_info = viaddr + offsetof(struct vesa_info, gi);
+ mbi->vbe_mode_info = viaddr + offsetof(struct vesa_info, mi);
+
+ /* Get the VBE 2.x PM entry point if supported */
+ rm.eax.w[0] = 0x4F0A;
+ rm.ebx.w[0] = 0;
+ __intcall(0x10, &rm, &rm);
+ if (rm.eax.w[0] == 0x004F) {
+ mbi->vbe_interface_seg = rm.es;
+ mbi->vbe_interface_off = rm.edi.w[0];
+ mbi->vbe_interface_len = rm.ecx.w[0];
+ }
+
+ /* Tell syslinux we changed video mode */
+ rm.eax.w[0] = 0x0017; /* Report video mode change */
+ /* In theory this should be:
+
+ rm.ebx.w[0] = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
+
+ However, that would assume all systems that claim to handle text
+ output in VESA modes actually do that... */
+ rm.ebx.w[0] = 0x000f;
+ rm.ecx.w[0] = vesa_info.mi.h_res;
+ rm.edx.w[0] = vesa_info.mi.v_res;
+ __intcall(0x22, &rm, NULL);
+}
static struct syslinux_movelist *ml = NULL;
static struct syslinux_memmap *mmap = NULL, *amap = NULL;
-static struct multiboot_header *mbh;
static addr_t mboot_high_water_mark = 0x100000;
/*
return 0;
}
-int map_image(void *ptr, size_t len)
+struct multiboot_header *map_image(void *ptr, size_t len)
{
+ struct multiboot_header *mbh;
int mbh_len;
char *cptr = ptr;
Elf32_Ehdr *eh = ptr;
}
if (mbh_len) {
- bad_flags = mbh->flags & (MULTIBOOT_UNSUPPORTED | MULTIBOOT_VIDEO_MODE);
+ bad_flags = mbh->flags & MULTIBOOT_UNSUPPORTED;
if (bad_flags) {
printf("Unsupported Multiboot flags set: %#x\n", bad_flags);
- return -1;
+ return NULL;
}
}
printf
("Memory segment at 0x%08x (len 0x%08x) is unavailable\n",
addr, msize);
- return -1; /* Memory region unavailable */
+ return NULL; /* Memory region unavailable */
}
/* Mark this region as allocated in the available map */
if (syslinux_add_memmap(&amap, addr, msize, SMT_ALLOC)) {
error("Overlapping segments found in ELF header\n");
- return -1;
+ return NULL;
}
if (ph->p_filesz) {
if (syslinux_add_movelist
(&ml, addr, (addr_t) cptr + ph->p_offset, dsize)) {
error("Failed to map PHDR data\n");
- return -1;
+ return NULL;
}
}
if (msize > dsize) {
if (syslinux_add_memmap
(&mmap, addr + dsize, msize - dsize, SMT_ZERO)) {
error("Failed to map PHDR zero region\n");
- return -1;
+ return NULL;
}
}
if (addr + msize > mboot_high_water_mark)
addr = map_data(sh, len, 4096, MAP_HIGH | MAP_NOPAD);
if (!addr) {
error("Failed to map symbol table\n");
- return -1;
+ return NULL;
}
mbinfo.flags |= MB_INFO_ELF_SHDR;
align, MAP_HIGH);
if (!addr) {
error("Failed to map symbol section\n");
- return -1;
+ return NULL;
}
sh[i].sh_addr = addr;
}
!= SMT_FREE) {
printf("Memory segment at 0x%08x (len 0x%08x) is unavailable\n",
mbh->load_addr, data_len + bss_len);
- return -1; /* Memory region unavailable */
+ return NULL; /* Memory region unavailable */
}
if (syslinux_add_memmap(&amap, mbh->load_addr,
data_len + bss_len, SMT_ALLOC)) {
error("Failed to claim a.out address space!\n");
- return -1;
+ return NULL;
}
if (data_len)
if (syslinux_add_movelist(&ml, mbh->load_addr, (addr_t) data_ptr,
data_len)) {
error("Failed to map a.out data\n");
- return -1;
+ return NULL;
}
if (bss_len)
if (syslinux_add_memmap
(&mmap, mbh->load_end_addr, bss_len, SMT_ZERO)) {
error("Failed to map a.out bss\n");
- return -1;
+ return NULL;
}
if (mbh->bss_end_addr > mboot_high_water_mark)
mboot_high_water_mark = mbh->bss_end_addr;
} else {
error
("Invalid Multiboot image: neither ELF header nor a.out kludge found\n");
- return -1;
+ return NULL;
}
- return 0;
+ return mbh;
}
/*
--- /dev/null
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef LIB_SYS_VESA_H
+#define LIB_SYS_VESA_H
+
+#include <inttypes.h>
+#include <com32.h>
+
+/* VESA General Information table */
+struct vesa_general_info {
+ uint32_t signature; /* Magic number = "VESA" */
+ uint16_t version;
+ far_ptr_t vendor_string;
+ uint8_t capabilities[4];
+ far_ptr_t video_mode_ptr;
+ uint16_t total_memory;
+
+ uint16_t oem_software_rev;
+ far_ptr_t oem_vendor_name_ptr;
+ far_ptr_t oem_product_name_ptr;
+ far_ptr_t oem_product_rev_ptr;
+
+ uint8_t reserved[222];
+ uint8_t oem_data[256];
+} __attribute__ ((packed));
+
+#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24))
+#define VBE2_MAGIC ('V' + ('B' << 8) + ('E' << 16) + ('2' << 24))
+
+struct vesa_mode_info {
+ uint16_t mode_attr;
+ uint8_t win_attr[2];
+ uint16_t win_grain;
+ uint16_t win_size;
+ uint16_t win_seg[2];
+ far_ptr_t win_scheme;
+ uint16_t logical_scan;
+
+ uint16_t h_res;
+ uint16_t v_res;
+ uint8_t char_width;
+ uint8_t char_height;
+ uint8_t memory_planes;
+ uint8_t bpp;
+ uint8_t banks;
+ uint8_t memory_layout;
+ uint8_t bank_size;
+ uint8_t image_pages;
+ uint8_t page_function;
+
+ uint8_t rmask;
+ uint8_t rpos;
+ uint8_t gmask;
+ uint8_t gpos;
+ uint8_t bmask;
+ uint8_t bpos;
+ uint8_t resv_mask;
+ uint8_t resv_pos;
+ uint8_t dcm_info;
+
+ uint8_t *lfb_ptr; /* Linear frame buffer address */
+ uint8_t *offscreen_ptr; /* Offscreen memory address */
+ uint16_t offscreen_size;
+
+ uint8_t reserved[206];
+} __attribute__ ((packed));
+
+struct vesa_info {
+ struct vesa_general_info gi;
+ struct vesa_mode_info mi;
+};
+
+extern struct vesa_info vesa_info;
+
+#endif /* LIB_SYS_VESA_H */