From patchwork Thu Jun 14 14:53:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Huth X-Patchwork-Id: 929501 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4166G46x74z9s19 for ; Fri, 15 Jun 2018 00:59:08 +1000 (AEST) Received: from localhost ([::1]:41126 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fTTiM-0003DZ-P3 for incoming@patchwork.ozlabs.org; Thu, 14 Jun 2018 10:59:06 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39995) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fTTd3-00073C-Cm for qemu-devel@nongnu.org; Thu, 14 Jun 2018 10:53:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fTTd2-0006TT-0Y for qemu-devel@nongnu.org; Thu, 14 Jun 2018 10:53:37 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:42942 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fTTd1-0006TF-QI; Thu, 14 Jun 2018 10:53:35 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 49D88818BAFD; Thu, 14 Jun 2018 14:53:35 +0000 (UTC) Received: from thh440s.redhat.com (ovpn-116-79.ams2.redhat.com [10.36.116.79]) by smtp.corp.redhat.com (Postfix) with ESMTP id A8E571C5AD; Thu, 14 Jun 2018 14:53:33 +0000 (UTC) From: Thomas Huth To: Cornelia Huck , qemu-s390x@nongnu.org Date: Thu, 14 Jun 2018 16:53:20 +0200 Message-Id: <1528988003-21855-5-git-send-email-thuth@redhat.com> In-Reply-To: <1528988003-21855-1-git-send-email-thuth@redhat.com> References: <1528988003-21855-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 14 Jun 2018 14:53:35 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Thu, 14 Jun 2018 14:53:35 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'thuth@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL SUBSYSTEM s390x 4/7] pc-bios/s390-ccw/net: Add support for pxelinux-style config files 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: Alexey Kardashevskiy , Christian Borntraeger , Collin Walling , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" Since it is quite cumbersome to manually create a combined kernel with initrd image for network booting, we now support loading via pxelinux configuration files, too. In these files, the kernel, initrd and command line parameters can be specified seperately, and the firmware then takes care of glueing everything together in memory after the files have been downloaded. See this URL for details about the config file layout: https://www.syslinux.org/wiki/index.php?title=PXELINUX The user can either specify a config file directly as bootfile via DHCP (but in this case, the file has to start either with "default" or a "#" comment so we can distinguish it from binary kernels), or a folder (i.e. the bootfile name must end with "/") where the firmware should look for the typical pxelinux.cfg file names, e.g. based on MAC or IP address. We also support the pxelinux.cfg DHCP options 209 and 210 from RFC 5071. Acked-by: Christian Borntraeger Tested-by: Viktor Mihajlovski Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/netboot.mak | 7 ++-- pc-bios/s390-ccw/netmain.c | 86 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 4 deletions(-) diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak index a73be36..8af0cfd 100644 --- a/pc-bios/s390-ccw/netboot.mak +++ b/pc-bios/s390-ccw/netboot.mak @@ -25,8 +25,9 @@ CTYPE_OBJS = isdigit.o isxdigit.o toupper.o %.o : $(SLOF_DIR)/lib/libc/ctype/%.c $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") -STRING_OBJS = strcat.o strchr.o strcmp.o strcpy.o strlen.o strncmp.o strncpy.o \ - strstr.o memset.o memcpy.o memmove.o memcmp.o +STRING_OBJS = strcat.o strchr.o strrchr.o strcpy.o strlen.o strncpy.o \ + strcmp.o strncmp.o strcasecmp.o strncasecmp.o strstr.o \ + memset.o memcpy.o memmove.o memcmp.o %.o : $(SLOF_DIR)/lib/libc/string/%.c $(call quiet-command,$(CC) $(LIBC_CFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") @@ -50,7 +51,7 @@ libc.a: $(LIBCOBJS) # libnet files: LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \ - dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o + dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o LIBNETCFLAGS := $(QEMU_CFLAGS) -DDHCPARCH=0x1F $(LIBC_INC) $(LIBNET_INC) %.o : $(SLOF_DIR)/lib/libnet/%.c diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c index d007fb7..c059546 100644 --- a/pc-bios/s390-ccw/netmain.c +++ b/pc-bios/s390-ccw/netmain.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "s390-ccw.h" #include "virtio.h" @@ -41,12 +42,14 @@ extern char _start[]; #define KERNEL_ADDR ((void *)0L) #define KERNEL_MAX_SIZE ((long)_start) +#define ARCH_COMMAND_LINE_SIZE 896 /* Taken from Linux kernel */ char stack[PAGE_SIZE * 8] __attribute__((aligned(PAGE_SIZE))); IplParameterBlock iplb __attribute__((aligned(PAGE_SIZE))); static char cfgbuf[2048]; static SubChannelId net_schid = { .one = 1 }; +static uint8_t mac[6]; static uint64_t dest_timer; static uint64_t get_timer_ms(void) @@ -159,7 +162,6 @@ static int tftp_load(filename_ip_t *fnip, void *buffer, int len) static int net_init(filename_ip_t *fn_ip) { - uint8_t mac[6]; int rc; memset(fn_ip, 0, sizeof(filename_ip_t)); @@ -234,6 +236,66 @@ static void net_release(filename_ip_t *fn_ip) } /** + * Load a kernel with initrd (i.e. with the information that we've got from + * a pxelinux.cfg config file) + */ +static int load_kernel_with_initrd(filename_ip_t *fn_ip, + struct pl_cfg_entry *entry) +{ + int rc; + + printf("Loading pxelinux.cfg entry '%s'\n", entry->label); + + if (!entry->kernel) { + printf("Kernel entry is missing!\n"); + return -1; + } + + strncpy(fn_ip->filename, entry->kernel, sizeof(fn_ip->filename)); + rc = tftp_load(fn_ip, KERNEL_ADDR, KERNEL_MAX_SIZE); + if (rc < 0) { + return rc; + } + + if (entry->initrd) { + uint64_t iaddr = (rc + 0xfff) & ~0xfffUL; + + strncpy(fn_ip->filename, entry->initrd, sizeof(fn_ip->filename)); + rc = tftp_load(fn_ip, (void *)iaddr, KERNEL_MAX_SIZE - iaddr); + if (rc < 0) { + return rc; + } + /* Patch location and size: */ + *(uint64_t *)0x10408 = iaddr; + *(uint64_t *)0x10410 = rc; + rc += iaddr; + } + + if (entry->append) { + strncpy((char *)0x10480, entry->append, ARCH_COMMAND_LINE_SIZE); + } + + return rc; +} + +#define MAX_PXELINUX_ENTRIES 16 + +static int net_try_pxelinux_cfg(filename_ip_t *fn_ip) +{ + struct pl_cfg_entry entries[MAX_PXELINUX_ENTRIES]; + int num_ent, def_ent = 0; + + num_ent = pxelinux_load_parse_cfg(fn_ip, mac, NULL, DEFAULT_TFTP_RETRIES, + cfgbuf, sizeof(cfgbuf), + entries, MAX_PXELINUX_ENTRIES, &def_ent); + if (num_ent > 0) { + return load_kernel_with_initrd(fn_ip, &entries[def_ent]); + } + + return -1; +} + +/** * Load via information from a .INS file (which can be found on CD-ROMs * for example) */ @@ -302,6 +364,25 @@ static int net_try_direct_tftp_load(filename_ip_t *fn_ip) if (!strncmp("* ", cfgbuf, 2)) { return handle_ins_cfg(fn_ip, cfgbuf, rc); } + /* + * pxelinux.cfg support via bootfile name is just here for developers' + * convenience (it eases testing with the built-in DHCP server of QEMU + * that does not support RFC 5071). The official way to configure a + * pxelinux.cfg file name is to use DHCP options 209 and 210 instead. + * So only use the pxelinux.cfg parser here for files that start with + * a magic comment string. + */ + if (!strncasecmp("# pxelinux", cfgbuf, 10)) { + struct pl_cfg_entry entries[MAX_PXELINUX_ENTRIES]; + int num_ent, def_ent = 0; + + num_ent = pxelinux_parse_cfg(cfgbuf, sizeof(cfgbuf), entries, + MAX_PXELINUX_ENTRIES, &def_ent); + if (num_ent <= 0) { + return -1; + } + return load_kernel_with_initrd(fn_ip, &entries[def_ent]); + } } /* Move kernel to right location */ @@ -407,6 +488,9 @@ void main(void) if (fnlen > 0 && fn_ip.filename[fnlen - 1] != '/') { rc = net_try_direct_tftp_load(&fn_ip); } + if (rc <= 0) { + rc = net_try_pxelinux_cfg(&fn_ip); + } net_release(&fn_ip);