How can I convert user virtual address to kernel virtual address and then to physical address?
ckim at etri.re.kr
ckim at etri.re.kr
Sun Jul 25 22:15:53 EDT 2021
Hi, all,
I'm testing a simple character driver on qemu arm64 virtual machine.
I have uint64_t args[32] array and I pass args to the ioctl data.
By the way args[2] contains the address of test_val which is set to 77. I
want to change this value to 78 in the driver using kernel virtual address.
(ultimately I want to get the physical address of test_val and pass it to
the qemu hardware model).
I read I can change user virtual address to kernel land virtual address
using get_user_pages function and then I can use virt_to_phys function to
get the physical address from kernel land virtual address.
(please correct me if I'm wrong)
When I try to write 78 at the kernel virtual address for test_val, trap
occurs.
## app.c ##
uint64_t __attribute__(( aligned(64) )) args[32];
uint64_t test_val = 77;
args[2] = (uint64_t) &test_val; // let's see it's changed to 78
printf("app : args[2] = %p, *args[2] = %lld\n", args[2], *(uint64_t
*)args[2]);
ioctl(fd, CallSetBareMetalMode, (uint64_t)args);
### driver.c ###
static long my_ioctl(struct file *file, unsigned int cmd, unsigned long
arg)
{
switch(cmd) {
case CallSetBareMetalMode:
printk("driver:cmd = %x, arg = %lx\n", cmd, arg);
copy_from_user(&args, (void __user *)arg, 8*3);
printk("args[2] = %llx\n", args[2]);
offs = args[2] % 4096;
down_read(¤t->mm->mmap_sem);
res = get_user_pages( (unsigned long)args[2], 1, 1, &pages,
NULL);
printk("get_user_pages done! args[2] = %px\n", args[2]);
if (res) {
printk(KERN_INFO "Got mmaped.\n");
kvpaddr = kmap(pages);
printk("kmap done!\n");
printk(KERN_INFO "kvpaddr = %px, ofs = %x\n", kvpaddr,
offs);
printk("xx = %llx\n", ((unsigned long long
int)(kvpaddr)+offs));
*(uint64_t *)((unsigned long long int)(kvpaddr)+offs) = 78;
printk(KERN_INFO "changed value : %lld\n",\
*(uint64_t *)((unsigned int)(kvpaddr)+offs));
put_page(pages); //page_cache_release(page);
printk("put_page done!\n");
}
else {
printk("get_user_pages failed!\n");
}
up_read(¤t->mm->mmap_sem);
### run output ###
args = 0x442f40
app : args[0] = 0x443040
app : args[2] = 0xffffd2e44d98, *args[2] = 77
[85194.544029] driver:cmd = 40086142, arg = 442f40
[85194.544822] args[2] = ffffd2e44d98
[85194.545613] get_user_pages done! args[2] = 0000ffffd2e44d98
[85194.546004] Got mmaped.
[85194.546248] kmap done!
[85194.546536] kvpaddr = ffff00001f7c0000, ofs = d98
[85194.546976] kvaddr = ffff00001f7c0d98
[85194.548645] Unable to handle kernel paging request at virtual address
000000001f7c0d98
[85194.549245] Mem abort info:
[85194.549513] ESR = 0x96000006
[85194.549929] EC = 0x25: DABT (current EL), IL = 32 bits
[85194.550364] SET = 0, FnV = 0
[85194.550719] EA = 0, S1PTW = 0
[85194.551008] Data abort info:
[85194.551555] ISV = 0, ISS = 0x00000006
[85194.551938] CM = 0, WnR = 0
[85194.552609] user pgtable: 4k pages, 48-bit VAs, pgdp=00000000568fb000
[85194.553441] [000000001f7c0d98] pgd=0000000056209003,
pud=0000000047b97003, pmd=0000000000000000
[85194.555783] Internal error: Oops: 96000006 [#16] SMP
[85194.556761] Modules linked in: chr_drv_ex1(OE) nls_iso8859_1
dm_multipath scsi_dh_rdac scsi_dh_emc scsi_dh_alua qemu_fw_cfg sch_fq_codel
ppdev lp parport drm ip_tables x_tables autofs4 btrfs zstd_compress raid10
raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor
xor_neon raid6_pq libcrc32c raid1 raid0 multipath linear crct10dif_ce
ghash_ce sm4_ce sm4_generic sm3_ce sm3_generic sha3_ce sha3_generic
sha512_ce sha512_arm64 sha2_ce sha256_arm64 sha1_ce virtio_net net_failover
virtio_blk failover aes_neon_bs aes_neon_blk aes_ce_blk crypto_simd cryptd
aes_ce_cipher [last unloaded: chr_drv_ex1]
[85194.563741] CPU: 2 PID: 4258 Comm: test_axpu_app Tainted: G D W
OE 5.4.0-77-generic #86-Ubuntu
[85194.564638] Hardware name: QEMU QEMU Ab21q Virtual Machine, BIOS
0.0.0 02/06/2015
[85194.565687] pstate: 60400005 (nZCv daif +PAN -UAO)
[85194.568143] pc : my_ioctl+0x310/0x370 [chr_drv_ex1]
[85194.568854] lr : my_ioctl+0x300/0x370 [chr_drv_ex1]
[85194.569473] sp : ffff80001372bd30
[85194.569838] x29: ffff80001372bd30 x28: ffff000009f7bc00
[85194.570354] x27: 0000000000000000 x26: 0000000000000000
[85194.570796] x25: 0000000056000000 x24: ffff00000d3c35e0
[85194.571308] x23: ffff000016875600 x22: 0000000000000d98
[85194.571870] x21: 000000001f7c0d98 x20: 0000000000442f40
[85194.572273] x19: ffff00001f7c0000 x18: 0000000000000010
[85194.572669] x17: 0000000000000000 x16: 0000000000000000
[85194.573126] x15: ffff000009f7c128 x14: ffffffffffffffff
[85194.573632] x13: ffff80009372ba77 x12: ffff80001372ba7f
[85194.574127] x11: ffff800011b9e000 x10: 0000000000000000
[85194.574578] x9 : ffff800011db4000 x8 : 00000000000005f2
[85194.575193] x7 : 0000000000000017 x6 : ffff800011db39d4
[85194.575700] x5 : 0000000000000000 x4 : ffff00001feb5250
[85194.576139] x3 : ffff00001fec56c8 x2 : 0000000000000000
[85194.576550] x1 : 0000000000000000 x0 : ffff80000924b220
[85194.577379] Call trace:
[85194.577805] my_ioctl+0x310/0x370 [chr_drv_ex1]
[85194.579423] do_vfs_ioctl+0xc64/0xe60
[85194.579846] ksys_ioctl+0x88/0xb8
[85194.580116] __arm64_sys_ioctl+0x2c/0x228
[85194.580479] el0_svc_common.constprop.0+0xe4/0x1f0
[85194.580929] el0_svc_handler+0x38/0xa8
[85194.581293] el0_svc+0x10/0x2c8
[85194.582065] Code: d28009c0 f8336ac0 b0000000 91088000 (f94002a1)
[85194.583646] ---[ end trace bd1ac75ca265aec2 ]---
[85194.590696] Device File closed..
Segmentation fault (core dumped)
I thought I changed the user virtual address to kernel virtual address, but
writing to the kernel virtual address causes trap.
Can anyone help me with finding what is wrong here?
Thank you for reading.
Chan Kim
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.kernelnewbies.org/pipermail/kernelnewbies/attachments/20210726/f56ff6c5/attachment-0001.html>
More information about the Kernelnewbies
mailing list