• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 The Chromium OS Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6 
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <linux/memfd.h>
10 #include <pthread.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/mman.h>
16 #include <sys/syscall.h>
17 #include <time.h>
18 #include <unistd.h>
19 
20 #include "crosvm.h"
21 
22 #ifndef F_LINUX_SPECIFIC_BASE
23 #define F_LINUX_SPECIFIC_BASE 1024
24 #endif
25 
26 #ifndef F_ADD_SEALS
27 #define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
28 #endif
29 
30 #ifndef F_SEAL_SHRINK
31 #define F_SEAL_SHRINK 0x0002
32 #endif
33 
34 #define LOAD_ADDRESS 0x1000
35 #define DATAMATCH_VAL 0x88
36 #define KILL_ADDRESS 0x4000
37 
38 int g_kill_evt;
39 
vcpu_thread(void * arg)40 void *vcpu_thread(void *arg) {
41     struct crosvm_vcpu *vcpu = arg;
42     struct crosvm_vcpu_event evt;
43     int i = 0;
44     while (crosvm_vcpu_wait(vcpu, &evt) == 0) {
45         if (evt.kind == CROSVM_VCPU_EVENT_KIND_INIT) {
46             struct kvm_sregs sregs;
47             crosvm_vcpu_get_sregs(vcpu, &sregs);
48             sregs.cs.base = 0;
49             sregs.cs.selector = 0;
50             sregs.es.base = KILL_ADDRESS;
51             sregs.es.selector = 0;
52             crosvm_vcpu_set_sregs(vcpu, &sregs);
53 
54             struct kvm_regs regs;
55             crosvm_vcpu_get_regs(vcpu, &regs);
56             regs.rflags = 2;
57             regs.rip = LOAD_ADDRESS;
58             regs.rax = DATAMATCH_VAL;
59             regs.rbx = DATAMATCH_VAL - 1;
60             crosvm_vcpu_set_regs(vcpu, &regs);
61         }
62 
63         if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
64             evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
65             evt.io_access.address == KILL_ADDRESS &&
66             evt.io_access.is_write &&
67             evt.io_access.length == 1 &&
68             evt.io_access.data[0] == 1)
69         {
70             uint64_t dummy = 1;
71             write(g_kill_evt, &dummy, sizeof(dummy));
72             return NULL;
73         }
74 
75         crosvm_vcpu_resume(vcpu);
76     }
77 
78     return NULL;
79 }
80 
main(int argc,char ** argv)81 int main(int argc, char** argv) {
82     const uint8_t code[] = {
83     /*
84     0000  BAF803        mov dx,0x3f8
85     0003  88C3          mov bl,al
86     0005  EE            out dx,al
87     0006  B000          mov al,0x0
88     0008  EE            out dx,al
89     0009  88D8          mov al,bl
90     000B  EE            out dx,al
91     0014  26C606000001  mov byte [es:0x0],0x1
92     000C  F4            hlt
93     */
94         0xba, 0xf8, 0x03,
95         0x88, 0xc3,
96         0xee,
97         0xb0, 0x00,
98         0xee,
99         0x88, 0xd8,
100         0xee,
101         0x26, 0xc6, 0x06, 0x00, 0x00, 0x01,
102         0xf4,
103     };
104 
105     struct crosvm *crosvm;
106     int ret = crosvm_connect(&crosvm);
107     if (ret) {
108         fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
109         return 1;
110     }
111 
112     g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
113     if (g_kill_evt < 0) {
114         fprintf(stderr, "failed to get kill eventfd: %d\n", g_kill_evt);
115         return 1;
116     }
117 
118     ret = crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
119     if (ret) {
120         fprintf(stderr, "failed to reserve mmio range: %d\n", ret);
121         return 1;
122     }
123 
124     uint8_t datamatch = DATAMATCH_VAL;
125     struct crosvm_io *io;
126     ret = crosvm_create_io_event(crosvm, CROSVM_ADDRESS_SPACE_IOPORT, 0x3f8, 1, &datamatch, &io);
127     if (ret) {
128         fprintf(stderr, "failed to create ioevent: %d\n", ret);
129         return 1;
130     }
131 
132     int ioeventfd = crosvm_io_event_fd(io);
133 
134     int mem_size = 0x4000;
135     int mem_fd = syscall(SYS_memfd_create, "guest_mem", MFD_CLOEXEC | MFD_ALLOW_SEALING);
136     if (mem_fd < 0) {
137         fprintf(stderr, "failed to create guest memfd: %d\n", errno);
138         return 1;
139     }
140     ret = ftruncate(mem_fd, mem_size);
141     if (ret) {
142         fprintf(stderr, "failed to set size of guest memory: %d\n", errno);
143         return 1;
144     }
145     uint8_t *mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, 0);
146     if (mem == MAP_FAILED) {
147         fprintf(stderr, "failed to mmap guest memory: %d\n", errno);
148         return 1;
149     }
150     fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK);
151     memcpy(mem + LOAD_ADDRESS, code, sizeof(code));
152 
153     struct crosvm_memory *mem_obj;
154     ret = crosvm_create_memory(crosvm, mem_fd, 0, mem_size, 0, false, false, &mem_obj);
155     if (ret) {
156         fprintf(stderr, "failed to create memory in crosvm: %d\n", ret);
157         return 1;
158     }
159 
160     /* get and creat a thread for each vcpu */
161     struct crosvm_vcpu *vcpus[32];
162     pthread_t vcpu_threads[32];
163     uint32_t vcpu_count;
164     for (vcpu_count = 0; vcpu_count < 32; vcpu_count++) {
165         ret = crosvm_get_vcpu(crosvm, vcpu_count, &vcpus[vcpu_count]);
166         if (ret == -ENOENT)
167             break;
168 
169         if (ret) {
170             fprintf(stderr, "error while getting all vcpus: %d\n", ret);
171             return 1;
172         }
173         pthread_create(&vcpu_threads[vcpu_count], NULL, vcpu_thread, vcpus[vcpu_count]);
174     }
175 
176     ret = crosvm_start(crosvm);
177     if (ret) {
178         fprintf(stderr, "failed to tell crosvm to start: %d\n", ret);
179         return 1;
180     }
181 
182     uint64_t dummy;
183     read(g_kill_evt, &dummy, 8);
184 
185     ret = read(ioeventfd, &dummy, sizeof(dummy));
186     if (ret == -1) {
187         fprintf(stderr, "failed to read ioeventfd: %d\n", errno);
188         return 1;
189     }
190 
191     if (dummy != 2) {
192         fprintf(stderr, "ioeventfd was not triggered the expected number of times: %d\n", dummy);
193         return 1;
194     }
195 
196     return 0;
197 }
198