From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56736) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bjsaN-0001C8-Df for qemu-devel@nongnu.org; Tue, 13 Sep 2016 14:37:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bjsaK-0003kI-Lm for qemu-devel@nongnu.org; Tue, 13 Sep 2016 14:37:35 -0400 Received: from mx1.redhat.com ([209.132.183.28]:37856) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bjsaK-0003jp-Eg for qemu-devel@nongnu.org; Tue, 13 Sep 2016 14:37:32 -0400 Date: Tue, 13 Sep 2016 21:37:28 +0300 From: "Michael S. Tsirkin" Message-ID: <20160913183728.qcmhrxii44pug7ck@redhat.com> References: <147377800565.11859.4411044563640180545.stgit@brijesh-build-machine> <147377816978.11859.942423377333907417.stgit@brijesh-build-machine> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <147377816978.11859.942423377333907417.stgit@brijesh-build-machine> Subject: Re: [Qemu-devel] [RFC PATCH v1 16/22] i386: pc: load OS images at fixed location in SEV-enabled guest List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Brijesh Singh Cc: ehabkost@redhat.com, crosthwaite.peter@gmail.com, armbru@redhat.com, p.fedin@samsung.com, qemu-devel@nongnu.org, lcapitulino@redhat.com, pbonzini@redhat.com, rth@twiddle.net On Tue, Sep 13, 2016 at 10:49:29AM -0400, Brijesh Singh wrote: > Typically linux kernel, initrd and cmdline are build and loaded > into guest memory through linux optionrom. The linux optionrom is > probed and executed by SeaBIOS. This method will not work for > SEV-enabled guest. > > In SEV-enabled guest all the code and data must be copied using SEV > launch command prior to starting the guest (i.e before first vmrun). > The data copied using SEV launch command will be encrypted using guest > owner's key. This patch loads kernel, initrd and cmdline blobs at fixed > location into guest memory and builds etc/sev_cfg config file. The cfg > file provide the below structure > > struct sev_cfg { > u32 kernel_addr, initrd_addr, cmdline_addr; > u32 kernel_size, initrd_size, cmdline_size; > } > > The config file can be used by SeaBIOS to locate OS images into guest > RAM and build linux boot entry code. > > Signed-off-by: Brijesh Singh I don't think we want to give users this kind of control over how we manage memory internally for what is essentially a debugging feature at this point. Isn't there a way to first launch guest, and then have it encrypt itself once it's running? If not, I guess it's not too bad if -kernel does not work with sev debug feature - just load kernel from disk. > --- > hw/i386/pc.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 93 insertions(+), 1 deletion(-) > > diff --git a/hw/i386/pc.c b/hw/i386/pc.c > index 1471df4..f2c7472 100644 > --- a/hw/i386/pc.c > +++ b/hw/i386/pc.c > @@ -104,6 +104,15 @@ static struct e820_entry *e820_table; > static unsigned e820_entries; > struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX}; > > +struct sev_cfg_data { > + uint32_t kernel_addr; > + uint32_t initrd_addr; > + uint32_t cmdline_addr; > + uint32_t kernel_size; > + uint32_t initrd_size; > + uint32_t cmdline_size; > +} QEMU_PACKED __attribute((__aligned__(4))); > + > void gsi_handler(void *opaque, int n, int level) > { > GSIState *s = opaque; > @@ -824,6 +833,86 @@ struct setup_data { > uint8_t data[0]; > } __attribute__((packed)); > > +#define round_up(x, align) ((x + align) & ~(align - 1)) > + > +static void sev_load_file_fixed(const char *filename, int start, > + int *end, int *sz) > +{ > + FILE *f; > + int sz_aligned, ret; > + char *data; > + > + f = fopen(filename, "rb"); > + if (!f) { > + fprintf(stderr, "qemu: could not load '%s': %s\n", > + filename, strerror(errno)); > + exit(1); > + } > + > + /* SEV update commands needs 16-byte aligned length */ > + *sz = get_file_size(f); > + sz_aligned = round_up(*sz, 16); > + data = g_malloc(sz_aligned); > + ret = fread(data, 1, *sz, f); > + if (ret != *sz) { > + fprintf(stderr, "qemu: failed to read %d bytes from %s\n", > + *sz, filename); > + exit(1); > + } > + rom_add_blob_fixed(filename, data, sz_aligned, start); > + *end = start + sz_aligned; > + fclose(f); > + g_free(data); > +} > + > +/* load kernel, initrd and cmdline blobs at fixed location into guest > + * memory and generate etc/sev config file. > + */ > +static void sev_load_linux(PCMachineState *pcms, > + FWCfgState *fw_cfg) > +{ > + FILE *f; > + int cmdline_size, kernel_size, initrd_size; > + int initrd_addr, kernel_addr, cmdline_addr, end; > + MachineState *machine = MACHINE(pcms); > + const char *kernel_cmdline = machine->kernel_cmdline; > + struct sev_cfg_data *sev_cfg; > + char *cmdline_string; > + > + /* load kernel command line string */ > + cmdline_addr = 0x1000000; > + cmdline_size = round_up(strlen(kernel_cmdline), 16); > + cmdline_string = g_malloc(cmdline_size); > + strncpy(cmdline_string, kernel_cmdline, strlen(kernel_cmdline)); > + rom_add_blob_fixed("cmdline", cmdline_string, cmdline_size, cmdline_addr); > + g_free(cmdline_string); > + > + /* load linux kernel */ > + kernel_addr = cmdline_addr + cmdline_size; > + sev_load_file_fixed(machine->kernel_filename, kernel_addr, > + &initrd_addr, &kernel_size); > + > + /* load initrd */ > + f = fopen(machine->initrd_filename, "rb"); > + if (f) { > + sev_load_file_fixed(machine->initrd_filename, initrd_addr, > + &end, &initrd_size); > + } else { > + initrd_addr = 0; > + initrd_size = 0; > + } > + > + sev_cfg = g_malloc0(sizeof(*sev_cfg)); > + sev_cfg->kernel_addr = kernel_addr; > + sev_cfg->initrd_addr = initrd_addr; > + sev_cfg->cmdline_addr = cmdline_addr; > + sev_cfg->kernel_size = kernel_size; > + sev_cfg->initrd_size = initrd_size; > + sev_cfg->cmdline_size = cmdline_size; > + > + fw_cfg_add_file(fw_cfg, "etc/sev_cfg", sev_cfg, sizeof(*sev_cfg)); > +} > + > static void load_linux(PCMachineState *pcms, > FWCfgState *fw_cfg) > { > @@ -1471,7 +1560,10 @@ void pc_memory_init(PCMachineState *pcms, > } > > if (linux_boot) { > - load_linux(pcms, fw_cfg); > + if (kvm_sev_enabled()) > + sev_load_linux(pcms, fw_cfg); > + else > + load_linux(pcms, fw_cfg); > } > > for (i = 0; i < nb_option_roms; i++) {