debuggers.hg

view xen/drivers/video/vesa.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents 04cb0829d138
children
line source
1 /******************************************************************************
2 * vesa.c
3 *
4 * VESA linear frame buffer handling.
5 */
7 #include <xen/config.h>
8 #include <xen/init.h>
9 #include <xen/lib.h>
10 #include <xen/mm.h>
11 #include <xen/errno.h>
12 #include <xen/console.h>
13 #include <xen/vga.h>
14 #include "font.h"
16 #define vlfb_info vga_console_info.u.vesa_lfb
17 #define text_columns (vlfb_info.width / font->width)
18 #define text_rows (vlfb_info.height / font->height)
20 static void vesa_redraw_puts(const char *s);
21 static void vesa_scroll_puts(const char *s);
23 static unsigned char *lfb, *lbuf, *text_buf;
24 static unsigned int *__initdata line_len;
25 static const struct font_desc *font;
26 static bool_t vga_compat;
27 static unsigned int pixel_on;
28 static unsigned int xpos, ypos;
30 static unsigned int vram_total;
31 integer_param("vesa-ram", vram_total);
33 static unsigned int vram_remap;
34 integer_param("vesa-map", vram_remap);
36 static int font_height;
37 static void __init parse_font_height(const char *s)
38 {
39 if ( simple_strtoul(s, &s, 10) == 8 && (*s++ == 'x') )
40 font_height = simple_strtoul(s, &s, 10);
41 if ( *s != '\0' )
42 font_height = 0;
43 }
44 custom_param("font", parse_font_height);
46 void __init vesa_early_init(void)
47 {
48 unsigned int vram_vmode;
50 vga_compat = !(vga_console_info.u.vesa_lfb.gbl_caps & 2);
52 if ( (vlfb_info.bits_per_pixel < 8) || (vlfb_info.bits_per_pixel > 32) )
53 return;
55 if ( font_height == 0 ) /* choose a sensible default */
56 font = ((vlfb_info.height <= 600) ? &font_vga_8x8 :
57 (vlfb_info.height <= 768) ? &font_vga_8x14 : &font_vga_8x16);
58 else if ( font_height <= 8 )
59 font = &font_vga_8x8;
60 else if ( font_height <= 14 )
61 font = &font_vga_8x14;
62 else
63 font = &font_vga_8x16;
65 /* vram_vmode -- that is the amount of memory needed for the
66 * used video mode, i.e. the minimum amount of
67 * memory we need. */
68 vram_vmode = vlfb_info.height * vlfb_info.bytes_per_line;
70 /* vram_total -- all video memory we have. Used for mtrr
71 * entries. */
72 vram_total = vram_total ? (vram_total << 20) : (vlfb_info.lfb_size << 16);
73 vram_total = max_t(unsigned int, vram_total, vram_vmode);
75 /* vram_remap -- the amount of video memory we are going to
76 * use for vesafb. With modern cards it is no
77 * option to simply use vram_total as that
78 * wastes plenty of kernel address space. */
79 vram_remap = (vram_remap ?
80 (vram_remap << 20) :
81 ((vram_vmode + (1 << L2_PAGETABLE_SHIFT) - 1) &
82 ~((1 << L2_PAGETABLE_SHIFT) - 1)));
83 vram_remap = max_t(unsigned int, vram_remap, vram_vmode);
84 vram_remap = min_t(unsigned int, vram_remap, vram_total);
85 }
87 void __init vesa_init(void)
88 {
89 if ( !font )
90 goto fail;
92 lbuf = xmalloc_bytes(vlfb_info.bytes_per_line);
93 if ( !lbuf )
94 goto fail;
96 text_buf = xmalloc_bytes(text_columns * text_rows);
97 if ( !text_buf )
98 goto fail;
100 line_len = xmalloc_array(unsigned int, text_columns);
101 if ( !line_len )
102 goto fail;
104 if ( map_pages_to_xen(IOREMAP_VIRT_START,
105 vlfb_info.lfb_base >> PAGE_SHIFT,
106 vram_remap >> PAGE_SHIFT,
107 PAGE_HYPERVISOR_NOCACHE) )
108 goto fail;
110 lfb = memset((void *)IOREMAP_VIRT_START, 0, vram_remap);
111 memset(text_buf, 0, text_columns * text_rows);
112 memset(line_len, 0, text_columns * sizeof(*line_len));
114 vga_puts = vesa_redraw_puts;
116 printk(XENLOG_INFO "vesafb: framebuffer at 0x%x, mapped to 0x%p, "
117 "using %uk, total %uk\n",
118 vlfb_info.lfb_base, lfb,
119 vram_remap >> 10, vram_total >> 10);
120 printk(XENLOG_INFO "vesafb: mode is %dx%dx%u, linelength=%d, font %ux%u\n",
121 vlfb_info.width, vlfb_info.height,
122 vlfb_info.bits_per_pixel, vlfb_info.bytes_per_line,
123 font->width, font->height);
124 printk(XENLOG_INFO "vesafb: %scolor: size=%d:%d:%d:%d, "
125 "shift=%d:%d:%d:%d\n",
126 vlfb_info.bits_per_pixel > 8 ? "True" :
127 vga_compat ? "Pseudo" : "Static Pseudo",
128 vlfb_info.rsvd_size, vlfb_info.red_size,
129 vlfb_info.green_size, vlfb_info.blue_size,
130 vlfb_info.rsvd_pos, vlfb_info.red_pos,
131 vlfb_info.green_pos, vlfb_info.blue_pos);
133 if ( vlfb_info.bits_per_pixel > 8 )
134 {
135 /* Light grey in truecolor. */
136 unsigned int grey = 0xaaaaaaaa;
137 pixel_on =
138 ((grey >> (32 - vlfb_info. red_size)) << vlfb_info. red_pos) |
139 ((grey >> (32 - vlfb_info.green_size)) << vlfb_info.green_pos) |
140 ((grey >> (32 - vlfb_info. blue_size)) << vlfb_info. blue_pos);
141 }
142 else
143 {
144 /* White(ish) in default pseudocolor palette. */
145 pixel_on = 7;
146 }
148 return;
150 fail:
151 xfree(lbuf);
152 xfree(text_buf);
153 xfree(line_len);
154 }
156 void __init vesa_endboot(bool_t keep)
157 {
158 if ( keep )
159 {
160 xpos = 0;
161 vga_puts = vesa_scroll_puts;
162 }
163 else
164 {
165 unsigned int i, bpp = (vlfb_info.bits_per_pixel + 7) >> 3;
166 for ( i = 0; i < vlfb_info.height; i++ )
167 memset(lfb + i * vlfb_info.bytes_per_line, 0,
168 vlfb_info.width * bpp);
169 }
171 xfree(line_len);
172 }
174 #if defined(CONFIG_X86)
176 #include <asm/mtrr.h>
178 static unsigned int vesa_mtrr;
179 integer_param("vesa-mtrr", vesa_mtrr);
181 void __init vesa_mtrr_init(void)
182 {
183 static const int mtrr_types[] = {
184 0, MTRR_TYPE_UNCACHABLE, MTRR_TYPE_WRBACK,
185 MTRR_TYPE_WRCOMB, MTRR_TYPE_WRTHROUGH };
186 unsigned int size_total;
187 int rc, type;
189 if ( !lfb || (vesa_mtrr == 0) || (vesa_mtrr >= ARRAY_SIZE(mtrr_types)) )
190 return;
192 type = mtrr_types[vesa_mtrr];
193 if ( !type )
194 return;
196 /* Find the largest power-of-two */
197 size_total = vram_total;
198 while ( size_total & (size_total - 1) )
199 size_total &= size_total - 1;
201 /* Try and find a power of two to add */
202 do {
203 rc = mtrr_add(vlfb_info.lfb_base, size_total, type, 1);
204 size_total >>= 1;
205 } while ( (size_total >= PAGE_SIZE) && (rc == -EINVAL) );
206 }
208 static void lfb_flush(void)
209 {
210 if ( vesa_mtrr == 3 )
211 __asm__ __volatile__ ("sfence" : : : "memory");
212 }
214 #else /* !defined(CONFIG_X86) */
216 #define lfb_flush() ((void)0)
218 #endif
220 /* Render one line of text to given linear framebuffer line. */
221 static void vesa_show_line(
222 const unsigned char *text_line,
223 unsigned char *video_line,
224 unsigned int nr_chars,
225 unsigned int nr_cells)
226 {
227 unsigned int i, j, b, bpp, pixel;
229 bpp = (vlfb_info.bits_per_pixel + 7) >> 3;
231 for ( i = 0; i < font->height; i++ )
232 {
233 unsigned char *ptr = lbuf;
235 for ( j = 0; j < nr_chars; j++ )
236 {
237 const unsigned char *bits = font->data;
238 bits += ((text_line[j] * font->height + i) *
239 ((font->width + 7) >> 3));
240 for ( b = font->width; b--; )
241 {
242 pixel = (*bits & (1u<<b)) ? pixel_on : 0;
243 memcpy(ptr, &pixel, bpp);
244 ptr += bpp;
245 }
246 }
248 memset(ptr, 0, (vlfb_info.width - nr_chars * font->width) * bpp);
249 memcpy(video_line, lbuf, nr_cells * font->width * bpp);
250 video_line += vlfb_info.bytes_per_line;
251 }
252 }
254 /* Fast mode which redraws all modified parts of a 2D text buffer. */
255 static void __init vesa_redraw_puts(const char *s)
256 {
257 unsigned int i, min_redraw_y = ypos;
258 char c;
260 /* Paste characters into text buffer. */
261 while ( (c = *s++) != '\0' )
262 {
263 if ( (c == '\n') || (xpos >= text_columns) )
264 {
265 if ( ++ypos >= text_rows )
266 {
267 min_redraw_y = 0;
268 ypos = text_rows - 1;
269 memmove(text_buf, text_buf + text_columns,
270 ypos * text_columns);
271 memset(text_buf + ypos * text_columns, 0, xpos);
272 }
273 xpos = 0;
274 }
276 if ( c != '\n' )
277 text_buf[xpos++ + ypos * text_columns] = c;
278 }
280 /* Render modified section of text buffer to VESA linear framebuffer. */
281 for ( i = min_redraw_y; i <= ypos; i++ )
282 {
283 const unsigned char *line = text_buf + i * text_columns;
284 unsigned int width;
286 for ( width = text_columns; width; --width )
287 if ( line[width - 1] )
288 break;
289 vesa_show_line(line,
290 lfb + i * font->height * vlfb_info.bytes_per_line,
291 width, max(line_len[i], width));
292 line_len[i] = width;
293 }
295 lfb_flush();
296 }
298 /* Slower line-based scroll mode which interacts better with dom0. */
299 static void vesa_scroll_puts(const char *s)
300 {
301 unsigned int i;
302 char c;
304 while ( (c = *s++) != '\0' )
305 {
306 if ( (c == '\n') || (xpos >= text_columns) )
307 {
308 unsigned int bytes = (vlfb_info.width *
309 ((vlfb_info.bits_per_pixel + 7) >> 3));
310 unsigned char *src = lfb + font->height * vlfb_info.bytes_per_line;
311 unsigned char *dst = lfb;
313 /* New line: scroll all previous rows up one line. */
314 for ( i = font->height; i < vlfb_info.height; i++ )
315 {
316 memcpy(dst, src, bytes);
317 src += vlfb_info.bytes_per_line;
318 dst += vlfb_info.bytes_per_line;
319 }
321 /* Render new line. */
322 vesa_show_line(
323 text_buf,
324 lfb + (text_rows-1) * font->height * vlfb_info.bytes_per_line,
325 xpos, text_columns);
327 xpos = 0;
328 }
330 if ( c != '\n' )
331 text_buf[xpos++] = c;
332 }
334 lfb_flush();
335 }