aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2015-02-13 01:43:43 -0500
committerRusty Russell <rusty@rustcorp.com.au>2015-02-13 01:45:51 -0500
commit55c2d7884e9a97c2f2d46d5818f783bf3dcc5314 (patch)
tree6291c81f9c5456dff1a1c284f8aa14a851f7e5b1 /arch
parentd761b0329108c73020a7c95b6fa0d7e82e35fe8b (diff)
lguest: don't look in console features to find emerg_wr.
The 1.0 spec clearly states that you must set the ACKNOWLEDGE and DRIVER status bits before accessing the feature bits. This is a problem for the early console code, which doesn't really want to acknowledge the device (the spec specifically excepts writing to the console's emerg_wr from the usual ordering constrains). Instead, we check that the *size* of the device configuration is sufficient to hold emerg_wr: at worst (if the device doesn't support the VIRTIO_CONSOLE_F_EMERG_WRITE feature), it will ignore the writes. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/lguest/boot.c57
1 files changed, 24 insertions, 33 deletions
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 531b844cb48d..ac4453d8520e 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -1222,15 +1222,13 @@ static void set_cfg_window(u32 cfg_offset, u32 off)
1222 off); 1222 off);
1223} 1223}
1224 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) 1225static void write_bar_via_cfg(u32 cfg_offset, u32 off, u32 val)
1233{ 1226{
1227 /*
1228 * We could set this up once, then leave it; nothing else in the *
1229 * kernel should touch these registers. But if it went wrong, that
1230 * would be a horrible bug to find.
1231 */
1234 set_cfg_window(cfg_offset, off); 1232 set_cfg_window(cfg_offset, off);
1235 write_pci_config(0, 1, 0, 1233 write_pci_config(0, 1, 0,
1236 cfg_offset + sizeof(struct virtio_pci_cap), val); 1234 cfg_offset + sizeof(struct virtio_pci_cap), val);
@@ -1239,8 +1237,9 @@ static void write_bar_via_cfg(u32 cfg_offset, u32 off, u32 val)
1239static void probe_pci_console(void) 1237static void probe_pci_console(void)
1240{ 1238{
1241 u8 cap, common_cap = 0, device_cap = 0; 1239 u8 cap, common_cap = 0, device_cap = 0;
1242 /* Offsets within BAR0 */ 1240 /* Offset within BAR0 */
1243 u32 common_offset, device_offset; 1241 u32 device_offset;
1242 u32 device_len;
1244 1243
1245 /* Avoid recursive printk into here. */ 1244 /* Avoid recursive printk into here. */
1246 console_cfg_offset = -1; 1245 console_cfg_offset = -1;
@@ -1263,7 +1262,7 @@ static void probe_pci_console(void)
1263 u8 vndr = read_pci_config_byte(0, 1, 0, cap); 1262 u8 vndr = read_pci_config_byte(0, 1, 0, cap);
1264 if (vndr == PCI_CAP_ID_VNDR) { 1263 if (vndr == PCI_CAP_ID_VNDR) {
1265 u8 type, bar; 1264 u8 type, bar;
1266 u32 offset; 1265 u32 offset, length;
1267 1266
1268 type = read_pci_config_byte(0, 1, 0, 1267 type = read_pci_config_byte(0, 1, 0,
1269 cap + offsetof(struct virtio_pci_cap, cfg_type)); 1268 cap + offsetof(struct virtio_pci_cap, cfg_type));
@@ -1271,18 +1270,15 @@ static void probe_pci_console(void)
1271 cap + offsetof(struct virtio_pci_cap, bar)); 1270 cap + offsetof(struct virtio_pci_cap, bar));
1272 offset = read_pci_config(0, 1, 0, 1271 offset = read_pci_config(0, 1, 0,
1273 cap + offsetof(struct virtio_pci_cap, offset)); 1272 cap + offsetof(struct virtio_pci_cap, offset));
1273 length = read_pci_config(0, 1, 0,
1274 cap + offsetof(struct virtio_pci_cap, length));
1274 1275
1275 switch (type) { 1276 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: 1277 case VIRTIO_PCI_CAP_DEVICE_CFG:
1283 if (bar == 0) { 1278 if (bar == 0) {
1284 device_cap = cap; 1279 device_cap = cap;
1285 device_offset = offset; 1280 device_offset = offset;
1281 device_len = length;
1286 } 1282 }
1287 break; 1283 break;
1288 case VIRTIO_PCI_CAP_PCI_CFG: 1284 case VIRTIO_PCI_CAP_PCI_CFG:
@@ -1292,32 +1288,27 @@ static void probe_pci_console(void)
1292 } 1288 }
1293 cap = read_pci_config_byte(0, 1, 0, cap + PCI_CAP_LIST_NEXT); 1289 cap = read_pci_config_byte(0, 1, 0, cap + PCI_CAP_LIST_NEXT);
1294 } 1290 }
1295 if (!common_cap || !device_cap || !console_access_cap) { 1291 if (!device_cap || !console_access_cap) {
1296 printk(KERN_ERR "lguest: No caps (%u/%u/%u) in console!\n", 1292 printk(KERN_ERR "lguest: No caps (%u/%u/%u) in console!\n",
1297 common_cap, device_cap, console_access_cap); 1293 common_cap, device_cap, console_access_cap);
1298 return; 1294 return;
1299 } 1295 }
1300 1296
1301 1297 /*
1302#define write_common_config(reg, val) \ 1298 * Note that we can't check features, until we've set the DRIVER
1303 write_bar_via_cfg(console_access_cap, \ 1299 * status bit. We don't want to do that until we have a real driver,
1304 common_offset+offsetof(struct virtio_pci_common_cfg,reg),\ 1300 * so we just check that the device-specific config has room for
1305 val) 1301 * emerg_wr. If it doesn't support VIRTIO_CONSOLE_F_EMERG_WRITE
1306 1302 * it should ignore the access.
1307#define read_common_config(reg) \ 1303 */
1308 read_bar_via_cfg(console_access_cap, \ 1304 if (device_len < (offsetof(struct virtio_console_config, emerg_wr)
1309 common_offset+offsetof(struct virtio_pci_common_cfg,reg)) 1305 + sizeof(u32))) {
1310 1306 printk(KERN_ERR "lguest: console missing emerg_wr field\n");
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; 1307 return;
1318 } 1308 }
1319 1309
1320 console_cfg_offset = device_offset; 1310 console_cfg_offset = device_offset;
1311 printk(KERN_INFO "lguest: Console via virtio-pci emerg_wr\n");
1321} 1312}
1322 1313
1323/* 1314/*