blob: d3b4f2fdd20497dd9b0fcd55eb797d964a92835b [file]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2025 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*/
#include <linux/debugfs.h>
#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);
}