3 # Jailhouse, a Linux-based partitioning hypervisor
5 # Copyright (c) Siemens AG, 2015
8 # Jan Kiszka <jan.kiszka@siemens.com>
10 # This work is licensed under the terms of the GNU GPL, version 2. See
11 # the COPYING file in the top-level directory.
13 from __future__ import print_function
28 JAILHOUSE_MEM_READ = 0x0001
29 JAILHOUSE_MEM_WRITE = 0x0002
30 JAILHOUSE_MEM_EXECUTE = 0x0004
31 JAILHOUSE_MEM_DMA = 0x0008
32 JAILHOUSE_MEM_IO = 0x0010
33 JAILHOUSE_MEM_COMM_REGION = 0x0020
34 JAILHOUSE_MEM_ROOTSHARED = 0x0080
39 _REGION_FORMAT = 'QQQQ'
40 SIZE = struct.calcsize(_REGION_FORMAT)
42 def __init__(self, region_struct):
47 struct.unpack_from(MemoryRegion._REGION_FORMAT, region_struct)
50 return ((self.flags & (MemoryRegion.JAILHOUSE_MEM_READ |
51 MemoryRegion.JAILHOUSE_MEM_WRITE |
52 MemoryRegion.JAILHOUSE_MEM_EXECUTE |
53 MemoryRegion.JAILHOUSE_MEM_DMA |
54 MemoryRegion.JAILHOUSE_MEM_IO |
55 MemoryRegion.JAILHOUSE_MEM_COMM_REGION |
56 MemoryRegion.JAILHOUSE_MEM_ROOTSHARED)) ==
57 (MemoryRegion.JAILHOUSE_MEM_READ |
58 MemoryRegion.JAILHOUSE_MEM_WRITE |
59 MemoryRegion.JAILHOUSE_MEM_EXECUTE |
60 MemoryRegion.JAILHOUSE_MEM_DMA))
62 def is_comm_region(self):
63 return (self.flags & MemoryRegion.JAILHOUSE_MEM_COMM_REGION) != 0
66 return struct.pack('QQI', self.virt_start, self.size,
67 MemoryRegion.E820_RAM if self.is_ram() else
68 MemoryRegion.E820_RESERVED)
72 _HEADER_FORMAT = '8x32sIIIIIII'
74 def __init__(self, config_file):
75 self.data = config_file.read()
80 self.num_memory_regions,
84 self.num_pci_caps) = \
85 struct.unpack_from(Config._HEADER_FORMAT, self.data)
86 self.name = str(name.decode())
88 memregion_offs = struct.calcsize(Config._HEADER_FORMAT) + \
90 self.memory_regions = []
91 for n in range(self.num_memory_regions):
92 self.memory_regions.append(
93 MemoryRegion(self.data[memregion_offs:]))
94 memregion_offs += MemoryRegion.SIZE
98 _HEADER_FORMAT = 'xB2xI8xH14xB7xII8xI4xI28xQ'
100 def __init__(self, kernel):
102 parse_size = struct.calcsize(SetupHeader._HEADER_FORMAT)
110 self.kernel_alignment,
112 struct.unpack(SetupHeader._HEADER_FORMAT, kernel.read(parse_size))
114 self.size = 0x202 + (self.jump >> 8) - 0x1f0
116 self.data = bytearray(kernel.read(self.size))
119 struct.pack_into(SetupHeader._HEADER_FORMAT, self.data, 0,
120 self.setup_sects, self.syssize, self.jump,
121 self.type_of_loader, self.ramdisk_image,
122 self.ramdisk_size, self.cmd_line_ptr,
123 self.kernel_alignment, self.setup_data)
128 def __init__(self, kernel, initrd, config):
129 self.setup_header = SetupHeader(kernel)
131 prot_image_offs = (self.setup_header.setup_sects + 1) * 512
132 prot_image_size = self.setup_header.syssize * 16
134 self.kernel_load_addr = self.setup_header.kernel_alignment - \
137 self.setup_header.type_of_loader = 0xff
140 kernel_size = os.fstat(kernel.fileno()).st_size
141 self.setup_header.ramdisk_size = os.fstat(initrd.fileno()).st_size
142 self.setup_header.ramdisk_image = \
143 (self.kernel_load_addr - self.setup_header.ramdisk_size) & \
146 self.setup_header.ramdisk_image = 0
147 self.setup_header.ramdisk_size = 0
149 self.e820_entries = []
150 for region in config.memory_regions:
151 if region.is_ram() or region.is_comm_region():
152 if len(self.e820_entries) >= 128:
153 print("Too many memory regions", file=sys.stderr)
155 self.e820_entries.append(region)
158 data = bytearray(0x1e8) + \
159 struct.pack('B', len(self.e820_entries)) + \
160 bytearray(0x1f0 - 0x1e9) + self.setup_header.get_data() + \
161 bytearray(0x2d0 - 0x1f0 - self.setup_header.size)
162 for region in self.e820_entries:
163 data += region.as_e820()
164 return data + bytearray(0x1000 - len(data))
168 JAILHOUSE_CELL_CREATE = 0x40100002
169 JAILHOUSE_CELL_LOAD = 0x40300003
170 JAILHOUSE_CELL_START = 0x40280004
172 JAILHOUSE_CELL_ID_UNUSED = -1
174 def __init__(self, config):
175 self.name = config.name.encode('utf-8')
177 self.dev = open('/dev/jailhouse')
179 cbuf = ctypes.c_buffer(config.data)
180 create = struct.pack('QI4x', ctypes.addressof(cbuf), len(config.data))
182 fcntl.ioctl(self.dev, JailhouseCell.JAILHOUSE_CELL_CREATE, create)
184 if e.errno != errno.EEXIST:
187 def load(self, image, address):
188 cbuf = ctypes.create_string_buffer(bytes(image))
190 load = struct.pack('i4x32sI4xQQQ8x',
191 JailhouseCell.JAILHOUSE_CELL_ID_UNUSED, self.name,
192 1, ctypes.addressof(cbuf), len(image), address)
193 fcntl.ioctl(self.dev, self.JAILHOUSE_CELL_LOAD, load)
196 start = struct.pack('i4x32s', JailhouseCell.JAILHOUSE_CELL_ID_UNUSED,
198 fcntl.ioctl(self.dev, JailhouseCell.JAILHOUSE_CELL_START, start)
201 def gen_setup_data():
203 return struct.pack('8x4sI4x', b'JLHS', 4 + MAX_CPUS) + bytearray(MAX_CPUS)
206 # pretend to be part of the jailhouse tool
207 sys.argv[0] = sys.argv[0].replace('-', ' ')
209 parser = argparse.ArgumentParser(description='Boot Linux in a non-root cell.')
210 parser.add_argument('config', metavar='CELLCONFIG',
211 type=argparse.FileType('rb'),
212 help='cell configuration file')
213 parser.add_argument('kernel', metavar='KERNEL', type=argparse.FileType('rb'),
214 help='image of the kernel to be booted')
215 parser.add_argument('--initrd', '-i', metavar='FILE',
216 type=argparse.FileType('rb'),
217 help='initrd/initramfs for the kernel')
218 parser.add_argument('--cmdline', '-c', metavar='"STRING"',
219 help='kernel command line')
220 parser.add_argument('--write-params', '-w', metavar='FILE',
221 type=argparse.FileType('wb'),
222 help='only parse cell configuration, write out '
223 'parameters into the specified file and print '
224 'required jailhouse cell commands to boot Linux '
228 args = parser.parse_args()
230 print(e.strerror, file=sys.stderr)
233 config = Config(args.config)
235 zero_page = ZeroPage(args.kernel, args.initrd, config)
237 setup_data = gen_setup_data()
239 zero_page.setup_header.setup_data = PARAMS_BASE + 0x1000
240 zero_page.setup_header.cmd_line_ptr = \
241 zero_page.setup_header.setup_data + len(setup_data)
243 params = zero_page.get_data() + setup_data + \
244 (args.cmdline.encode() if args.cmdline else b'') + b'\0'
246 if args.write_params:
247 args.write_params.write(params)
248 args.write_params.close()
251 Boot parameters written. Start Linux with the following commands (adjusting \
254 jailhouse cell create %s\n\
255 jailhouse cell load %s linux-loader.bin -a 0xf0000 %s -a 0x%x " %
256 (args.config.name, config.name, args.kernel.name,
257 zero_page.kernel_load_addr),
260 print("%s -a 0x%x " %
261 (args.initrd.name, zero_page.setup_header.ramdisk_image),
263 print("%s -a 0x%x" % (args.write_params.name, PARAMS_BASE))
264 print("jailhouse cell start %s" % config.name)
266 arch_str = os.uname()[4]
267 if arch_str in ('i686', 'x86_64'):
270 print("Unsupported architecture", file=sys.stderr)
274 linux_loader = libexecdir + '/jailhouse/linux-loader.bin'
276 linux_loader = os.path.abspath(os.path.dirname(sys.argv[0])) + \
277 '/../inmates/tools/' + srcarch + '/linux-loader.bin'
279 cell = JailhouseCell(config)
280 cell.load(open(linux_loader, mode='rb').read(), 0xf0000)
282 cell.load(args.kernel.read(), zero_page.kernel_load_addr)
284 cell.load(args.initrd.read(), zero_page.setup_header.ramdisk_image)
285 cell.load(params, PARAMS_BASE)