Content from 2015-10

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(&region, 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, &region));
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(&regs, 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, &regs));
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 }