diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2015-02-10 23:45:09 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2015-02-11 01:17:30 -0500 |
commit | 69a09dc1742ffbb3b02f3a1e03da4801e96452e9 (patch) | |
tree | c9887c6b6150810ba103b76cf9d4376af3edd5e5 | |
parent | 18c137371b2ea86d263b75665a4904a0b8872990 (diff) |
lguest: write more information to userspace about pending traps.
This is preparation for userspace handling MMIO and ioport accesses.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r-- | drivers/lguest/core.c | 7 | ||||
-rw-r--r-- | drivers/lguest/hypercalls.c | 7 | ||||
-rw-r--r-- | drivers/lguest/lg.h | 3 | ||||
-rw-r--r-- | drivers/lguest/lguest_user.c | 14 | ||||
-rw-r--r-- | include/linux/lguest_launcher.h | 13 | ||||
-rw-r--r-- | tools/lguest/lguest.c | 16 |
6 files changed, 42 insertions, 18 deletions
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index cdb2f9aa5860..9159dbc583f6 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c | |||
@@ -229,16 +229,17 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user) | |||
229 | * It's possible the Guest did a NOTIFY hypercall to the | 229 | * It's possible the Guest did a NOTIFY hypercall to the |
230 | * Launcher. | 230 | * Launcher. |
231 | */ | 231 | */ |
232 | if (cpu->pending_notify) { | 232 | if (cpu->pending.trap) { |
233 | /* | 233 | /* |
234 | * Does it just needs to write to a registered | 234 | * Does it just needs to write to a registered |
235 | * eventfd (ie. the appropriate virtqueue thread)? | 235 | * eventfd (ie. the appropriate virtqueue thread)? |
236 | */ | 236 | */ |
237 | if (!send_notify_to_eventfd(cpu)) { | 237 | if (!send_notify_to_eventfd(cpu)) { |
238 | /* OK, we tell the main Launcher. */ | 238 | /* OK, we tell the main Launcher. */ |
239 | if (put_user(cpu->pending_notify, user)) | 239 | if (copy_to_user(user, &cpu->pending, |
240 | sizeof(cpu->pending))) | ||
240 | return -EFAULT; | 241 | return -EFAULT; |
241 | return sizeof(cpu->pending_notify); | 242 | return sizeof(cpu->pending); |
242 | } | 243 | } |
243 | } | 244 | } |
244 | 245 | ||
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c index 83511eb0923d..5dd1fb8a6610 100644 --- a/drivers/lguest/hypercalls.c +++ b/drivers/lguest/hypercalls.c | |||
@@ -118,7 +118,8 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args) | |||
118 | cpu->halted = 1; | 118 | cpu->halted = 1; |
119 | break; | 119 | break; |
120 | case LHCALL_NOTIFY: | 120 | case LHCALL_NOTIFY: |
121 | cpu->pending_notify = args->arg1; | 121 | cpu->pending.trap = LGUEST_TRAP_ENTRY; |
122 | cpu->pending.addr = args->arg1; | ||
122 | break; | 123 | break; |
123 | default: | 124 | default: |
124 | /* It should be an architecture-specific hypercall. */ | 125 | /* It should be an architecture-specific hypercall. */ |
@@ -189,7 +190,7 @@ static void do_async_hcalls(struct lg_cpu *cpu) | |||
189 | * Stop doing hypercalls if they want to notify the Launcher: | 190 | * Stop doing hypercalls if they want to notify the Launcher: |
190 | * it needs to service this first. | 191 | * it needs to service this first. |
191 | */ | 192 | */ |
192 | if (cpu->pending_notify) | 193 | if (cpu->pending.trap) |
193 | break; | 194 | break; |
194 | } | 195 | } |
195 | } | 196 | } |
@@ -280,7 +281,7 @@ void do_hypercalls(struct lg_cpu *cpu) | |||
280 | * NOTIFY to the Launcher, we want to return now. Otherwise we do | 281 | * NOTIFY to the Launcher, we want to return now. Otherwise we do |
281 | * the hypercall. | 282 | * the hypercall. |
282 | */ | 283 | */ |
283 | if (!cpu->pending_notify) { | 284 | if (!cpu->pending.trap) { |
284 | do_hcall(cpu, cpu->hcall); | 285 | do_hcall(cpu, cpu->hcall); |
285 | /* | 286 | /* |
286 | * Tricky point: we reset the hcall pointer to mark the | 287 | * Tricky point: we reset the hcall pointer to mark the |
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index 1c98bf74fd68..020fec5bb072 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h | |||
@@ -50,7 +50,8 @@ struct lg_cpu { | |||
50 | /* Bitmap of what has changed: see CHANGED_* above. */ | 50 | /* Bitmap of what has changed: see CHANGED_* above. */ |
51 | int changed; | 51 | int changed; |
52 | 52 | ||
53 | unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */ | 53 | /* Pending operation. */ |
54 | struct lguest_pending pending; | ||
54 | 55 | ||
55 | unsigned long *reg_read; /* register from LHREQ_GETREG */ | 56 | unsigned long *reg_read; /* register from LHREQ_GETREG */ |
56 | 57 | ||
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index 7f14c152dd23..dcf9efd94cf4 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c | |||
@@ -29,6 +29,10 @@ bool send_notify_to_eventfd(struct lg_cpu *cpu) | |||
29 | unsigned int i; | 29 | unsigned int i; |
30 | struct lg_eventfd_map *map; | 30 | struct lg_eventfd_map *map; |
31 | 31 | ||
32 | /* We only connect LHCALL_NOTIFY to event fds, not other traps. */ | ||
33 | if (cpu->pending.trap != LGUEST_TRAP_ENTRY) | ||
34 | return false; | ||
35 | |||
32 | /* | 36 | /* |
33 | * This "rcu_read_lock()" helps track when someone is still looking at | 37 | * This "rcu_read_lock()" helps track when someone is still looking at |
34 | * the (RCU-using) eventfds array. It's not actually a lock at all; | 38 | * the (RCU-using) eventfds array. It's not actually a lock at all; |
@@ -52,9 +56,9 @@ bool send_notify_to_eventfd(struct lg_cpu *cpu) | |||
52 | * we'll continue to use the old array and just won't see the new one. | 56 | * we'll continue to use the old array and just won't see the new one. |
53 | */ | 57 | */ |
54 | for (i = 0; i < map->num; i++) { | 58 | for (i = 0; i < map->num; i++) { |
55 | if (map->map[i].addr == cpu->pending_notify) { | 59 | if (map->map[i].addr == cpu->pending.addr) { |
56 | eventfd_signal(map->map[i].event, 1); | 60 | eventfd_signal(map->map[i].event, 1); |
57 | cpu->pending_notify = 0; | 61 | cpu->pending.trap = 0; |
58 | break; | 62 | break; |
59 | } | 63 | } |
60 | } | 64 | } |
@@ -62,7 +66,7 @@ bool send_notify_to_eventfd(struct lg_cpu *cpu) | |||
62 | rcu_read_unlock(); | 66 | rcu_read_unlock(); |
63 | 67 | ||
64 | /* If we cleared the notification, it's because we found a match. */ | 68 | /* If we cleared the notification, it's because we found a match. */ |
65 | return cpu->pending_notify == 0; | 69 | return cpu->pending.trap == 0; |
66 | } | 70 | } |
67 | 71 | ||
68 | /*L:055 | 72 | /*L:055 |
@@ -282,8 +286,8 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o) | |||
282 | * If we returned from read() last time because the Guest sent I/O, | 286 | * If we returned from read() last time because the Guest sent I/O, |
283 | * clear the flag. | 287 | * clear the flag. |
284 | */ | 288 | */ |
285 | if (cpu->pending_notify) | 289 | if (cpu->pending.trap) |
286 | cpu->pending_notify = 0; | 290 | cpu->pending.trap = 0; |
287 | 291 | ||
288 | /* Run the Guest until something interesting happens. */ | 292 | /* Run the Guest until something interesting happens. */ |
289 | return run_guest(cpu, (unsigned long __user *)user); | 293 | return run_guest(cpu, (unsigned long __user *)user); |
diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h index f27cae27b0c1..c4451ebece47 100644 --- a/include/linux/lguest_launcher.h +++ b/include/linux/lguest_launcher.h | |||
@@ -68,6 +68,19 @@ enum lguest_req | |||
68 | }; | 68 | }; |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * This is what read() of the lguest fd populates. trap == | ||
72 | * LGUEST_TRAP_ENTRY for an LHCALL_NOTIFY (addr is the | ||
73 | * argument), 14 for a page fault in the MMIO region (addr is | ||
74 | * the trap address, insn is the instruction), or 13 for a GPF | ||
75 | * (insn is the instruction). | ||
76 | */ | ||
77 | struct lguest_pending { | ||
78 | __u8 trap; | ||
79 | __u8 insn[7]; | ||
80 | __u32 addr; | ||
81 | }; | ||
82 | |||
83 | /* | ||
71 | * The alignment to use between consumer and producer parts of vring. | 84 | * The alignment to use between consumer and producer parts of vring. |
72 | * x86 pagesize for historical reasons. | 85 | * x86 pagesize for historical reasons. |
73 | */ | 86 | */ |
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index 3f7f2326cd9a..0e754d04876d 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c | |||
@@ -1820,17 +1820,21 @@ static void __attribute__((noreturn)) restart_guest(void) | |||
1820 | static void __attribute__((noreturn)) run_guest(void) | 1820 | static void __attribute__((noreturn)) run_guest(void) |
1821 | { | 1821 | { |
1822 | for (;;) { | 1822 | for (;;) { |
1823 | unsigned long notify_addr; | 1823 | struct lguest_pending notify; |
1824 | int readval; | 1824 | int readval; |
1825 | 1825 | ||
1826 | /* We read from the /dev/lguest device to run the Guest. */ | 1826 | /* We read from the /dev/lguest device to run the Guest. */ |
1827 | readval = pread(lguest_fd, ¬ify_addr, | 1827 | readval = pread(lguest_fd, ¬ify, sizeof(notify), cpu_id); |
1828 | sizeof(notify_addr), cpu_id); | ||
1829 | 1828 | ||
1830 | /* One unsigned long means the Guest did HCALL_NOTIFY */ | 1829 | /* One unsigned long means the Guest did HCALL_NOTIFY */ |
1831 | if (readval == sizeof(notify_addr)) { | 1830 | if (readval == sizeof(notify)) { |
1832 | verbose("Notify on address %#lx\n", notify_addr); | 1831 | if (notify.trap == 0x1F) { |
1833 | handle_output(notify_addr); | 1832 | verbose("Notify on address %#08x\n", |
1833 | notify.addr); | ||
1834 | handle_output(notify.addr); | ||
1835 | } else | ||
1836 | errx(1, "Unknown trap %i addr %#08x\n", | ||
1837 | notify.trap, notify.addr); | ||
1834 | /* ENOENT means the Guest died. Reading tells us why. */ | 1838 | /* ENOENT means the Guest died. Reading tells us why. */ |
1835 | } else if (errno == ENOENT) { | 1839 | } else if (errno == ENOENT) { |
1836 | char reason[1024] = { 0 }; | 1840 | char reason[1024] = { 0 }; |