6302133e7e5ddd6d99ce94b0c42a6f9eb5294614
[seabios.git] / src / bootsplash.c
1 // Option rom scanning code.
2 //
3 // Copyright (C) 2009-2010  coresystems GmbH
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "bregs.h" // struct bregs
8 #include "farptr.h" // FLATPTR_TO_SEG
9 #include "config.h" // CONFIG_*
10 #include "util.h" // dprintf
11 #include "jpeg.h" // splash
12
13 /****************************************************************
14  * Definitions
15  ****************************************************************/
16
17 /****************************************************************
18  * VESA structures
19  ****************************************************************/
20
21 struct vesa_info
22 {
23     u8 vesa_signature[4];
24     u16 vesa_version;
25     struct segoff_s oem_string_ptr;
26     u8 capabilities[4];
27     struct segoff_s video_mode_ptr;
28     u16 total_memory;
29     u16 oem_software_rev;
30     struct segoff_s oem_vendor_name_ptr;
31     struct segoff_s oem_product_name_ptr;
32     struct segoff_s oem_product_rev_ptr;
33     u8 reserved[222];
34     u8 oem_data[256];
35 } PACKED;
36
37 struct vesa_mode_info
38 {
39     u16 mode_attributes;
40     u8 win_a_attributes;
41     u8 win_b_attributes;
42     u16 win_granularity;
43     u16 win_size;
44     u16 win_a_segment;
45     u16 win_b_segment;
46     u32 win_func_ptr;
47     u16 bytes_per_scanline;
48     u16 x_resolution;
49     u16 y_resolution;
50     u8 x_charsize;
51     u8 y_charsize;
52     u8 number_of_planes;
53     u8 bits_per_pixel;
54     u8 number_of_banks;
55     u8 memory_model;
56     u8 bank_size;
57     u8 number_of_image_pages;
58     u8 reserved_page;
59     u8 red_mask_size;
60     u8 red_mask_pos;
61     u8 green_mask_size;
62     u8 green_mask_pos;
63     u8 blue_mask_size;
64     u8 blue_mask_pos;
65     u8 reserved_mask_size;
66     u8 reserved_mask_pos;
67     u8 direct_color_mode_info;
68     u32 phys_base_ptr;
69     u32 offscreen_mem_offset;
70     u16 offscreen_mem_size;
71     u8 reserved[206];
72 } PACKED;
73
74 /****************************************************************
75  * Helper functions
76  ****************************************************************/
77
78 /****************************************************************
79  * VGA text / graphics console
80  ****************************************************************/
81 static void enable_vga_text_console(void)
82 {
83     dprintf(1, "Turning on vga text mode console\n");
84     struct bregs br;
85
86     /* Enable VGA text mode */
87     memset(&br, 0, sizeof(br));
88     br.flags = F_IF;
89     br.ax = 0x0003;
90     start_preempt();
91     call16_int(0x10, &br);
92     finish_preempt();
93
94     if (CONFIG_BOOTSPLASH) {
95         /* Switch back to start of the framebuffer
96          * (disable "double buffering")
97          */
98         memset(&br, 0, sizeof(br));
99         br.flags = F_IF;
100         br.ax = 0x4f07;
101         br.bl = 0x02;
102         br.ecx = 0;
103
104         start_preempt();
105         call16_int(0x10, &br);
106         finish_preempt();
107     }
108
109     // Write to screen.
110     printf("Starting SeaBIOS (version %s)\n\n", VERSION);
111 }
112
113 void enable_vga_console(void)
114 {
115     /* Needs coreboot support for CBFS */
116     if (!CONFIG_BOOTSPLASH || !CONFIG_COREBOOT) {
117         enable_vga_text_console();
118         return;
119     }
120
121     struct bregs br;
122     struct vesa_info *vesa_info;
123     struct vesa_mode_info *mode_info;
124     struct jpeg_decdata *decdata;
125
126     vesa_info = malloc_tmplow(sizeof(*vesa_info));
127     mode_info = malloc_tmplow(sizeof(*mode_info));
128     decdata = malloc_tmphigh(sizeof(*decdata));
129
130     /* Check whether we have a VESA 2.0 compliant BIOS */
131     memset(vesa_info, 0, sizeof(struct vesa_info));
132     memcpy(vesa_info, "VBE2", 4);
133
134     memset(&br, 0, sizeof(br));
135     br.flags = F_IF;
136     br.ax = 0x4f00;
137     br.di = FLATPTR_TO_OFFSET(vesa_info);
138     br.es = FLATPTR_TO_SEG(vesa_info);
139     start_preempt();
140     call16_int(0x10, &br);
141     finish_preempt();
142
143     if(strcmp("VESA", (char *)vesa_info) != 0) {
144         dprintf(1,"No VBE2 found.\n");
145         goto cleanup;
146     }
147
148     /* Print some debugging information about our card. */
149     char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_name_ptr);
150     char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_name_ptr);
151
152     dprintf(8, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n",
153             vesa_info->vesa_version>>8, vesa_info->vesa_version&0xff,
154             vendor, product);
155
156     /* Get information about our graphics mode, like the
157      * framebuffer start address
158      */
159     memset(&br, 0, sizeof(br));
160     br.flags = F_IF;
161     br.ax = 0x4f01;
162     br.cx = (1 << 14) | CONFIG_BOOTSPLASH_VESA_MODE;
163     br.di = FLATPTR_TO_OFFSET(mode_info);
164     br.es = FLATPTR_TO_SEG(mode_info);
165     start_preempt();
166     call16_int(0x10, &br);
167     finish_preempt();
168     if (br.ax != 0x4f) {
169         dprintf(1, "get_mode failed.\n");
170         enable_vga_text_console();
171         goto cleanup;
172     }
173     unsigned char *framebuffer = (unsigned char *) (mode_info->phys_base_ptr);
174
175     /* Switch to graphics mode */
176     memset(&br, 0, sizeof(br));
177     br.flags = F_IF;
178     br.ax = 0x4f02;
179     br.bx = (1 << 14) | CONFIG_BOOTSPLASH_VESA_MODE;
180     start_preempt();
181     call16_int(0x10, &br);
182     finish_preempt();
183     if (br.ax != 0x4f) {
184         dprintf(1, "set_mode failed.\n");
185         enable_vga_text_console();
186         goto cleanup;
187     }
188
189     /* Switching Intel IGD to 1MB video memory will break this. Who cares. */
190     int imagesize = CONFIG_BOOTSPLASH_X * CONFIG_BOOTSPLASH_Y *
191                         (CONFIG_BOOTSPLASH_DEPTH / 8);
192
193     /* We use "double buffering" to make things look nicer */
194     framebuffer += imagesize;
195
196     dprintf(8, "framebuffer: %x\n", (u32)framebuffer);
197     dprintf(8, "bytes per scanline: %d\n", mode_info->bytes_per_scanline);
198     dprintf(8, "bits per pixel: %d\n", mode_info->bits_per_pixel);
199
200     /* Look for bootsplash.jpg in CBFS and decompress it... */
201     int ret = 0;
202     unsigned char *jpeg = NULL;
203
204     struct cbfs_file *file = cbfs_finddatafile("bootsplash.jpg");
205     int filesize = 0;
206
207     if (file) {
208         filesize = cbfs_datasize(file);
209         jpeg = malloc_tmphigh(filesize);
210     } else {
211         dprintf(1, "Could not find boot splash screen \"bootsplash.jpg\"\n");
212     }
213     if(jpeg) {
214         dprintf(8, "Copying boot splash screen...\n");
215         cbfs_copyfile(file, jpeg, filesize);
216         dprintf(8, "Decompressing boot splash screen...\n");
217         ret = jpeg_decode(jpeg, framebuffer, CONFIG_BOOTSPLASH_X,
218                           CONFIG_BOOTSPLASH_Y, CONFIG_BOOTSPLASH_DEPTH, decdata);
219         if (ret)
220             dprintf(1, "Failed with return code %d...\n", ret);
221     } else {
222         ret = -1;
223     }
224     free(jpeg);
225     if (ret) {
226         enable_vga_text_console();
227         goto cleanup;
228     }
229
230     /* Show the picture */
231     memset(&br, 0, sizeof(br));
232     br.flags = F_IF;
233     br.ax = 0x4f07;
234     br.bl = 0x02;
235     br.ecx = imagesize;
236     start_preempt();
237     call16_int(0x10, &br);
238     finish_preempt();
239     if (br.ax != 0x4f) {
240         dprintf(1, "display_start failed (ax=%04x).\n", br.ax);
241         enable_vga_text_console();
242     }
243
244 cleanup:
245     free (vesa_info);
246     free (mode_info);
247     free (decdata);
248 }
249
250 void
251 disable_bootsplash(void)
252 {
253     if (! CONFIG_BOOTSPLASH)
254         return;
255     enable_vga_text_console();
256 }