// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2025 Samsung Electronics Co., Ltd. * http://www.samsung.com/ */ #include #include "exynos-hvc.h" #include "hvm_drv.h" static ssize_t translate_addr_ops_get_pa(struct file *file, char __user *buf, size_t len, loff_t *offset) { char tmp[64] = {0, }; struct hvm *vm = file->private_data; u64 ipa, pa; u64 ret; if (*offset == 0) { // get translated pa ipa = vm->vm_debug.ipa_requested; ret = exynos_hvc(HVC_FID_HVM_DEBUG, HVM_DEBUG_TRANSLATE_IPA2PA, vm->vm_id, ipa, 0); if (ret == -ENOMEM) { snprintf(tmp, sizeof(tmp), "Invalid address 0x%llx: Outside of vm memory\n", ipa); goto exit; } else if (ret == -EFAULT) { snprintf(tmp, sizeof(tmp), "Invalid address 0x%llx: Not mapped\n", ipa); goto exit; } pa = ret; // Is ipa shared with host? ret = exynos_hvc(HVC_FID_HVM_DEBUG, HVM_DEBUG_IS_SHARED_PAGE, vm->vm_id, ipa, 0); if (ret == -EFAULT) { snprintf(tmp, sizeof(tmp), "Invalid address 0X%llx: Not mapped\n", ipa); goto exit; } snprintf(tmp, sizeof(tmp), "0x%llx -> 0x%llx: %s\n", ipa, pa, (ret ? "Shared w/ host" : "Protected")); exit: if (copy_to_user(buf, tmp, sizeof(tmp))) return -EFAULT; *offset += sizeof(tmp); return sizeof(tmp); } return 0; } static ssize_t translate_addr_ops_set_ipa(struct file *file, const char __user *buf, size_t len, loff_t *offset) { char tmp[64] = {0, }; struct hvm *vm = file->private_data; ssize_t ret = -EFAULT; if (*offset == 0) { // set ipa to be translated if (copy_from_user(tmp, buf, sizeof(tmp))) return -EFAULT; ret = kstrtoull(tmp, 0, &vm->vm_debug.ipa_requested); if (ret) return ret; return len; } return 0; } static const struct file_operations translate_addr_ops = { .open = simple_open, .read = translate_addr_ops_get_pa, .write = translate_addr_ops_set_ipa, }; int hvm_drv_debug_init(void) { debugfs_create_dir(HALLA_KERNEL_DEV_NAME, NULL); return 0; } int hvm_create_vm_debugfs(struct hvm *hvm) { struct dentry *dent, *parent; char dname[16]; snprintf(dname, sizeof(dname), "VM-%d", hvm->vm_id); parent = debugfs_lookup(HALLA_KERNEL_DEV_NAME, NULL); dent = debugfs_create_dir(dname, parent); debugfs_create_file("stage2_ipa_to_pa", 0644, dent, hvm, &translate_addr_ops); dput(parent); return 0; } int hvm_destroy_vm_debugfs(struct hvm *hvm) { struct dentry *parent; char dname[16]; snprintf(dname, sizeof(dname), "VM-%d", hvm->vm_id); parent = debugfs_lookup(HALLA_KERNEL_DEV_NAME, NULL); debugfs_lookup_and_remove(dname, parent); dput(parent); return 0; } void hvm_drv_debug_exit(void) { debugfs_lookup_and_remove(HALLA_KERNEL_DEV_NAME, NULL); }