summaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2022-10-20 17:10:44 +0200
committerLouis Burda <quent.burda@gmail.com>2022-10-20 17:10:44 +0200
commit0c0fd49e91a37cfb9538481972b30b0cd4cff16d (patch)
tree811dc67dbbd5643d9bf701d75acae44157712d20 /virt
parent097eb29a8b13b58fcddf254a55cb3754d7759401 (diff)
downloadcachepc-linux-0c0fd49e91a37cfb9538481972b30b0cd4cff16d.tar.gz
cachepc-linux-0c0fd49e91a37cfb9538481972b30b0cd4cff16d.zip
Refactor more code out into repo files
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/kvm_main.c579
1 files changed, 5 insertions, 574 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index bd26b7a29c9e..4c55f85fc775 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -13,6 +13,7 @@
* Yaniv Kamay <yaniv@qumranet.com>
*/
+#include <asm-generic/errno-base.h>
#include <kvm/iodev.h>
#include <linux/kvm_host.h>
@@ -70,9 +71,9 @@
/* Worst case buffer size needed for holding an integer. */
#define ITOA_MAX_LEN 12
-#include "../../arch/x86/kvm/svm/cachepc/kvm.h"
-#include "../../arch/x86/kvm/sevstep/sevstep.h"
-#include "../../arch/x86/kvm/sevstep/uspt.h"
+#include "../../arch/x86/kvm/cachepc/kvm.h"
+#include "../../arch/x86/kvm/cachepc/sevstep.h"
+#include "../../arch/x86/kvm/cachepc/uspt.h"
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
@@ -163,267 +164,6 @@ static unsigned long long kvm_active_vms;
static DEFINE_PER_CPU(cpumask_var_t, cpu_kick_mask);
-static long
-get_user_pages_remote_unlocked(struct mm_struct *mm,
- unsigned long start, unsigned long nr_pages,
- unsigned int gup_flags, struct page **pages)
-{
- struct vm_area_struct **vmas = NULL;
- int locked = 1;
- long ret;
-
- down_read(&mm->mmap_lock);
- ret = get_user_pages_remote( mm, start, nr_pages,
- gup_flags, pages, vmas, &locked);
- if (locked) up_read(&mm->mmap_lock);
-
- return ret;
-}
-
-// static int
-// get_hpa_for_gpa(struct kvm *kvm, gpa_t gpa, hpa_t *hpa)
-// {
-// int ec;
-// unsigned long hva;
-// struct page *page = NULL;
-//
-// ec = 0;
-//
-// hva = gfn_to_hva(kvm, gpa_to_gfn(gpa));
-// if (kvm_is_error_hva(hva)) {
-// pr_warn("in %s line %d get_hpa_for_gpa: translation to hva failed\n",
-// __FILE__, __LINE__);
-// ec = -100;
-// goto out;
-// }
-// if (get_user_pages_remote_unlocked(kvm->mm, hva, 1, 0, &page) != 1) {
-// pr_warn("in %s line %d get_hpa_for_gpa: failed to get page struct from mm",
-// __FILE__, __LINE__);
-// ec = -KVM_EINVAL;
-// goto out;
-// }
-//
-// (*hpa) = (page_to_pfn(page) << 12) + (gpa & 0xfff);
-//
-// out:
-// put_page(page);
-//
-// return ec;
-// }
-
-int
-read_physical(struct kvm *kvm, u64 gpa, void *buff, u64 size,
- bool decrypt_at_host)
-{
- unsigned long hva;
- struct page *page = NULL;
- void *ptr_page = NULL;
- uint64_t offset;
- int ec;
-
- offset = (gpa & 0xFFF);
-
- if ((offset + size - 1) > 0xFFF) {
- printk("read_phyiscal: trying to read "
- "beyond page (offset+size=%016llx)\n",
- offset + size);
- return -EINVAL;
- }
-
- ec = 0;
-
- hva = gfn_to_hva(kvm, gpa_to_gfn(gpa));
-
- // TODO: test change
- /*
- if (kvm_is_error_hva(hva)) {
- printk(KERN_CRIT "Luca: read_physical: translation to hva failed( gpa was "
- "%016llx hva is %016lx\n",
- gpa, hva);
- ec = -100;
- goto out;
- }
- */
-
- if (get_user_pages_remote_unlocked(kvm->mm, hva, 1, 0, &page) != 1) {
- pr_warn("read_physical: failed to get page struct from mm\n");
- // ec = -KVM_EINVAL;
- ec = -100;
- goto out;
- }
-
- if (decrypt_at_host) {
- // map with encryption bit. Content is decrypted with host key. If sev is
- // disabled but sme is enable this allows to read the plaintext.
- ptr_page = vmap(&page, 1, 0, PAGE_KERNEL_NOCACHE);
- } else {
- // map without encryption bit to read ciphertexts
- ptr_page = vmap(&page, 1, 0, __pgprot(__PAGE_KERNEL_NOCACHE));
- }
-
- /*printk("value of buff ptr = %p\t value of ptr_page=%p\n", buff,
- ptr_page + offset);*/
- memcpy(buff, ptr_page + offset, size);
-
-out:
- if (ptr_page)
- vunmap(ptr_page);
- if (page)
- put_page(page);
-
- return ec;
-}
-
-int
-print_physical(struct kvm *kvm, u64 gpa, u64 size, bool decrypt_at_host)
-{
- u8 *buffer;
- int i, err;
-
- buffer = kmalloc(size, GFP_ATOMIC);
-
- err = read_physical(kvm, gpa, buffer, size, decrypt_at_host);
- if (err != 0) {
- pr_warn("at %s line %d: read_physical "
- "failed with: %d\n", __FILE__, __LINE__, err);
- }
- for (i = 0; i < size; i++) {
- // print bytewise with line break every 16 bytes
- if (i % 16 == 0) {
- printk("%02x ", buffer[i]);
- } else {
- printk(KERN_CONT " %02x ", buffer[i]);
- }
- }
- printk("\n");
-
- kfree(buffer);
-
- return err;
-}
-
-int
-map_physical(struct kvm *kvm, u64 gpa, bool decrypt_at_host,
- void **mapping, struct page **page)
-{
-
- int ec;
- unsigned long hva;
- uint64_t offset;
-
- offset = (gpa & 0xFFF);
-
- ec = 0;
-
- hva = gfn_to_hva(kvm, gpa_to_gfn(gpa));
-
- if (get_user_pages_remote_unlocked(kvm->mm, hva, 1, 0, page) != 1) {
- pr_warn("map_physical: failed to get page struct from mm");
- // ec = -KVM_EINVAL;
- ec = -100;
- return ec;
- }
-
- if (decrypt_at_host) {
- // map with encryption bit. Content is decrypted with host key. If sev is
- // disabled but sme is enable this allows to read the plaintext.
- (*mapping) = vmap(page, 1, 0, PAGE_KERNEL);
- } else {
- // map without encryption bit to read ciphertexts
- (*mapping) = vmap(page, 1, 0, __pgprot(__PAGE_KERNEL));
- }
-
- return ec;
-}
-
-void
-unmap_physical(void **mapping, struct page **page)
-{
- if (*mapping)
- vunmap(*mapping);
- if (*page)
- put_page(*page);
-}
-
-int
-read_mapped(u64 gpa, void *buff, u64 size, void *mapping)
-{
- uint64_t offset;
- offset = (gpa & 0xFFF);
-
- if ((offset + size - 1) > 0xFFF) {
- pr_warn("read_mapped: trying to read "
- "beyond page (offset+size=%016llx)\n",
- offset + size);
- return -EINVAL;
- }
- memcpy(buff, mapping + offset, size);
-
- return 0;
-}
-
-int
-write_mapped(u64 gpa, u64 size, const void *buf, void *mapping)
-{
- uint64_t offset;
-
- offset = (gpa & 0xFFF);
-
- if ((offset + size - 1) > 0xFFF) {
- printk("write_physical: trying to write beyond page(offset+size=%016llx)\n",
- offset + size);
- return -EINVAL;
- }
- memcpy(mapping + offset, buf, size);
-
- return 0;
-}
-
-int
-write_physical(struct kvm *kvm, u64 gpa, u64 size,
- const void *buf, bool write_plaintexts)
-{
- int ec;
- unsigned long hva;
- struct page *page;
- void *ptr_page;
- uint64_t offset;
-
- offset = (gpa & 0xFFF);
-
- if ((offset + size - 1) > 0xFFF) {
- pr_warn("write_physical: trying to write "
- "beyond page(offset+size=%016llx)\n",
- offset + size);
- return -EINVAL;
- }
-
- ec = 0;
- hva = gfn_to_hva(kvm, gpa_to_gfn(gpa));
-
- if (kvm_is_error_hva(hva))
- return -KVM_EINVAL;
-
- if (get_user_pages_remote_unlocked(kvm->mm, hva, 1, FOLL_WRITE, &page) != 1)
- return -KVM_EINVAL;
-
- if (write_plaintexts) {
- // map with encrytpion bit to aplly host encryption. Usefull if sev is
- // disabled but sme is enabled and we want to write a certain value into a
- // page
- ptr_page = vmap(&page, 1, 0, PAGE_KERNEL_NOCACHE);
- } else {
- // map without encryption bit to write ciphertexts
- ptr_page = vmap(&page, 1, 0, __pgprot(__PAGE_KERNEL_NOCACHE));
- }
-
- memcpy(ptr_page + offset, buf, size);
-
- vunmap(ptr_page);
- put_page(page);
- return ec;
-}
-
__weak void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
unsigned long start, unsigned long end)
{
@@ -5107,315 +4847,6 @@ static long kvm_dev_ioctl(struct file *filp,
long r = -EINVAL;
switch (ioctl) {
- case KVM_TRACK_PAGE: {
- track_page_param_t param;
- void __user* argp = (void __user *)arg;
- struct kvm_vcpu *vcpu;
-
- if (copy_from_user(&param, argp, sizeof(param))) {
- pr_warn("KVM_TRACK_PAGE: error copying arguments, exiting\n");
- return -EFAULT;
- }
-
- if (main_vm == NULL) {
- pr_warn("KVM_TRACK_PAGE: main_vm is not initialized, aborting!\n");
- return -EFAULT;
- }
-
- if (param.track_mode < 0 || param.track_mode >= KVM_PAGE_TRACK_MAX) {
- pr_warn("KVM_TRACK_PAGE track_mode %d invalid, "
- "must be in range [%d,%d]", param.track_mode,
- 0, KVM_PAGE_TRACK_MAX);
- return -EFAULT;
- }
-
- vcpu = xa_load(&main_vm->vcpu_array, 0);
- if (!sevstep_track_single_page(vcpu,
- param.gpa >> PAGE_SHIFT, param.track_mode)) {
- printk("KVM_TRACK_PAGE: sevstep_track_single_page failed");
- }
- r = 0;
- }
- break;
- case KVM_USPT_BATCH_TRACK_START: {
- batch_track_config_t param;
- void __user* argp = (void __user *)arg;
-
- if (copy_from_user(&param, argp, sizeof(param))) {
- pr_warn("KVM_USPT_BATCH_TRACK_START: "
- "error copying arguments, exiting\n");
- return -EFAULT;
- }
-
- r = sevstep_uspt_batch_tracking_start(param.tracking_type,
- param.expected_events, param.perf_cpu, param.retrack);
- if (r != 0) {
- pr_warn("KVM_USPT_BATCH_TRACK_START: failed\n");
- return r;
- }
- }
- break;
- case KVM_USPT_BATCH_TRACK_EVENT_COUNT: {
- batch_track_event_count_t result;
- void __user* argp = (void __user *)arg;
-
- result.event_count = sevstep_uspt_batch_tracking_get_events_count();
-
- if (copy_to_user(argp, &result, sizeof(result))) {
- pr_warn("KVM_USPT_BATCH_TRACK_EVENT_COUNT: "
- "error copying result to user, exiting\n");
- return -EFAULT;
- }
-
- r = 0;
- }
- break;
- case KVM_USPT_BATCH_TRACK_STOP: {
- batch_track_stop_and_get_t param;
- page_fault_event_t* buf;
- uint64_t buf_bytes;
- void __user* argp = (void __user *)arg;
- void __user* inner_user_out_buf;
-
- if (copy_from_user(&param, argp, sizeof(param))) {
- pr_warn("KVM_USPT_BATCH_TRACK_STOP: "
- "error copying arguments, exiting\n");
- return -EFAULT;
- }
- inner_user_out_buf = param.out_buf;
-
- buf_bytes = sizeof(page_fault_event_t)*param.len;
- pr_warn("KVM_USPT_BATCH_TRACK_STOP: "
- "allocating %llu bytes for tmp buf\n", buf_bytes);
-
- buf = vmalloc(buf_bytes);
- if (buf == NULL) {
- pr_warn("KVM_USPT_BATCH_TRACK_STOP: "
- "failed to alloc tmp buf\n");
- return -EFAULT;
- }
- param.out_buf = buf;
-
- r = sevstep_uspt_batch_tracking_stop(buf, param.len,
- &param.error_during_batch);
- if (r != 0) {
- pr_warn("KVM_USPT_BATCH_TRACK_STOP: failed\n");
- vfree(buf);
- return -EFAULT;
- }
-
- if (copy_to_user(argp, &param, sizeof(param))) {
- pr_warn("KVM_USPT_BATCH_TRACK_STOP: "
- "error copying result to user, exiting\n");
- vfree(buf);
- return -EFAULT;
- }
-
- if (copy_to_user(inner_user_out_buf, buf,buf_bytes)) {
- pr_warn("KVM_USPT_BATCH_TRACK_STOP: "
- "error copying result to user, exiting\n");
- vfree(buf);
- return -EFAULT;
- }
-
- vfree(buf);
- }
- break;
- case KVM_USPT_TRACK_ALL: {
- track_all_pages_t param;
- void __user* argp = (void __user *)arg;
- struct kvm_vcpu *vcpu;
- long tracked_pages;
-
- if (copy_from_user(&param, argp, sizeof(param))) {
- pr_warn("KVM_USPT_TRACK_ALL: error copying arguments, exiting\n");
- return -EFAULT;
- }
-
- if (main_vm == NULL) {
- pr_warn("KVM_USPT_TRACK_ALL: main_vm is not initialized, aborting!\n");
- return -EFAULT;
- }
-
- if (param.track_mode < 0 || param.track_mode >= KVM_PAGE_TRACK_MAX) {
- pr_warn("KVM_USPT_TRACK_ALL: "
- "track_mode %d invalid, must be in range [%d,%d]\n",
- param.track_mode, 0, KVM_PAGE_TRACK_MAX);
- return -EFAULT;
- }
-
- vcpu = xa_load(&main_vm->vcpu_array, 0);
- tracked_pages = sevstep_start_tracking(vcpu, param.track_mode);
- r = 0;
- }
- break;
- case KVM_USPT_UNTRACK_ALL: {
- track_all_pages_t param;
- void __user* argp = (void __user *)arg;
- struct kvm_vcpu *vcpu;
- long untrack_count;
-
- if (copy_from_user(&param, argp, sizeof(param))) {
- printk(KERN_CRIT
- "KVM_USPT_UNTRACK_ALL: error copying arguments, exiting\n");
- return -EFAULT;
- }
-
- if (main_vm == NULL) {
- printk("KVM_USPT_UNTRACK_ALL: main_vm is not initialized, aborting!\n");
- return -EFAULT;
- }
-
- if (param.track_mode < 0 || param.track_mode >= KVM_PAGE_TRACK_MAX) {
- printk("KVM_USPT_UNTRACK_ALL: track_mode %d invalid, must be in range [%d,%d]",param.track_mode,0,KVM_PAGE_TRACK_MAX);
- return -EFAULT;
- }
-
- //printk("KVM_USPT_UNTRACK_ALL: with mode %d\n",param.track_mode);
- vcpu = xa_load(&main_vm->vcpu_array, 0);
- untrack_count = sevstep_stop_tracking(vcpu, param.track_mode);
- //printk("KVM_USPT_UNTRACK_ALL: untracked %ld pages\n",untrack_count);
- r = 0;
- }
- break;
- case KVM_USPT_SETUP_RETINSTR_PERF: {
- retired_instr_perf_config_t config;
- void __user* argp = (void __user *)arg;
-
- printk("Received KVM_USPT_SETUP_RETINSTR_PERF ioctl!\n");
- if (copy_from_user(&config, argp, sizeof(config))) {
- printk("copy from user failed\n");
- return -EACCES;
- }
-
- cachepc_init_pmc(0, 0xc0, 0x00, PMC_GUEST, PMC_KERNEL | PMC_USER);
-
- r = 0;
- }
- break;
- case KVM_USPT_READ_RETINSTR_PERF: {
- retired_instr_perf_t request;
- void __user* argp = (void __user *)arg;
-
- if (copy_from_user(&request, argp, sizeof(request))) {
- printk("KVM_USPT_READ_RETINSTR_PERF: copy from user failed\n");
- return -EACCES;
- }
-
- request.retired_instruction_count = cachepc_read_pmc(0);
- if (copy_to_user(argp, &request, sizeof(request))) {
- printk("KVM_USPT_READ_RETINSTR_PERF : copy to user failed\n");
- }
- r = 0;
- }
- break;
- case KVM_READ_GUEST_MEMORY: {
- read_guest_memory_t param;
- int res;
- void * buf;
- void __user* argp = (void __user *)arg;
-
- if (copy_from_user(&param, argp, sizeof(read_guest_memory_t))) {
- printk(KERN_CRIT
- "KVM_READ_GUEST_MEMORY: error copying arguments, exiting\n");
- return -EFAULT;
- }
-
- if (param.len > PAGE_SIZE) {
- printk("KVM_READ_GUEST_MEMORY len may be at most page size");
- }
-
- buf = kmalloc(param.len, GFP_KERNEL);
- if (buf == NULL) {
- printk("KVM_READ_GUEST_MEMORY: failed to alloc memory");
- return -ENOMEM;
- }
-
- if (param.wbinvd_cpu >= 0) {
- wbinvd_on_cpu(param.wbinvd_cpu);
- }
- wbinvd_on_all_cpus();
-
- res = read_physical(main_vm, param.gpa, buf,
- param.len, param.decrypt_with_host_key);
- if (res) {
- printk("KVM_READ_GUEST_MEMORY: read_physical failed with %d\n", res);
- return -EINVAL;
- }
-
- if (copy_to_user(param.output_buffer, buf, param.len)) {
- printk("KVM_READ_GUEST_MEMORY: failed to copy buf to userspace");
- }
-
- return 0;
- }
- break;
- case KVM_USPT_RESET: {
- struct kvm_vcpu *vcpu;
-
- printk("Received KVM_USPT_RESET ioctl!\n");
-
- sevstep_uspt_clear();
- vcpu = xa_load(&main_vm->vcpu_array, 0);
- sevstep_stop_tracking(vcpu, KVM_PAGE_TRACK_EXEC);
- sevstep_stop_tracking(vcpu, KVM_PAGE_TRACK_ACCESS);
- sevstep_stop_tracking(vcpu, KVM_PAGE_TRACK_WRITE);
- r = 0;
- }
- break;
- case KVM_USPT_REGISTER_PID: {
- userspace_ctx_t ctx;
- void __user* argp = (void __user *)arg;
- struct kvm_vcpu *vcpu;
-
- printk("Received REGISTER_PID ioctl!\n");
- if (copy_from_user(&ctx, argp, sizeof(userspace_ctx_t))) {
- printk("copy from user failed\n");
- return -EACCES;
- }
-
- if (main_vm == NULL) {
- printk("KVM_TRACK_PAGE: main_vm is not initialized, aborting!\n");
- return -EFAULT;
- }
-
- sevstep_uspt_clear();
- sevstep_uspt_initialize(ctx.pid, ctx.get_rip);
-
- printk("Resetting page tracking\n");
- vcpu = xa_load(&main_vm->vcpu_array, 0);
- sevstep_stop_tracking(vcpu, KVM_PAGE_TRACK_EXEC);
- sevstep_stop_tracking(vcpu, KVM_PAGE_TRACK_ACCESS);
- sevstep_stop_tracking(vcpu, KVM_PAGE_TRACK_WRITE);
-
- return 0;
- }
- break;
- case KVM_USPT_POLL_EVENT: {
- void __user* argp = (void __user *)arg;
- if (!sevstep_uspt_is_initialiized()) {
- printk("userspace context not initilaized, call REGISTER_PID");
- return -EINVAL;
- }
- return sevstep_uspt_handle_poll_event(argp);
- }
- break;
- case KVM_USPT_ACK_EVENT: {
- ack_event_t ack_event;
- void __user* argp = (void __user *)arg;
-
- if (!sevstep_uspt_is_initialiized()) {
- printk("userspace context not initilaized, call REGISTER_PID");
- return -EINVAL;
- }
- if (copy_from_user(&ack_event, argp, sizeof(ack_event_t))) {
- printk("ACK_EVENT failed to copy args");
- return -EINVAL;
- }
-
- return sevstep_uspt_handle_ack_event_ioctl(ack_event);
- }
- break;
case KVM_GET_API_VERSION:
if (arg)
goto out;
@@ -5444,7 +4875,7 @@ static long kvm_dev_ioctl(struct file *filp,
r = -EOPNOTSUPP;
break;
default:
- return kvm_arch_dev_ioctl(filp, ioctl, arg);
+ return cachepc_kvm_ioctl(filp, ioctl, arg);
}
out:
return r;