qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Liam Merwick <liam.merwick@oracle.com>
To: Stefano Garzarella <sgarzare@redhat.com>, qemu-devel@nongnu.org
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>,
	Eduardo Habkost <ehabkost@redhat.com>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	Gerd Hoffmann <kraxel@redhat.com>,
	George Kennedy <george.kennedy@oracle.com>,
	Marcel Apfelbaum <marcel.apfelbaum@gmail.com>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Eric Blake <eblake@redhat.com>,
	Marc-Andre Lureau <marcandre.lureau@redhat.com>,
	Richard Henderson <rth@twiddle.net>,
	Stefan Hajnoczi <stefanha@redhat.com>,
	Maran Wilson <maran.wilson@oracle.com>,
	liam.merwick@oracle.com
Subject: Re: [Qemu-devel] [PATCH v2 3/4] optionrom: add new PVH option rom
Date: Wed, 16 Jan 2019 10:16:04 +0000	[thread overview]
Message-ID: <9737a9f4-bc26-73fd-f3ee-b394b46d861b@oracle.com> (raw)
In-Reply-To: <20190115100058.44712-4-sgarzare@redhat.com>

Hi Stefano,

Code LGTM, just a few minor comments below

On 15/01/2019 10:00, Stefano Garzarella wrote:
> The new pvh.bin option rom can be used with SeaBIOS to boot
> uncompressed kernel using the x86/HVM direct boot ABI.
> 
> pvh.S contains the entry point of the option rom. It runs
> in real mode, loads the e820 table querying the BIOS, and
> then it switches to 32bit protect mode and jump to the

"protect" -> "protected"
"jump" -> "jumps"

