Skip to content

Commit 71aaaf2

Browse files
committed
Support multiple kernel formats
In the previous commit we added support for the simplest type of external kernel, a raw image that can be directly copied into the VM's memory. This commit builds on that to add support for multiple kernel formats. The ones currently implemented are: - ELF: A kernel binary in ELF format (vmlinux). - PeGz: A PE binary embedding a kernel image compressed with GZIP. - ImageBz2: An Image file embedding a kernel compressed with BZIP2. - ImageGz: An Image file embedding a kernel compressed with GZIP. - ImageZstd: An Image file embedding a kernel compressed with ZSTD. Adding new kernel formats should be quite straightforward. Please note this change doesn't implement support for loading an external initramfs. The main reason is that we can't guarantee to maintain the control of the VM boot when using an arbitrary initramfs. This means that the external kernel must be built with, at least, the following driver built-in: - virtio-mmio - virtio-console - virtio-fs Depending on the use case, more drivers might be required. Signed-off-by: Sergio Lopez <[email protected]>
1 parent 07a2ebe commit 71aaaf2

File tree

9 files changed

+737
-233
lines changed

9 files changed

+737
-233
lines changed

Cargo.lock

+73
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

include/libkrun.h

+12-3
Original file line numberDiff line numberDiff line change
@@ -403,18 +403,27 @@ int32_t krun_set_exec(uint32_t ctx_id,
403403
const char *const argv[],
404404
const char *const envp[]);
405405

406+
#define KRUN_KERNEL_FORMAT_RAW 0
407+
#define KRUN_KERNEL_FORMAT_ELF 1
408+
#define KRUN_KERNEL_FORMAT_PE_GZ 2
409+
#define KRUN_KERNEL_FORMAT_IMAGE_BZ2 3
410+
#define KRUN_KERNEL_FORMAT_IMAGE_GZ 4
411+
#define KRUN_KERNEL_FORMAT_IMAGE_ZSTD 5
406412
/**
407413
* Sets the path to the kernel to be loaded in the microVM.
408414
*
409415
* Arguments:
410-
* "ctx_id" - the configuration context ID.
411-
* "kernel_path" - the path to the kernel, relative to the host's filesystem.
416+
* "ctx_id" - the configuration context ID.
417+
* "kernel_path" - the path to the kernel, relative to the host's filesystem.
418+
* "kernel_format" - the kernel format
412419
*
413420
* Returns:
414421
* Zero on success or a negative error number on failure.
415422
*/
423+
/* Supported disk image formats */
416424
int32_t krun_set_kernel(uint32_t ctx_id,
417-
const char *kernel_path);
425+
const char *kernel_path,
426+
uint32_t kernel_format);
418427

