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 = '8x32sIIIIIIII'
74 def __init__(self, config_file):
75 self.data = config_file.read()
80 self.num_memory_regions,
81 self.num_cache_regions,
85 self.num_pci_caps) = \
86 struct.unpack_from(Config._HEADER_FORMAT, self.data)
87 self.name = str(name.decode())
89 memregion_offs = struct.calcsize(Config._HEADER_FORMAT) + \
91 self.memory_regions = []
92 for n in range(self.num_memory_regions):
93 self.memory_regions.append(
94 MemoryRegion(self.data[memregion_offs:]))
95 memregion_offs += MemoryRegion.SIZE
99 _HEADER_FORMAT = 'xB2xI8xH14xB7xII8xI4xI28xQ'
101 def __init__(self, kernel):
103 parse_size = struct.calcsize(SetupHeader._HEADER_FORMAT)
111 self.kernel_alignment,
113 struct.unpack(SetupHeader._HEADER_FORMAT, kernel.read(parse_size))
115 self.size = 0x202 + (self.jump >> 8) - 0x1f0
117 self.data = bytearray(kernel.read(self.size))
120 struct.pack_into(SetupHeader._HEADER_FORMAT, self.data, 0,
121 self.setup_sects, self.syssize, self.jump,
122 self.type_of_loader, self.ramdisk_image,
123 self.ramdisk_size, self.cmd_line_ptr,
124 self.kernel_alignment, self.setup_data)
129 def __init__(self, kernel, initrd, config):
130 self.setup_header = SetupHeader(kernel)
132 prot_image_offs = (self.setup_header.setup_sects + 1) * 512
133 prot_image_size = self.setup_header.syssize * 16
135 self.kernel_load_addr = self.setup_header.kernel_alignment - \
138 self.setup_header.type_of_loader = 0xff
141 kernel_size = os.fstat(kernel.fileno()).st_size
142 self.setup_header.ramdisk_size = os.fstat(initrd.fileno()).st_size
143 self.setup_header.ramdisk_image = \
144 (self.kernel_load_addr - self.setup_header.ramdisk_size) & \
147 self.setup_header.ramdisk_image = 0
148 self.setup_header.ramdisk_size = 0
150 self.e820_entries = []
151 for region in config.memory_regions:
152 if region.is_ram() or region.is_comm_region():
153 if len(self.e820_entries) >= 128:
154 print("Too many memory regions", file=sys.stderr)
156 self.e820_entries.append(region)
159 data = bytearray(0x1e8) + \
160 struct.pack('B', len(self.e820_entries)) + \
161 bytearray(0x1f0 - 0x1e9) + self.setup_header.get_data() + \
162 bytearray(0x2d0 - 0x1f0 - self.setup_header.size)
163 for region in self.e820_entries:
164 data += region.as_e820()
165 return data + bytearray(0x1000 - len(data))
169 JAILHOUSE_CELL_CREATE = 0x40100002
170 JAILHOUSE_CELL_LOAD = 0x40300003
171 JAILHOUSE_CELL_START = 0x40280004
173 JAILHOUSE_CELL_ID_UNUSED = -1
175 def __init__(self, config):
176 self.name = config.name.encode('utf-8')
178 self.dev = open('/dev/jailhouse')
180 cbuf = ctypes.c_buffer(config.data)
181 create = struct.pack('QI4x', ctypes.addressof(cbuf), len(config.data))
183 fcntl.ioctl(self.dev, JailhouseCell.JAILHOUSE_CELL_CREATE, create)
185 if e.errno != errno.EEXIST:
188 def load(self, image, address):
189 cbuf = ctypes.create_string_buffer(bytes(image))
191 load = struct.pack('i4x32sI4xQQQ8x',
192 JailhouseCell.JAILHOUSE_CELL_ID_UNUSED, self.name,
193 1, ctypes.addressof(cbuf), len(image), address)
194 fcntl.ioctl(self.dev, self.JAILHOUSE_CELL_LOAD, load)
197 start = struct.pack('i4x32s', JailhouseCell.JAILHOUSE_CELL_ID_UNUSED,
199 fcntl.ioctl(self.dev, JailhouseCell.JAILHOUSE_CELL_START, start)
202 def gen_setup_data():
204 return struct.pack('8x4sI4x', b'JLHS', 4 + MAX_CPUS) + bytearray(MAX_CPUS)
207 # pretend to be part of the jailhouse tool
208 sys.argv[0] = sys.argv[0].replace('-', ' ')
210 parser = argparse.ArgumentParser(description='Boot Linux in a non-root cell.')
211 parser.add_argument('config', metavar='CELLCONFIG',
212 type=argparse.FileType('rb'),
213 help='cell configuration file')
214 parser.add_argument('kernel', metavar='KERNEL', type=argparse.FileType('rb'),
215 help='image of the kernel to be booted')
216 parser.add_argument('--initrd', '-i', metavar='FILE',
217 type=argparse.FileType('rb'),
218 help='initrd/initramfs for the kernel')
219 parser.add_argument('--cmdline', '-c', metavar='"STRING"',
220 help='kernel command line')
221 parser.add_argument('--write-params', '-w', metavar='FILE',
222 type=argparse.FileType('wb'),
223 help='only parse cell configuration, write out '
224 'parameters into the specified file and print '
225 'required jailhouse cell commands to boot Linux '
229 args = parser.parse_args()
231 print(e.strerror, file=sys.stderr)
234 config = Config(args.config)
236 zero_page = ZeroPage(args.kernel, args.initrd, config)
238 setup_data = gen_setup_data()
240 zero_page.setup_header.setup_data = PARAMS_BASE + 0x1000
241 zero_page.setup_header.cmd_line_ptr = \
242 zero_page.setup_header.setup_data + len(setup_data)
244 params = zero_page.get_data() + setup_data + \
245 (args.cmdline.encode() if args.cmdline else b'') + b'\0'
247 if args.write_params:
248 args.write_params.write(params)
249 args.write_params.close()
252 Boot parameters written. Start Linux with the following commands (adjusting \
255 jailhouse cell create %s\n\
256 jailhouse cell load %s linux-loader.bin -a 0xf0000 %s -a 0x%x " %
257 (args.config.name, config.name, args.kernel.name,
258 zero_page.kernel_load_addr),
261 print("%s -a 0x%x " %
262 (args.initrd.name, zero_page.setup_header.ramdisk_image),
264 print("%s -a 0x%x" % (args.write_params.name, PARAMS_BASE))
265 print("jailhouse cell start %s" % config.name)
267 arch_str = os.uname()[4]
268 if arch_str in ('i686', 'x86_64'):
271 print("Unsupported architecture", file=sys.stderr)
275 linux_loader = libexecdir + '/jailhouse/linux-loader.bin'
277 linux_loader = os.path.abspath(os.path.dirname(sys.argv[0])) + \
278 '/../inmates/tools/' + srcarch + '/linux-loader.bin'
280 cell = JailhouseCell(config)
281 cell.load(open(linux_loader, mode='rb').read(), 0xf0000)
283 cell.load(args.kernel.read(), zero_page.kernel_load_addr)
285 cell.load(args.initrd.read(), zero_page.setup_header.ramdisk_image)
286 cell.load(params, PARAMS_BASE)