> pvh_load_kernel() written in pvh_main.c.
> pvh_load_kernel() loads the cmdline and kernel entry_point
> using fw_cfg, then it looks for RSDP, fills the
> hvm_start_info required by x86/HVM ABI, and finally jumps
> to the kernel entry_point.
> 
> Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>   pc-bios/optionrom/Makefile   |   5 +-
>   pc-bios/optionrom/pvh.S      | 200 +++++++++++++++++++++++++++++++++++
>   pc-bios/optionrom/pvh_main.c | 117 ++++++++++++++++++++
>   3 files changed, 321 insertions(+), 1 deletion(-)
>   create mode 100644 pc-bios/optionrom/pvh.S
>   create mode 100644 pc-bios/optionrom/pvh_main.c
> 
> diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile
> index a9a9e5e7eb..92c91d9949 100644
> --- a/pc-bios/optionrom/Makefile
> +++ b/pc-bios/optionrom/Makefile
> @@ -37,7 +37,7 @@ Wa = -Wa,
>   ASFLAGS += -32
>   QEMU_CFLAGS += $(call cc-c-option, $(QEMU_CFLAGS), $(Wa)-32)
>   
> -build-all: multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin
> +build-all: multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin
>   
>   # suppress auto-removal of intermediate files
>   .SECONDARY:
> @@ -46,6 +46,9 @@ build-all: multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin
>   %.o: %.S
>   	$(call quiet-command,$(CPP) $(QEMU_INCLUDES) $(QEMU_DGFLAGS) -c -o - $< | $(AS) $(ASFLAGS) -o $@,"AS","$(TARGET_DIR)$@")
>   
> +%.img: %.o %_main.o
> +	$(call quiet-command,$(LD) $(LDFLAGS_NOPIE) -m $(LD_I386_EMULATION) -T $(SRC_PATH)/pc-bios/optionrom/flat.lds -s -o $@ $?,"BUILD","$(TARGET_DIR)$@")
> +
>   %.img: %.o
>   	$(call quiet-command,$(LD) $(LDFLAGS_NOPIE) -m $(LD_I386_EMULATION) -T $(SRC_PATH)/pc-bios/optionrom/flat.lds -s -o $@ $<,"BUILD","$(TARGET_DIR)$@")
>   
> diff --git a/pc-bios/optionrom/pvh.S b/pc-bios/optionrom/pvh.S
> new file mode 100644
> index 0000000000..e1d7f4a7a7
> --- /dev/null
> +++ b/pc-bios/optionrom/pvh.S
> @@ -0,0 +1,200 @@
> +/*
> + * PVH Option ROM
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + * Copyright Novell Inc, 2009
> + *   Authors: Alexander Graf <agraf@suse.de>
> + *
> + * Copyright (c) 2019 Red Hat Inc.
> + *   Authors: Stefano Garzarella <sgarzare@redhat.com>
> + */
> +
> +#include "optionrom.h"
> +
> +#define BOOT_ROM_PRODUCT "PVH loader"
> +
> +#define GS_PROT_JUMP		0
> +#define GS_GDT_DESC		6
> +
> +#ifdef OPTION_ROM_START
> +#undef OPTION_ROM_START
> +#endif
> +#ifdef OPTION_ROM_END
> +#undef OPTION_ROM_END
> +#endif
> +
> +/*
> + * Redefine OPTION_ROM_START and OPTION_ROM_END, because this rom is produced
> + * linking multiple objects.
> + * signrom.py will add padding.
> + */
> +#define OPTION_ROM_START                                \
> +    .code16;						\
> +    .text;						\
> +	.global 	_start;				\
> +    _start:;						\
> +	.short		0xaa55;				\
> +	.byte		3; /* desired size in 512 units */
> +
> +#define OPTION_ROM_END					\
> +    _end:
> +
> +BOOT_ROM_START
> +
> +run_pvhboot:
> +
> +	cli
> +	cld
> +
> +	mov		%cs, %eax
> +	shl		$0x4, %eax
> +
> +	/* set up a long jump descriptor that is PC relative */
> +
> +	/* move stack memory to %gs */
> +	mov		%ss, %ecx
> +	shl		$0x4, %ecx
> +	mov		%esp, %ebx
> +	add		%ebx, %ecx
> +	sub		$0x20, %ecx
> +	sub		$0x30, %esp
> +	shr		$0x4, %ecx
> +	mov		%cx, %gs
> +
> +	/* now push the indirect jump descriptor there */
> +	mov		(prot_jump), %ebx
> +	add		%eax, %ebx
> +	movl		%ebx, %gs:GS_PROT_JUMP
> +	mov		$8, %bx
> +	movw		%bx, %gs:GS_PROT_JUMP + 4
> +
> +	/* fix the gdt descriptor to be PC relative */
> +	movw		(gdt_desc), %bx
> +	movw		%bx, %gs:GS_GDT_DESC
> +	movl		(gdt_desc+2), %ebx
> +	add		%eax, %ebx
> +	movl		%ebx, %gs:GS_GDT_DESC + 2
> +
> +	/* initialize HVM memmap table using int 0x15(e820) */
> +
> +	/* ES = pvh_e820 struct */
> +	mov 		$pvh_e820, %eax
> +	shr		$4, %eax
> +	mov		%ax, %es
> +
> +	/* start storing memmap table at %es:8 (pvh_e820.table) */
> +	mov 		$8,%edi
> +	xor		%ebx, %ebx
> +	jmp 		memmap_loop
> +
> +memmap_loop_check:
> +	/* pvh_e820 can contains up to 128 entries */
> +	cmp 		$128, %ebx
> +	je 		memmap_done
> +
> +memmap_loop:
> +	/* entry size (hvm_memmap_table_entry) & max buffer size (int15) */
> +	movl		$24, %ecx
> +	/* e820 */
> +	movl		$0x0000e820, %eax
> +	/* 'SMAP' magic */
> +	movl		$0x534d4150, %edx
> +	/* store counter value at %es:0 (pvh_e820.entries) */
> +	movl 		%ebx, %es:0
> +
> +	int		$0x15
> +	/* error or last entry already done? */
> +	jb		memmap_err
> +
> +	/* %edi += entry size (hvm_memmap_table_entry) */
> +	add		$24, %edi
> +
> +	/* continuation value 0 means last entry */
> +	test		%ebx, %ebx
> +	jnz		memmap_loop_check
> +
> +	/* increase pvh_e820.entries to save the last entry */
> +	movl 		%es:0, %ebx
> +	inc 		%ebx
> +
> +memmap_done:
> +	movl 		%ebx, %es:0
> +
> +memmap_err:
> +
> +	/* load the GDT before going into protected mode */
> +lgdt:
> +	data32 lgdt	%gs:GS_GDT_DESC
> +
> +	/* get us to protected mode now */
> +	movl		$1, %eax
> +	movl		%eax, %cr0
> +
> +	/* the LJMP sets CS for us and gets us to 32-bit */
> +ljmp:
> +	data32 ljmp	*%gs:GS_PROT_JUMP
> +
> +prot_mode:
> +.code32
> +
> +	/* initialize all other segments */
> +	movl		$0x10, %eax
> +	movl		%eax, %ss
> +	movl		%eax, %ds
> +	movl		%eax, %es
> +	movl		%eax, %fs
> +	movl		%eax, %gs
> +
> +	jmp pvh_load_kernel
> +
> +/* Variables */
> +.align 4, 0
> +prot_jump:	.long prot_mode
> +		.short 8
> +
> +.align 4, 0
> +gdt:
> +	/* 0x00 */
> +.byte	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +
> +	/*
> +	 * 0x08: code segment
> +	 * (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k)
> +	 */
> +.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x9a, 0xcf, 0x00
> +
> +	/*
> +	 * 0x10: data segment
> +	 * (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k)
> +	 */
> +.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0xcf, 0x00
> +
> +	/*
> +	 * 0x18: code segment
> +	 * (base=0, limit=0x0ffff, type=16bit code exec/read/conf, DPL=0, 1b)
> +	 */
> +.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00
> +
> +	/*
> +	 * 0x20: data segment
> +	 * (base=0, limit=0x0ffff, type=16bit data read/write, DPL=0, 1b)
> +	 */
> +.byte	0xff, 0xff, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00
> +
> +gdt_desc:
> +.short	(5 * 8) - 1
> +.long	gdt
> +
> +BOOT_ROM_END
> diff --git a/pc-bios/optionrom/pvh_main.c b/pc-bios/optionrom/pvh_main.c
> new file mode 100644
> index 0000000000..9100952463
> --- /dev/null
> +++ b/pc-bios/optionrom/pvh_main.c
> @@ -0,0 +1,117 @@
> +/*
> + * PVH Option ROM for fw_cfg DMA
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + * Copyright (c) 2019 Red Hat Inc.
> + *   Authors:
> + *     Stefano Garzarella <sgarzare@redhat.com>
> + */
> +
> +asm (".code32"); /* this code will be executed in protect mode */


