1 /******************************************************************************
2  * vesa.c
3  *
4  * VESA linear frame buffer handling.
5  */
6 
7 #include <xen/init.h>
8 #include <xen/lib.h>
9 #include <xen/xmalloc.h>
10 #include <xen/kernel.h>
11 #include <xen/vga.h>
12 #include <asm/io.h>
13 #include <asm/page.h>
14 #include "font.h"
15 #include "lfb.h"
16 
17 #define vlfb_info    vga_console_info.u.vesa_lfb
18 
19 static void lfb_flush(void);
20 
21 static unsigned char *lfb;
22 static const struct font_desc *font;
23 static bool_t vga_compat;
24 
25 static unsigned int vram_total;
26 integer_param("vesa-ram", vram_total);
27 
28 static unsigned int vram_remap;
29 integer_param("vesa-map", vram_remap);
30 
31 static int font_height;
parse_font_height(const char * s)32 static int __init parse_font_height(const char *s)
33 {
34     if ( simple_strtoul(s, &s, 10) == 8 && (*s++ == 'x') )
35         font_height = simple_strtoul(s, &s, 10);
36     if ( *s != '\0' )
37         font_height = 0;
38 
39     return 0;
40 }
41 custom_param("font", parse_font_height);
42 
vesa_early_init(void)43 void __init vesa_early_init(void)
44 {
45     unsigned int vram_vmode;
46 
47     vga_compat = !(vga_console_info.u.vesa_lfb.gbl_caps & 2);
48 
49     if ( (vlfb_info.bits_per_pixel < 8) || (vlfb_info.bits_per_pixel > 32) )
50         return;
51 
52     if ( font_height == 0 ) /* choose a sensible default */
53         font = ((vlfb_info.height <= 600) ? &font_vga_8x8 :
54                 (vlfb_info.height <= 768) ? &font_vga_8x14 : &font_vga_8x16);
55     else if ( font_height <= 8 )
56         font = &font_vga_8x8;
57     else if ( font_height <= 14 )
58         font = &font_vga_8x14;
59     else
60         font = &font_vga_8x16;
61 
62     /*   vram_vmode -- that is the amount of memory needed for the
63      *                 used video mode, i.e. the minimum amount of
64      *                 memory we need. */
65     vram_vmode = vlfb_info.height * vlfb_info.bytes_per_line;
66 
67     /*   vram_total -- all video memory we have. Used for mtrr
68      *                 entries. */
69     vram_total = vram_total ? (vram_total << 20) : (vlfb_info.lfb_size << 16);
70     vram_total = max_t(unsigned int, vram_total, vram_vmode);
71 
72     /*   vram_remap -- the amount of video memory we are going to
73      *                 use for vesafb.  With modern cards it is no
74      *                 option to simply use vram_total as that
75      *                 wastes plenty of kernel address space. */
76     vram_remap = (vram_remap ?
77                   (vram_remap << 20) :
78                   ((vram_vmode + (1 << L2_PAGETABLE_SHIFT) - 1) &
79                    ~((1 << L2_PAGETABLE_SHIFT) - 1)));
80     vram_remap = max_t(unsigned int, vram_remap, vram_vmode);
81     vram_remap = min_t(unsigned int, vram_remap, vram_total);
82 }
83 
vesa_init(void)84 void __init vesa_init(void)
85 {
86     struct lfb_prop lfbp;
87 
88     if ( !font )
89         return;
90 
91     lfbp.font = font;
92     lfbp.bits_per_pixel = vlfb_info.bits_per_pixel;
93     lfbp.bytes_per_line = vlfb_info.bytes_per_line;
94     lfbp.width = vlfb_info.width;
95     lfbp.height = vlfb_info.height;
96     lfbp.flush = lfb_flush;
97     lfbp.text_columns = vlfb_info.width / font->width;
98     lfbp.text_rows = vlfb_info.height / font->height;
99 
100     lfbp.lfb = lfb = ioremap(vlfb_info.lfb_base, vram_remap);
101     if ( !lfb )
102         return;
103 
104     memset(lfb, 0, vram_remap);
105 
106     printk(XENLOG_INFO "vesafb: framebuffer at %#x, mapped to 0x%p, "
107            "using %uk, total %uk\n",
108            vlfb_info.lfb_base, lfb,
109            vram_remap >> 10, vram_total >> 10);
110     printk(XENLOG_INFO "vesafb: mode is %dx%dx%u, linelength=%d, font %ux%u\n",
111            vlfb_info.width, vlfb_info.height,
112            vlfb_info.bits_per_pixel, vlfb_info.bytes_per_line,
113            font->width, font->height);
114     printk(XENLOG_INFO "vesafb: %scolor: size=%d:%d:%d:%d, "
115            "shift=%d:%d:%d:%d\n",
116            vlfb_info.bits_per_pixel > 8 ? "True" :
117            vga_compat ? "Pseudo" : "Static Pseudo",
118            vlfb_info.rsvd_size, vlfb_info.red_size,
119            vlfb_info.green_size, vlfb_info.blue_size,
120            vlfb_info.rsvd_pos, vlfb_info.red_pos,
121            vlfb_info.green_pos, vlfb_info.blue_pos);
122 
123     if ( vlfb_info.bits_per_pixel > 8 )
124     {
125         /* Light grey in truecolor. */
126         unsigned int grey = 0xaaaaaaaa;
127         lfbp.pixel_on =
128             ((grey >> (32 - vlfb_info.  red_size)) << vlfb_info.  red_pos) |
129             ((grey >> (32 - vlfb_info.green_size)) << vlfb_info.green_pos) |
130             ((grey >> (32 - vlfb_info. blue_size)) << vlfb_info. blue_pos);
131     }
132     else
133     {
134         /* White(ish) in default pseudocolor palette. */
135         lfbp.pixel_on = 7;
136     }
137 
138     if ( lfb_init(&lfbp) < 0 )
139         return;
140     video_puts = lfb_redraw_puts;
141 }
142 
143 #include <asm/mtrr.h>
144 
145 static unsigned int vesa_mtrr;
146 integer_param("vesa-mtrr", vesa_mtrr);
147 
vesa_mtrr_init(void)148 void __init vesa_mtrr_init(void)
149 {
150     static const int mtrr_types[] = {
151         0, MTRR_TYPE_UNCACHABLE, MTRR_TYPE_WRBACK,
152         MTRR_TYPE_WRCOMB, MTRR_TYPE_WRTHROUGH };
153     unsigned int size_total;
154     int rc, type;
155 
156     if ( !lfb || (vesa_mtrr == 0) || (vesa_mtrr >= ARRAY_SIZE(mtrr_types)) )
157         return;
158 
159     type = mtrr_types[vesa_mtrr];
160     if ( !type )
161         return;
162 
163     /* Find the largest power-of-two */
164     size_total = vram_total;
165     while ( size_total & (size_total - 1) )
166         size_total &= size_total - 1;
167 
168     /* Try and find a power of two to add */
169     do {
170         rc = mtrr_add(vlfb_info.lfb_base, size_total, type, 1);
171         size_total >>= 1;
172     } while ( (size_total >= PAGE_SIZE) && (rc == -EINVAL) );
173 }
174 
lfb_flush(void)175 static void lfb_flush(void)
176 {
177     if ( vesa_mtrr == 3 )
178         __asm__ __volatile__ ("sfence" : : : "memory");
179 }
180 
vesa_endboot(bool_t keep)181 void __init vesa_endboot(bool_t keep)
182 {
183     if ( keep )
184     {
185         video_puts = lfb_scroll_puts;
186         lfb_carriage_return();
187     }
188     else
189     {
190         unsigned int i, bpp = (vlfb_info.bits_per_pixel + 7) >> 3;
191         for ( i = 0; i < vlfb_info.height; i++ )
192             memset(lfb + i * vlfb_info.bytes_per_line, 0,
193                    vlfb_info.width * bpp);
194         lfb_flush();
195         lfb_free();
196     }
197 }
198