Commit | Line | Data |
---|---|---|
5b06931d SL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * A sample program to run a User VM on the ACRN hypervisor | |
4 | * | |
5 | * This sample runs in a Service VM, which is a privileged VM of ACRN. | |
203b283c | 6 | * CONFIG_ACRN_HSM needs to be enabled in the Service VM. |
5b06931d SL |
7 | * |
8 | * Guest VM code in guest16.s will be executed after the VM launched. | |
9 | * | |
10 | * Copyright (C) 2020 Intel Corporation. All rights reserved. | |
11 | */ | |
12 | #include <stdio.h> | |
13 | #include <stdint.h> | |
14 | #include <stdlib.h> | |
15 | #include <string.h> | |
5b06931d SL |
16 | #include <fcntl.h> |
17 | #include <unistd.h> | |
18 | #include <signal.h> | |
19 | #include <sys/ioctl.h> | |
20 | #include <linux/acrn.h> | |
21 | ||
22 | #define GUEST_MEMORY_SIZE (1024*1024) | |
23 | void *guest_memory; | |
24 | ||
25 | extern const unsigned char guest16[], guest16_end[]; | |
26 | static char io_request_page[4096] __attribute__((aligned(4096))); | |
27 | static struct acrn_io_request *io_req_buf = (struct acrn_io_request *)io_request_page; | |
28 | ||
29 | __u16 vcpu_num; | |
30 | __u16 vmid; | |
5b06931d SL |
31 | |
32 | int hsm_fd; | |
33 | int is_running = 1; | |
34 | ||
35 | void vm_exit(int sig) | |
36 | { | |
37 | sig = sig; | |
38 | ||
39 | is_running = 0; | |
40 | ioctl(hsm_fd, ACRN_IOCTL_PAUSE_VM, vmid); | |
41 | ioctl(hsm_fd, ACRN_IOCTL_DESTROY_IOREQ_CLIENT, 0); | |
42 | } | |
43 | ||
44 | int main(int argc, char **argv) | |
45 | { | |
46 | int vcpu_id, ret; | |
47 | struct acrn_vm_creation create_vm = {0}; | |
48 | struct acrn_vm_memmap ram_map = {0}; | |
49 | struct acrn_vcpu_regs regs; | |
50 | struct acrn_io_request *io_req; | |
51 | struct acrn_ioreq_notify __attribute__((aligned(8))) notify; | |
52 | ||
53 | argc = argc; | |
54 | argv = argv; | |
55 | ||
32118bdc DW |
56 | ret = posix_memalign(&guest_memory, 4096, GUEST_MEMORY_SIZE); |
57 | if (ret < 0) { | |
203b283c | 58 | printf("Not enough memory!\n"); |
5b06931d SL |
59 | return -1; |
60 | } | |
61 | hsm_fd = open("/dev/acrn_hsm", O_RDWR|O_CLOEXEC); | |
62 | ||
5b06931d SL |
63 | create_vm.ioreq_buf = (__u64)io_req_buf; |
64 | ret = ioctl(hsm_fd, ACRN_IOCTL_CREATE_VM, &create_vm); | |
65 | printf("Created VM! [%d]\n", ret); | |
66 | vcpu_num = create_vm.vcpu_num; | |
67 | vmid = create_vm.vmid; | |
68 | ||
69 | /* setup guest memory */ | |
70 | ram_map.type = ACRN_MEMMAP_RAM; | |
71 | ram_map.vma_base = (__u64)guest_memory; | |
72 | ram_map.len = GUEST_MEMORY_SIZE; | |
73 | ram_map.user_vm_pa = 0; | |
74 | ram_map.attr = ACRN_MEM_ACCESS_RWX; | |
75 | ret = ioctl(hsm_fd, ACRN_IOCTL_SET_MEMSEG, &ram_map); | |
76 | printf("Set up VM memory! [%d]\n", ret); | |
77 | ||
78 | memcpy(guest_memory, guest16, guest16_end-guest16); | |
79 | ||
80 | /* setup vcpu registers */ | |
81 | memset(®s, 0, sizeof(regs)); | |
82 | regs.vcpu_id = 0; | |
83 | regs.vcpu_regs.rip = 0; | |
84 | ||
85 | /* CR0_ET | CR0_NE */ | |
86 | regs.vcpu_regs.cr0 = 0x30U; | |
87 | regs.vcpu_regs.cs_ar = 0x009FU; | |
88 | regs.vcpu_regs.cs_sel = 0xF000U; | |
89 | regs.vcpu_regs.cs_limit = 0xFFFFU; | |
90 | regs.vcpu_regs.cs_base = 0 & 0xFFFF0000UL; | |
91 | regs.vcpu_regs.rip = 0 & 0xFFFFUL; | |
92 | ||
93 | ret = ioctl(hsm_fd, ACRN_IOCTL_SET_VCPU_REGS, ®s); | |
94 | printf("Set up VM BSP registers! [%d]\n", ret); | |
95 | ||
96 | /* create an ioreq client for this VM */ | |
97 | ret = ioctl(hsm_fd, ACRN_IOCTL_CREATE_IOREQ_CLIENT, 0); | |
98 | printf("Created IO request client! [%d]\n", ret); | |
99 | ||
100 | /* run vm */ | |
101 | ret = ioctl(hsm_fd, ACRN_IOCTL_START_VM, vmid); | |
102 | printf("Start VM! [%d]\n", ret); | |
103 | ||
104 | signal(SIGINT, vm_exit); | |
105 | while (is_running) { | |
106 | ret = ioctl(hsm_fd, ACRN_IOCTL_ATTACH_IOREQ_CLIENT, 0); | |
107 | ||
108 | for (vcpu_id = 0; vcpu_id < vcpu_num; vcpu_id++) { | |
109 | io_req = &io_req_buf[vcpu_id]; | |
110 | if ((__sync_add_and_fetch(&io_req->processed, 0) == ACRN_IOREQ_STATE_PROCESSING) | |
111 | && (!io_req->kernel_handled)) | |
112 | if (io_req->type == ACRN_IOREQ_TYPE_PORTIO) { | |
113 | int bytes, port, in; | |
114 | ||
115 | port = io_req->reqs.pio_request.address; | |
116 | bytes = io_req->reqs.pio_request.size; | |
117 | in = (io_req->reqs.pio_request.direction == ACRN_IOREQ_DIR_READ); | |
118 | printf("Guest VM %s PIO[%x] with size[%x]\n", in ? "read" : "write", port, bytes); | |
119 | ||
120 | notify.vmid = vmid; | |
121 | notify.vcpu = vcpu_id; | |
122 | ioctl(hsm_fd, ACRN_IOCTL_NOTIFY_REQUEST_FINISH, ¬ify); | |
123 | } | |
124 | } | |
125 | } | |
126 | ||
127 | ret = ioctl(hsm_fd, ACRN_IOCTL_DESTROY_VM, NULL); | |
128 | printf("Destroy VM! [%d]\n", ret); | |
129 | close(hsm_fd); | |
130 | free(guest_memory); | |
131 | return 0; | |
132 | } |