/** * Dirty CMMA attributes of exactly one page in the TEST_DATA memslot, * so use_cmma goes on and the CMMA related ioctls do something.
*/ staticvoid guest_do_one_essa(void)
{ asmvolatile( /* load TEST_DATA_START_GFN into r1 */ " llilf 1,%[start_gfn]\n" /* calculate the address from the gfn */ " sllg 1,1,12(0)\n" /* set the first page in TEST_DATA memslot to STABLE */ " .insn rrf,0xb9ab0000,2,1,1,0\n" /* hypercall */ " diag 0,0,0x501\n" "0: j 0b"
:
: [start_gfn] "L"(TEST_DATA_START_GFN)
: "r1", "r2", "memory", "cc"
);
}
/** * Touch CMMA attributes of all pages in TEST_DATA memslot. Set them to stable * state.
*/ staticvoid guest_dirty_test_data(void)
{ asmvolatile( /* r1 = TEST_DATA_START_GFN */ " xgr 1,1\n" " llilf 1,%[start_gfn]\n" /* r5 = TEST_DATA_PAGE_COUNT */ " lghi 5,%[page_count]\n" /* r5 += r1 */ "2: agfr 5,1\n" /* r2 = r1 << PAGE_SHIFT */ "1: sllg 2,1,12(0)\n" /* essa(r4, r2, SET_STABLE) */ " .insn rrf,0xb9ab0000,4,2,1,0\n" /* i++ */ " agfi 1,1\n" /* if r1 < r5 goto 1 */ " cgrjl 1,5,1b\n" /* hypercall */ " diag 0,0,0x501\n" "0: j 0b"
:
: [start_gfn] "L"(TEST_DATA_START_GFN),
[page_count] "L"(TEST_DATA_PAGE_COUNT)
: /* the counter in our loop over the pages */ "r1", /* the calculated page physical address */ "r2", /* ESSA output register */ "r4", /* last page */ "r5", "cc", "memory"
);
}
staticvoid create_main_memslot(struct kvm_vm *vm)
{ int i;
vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, MAIN_PAGE_COUNT, 0); /* set the array of memslots to zero like __vm_create does */ for (i = 0; i < NR_MEM_REGIONS; i++)
vm->memslots[i] = 0;
}
/* GET_CMMA_BITS without migration mode and without peeking should fail */
rc = vm_get_cmma_bits(vm, 0, &errno_out);
TEST_ASSERT_EQ(rc, -1);
TEST_ASSERT_EQ(errno_out, EINVAL);
/* GET_CMMA_BITS without migration mode and with peeking should work */
rc = vm_get_cmma_bits(vm, KVM_S390_CMMA_PEEK, &errno_out);
TEST_ASSERT_EQ(rc, 0);
TEST_ASSERT_EQ(errno_out, 0);
/* enabling migration mode on a VM without memory should fail */
rc = __enable_migration_mode(vm);
TEST_ASSERT_EQ(rc, -1);
TEST_ASSERT_EQ(errno, EINVAL);
TEST_ASSERT(!is_migration_mode_on(vm), "migration mode should still be off");
errno = 0;
/* * Execute one essa instruction in the guest. Otherwise the guest will * not have use_cmm enabled and GET_CMMA_BITS will return no pages.
*/
vcpu_run(vcpu);
assert_exit_was_hypercall(vcpu);
/* migration mode when memslots have dirty tracking off should fail */
rc = __enable_migration_mode(vm);
TEST_ASSERT_EQ(rc, -1);
TEST_ASSERT_EQ(errno, EINVAL);
TEST_ASSERT(!is_migration_mode_on(vm), "migration mode should still be off");
errno = 0;
/* enabling migration mode should work now */
rc = __enable_migration_mode(vm);
TEST_ASSERT_EQ(rc, 0);
TEST_ASSERT(is_migration_mode_on(vm), "migration mode should be on");
errno = 0;
/* execute another ESSA instruction to see this goes fine */
vcpu->run->psw_addr = orig_psw;
vcpu_run(vcpu);
assert_exit_was_hypercall(vcpu);
/* * With migration mode on, create a new memslot with dirty tracking off. * This should turn off migration mode.
*/
TEST_ASSERT(is_migration_mode_on(vm), "migration mode should be on");
vm_userspace_mem_region_add(vm,
VM_MEM_SRC_ANONYMOUS,
TEST_DATA_TWO_START_GFN << vm->page_shift,
TEST_DATA_TWO_MEMSLOT,
TEST_DATA_TWO_PAGE_COUNT,
0
);
TEST_ASSERT(!is_migration_mode_on(vm), "creating memslot without dirty tracking turns off migration mode"
);
/* ESSA instructions should still execute fine */
vcpu->run->psw_addr = orig_psw;
vcpu_run(vcpu);
assert_exit_was_hypercall(vcpu);
/* * Turn on dirty tracking on the new memslot. * It should be possible to turn migration mode back on again.
*/
vm_mem_region_set_flags(vm, TEST_DATA_TWO_MEMSLOT, KVM_MEM_LOG_DIRTY_PAGES);
rc = __enable_migration_mode(vm);
TEST_ASSERT_EQ(rc, 0);
TEST_ASSERT(is_migration_mode_on(vm), "migration mode should be on");
errno = 0;
/* * Turn off dirty tracking again, this time with just a flag change. * Again, migration mode should turn off.
*/
TEST_ASSERT(is_migration_mode_on(vm), "migration mode should be on");
vm_mem_region_set_flags(vm, TEST_DATA_TWO_MEMSLOT, 0);
TEST_ASSERT(!is_migration_mode_on(vm), "disabling dirty tracking should turn off migration mode"
);
/* ESSA instructions should still execute fine */
vcpu->run->psw_addr = orig_psw;
vcpu_run(vcpu);
assert_exit_was_hypercall(vcpu);
kvm_vm_free(vm);
}
/** * Given a VM with the MAIN and TEST_DATA memslot, assert that both slots have * CMMA attributes of all pages in both memslots and nothing more dirty. * This has the useful side effect of ensuring nothing is CMMA dirty after this * function.
*/ staticvoid assert_all_slots_cmma_dirty(struct kvm_vm *vm)
{ struct kvm_s390_cmma_log args;
/* * First iteration - everything should be dirty. * Start at the main memslot...
*/
args = (struct kvm_s390_cmma_log){
.start_gfn = 0,
.count = sizeof(cmma_value_buf),
.flags = 0,
.values = (__u64)&cmma_value_buf[0]
};
memset(cmma_value_buf, 0xff, sizeof(cmma_value_buf));
vm_ioctl(vm, KVM_S390_GET_CMMA_BITS, &args);
TEST_ASSERT_EQ(args.count, MAIN_PAGE_COUNT);
TEST_ASSERT_EQ(args.remaining, TEST_DATA_PAGE_COUNT);
TEST_ASSERT_EQ(args.start_gfn, 0);
/* ...and then - after a hole - the TEST_DATA memslot should follow */
args = (struct kvm_s390_cmma_log){
.start_gfn = MAIN_PAGE_COUNT,
.count = sizeof(cmma_value_buf),
.flags = 0,
.values = (__u64)&cmma_value_buf[0]
};
memset(cmma_value_buf, 0xff, sizeof(cmma_value_buf));
vm_ioctl(vm, KVM_S390_GET_CMMA_BITS, &args);
TEST_ASSERT_EQ(args.count, TEST_DATA_PAGE_COUNT);
TEST_ASSERT_EQ(args.start_gfn, TEST_DATA_START_GFN);
TEST_ASSERT_EQ(args.remaining, 0);
/* * Execute one essa instruction in the guest. Otherwise the guest will * not have use_cmm enabled and GET_CMMA_BITS will return no pages.
*/
vcpu_run(vcpu);
assert_exit_was_hypercall(vcpu);
/** * Assert the given cmma_log struct that was executed by query_cmma_range() * indicates the first dirty gfn is at first_dirty_gfn and contains exactly * dirty_gfn_count CMMA values.
*/ staticvoid assert_cmma_dirty(u64 first_dirty_gfn,
u64 dirty_gfn_count, conststruct kvm_s390_cmma_log *res)
{
TEST_ASSERT_EQ(res->start_gfn, first_dirty_gfn);
TEST_ASSERT_EQ(res->count, dirty_gfn_count); for (size_t i = 0; i < dirty_gfn_count; i++)
TEST_ASSERT_EQ(cmma_value_buf[0], 0x0); /* stable state */
TEST_ASSERT_EQ(cmma_value_buf[dirty_gfn_count], 0xff); /* not touched */
}
/* * Execute some essa instructions in the guest. Otherwise the guest will * not have use_cmm enabled and GET_CMMA_BITS will return no pages.
*/
vcpu_run(vcpu);
assert_exit_was_hypercall(vcpu);
/* un-dirty all pages */
assert_all_slots_cmma_dirty(vm);
/* Then, dirty just the TEST_DATA memslot */
vcpu->run->psw_addr = orig_psw;
vcpu_run(vcpu);
gfn_offset = TEST_DATA_START_GFN; /** * Query CMMA attributes of one page, starting at page 0. Since the * main memslot was not touched by the VM, this should yield the first * page of the TEST_DATA memslot. * The dirty bitmap should now look like this: * 0: not dirty * [0x1, 0x200): dirty
*/
query_cmma_range(vm, 0, 1, &log);
assert_cmma_dirty(gfn_offset, 1, &log);
gfn_offset++;
/** * Query CMMA attributes of 32 (0x20) pages past the end of the TEST_DATA * memslot. This should wrap back to the beginning of the TEST_DATA * memslot, page 1. * The dirty bitmap should now look like this: * [0, 0x21): not dirty * [0x21, 0x200): dirty
*/
query_cmma_range(vm, TEST_DATA_START_GFN + TEST_DATA_PAGE_COUNT, 0x20, &log);
assert_cmma_dirty(gfn_offset, 0x20, &log);
gfn_offset += 0x20;
/* Skip 32 pages */
gfn_offset += 0x20;
/** * After skipping 32 pages, query the next 32 (0x20) pages. * The dirty bitmap should now look like this: * [0, 0x21): not dirty * [0x21, 0x41): dirty * [0x41, 0x61): not dirty * [0x61, 0x200): dirty
*/
query_cmma_range(vm, gfn_offset, 0x20, &log);
assert_cmma_dirty(gfn_offset, 0x20, &log);
gfn_offset += 0x20;
/** * Query 1 page from the beginning of the TEST_DATA memslot. This should * yield page 0x21. * The dirty bitmap should now look like this: * [0, 0x22): not dirty * [0x22, 0x41): dirty * [0x41, 0x61): not dirty * [0x61, 0x200): dirty
*/
query_cmma_range(vm, TEST_DATA_START_GFN, 1, &log);
assert_cmma_dirty(TEST_DATA_START_GFN + 0x21, 1, &log);
gfn_offset++;
/** * Query 15 (0xF) pages from page 0x23 in TEST_DATA memslot. * This should yield pages [0x23, 0x33). * The dirty bitmap should now look like this: * [0, 0x22): not dirty * 0x22: dirty * [0x23, 0x33): not dirty * [0x33, 0x41): dirty * [0x41, 0x61): not dirty * [0x61, 0x200): dirty
*/
gfn_offset = TEST_DATA_START_GFN + 0x23;
query_cmma_range(vm, gfn_offset, 15, &log);
assert_cmma_dirty(gfn_offset, 15, &log);
/** * Query 17 (0x11) pages from page 0x22 in TEST_DATA memslot. * This should yield page [0x22, 0x33) * The dirty bitmap should now look like this: * [0, 0x33): not dirty * [0x33, 0x41): dirty * [0x41, 0x61): not dirty * [0x61, 0x200): dirty
*/
gfn_offset = TEST_DATA_START_GFN + 0x22;
query_cmma_range(vm, gfn_offset, 17, &log);
assert_cmma_dirty(gfn_offset, 17, &log);
/** * Query 25 (0x19) pages from page 0x40 in TEST_DATA memslot. * This should yield page 0x40 and nothing more, since there are more * than 16 non-dirty pages after page 0x40. * The dirty bitmap should now look like this: * [0, 0x33): not dirty * [0x33, 0x40): dirty * [0x40, 0x61): not dirty * [0x61, 0x200): dirty
*/
gfn_offset = TEST_DATA_START_GFN + 0x40;
query_cmma_range(vm, gfn_offset, 25, &log);
assert_cmma_dirty(gfn_offset, 1, &log);
/** * Query pages [0x33, 0x40). * The dirty bitmap should now look like this: * [0, 0x61): not dirty * [0x61, 0x200): dirty
*/
gfn_offset = TEST_DATA_START_GFN + 0x33;
query_cmma_range(vm, gfn_offset, 0x40 - 0x33, &log);
assert_cmma_dirty(gfn_offset, 0x40 - 0x33, &log);
/** * The kernel may support CMMA, but the machine may not (i.e. if running as * guest-3). * * In this case, the CMMA capabilities are all there, but the CMMA-related * ioctls fail. To find out whether the machine supports CMMA, create a * temporary VM and then query the CMMA feature of the VM.
*/ staticint machine_has_cmma(void)
{ struct kvm_vm *vm = vm_create_barebones(); int r;
r = !__kvm_has_device_attr(vm->fd, KVM_S390_VM_MEM_CTRL, KVM_S390_VM_MEM_ENABLE_CMMA);
kvm_vm_free(vm);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.