1 /******************************************************************************
2  * vga.c
3  *
4  * VGA support routines.
5  */
6 
7 #include <xen/init.h>
8 #include <xen/lib.h>
9 #include <xen/mm.h>
10 #include <xen/vga.h>
11 #include <xen/pci.h>
12 #include <asm/io.h>
13 
14 /* Filled in by arch boot code. */
15 struct xen_vga_console_info vga_console_info;
16 
17 static int vgacon_keep;
18 static unsigned int xpos, ypos;
19 static unsigned char *video;
20 
21 static void vga_text_puts(const char *s);
vga_noop_puts(const char * s)22 static void vga_noop_puts(const char *s) {}
23 void (*video_puts)(const char *) = vga_noop_puts;
24 
25 /*
26  * 'vga=<mode-specifier>[,keep]' where <mode-specifier> is one of:
27  *
28  *   'vga=ask':
29  *      display a vga menu of available modes
30  *
31  *   'vga=current':
32  *      use the current vga mode without modification
33  *
34  *   'vga=text-80x<rows>':
35  *      text mode, where <rows> is one of {25,28,30,34,43,50,60}
36  *
37  *   'vga=gfx-<width>x<height>x<depth>':
38  *      graphics mode, e.g., vga=gfx-1024x768x16
39  *
40  *   'vga=mode-<mode>:
41  *      specifies a mode as specified in 'vga=ask' menu
42  *      (NB. menu modes are displayed in hex, so mode numbers here must
43  *           be prefixed with '0x' (e.g., 'vga=mode-0x0318'))
44  *
45  * The option 'keep' causes Xen to continue to print to the VGA console even
46  * after domain 0 starts to boot. The default behaviour is to relinquish
47  * control of the console to domain 0.
48  */
49 static char __initdata opt_vga[30] = "";
50 string_param("vga", opt_vga);
51 
52 /* VGA text-mode definitions. */
53 static unsigned int columns, lines;
54 #define ATTRIBUTE   7
55 
56 #ifdef CONFIG_X86
57 void vesa_early_init(void);
58 void vesa_endboot(bool_t keep);
59 #else
60 #define vesa_early_init() ((void)0)
61 #define vesa_endboot(x)   ((void)0)
62 #endif
63 
video_init(void)64 void __init video_init(void)
65 {
66     char *p;
67 
68     /* Look for 'keep' in comma-separated options. */
69     for ( p = opt_vga; p != NULL; p = strchr(p, ',') )
70     {
71         if ( *p == ',' )
72             p++;
73         if ( strncmp(p, "keep", 4) == 0 )
74             vgacon_keep = 1;
75     }
76 
77     switch ( vga_console_info.video_type )
78     {
79     case XEN_VGATYPE_TEXT_MODE_3:
80         if ( page_is_ram_type(paddr_to_pfn(0xB8000), RAM_TYPE_CONVENTIONAL) ||
81              ((video = ioremap(0xB8000, 0x8000)) == NULL) )
82             return;
83         outw(0x200a, 0x3d4); /* disable cursor */
84         columns = vga_console_info.u.text_mode_3.columns;
85         lines   = vga_console_info.u.text_mode_3.rows;
86         memset(video, 0, columns * lines * 2);
87         video_puts = vga_text_puts;
88         break;
89     case XEN_VGATYPE_VESA_LFB:
90     case XEN_VGATYPE_EFI_LFB:
91         vesa_early_init();
92         break;
93     default:
94         memset(&vga_console_info, 0, sizeof(vga_console_info));
95         break;
96     }
97 }
98 
video_endboot(void)99 void __init video_endboot(void)
100 {
101     if ( video_puts == vga_noop_puts )
102         return;
103 
104     printk("Xen is %s VGA console.\n",
105            vgacon_keep ? "keeping" : "relinquishing");
106 
107     if ( !vgacon_keep )
108         video_puts = vga_noop_puts;
109     else
110     {
111         int bus, devfn;
112 
113         for ( bus = 0; bus < 256; ++bus )
114             for ( devfn = 0; devfn < 256; ++devfn )
115             {
116                 const struct pci_dev *pdev;
117                 u8 b = bus, df = devfn, sb;
118 
119                 pcidevs_lock();
120                 pdev = pci_get_pdev(0, bus, devfn);
121                 pcidevs_unlock();
122 
123                 if ( !pdev ||
124                      pci_conf_read16(0, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
125                                      PCI_CLASS_DEVICE) != 0x0300 ||
126                      !(pci_conf_read16(0, bus, PCI_SLOT(devfn),
127                                        PCI_FUNC(devfn), PCI_COMMAND) &
128                        (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) )
129                     continue;
130 
131                 while ( b )
132                 {
133                     switch ( find_upstream_bridge(0, &b, &df, &sb) )
134                     {
135                     case 0:
136                         b = 0;
137                         break;
138                     case 1:
139                         switch ( pci_conf_read8(0, b, PCI_SLOT(df),
140                                                 PCI_FUNC(df),
141                                                 PCI_HEADER_TYPE) )
142                         {
143                         case PCI_HEADER_TYPE_BRIDGE:
144                         case PCI_HEADER_TYPE_CARDBUS:
145                             if ( pci_conf_read16(0, b, PCI_SLOT(df),
146                                                  PCI_FUNC(df),
147                                                  PCI_BRIDGE_CONTROL) &
148                                  PCI_BRIDGE_CTL_VGA )
149                                 continue;
150                             break;
151                         }
152                         break;
153                     }
154                     break;
155                 }
156                 if ( !b )
157                 {
158                     printk(XENLOG_INFO "Boot video device %02x:%02x.%u\n",
159                            bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
160                     pci_hide_device(bus, devfn);
161                 }
162             }
163     }
164 
165     switch ( vga_console_info.video_type )
166     {
167     case XEN_VGATYPE_TEXT_MODE_3:
168         if ( !vgacon_keep )
169             memset(video, 0, columns * lines * 2);
170         break;
171     case XEN_VGATYPE_VESA_LFB:
172     case XEN_VGATYPE_EFI_LFB:
173         vesa_endboot(vgacon_keep);
174         break;
175     default:
176         BUG();
177     }
178 }
179 
vga_text_puts(const char * s)180 static void vga_text_puts(const char *s)
181 {
182     char c;
183 
184     while ( (c = *s++) != '\0' )
185     {
186         if ( (c == '\n') || (xpos >= columns) )
187         {
188             if ( ++ypos >= lines )
189             {
190                 ypos = lines - 1;
191                 memmove(video, video + 2 * columns, ypos * 2 * columns);
192                 memset(video + ypos * 2 * columns, 0, 2 * xpos);
193             }
194             xpos = 0;
195         }
196 
197         if ( c != '\n' )
198         {
199             video[(xpos + ypos * columns) * 2]     = c;
200             video[(xpos + ypos * columns) * 2 + 1] = ATTRIBUTE;
201             xpos++;
202         }
203     }
204 }
205 
fill_console_start_info(struct dom0_vga_console_info * ci)206 int __init fill_console_start_info(struct dom0_vga_console_info *ci)
207 {
208     memcpy(ci, &vga_console_info, sizeof(*ci));
209     return 1;
210 }
211