blob: cf1a603e790fabdb9a1aba15c377c4151e8294c3 [file] [log] [blame]
Kevin O'Connorafbed1b2010-06-28 07:34:53 -04001// Option rom scanning code.
2//
3// Copyright (C) 2009-2010 coresystems GmbH
Kevin O'Connor6dc76f42010-07-26 23:16:12 -04004// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
Kevin O'Connorafbed1b2010-06-28 07:34:53 -04005//
6// This file may be distributed under the terms of the GNU LGPLv3 license.
7
8#include "bregs.h" // struct bregs
9#include "farptr.h" // FLATPTR_TO_SEG
10#include "config.h" // CONFIG_*
11#include "util.h" // dprintf
12#include "jpeg.h" // splash
Kevin O'Connorcadaf0e2010-07-26 23:47:26 -040013#include "biosvar.h" // SET_EBDA
Kevin O'Connorc8e4e882010-07-30 18:53:10 -040014#include "paravirt.h" // romfile_find
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040015
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040016
17/****************************************************************
18 * VESA structures
19 ****************************************************************/
20
Kevin O'Connorc8e4e882010-07-30 18:53:10 -040021struct vesa_info {
Kevin O'Connor0e27e192010-07-27 00:00:53 -040022 u32 vesa_signature;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040023 u16 vesa_version;
Kevin O'Connora576c9c2010-07-26 22:43:18 -040024 struct segoff_s oem_string_ptr;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040025 u8 capabilities[4];
Kevin O'Connora576c9c2010-07-26 22:43:18 -040026 struct segoff_s video_mode_ptr;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040027 u16 total_memory;
28 u16 oem_software_rev;
Kevin O'Connora576c9c2010-07-26 22:43:18 -040029 struct segoff_s oem_vendor_name_ptr;
30 struct segoff_s oem_product_name_ptr;
31 struct segoff_s oem_product_rev_ptr;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040032 u8 reserved[222];
33 u8 oem_data[256];
34} PACKED;
35
Kevin O'Connor0e27e192010-07-27 00:00:53 -040036#define VESA_SIGNATURE 0x41534556 // VESA
37#define VBE2_SIGNATURE 0x32454256 // VBE2
38
Kevin O'Connorc8e4e882010-07-30 18:53:10 -040039struct vesa_mode_info {
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040040 u16 mode_attributes;
41 u8 win_a_attributes;
42 u8 win_b_attributes;
43 u16 win_granularity;
44 u16 win_size;
45 u16 win_a_segment;
46 u16 win_b_segment;
47 u32 win_func_ptr;
48 u16 bytes_per_scanline;
49 u16 x_resolution;
50 u16 y_resolution;
51 u8 x_charsize;
52 u8 y_charsize;
53 u8 number_of_planes;
54 u8 bits_per_pixel;
55 u8 number_of_banks;
56 u8 memory_model;
57 u8 bank_size;
58 u8 number_of_image_pages;
59 u8 reserved_page;
60 u8 red_mask_size;
61 u8 red_mask_pos;
62 u8 green_mask_size;
63 u8 green_mask_pos;
64 u8 blue_mask_size;
65 u8 blue_mask_pos;
66 u8 reserved_mask_size;
67 u8 reserved_mask_pos;
68 u8 direct_color_mode_info;
Kevin O'Connor8d85eb12010-07-30 14:07:03 -040069 void *phys_base_ptr;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040070 u32 offscreen_mem_offset;
71 u16 offscreen_mem_size;
72 u8 reserved[206];
73} PACKED;
74
Kevin O'Connorc8e4e882010-07-30 18:53:10 -040075
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040076/****************************************************************
77 * Helper functions
78 ****************************************************************/
79
Kevin O'Connor26411862010-07-26 23:25:39 -040080// Call int10 vga handler.
81static void
82call16_int10(struct bregs *br)
83{
84 br->flags = F_IF;
85 start_preempt();
86 call16_int(0x10, br);
87 finish_preempt();
88}
89
90
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040091/****************************************************************
92 * VGA text / graphics console
93 ****************************************************************/
Kevin O'Connor26411862010-07-26 23:25:39 -040094
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -040095void
96enable_vga_console(void)
Kevin O'Connorafbed1b2010-06-28 07:34:53 -040097{
98 dprintf(1, "Turning on vga text mode console\n");
99 struct bregs br;
100
101 /* Enable VGA text mode */
102 memset(&br, 0, sizeof(br));
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400103 br.ax = 0x0003;
Kevin O'Connor26411862010-07-26 23:25:39 -0400104 call16_int10(&br);
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400105
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400106 // Write to screen.
Kevin O'Connorcadaf0e2010-07-26 23:47:26 -0400107 printf("SeaBIOS (version %s)\n\n", VERSION);
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400108}
109
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400110static int
111find_videomode(struct vesa_info *vesa_info, struct vesa_mode_info *mode_info
112 , int width, int height)
113{
114 dprintf(3, "Finding vesa mode with dimensions %d/%d\n", width, height);
115 u16 *videomodes = SEGOFF_TO_FLATPTR(vesa_info->video_mode_ptr);
116 for (;; videomodes++) {
117 u16 videomode = *videomodes;
118 if (videomode == 0xffff) {
119 dprintf(1, "Unable to find vesa video mode dimensions %d/%d\n"
120 , width, height);
121 return -1;
122 }
123 struct bregs br;
124 memset(&br, 0, sizeof(br));
125 br.ax = 0x4f01;
126 br.cx = (1 << 14) | videomode;
127 br.di = FLATPTR_TO_OFFSET(mode_info);
128 br.es = FLATPTR_TO_SEG(mode_info);
129 call16_int10(&br);
130 if (br.ax != 0x4f) {
131 dprintf(1, "get_mode failed.\n");
132 continue;
133 }
134 if (mode_info->x_resolution != width
135 || mode_info->y_resolution != height)
136 continue;
137 u8 depth = mode_info->bits_per_pixel;
138 if (depth != 16 && depth != 24 && depth != 32)
139 continue;
140 return videomode;
141 }
142}
143
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400144static int BootsplashActive;
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400145
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400146void
147enable_bootsplash(void)
148{
Kevin O'Connorc8e4e882010-07-30 18:53:10 -0400149 if (!CONFIG_BOOTSPLASH)
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400150 return;
Kevin O'Connoreb6dc782010-08-03 20:58:43 -0400151 dprintf(3, "Checking for bootsplash\n");
Kevin O'Connorf9b09302010-12-24 11:15:26 -0500152 int filesize;
153 u8 *filedata = romfile_loadfile("bootsplash.jpg", &filesize);
154 if (!filedata)
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400155 return;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400156
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400157 u8 *picture = NULL;
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400158 struct vesa_info *vesa_info = malloc_tmplow(sizeof(*vesa_info));
159 struct vesa_mode_info *mode_info = malloc_tmplow(sizeof(*mode_info));
160 struct jpeg_decdata *jpeg = jpeg_alloc();
Kevin O'Connorf9b09302010-12-24 11:15:26 -0500161 if (!jpeg || !vesa_info || !mode_info) {
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400162 warn_noalloc();
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400163 goto done;
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400164 }
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400165
166 /* Check whether we have a VESA 2.0 compliant BIOS */
167 memset(vesa_info, 0, sizeof(struct vesa_info));
Kevin O'Connor0e27e192010-07-27 00:00:53 -0400168 vesa_info->vesa_signature = VBE2_SIGNATURE;
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400169 struct bregs br;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400170 memset(&br, 0, sizeof(br));
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400171 br.ax = 0x4f00;
172 br.di = FLATPTR_TO_OFFSET(vesa_info);
173 br.es = FLATPTR_TO_SEG(vesa_info);
Kevin O'Connor26411862010-07-26 23:25:39 -0400174 call16_int10(&br);
Kevin O'Connor0e27e192010-07-27 00:00:53 -0400175 if (vesa_info->vesa_signature != VESA_SIGNATURE) {
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400176 dprintf(1,"No VBE2 found.\n");
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400177 goto done;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400178 }
179
180 /* Print some debugging information about our card. */
Kevin O'Connora576c9c2010-07-26 22:43:18 -0400181 char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_name_ptr);
182 char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_name_ptr);
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400183 dprintf(3, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n",
Kevin O'Connora576c9c2010-07-26 22:43:18 -0400184 vesa_info->vesa_version>>8, vesa_info->vesa_version&0xff,
185 vendor, product);
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400186
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400187 // Parse jpeg and get image size.
Kevin O'Connoreb6dc782010-08-03 20:58:43 -0400188 dprintf(5, "Decoding bootsplash.jpg\n");
Kevin O'Connorb2b9d4a2010-07-30 13:25:21 -0400189 int ret = jpeg_decode(jpeg, filedata);
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400190 if (ret) {
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400191 dprintf(1, "jpeg_decode failed with return code %d...\n", ret);
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400192 goto done;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400193 }
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400194 int width, height;
195 jpeg_get_size(jpeg, &width, &height);
196
197 // Try to find a graphics mode with the corresponding dimensions.
198 int videomode = find_videomode(vesa_info, mode_info, width, height);
199 if (videomode < 0)
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400200 goto done;
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400201 void *framebuffer = mode_info->phys_base_ptr;
202 int depth = mode_info->bits_per_pixel;
203 dprintf(3, "mode: %04x\n", videomode);
204 dprintf(3, "framebuffer: %p\n", framebuffer);
205 dprintf(3, "bytes per scanline: %d\n", mode_info->bytes_per_scanline);
206 dprintf(3, "bits per pixel: %d\n", depth);
207
208 // Allocate space for image and decompress it.
209 int imagesize = width * height * (depth / 8);
210 picture = malloc_tmphigh(imagesize);
211 if (!picture) {
212 warn_noalloc();
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400213 goto done;
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400214 }
Kevin O'Connoreb6dc782010-08-03 20:58:43 -0400215 dprintf(5, "Decompressing bootsplash.jpg\n");
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400216 ret = jpeg_show(jpeg, picture, width, height, depth);
Kevin O'Connorbbc47222010-07-30 13:07:08 -0400217 if (ret) {
218 dprintf(1, "jpeg_show failed with return code %d...\n", ret);
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400219 goto done;
Kevin O'Connorbbc47222010-07-30 13:07:08 -0400220 }
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400221
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400222 /* Switch to graphics mode */
Kevin O'Connoreb6dc782010-08-03 20:58:43 -0400223 dprintf(5, "Switching to graphics mode\n");
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400224 memset(&br, 0, sizeof(br));
225 br.ax = 0x4f02;
226 br.bx = (1 << 14) | videomode;
227 call16_int10(&br);
228 if (br.ax != 0x4f) {
229 dprintf(1, "set_mode failed.\n");
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400230 goto done;
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400231 }
232
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400233 /* Show the picture */
Kevin O'Connoreb6dc782010-08-03 20:58:43 -0400234 dprintf(5, "Showing bootsplash.jpg\n");
Kevin O'Connor6dc76f42010-07-26 23:16:12 -0400235 iomemcpy(framebuffer, picture, imagesize);
Kevin O'Connoreb6dc782010-08-03 20:58:43 -0400236 dprintf(5, "Bootsplash copy complete\n");
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400237 BootsplashActive = 1;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400238
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400239done:
Kevin O'Connorb2b9d4a2010-07-30 13:25:21 -0400240 free(filedata);
Kevin O'Connor6dc76f42010-07-26 23:16:12 -0400241 free(picture);
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400242 free(vesa_info);
243 free(mode_info);
Kevin O'Connorb2b9d4a2010-07-30 13:25:21 -0400244 free(jpeg);
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400245 return;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400246}
247
248void
249disable_bootsplash(void)
250{
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400251 if (!CONFIG_BOOTSPLASH || !BootsplashActive)
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400252 return;
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400253 BootsplashActive = 0;
254 enable_vga_console();
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400255}