1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
31static struct cdev file_cdev;
32static struct visorchannel **file_controlvm_channel;
33
34void
35visorchipset_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
43static int
44visorchipset_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
54static int
55visorchipset_release(struct inode *inode, struct file *file)
56{
57 return 0;
58}
59
60static int
61visorchipset_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
68 if (offset & (PAGE_SIZE - 1))
69 return -ENXIO;
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
89 (vma->vm_page_prot))) {
90 return -EAGAIN;
91 }
92 break;
93 default:
94 return -ENOSYS;
95 }
96 return 0;
97}
98
99static 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
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
125static 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
135int
136visorchipset_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
146 if (rc < 0)
147 return rc;
148 } else {
149
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