Merge from Etherboot 5.4
authorMichael Brown <mcb30@etherboot.org>
Thu, 16 Mar 2006 17:40:55 +0000 (17:40 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 16 Mar 2006 17:40:55 +0000 (17:40 +0000)
1  2 
src/core/main.c
src/core/nic.c
src/core/vsprintf.c
src/include/vsprintf.h
src/interface/pxe/pxe_preboot.c

diff --cc src/core/main.c
@@@ -39,11 -36,11 +39,6 @@@ int url_port
  
  char as_main_program = 1;
  
--#ifdef        IMAGE_FREEBSD
--int freebsd_howto = 0;
--char freebsd_kernel_env[FREEBSD_KERNEL_ENV_SIZE];
--#endif
--
  #if 0
  
  static inline unsigned long ask_boot(unsigned *index)
@@@ -282,6 -279,6 +277,16 @@@ static int main_loop(int state
                        if (dev->how_probe == PROBE_FAILED) {
                                state = -1;
                        }
++                      if (state == 1) {
++                              /* The bootp reply might have been changed, re-parse.  */
++                              decode_rfc1533(bootp_data.bootp_reply.bp_vend, 0,
++#ifdef        NO_DHCP_SUPPORT
++                                             BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 
++#else
++                                             DHCP_OPT_LEN + MAX_BOOTP_EXTLEN, 
++#endif        /* NO_DHCP_SUPPORT */
++                                             1);
++                      }
                }
        }
        switch(state) {
diff --cc src/core/nic.c
@@@ -33,6 -36,6 +33,14 @@@ char *hostname = ""
  int hostnamelen = 0;
  static uint32_t xid;
  unsigned char *end_of_rfc1533 = NULL;
++unsigned char *addparam;
++int addparamlen;
++
++#ifdef IMAGE_FREEBSD
++int freebsd_howto = 0;
++char freebsd_kernel_env[FREEBSD_KERNEL_ENV_SIZE];
++#endif /* IMAGE_FREEBSD */
++
  static int vendorext_isvalid;
  static const unsigned char vendorext_magic[] = {0xE4,0x45,0x74,0x68}; /* √§Eth */
  static const unsigned char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
@@@ -261,9 -264,9 +269,8 @@@ static int nic_configure ( struct type_
  #endif /* PXE_EXPORT */
  #endif /* ! NO_DHCP_SUPPORT */
        printf(", TFTP: %@", arptable[ARP_SERVER].ipaddr.s_addr);
--      if (BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr)
--              printf(", Relay: %@",
--                      BOOTP_DATA_ADDR->bootp_reply.bp_giaddr.s_addr);
++      if (bootp_data.bootp_reply.bp_giaddr.s_addr)
++              printf(", Relay: %@", bootp_data.bootp_reply.bp_giaddr.s_addr);
        if (arptable[ARP_GATEWAY].ipaddr.s_addr)
                printf(", Gateway %@", arptable[ARP_GATEWAY].ipaddr.s_addr);
        if (arptable[ARP_NAMESERVER].ipaddr.s_addr)
@@@ -316,6 -319,6 +323,22 @@@ static int nic_load ( struct type_dev *
                NULL
  #endif
                : KERNEL_BUF;
++#ifdef  ZPXE_SUFFIX_STRIP
++        {
++          int i = 0;
++          while (kernel[i++]);
++          if(i > 5) {
++            if(kernel[i - 6] == '.' &&
++               kernel[i - 5] == 'z' &&
++               kernel[i - 4] == 'p' &&
++               kernel[i - 3] == 'x' &&
++               kernel[i - 2] == 'e') {
++              printf("Trimming .zpxe extension\n");
++              kernel[i - 6] = 0;
++            }
++          }
++        }
++#endif
        if ( kernel ) {
                return download_url ( kernel, buffer );
        } else {        
@@@ -659,8 -664,8 +682,8 @@@ static int await_bootp(int ival __unuse
  #endif        /* NO_DHCP_SUPPORT */
                netmask = default_netmask();
                /* bootpreply->bp_file will be copied to KERNEL_BUF in the memcpy */
--              memcpy((char *)BOOTP_DATA_ADDR, (char *)bootpreply, sizeof(struct bootpd_t));
--              decode_rfc1533(BOOTP_DATA_ADDR->bootp_reply.bp_vend, 0,
++              memcpy((char *)&bootp_data, (char *)bootpreply, sizeof(struct bootpd_t));
++              decode_rfc1533(bootp_data.bootp_reply.bp_vend, 0,
  #ifdef        NO_DHCP_SUPPORT
                               BOOTP_VENDOR_LEN + MAX_BOOTP_EXTLEN, 
  #else
@@@ -740,6 -745,6 +763,8 @@@ static int bootp(void
  #else
                while ( remaining_time > 0 ) {
                        if (await_reply(await_bootp, 0, NULL, remaining_time)){
++                              if (arptable[ARP_CLIENT].ipaddr.s_addr)
++                                      break;
                        }
                        remaining_time = stop_time - currticks();
                }
@@@ -1029,6 -1168,6 +1054,8 @@@ int decode_rfc1533(unsigned char *p, un
  #else
                vendorext_isvalid = 0;
  #endif
++              addparam = NULL;
++              addparamlen = 0;
                if (memcmp(p, rfc1533_cookie, 4))
                        return(0); /* no RFC 1533 header found */
                p += 4;
                                return(0); /* no RFC 1533 header found */
                        p += 4;
                        len -= 4; }
--              if (extend + len <= (unsigned char *)&(BOOTP_DATA_ADDR->bootp_extension[MAX_BOOTP_EXTLEN])) {
++              if (extend + len <= (unsigned char *)&(bootp_data.bootp_extension[MAX_BOOTP_EXTLEN])) {
                        memcpy(extend, p, len);
                        extend += len;
                } else {
                          p[6] == RFC1533_VENDOR_MAJOR
                        )
                        vendorext_isvalid++;
++              else if (c == RFC1533_VENDOR_ADDPARM) {
++                      /* This tag intentionally works for BOTH the encapsulated and
++                       * non-encapsulated case, since the current menu code (in mknbi)
++                       * creates this tag without encapsulation.  In the future both the
++                       * menu from mknbi and this code should learn about the proper
++                       * encapsulation (which will require substantial changes to various
++                       * stuff from mknbi, which will break compatibility with older
++                       * versions of Etherboot).  */
++                      addparam = p + 2;
++                      addparamlen = *(p + 1);
++              }
                else if (NON_ENCAP_OPT c == RFC1533_VENDOR_ETHERBOOT_ENCAP) {
                        in_encapsulated_options = 1;
                        decode_rfc1533(p+2, 0, TAG_LEN(p), -1);
@@@ -45,12 -47,10 +45,12 @@@ static int vsprintf(char *buf, const ch
                while (*fmt >= '0' && *fmt <= '9')
                        fmt++;
                if (*fmt == 's') {
--                      for(p = va_arg(args, char *); *p != '\0'; p++) 
++                      for(p = va_arg(args, char *); *p != '\0'; p++)
                                buf ? *s++ = *p : putchar(*p);
 -              }
 -              else {  /* Length of item is bounded */
 +              } else if (*fmt == 'm') {
 +                      for(p = strerror(errno); *p != '\0'; p++)
 +                              buf ? *s++ = *p : putchar(*p);
 +              } else {        /* Length of item is bounded */
                        char tmp[40], *q = tmp;
                        int alt = 0;
                        int shift = INT_SHIFT;
@@@ -70,7 -70,7 +70,7 @@@
                                        fmt++;
                                }
                        }
--                      
++
                        /*
                         * Before each format q points to tmp buffer
                         * After each format q points past end of item
@@@ -173,20 -159,11 +173,21 @@@ int sprintf(char *buf, const char *fmt
        return i;
  }
  
 -void printf(const char *fmt, ...)
 +/**
 + * Write a formatted string to the console.
 + *
 + * @v fmt             Format string
 + * @v ...             Arguments corresponding to the format string
 + * @ret       None            -
 + * @err None          -
 + *
 + */
- void printf(const char *fmt, ...)
++int printf(const char *fmt, ...)
  {
        va_list args;
        int i;
        va_start(args, fmt);
        i=vsprintf(0, fmt, args);
        va_end(args);
++      return i;
  }
@@@ -45,6 -9,6 +45,6 @@@
   */
  
  extern int sprintf ( char *buf, const char *fmt, ... );
--extern void printf ( const char *fmt, ... );
++extern int printf ( const char *fmt, ... );
  
  #endif /* VSPRINTF_H */
index bed3204,0000000..f0e12bb
mode 100644,000000..100644
--- /dev/null
@@@ -1,249 -1,0 +1,249 @@@
-       memcpy ( &cached_info->vendor.d, BOOTP_DATA_ADDR->bootp_reply.bp_vend,
 +/** @file
 + *
 + * PXE Preboot API
 + *
 + */
 +
 +/* PXE API interface for Etherboot.
 + *
 + * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
 + *
 + * 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 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, write to the Free Software
 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 + */
 +
 +#include "pxe.h"
 +#include "pxe_callbacks.h"
 +
 +/**
 + * UNLOAD BASE CODE STACK
 + *
 + * @v None                            -
 + * @ret ...
 + *
 + */
 +PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
 +      int success;
 +
 +      DBG ( "PXENV_UNLOAD_STACK" );
 +      success = ensure_pxe_state ( CAN_UNLOAD );
 +
 +      /* We need to call cleanup() at some point.  The network card
 +       * has already been disabled by ENSURE_CAN_UNLOAD(), but for
 +       * the sake of completeness we should call the console_fini()
 +       * etc. that are part of cleanup().
 +       *
 +       * There seems to be a lack of consensus on which is the final
 +       * PXE API call to make, but it's a fairly safe bet that all
 +       * the potential shutdown sequences will include a call to
 +       * PXENV_UNLOAD_STACK at some point, so we may as well do it
 +       * here.
 +       */
 +      cleanup();
 +
 +      if ( ! success ) {
 +              unload_stack->Status = PXENV_STATUS_KEEP_ALL;
 +              return PXENV_EXIT_FAILURE;
 +      }
 +
 +      unload_stack->Status = PXENV_STATUS_SUCCESS;
 +      return PXENV_EXIT_SUCCESS;
 +}
 +
 +/* PXENV_GET_CACHED_INFO
 + *
 + * Status: working
 + */
 +PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
 +                                   *get_cached_info ) {
 +      BOOTPLAYER_t *cached_info = &pxe_stack->cached_info;
 +      DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
 +      ENSURE_READY ( get_cached_info );
 +
 +      /* Fill in cached_info structure in our pxe_stack */
 +
 +      /* I don't think there's actually any way we can be called in
 +       * the middle of a DHCP request... 
 +       */
 +      cached_info->opcode = BOOTP_REP;
 +      /* We only have Ethernet drivers */
 +      cached_info->Hardware = ETHER_TYPE;
 +      cached_info->Hardlen = ETH_ALEN;
 +      /* PXESPEC: "Client sets" says the spec, but who's filling in
 +       * this structure?  It ain't the client.
 +       */
 +      cached_info->Gatehops = 0;
 +      cached_info->ident = 0;
 +      cached_info->seconds = 0;
 +      cached_info->Flags = BOOTP_BCAST;
 +      /* PXESPEC: What do 'Client' and 'Your' IP address refer to? */
 +      cached_info->cip = arptable[ARP_CLIENT].ipaddr.s_addr;
 +      cached_info->yip = arptable[ARP_CLIENT].ipaddr.s_addr;
 +      cached_info->sip = arptable[ARP_SERVER].ipaddr.s_addr;
 +      /* PXESPEC: Does "GIP" mean "Gateway" or "Relay agent"? */
 +      cached_info->gip = arptable[ARP_GATEWAY].ipaddr.s_addr;
 +      memcpy ( cached_info->CAddr, arptable[ARP_CLIENT].node, ETH_ALEN );
 +      /* Nullify server name */
 +      cached_info->Sname[0] = '\0';
 +      memcpy ( cached_info->bootfile, KERNEL_BUF,
 +               sizeof(cached_info->bootfile) );
 +      /* Copy DHCP vendor options */
++      memcpy ( &cached_info->vendor.d, bootp_data.bootp_reply.bp_vend,
 +               sizeof(cached_info->vendor.d) );
 +      
 +      /* Copy to user-specified buffer, or set pointer to our buffer */
 +      get_cached_info->BufferLimit = sizeof(*cached_info);
 +      /* PXESPEC: says to test for Buffer == NULL *and* BufferSize =
 +       * 0, but what are we supposed to do with a null buffer of
 +       * non-zero size?!
 +       */
 +      if ( IS_NULL_SEGOFF16 ( get_cached_info->Buffer ) ) {
 +              /* Point back to our buffer */
 +              PTR_TO_SEGOFF16 ( cached_info, get_cached_info->Buffer );
 +              get_cached_info->BufferSize = sizeof(*cached_info);
 +      } else {
 +              /* Copy to user buffer */
 +              size_t size = sizeof(*cached_info);
 +              void *buffer = SEGOFF16_TO_PTR ( get_cached_info->Buffer );
 +              if ( get_cached_info->BufferSize < size )
 +                      size = get_cached_info->BufferSize;
 +              DBG ( " to %x", virt_to_phys ( buffer ) );
 +              memcpy ( buffer, cached_info, size );
 +              /* PXESPEC: Should we return an error if the user
 +               * buffer is too small?  We do return the actual size
 +               * of the buffer via BufferLimit, so the user does
 +               * have a way to detect this already.
 +               */
 +      }
 +
 +      get_cached_info->Status = PXENV_STATUS_SUCCESS;
 +      return PXENV_EXIT_SUCCESS;
 +}
 +
 +/* PXENV_RESTART_TFTP
 + *
 + * Status: working
 + */
 +PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
 +                                *restart_tftp ) {
 +      PXENV_EXIT_t tftp_exit;
 +
 +      DBG ( "PXENV_RESTART_TFTP" );
 +      ENSURE_READY ( restart_tftp );
 +
 +      /* Words cannot describe the complete mismatch between the PXE
 +       * specification and any possible version of reality...
 +       */
 +      restart_tftp->Buffer = PXE_LOAD_ADDRESS; /* Fixed by spec, apparently */
 +      restart_tftp->BufferSize = get_free_base_memory() - PXE_LOAD_ADDRESS; /* Near enough */
 +      DBG ( "(" );
 +      tftp_exit = pxe_api_call ( PXENV_TFTP_READ_FILE, (union u_PXENV_ANY*)restart_tftp );
 +      DBG ( ")" );
 +      if ( tftp_exit != PXENV_EXIT_SUCCESS ) return tftp_exit;
 +
 +      /* Fire up the new NBP */
 +      restart_tftp->Status = xstartpxe();
 +
 +      /* Not sure what "SUCCESS" actually means, since we can only
 +       * return if the new NBP failed to boot...
 +       */
 +      return PXENV_EXIT_SUCCESS;
 +}
 +
 +/* PXENV_START_UNDI
 + *
 + * Status: working
 + */
 +PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
 +      unsigned char bus, devfn;
 +
 +      DBG ( "PXENV_START_UNDI" );
 +      ENSURE_MIDWAY(start_undi);
 +
 +      /* Record PCI bus & devfn passed by caller, so we know which
 +       * NIC they want to use.
 +       *
 +       * If they don't match our already-existing NIC structure, set
 +       * values to ensure that the specified NIC is used at the next
 +       * call to pxe_intialise_nic().
 +       */
 +      bus = ( start_undi->AX >> 8 ) & 0xff;
 +      devfn = start_undi->AX & 0xff;
 +
 +#warning "device probing mechanism has completely changed"
 +#if 0
 +      if ( ( pci->dev.driver == NULL ) ||
 +           ( pci->dev.bus != bus ) || ( pci->dev.devfn != devfn ) ) {
 +              /* This is quite a bit of a hack and relies on
 +               * knowledge of the internal operation of Etherboot's
 +               * probe mechanism.
 +               */
 +              DBG ( " set PCI %hhx:%hhx.%hhx",
 +                    bus, PCI_SLOT(devfn), PCI_FUNC(devfn) );
 +              dev->type = BOOT_NIC;
 +              dev->to_probe = PROBE_PCI;
 +              memset ( &dev->state, 0, sizeof(dev->state) );
 +              pci->advance = 1;
 +              pci->dev.use_specified = 1;
 +              pci->dev.bus = bus;
 +              pci->dev.devfn = devfn;
 +      }
 +#endif
 +
 +      start_undi->Status = PXENV_STATUS_SUCCESS;
 +      return PXENV_EXIT_SUCCESS;
 +}
 +
 +/* PXENV_STOP_UNDI
 + *
 + * Status: working
 + */
 +PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
 +      DBG ( "PXENV_STOP_UNDI" );
 +
 +      if ( ! ensure_pxe_state(CAN_UNLOAD) ) {
 +              stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
 +              return PXENV_EXIT_FAILURE;
 +      }
 +
 +      stop_undi->Status = PXENV_STATUS_SUCCESS;
 +      return PXENV_EXIT_SUCCESS;
 +}
 +
 +/* PXENV_START_BASE
 + *
 + * Status: won't implement (requires major structural changes)
 + */
 +PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) {
 +      DBG ( "PXENV_START_BASE" );
 +      /* ENSURE_READY ( start_base ); */
 +      start_base->Status = PXENV_STATUS_UNSUPPORTED;
 +      return PXENV_EXIT_FAILURE;
 +}
 +
 +/* PXENV_STOP_BASE
 + *
 + * Status: working
 + */
 +PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
 +      DBG ( "PXENV_STOP_BASE" );
 +
 +      /* The only time we will be called is when the NBP is trying
 +       * to shut down the PXE stack.  There's nothing we need to do
 +       * in this call.
 +       */
 +
 +      stop_base->Status = PXENV_STATUS_SUCCESS;
 +      return PXENV_EXIT_SUCCESS;
 +}