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.

Reply via email to