"protect" -> "protected"


> +
> +#include <stddef.h>
> +#include <stdint.h>
> +#include "optrom.h"
> +#include "optrom_fw_cfg.h"
> +#include "../../include/hw/xen/start_info.h"
> +
> +#define RSDP_SIGNATURE          0x2052545020445352LL /* "RSD PTR " */
> +#define RSDP_AREA_ADDR          0x000E0000
> +#define RSDP_AREA_SIZE          2048
> +#define EBDA_BASE_ADDR          0x0000040E
> +#define EBDA_SIZE               1024
> +
> +#define E820_MAXENTRIES         128
> +#define CMDLINE_BUFSIZE         4096
> +
> +/* e820 table filled in pvh.S using int 0x15 */
> +struct pvh_e820_table {
> +    uint32_t entries;
> +    uint32_t reserved;
> +    struct hvm_memmap_table_entry table[E820_MAXENTRIES];
> +};
> +
> +struct pvh_e820_table pvh_e820 __attribute__ ((aligned));
> +
> +struct hvm_start_info start_info;

Can this be static?

> +struct hvm_modlist_entry ramdisk_mod;

Is this used?

> +uint8_t cmdline_buffer[CMDLINE_BUFSIZE];

Can this be static?

> +
> +
> +/* Search RSDP signature. */
> +static uintptr_t search_rsdp(uint32_t start_addr, uint32_t end_addr)
> +{
> +    uint64_t *rsdp_p;
> +
> +    /* RSDP signature is always on a 16 byte boundary */
> +    for (rsdp_p = (uint64_t *)start_addr; rsdp_p < (uint64_t *)end_addr;
> +         rsdp_p += 2) {
> +        if (*rsdp_p == RSDP_SIGNATURE) {
> +            return (uintptr_t)rsdp_p;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +/* Force the asm name without leading underscore, even on Win32. */
> +extern void pvh_load_kernel(void) asm("pvh_load_kernel");
> +
> +void pvh_load_kernel(void)
> +{
> +    void *cmdline_addr = &cmdline_buffer;
> +    void *kernel_entry;
> +    uint32_t cmdline_size, fw_cfg_version = bios_cfg_version();
> +
> +    start_info.magic = XEN_HVM_START_MAGIC_VALUE;
> +    start_info.version = 1;
> +
> +    /*
> +     * pvh_e820 is filled in the pvh.S before to switch in protected mode,
> +     * because we can use int 0x15 only in real mode.
> +     */
> +    start_info.memmap_entries = pvh_e820.entries;
> +    start_info.memmap_paddr = (uintptr_t)pvh_e820.table;
> +
> +    /*
> +     * Search RSDP in the main BIOS area below 1 MB.
> +     * SeaBIOS store the RSDP in this area, so we try it first.
> +     */
> +    start_info.rsdp_paddr = search_rsdp(RSDP_AREA_ADDR,
> +                                        RSDP_AREA_ADDR + RSDP_AREA_SIZE);
> +
> +    /* Search RSDP in the EBDA if it is not found */
> +    if (!start_info.rsdp_paddr) {
> +        /*
> +         * Th EBDA address is stored at EBDA_BASE_ADDR. It contains 2 bytes
> +         * segment pointer to EBDA, so we must convert it to a linear address.
> +         */
> +        uint32_t ebda_paddr = ((uint32_t)*((uint16_t *)EBDA_BASE_ADDR)) << 4;
> +        if (ebda_paddr > 0x400) {
> +            uint32_t *ebda = (uint32_t *)ebda_paddr;
> +
> +            start_info.rsdp_paddr = search_rsdp(*ebda, *ebda + EBDA_SIZE);
> +        }
> +    }
> +
> +    bios_cfg_read_entry(&cmdline_size, FW_CFG_CMDLINE_SIZE, 4, fw_cfg_version);
> +    bios_cfg_read_entry(cmdline_addr, FW_CFG_CMDLINE_DATA, cmdline_size,
> +                        fw_cfg_version);
> +    start_info.cmdline_paddr = (uintptr_t)cmdline_addr;
> +
> +    bios_cfg_read_entry(&kernel_entry, FW_CFG_KERNEL_ENTRY, 4, fw_cfg_version);
> +
> +    asm volatile("jmp *%1" : : "b"(&start_info), "c"(kernel_entry));
> +}
> 

  reply	other threads:[~2019-01-16 10:31 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-15 10:00 [Qemu-devel] [PATCH v2 0/4] pvh: add new PVH option rom Stefano Garzarella
2019-01-15 10:00 ` [Qemu-devel] [PATCH v2 1/4] linuxboot_dma: remove duplicate definitions of FW_CFG Stefano Garzarella
2019-01-15 10:00 ` [Qemu-devel] [PATCH v2 2/4] linuxboot_dma: move common functions in a new header Stefano Garzarella
2019-01-15 10:00 ` [Qemu-devel] [PATCH v2 3/4] optionrom: add new PVH option rom Stefano Garzarella
2019-01-16 10:16   ` Liam Merwick [this message]
2019-01-16 11:02     ` Stefano Garzarella
2019-01-15 10:00 ` [Qemu-devel] [PATCH v2 4/4] hw/i386/pc: use " Stefano Garzarella
2019-01-15 18:57   ` Michael S. Tsirkin
2019-01-15 19:12     ` Eric Blake
2019-01-15 20:05       ` Michael S. Tsirkin
2019-01-15 21:50         ` Paolo Bonzini
2019-01-16  8:19         ` Stefano Garzarella
2019-01-16  8:22       ` Stefano Garzarella
2019-01-18 17:33     ` Eduardo Habkost
2019-01-15 14:24 ` [Qemu-devel] [PATCH v2 0/4] pvh: add new " Stefan Hajnoczi
2019-01-16 10:18 ` Liam Merwick

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9737a9f4-bc26-73fd-f3ee-b394b46d861b@oracle.com \
    --to=liam.merwick@oracle.com \
    --cc=boris.ostrovsky@oracle.com \
    --cc=eblake@redhat.com \
    --cc=ehabkost@redhat.com \
    --cc=george.kennedy@oracle.com \
    --cc=kraxel@redhat.com \
    --cc=maran.wilson@oracle.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=marcel.apfelbaum@gmail.com \
    --cc=mst@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rth@twiddle.net \
    --cc=sgarzare@redhat.com \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).