add pager requests for device mapping
- PAGER_REQ_MAP map specified file, and create a private device pager. - PAGER_REQ_UNMAP destroy specified private device pager, and unmap related mapping. - PAGER_REQ_PFN report a physical address.
This commit is contained in:
@@ -747,6 +747,9 @@ struct pager {
|
|||||||
int ref;
|
int ref;
|
||||||
struct file * rofile;
|
struct file * rofile;
|
||||||
struct file * rwfile;
|
struct file * rwfile;
|
||||||
|
uintptr_t map_uaddr;
|
||||||
|
size_t map_len;
|
||||||
|
off_t map_off;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1069,6 +1072,165 @@ out:
|
|||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct pager_map_result {
|
||||||
|
uintptr_t handle;
|
||||||
|
int maxprot;
|
||||||
|
int8_t padding[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pager_req_map(ihk_os_t os, int fd, size_t len, off_t off, uintptr_t result_rpa)
|
||||||
|
{
|
||||||
|
const ihk_device_t dev = ihk_os_to_dev(os);
|
||||||
|
const off_t pgoff = off / PAGE_SIZE;
|
||||||
|
int error;
|
||||||
|
struct file *file = NULL;
|
||||||
|
uintptr_t va = -1;
|
||||||
|
int maxprot;
|
||||||
|
struct pager *pager = NULL;
|
||||||
|
struct pager_map_result *resp;
|
||||||
|
uintptr_t phys;
|
||||||
|
|
||||||
|
printk("pager_req_map(%p,%d,%lx,%lx,%lx)\n", os, fd, len, off, result_rpa);
|
||||||
|
pager = kzalloc(sizeof(*pager), GFP_KERNEL);
|
||||||
|
if (!pager) {
|
||||||
|
error = -ENOMEM;
|
||||||
|
printk("pager_req_map(%p,%d,%lx,%lx,%lx):kzalloc failed. %d\n", os, fd, len, off, result_rpa, error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = fget(fd);
|
||||||
|
if (!file) {
|
||||||
|
error = -EBADF;
|
||||||
|
printk("pager_req_map(%p,%d,%lx,%lx,%lx):fget failed. %d\n", os, fd, len, off, result_rpa, error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
maxprot = 0;
|
||||||
|
if (file->f_mode & FMODE_READ) {
|
||||||
|
maxprot |= PROT_READ;
|
||||||
|
}
|
||||||
|
if (file->f_mode & FMODE_WRITE) {
|
||||||
|
maxprot |= PROT_WRITE;
|
||||||
|
}
|
||||||
|
if (!(file->f_path.mnt->mnt_flags & MNT_NOEXEC)) {
|
||||||
|
maxprot |= PROT_EXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
down_write(¤t->mm->mmap_sem);
|
||||||
|
#define ANY_WHERE 0
|
||||||
|
va = do_mmap_pgoff(file, ANY_WHERE, len, maxprot, MAP_SHARED, pgoff);
|
||||||
|
up_write(¤t->mm->mmap_sem);
|
||||||
|
if (IS_ERR_VALUE(va)) {
|
||||||
|
printk("pager_req_map(%p,%d,%lx,%lx,%lx):do_mmap_pgoff failed. %d\n", os, fd, len, off, result_rpa, (int)va);
|
||||||
|
error = va;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pager->ref = 1;
|
||||||
|
pager->map_uaddr = va;
|
||||||
|
pager->map_len = len;
|
||||||
|
pager->map_off = off;
|
||||||
|
|
||||||
|
phys = ihk_device_map_memory(dev, result_rpa, sizeof(*resp));
|
||||||
|
resp = ihk_device_map_virtual(dev, phys, sizeof(*resp), NULL, 0);
|
||||||
|
resp->handle = (uintptr_t)pager;
|
||||||
|
resp->maxprot = maxprot;
|
||||||
|
ihk_device_unmap_virtual(dev, resp, sizeof(*resp));
|
||||||
|
ihk_device_unmap_memory(dev, phys, sizeof(*resp));
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
pager = 0; /* pager should be in list? */
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (file) {
|
||||||
|
fput(file);
|
||||||
|
}
|
||||||
|
if (pager) {
|
||||||
|
kfree(pager);
|
||||||
|
}
|
||||||
|
printk("pager_req_map(%p,%d,%lx,%lx,%lx): %d\n", os, fd, len, off, result_rpa, error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pager_req_pfn(ihk_os_t os, uintptr_t handle, off_t off, uintptr_t ppfn_rpa)
|
||||||
|
{
|
||||||
|
const ihk_device_t dev = ihk_os_to_dev(os);
|
||||||
|
struct pager * const pager = (void *)handle;
|
||||||
|
int error;
|
||||||
|
uintptr_t pfn;
|
||||||
|
uintptr_t va;
|
||||||
|
pgd_t *pgd;
|
||||||
|
pud_t *pud;
|
||||||
|
pmd_t *pmd;
|
||||||
|
pte_t *pte;
|
||||||
|
uintptr_t phys;
|
||||||
|
uintptr_t *ppfn;
|
||||||
|
|
||||||
|
printk("pager_req_pfn(%p,%lx,%lx)\n", os, handle, off);
|
||||||
|
|
||||||
|
if ((off < pager->map_off) || ((pager->map_off+pager->map_len) < (off + PAGE_SIZE))) {
|
||||||
|
error = -ERANGE;
|
||||||
|
pfn = 0;
|
||||||
|
printk("pager_req_pfn(%p,%lx,%lx):out of range. %d [%lx..%lx)\n", os, handle, off, error, pager->map_off, pager->map_off+pager->map_len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
va = pager->map_uaddr + (off - pager->map_off);
|
||||||
|
#define PFN_VALID ((uintptr_t)1 << 63)
|
||||||
|
pfn = PFN_VALID; /* デフォルトは not present */
|
||||||
|
|
||||||
|
down_read(¤t->mm->mmap_sem);
|
||||||
|
pgd = pgd_offset(current->mm, va);
|
||||||
|
if (!pgd_none(*pgd) && !pgd_bad(*pgd) && pgd_present(*pgd)) {
|
||||||
|
pud = pud_offset(pgd, va);
|
||||||
|
if (!pud_none(*pud) && !pud_bad(*pud) && pud_present(*pud)) {
|
||||||
|
pmd = pmd_offset(pud, va);
|
||||||
|
if (!pmd_none(*pmd) && !pmd_bad(*pmd) && pmd_present(*pmd)) {
|
||||||
|
pte = pte_offset_map(pmd, va);
|
||||||
|
if (!pte_none(*pte) && pte_present(*pte)) {
|
||||||
|
pfn = (uintptr_t)pte_pfn(*pte) << PAGE_SHIFT;
|
||||||
|
#define PFN_PRESENT ((uintptr_t)1 << 0)
|
||||||
|
pfn |= PFN_VALID | PFN_PRESENT;
|
||||||
|
}
|
||||||
|
pte_unmap(pte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
up_read(¤t->mm->mmap_sem);
|
||||||
|
|
||||||
|
phys = ihk_device_map_memory(dev, ppfn_rpa, sizeof(*ppfn));
|
||||||
|
ppfn = ihk_device_map_virtual(dev, phys, sizeof(*ppfn), NULL, 0);
|
||||||
|
*ppfn = pfn;
|
||||||
|
ihk_device_unmap_virtual(dev, ppfn, sizeof(*ppfn));
|
||||||
|
ihk_device_unmap_memory(dev, phys, sizeof(*ppfn));
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
out:
|
||||||
|
printk("pager_req_pfn(%p,%lx,%lx): %d %lx\n", os, handle, off, error, pfn);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pager_req_unmap(ihk_os_t os, uintptr_t handle)
|
||||||
|
{
|
||||||
|
struct pager * const pager = (void *)handle;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
printk("pager_req_unmap(%p,%lx)\n", os, handle);
|
||||||
|
|
||||||
|
down_write(¤t->mm->mmap_sem);
|
||||||
|
error = do_munmap(current->mm, pager->map_uaddr, pager->map_len);
|
||||||
|
up_write(¤t->mm->mmap_sem);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
printk("pager_req_unmap(%p,%lx):do_munmap failed. %d\n", os, handle, error);
|
||||||
|
/* through */
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree(pager);
|
||||||
|
printk("pager_req_unmap(%p,%lx): %d\n", os, handle, error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
static long pager_call(ihk_os_t os, struct syscall_request *req)
|
static long pager_call(ihk_os_t os, struct syscall_request *req)
|
||||||
{
|
{
|
||||||
long ret;
|
long ret;
|
||||||
@@ -1079,6 +1241,9 @@ static long pager_call(ihk_os_t os, struct syscall_request *req)
|
|||||||
#define PAGER_REQ_RELEASE 0x0002
|
#define PAGER_REQ_RELEASE 0x0002
|
||||||
#define PAGER_REQ_READ 0x0003
|
#define PAGER_REQ_READ 0x0003
|
||||||
#define PAGER_REQ_WRITE 0x0004
|
#define PAGER_REQ_WRITE 0x0004
|
||||||
|
#define PAGER_REQ_MAP 0x0005
|
||||||
|
#define PAGER_REQ_PFN 0x0006
|
||||||
|
#define PAGER_REQ_UNMAP 0x0007
|
||||||
case PAGER_REQ_CREATE:
|
case PAGER_REQ_CREATE:
|
||||||
ret = pager_req_create(os, req->args[1], req->args[2]);
|
ret = pager_req_create(os, req->args[1], req->args[2]);
|
||||||
break;
|
break;
|
||||||
@@ -1095,8 +1260,21 @@ static long pager_call(ihk_os_t os, struct syscall_request *req)
|
|||||||
ret = pager_req_write(os, req->args[1], req->args[2], req->args[3], req->args[4]);
|
ret = pager_req_write(os, req->args[1], req->args[2], req->args[3], req->args[4]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PAGER_REQ_MAP:
|
||||||
|
ret = pager_req_map(os, req->args[1], req->args[2], req->args[3], req->args[4]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PAGER_REQ_PFN:
|
||||||
|
ret = pager_req_pfn(os, req->args[1], req->args[2], req->args[3]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PAGER_REQ_UNMAP:
|
||||||
|
ret = pager_req_unmap(os, req->args[1]);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ret = -ENOSYS;
|
ret = -ENOSYS;
|
||||||
|
printk("pager_call(%#lx):unknown req %ld\n", req->args[0], ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ enum pager_op {
|
|||||||
PAGER_REQ_RELEASE = 0x0002,
|
PAGER_REQ_RELEASE = 0x0002,
|
||||||
PAGER_REQ_READ = 0x0003,
|
PAGER_REQ_READ = 0x0003,
|
||||||
PAGER_REQ_WRITE = 0x0004,
|
PAGER_REQ_WRITE = 0x0004,
|
||||||
|
PAGER_REQ_MAP = 0x0005,
|
||||||
|
PAGER_REQ_PFN = 0x0006,
|
||||||
|
PAGER_REQ_UNMAP = 0x0007,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -36,4 +39,17 @@ struct pager_create_result {
|
|||||||
/*
|
/*
|
||||||
* int pager_req_read(uintptr_t handle, off_t off, size_t size, uintptr_t buf_rpa);
|
* int pager_req_read(uintptr_t handle, off_t off, size_t size, uintptr_t buf_rpa);
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
struct pager_map_result {
|
||||||
|
uintptr_t handle;
|
||||||
|
int maxprot;
|
||||||
|
int8_t padding[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* for pager_req_pfn() */
|
||||||
|
#define PFN_VALID ((uintptr_t)1 << 63)
|
||||||
|
#define PFN_PRESENT ((uintptr_t)1 << 0)
|
||||||
|
#define PFN_PFN ((((uintptr_t)1 << 56) - 1) & ~(PAGE_SIZE - 1))
|
||||||
|
|
||||||
#endif /* HEADER_PAGER_H */
|
#endif /* HEADER_PAGER_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user