1 /* file.c
2  *
3  * Copyright (C) 2010 - 2013 UNISYS CORPORATION
4  * All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or (at
9  * your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14  * NON INFRINGEMENT.  See the GNU General Public License for more
15  * details.
16  */
17 
18 /* This contains the implementation that allows a usermode program to
19  * communicate with the visorchipset driver using a device/file interface.
20  */
21 
22 #include "globals.h"
23 #include "visorchannel.h"
24 #include <linux/mm.h>
25 #include <linux/fs.h>
26 #include "uisutils.h"
27 #include "file.h"
28 
29 #define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c
30 
31 static struct cdev file_cdev;
32 static struct visorchannel **file_controlvm_channel;
33 
34 void
visorchipset_file_cleanup(dev_t major_dev)35 visorchipset_file_cleanup(dev_t major_dev)
36 {
37 	if (file_cdev.ops != NULL)
38 		cdev_del(&file_cdev);
39 	file_cdev.ops = NULL;
40 	unregister_chrdev_region(major_dev, 1);
41 }
42 
43 static int
visorchipset_open(struct inode * inode,struct file * file)44 visorchipset_open(struct inode *inode, struct file *file)
45 {
46 	unsigned minor_number = iminor(inode);
47 
48 	if (minor_number != 0)
49 		return -ENODEV;
50 	file->private_data = NULL;
51 	return 0;
52 }
53 
54 static int
visorchipset_release(struct inode * inode,struct file * file)55 visorchipset_release(struct inode *inode, struct file *file)
56 {
57 	return 0;
58 }
59 
60 static int
visorchipset_mmap(struct file * file,struct vm_area_struct * vma)61 visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
62 {
63 	ulong physaddr = 0;
64 	ulong offset = vma->vm_pgoff << PAGE_SHIFT;
65 	GUEST_PHYSICAL_ADDRESS addr = 0;
66 
67 	/* sv_enable_dfp(); */
68 	if (offset & (PAGE_SIZE - 1))
69 		return -ENXIO;	/* need aligned offsets */
70 
71 	switch (offset) {
72 	case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
73 		vma->vm_flags |= VM_IO;
74 		if (*file_controlvm_channel == NULL) {
75 			return -ENXIO;
76 		}
77 		visorchannel_read(*file_controlvm_channel,
78 			offsetof(struct spar_controlvm_channel_protocol,
79 				 gp_control_channel),
80 			&addr, sizeof(addr));
81 		if (addr == 0) {
82 			return -ENXIO;
83 		}
84 		physaddr = (ulong)addr;
85 		if (remap_pfn_range(vma, vma->vm_start,
86 				    physaddr >> PAGE_SHIFT,
87 				    vma->vm_end - vma->vm_start,
88 				    /*pgprot_noncached */
89 				    (vma->vm_page_prot))) {
90 			return -EAGAIN;
91 		}
92 		break;
93 	default:
94 		return -ENOSYS;
95 	}
96 	return 0;
97 }
98 
visorchipset_ioctl(struct file * file,unsigned int cmd,unsigned long arg)99 static long visorchipset_ioctl(struct file *file, unsigned int cmd,
100 				unsigned long arg)
101 {
102 	s64 adjustment;
103 	s64 vrtc_offset;
104 
105 	switch (cmd) {
106 	case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET:
107 		/* get the physical rtc offset */
108 		vrtc_offset = issue_vmcall_query_guest_virtual_time_offset();
109 		if (copy_to_user
110 		    ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) {
111 			return -EFAULT;
112 		}
113 		return SUCCESS;
114 	case VMCALL_UPDATE_PHYSICAL_TIME:
115 		if (copy_from_user
116 		    (&adjustment, (void __user *)arg, sizeof(adjustment))) {
117 			return -EFAULT;
118 		}
119 		return issue_vmcall_update_physical_time(adjustment);
120 	default:
121 		return -EFAULT;
122 	}
123 }
124 
125 static const struct file_operations visorchipset_fops = {
126 	.owner = THIS_MODULE,
127 	.open = visorchipset_open,
128 	.read = NULL,
129 	.write = NULL,
130 	.unlocked_ioctl = visorchipset_ioctl,
131 	.release = visorchipset_release,
132 	.mmap = visorchipset_mmap,
133 };
134 
135 int
visorchipset_file_init(dev_t major_dev,struct visorchannel ** controlvm_channel)136 visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
137 {
138 	int rc = 0;
139 
140 	file_controlvm_channel = controlvm_channel;
141 	cdev_init(&file_cdev, &visorchipset_fops);
142 	file_cdev.owner = THIS_MODULE;
143 	if (MAJOR(major_dev) == 0) {
144 		rc = alloc_chrdev_region(&major_dev, 0, 1, MYDRVNAME);
145 		/* dynamic major device number registration required */
146 		if (rc < 0)
147 			return rc;
148 	} else {
149 		/* static major device number registration required */
150 		rc = register_chrdev_region(major_dev, 1, MYDRVNAME);
151 		if (rc < 0)
152 			return rc;
153 	}
154 	rc = cdev_add(&file_cdev, MKDEV(MAJOR(major_dev), 0), 1);
155 	if (rc < 0) {
156 		unregister_chrdev_region(major_dev, 1);
157 		return rc;
158 	}
159 	return 0;
160 }
161