From: Waldemar Kozaczuk <jwkozac...@gmail.com>
Committer: Waldemar Kozaczuk <jwkozac...@gmail.com>
Branch: master
Make OSv boot as vmlinuz
This patch adds new type of build artifact - vmlinuz.bin - that allows
OSv boot as vmlinuz image. Essentialy the vmlinuz.bin wraps
the uncompressed version of OSv loader.elf by prepending it
with 1K-long vmlinuz header and 1K-long 32-bit bootstrap code
that provides simple logic to jump to start32 in boot.S.
Please note that OSv vmlinuz.bin requires bootloader
to load it in the physical memory at the address OSV_KERNEL_BASE-0x400.
This is expressed by setting the header field 'relocatable_kernel' to 0 and
the field 'pref_address' to point to the mentioned address. Unfortunately
some bootloaders (like those part of QEMU) disregard
the 'relocatable_kernel'
field and load the kernel at some fixed load address determined by the value
of the 'version' header field (see the document below). In future we
could allow creating a vmlinuz version wrapping lzloader.elf that would
decompress
itself correcttly to the desired OSV_KERNEL_BASE address in physical memory.
For details about vmlinuz format see this document -
https://www.kernel.org/doc/Documentation/x86/boot.txt
This patch effectively allows OSv to boot on Docker's hyperkit
hypervisor.
Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
---
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -133,7 +133,7 @@ very-quiet = $(if $V, $1, @$1)
all: $(out)/loader.img links
ifeq ($(arch),x64)
-all: $(out)/loader.bin
+all: $(out)/loader.bin $(out)/vmlinuz.bin
endif
.PHONY: all
@@ -438,12 +438,25 @@ $(out)/loader.img: $(out)/boot.bin $(out)/lzloader.elf
$(call quiet, scripts/imgedit.py setargs "-f raw $@" $(cmdline), IMGEDIT
$@)
$(out)/arch/x64/boot32.o: $(out)/lzloader.elf
+$(out)/arch/x64/boot32.o: ASFLAGS += -I$(out)
+
$(out)/loader.bin: $(out)/arch/x64/boot32.o arch/x64/loader32.ld
$(call quiet, $(LD) -nostartfiles -static -nodefaultlibs -o $@ \
$(filter-out %.bin, $(^:%.ld=-T %.ld)), LD $@)
-$(out)/arch/x64/boot32.o: $(out)/lzloader.elf
-$(out)/arch/x64/boot32.o: ASFLAGS += -I$(out)
+kernel_size = $(shell stat --printf %s $(out)/loader-stripped.elf)
+
+$(out)/arch/x64/vmlinuz-boot32.o: $(out)/loader-stripped.elf
+$(out)/arch/x64/vmlinuz-boot32.o: ASFLAGS += -I$(out)
-DOSV_KERNEL_SIZE=$(kernel_size)
+
+$(out)/vmlinuz-boot.bin: $(out)/arch/x64/vmlinuz-boot32.o
arch/x64/vmlinuz-boot.ld
+ $(call quiet, $(LD) -nostartfiles -static -nodefaultlibs -T
arch/x64/vmlinuz-boot.ld -o $@ \
+ $(filter-out %.bin, $(^:%.ld=-T %.ld)), LD $@)
+
+$(out)/vmlinuz.bin: $(out)/vmlinuz-boot.bin $(out)/loader-stripped.elf
+ $(call quiet, dd if=$(out)/vmlinuz-boot.bin of=$@ > /dev/null 2>&1, DD
vmlinuz.bin vmlinuz-boot.bin)
+ $(call quiet, dd if=$(out)/loader-stripped.elf of=$@ conv=notrunc seek=4
/dev/null 2>&1, \
+ DD vmlinuz.bin loader-stripped.elf)
$(out)/fastlz/fastlz.o:
$(makedir)
diff --git a/arch/x64/arch-setup.cc b/arch/x64/arch-setup.cc
--- a/arch/x64/arch-setup.cc
+++ b/arch/x64/arch-setup.cc
@@ -88,6 +88,10 @@ extern "C" void start32();
void * __attribute__((section (".start32_address"))) start32_address =
reinterpret_cast<void*>((long)&start32 - OSV_KERNEL_VM_SHIFT);
+extern "C" void start32_from_vmlinuz();
+void * __attribute__((section (".start32_from_vmlinuz_address")))
start32_from_vmlinuz_address =
+ reinterpret_cast<void*>((long)&start32_from_vmlinuz -
OSV_KERNEL_VM_SHIFT);
+
void arch_setup_free_memory()
{
static ulong edata, edata_phys;
diff --git a/arch/x64/boot.S b/arch/x64/boot.S
--- a/arch/x64/boot.S
+++ b/arch/x64/boot.S
@@ -92,13 +92,16 @@ init_stack_top = .
.text
.globl start32
+.globl start32_from_vmlinuz
.globl start32_from_64
start32:
# Because the memory is mapped 1:1 at this point, we have to manualy
# subtract OSV_KERNEL_VM_SHIFT from virtual addresses in all relevant
places
# boot16.S set %eax to ELF start address, we'll use it later
mov %eax, %ebp
mov $0x0, %edi
+
+start32_from_vmlinuz:
lgdt gdt_desc-OSV_KERNEL_VM_SHIFT
# Add an address the vmlinux_entry64 will jump to when
diff --git a/arch/x64/loader.ld b/arch/x64/loader.ld
--- a/arch/x64/loader.ld
+++ b/arch/x64/loader.ld
@@ -22,6 +22,13 @@ SECTIONS
.start32_address : AT(ADDR(.start32_address) - OSV_KERNEL_VM_SHIFT) {
*(.start32_address)
}
+ . = OSV_KERNEL_VM_BASE + 0x900;
+ /*
+ * Place address of start32_from_vmlinuz routine at predefined offset in
memory
+ */
+ .start32_from_vmlinuz_address : AT(ADDR(.start32_from_vmlinuz_address)
- OSV_KERNEL_VM_SHIFT) {
+ *(.start32_from_vmlinuz_address)
+ }
. = OSV_KERNEL_VM_BASE + 0x1000;
.dynamic : AT(ADDR(.dynamic) - OSV_KERNEL_VM_SHIFT) { *(.dynamic)
} :dynamic :text
.text : AT(ADDR(.text) - OSV_KERNEL_VM_SHIFT) {
diff --git a/arch/x64/vmlinuz-boot.ld b/arch/x64/vmlinuz-boot.ld
--- a/arch/x64/vmlinuz-boot.ld
+++ b/arch/x64/vmlinuz-boot.ld
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2019 Waldemar Kozaczuk
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+OUTPUT_FORMAT(binary)
+
+SECTIONS
+{
+/* Layout:
+ 1K of header
+ 1K of code
+ ------------
+ - header's pref_address points to second 1K
+ - the code in second 1K (first instruction) jumps to start32 version
+*/
+ .data : { *(.data) }
+ .text 0x400 : { *(.text) }
+}
diff --git a/arch/x64/vmlinuz-boot32.S b/arch/x64/vmlinuz-boot32.S
--- a/arch/x64/vmlinuz-boot32.S
+++ b/arch/x64/vmlinuz-boot32.S
@@ -0,0 +1,65 @@
+# Copyright (C) 2019 Waldemar Kozaczuk
+#
+# This work is open source software, licensed under the terms of the
+# BSD license as described in the LICENSE file in the top-level directory.
+
+.code32
+.data
+
+loader = OSV_KERNEL_BASE
+start32_from_vmlinuz = loader + 0x900
+magic = 0xAA55
+vmlinuz_load_address = OSV_KERNEL_BASE - 0x400
+vmlinuz_size = OSV_KERNEL_SIZE + 0x400
+
+.rept 0x1f1
+.byte 0
+.endr
+
+setup_sects: .byte 1 /* The size of the
setup in sectors - (-1 in our case)*/
+root_flags: .2byte 0 /* If set, the root is
mounted readonly */
+syssize: .4byte 0x400 /* The size of the
32-bit code in 16-byte paras */
+ram_size: .2byte 0 /* DO NOT USE - for
bootsect.S use only */
+vid_mode: .2byte 0 /* Video mode control
*/
+root_dev: .2byte 0 /* Default root device
number */
+boot_flag: .2byte magic /* 0xAA55 magic number
*/
+jump: .2byte 0 /* Jump instruction */
+header: .ascii "HdrS" /* Magic
signature "HdrS" */
+version: .2byte 0x020a /* Boot protocol
version supported */
+realmode_swtch: .4byte 0 /* Boot loader hook
(see below) */
+start_sys_seg: .2byte 0 /* The load-low
segment (0x1000) (obsolete) */
+kernel_version: .2byte 0 /* Pointer to kernel
version string */
+type_of_loader: .byte 0 /* Boot loader
identifier */
+loadflags: .byte 1 /* Boot protocol
option flags */
+setup_move_size: .2byte 0 /* Move to high memory
size (used with hooks) */
+code32_start: .4byte 0 /* Boot loader hook
(see below) */
+ramdisk_image: .4byte 0 /* initrd load address
(set by boot loader) */
+ramdisk_size: .4byte 0 /* initrd size (set by
boot loader) */
+bootsect_kludge: .4byte 0 /* DO NOT USE - for
bootsect.S use only */
+heap_end_ptr: .2byte 0 /* Free memory after
setup end */
+ext_loader_ver: .byte 0 /* Extended boot
loader version */
+ext_loader_type: .byte 0 /* Extended boot
loader ID */
+cmd_line_ptr: .4byte 0 /* 32-bit pointer to
the kernel command line */
+initrd_addr_max: .4byte 0 /* Highest legal
initrd address */
+kernel_alignment: .4byte 0 /* Physical addr
alignment required for kernel */
+relocatable_kernel: .byte 0 /* Whether kernel is
relocatable or not */
+min_alignment: .byte 0 /* Minimum alignment,
as a power of two */
+xloadflags: .2byte 0 /* Boot protocol
option flags */
+cmdline_size: .4byte 65536 /* Maximum size of the
kernel command line */
+hardware_subarch: .4byte 0 /* Hardware
subarchitecture */
+hardware_subarch_data: .8byte 0 /*
Subarchitecture-specific data */
+payload_offset: .4byte 0 /* Offset of kernel
payload */
+payload_length: .4byte 0 /* Length of kernel
payload */
+setup_data: .8byte 0 /* 64bit pointer to
linked list of struct setup_data */
+pref_address: .8byte vmlinuz_load_address /* Preferred loading
address */
+init_size: .4byte vmlinuz_size /* Linear memory
required during initialization */
+handover_offset: .4byte 0 /* Offset of handover
entry point */
+
+.text
+ # The address of the boot_params structure is passed in the RSI
+ # register so store it in RDI register so that it can be received
+ # by the extract_linux_boot_params fuction later
+ mov %esi, %edi
+ mov $OSV_KERNEL_BASE, %ebp
+ mov $0x7c00, %esp # Allocate some temporary stack
+ jmp *start32_from_vmlinuz
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit
https://groups.google.com/d/msgid/osv-dev/000000000000a86777058cba1979%40google.com.
For more options, visit https://groups.google.com/d/optout.