xref: /netbsd-src/sys/arch/i386/stand/pxeboot/pxe.c (revision 98d16a591800eb4524b2728b4717362aa4dbf6ba)
1*98d16a59Schristos /*	$NetBSD: pxe.c,v 1.18 2013/10/20 19:47:28 christos Exp $	*/
28bb2be29Sthorpej 
38bb2be29Sthorpej /*
48bb2be29Sthorpej  * Copyright 2001 Wasabi Systems, Inc.
58bb2be29Sthorpej  * All rights reserved.
68bb2be29Sthorpej  *
78bb2be29Sthorpej  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
88bb2be29Sthorpej  *
98bb2be29Sthorpej  * Redistribution and use in source and binary forms, with or without
108bb2be29Sthorpej  * modification, are permitted provided that the following conditions
118bb2be29Sthorpej  * are met:
128bb2be29Sthorpej  * 1. Redistributions of source code must retain the above copyright
138bb2be29Sthorpej  *    notice, this list of conditions and the following disclaimer.
148bb2be29Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
158bb2be29Sthorpej  *    notice, this list of conditions and the following disclaimer in the
168bb2be29Sthorpej  *    documentation and/or other materials provided with the distribution.
178bb2be29Sthorpej  * 3. All advertising materials mentioning features or use of this software
188bb2be29Sthorpej  *    must display the following acknowledgement:
198bb2be29Sthorpej  *	This product includes software developed for the NetBSD Project by
208bb2be29Sthorpej  *	Wasabi Systems, Inc.
218bb2be29Sthorpej  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
228bb2be29Sthorpej  *    or promote products derived from this software without specific prior
238bb2be29Sthorpej  *    written permission.
248bb2be29Sthorpej  *
258bb2be29Sthorpej  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
268bb2be29Sthorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
278bb2be29Sthorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
288bb2be29Sthorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
298bb2be29Sthorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
308bb2be29Sthorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
318bb2be29Sthorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
328bb2be29Sthorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
338bb2be29Sthorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
348bb2be29Sthorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
358bb2be29Sthorpej  * POSSIBILITY OF SUCH DAMAGE.
368bb2be29Sthorpej  */
378bb2be29Sthorpej 
388bb2be29Sthorpej /*
398bb2be29Sthorpej  * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
408bb2be29Sthorpej  * All rights reserved.
418bb2be29Sthorpej  * Copyright (c) 2000 Paul Saab <ps@freebsd.org>
428bb2be29Sthorpej  * All rights reserved.
438bb2be29Sthorpej  * Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
448bb2be29Sthorpej  * All rights reserved.
458bb2be29Sthorpej  *
468bb2be29Sthorpej  * Redistribution and use in source and binary forms, with or without
478bb2be29Sthorpej  * modification, are permitted provided that the following conditions
488bb2be29Sthorpej  * are met:
498bb2be29Sthorpej  * 1. Redistributions of source code must retain the above copyright
508bb2be29Sthorpej  *    notice, this list of conditions and the following disclaimer.
518bb2be29Sthorpej  * 2. Redistributions in binary form must reproduce the above copyright
528bb2be29Sthorpej  *    notice, this list of conditions and the following disclaimer in the
538bb2be29Sthorpej  *    documentation and/or other materials provided with the distribution.
548bb2be29Sthorpej  *
558bb2be29Sthorpej  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
568bb2be29Sthorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
578bb2be29Sthorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
588bb2be29Sthorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
598bb2be29Sthorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
608bb2be29Sthorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
618bb2be29Sthorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
628bb2be29Sthorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
638bb2be29Sthorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
648bb2be29Sthorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
658bb2be29Sthorpej  * SUCH DAMAGE.
668bb2be29Sthorpej  */
678bb2be29Sthorpej 
688bb2be29Sthorpej /*
698bb2be29Sthorpej  * Support for the Intel Preboot Execution Environment (PXE).
708bb2be29Sthorpej  *
718bb2be29Sthorpej  * PXE provides a UDP implementation as well as a UNDI network device
728bb2be29Sthorpej  * driver.  UNDI is much more complicated to use than PXE UDP, so we
738bb2be29Sthorpej  * use PXE UDP as a cheap and easy way to get PXE support.
748bb2be29Sthorpej  */
758bb2be29Sthorpej 
768bb2be29Sthorpej #include <sys/param.h>
778bb2be29Sthorpej #include <sys/socket.h>
788bb2be29Sthorpej 
798bb2be29Sthorpej #ifdef _STANDALONE
808bb2be29Sthorpej #include <lib/libkern/libkern.h>
818bb2be29Sthorpej #else
828bb2be29Sthorpej #include <string.h>
838bb2be29Sthorpej #endif
848bb2be29Sthorpej 
858bb2be29Sthorpej #include <netinet/in.h>
868bb2be29Sthorpej #include <netinet/in_systm.h>
878bb2be29Sthorpej #include <netinet/ip.h>
888bb2be29Sthorpej #include <netinet/ip_var.h>
898bb2be29Sthorpej #include <netinet/udp.h>
908bb2be29Sthorpej #include <netinet/udp_var.h>
918bb2be29Sthorpej 
928bb2be29Sthorpej #include <net/if_ether.h>
938bb2be29Sthorpej 
948bb2be29Sthorpej #include <lib/libsa/stand.h>
958bb2be29Sthorpej #include <lib/libsa/net.h>
968bb2be29Sthorpej #include <lib/libsa/bootp.h>
978bb2be29Sthorpej 
988bb2be29Sthorpej #include <libi386.h>
998bb2be29Sthorpej #include <bootinfo.h>
1008bb2be29Sthorpej 
1018bb2be29Sthorpej #include "pxeboot.h"
1028bb2be29Sthorpej #include "pxe.h"
103542ccfb0Sdrochner #include "pxe_netif.h"
1048bb2be29Sthorpej 
10568da4482Sperry void	(*pxe_call)(uint16_t);
1068bb2be29Sthorpej 
10768da4482Sperry void	pxecall_bangpxe(uint16_t);	/* pxe_call.S */
10868da4482Sperry void	pxecall_pxenv(uint16_t);	/* pxe_call.S */
1098bb2be29Sthorpej 
110*98d16a59Schristos extern char pxe_command_buf[256];
1118bb2be29Sthorpej 
1128bb2be29Sthorpej BOOTPLAYER bootplayer;
1138bb2be29Sthorpej 
114542ccfb0Sdrochner static struct btinfo_netif bi_netif;
115542ccfb0Sdrochner 
1168bb2be29Sthorpej /*****************************************************************************
1178bb2be29Sthorpej  * This section is a replacement for libsa/udp.c
1188bb2be29Sthorpej  *****************************************************************************/
1198bb2be29Sthorpej 
1208bb2be29Sthorpej /* Caller must leave room for ethernet, ip, and udp headers in front!! */
1218bb2be29Sthorpej ssize_t
sendudp(struct iodesc * d,void * pkt,size_t len)1228bb2be29Sthorpej sendudp(struct iodesc *d, void *pkt, size_t len)
1238bb2be29Sthorpej {
1248bb2be29Sthorpej 	t_PXENV_UDP_WRITE *uw = (void *) pxe_command_buf;
1258bb2be29Sthorpej 
1268bb2be29Sthorpej 	uw->status = 0;
1278bb2be29Sthorpej 
1288bb2be29Sthorpej 	uw->ip = d->destip.s_addr;
1298bb2be29Sthorpej 	uw->gw = gateip.s_addr;
1308bb2be29Sthorpej 	uw->src_port = d->myport;
1318bb2be29Sthorpej 	uw->dst_port = d->destport;
1328bb2be29Sthorpej 	uw->buffer_size = len;
1338bb2be29Sthorpej 	uw->buffer.segment = VTOPSEG(pkt);
1348bb2be29Sthorpej 	uw->buffer.offset = VTOPOFF(pkt);
1358bb2be29Sthorpej 
1368bb2be29Sthorpej 	pxe_call(PXENV_UDP_WRITE);
1378bb2be29Sthorpej 
1388bb2be29Sthorpej 	if (uw->status != PXENV_STATUS_SUCCESS) {
1398bb2be29Sthorpej 		/* XXX This happens a lot; it shouldn't. */
1408bb2be29Sthorpej 		if (uw->status != PXENV_STATUS_FAILURE)
1418bb2be29Sthorpej 			printf("sendudp: PXENV_UDP_WRITE failed: 0x%x\n",
1428bb2be29Sthorpej 			    uw->status);
1438bb2be29Sthorpej 		return (-1);
1448bb2be29Sthorpej 	}
1458bb2be29Sthorpej 
1468bb2be29Sthorpej 	return (len);
1478bb2be29Sthorpej }
1488bb2be29Sthorpej 
1498bb2be29Sthorpej /*
1508bb2be29Sthorpej  * Receive a UDP packet and validate it for us.
1518bb2be29Sthorpej  * Caller leaves room for the headers (Ether, IP, UDP).
1528bb2be29Sthorpej  */
1538bb2be29Sthorpej ssize_t
readudp(struct iodesc * d,void * pkt,size_t len,saseconds_t tleft)15469cf32a7Stsutsui readudp(struct iodesc *d, void *pkt, size_t len, saseconds_t tleft)
1558bb2be29Sthorpej {
1568bb2be29Sthorpej 	t_PXENV_UDP_READ *ur = (void *) pxe_command_buf;
1578bb2be29Sthorpej 	struct udphdr *uh;
1588bb2be29Sthorpej 	struct ip *ip;
1598bb2be29Sthorpej 
1608bb2be29Sthorpej 	uh = (struct udphdr *)pkt - 1;
1618bb2be29Sthorpej 	ip = (struct ip *)uh - 1;
1628bb2be29Sthorpej 
163461a86f9Schristos 	(void)memset(ur, 0, sizeof(*ur));
1648bb2be29Sthorpej 
1658bb2be29Sthorpej 	ur->dest_ip = d->myip.s_addr;
1668bb2be29Sthorpej 	ur->d_port = d->myport;
1678bb2be29Sthorpej 	ur->buffer_size = len;
1688bb2be29Sthorpej 	ur->buffer.segment = VTOPSEG(pkt);
1698bb2be29Sthorpej 	ur->buffer.offset = VTOPOFF(pkt);
1708bb2be29Sthorpej 
1718bb2be29Sthorpej 	/* XXX Timeout unused. */
1728bb2be29Sthorpej 
1738bb2be29Sthorpej 	pxe_call(PXENV_UDP_READ);
1748bb2be29Sthorpej 
1758bb2be29Sthorpej 	if (ur->status != PXENV_STATUS_SUCCESS) {
1768bb2be29Sthorpej 		/* XXX This happens a lot; it shouldn't. */
1778bb2be29Sthorpej 		if (ur->status != PXENV_STATUS_FAILURE)
1788bb2be29Sthorpej 			printf("readudp: PXENV_UDP_READ_failed: 0x%0x\n",
1798bb2be29Sthorpej 			    ur->status);
1808bb2be29Sthorpej 		return (-1);
1818bb2be29Sthorpej 	}
1828bb2be29Sthorpej 
1838bb2be29Sthorpej 	ip->ip_src.s_addr = ur->src_ip;
1848bb2be29Sthorpej 	uh->uh_sport = ur->s_port;
1858bb2be29Sthorpej 	uh->uh_dport = d->myport;
1868bb2be29Sthorpej 
187dd15fa81Sdrochner 	return (ur->buffer_size);
1888bb2be29Sthorpej }
1898bb2be29Sthorpej 
190542ccfb0Sdrochner /*
191542ccfb0Sdrochner  * netif layer:
192542ccfb0Sdrochner  *  open, close, shutdown: called from dev_net.c
193542ccfb0Sdrochner  *  socktodesc: called by network protocol modules
194542ccfb0Sdrochner  *
195542ccfb0Sdrochner  * We only allow one open socket.
196542ccfb0Sdrochner  */
1978bb2be29Sthorpej 
198542ccfb0Sdrochner static int pxe_inited;
199542ccfb0Sdrochner static struct iodesc desc;
2008bb2be29Sthorpej 
2018bb2be29Sthorpej int
pxe_netif_open(void)202df7f595eScegger pxe_netif_open(void)
2038bb2be29Sthorpej {
2048bb2be29Sthorpej 	t_PXENV_UDP_OPEN *uo = (void *) pxe_command_buf;
2058bb2be29Sthorpej 
206542ccfb0Sdrochner 	if (!pxe_inited) {
207542ccfb0Sdrochner 		if (pxe_init() != 0)
208542ccfb0Sdrochner 			return (-1);
209542ccfb0Sdrochner 		pxe_inited = 1;
210542ccfb0Sdrochner 	}
211542ccfb0Sdrochner 	BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
2128bb2be29Sthorpej 
213461a86f9Schristos 	(void)memset(uo, 0, sizeof(*uo));
2148bb2be29Sthorpej 
2158bb2be29Sthorpej 	uo->src_ip = bootplayer.yip;
2168bb2be29Sthorpej 
2178bb2be29Sthorpej 	pxe_call(PXENV_UDP_OPEN);
2188bb2be29Sthorpej 
2198bb2be29Sthorpej 	if (uo->status != PXENV_STATUS_SUCCESS) {
2208bb2be29Sthorpej 		printf("pxe_netif_probe: PXENV_UDP_OPEN failed: 0x%x\n",
2218bb2be29Sthorpej 		    uo->status);
222542ccfb0Sdrochner 		return (-1);
2238bb2be29Sthorpej 	}
2248bb2be29Sthorpej 
225e2cb8590Scegger 	memcpy(desc.myea, bootplayer.CAddr, ETHER_ADDR_LEN);
2268bb2be29Sthorpej 
2278bb2be29Sthorpej 	/*
2288bb2be29Sthorpej 	 * Since the PXE BIOS has already done DHCP, make sure we
2298bb2be29Sthorpej 	 * don't reuse any of its transaction IDs.
2308bb2be29Sthorpej 	 */
231542ccfb0Sdrochner 	desc.xid = bootplayer.ident;
2328bb2be29Sthorpej 
233542ccfb0Sdrochner 	return (0);
2348bb2be29Sthorpej }
2358bb2be29Sthorpej 
2368bb2be29Sthorpej void
pxe_netif_close(int sock)237454af1c0Sdsl pxe_netif_close(int sock)
2388bb2be29Sthorpej {
2398bb2be29Sthorpej 	t_PXENV_UDP_CLOSE *uc = (void *) pxe_command_buf;
2408bb2be29Sthorpej 
241542ccfb0Sdrochner #ifdef NETIF_DEBUG
242542ccfb0Sdrochner 	if (sock != 0)
243542ccfb0Sdrochner 		printf("pxe_netif_close: sock=%d\n", sock);
244542ccfb0Sdrochner #endif
245542ccfb0Sdrochner 
2468bb2be29Sthorpej 	uc->status = 0;
2478bb2be29Sthorpej 
2488bb2be29Sthorpej 	pxe_call(PXENV_UDP_CLOSE);
2498bb2be29Sthorpej 
2508bb2be29Sthorpej 	if (uc->status != PXENV_STATUS_SUCCESS)
2518bb2be29Sthorpej 		printf("pxe_netif_end: PXENV_UDP_CLOSE failed: 0x%x\n",
2528bb2be29Sthorpej 		    uc->status);
253542ccfb0Sdrochner }
254542ccfb0Sdrochner 
255542ccfb0Sdrochner struct iodesc *
socktodesc(int sock)256454af1c0Sdsl socktodesc(int sock)
257542ccfb0Sdrochner {
258542ccfb0Sdrochner 
259542ccfb0Sdrochner #ifdef NETIF_DEBUG
260542ccfb0Sdrochner 	if (sock != 0)
261542ccfb0Sdrochner 		return (0);
262542ccfb0Sdrochner 	else
263542ccfb0Sdrochner #endif
264542ccfb0Sdrochner 		return (&desc);
265542ccfb0Sdrochner }
266542ccfb0Sdrochner 
2678bb2be29Sthorpej /*****************************************************************************
2688bb2be29Sthorpej  * PXE initialization and support routines
2698bb2be29Sthorpej  *****************************************************************************/
2708bb2be29Sthorpej 
27168da4482Sperry uint16_t pxe_command_buf_seg;
27268da4482Sperry uint16_t pxe_command_buf_off;
2738bb2be29Sthorpej 
27468da4482Sperry extern uint16_t bangpxe_off, bangpxe_seg;
27568da4482Sperry extern uint16_t pxenv_off, pxenv_seg;
2768bb2be29Sthorpej 
2778bb2be29Sthorpej static struct btinfo_netif bi_netif;
2788bb2be29Sthorpej 
2798bb2be29Sthorpej int
pxe_init(void)2808bb2be29Sthorpej pxe_init(void)
2818bb2be29Sthorpej {
2828bb2be29Sthorpej 	t_PXENV_GET_CACHED_INFO *gci = (void *) pxe_command_buf;
2838bb2be29Sthorpej 	t_PXENV_UNDI_GET_NIC_TYPE *gnt = (void *) pxe_command_buf;
2848bb2be29Sthorpej 	pxenv_t *pxenv;
2858bb2be29Sthorpej 	pxe_t *pxe;
2868bb2be29Sthorpej 	char *cp;
2878bb2be29Sthorpej 	int i;
28868da4482Sperry 	uint8_t cksum, *ucp;
2898bb2be29Sthorpej 
2908bb2be29Sthorpej 	/*
2918bb2be29Sthorpej 	 * Checking for the presence of PXE is a machine-dependent
2928bb2be29Sthorpej 	 * operation.  On the IA-32, this can be done two ways:
2938bb2be29Sthorpej 	 *
2948bb2be29Sthorpej 	 *	Int 0x1a function 0x5650
2958bb2be29Sthorpej 	 *
2968bb2be29Sthorpej 	 *	Scan memory for the !PXE or PXENV+ signatures
2978bb2be29Sthorpej 	 *
2988bb2be29Sthorpej 	 * We do the latter, since the Int method returns a pointer
2998bb2be29Sthorpej 	 * to a deprecated structure (PXENV+).
3008bb2be29Sthorpej 	 */
3018bb2be29Sthorpej 
3028bb2be29Sthorpej 	pxenv = NULL;
3038bb2be29Sthorpej 	pxe = NULL;
3048bb2be29Sthorpej 
305e42f3e30Skanaoka 	for (cp = (char *)0xa0000; cp > (char *)0x10000; cp -= 2) {
3068bb2be29Sthorpej 		if (pxenv == NULL) {
3078bb2be29Sthorpej 			pxenv = (pxenv_t *)cp;
3088ff1e4e4Stron 			if (MEMSTRCMP(pxenv->Signature, "PXENV+"))
3098bb2be29Sthorpej 				pxenv = NULL;
3108bb2be29Sthorpej 			else {
31168da4482Sperry 				for (i = 0, ucp = (uint8_t *)cp, cksum = 0;
3128bb2be29Sthorpej 				     i < pxenv->Length; i++)
3138bb2be29Sthorpej 					cksum += ucp[i];
3148bb2be29Sthorpej 				if (cksum != 0) {
3158bb2be29Sthorpej 					printf("pxe_init: bad cksum (0x%x) "
3168bb2be29Sthorpej 					    "for PXENV+ at 0x%lx\n", cksum,
3178bb2be29Sthorpej 					    (u_long) cp);
3188bb2be29Sthorpej 					pxenv = NULL;
3198bb2be29Sthorpej 				}
3208bb2be29Sthorpej 			}
3218bb2be29Sthorpej 		}
3228bb2be29Sthorpej 
3238bb2be29Sthorpej 		if (pxe == NULL) {
3248bb2be29Sthorpej 			pxe = (pxe_t *)cp;
3258ff1e4e4Stron 			if (MEMSTRCMP(pxe->Signature, "!PXE"))
3268bb2be29Sthorpej 				pxe = NULL;
3278bb2be29Sthorpej 			else {
32868da4482Sperry 				for (i = 0, ucp = (uint8_t *)cp, cksum = 0;
3298bb2be29Sthorpej 				     i < pxe->StructLength; i++)
3308bb2be29Sthorpej 					cksum += ucp[i];
3318bb2be29Sthorpej 				if (cksum != 0) {
3328bb2be29Sthorpej 					printf("pxe_init: bad cksum (0x%x) "
3338bb2be29Sthorpej 					    "for !PXE at 0x%lx\n", cksum,
3348bb2be29Sthorpej 					    (u_long) cp);
3358bb2be29Sthorpej 					pxe = NULL;
3368bb2be29Sthorpej 				}
3378bb2be29Sthorpej 			}
3388bb2be29Sthorpej 		}
3398bb2be29Sthorpej 
3408bb2be29Sthorpej 		if (pxe != NULL && pxenv != NULL)
3418bb2be29Sthorpej 			break;
3428bb2be29Sthorpej 	}
3438bb2be29Sthorpej 
3448bb2be29Sthorpej 	if (pxe == NULL && pxenv == NULL) {
3458bb2be29Sthorpej 		printf("pxe_init: No PXE BIOS found.\n");
3468bb2be29Sthorpej 		return (1);
3478bb2be29Sthorpej 	}
3488bb2be29Sthorpej 
3498bb2be29Sthorpej 	if (pxenv != NULL) {
3508bb2be29Sthorpej 		printf("PXE BIOS Version %d.%d\n",
3518bb2be29Sthorpej 		    (pxenv->Version >> 8) & 0xff, pxenv->Version & 0xff);
3528bb2be29Sthorpej 		if (pxenv->Version >= 0x0201 && pxe != NULL) {
3538bb2be29Sthorpej 			/* 2.1 or greater -- don't use PXENV+ */
3548bb2be29Sthorpej 			pxenv = NULL;
3558bb2be29Sthorpej 		}
3568bb2be29Sthorpej 	}
3578bb2be29Sthorpej 
3588bb2be29Sthorpej 	if (pxe != NULL) {
3598bb2be29Sthorpej 		pxe_call = pxecall_bangpxe;
3608bb2be29Sthorpej 		bangpxe_off = pxe->EntryPointSP.offset;
3618bb2be29Sthorpej 		bangpxe_seg = pxe->EntryPointSP.segment;
3628bb2be29Sthorpej 	} else {
3638bb2be29Sthorpej 		pxe_call = pxecall_pxenv;
3648bb2be29Sthorpej 		pxenv_off = pxenv->RMEntry.offset;
3658bb2be29Sthorpej 		pxenv_seg = pxenv->RMEntry.segment;
3668bb2be29Sthorpej 	}
3678bb2be29Sthorpej 
3688bb2be29Sthorpej 	/*
3698bb2be29Sthorpej 	 * Pre-compute the segment/offset of the pxe_command_buf
3708bb2be29Sthorpej 	 * to make things nicer in the low-level calling glue.
3718bb2be29Sthorpej 	 */
3728bb2be29Sthorpej 	pxe_command_buf_seg = VTOPSEG(pxe_command_buf);
3738bb2be29Sthorpej 	pxe_command_buf_off = VTOPOFF(pxe_command_buf);
3748bb2be29Sthorpej 
3758bb2be29Sthorpej 	/*
3768bb2be29Sthorpej 	 * Get the cached info from the server's Discovery reply packet.
3778bb2be29Sthorpej 	 */
378461a86f9Schristos 	(void)memset(gci, 0, sizeof(*gci));
3798bb2be29Sthorpej 	gci->PacketType = PXENV_PACKET_TYPE_BINL_REPLY;
3808bb2be29Sthorpej 	pxe_call(PXENV_GET_CACHED_INFO);
3818bb2be29Sthorpej 	if (gci->Status != PXENV_STATUS_SUCCESS) {
3828bb2be29Sthorpej 		printf("pxe_init: PXENV_GET_CACHED_INFO failed: 0x%x\n",
3838bb2be29Sthorpej 		    gci->Status);
3848bb2be29Sthorpej 		return (1);
3858bb2be29Sthorpej 	}
3868bb2be29Sthorpej 	pvbcopy((void *)((gci->Buffer.segment << 4) + gci->Buffer.offset),
3878bb2be29Sthorpej 	    &bootplayer, gci->BufferSize);
3888bb2be29Sthorpej 
3898bb2be29Sthorpej 	/*
3908bb2be29Sthorpej 	 * Get network interface information.
3918bb2be29Sthorpej 	 */
392461a86f9Schristos 	(void)memset(gnt, 0, sizeof(*gnt));
3938bb2be29Sthorpej 	pxe_call(PXENV_UNDI_GET_NIC_TYPE);
3948bb2be29Sthorpej 
3958bb2be29Sthorpej 	if (gnt->Status != PXENV_STATUS_SUCCESS) {
3968bb2be29Sthorpej 		printf("pxe_init: PXENV_UNDI_GET_NIC_TYPE failed: 0x%x\n",
3978bb2be29Sthorpej 		    gnt->Status);
3988bb2be29Sthorpej 		return (0);
3998bb2be29Sthorpej 	}
4008bb2be29Sthorpej 
4018bb2be29Sthorpej 	switch (gnt->NicType) {
4028bb2be29Sthorpej 	case PCI_NIC:
4038bb2be29Sthorpej 	case CardBus_NIC:
4048bb2be29Sthorpej 		strncpy(bi_netif.ifname, "pxe", sizeof(bi_netif.ifname));
4058bb2be29Sthorpej 		bi_netif.bus = BI_BUS_PCI;
4068bb2be29Sthorpej 		bi_netif.addr.tag = gnt->info.pci.BusDevFunc;
4078bb2be29Sthorpej 
4088bb2be29Sthorpej 		printf("Using %s device at bus %d device %d function %d\n",
4098bb2be29Sthorpej 		    gnt->NicType == PCI_NIC ? "PCI" : "CardBus",
4108bb2be29Sthorpej 		    (gnt->info.pci.BusDevFunc >> 8) & 0xff,
4118bb2be29Sthorpej 		    (gnt->info.pci.BusDevFunc >> 3) & 0x1f,
4128bb2be29Sthorpej 		    gnt->info.pci.BusDevFunc & 0x7);
4138bb2be29Sthorpej 		break;
4148bb2be29Sthorpej 
4158bb2be29Sthorpej 	case PnP_NIC:
4168bb2be29Sthorpej 		/* XXX Make bootinfo work with this. */
4178bb2be29Sthorpej 		printf("Using PnP device at 0x%x\n", gnt->info.pnp.CardSelNum);
4188bb2be29Sthorpej 	}
4198bb2be29Sthorpej 
420542ccfb0Sdrochner 	printf("Ethernet address %s\n", ether_sprintf(bootplayer.CAddr));
421542ccfb0Sdrochner 
4228bb2be29Sthorpej 	return (0);
4238bb2be29Sthorpej }
4248bb2be29Sthorpej 
4258bb2be29Sthorpej void
pxe_fini(void)4268bb2be29Sthorpej pxe_fini(void)
4278bb2be29Sthorpej {
4288bb2be29Sthorpej 	t_PXENV_UNDI_SHUTDOWN *shutdown = (void *) pxe_command_buf;
4298bb2be29Sthorpej 
4308bb2be29Sthorpej 	if (pxe_call == NULL)
4318bb2be29Sthorpej 		return;
4328bb2be29Sthorpej 
4338bb2be29Sthorpej 	pxe_call(PXENV_UNDI_SHUTDOWN);
4348bb2be29Sthorpej 
4358bb2be29Sthorpej 	if (shutdown->Status != PXENV_STATUS_SUCCESS)
4368bb2be29Sthorpej 		printf("pxe_fini: PXENV_UNDI_SHUTDOWN failed: 0x%x\n",
4378bb2be29Sthorpej 		    shutdown->Status);
4388bb2be29Sthorpej }
439