blob: 9c33b805de10e73a6541797b2aa64beb40f18c3c [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
Wayne Xia5042ca52011-07-08 11:02:09 +080015#include "bmp.h"
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
Wayne Xia5042ca52011-07-08 11:02:09 +0800112 , int width, int height, int bpp_req)
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400113{
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;
Wayne Xia5042ca52011-07-08 11:02:09 +0800138 if (bpp_req == 0) {
139 if (depth != 16 && depth != 24 && depth != 32)
140 continue;
141 } else {
142 if (depth != bpp_req)
143 continue;
144 }
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400145 return videomode;
146 }
147}
148
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400149static int BootsplashActive;
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400150
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400151void
152enable_bootsplash(void)
153{
Kevin O'Connorc8e4e882010-07-30 18:53:10 -0400154 if (!CONFIG_BOOTSPLASH)
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400155 return;
Wayne Xia5042ca52011-07-08 11:02:09 +0800156 /* splash picture can be bmp or jpeg file */
Kevin O'Connoreb6dc782010-08-03 20:58:43 -0400157 dprintf(3, "Checking for bootsplash\n");
Wayne Xia5042ca52011-07-08 11:02:09 +0800158 u8 type = 0; /* 0 means jpg, 1 means bmp, default is 0=jpg */
Kevin O'Connorf9b09302010-12-24 11:15:26 -0500159 int filesize;
160 u8 *filedata = romfile_loadfile("bootsplash.jpg", &filesize);
Wayne Xia5042ca52011-07-08 11:02:09 +0800161 if (!filedata) {
162 filedata = romfile_loadfile("bootsplash.bmp", &filesize);
163 if (!filedata)
164 return;
165 type = 1;
166 }
167 dprintf(3, "start showing bootsplash\n");
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400168
Wayne Xia5042ca52011-07-08 11:02:09 +0800169 u8 *picture = NULL; /* data buff used to be flushed to the video buf */
170 struct jpeg_decdata *jpeg = NULL;
171 struct bmp_decdata *bmp = NULL;
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400172 struct vesa_info *vesa_info = malloc_tmplow(sizeof(*vesa_info));
173 struct vesa_mode_info *mode_info = malloc_tmplow(sizeof(*mode_info));
Wayne Xia5042ca52011-07-08 11:02:09 +0800174 if (!vesa_info || !mode_info) {
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400175 warn_noalloc();
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400176 goto done;
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400177 }
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400178
179 /* Check whether we have a VESA 2.0 compliant BIOS */
180 memset(vesa_info, 0, sizeof(struct vesa_info));
Kevin O'Connor0e27e192010-07-27 00:00:53 -0400181 vesa_info->vesa_signature = VBE2_SIGNATURE;
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400182 struct bregs br;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400183 memset(&br, 0, sizeof(br));
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400184 br.ax = 0x4f00;
185 br.di = FLATPTR_TO_OFFSET(vesa_info);
186 br.es = FLATPTR_TO_SEG(vesa_info);
Kevin O'Connor26411862010-07-26 23:25:39 -0400187 call16_int10(&br);
Kevin O'Connor0e27e192010-07-27 00:00:53 -0400188 if (vesa_info->vesa_signature != VESA_SIGNATURE) {
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400189 dprintf(1,"No VBE2 found.\n");
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400190 goto done;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400191 }
192
193 /* Print some debugging information about our card. */
Kevin O'Connora576c9c2010-07-26 22:43:18 -0400194 char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_name_ptr);
195 char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_name_ptr);
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400196 dprintf(3, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n",
Kevin O'Connora576c9c2010-07-26 22:43:18 -0400197 vesa_info->vesa_version>>8, vesa_info->vesa_version&0xff,
198 vendor, product);
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400199
Wayne Xia5042ca52011-07-08 11:02:09 +0800200 int ret, width, height;
201 int bpp_require = 0;
202 if (type == 0) {
203 jpeg = jpeg_alloc();
204 if (!jpeg) {
205 warn_noalloc();
206 goto done;
207 }
208 /* Parse jpeg and get image size. */
209 dprintf(5, "Decoding bootsplash.jpg\n");
210 ret = jpeg_decode(jpeg, filedata);
211 if (ret) {
212 dprintf(1, "jpeg_decode failed with return code %d...\n", ret);
213 goto done;
214 }
215 jpeg_get_size(jpeg, &width, &height);
216 } else {
217 bmp = bmp_alloc();
218 if (!bmp) {
219 warn_noalloc();
220 goto done;
221 }
222 /* Parse bmp and get image size. */
223 dprintf(5, "Decoding bootsplash.bmp\n");
224 ret = bmp_decode(bmp, filedata, filesize);
225 if (ret) {
226 dprintf(1, "bmp_decode failed with return code %d...\n", ret);
227 goto done;
228 }
229 bmp_get_size(bmp, &width, &height);
230 bpp_require = 24;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400231 }
Wayne Xia5042ca52011-07-08 11:02:09 +0800232 /* jpeg would use 16 or 24 bpp video mode, BMP use 24bpp mode only */
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400233
234 // Try to find a graphics mode with the corresponding dimensions.
Wayne Xia5042ca52011-07-08 11:02:09 +0800235 int videomode = find_videomode(vesa_info, mode_info, width, height,
236 bpp_require);
237 if (videomode < 0) {
238 dprintf(1, "failed to find a videomode with %dx%d %dbpp (0=any).\n",
239 width, height, bpp_require);
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400240 goto done;
Wayne Xia5042ca52011-07-08 11:02:09 +0800241 }
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400242 void *framebuffer = mode_info->phys_base_ptr;
243 int depth = mode_info->bits_per_pixel;
244 dprintf(3, "mode: %04x\n", videomode);
245 dprintf(3, "framebuffer: %p\n", framebuffer);
246 dprintf(3, "bytes per scanline: %d\n", mode_info->bytes_per_scanline);
247 dprintf(3, "bits per pixel: %d\n", depth);
248
249 // Allocate space for image and decompress it.
Wayne Xia5042ca52011-07-08 11:02:09 +0800250 int imagesize = height * mode_info->bytes_per_scanline;
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400251 picture = malloc_tmphigh(imagesize);
252 if (!picture) {
253 warn_noalloc();
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400254 goto done;
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400255 }
Wayne Xia5042ca52011-07-08 11:02:09 +0800256
257 if (type == 0) {
258 dprintf(5, "Decompressing bootsplash.jpg\n");
Wayne Xia8031efa2011-07-08 11:03:16 +0800259 ret = jpeg_show(jpeg, picture, width, height, depth,
260 mode_info->bytes_per_scanline);
Wayne Xia5042ca52011-07-08 11:02:09 +0800261 if (ret) {
262 dprintf(1, "jpeg_show failed with return code %d...\n", ret);
263 goto done;
264 }
265 } else {
266 dprintf(5, "Decompressing bootsplash.bmp\n");
267 ret = bmp_show(bmp, picture, width, height, depth,
268 mode_info->bytes_per_scanline);
269 if (ret) {
270 dprintf(1, "bmp_show failed with return code %d...\n", ret);
271 goto done;
272 }
Kevin O'Connorbbc47222010-07-30 13:07:08 -0400273 }
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400274
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400275 /* Switch to graphics mode */
Kevin O'Connoreb6dc782010-08-03 20:58:43 -0400276 dprintf(5, "Switching to graphics mode\n");
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400277 memset(&br, 0, sizeof(br));
278 br.ax = 0x4f02;
279 br.bx = (1 << 14) | videomode;
280 call16_int10(&br);
281 if (br.ax != 0x4f) {
282 dprintf(1, "set_mode failed.\n");
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400283 goto done;
Kevin O'Connor8d85eb12010-07-30 14:07:03 -0400284 }
285
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400286 /* Show the picture */
Wayne Xia5042ca52011-07-08 11:02:09 +0800287 dprintf(5, "Showing bootsplash picture\n");
Kevin O'Connor6dc76f42010-07-26 23:16:12 -0400288 iomemcpy(framebuffer, picture, imagesize);
Kevin O'Connoreb6dc782010-08-03 20:58:43 -0400289 dprintf(5, "Bootsplash copy complete\n");
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400290 BootsplashActive = 1;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400291
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400292done:
Kevin O'Connorb2b9d4a2010-07-30 13:25:21 -0400293 free(filedata);
Kevin O'Connor6dc76f42010-07-26 23:16:12 -0400294 free(picture);
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400295 free(vesa_info);
296 free(mode_info);
Kevin O'Connorb2b9d4a2010-07-30 13:25:21 -0400297 free(jpeg);
Wayne Xia5042ca52011-07-08 11:02:09 +0800298 free(bmp);
Kevin O'Connor227dc3e2010-07-26 23:02:26 -0400299 return;
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400300}
301
302void
303disable_bootsplash(void)
304{
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400305 if (!CONFIG_BOOTSPLASH || !BootsplashActive)
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400306 return;
Kevin O'Connor9a01a9c2010-08-25 21:07:48 -0400307 BootsplashActive = 0;
308 enable_vga_console();
Kevin O'Connorafbed1b2010-06-28 07:34:53 -0400309}