Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / seabios / src / bootsplash.c
1 // Initialize the VGA console and possibly show a boot splash image.
2 //
3 // Copyright (C) 2009-2010  coresystems GmbH
4 // Copyright (C) 2010  Kevin O'Connor <kevin@koconnor.net>
5 //
6 // This file may be distributed under the terms of the GNU LGPLv3 license.
7
8 #include "bregs.h" // struct bregs
9 #include "config.h" // CONFIG_*
10 #include "farptr.h" // FLATPTR_TO_SEG
11 #include "malloc.h" // free
12 #include "output.h" // dprintf
13 #include "romfile.h" // romfile_loadfile
14 #include "stacks.h" // call16_int
15 #include "std/vbe.h" // struct vbe_info
16 #include "string.h" // memset
17 #include "util.h" // enable_bootsplash
18
19
20 /****************************************************************
21  * Helper functions
22  ****************************************************************/
23
24 // Call int10 vga handler.
25 static void
26 call16_int10(struct bregs *br)
27 {
28     br->flags = F_IF;
29     start_preempt();
30     call16_int(0x10, br);
31     finish_preempt();
32 }
33
34
35 /****************************************************************
36  * VGA text / graphics console
37  ****************************************************************/
38
39 void
40 enable_vga_console(void)
41 {
42     dprintf(1, "Turning on vga text mode console\n");
43     struct bregs br;
44
45     /* Enable VGA text mode */
46     memset(&br, 0, sizeof(br));
47     br.ax = 0x0003;
48     call16_int10(&br);
49
50     // Write to screen.
51     printf("SeaBIOS (version %s)\n", VERSION);
52     display_uuid();
53 }
54
55 static int
56 find_videomode(struct vbe_info *vesa_info, struct vbe_mode_info *mode_info
57                , int width, int height, int bpp_req)
58 {
59     dprintf(3, "Finding vesa mode with dimensions %d/%d\n", width, height);
60     u16 *videomodes = SEGOFF_TO_FLATPTR(vesa_info->video_mode);
61     for (;; videomodes++) {
62         u16 videomode = *videomodes;
63         if (videomode == 0xffff) {
64             dprintf(1, "Unable to find vesa video mode dimensions %d/%d\n"
65                     , width, height);
66             return -1;
67         }
68         struct bregs br;
69         memset(&br, 0, sizeof(br));
70         br.ax = 0x4f01;
71         br.cx = videomode;
72         br.di = FLATPTR_TO_OFFSET(mode_info);
73         br.es = FLATPTR_TO_SEG(mode_info);
74         call16_int10(&br);
75         if (br.ax != 0x4f) {
76             dprintf(1, "get_mode failed.\n");
77             continue;
78         }
79         if (mode_info->xres != width
80             || mode_info->yres != height)
81             continue;
82         u8 depth = mode_info->bits_per_pixel;
83         if (bpp_req == 0) {
84             if (depth != 16 && depth != 24 && depth != 32)
85                 continue;
86         } else {
87             if (depth != bpp_req)
88                 continue;
89         }
90         return videomode;
91     }
92 }
93
94 static int BootsplashActive;
95
96 void
97 enable_bootsplash(void)
98 {
99     if (!CONFIG_BOOTSPLASH)
100         return;
101     /* splash picture can be bmp or jpeg file */
102     dprintf(3, "Checking for bootsplash\n");
103     u8 type = 0; /* 0 means jpg, 1 means bmp, default is 0=jpg */
104     int filesize;
105     u8 *filedata = romfile_loadfile("bootsplash.jpg", &filesize);
106     if (!filedata) {
107         filedata = romfile_loadfile("bootsplash.bmp", &filesize);
108         if (!filedata)
109             return;
110         type = 1;
111     }
112     dprintf(3, "start showing bootsplash\n");
113
114     u8 *picture = NULL; /* data buff used to be flushed to the video buf */
115     struct jpeg_decdata *jpeg = NULL;
116     struct bmp_decdata *bmp = NULL;
117     struct vbe_info *vesa_info = malloc_tmplow(sizeof(*vesa_info));
118     struct vbe_mode_info *mode_info = malloc_tmplow(sizeof(*mode_info));
119     if (!vesa_info || !mode_info) {
120         warn_noalloc();
121         goto done;
122     }
123
124     /* Check whether we have a VESA 2.0 compliant BIOS */
125     memset(vesa_info, 0, sizeof(struct vbe_info));
126     vesa_info->signature = VBE2_SIGNATURE;
127     struct bregs br;
128     memset(&br, 0, sizeof(br));
129     br.ax = 0x4f00;
130     br.di = FLATPTR_TO_OFFSET(vesa_info);
131     br.es = FLATPTR_TO_SEG(vesa_info);
132     call16_int10(&br);
133     if (vesa_info->signature != VESA_SIGNATURE) {
134         dprintf(1,"No VBE2 found.\n");
135         goto done;
136     }
137
138     /* Print some debugging information about our card. */
139     char *vendor = SEGOFF_TO_FLATPTR(vesa_info->oem_vendor_string);
140     char *product = SEGOFF_TO_FLATPTR(vesa_info->oem_product_string);
141     dprintf(3, "VESA %d.%d\nVENDOR: %s\nPRODUCT: %s\n",
142             vesa_info->version>>8, vesa_info->version&0xff,
143             vendor, product);
144
145     int ret, width, height;
146     int bpp_require = 0;
147     if (type == 0) {
148         jpeg = jpeg_alloc();
149         if (!jpeg) {
150             warn_noalloc();
151             goto done;
152         }
153         /* Parse jpeg and get image size. */
154         dprintf(5, "Decoding bootsplash.jpg\n");
155         ret = jpeg_decode(jpeg, filedata);
156         if (ret) {
157             dprintf(1, "jpeg_decode failed with return code %d...\n", ret);
158             goto done;
159         }
160         jpeg_get_size(jpeg, &width, &height);
161     } else {
162         bmp = bmp_alloc();
163         if (!bmp) {
164             warn_noalloc();
165             goto done;
166         }
167         /* Parse bmp and get image size. */
168         dprintf(5, "Decoding bootsplash.bmp\n");
169         ret = bmp_decode(bmp, filedata, filesize);
170         if (ret) {
171             dprintf(1, "bmp_decode failed with return code %d...\n", ret);
172             goto done;
173         }
174         bmp_get_size(bmp, &width, &height);
175         bpp_require = 24;
176     }
177     /* jpeg would use 16 or 24 bpp video mode, BMP use 24bpp mode only */
178
179     // Try to find a graphics mode with the corresponding dimensions.
180     int videomode = find_videomode(vesa_info, mode_info, width, height,
181                                        bpp_require);
182     if (videomode < 0) {
183         dprintf(1, "failed to find a videomode with %dx%d %dbpp (0=any).\n",
184                     width, height, bpp_require);
185         goto done;
186     }
187     void *framebuffer = (void *)mode_info->phys_base;
188     int depth = mode_info->bits_per_pixel;
189     dprintf(3, "mode: %04x\n", videomode);
190     dprintf(3, "framebuffer: %p\n", framebuffer);
191     dprintf(3, "bytes per scanline: %d\n", mode_info->bytes_per_scanline);
192     dprintf(3, "bits per pixel: %d\n", depth);
193
194     // Allocate space for image and decompress it.
195     int imagesize = height * mode_info->bytes_per_scanline;
196     picture = malloc_tmphigh(imagesize);
197     if (!picture) {
198         warn_noalloc();
199         goto done;
200     }
201
202     if (type == 0) {
203         dprintf(5, "Decompressing bootsplash.jpg\n");
204         ret = jpeg_show(jpeg, picture, width, height, depth,
205                             mode_info->bytes_per_scanline);
206         if (ret) {
207             dprintf(1, "jpeg_show failed with return code %d...\n", ret);
208             goto done;
209         }
210     } else {
211         dprintf(5, "Decompressing bootsplash.bmp\n");
212         ret = bmp_show(bmp, picture, width, height, depth,
213                            mode_info->bytes_per_scanline);
214         if (ret) {
215             dprintf(1, "bmp_show failed with return code %d...\n", ret);
216             goto done;
217         }
218     }
219
220     /* Switch to graphics mode */
221     dprintf(5, "Switching to graphics mode\n");
222     memset(&br, 0, sizeof(br));
223     br.ax = 0x4f02;
224     br.bx = videomode | VBE_MODE_LINEAR_FRAME_BUFFER;
225     call16_int10(&br);
226     if (br.ax != 0x4f) {
227         dprintf(1, "set_mode failed.\n");
228         goto done;
229     }
230
231     /* Show the picture */
232     dprintf(5, "Showing bootsplash picture\n");
233     iomemcpy(framebuffer, picture, imagesize);
234     dprintf(5, "Bootsplash copy complete\n");
235     BootsplashActive = 1;
236
237 done:
238     free(filedata);
239     free(picture);
240     free(vesa_info);
241     free(mode_info);
242     free(jpeg);
243     free(bmp);
244     return;
245 }
246
247 void
248 disable_bootsplash(void)
249 {
250     if (!CONFIG_BOOTSPLASH || !BootsplashActive)
251         return;
252     BootsplashActive = 0;
253     enable_vga_console();
254 }