diff options
author | Carsten Otte <cotte@de.ibm.com> | 2007-10-30 13:44:25 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:52:59 -0500 |
commit | de7d789acd7f373268194bb48dc0690c975ab8e6 (patch) | |
tree | c2e9c4e1bb8d127e7a53459f9ed83c711901f31d /drivers/kvm | |
parent | bbd9b64e37aff5aa715ec5e168425790f5983bf1 (diff) |
KVM: Portability: Move pio emulation functions to x86.c
This patch moves implementation of the following functions from
kvm_main.c to x86.c:
free_pio_guest_pages, vcpu_find_pio_dev, pio_copy_data, complete_pio,
kernel_pio, pio_string_write, kvm_emulate_pio, kvm_emulate_pio_string
The function inject_gp, which was duplicated by yesterday's patch
series, is removed from kvm_main.c now because it is not needed anymore.
Signed-off-by: Carsten Otte <cotte@de.ibm.com>
Acked-by: Hollis Blanchard <hollisb@us.ibm.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm')
-rw-r--r-- | drivers/kvm/kvm_main.c | 248 | ||||
-rw-r--r-- | drivers/kvm/x86.c | 243 | ||||
-rw-r--r-- | drivers/kvm/x86.h | 1 |
3 files changed, 244 insertions, 248 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 1a56d76560de..2025cdfb4593 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -271,17 +271,6 @@ static void kvm_free_physmem(struct kvm *kvm) | |||
271 | kvm_free_physmem_slot(&kvm->memslots[i], NULL); | 271 | kvm_free_physmem_slot(&kvm->memslots[i], NULL); |
272 | } | 272 | } |
273 | 273 | ||
274 | static void free_pio_guest_pages(struct kvm_vcpu *vcpu) | ||
275 | { | ||
276 | int i; | ||
277 | |||
278 | for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i) | ||
279 | if (vcpu->pio.guest_pages[i]) { | ||
280 | kvm_release_page(vcpu->pio.guest_pages[i]); | ||
281 | vcpu->pio.guest_pages[i] = NULL; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) | 274 | static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) |
286 | { | 275 | { |
287 | vcpu_load(vcpu); | 276 | vcpu_load(vcpu); |
@@ -330,11 +319,6 @@ static int kvm_vm_release(struct inode *inode, struct file *filp) | |||
330 | return 0; | 319 | return 0; |
331 | } | 320 | } |
332 | 321 | ||
333 | static void inject_gp(struct kvm_vcpu *vcpu) | ||
334 | { | ||
335 | kvm_x86_ops->inject_gp(vcpu, 0); | ||
336 | } | ||
337 | |||
338 | void fx_init(struct kvm_vcpu *vcpu) | 322 | void fx_init(struct kvm_vcpu *vcpu) |
339 | { | 323 | { |
340 | unsigned after_mxcsr_mask; | 324 | unsigned after_mxcsr_mask; |
@@ -827,12 +811,6 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn) | |||
827 | } | 811 | } |
828 | } | 812 | } |
829 | 813 | ||
830 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, | ||
831 | gpa_t addr) | ||
832 | { | ||
833 | return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr); | ||
834 | } | ||
835 | |||
836 | /* | 814 | /* |
837 | * The vCPU has executed a HLT instruction with in-kernel mode enabled. | 815 | * The vCPU has executed a HLT instruction with in-kernel mode enabled. |
838 | */ | 816 | */ |
@@ -1042,232 +1020,6 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) | |||
1042 | } | 1020 | } |
1043 | EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); | 1021 | EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); |
1044 | 1022 | ||
1045 | static int pio_copy_data(struct kvm_vcpu *vcpu) | ||
1046 | { | ||
1047 | void *p = vcpu->pio_data; | ||
1048 | void *q; | ||
1049 | unsigned bytes; | ||
1050 | int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1; | ||
1051 | |||
1052 | q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE, | ||
1053 | PAGE_KERNEL); | ||
1054 | if (!q) { | ||
1055 | free_pio_guest_pages(vcpu); | ||
1056 | return -ENOMEM; | ||
1057 | } | ||
1058 | q += vcpu->pio.guest_page_offset; | ||
1059 | bytes = vcpu->pio.size * vcpu->pio.cur_count; | ||
1060 | if (vcpu->pio.in) | ||
1061 | memcpy(q, p, bytes); | ||
1062 | else | ||
1063 | memcpy(p, q, bytes); | ||
1064 | q -= vcpu->pio.guest_page_offset; | ||
1065 | vunmap(q); | ||
1066 | free_pio_guest_pages(vcpu); | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | static int complete_pio(struct kvm_vcpu *vcpu) | ||
1071 | { | ||
1072 | struct kvm_pio_request *io = &vcpu->pio; | ||
1073 | long delta; | ||
1074 | int r; | ||
1075 | |||
1076 | kvm_x86_ops->cache_regs(vcpu); | ||
1077 | |||
1078 | if (!io->string) { | ||
1079 | if (io->in) | ||
1080 | memcpy(&vcpu->regs[VCPU_REGS_RAX], vcpu->pio_data, | ||
1081 | io->size); | ||
1082 | } else { | ||
1083 | if (io->in) { | ||
1084 | r = pio_copy_data(vcpu); | ||
1085 | if (r) { | ||
1086 | kvm_x86_ops->cache_regs(vcpu); | ||
1087 | return r; | ||
1088 | } | ||
1089 | } | ||
1090 | |||
1091 | delta = 1; | ||
1092 | if (io->rep) { | ||
1093 | delta *= io->cur_count; | ||
1094 | /* | ||
1095 | * The size of the register should really depend on | ||
1096 | * current address size. | ||
1097 | */ | ||
1098 | vcpu->regs[VCPU_REGS_RCX] -= delta; | ||
1099 | } | ||
1100 | if (io->down) | ||
1101 | delta = -delta; | ||
1102 | delta *= io->size; | ||
1103 | if (io->in) | ||
1104 | vcpu->regs[VCPU_REGS_RDI] += delta; | ||
1105 | else | ||
1106 | vcpu->regs[VCPU_REGS_RSI] += delta; | ||
1107 | } | ||
1108 | |||
1109 | kvm_x86_ops->decache_regs(vcpu); | ||
1110 | |||
1111 | io->count -= io->cur_count; | ||
1112 | io->cur_count = 0; | ||
1113 | |||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | static void kernel_pio(struct kvm_io_device *pio_dev, | ||
1118 | struct kvm_vcpu *vcpu, | ||
1119 | void *pd) | ||
1120 | { | ||
1121 | /* TODO: String I/O for in kernel device */ | ||
1122 | |||
1123 | mutex_lock(&vcpu->kvm->lock); | ||
1124 | if (vcpu->pio.in) | ||
1125 | kvm_iodevice_read(pio_dev, vcpu->pio.port, | ||
1126 | vcpu->pio.size, | ||
1127 | pd); | ||
1128 | else | ||
1129 | kvm_iodevice_write(pio_dev, vcpu->pio.port, | ||
1130 | vcpu->pio.size, | ||
1131 | pd); | ||
1132 | mutex_unlock(&vcpu->kvm->lock); | ||
1133 | } | ||
1134 | |||
1135 | static void pio_string_write(struct kvm_io_device *pio_dev, | ||
1136 | struct kvm_vcpu *vcpu) | ||
1137 | { | ||
1138 | struct kvm_pio_request *io = &vcpu->pio; | ||
1139 | void *pd = vcpu->pio_data; | ||
1140 | int i; | ||
1141 | |||
1142 | mutex_lock(&vcpu->kvm->lock); | ||
1143 | for (i = 0; i < io->cur_count; i++) { | ||
1144 | kvm_iodevice_write(pio_dev, io->port, | ||
1145 | io->size, | ||
1146 | pd); | ||
1147 | pd += io->size; | ||
1148 | } | ||
1149 | mutex_unlock(&vcpu->kvm->lock); | ||
1150 | } | ||
1151 | |||
1152 | int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | ||
1153 | int size, unsigned port) | ||
1154 | { | ||
1155 | struct kvm_io_device *pio_dev; | ||
1156 | |||
1157 | vcpu->run->exit_reason = KVM_EXIT_IO; | ||
1158 | vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; | ||
1159 | vcpu->run->io.size = vcpu->pio.size = size; | ||
1160 | vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; | ||
1161 | vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = 1; | ||
1162 | vcpu->run->io.port = vcpu->pio.port = port; | ||
1163 | vcpu->pio.in = in; | ||
1164 | vcpu->pio.string = 0; | ||
1165 | vcpu->pio.down = 0; | ||
1166 | vcpu->pio.guest_page_offset = 0; | ||
1167 | vcpu->pio.rep = 0; | ||
1168 | |||
1169 | kvm_x86_ops->cache_regs(vcpu); | ||
1170 | memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4); | ||
1171 | kvm_x86_ops->decache_regs(vcpu); | ||
1172 | |||
1173 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
1174 | |||
1175 | pio_dev = vcpu_find_pio_dev(vcpu, port); | ||
1176 | if (pio_dev) { | ||
1177 | kernel_pio(pio_dev, vcpu, vcpu->pio_data); | ||
1178 | complete_pio(vcpu); | ||
1179 | return 1; | ||
1180 | } | ||
1181 | return 0; | ||
1182 | } | ||
1183 | EXPORT_SYMBOL_GPL(kvm_emulate_pio); | ||
1184 | |||
1185 | int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | ||
1186 | int size, unsigned long count, int down, | ||
1187 | gva_t address, int rep, unsigned port) | ||
1188 | { | ||
1189 | unsigned now, in_page; | ||
1190 | int i, ret = 0; | ||
1191 | int nr_pages = 1; | ||
1192 | struct page *page; | ||
1193 | struct kvm_io_device *pio_dev; | ||
1194 | |||
1195 | vcpu->run->exit_reason = KVM_EXIT_IO; | ||
1196 | vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; | ||
1197 | vcpu->run->io.size = vcpu->pio.size = size; | ||
1198 | vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; | ||
1199 | vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = count; | ||
1200 | vcpu->run->io.port = vcpu->pio.port = port; | ||
1201 | vcpu->pio.in = in; | ||
1202 | vcpu->pio.string = 1; | ||
1203 | vcpu->pio.down = down; | ||
1204 | vcpu->pio.guest_page_offset = offset_in_page(address); | ||
1205 | vcpu->pio.rep = rep; | ||
1206 | |||
1207 | if (!count) { | ||
1208 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
1209 | return 1; | ||
1210 | } | ||
1211 | |||
1212 | if (!down) | ||
1213 | in_page = PAGE_SIZE - offset_in_page(address); | ||
1214 | else | ||
1215 | in_page = offset_in_page(address) + size; | ||
1216 | now = min(count, (unsigned long)in_page / size); | ||
1217 | if (!now) { | ||
1218 | /* | ||
1219 | * String I/O straddles page boundary. Pin two guest pages | ||
1220 | * so that we satisfy atomicity constraints. Do just one | ||
1221 | * transaction to avoid complexity. | ||
1222 | */ | ||
1223 | nr_pages = 2; | ||
1224 | now = 1; | ||
1225 | } | ||
1226 | if (down) { | ||
1227 | /* | ||
1228 | * String I/O in reverse. Yuck. Kill the guest, fix later. | ||
1229 | */ | ||
1230 | pr_unimpl(vcpu, "guest string pio down\n"); | ||
1231 | inject_gp(vcpu); | ||
1232 | return 1; | ||
1233 | } | ||
1234 | vcpu->run->io.count = now; | ||
1235 | vcpu->pio.cur_count = now; | ||
1236 | |||
1237 | if (vcpu->pio.cur_count == vcpu->pio.count) | ||
1238 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
1239 | |||
1240 | for (i = 0; i < nr_pages; ++i) { | ||
1241 | mutex_lock(&vcpu->kvm->lock); | ||
1242 | page = gva_to_page(vcpu, address + i * PAGE_SIZE); | ||
1243 | vcpu->pio.guest_pages[i] = page; | ||
1244 | mutex_unlock(&vcpu->kvm->lock); | ||
1245 | if (!page) { | ||
1246 | inject_gp(vcpu); | ||
1247 | free_pio_guest_pages(vcpu); | ||
1248 | return 1; | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | pio_dev = vcpu_find_pio_dev(vcpu, port); | ||
1253 | if (!vcpu->pio.in) { | ||
1254 | /* string PIO write */ | ||
1255 | ret = pio_copy_data(vcpu); | ||
1256 | if (ret >= 0 && pio_dev) { | ||
1257 | pio_string_write(pio_dev, vcpu); | ||
1258 | complete_pio(vcpu); | ||
1259 | if (vcpu->pio.count == 0) | ||
1260 | ret = 1; | ||
1261 | } | ||
1262 | } else if (pio_dev) | ||
1263 | pr_unimpl(vcpu, "no string pio read support yet, " | ||
1264 | "port %x size %d count %ld\n", | ||
1265 | port, size, count); | ||
1266 | |||
1267 | return ret; | ||
1268 | } | ||
1269 | EXPORT_SYMBOL_GPL(kvm_emulate_pio_string); | ||
1270 | |||
1271 | /* | 1023 | /* |
1272 | * Check if userspace requested an interrupt window, and that the | 1024 | * Check if userspace requested an interrupt window, and that the |
1273 | * interrupt window is open. | 1025 | * interrupt window is open. |
diff --git a/drivers/kvm/x86.c b/drivers/kvm/x86.c index fe3733d8ece5..f75e7d7d9ead 100644 --- a/drivers/kvm/x86.c +++ b/drivers/kvm/x86.c | |||
@@ -1341,6 +1341,249 @@ int emulate_instruction(struct kvm_vcpu *vcpu, | |||
1341 | } | 1341 | } |
1342 | EXPORT_SYMBOL_GPL(emulate_instruction); | 1342 | EXPORT_SYMBOL_GPL(emulate_instruction); |
1343 | 1343 | ||
1344 | static void free_pio_guest_pages(struct kvm_vcpu *vcpu) | ||
1345 | { | ||
1346 | int i; | ||
1347 | |||
1348 | for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i) | ||
1349 | if (vcpu->pio.guest_pages[i]) { | ||
1350 | kvm_release_page(vcpu->pio.guest_pages[i]); | ||
1351 | vcpu->pio.guest_pages[i] = NULL; | ||
1352 | } | ||
1353 | } | ||
1354 | |||
1355 | static int pio_copy_data(struct kvm_vcpu *vcpu) | ||
1356 | { | ||
1357 | void *p = vcpu->pio_data; | ||
1358 | void *q; | ||
1359 | unsigned bytes; | ||
1360 | int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1; | ||
1361 | |||
1362 | q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE, | ||
1363 | PAGE_KERNEL); | ||
1364 | if (!q) { | ||
1365 | free_pio_guest_pages(vcpu); | ||
1366 | return -ENOMEM; | ||
1367 | } | ||
1368 | q += vcpu->pio.guest_page_offset; | ||
1369 | bytes = vcpu->pio.size * vcpu->pio.cur_count; | ||
1370 | if (vcpu->pio.in) | ||
1371 | memcpy(q, p, bytes); | ||
1372 | else | ||
1373 | memcpy(p, q, bytes); | ||
1374 | q -= vcpu->pio.guest_page_offset; | ||
1375 | vunmap(q); | ||
1376 | free_pio_guest_pages(vcpu); | ||
1377 | return 0; | ||
1378 | } | ||
1379 | |||
1380 | int complete_pio(struct kvm_vcpu *vcpu) | ||
1381 | { | ||
1382 | struct kvm_pio_request *io = &vcpu->pio; | ||
1383 | long delta; | ||
1384 | int r; | ||
1385 | |||
1386 | kvm_x86_ops->cache_regs(vcpu); | ||
1387 | |||
1388 | if (!io->string) { | ||
1389 | if (io->in) | ||
1390 | memcpy(&vcpu->regs[VCPU_REGS_RAX], vcpu->pio_data, | ||
1391 | io->size); | ||
1392 | } else { | ||
1393 | if (io->in) { | ||
1394 | r = pio_copy_data(vcpu); | ||
1395 | if (r) { | ||
1396 | kvm_x86_ops->cache_regs(vcpu); | ||
1397 | return r; | ||
1398 | } | ||
1399 | } | ||
1400 | |||
1401 | delta = 1; | ||
1402 | if (io->rep) { | ||
1403 | delta *= io->cur_count; | ||
1404 | /* | ||
1405 | * The size of the register should really depend on | ||
1406 | * current address size. | ||
1407 | */ | ||
1408 | vcpu->regs[VCPU_REGS_RCX] -= delta; | ||
1409 | } | ||
1410 | if (io->down) | ||
1411 | delta = -delta; | ||
1412 | delta *= io->size; | ||
1413 | if (io->in) | ||
1414 | vcpu->regs[VCPU_REGS_RDI] += delta; | ||
1415 | else | ||
1416 | vcpu->regs[VCPU_REGS_RSI] += delta; | ||
1417 | } | ||
1418 | |||
1419 | kvm_x86_ops->decache_regs(vcpu); | ||
1420 | |||
1421 | io->count -= io->cur_count; | ||
1422 | io->cur_count = 0; | ||
1423 | |||
1424 | return 0; | ||
1425 | } | ||
1426 | |||
1427 | static void kernel_pio(struct kvm_io_device *pio_dev, | ||
1428 | struct kvm_vcpu *vcpu, | ||
1429 | void *pd) | ||
1430 | { | ||
1431 | /* TODO: String I/O for in kernel device */ | ||
1432 | |||
1433 | mutex_lock(&vcpu->kvm->lock); | ||
1434 | if (vcpu->pio.in) | ||
1435 | kvm_iodevice_read(pio_dev, vcpu->pio.port, | ||
1436 | vcpu->pio.size, | ||
1437 | pd); | ||
1438 | else | ||
1439 | kvm_iodevice_write(pio_dev, vcpu->pio.port, | ||
1440 | vcpu->pio.size, | ||
1441 | pd); | ||
1442 | mutex_unlock(&vcpu->kvm->lock); | ||
1443 | } | ||
1444 | |||
1445 | static void pio_string_write(struct kvm_io_device *pio_dev, | ||
1446 | struct kvm_vcpu *vcpu) | ||
1447 | { | ||
1448 | struct kvm_pio_request *io = &vcpu->pio; | ||
1449 | void *pd = vcpu->pio_data; | ||
1450 | int i; | ||
1451 | |||
1452 | mutex_lock(&vcpu->kvm->lock); | ||
1453 | for (i = 0; i < io->cur_count; i++) { | ||
1454 | kvm_iodevice_write(pio_dev, io->port, | ||
1455 | io->size, | ||
1456 | pd); | ||
1457 | pd += io->size; | ||
1458 | } | ||
1459 | mutex_unlock(&vcpu->kvm->lock); | ||
1460 | } | ||
1461 | |||
1462 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, | ||
1463 | gpa_t addr) | ||
1464 | { | ||
1465 | return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr); | ||
1466 | } | ||
1467 | |||
1468 | int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | ||
1469 | int size, unsigned port) | ||
1470 | { | ||
1471 | struct kvm_io_device *pio_dev; | ||
1472 | |||
1473 | vcpu->run->exit_reason = KVM_EXIT_IO; | ||
1474 | vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; | ||
1475 | vcpu->run->io.size = vcpu->pio.size = size; | ||
1476 | vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; | ||
1477 | vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = 1; | ||
1478 | vcpu->run->io.port = vcpu->pio.port = port; | ||
1479 | vcpu->pio.in = in; | ||
1480 | vcpu->pio.string = 0; | ||
1481 | vcpu->pio.down = 0; | ||
1482 | vcpu->pio.guest_page_offset = 0; | ||
1483 | vcpu->pio.rep = 0; | ||
1484 | |||
1485 | kvm_x86_ops->cache_regs(vcpu); | ||
1486 | memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4); | ||
1487 | kvm_x86_ops->decache_regs(vcpu); | ||
1488 | |||
1489 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
1490 | |||
1491 | pio_dev = vcpu_find_pio_dev(vcpu, port); | ||
1492 | if (pio_dev) { | ||
1493 | kernel_pio(pio_dev, vcpu, vcpu->pio_data); | ||
1494 | complete_pio(vcpu); | ||
1495 | return 1; | ||
1496 | } | ||
1497 | return 0; | ||
1498 | } | ||
1499 | EXPORT_SYMBOL_GPL(kvm_emulate_pio); | ||
1500 | |||
1501 | int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | ||
1502 | int size, unsigned long count, int down, | ||
1503 | gva_t address, int rep, unsigned port) | ||
1504 | { | ||
1505 | unsigned now, in_page; | ||
1506 | int i, ret = 0; | ||
1507 | int nr_pages = 1; | ||
1508 | struct page *page; | ||
1509 | struct kvm_io_device *pio_dev; | ||
1510 | |||
1511 | vcpu->run->exit_reason = KVM_EXIT_IO; | ||
1512 | vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; | ||
1513 | vcpu->run->io.size = vcpu->pio.size = size; | ||
1514 | vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; | ||
1515 | vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = count; | ||
1516 | vcpu->run->io.port = vcpu->pio.port = port; | ||
1517 | vcpu->pio.in = in; | ||
1518 | vcpu->pio.string = 1; | ||
1519 | vcpu->pio.down = down; | ||
1520 | vcpu->pio.guest_page_offset = offset_in_page(address); | ||
1521 | vcpu->pio.rep = rep; | ||
1522 | |||
1523 | if (!count) { | ||
1524 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
1525 | return 1; | ||
1526 | } | ||
1527 | |||
1528 | if (!down) | ||
1529 | in_page = PAGE_SIZE - offset_in_page(address); | ||
1530 | else | ||
1531 | in_page = offset_in_page(address) + size; | ||
1532 | now = min(count, (unsigned long)in_page / size); | ||
1533 | if (!now) { | ||
1534 | /* | ||
1535 | * String I/O straddles page boundary. Pin two guest pages | ||
1536 | * so that we satisfy atomicity constraints. Do just one | ||
1537 | * transaction to avoid complexity. | ||
1538 | */ | ||
1539 | nr_pages = 2; | ||
1540 | now = 1; | ||
1541 | } | ||
1542 | if (down) { | ||
1543 | /* | ||
1544 | * String I/O in reverse. Yuck. Kill the guest, fix later. | ||
1545 | */ | ||
1546 | pr_unimpl(vcpu, "guest string pio down\n"); | ||
1547 | inject_gp(vcpu); | ||
1548 | return 1; | ||
1549 | } | ||
1550 | vcpu->run->io.count = now; | ||
1551 | vcpu->pio.cur_count = now; | ||
1552 | |||
1553 | if (vcpu->pio.cur_count == vcpu->pio.count) | ||
1554 | kvm_x86_ops->skip_emulated_instruction(vcpu); | ||
1555 | |||
1556 | for (i = 0; i < nr_pages; ++i) { | ||
1557 | mutex_lock(&vcpu->kvm->lock); | ||
1558 | page = gva_to_page(vcpu, address + i * PAGE_SIZE); | ||
1559 | vcpu->pio.guest_pages[i] = page; | ||
1560 | mutex_unlock(&vcpu->kvm->lock); | ||
1561 | if (!page) { | ||
1562 | inject_gp(vcpu); | ||
1563 | free_pio_guest_pages(vcpu); | ||
1564 | return 1; | ||
1565 | } | ||
1566 | } | ||
1567 | |||
1568 | pio_dev = vcpu_find_pio_dev(vcpu, port); | ||
1569 | if (!vcpu->pio.in) { | ||
1570 | /* string PIO write */ | ||
1571 | ret = pio_copy_data(vcpu); | ||
1572 | if (ret >= 0 && pio_dev) { | ||
1573 | pio_string_write(pio_dev, vcpu); | ||
1574 | complete_pio(vcpu); | ||
1575 | if (vcpu->pio.count == 0) | ||
1576 | ret = 1; | ||
1577 | } | ||
1578 | } else if (pio_dev) | ||
1579 | pr_unimpl(vcpu, "no string pio read support yet, " | ||
1580 | "port %x size %d count %ld\n", | ||
1581 | port, size, count); | ||
1582 | |||
1583 | return ret; | ||
1584 | } | ||
1585 | EXPORT_SYMBOL_GPL(kvm_emulate_pio_string); | ||
1586 | |||
1344 | __init void kvm_arch_init(void) | 1587 | __init void kvm_arch_init(void) |
1345 | { | 1588 | { |
1346 | kvm_init_msr_list(); | 1589 | kvm_init_msr_list(); |
diff --git a/drivers/kvm/x86.h b/drivers/kvm/x86.h index 5592456c36ad..663b822b4ddb 100644 --- a/drivers/kvm/x86.h +++ b/drivers/kvm/x86.h | |||
@@ -126,4 +126,5 @@ static inline int is_paging(struct kvm_vcpu *vcpu) | |||
126 | } | 126 | } |
127 | 127 | ||
128 | int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3); | 128 | int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3); |
129 | int complete_pio(struct kvm_vcpu *vcpu); | ||
129 | #endif | 130 | #endif |