Content from 2015-10
Tags
Months
I had read the first chapter and thought: "Gosh that's gonna be a politically correct manual for social justice warriors." I am glad I continued because, despite the dismissal of Ain Rand's ideas without any argument, it was not. The book is a pretty captivating story of Harry trying to use the scientific method to dissect the world of magic and having quite a bit of fun in the process of doing so. It's all about thinking, cognitive biases, decision theory, game theory and such. It's a fan-fiction, but I enjoyed it more than the original.
Some quotes:
Father had told Draco that to fathom a strange plot, one technique was to look at what ended up happening, assume it was the intended result, and ask who benefited.
"Undersstood," hissed the snake. "But remember thiss, boy, other eventss proceed whthout you. Hessitation iss alwayss eassy, rarely usseful."
So far as Harry was concerned, the five stages of grief were Rage, Remorse, Resolve, Research, and Resurrection.
"Oh, for Merlin’s sake - yes, he was trying to kill you. Get used to it. Only boring people never have that experience."
Free download here.
Generally, LWN runs top quality articles. I always read them with pleasure and they are good enough to make me a paid subscriber. Every now and then though, they would publish something pretty great even by their standards. I read this and was amazed. I had not realized that it is this easy to create and run a simple virtual machine. I typed the code in and played with it for a couple of hours. You can get the file that actually compiles (C++14) and runs here.
1 //------------------------------------------------------------------------------
2 // Based on: https://lwn.net/Articles/658511/
3 //------------------------------------------------------------------------------
4
5 #include <iostream>
6 #include <iomanip>
7 #include <cstdint>
8 #include <cstring>
9 #include <cerrno>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <sys/ioctl.h>
14 #include <sys/mman.h>
15 #include <linux/kvm.h>
16
17 //------------------------------------------------------------------------------
18 // Error handling macro
19 //------------------------------------------------------------------------------
20 #define RUN(var, command) \
21 var = command; \
22 if (var == -1) { \
23 std::cerr << #command ": " << strerror(errno) << std::endl; \
24 return 1; \
25 }
26
27 //------------------------------------------------------------------------------
28 // The code to be run inside of the virtual machine
29 //------------------------------------------------------------------------------
30 const uint8_t code[] = {
31 0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */
32 0x00, 0xd8, /* add %bl, %al */
33 0x04, '0', /* add $'0', %al */
34 0xee, /* out %al, (%dx) */
35 0xb0, '\n', /* mov $'\n', %al */
36 0xee, /* out %al, (%dx) */
37 0xf4 /* hlt */
38 };
39
40 int main(int argc, char **argv)
41 {
42 using namespace std;
43
44 //----------------------------------------------------------------------------
45 // Open KVM
46 //----------------------------------------------------------------------------
47 int kvm = open("/dev/kvm", O_RDWR | O_CLOEXEC);
48 if (kvm == -1) {
49 cerr << "Unable to open /dev/kvm: " << strerror(errno) << endl;
50 return 1;
51 }
52
53 //----------------------------------------------------------------------------
54 // Check the version of the API, we need 12
55 //----------------------------------------------------------------------------
56 int ret;
57 RUN(ret, ioctl(kvm, KVM_GET_API_VERSION, 0));
58
59 if (ret != 12) {
60 cerr << "KVM_GET_API_VERSION " << ret << ", expected 12" << endl;
61 return 1;
62 }
63
64 //----------------------------------------------------------------------------
65 // Check if the extension required to set up guest memory is present
66 //----------------------------------------------------------------------------
67 RUN(ret, ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY));
68
69 if (!ret) {
70 cerr << "KVM_CAP_USER_MEM extension is not available" << endl;
71 return 1;
72 }
73
74 //----------------------------------------------------------------------------
75 // Set up a virtual machine
76 //----------------------------------------------------------------------------
77 int vmfd;
78 RUN(vmfd, ioctl(kvm, KVM_CREATE_VM, (unsigned long)0));
79
80 //----------------------------------------------------------------------------
81 // Get some page-aligned memory and copy the code to it
82 //----------------------------------------------------------------------------
83 void *mem = mmap(0, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
84 -1, 0);
85 if (mem == MAP_FAILED) {
86 cerr << "Failed to get a page of memory: " << strerror(errno) << endl;
87 return 1;
88 }
89 memcpy(mem, code, sizeof(code));
90
91 //----------------------------------------------------------------------------
92 // Tell the virtual machine about this region
93 //----------------------------------------------------------------------------
94 kvm_userspace_memory_region region;
95 memset(®ion, 0, sizeof(region));
96 region.slot = 0;
97 region.guest_phys_addr = 0x1000;
98 region.memory_size = 0x1000;
99 region.userspace_addr = (uint64_t)mem;
100
101 RUN(ret, ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, ®ion));
102
103 //----------------------------------------------------------------------------
104 // Create a virtual CPU #0
105 //----------------------------------------------------------------------------
106 int vcpufd;
107 RUN(vcpufd, ioctl(vmfd, KVM_CREATE_VCPU, (unsigned long)0));
108
109 //----------------------------------------------------------------------------
110 // Allocate memory for kvm_run data structure
111 //----------------------------------------------------------------------------
112 int vcpu_run_size;
113 RUN(vcpu_run_size, ioctl(kvm, KVM_GET_VCPU_MMAP_SIZE, 0));
114
115 kvm_run *run;
116 run = (kvm_run *)mmap(0, vcpu_run_size, PROT_READ | PROT_WRITE, MAP_SHARED,
117 vcpufd, 0);
118 if (run == MAP_FAILED) {
119 cerr << "Allocating VCPU run struct failed: " << strerror(errno) << endl;
120 return 1;
121 }
122
123 //----------------------------------------------------------------------------
124 // Set up the special registers of the VCPU #0
125 //----------------------------------------------------------------------------
126 kvm_sregs sregs;
127 RUN(ret, ioctl(vcpufd, KVM_GET_SREGS, &sregs));
128 sregs.cs.base = 0;
129 sregs.cs.selector = 0;
130 RUN(ret, ioctl(vcpufd, KVM_SET_SREGS, &sregs));
131
132 //----------------------------------------------------------------------------
133 // Set up the standard registers
134 //----------------------------------------------------------------------------
135 kvm_regs regs;
136 memset(®s, 0, sizeof(regs));
137 regs.rip = 0x1000;
138 regs.rax = 2;
139 regs.rbx = 2;
140 regs.rflags = 0x2; // starting the VM will fail with this not set, x86
141 // architecture requirement
142 RUN(ret, ioctl(vcpufd, KVM_SET_REGS, ®s));
143
144 //----------------------------------------------------------------------------
145 // Run the VCPU #0
146 //----------------------------------------------------------------------------
147 while (1) {
148 RUN(ret, ioctl(vcpufd, KVM_RUN, 0));
149 switch (run->exit_reason) {
150
151 //------------------------------------------------------------------------
152 // HLT instruction - we're done
153 //------------------------------------------------------------------------
154 case KVM_EXIT_HLT:
155 cerr << "KVM_EXIT_HLT" << endl;
156 return 0;
157
158 //------------------------------------------------------------------------
159 // Simulate an IO port at 0x3f8
160 //------------------------------------------------------------------------
161 case KVM_EXIT_IO:
162 if (run->io.direction == KVM_EXIT_IO_OUT &&
163 run->io.size == 1 &&
164 run->io.port == 0x3f8 &&
165 run->io.count == 1)
166 cout << *(((char *)run) + run->io.data_offset) << flush;
167 else
168 cerr << "Unhandled KVM_EXIT_IO" << endl;
169 break;
170
171 //------------------------------------------------------------------------
172 // Underlying virtualization mechanism can't start the VM
173 //------------------------------------------------------------------------
174 case KVM_EXIT_FAIL_ENTRY:
175 cerr << "KVM_EXIT_FAIL_ENTRY: hardware_entry_failure_reason = 0x";
176 cerr << hex;
177 cerr << (unsigned long long)run->fail_entry.hardware_entry_failure_reason;
178 cerr << endl;
179 return 1;
180
181 //------------------------------------------------------------------------
182 // Error from the KVM subsystem
183 //------------------------------------------------------------------------
184 case KVM_EXIT_INTERNAL_ERROR:
185 cerr << "KVM_EXIT_INTERNAL_ERROR: suberror = 0x" << hex;
186 cerr << run->internal.suberror << endl;
187 return 1;
188 }
189 }
190
191 //----------------------------------------------------------------------------
192 // Cleanup
193 //----------------------------------------------------------------------------
194 munmap(mem, 0x1000);
195 munmap(run, vcpu_run_size);
196 close(vcpufd);
197 close(vmfd);
198 close(kvm);
199
200 return 0;
201 }