aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/lguest/boot.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2015-02-10 23:56:01 -0500
committerRusty Russell <rusty@rustcorp.com.au>2015-02-11 01:17:44 -0500
commita561adfaecc9eb6fb66941b450458801f3f60ca0 (patch)
treefc4bb1870df410e832adb8e321b6a2417706b33d /arch/x86/lguest/boot.c
parent713e3f72244cb67fe1ad5c82a061c0b1be2f2fc5 (diff)
lguest: use the PCI console device's emerg_wr for early boot messages.
This involves manually checking the console device (which is always in slot 1 of bus 0) and using the window in VIRTIO_PCI_CAP_PCI_CFG to program it (as we can't map the BAR yet). We could in fact do this much earlier, but we wait for the first write from the virtio_cons_early_init() facility. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'arch/x86/lguest/boot.c')
-rw-r--r--arch/x86/lguest/boot.c146
1 files changed, 134 insertions, 12 deletions
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 2943ab931671..531b844cb48d 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -57,6 +57,7 @@
57#include <linux/pm.h> 57#include <linux/pm.h>
58#include <linux/export.h> 58#include <linux/export.h>
59#include <linux/pci.h> 59#include <linux/pci.h>
60#include <linux/virtio_pci.h>
60#include <asm/acpi.h> 61#include <asm/acpi.h>
61#include <asm/apic.h> 62#include <asm/apic.h>
62#include <asm/lguest.h> 63#include <asm/lguest.h>
@@ -74,6 +75,7 @@
74#include <asm/reboot.h> /* for struct machine_ops */ 75#include <asm/reboot.h> /* for struct machine_ops */
75#include <asm/kvm_para.h> 76#include <asm/kvm_para.h>
76#include <asm/pci_x86.h> 77#include <asm/pci_x86.h>
78#include <asm/pci-direct.h>
77 79
78/*G:010 80/*G:010
79 * Welcome to the Guest! 81 * Welcome to the Guest!
@@ -1202,25 +1204,145 @@ static __init char *lguest_memory_setup(void)
1202 return "LGUEST"; 1204 return "LGUEST";
1203} 1205}
1204 1206
1207/* Offset within PCI config space of BAR access capability. */
1208static int console_cfg_offset = 0;
1209static int console_access_cap;
1210
1211/* Set up so that we access off in bar0 (on bus 0, device 1, function 0) */
1212static void set_cfg_window(u32 cfg_offset, u32 off)
1213{
1214 write_pci_config_byte(0, 1, 0,
1215 cfg_offset + offsetof(struct virtio_pci_cap, bar),
1216 0);
1217 write_pci_config(0, 1, 0,
1218 cfg_offset + offsetof(struct virtio_pci_cap, length),
1219 4);
1220 write_pci_config(0, 1, 0,
1221 cfg_offset + offsetof(struct virtio_pci_cap, offset),
1222 off);
1223}
1224
1225static u32 read_bar_via_cfg(u32 cfg_offset, u32 off)
1226{
1227 set_cfg_window(cfg_offset, off);
1228 return read_pci_config(0, 1, 0,
1229 cfg_offset + sizeof(struct virtio_pci_cap));
1230}
1231
1232static void write_bar_via_cfg(u32 cfg_offset, u32 off, u32 val)
1233{
1234 set_cfg_window(cfg_offset, off);
1235 write_pci_config(0, 1, 0,
1236 cfg_offset + sizeof(struct virtio_pci_cap), val);
1237}
1238
1239static void probe_pci_console(void)
1240{
1241 u8 cap, common_cap = 0, device_cap = 0;
1242 /* Offsets within BAR0 */
1243 u32 common_offset, device_offset;
1244
1245 /* Avoid recursive printk into here. */
1246 console_cfg_offset = -1;
1247
1248 if (!early_pci_allowed()) {
1249 printk(KERN_ERR "lguest: early PCI access not allowed!\n");
1250 return;
1251 }
1252
1253 /* We expect a console PCI device at BUS0, slot 1. */
1254 if (read_pci_config(0, 1, 0, 0) != 0x10431AF4) {
1255 printk(KERN_ERR "lguest: PCI device is %#x!\n",
1256 read_pci_config(0, 1, 0, 0));
1257 return;
1258 }
1259
1260 /* Find the capabilities we need (must be in bar0) */
1261 cap = read_pci_config_byte(0, 1, 0, PCI_CAPABILITY_LIST);
1262 while (cap) {
1263 u8 vndr = read_pci_config_byte(0, 1, 0, cap);
1264 if (vndr == PCI_CAP_ID_VNDR) {
1265 u8 type, bar;
1266 u32 offset;
1267
1268 type = read_pci_config_byte(0, 1, 0,
1269 cap + offsetof(struct virtio_pci_cap, cfg_type));
1270 bar = read_pci_config_byte(0, 1, 0,
1271 cap + offsetof(struct virtio_pci_cap, bar));
1272 offset = read_pci_config(0, 1, 0,
1273 cap + offsetof(struct virtio_pci_cap, offset));
1274
1275 switch (type) {
1276 case VIRTIO_PCI_CAP_COMMON_CFG:
1277 if (bar == 0) {
1278 common_cap = cap;
1279 common_offset = offset;
1280 }
1281 break;
1282 case VIRTIO_PCI_CAP_DEVICE_CFG:
1283 if (bar == 0) {
1284 device_cap = cap;
1285 device_offset = offset;
1286 }
1287 break;
1288 case VIRTIO_PCI_CAP_PCI_CFG:
1289 console_access_cap = cap;
1290 break;
1291 }
1292 }
1293 cap = read_pci_config_byte(0, 1, 0, cap + PCI_CAP_LIST_NEXT);
1294 }
1295 if (!common_cap || !device_cap || !console_access_cap) {
1296 printk(KERN_ERR "lguest: No caps (%u/%u/%u) in console!\n",
1297 common_cap, device_cap, console_access_cap);
1298 return;
1299 }
1300
1301
1302#define write_common_config(reg, val) \
1303 write_bar_via_cfg(console_access_cap, \
1304 common_offset+offsetof(struct virtio_pci_common_cfg,reg),\
1305 val)
1306
1307#define read_common_config(reg) \
1308 read_bar_via_cfg(console_access_cap, \
1309 common_offset+offsetof(struct virtio_pci_common_cfg,reg))
1310
1311 /* Check features: they must offer EMERG_WRITE */
1312 write_common_config(device_feature_select, 0);
1313
1314 if (!(read_common_config(device_feature)
1315 & (1 << VIRTIO_CONSOLE_F_EMERG_WRITE))) {
1316 printk(KERN_ERR "lguest: console missing EMERG_WRITE\n");
1317 return;
1318 }
1319
1320 console_cfg_offset = device_offset;
1321}
1322
1205/* 1323/*
1206 * We will eventually use the virtio console device to produce console output, 1324 * We will eventually use the virtio console device to produce console output,
1207 * but before that is set up we use LHCALL_NOTIFY on normal memory to produce 1325 * but before that is set up we use the virtio PCI console's backdoor mmio
1208 * console output. 1326 * access and the "emergency" write facility (which is legal even before the
1327 * device is configured).
1209 */ 1328 */
1210static __init int early_put_chars(u32 vtermno, const char *buf, int count) 1329static __init int early_put_chars(u32 vtermno, const char *buf, int count)
1211{ 1330{
1212 char scratch[17]; 1331 /* If we couldn't find PCI console, forget it. */
1213 unsigned int len = count; 1332 if (console_cfg_offset < 0)
1333 return count;
1214 1334
1215 /* We use a nul-terminated string, so we make a copy. Icky, huh? */ 1335 if (unlikely(!console_cfg_offset)) {
1216 if (len > sizeof(scratch) - 1) 1336 probe_pci_console();
1217 len = sizeof(scratch) - 1; 1337 if (console_cfg_offset < 0)
1218 scratch[len] = '\0'; 1338 return count;
1219 memcpy(scratch, buf, len); 1339 }
1220 hcall(LHCALL_NOTIFY, __pa(scratch), 0, 0, 0);
1221 1340
1222 /* This routine returns the number of bytes actually written. */ 1341 write_bar_via_cfg(console_access_cap,
1223 return len; 1342 console_cfg_offset
1343 + offsetof(struct virtio_console_config, emerg_wr),
1344 buf[0]);
1345 return 1;
1224} 1346}
1225 1347
1226/* 1348/*