/
/
static
int
bad_address(void
*
p)
{
unsigned
long
dummy;
return
probe_kernel_address((unsigned
long
*
)p, dummy);
}
/
*
*
map
any
virtual address of the current process to its
*
physical one.
*
/
static unsigned
long
long
any_v2p(unsigned
long
long
vaddr)
{
pgd_t
*
pgd
=
pgd_offset(current
-
>mm, vaddr);
p4d_t
*
p4d;
pud_t
*
pud;
pmd_t
*
pmd;
pte_t
*
pte;
/
*
to lock the page
*
/
struct page
*
pg;
unsigned
long
long
paddr;
if
(bad_address(pgd)) {
printk(KERN_ALERT
"[nskk] Alert: bad address of pgd %p\n"
, pgd);
goto bad;
}
if
(!pgd_present(
*
pgd)) {
printk(KERN_ALERT
"[nskk] Alert: pgd not present %lu\n"
,
*
pgd);
goto out;
}
p4d
=
p4d_offset(pgd, vaddr);
if
(p4d_none(
*
p4d))
return
0
;
pud
=
pud_offset(p4d, vaddr);
pud
=
pud_offset(pgd, vaddr);
if
(bad_address(pud)) {
printk(KERN_ALERT
"[nskk] Alert: bad address of pud %p\n"
, pud);
goto bad;
}
if
(!pud_present(
*
pud) || pud_large(
*
pud)) {
printk(KERN_ALERT
"[nskk] Alert: pud not present %lu\n"
,
*
pud);
goto out;
}
pmd
=
pmd_offset(pud, vaddr);
if
(bad_address(pmd)) {
printk(KERN_ALERT
"[nskk] Alert: bad address of pmd %p\n"
, pmd);
goto bad;
}
if
(!pmd_present(
*
pmd) || pmd_large(
*
pmd)) {
printk(KERN_ALERT
"[nskk] Alert: pmd not present %lu\n"
,
*
pmd);
goto out;
}
pte
=
pte_offset_kernel(pmd, vaddr);
if
(bad_address(pte)) {
printk(KERN_ALERT
"[nskk] Alert: bad address of pte %p\n"
, pte);
goto bad;
}
if
(!pte_present(
*
pte)) {
printk(KERN_ALERT
"[nskk] Alert: pte not present %lu\n"
,
*
pte);
goto out;
}
pg
=
pte_page(
*
pte);
paddr
=
(pte_val(
*
pte) & PHYSICAL_PAGE_MASK) | (vaddr&(PAGE_SIZE
-
1
));
pte
-
>pte |
=
_PAGE_RW;
/
/
| _PAGE_USER;
paddr
=
pte_val(
*
pte);
out:
return
paddr;
bad:
printk(KERN_ALERT
"[nskk] Alert: Bad address\n"
);
return
0
;
}
static
int
virt2phys_open(struct inode
*
inode, struct
file
*
filp)
{
printk(
"%s\n"
, __func__);
return
0
;
}
static ssize_t virt2phys_read(struct
file
*
filp, char __user
*
buf,
size_t count, loff_t
*
ppos)
{
int
copy_len;
printk(
"%s\n"
, __func__);
copy_len
=
0
;
return
copy_len;
}
static ssize_t virt2phys_write(struct
file
*
filp, const char __user
*
buf,
size_t count, loff_t
*
ppos)
{
int
copy_len;
copy_len
=
0
;
return
copy_len;
}
static
int
virt2phys_release(struct inode
*
inode, struct
file
*
filp)
{
printk(
"%s\n"
, __func__);
return
0
;
}
static unsigned
int
virt2phys_poll( struct
file
*
filp, poll_table
*
wait )
{
unsigned
int
retmask
=
0
;
printk(
"%s\n"
, __func__);
retmask |
=
POLLHUP;
/
*
Set
POLLHUP
in
retmask
if
read device
is
EOF
Set
POLLERR
if
the device
is
in
error
Set
POLLPRI
if
out
-
of
-
band data can be read
*
/
return
retmask;
}
static
long
virt2phys_ioctl(struct
file
*
filp,
unsigned
int
cmd, unsigned
long
arg)
{
unsigned
long
long
*
ptr, ret;
printk(
"%s\n"
, __func__);
if
(cmd
=
=
1
) {
ptr
=
(unsigned
long
long
*
)arg;
printk(
"VA=%p\n"
, (unsigned
long
long
*
)
*
ptr);
ret
=
any_v2p(
*
ptr);
printk(
"PA=%p\n"
, (unsigned
long
long
*
)ret);
*
ptr
=
ret;
return
0
;
}
return
-
ENOTTY;
}
static struct file_operations virt2phys_fops
=
{
.owner
=
THIS_MODULE,
.read
=
virt2phys_read,
.write
=
virt2phys_write,
.poll
=
virt2phys_poll,
.unlocked_ioctl
=
virt2phys_ioctl,
.
open
=
virt2phys_open,
.release
=
virt2phys_release,
};
static struct miscdevice virt2phys_dev
=
{
.minor
=
MISC_DYNAMIC_MINOR,
.name
=
DRV_NAME,
.fops
=
&virt2phys_fops,
};
static
int
__init virt2phys_init(void)
{
int
ret;
pr_info(virt2phys_DRIVER_NAME
"\n"
);
printk(
"%s\n"
, __func__);
ret
=
misc_register(&virt2phys_dev);
if
(ret) {
printk(
"fail to misc_register (MISC_DYNAMIC_MINOR)\n"
);
goto error;
}
return
0
;
error:
return
ret;
}
static void __exit virt2phys_cleanup(void)
{
misc_deregister(&virt2phys_dev);
printk(
"%s\n"
, __func__);
}
MODULE_LICENSE(
"GPL"
);
module_init(virt2phys_init);
module_exit(virt2phys_cleanup);