419428
/**
420429
* Sets environment variables to be configured in the context of the executable.

src/arch/src/x86_64/mod.rs

+54-31
Original file line numberDiff line numberDiff line change
@@ -67,48 +67,69 @@ pub const MMIO_MEM_START: u64 = FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE;
6767
#[cfg(not(feature = "tee"))]
6868
pub fn arch_memory_regions(
6969
size: usize,
70-
kernel_load_addr: u64,
70+
kernel_load_addr: Option<u64>,
7171
kernel_size: usize,
7272
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
7373
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };
7474

7575
let size = round_up(size, page_size);
76-
if size < (kernel_load_addr + kernel_size as u64) as usize {
77-
panic!("Kernel doesn't fit in RAM");
78-
}
7976

8077
// It's safe to cast MMIO_MEM_START to usize because it fits in a u32 variable
8178
// (It points to an address in the 32 bit space).
8279
let (ram_last_addr, shm_start_addr, regions) = match size.checked_sub(MMIO_MEM_START as usize) {
8380
// case1: guest memory fits before the gap
8481
None | Some(0) => {
85-
let ram_last_addr = kernel_load_addr + kernel_size as u64 + size as u64;
86-
let shm_start_addr = FIRST_ADDR_PAST_32BITS;
87-
(
88-
ram_last_addr,
89-
shm_start_addr,
90-
vec![
91-
(GuestAddress(0), kernel_load_addr as usize),
92-
(GuestAddress(kernel_load_addr + kernel_size as u64), size),
93-
],
94-
)
82+
if let Some(kernel_load_addr) = kernel_load_addr {
83+
if size < (kernel_load_addr + kernel_size as u64) as usize {
84+
panic!("Kernel doesn't fit in RAM");
85+
}
86+
87+
let ram_last_addr = kernel_load_addr + kernel_size as u64 + size as u64;
88+
let shm_start_addr = FIRST_ADDR_PAST_32BITS;
89+
(
90+
ram_last_addr,
91+
shm_start_addr,
92+
vec![
93+
(GuestAddress(0), kernel_load_addr as usize),
94+
(GuestAddress(kernel_load_addr + kernel_size as u64), size),
95+
],
96+
)
97+
} else {
98+
let ram_last_addr = size as u64;
99+
let shm_start_addr = FIRST_ADDR_PAST_32BITS;
100+
(ram_last_addr, shm_start_addr, vec![(GuestAddress(0), size)])
101+
}
95102
}
103+
96104
// case2: guest memory extends beyond the gap
97105
Some(remaining) => {
98-
let ram_last_addr = FIRST_ADDR_PAST_32BITS + remaining as u64;
99-
let shm_start_addr = ((ram_last_addr / 0x4000_0000) + 1) * 0x4000_0000;
100-
(
101-
ram_last_addr,
102-
shm_start_addr,
103-
vec![
104-
(GuestAddress(0), kernel_load_addr as usize),
105-
(
106-
GuestAddress(kernel_load_addr + kernel_size as u64),
107-
(MMIO_MEM_START - (kernel_load_addr + kernel_size as u64)) as usize,
108-
),
109-
(GuestAddress(FIRST_ADDR_PAST_32BITS), remaining),
110-
],
111-
)
106+
if let Some(kernel_load_addr) = kernel_load_addr {
107+
let ram_last_addr = FIRST_ADDR_PAST_32BITS + remaining as u64;
108+
let shm_start_addr = ((ram_last_addr / 0x4000_0000) + 1) * 0x4000_0000;
109+
(
110+
ram_last_addr,
111+
shm_start_addr,
112+
vec![
113+
(GuestAddress(0), kernel_load_addr as usize),
114+
(
115+
GuestAddress(kernel_load_addr + kernel_size as u64),
116+
(MMIO_MEM_START - (kernel_load_addr + kernel_size as u64)) as usize,
117+
),
118+
(GuestAddress(FIRST_ADDR_PAST_32BITS), remaining),
119+
],
120+
)
121+
} else {
122+
let ram_last_addr = FIRST_ADDR_PAST_32BITS + remaining as u64;
123+
let shm_start_addr = ((ram_last_addr / 0x4000_0000) + 1) * 0x4000_0000;
124+
(
125+
ram_last_addr,
126+
shm_start_addr,
127+
vec![
128+
(GuestAddress(0), MMIO_MEM_START as usize),
129+
(GuestAddress(FIRST_ADDR_PAST_32BITS), remaining),
130+
],
131+
)
132+
}
112133
}
113134
};
114135
let info = ArchMemoryInfo {
@@ -127,14 +148,16 @@ pub fn arch_memory_regions(
127148
#[cfg(feature = "tee")]
128149
pub fn arch_memory_regions(
129150
size: usize,
130-
kernel_load_addr: u64,
151+
kernel_load_addr: Option<u64>,
131152
kernel_size: usize,
132153
) -> (ArchMemoryInfo, Vec<(GuestAddress, usize)>) {
133154
let page_size: usize = unsafe { libc::sysconf(libc::_SC_PAGESIZE).try_into().unwrap() };
134155

135156
let size = round_up(size, page_size);
136-
if size < (kernel_load_addr + kernel_size as u64) as usize {
137-
panic!("Kernel doesn't fit in RAM");
157+
if let Some(kernel_load_addr) = kernel_load_addr {
158+
if size < (kernel_load_addr + kernel_size as u64) as usize {
159+
panic!("Kernel doesn't fit in RAM");
160+
}
138161
}
139162

140163
// It's safe to cast MMIO_MEM_START to usize because it fits in a u32 variable

0 commit comments

Comments
 (0)