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