From nobody Fri Nov 7 14:44:56 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1548095394266384.4255369140377; Mon, 21 Jan 2019 10:29:54 -0800 (PST) Received: from localhost ([127.0.0.1]:57666 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gleKS-0006VN-Rv for importer@patchew.org; Mon, 21 Jan 2019 13:29:48 -0500 Received: from eggs.gnu.org ([209.51.188.92]:51831) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gldyF-0004Uo-4A for qemu-devel@nongnu.org; Mon, 21 Jan 2019 13:06:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gldyD-0004Ia-Pe for qemu-devel@nongnu.org; Mon, 21 Jan 2019 13:06:51 -0500 Received: from mail-wm1-x341.google.com ([2a00:1450:4864:20::341]:50682) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1gldyD-0004Hm-J7 for qemu-devel@nongnu.org; Mon, 21 Jan 2019 13:06:49 -0500 Received: by mail-wm1-x341.google.com with SMTP id n190so11756591wmd.0 for ; Mon, 21 Jan 2019 10:06:49 -0800 (PST) Received: from 640k.lan ([93.56.166.5]) by smtp.gmail.com with ESMTPSA id 133sm56197732wme.9.2019.01.21.10.06.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 21 Jan 2019 10:06:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=QUma4t1tU+F2NnSGGYg8GDfcyFpiM/9bz2RrPKxKXKU=; b=XgazOgkNfyPTeJG8tbAOZloY/luMK3MwcInF1/ZUrWweBtTMnXTwoy3WFDJ2O0MAm1 F9MUQAhpoZ/ocMMrdaaEyCcIypMy1V8WbxlhdH3+QgtomH4LQPzKZxFHgtL7Ov+/tcJi H38PH17YgPRYYAdqvOSNbOBpIL38x4tqAo2gU274sjrGkIv+v2gewQQCurhNA5uqHWVY QcIOIpXkUDJnf3rCN4wOyaWY1acQEo5iSCAHgRbDAMQHF3aH8wFghGrfWw8CBRit7QS+ cTENcBvMzv2HopgjdXJ6UpeRIDfriNvY3MUJ11bkPgj6Dl5mXpIeCRMntIRmVjZ65Jl8 ZsXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=QUma4t1tU+F2NnSGGYg8GDfcyFpiM/9bz2RrPKxKXKU=; b=OOtTBNNUvwH6DD/9yxI05HHcCgvBDSTWevhLHMmi7V5+HuzxoudGGqy4cb0v34br2Y Nbth2VITg2sL79DPojXjNPTHyq6Oons/qgLeK452ZKxb1CT+4zgtrGXim10+OUrg3Umt JF6YMtXFV91bG52M1+jDwJgcFKfH264a4QSEeVYnr0S98sZH1pYZdbsYZX9yAQQb/9CX CQSl3vZyreOCISPsmNiIJPNy/vCkqJ4bzPZWppejz6jCiNeqWzHDMtCHGcvXmxDaYIYB kJBEdYyI3JJJfrtWD2+3JLiA7tjK9bbUsVeM+CnqFBv+Zo+GE/gVET7y466uWEfcH3Ab d8sg== X-Gm-Message-State: AJcUukd7fqQFVNCPKhsIlCfSy/Wd+FHP2nOSuOZ9ANalYcdI6/kV8xYG 8QQQRmQmR0GcbPuT8SvWhmVhNnwo X-Google-Smtp-Source: ALg8bN4fv2hawTlz0jz431WX5NW5S+rXC8Vii5Fa20I4SXuyqO5HXr2FMCcMGvB8OULzMsWFUEOAPw== X-Received: by 2002:a1c:ef11:: with SMTP id n17mr424588wmh.112.1548094008085; Mon, 21 Jan 2019 10:06:48 -0800 (PST) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Mon, 21 Jan 2019 19:05:57 +0100 Message-Id: <1548093980-43088-27-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1548093980-43088-1-git-send-email-pbonzini@redhat.com> References: <1548093980-43088-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::341 Subject: [Qemu-devel] [PULL 26/49] pvh: Boot uncompressed kernel using direct boot ABI X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: George Kennedy Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Liam Merwick These changes (along with corresponding Linux kernel and qboot changes) enable a guest to be booted using the x86/HVM direct boot ABI. This commit adds a load_elfboot() routine to pass the size and location of the kernel entry point to qboot (which will fill in the start_info struct information needed to to boot the guest). Having loaded the ELF binary, load_linux() will run qboot which continues the boot. The address for the kernel entry point is read from an ELF Note in the uncompressed kernel binary by a helper routine passed to load_elf(). Co-developed-by: George Kennedy Signed-off-by: George Kennedy Signed-off-by: Liam Merwick Signed-off-by: Paolo Bonzini --- hw/i386/pc.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ include/elf.h | 10 +++++ 2 files changed, 145 insertions(+) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 73d688f..6d54995 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -54,6 +54,7 @@ #include "sysemu/qtest.h" #include "kvm_i386.h" #include "hw/xen/xen.h" +#include "hw/xen/start_info.h" #include "ui/qemu-spice.h" #include "exec/memory.h" #include "exec/address-spaces.h" @@ -110,6 +111,9 @@ static struct e820_entry *e820_table; static unsigned e820_entries; struct hpet_fw_config hpet_cfg =3D {.count =3D UINT8_MAX}; =20 +/* Physical Address of PVH entry point read from kernel ELF NOTE */ +static size_t pvh_start_addr; + GlobalProperty pc_compat_3_1[] =3D { { "intel-iommu", "dma-drain", "off" }, { "Opteron_G3" "-" TYPE_X86_CPU, "rdtscp", "off" }, @@ -1060,6 +1064,109 @@ struct setup_data { uint8_t data[0]; } __attribute__((packed)); =20 + +/* + * The entry point into the kernel for PVH boot is different from + * the native entry point. The PVH entry is defined by the x86/HVM + * direct boot ABI and is available in an ELFNOTE in the kernel binary. + * + * This function is passed to load_elf() when it is called from + * load_elfboot() which then additionally checks for an ELF Note of + * type XEN_ELFNOTE_PHYS32_ENTRY and passes it to this function to + * parse the PVH entry address from the ELF Note. + * + * Due to trickery in elf_opts.h, load_elf() is actually available as + * load_elf32() or load_elf64() and this routine needs to be able + * to deal with being called as 32 or 64 bit. + * + * The address of the PVH entry point is saved to the 'pvh_start_addr' + * global variable. (although the entry point is 32-bit, the kernel + * binary can be either 32-bit or 64-bit). + */ +static uint64_t read_pvh_start_addr(void *arg1, void *arg2, bool is64) +{ + size_t *elf_note_data_addr; + + /* Check if ELF Note header passed in is valid */ + if (arg1 =3D=3D NULL) { + return 0; + } + + if (is64) { + struct elf64_note *nhdr64 =3D (struct elf64_note *)arg1; + uint64_t nhdr_size64 =3D sizeof(struct elf64_note); + uint64_t phdr_align =3D *(uint64_t *)arg2; + uint64_t nhdr_namesz =3D nhdr64->n_namesz; + + elf_note_data_addr =3D + ((void *)nhdr64) + nhdr_size64 + + QEMU_ALIGN_UP(nhdr_namesz, phdr_align); + } else { + struct elf32_note *nhdr32 =3D (struct elf32_note *)arg1; + uint32_t nhdr_size32 =3D sizeof(struct elf32_note); + uint32_t phdr_align =3D *(uint32_t *)arg2; + uint32_t nhdr_namesz =3D nhdr32->n_namesz; + + elf_note_data_addr =3D + ((void *)nhdr32) + nhdr_size32 + + QEMU_ALIGN_UP(nhdr_namesz, phdr_align); + } + + pvh_start_addr =3D *elf_note_data_addr; + + return pvh_start_addr; +} + +static bool load_elfboot(const char *kernel_filename, + int kernel_file_size, + uint8_t *header, + size_t pvh_xen_start_addr, + FWCfgState *fw_cfg) +{ + uint32_t flags =3D 0; + uint32_t mh_load_addr =3D 0; + uint32_t elf_kernel_size =3D 0; + uint64_t elf_entry; + uint64_t elf_low, elf_high; + int kernel_size; + + if (ldl_p(header) !=3D 0x464c457f) { + return false; /* no elfboot */ + } + + bool elf_is64 =3D header[EI_CLASS] =3D=3D ELFCLASS64; + flags =3D elf_is64 ? + ((Elf64_Ehdr *)header)->e_flags : ((Elf32_Ehdr *)header)->e_flags; + + if (flags & 0x00010004) { /* LOAD_ELF_HEADER_HAS_ADDR */ + error_report("elfboot unsupported flags =3D %x", flags); + exit(1); + } + + uint64_t elf_note_type =3D XEN_ELFNOTE_PHYS32_ENTRY; + kernel_size =3D load_elf(kernel_filename, read_pvh_start_addr, + NULL, &elf_note_type, &elf_entry, + &elf_low, &elf_high, 0, I386_ELF_MACHINE, + 0, 0); + + if (kernel_size < 0) { + error_report("Error while loading elf kernel"); + exit(1); + } + mh_load_addr =3D elf_low; + elf_kernel_size =3D elf_high - elf_low; + + if (pvh_start_addr =3D=3D 0) { + error_report("Error loading uncompressed kernel without PVH ELF No= te"); + exit(1); + } + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ENTRY, pvh_start_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, mh_load_addr); + fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, elf_kernel_size); + + return true; +} + static void load_linux(PCMachineState *pcms, FWCfgState *fw_cfg) { @@ -1099,6 +1206,34 @@ static void load_linux(PCMachineState *pcms, if (ldl_p(header+0x202) =3D=3D 0x53726448) { protocol =3D lduw_p(header+0x206); } else { + /* + * Check if the file is an uncompressed kernel file (ELF) and load= it, + * saving the PVH entry point used by the x86/HVM direct boot ABI. + * If load_elfboot() is successful, populate the fw_cfg info. + */ + if (load_elfboot(kernel_filename, kernel_size, + header, pvh_start_addr, fw_cfg)) { + struct hvm_modlist_entry ramdisk_mod =3D { 0 }; + + fclose(f); + + fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, + strlen(kernel_cmdline) + 1); + fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline); + + assert(machine->device_memory !=3D NULL); + ramdisk_mod.paddr =3D machine->device_memory->base; + ramdisk_mod.size =3D + memory_region_size(&machine->device_memory->mr); + + fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, &ramdisk_mod, + sizeof(ramdisk_mod)); + fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, sizeof(header)); + fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, + header, sizeof(header)); + + return; + } /* This looks like a multiboot kernel. If it is, let's stop treating it like a Linux kernel. */ if (load_multiboot(fw_cfg, f, kernel_filename, initrd_filename, diff --git a/include/elf.h b/include/elf.h index e816fb4..b35347e 100644 --- a/include/elf.h +++ b/include/elf.h @@ -1640,6 +1640,16 @@ typedef struct elf64_shdr { #define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registe= rs */ #define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */ =20 +/* + * Physical entry point into the kernel. + * + * 32bit entry point into the kernel. When requested to launch the + * guest kernel, use this entry point to launch the guest in 32-bit + * protected mode with paging disabled. + * + * [ Corresponding definition in Linux kernel: include/xen/interface/elfno= te.h ] + */ +#define XEN_ELFNOTE_PHYS32_ENTRY 18 /* 0x12 */ =20 /* Note header in a PT_NOTE section */ typedef struct elf32_note { --=20 1.8.3.1