From nobody Wed Nov 5 09:21:56 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1499423501623720.7074551650157; Fri, 7 Jul 2017 03:31:41 -0700 (PDT) Received: from localhost ([::1]:55489 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dTQXz-0006HP-7d for importer@patchew.org; Fri, 07 Jul 2017 06:31:39 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:35695) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dTQTw-0002nI-4T for qemu-devel@nongnu.org; Fri, 07 Jul 2017 06:27:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dTQTu-0001vy-91 for qemu-devel@nongnu.org; Fri, 07 Jul 2017 06:27:28 -0400 Received: from mx1.redhat.com ([209.132.183.28]:54098) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dTQTt-0001uv-SH for qemu-devel@nongnu.org; Fri, 07 Jul 2017 06:27:26 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B8961315D20; Fri, 7 Jul 2017 10:27:24 +0000 (UTC) Received: from thh440s.str.redhat.com (dhcp-200-180.str.redhat.com [10.33.200.180]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5F4B55F912; Fri, 7 Jul 2017 10:27:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com B8961315D20 Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com B8961315D20 From: Thomas Huth To: qemu-devel@nongnu.org, Christian Borntraeger Date: Fri, 7 Jul 2017 12:27:04 +0200 Message-Id: <1499423224-23060-9-git-send-email-thuth@redhat.com> In-Reply-To: <1499423224-23060-1-git-send-email-thuth@redhat.com> References: <1499423224-23060-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Fri, 07 Jul 2017 10:27:24 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [RFC PATCH v2 8/8] pc-bios/s390-ccw: Link libnet into the netboot image and do the TFTP load 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: Cornelia Huck , Viktor Mihajlovski , Farhan Ali , Alexander Graf , David Hildenbrand Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Most of the code has been taken from SLOF's netload.c file. Now we can finally load an image via TFTP and execute the downloaded kernel. Signed-off-by: Thomas Huth --- pc-bios/s390-ccw/netboot.mak | 12 ++- pc-bios/s390-ccw/netmain.c | 225 +++++++++++++++++++++++++++++++++++++++= ++++ 2 files changed, 236 insertions(+), 1 deletion(-) diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak index dd9119a..8c54b05 100644 --- a/pc-bios/s390-ccw/netboot.mak +++ b/pc-bios/s390-ccw/netboot.mak @@ -1,7 +1,7 @@ =20 SLOF_DIR :=3D $(SRC_PATH)/roms/SLOF =20 -NETOBJS :=3D start.o sclp.o virtio.o virtio-net.o netmain.o sbrk.o libc.a +NETOBJS :=3D start.o sclp.o virtio.o virtio-net.o netmain.o sbrk.o libnet.= a libc.a =20 LIBC_INC :=3D -I$(SLOF_DIR)/lib/libc/include LIBNET_INC :=3D -I$(SLOF_DIR)/lib/libnet @@ -39,3 +39,13 @@ libc.a: $(LIBCOBJS) =20 sbrk.o: $(SLOF_DIR)/slof/sbrk.c $(call quiet-command,$(CC) $(QEMU_CFLAGS) $(LIBC_INC) -c -o $@ $<,"CC","$= (TARGET_DIR)$@") + +LIBNETOBJS :=3D 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 +LIBNETCFLAGS :=3D $(QEMU_CFLAGS) $(LIBC_INC) $(LIBNET_INC) + +%.o : $(SLOF_DIR)/lib/libnet/%.c + $(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR= )$@") + +libnet.a: $(LIBNETOBJS) + $(call quiet-command,$(AR) -rc $@ $^,"AR","$(TARGET_DIR)$@") diff --git a/pc-bios/s390-ccw/netmain.c b/pc-bios/s390-ccw/netmain.c index fcdd7a1..ba0ccb3 100644 --- a/pc-bios/s390-ccw/netmain.c +++ b/pc-bios/s390-ccw/netmain.c @@ -6,6 +6,9 @@ * Based on the S390 virtio-ccw loading program (main.c) * Copyright (c) 2013 Alexander Graf * + * And based on the network loading code from SLOF (netload.c) + * Copyright (c) 2004, 2008 IBM Corporation + * * This code 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 @@ -18,17 +21,29 @@ #include #include #include + +#include +#include +#include +#include +#include +#include +#include #include =20 #include "s390-ccw.h" #include "virtio.h" =20 +#define DEFAULT_BOOT_RETRIES 10 +#define DEFAULT_TFTP_RETRIES 20 + extern char _start[]; =20 char stack[PAGE_SIZE * 8] __attribute__((aligned(PAGE_SIZE))); IplParameterBlock iplb __attribute__((aligned(PAGE_SIZE))); =20 static SubChannelId blk_schid =3D { .one =3D 1 }; +static int ip_version =3D 4; static uint64_t dest_timer; =20 static uint64_t get_timer_ms(void) @@ -56,6 +71,208 @@ int get_sec_ticks(void) return 1000; /* number of ticks in 1 second */ } =20 +/** + * Obtain IP and configuration info from DHCP server (either IPv4 or IPv6). + * @param fn_ip contains the following configuration information: + * client MAC, client IP, TFTP-server MAC, TFTP-server I= P, + * boot file name + * @param retries Number of DHCP attempts + * @return 0 : IP and configuration info obtained; + * non-0 : error condition occurred. + */ +static int dhcp(struct filename_ip *fn_ip, int retries) +{ + int i =3D retries + 1; + int rc =3D -1; + + printf(" Requesting information via DHCP: "); + + dhcpv4_generate_transaction_id(); + dhcpv6_generate_transaction_id(); + + do { + printf("\b\b\b%03d", i - 1); + if (!--i) { + printf("\nGiving up after %d DHCP requests\n", retries); + return -1; + } + ip_version =3D 4; + rc =3D dhcpv4(NULL, fn_ip); + if (rc =3D=3D -1) { + ip_version =3D 6; + set_ipv6_address(fn_ip->fd, 0); + rc =3D dhcpv6(NULL, fn_ip); + if (rc =3D=3D 0) { + memcpy(&fn_ip->own_ip6, get_ipv6_address(), 16); + break; + } + } + if (rc !=3D -1) { /* either success or non-dhcp failure */ + break; + } + } while (1); + printf("\b\b\b\bdone\n"); + + return rc; +} + +/** + * Seed the random number generator with our mac and current timestamp + */ +static void seed_rng(uint8_t mac[]) +{ + uint64_t seed; + + asm volatile(" stck %0 " : : "Q"(seed) : "memory"); + seed ^=3D (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5]; + srand(seed); +} + +static int tftp_load(filename_ip_t *fnip, void *buffer, int len, + unsigned int retries, int ip_vers) +{ + tftp_err_t tftp_err; + int rc; + + rc =3D tftp(fnip, buffer, len, retries, &tftp_err, 1, 1428, ip_vers); + + if (rc > 0) { + printf(" TFTP: Received %s (%d KBytes)\n", fnip->filename, + rc / 1024); + } else if (rc =3D=3D -1) { + puts("unknown TFTP error"); + } else if (rc =3D=3D -2) { + printf("TFTP buffer of %d bytes is too small for %s\n", + len, fnip->filename); + } else if (rc =3D=3D -3) { + printf("file not found: %s\n", fnip->filename); + } else if (rc =3D=3D -4) { + puts("TFTP access violation"); + } else if (rc =3D=3D -5) { + puts("illegal TFTP operation"); + } else if (rc =3D=3D -6) { + puts("unknown TFTP transfer ID"); + } else if (rc =3D=3D -7) { + puts("no such TFTP user"); + } else if (rc =3D=3D -8) { + puts("TFTP blocksize negotiation failed"); + } else if (rc =3D=3D -9) { + puts("file exceeds maximum TFTP transfer size"); + } else if (rc <=3D -10 && rc >=3D -15) { + const char *icmp_err_str; + switch (rc) { + case -ICMP_NET_UNREACHABLE - 10: + icmp_err_str =3D "net unreachable"; + break; + case -ICMP_HOST_UNREACHABLE - 10: + icmp_err_str =3D "host unreachable"; + break; + case -ICMP_PROTOCOL_UNREACHABLE - 10: + icmp_err_str =3D "protocol unreachable"; + break; + case -ICMP_PORT_UNREACHABLE - 10: + icmp_err_str =3D "port unreachable"; + break; + case -ICMP_FRAGMENTATION_NEEDED - 10: + icmp_err_str =3D "fragmentation needed and DF set"; + break; + case -ICMP_SOURCE_ROUTE_FAILED - 10: + icmp_err_str =3D "source route failed"; + break; + default: + icmp_err_str =3D " UNKNOWN"; + break; + } + printf("ICMP ERROR \"%s\"\n", icmp_err_str); + } else if (rc =3D=3D -40) { + printf("TFTP error occurred after %d bad packets received", + tftp_err.bad_tftp_packets); + } else if (rc =3D=3D -41) { + printf("TFTP error occurred after missing %d responses", + tftp_err.no_packets); + } else if (rc =3D=3D -42) { + printf("TFTP error missing block %d, expected block was %d", + tftp_err.blocks_missed, + tftp_err.blocks_received); + } + + return rc; +} + +static int net_load(char *buffer, int len) +{ + filename_ip_t fn_ip; + uint8_t mac[6]; + int rc; + + memset(&fn_ip, 0, sizeof(filename_ip_t)); + + rc =3D virtio_net_init(mac); + if (rc < 0) { + puts("Could not initialize network device"); + return -101; + } + fn_ip.fd =3D rc; + + printf(" Using MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + set_mac_address(mac); /* init ethernet layer */ + seed_rng(mac); + + rc =3D dhcp(&fn_ip, DEFAULT_BOOT_RETRIES); + if (rc >=3D 0) { + if (ip_version =3D=3D 4) { + set_ipv4_address(fn_ip.own_ip); + } + } else { + puts("Could not get IP address"); + return -101; + } + + if (ip_version =3D=3D 4) { + printf(" Using IPv4 address: %d.%d.%d.%d\n", + (fn_ip.own_ip >> 24) & 0xFF, (fn_ip.own_ip >> 16) & 0xFF, + (fn_ip.own_ip >> 8) & 0xFF, fn_ip.own_ip & 0xFF); + } else if (ip_version =3D=3D 6) { + char ip6_str[40]; + ipv6_to_str(fn_ip.own_ip6.addr, ip6_str); + printf(" Using IPv6 address: %s\n", ip6_str); + } + + if (rc =3D=3D -2) { + printf("ARP request to TFTP server (%d.%d.%d.%d) failed\n", + (fn_ip.server_ip >> 24) & 0xFF, (fn_ip.server_ip >> 16) & 0= xFF, + (fn_ip.server_ip >> 8) & 0xFF, fn_ip.server_ip & 0xFF); + return -102; + } + if (rc =3D=3D -4 || rc =3D=3D -3) { + puts("Can't obtain TFTP server IP address"); + return -107; + } + + if (ip_version =3D=3D 4) { + printf(" Requesting file \"%s\" via TFTP from %d.%d.%d.%d\n", + fn_ip.filename, + (fn_ip.server_ip >> 24) & 0xFF, (fn_ip.server_ip >> 16) & 0= xFF, + (fn_ip.server_ip >> 8) & 0xFF, fn_ip.server_ip & 0xFF); + } else if (ip_version =3D=3D 6) { + char ip6_str[40]; + printf(" Requesting file \"%s\" via TFTP from ", fn_ip.filename); + ipv6_to_str(fn_ip.server_ip6.addr, ip6_str); + printf("%s\n", ip6_str); + } + + /* Do the TFTP load and print error message if necessary */ + rc =3D tftp_load(&fn_ip, buffer, len, DEFAULT_TFTP_RETRIES, ip_version= ); + + if (ip_version =3D=3D 4) { + dhcp_send_release(fn_ip.fd); + } + + return rc; +} + void panic(const char *string) { sclp_print(string); @@ -131,10 +348,18 @@ static void virtio_setup(void) =20 void main(void) { + int rc; + sclp_setup(); sclp_print("Network boot starting...\n"); =20 virtio_setup(); =20 + rc =3D net_load(NULL, (long)_start); + if (rc > 0) { + sclp_print("Network loading done, starting kernel...\n"); + asm volatile (" lpsw 0(%0) " : : "r"(0) : "memory"); + } + panic("Failed to load OS from network\n"); } --=20 1.8.3.1