137 lines
2.7 KiB
C
137 lines
2.7 KiB
C
// 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);
|
||
|
|
}
|