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