grub-0.95-diskless-patch-2-undi.patch revision 7c478bd95313f5f23a4c958a745db2134aa03244
diff -urN release_2/configure release_2_undi/configure
--- release_2/configure 2004-06-18 16:20:47.000000000 +0800
+++ release_2_undi/configure 2004-07-03 14:27:01.000000000 +0800
@@ -882,17 +882,18 @@
--enable-natsemi enable NatSemi DP8381x driver
--enable-ns83820 enable NS83820 driver
--enable-ns8390 enable NE2000 PCI driver
- --enable-pcnet32 enable AMD Lance/PCI PCNet/32 driver
- --enable-pnic enable Bochs Pseudo Nic driver
+ --enable-pcnet32 enable AMD Lance/PCI PCNet/32 driver
+ --enable-pnic enable Bochs Pseudo Nic driver
--enable-rtl8139 enable Realtek 8139 driver
- --enable-r8169 enable Realtek 8169 driver
+ --enable-r8169 enable Realtek 8169 driver
--enable-sis900 enable SIS 900 and SIS 7016 driver
- --enable-tg3 enable Broadcom Tigon3 driver
+ --enable-sundance enable Sundance ST201 driver
+ --enable-tg3 enable Broadcom Tigon3 driver
--enable-tulip enable Tulip driver
- --enable-tlan enable TI ThunderLAN driver
- --enable-sundance enable Sundance ST201 driver
+ --enable-tlan enable TI ThunderLAN driver
+ --enable-undi enable PXE UNDI driver
--enable-via-rhine enable Rhine-I/II driver
- --enable-w89c840 enable Winbond W89c840, Compex RL100-ATX driver
+ --enable-w89c840 enable Winbond W89c840 driver
--enable-compex-rl2000-fix
specify this if you have a Compex RL2000 PCI
--enable-ne-scan=LIST probe for NE base address using LIST
@@ -5680,6 +5681,16 @@
NETBOOT_DRIVERS="$NETBOOT_DRIVERS sis900.o"
fi
+# Check whether --enable-sundance or --disable-sundance was given.
+if test "${enable_sundance+set}" = set; then
+ enableval="$enable_sundance"
+
+fi;
+if test "x$enable_sundance" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SUNDANCE=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS sundance.o"
+fi
+
# Check whether --enable-tg3 or --disable-tg3 was given.
if test "${enable_tg3+set}" = set; then
enableval="$enable_tg3"
@@ -5710,14 +5721,14 @@
NETBOOT_DRIVERS="$NETBOOT_DRIVERS tlan.o"
fi
-# Check whether --enable-sundance or --disable-sundance was given.
-if test "${enable_sundance+set}" = set; then
- enableval="$enable_sundance"
+# Check whether --enable-undi or --disable-undi was given.
+if test "${enable_undi+set}" = set; then
+ enableval="$enable_undi"
fi;
-if test "x$enable_sundance" = xyes; then
- NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SUNDANCE=1"
- NETBOOT_DRIVERS="$NETBOOT_DRIVERS sundance.o"
+if test "x$enable_undi" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_UNDI=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS undi.o"
fi
# Check whether --enable-via-rhine or --disable-via-rhine was given.
diff -urN release_2/configure.ac release_2_undi/configure.ac
--- release_2/configure.ac 2004-06-18 16:20:47.000000000 +0800
+++ release_2_undi/configure.ac 2004-07-03 14:27:01.000000000 +0800
@@ -398,14 +398,14 @@
fi
AC_ARG_ENABLE(pcnet32,
- [ --enable-pcnet32 enable AMD Lance/PCI PCNet/32 driver])
+ [ --enable-pcnet32 enable AMD Lance/PCI PCNet/32 driver])
if test "x$enable_pcnet32" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_PCNET32=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS pcnet32.o"
fi
AC_ARG_ENABLE(pnic,
- [ --enable-pnic enable Bochs Pseudo Nic driver])
+ [ --enable-pnic enable Bochs Pseudo Nic driver])
if test "x$enable_pnic" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_PNIC=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS pnic.o"
@@ -419,7 +419,7 @@
fi
AC_ARG_ENABLE(r8169,
- [ --enable-r8169 enable Realtek 8169 driver])
+ [ --enable-r8169 enable Realtek 8169 driver])
if test "x$enable_r8169" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_R8169=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS r8169.o"
@@ -432,8 +432,15 @@
NETBOOT_DRIVERS="$NETBOOT_DRIVERS sis900.o"
fi
+AC_ARG_ENABLE(sundance,
+ [ --enable-sundance enable Sundance ST201 driver])
+if test "x$enable_sundance" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SUNDANCE=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS sundance.o"
+fi
+
AC_ARG_ENABLE(tg3,
- [ --enable-tg3 enable Broadcom Tigon3 driver])
+ [ --enable-tg3 enable Broadcom Tigon3 driver])
if test "x$enable_tg3" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_TG3=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS tg3.o"
@@ -447,17 +454,17 @@
fi
AC_ARG_ENABLE(tlan,
- [ --enable-tlan enable TI ThunderLAN driver])
+ [ --enable-tlan enable TI ThunderLAN driver])
if test "x$enable_tlan" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_TLAN=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS tlan.o"
fi
-AC_ARG_ENABLE(sundance,
- [ --enable-sundance enable Sundance ST201 driver])
-if test "x$enable_sundance" = xyes; then
- NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SUNDANCE=1"
- NETBOOT_DRIVERS="$NETBOOT_DRIVERS sundance.o"
+AC_ARG_ENABLE(undi,
+ [ --enable-undi enable PXE UNDI driver])
+if test "x$enable_undi" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_UNDI=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS undi.o"
fi
AC_ARG_ENABLE(via-rhine,
@@ -468,7 +475,7 @@
fi
AC_ARG_ENABLE(w89c840,
- [ --enable-w89c840 enable Winbond W89c840, Compex RL100-ATX driver])
+ [ --enable-w89c840 enable Winbond W89c840 driver])
if test "x$enable_w89c840" = xyes; then
NET_CFLAGS="$NET_CFLAGS -DINCLUDE_W89C840=1"
NETBOOT_DRIVERS="$NETBOOT_DRIVERS w89c840.o"
diff -urN release_2/netboot/basemem.c release_2_undi/netboot/basemem.c
--- release_2/netboot/basemem.c 1970-01-01 08:00:00.000000000 +0800
+++ release_2_undi/netboot/basemem.c 2004-06-17 20:48:08.000000000 +0800
@@ -0,0 +1,178 @@
+#include "etherboot.h"
+#define DEBUG_BASEMEM
+/* Routines to allocate base memory in a BIOS-compatible way, by
+ * updating the Free Base Memory Size counter at 40:13h.
+ *
+ * Michael Brown <mbrown@fensystems.co.uk> (mcb30)
+ * $Id: basemem.c,v 1.5 2004/06/17 12:48:08 fengshuo Exp $
+ */
+
+#define fbms ( ( uint16_t * ) phys_to_virt ( 0x413 ) )
+#define BASE_MEMORY_MAX ( 640 )
+#define FREE_BLOCK_MAGIC ( ('!'<<0) + ('F'<<8) + ('R'<<16) + ('E'<<24) )
+
+typedef struct free_base_memory_block {
+ uint32_t magic;
+ uint16_t size_kb;
+} free_base_memory_block_t;
+
+/* Return amount of free base memory in bytes
+ */
+
+uint32_t get_free_base_memory ( void ) {
+ return *fbms << 10;
+}
+
+/* Adjust the real mode stack pointer. We keep the real mode stack at
+ * the top of free base memory, rather than allocating space for it.
+ */
+
+inline void adjust_real_mode_stack ( void ) {
+/* real_mode_stack = ( *fbms << 10 ); */
+}
+
+/* Allocate N bytes of base memory. Amount allocated will be rounded
+ * up to the nearest kB, since that's the granularity of the BIOS FBMS
+ * counter. Returns NULL if memory cannot be allocated.
+ */
+
+void * allot_base_memory ( size_t size ) {
+ uint16_t size_kb = ( size + 1023 ) >> 10;
+ void *ptr = NULL;
+
+#ifdef DEBUG_BASEMEM
+ printf ( "Trying to allocate %d kB of base memory, %d kB free\n",
+ size_kb, *fbms );
+#endif
+
+ /* Free up any unused memory before we start */
+ free_unused_base_memory();
+
+ /* Check available base memory */
+ if ( size_kb > *fbms ) { return NULL; }
+
+ /* Reduce available base memory */
+ *fbms -= size_kb;
+
+ /* Calculate address of memory allocated */
+ ptr = phys_to_virt ( *fbms << 10 );
+
+#ifdef DEBUG_BASEMEM
+ /* Zero out memory. We do this so that allocation of
+ * already-used space will show up in the form of a crash as
+ * soon as possible.
+ */
+ memset ( ptr, 0, size_kb << 10 );
+#endif
+
+ /* Adjust real mode stack pointer */
+ adjust_real_mode_stack ();
+
+ return ptr;
+}
+
+/* Free base memory allocated by allot_base_memory. The BIOS provides
+ * nothing better than a LIFO mechanism for freeing memory (i.e. it
+ * just has the single "total free memory" counter), but we improve
+ * upon this slightly; as long as you free all the allotted blocks, it
+ * doesn't matter what order you free them in. (This will only work
+ * for blocks that are freed via forget_base_memory()).
+ *
+ * Yes, it's annoying that you have to remember the size of the blocks
+ * you've allotted. However, since our granularity of allocation is
+ * 1K, the alternative is to risk wasting the occasional kB of base
+ * memory, which is a Bad Thing. Really, you should be using as
+ * little base memory as possible, so consider the awkwardness of the
+ * API to be a feature! :-)
+ */
+
+void forget_base_memory ( void *ptr, size_t size ) {
+ uint16_t remainder = virt_to_phys(ptr) & 1023;
+ uint16_t size_kb = ( size + remainder + 1023 ) >> 10;
+ free_base_memory_block_t *free_block =
+ ( free_base_memory_block_t * ) ( ptr - remainder );
+
+ if ( ( ptr == NULL ) || ( size == 0 ) ) { return; }
+
+#ifdef DEBUG_BASEMEM
+ printf ( "Trying to free %d bytes base memory at 0x%x\n",
+ size, virt_to_phys ( ptr ) );
+ if ( remainder > 0 ) {
+ printf ( "WARNING: destructively expanding free block "
+ "downwards to 0x%x\n",
+ virt_to_phys ( ptr - remainder ) );
+ }
+#endif
+
+ /* Mark every kilobyte within this block as free. This is
+ * overkill for normal purposes, but helps when something has
+ * allocated base memory with a granularity finer than the
+ * BIOS granularity of 1kB. PXE ROMs tend to do this when
+ * they allocate their own memory. This method allows us to
+ * free their blocks (admittedly in a rather dangerous,
+ * tread-on-anything-either-side sort of way, but there's no
+ * other way to do it).
+ *
+ * Since we're marking every kB as free, there's actually no
+ * need for recording the size of the blocks. However, we
+ * keep this in so that debug messages are friendlier. It
+ * probably adds around 8 bytes to the overall code size.
+ */
+ while ( size_kb > 0 ) {
+ /* Mark this block as unused */
+ free_block->magic = FREE_BLOCK_MAGIC;
+ free_block->size_kb = size_kb;
+ /* Move up by 1 kB */
+ (void *)free_block += ( 1 << 10 );
+ size_kb--;
+ }
+
+ /* Free up unused base memory */
+ free_unused_base_memory();
+}
+
+/* Do the actual freeing of memory. This is split out from
+ * forget_base_memory() so that it may be called separately. It
+ * should be called whenever base memory is deallocated by an external
+ * entity (if we can detect that it has done so) so that we get the
+ * chance to free up our own blocks.
+ */
+void free_unused_base_memory ( void ) {
+ free_base_memory_block_t *free_block = NULL;
+
+ /* Try to release memory back to the BIOS. Free all
+ * consecutive blocks marked as free.
+ */
+ while ( 1 ) {
+ /* Calculate address of next potential free block */
+ free_block = ( free_base_memory_block_t * )
+ phys_to_virt ( *fbms << 10 );
+
+ /* Stop processing if we're all the way up to 640K or
+ * if this is not a free block
+ */
+ if ( ( *fbms == BASE_MEMORY_MAX ) ||
+ ( free_block->magic != FREE_BLOCK_MAGIC ) ) {
+ break;
+ }
+
+ /* Return memory to BIOS */
+ *fbms += free_block->size_kb;
+
+#ifdef DEBUG_BASEMEM
+ printf ( "Freed %d kB base memory, %d kB now free\n",
+ free_block->size_kb, *fbms );
+
+ /* Zero out freed block. We do this in case
+ * the block contained any structures that
+ * might be located by scanning through
+ * memory.
+ */
+ memset ( free_block, 0, free_block->size_kb << 10 );
+#endif
+ }
+
+ /* Adjust real mode stack pointer */
+ adjust_real_mode_stack ();
+}
+
diff -urN release_2/netboot/etherboot.h release_2_undi/netboot/etherboot.h
--- release_2/netboot/etherboot.h 2004-06-30 15:06:12.000000000 +0800
+++ release_2_undi/netboot/etherboot.h 2004-07-03 14:52:13.000000000 +0800
@@ -27,6 +27,7 @@
#include "shared.h"
#include "osdep.h"
#include "if_ether.h"
+#include "in.h"
/* Link configuration time in tenths of a second */
#ifndef VALID_LINK_TIMEOUT
@@ -50,4 +51,11 @@
extern void poll_interruptions P((void));
+/* For UNDI drivers */
+extern void fake_irq ( uint8_t irq );
+extern void _trivial_irq_handler_start;
+extern uint32_t get_free_base_memory ( void );
+extern void forget_base_memory ( void*, size_t );
+extern void free_unused_base_memory ( void );
+
#endif /* ETHERBOOT_H */
diff -urN release_2/netboot/Makefile.am release_2_undi/netboot/Makefile.am
--- release_2/netboot/Makefile.am 2004-06-21 10:38:31.000000000 +0800
+++ release_2_undi/netboot/Makefile.am 2004-07-03 14:28:42.000000000 +0800
@@ -16,12 +16,13 @@
if_arp.h if_ether.h igmp.h in.h io.h ip.h isa.h latch.h \
little_bswap.h misc.c nic.c nic.h osdep.h pci.c pci.h \
pci_ids.h pci_io.c stdint.h tftp.h timer.c timer.h \
- types.h udp.h mii.h
+ types.h udp.h mii.h pic8259.c pic8259.h pxe.h basemem.c segoff.h
EXTRA_libdrivers_a_SOURCES = 3c595.c 3c595.h 3c90x.c davicom.c \
e1000.c e1000_hw.h eepro100.c epic100.c epic100.h natsemi.c \
ns8390.c ns8390.h pcnet32.c rtl8139.c sis900.c sis900.h \
sundance.c tg3.c tg3.h tlan.c tlan.h tulip.c via-rhine.c \
- w89c840.c r8169.c forcedeth.c ns83820.c pnic.c pnic_api.c
+ w89c840.c r8169.c forcedeth.c ns83820.c pnic.c pnic_api.c \
+ undi.c undi.h
libdrivers_a_CFLAGS = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
-DFSYS_TFTP=1 $(NET_CFLAGS) $(NET_EXTRAFLAGS)
# Filled by configure.
@@ -65,6 +66,7 @@
#tiara_drivers = tiara.o
tlan_drivers = tlan.o
tulip_drivers = tulip.o
+undi_drivers = undi.o
via_rhine_drivers = via_rhine.o
w89c840_drivers = w89c840.o
@@ -225,6 +227,11 @@
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
+$(undi_drivers): undi.c undi.h
+$(undi_drivers): %.o: undi.c
+ $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
+ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
+
$(via_rhine_drivers): via-rhine.c
$(via_rhine_drivers): %.o: via-rhine.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
@@ -275,5 +282,6 @@
tg3_o_CFLAGS = -DINCLUDE_TG3=1
tlan_o_CFLAGS = -DINCLUDE_TLAN=1
tulip_o_CFLAGS = -DINCLUDE_TULIP=1
+undi_o_CFLAGS = -DINCLUDE_UNDI=1
via_rhine_o_CFLAGS = -DINCLUDE_VIA_RHINE=1
w89c840_o_CFLAGS = -DINCLUDE_W89C840=1
diff -urN release_2/netboot/Makefile.in release_2_undi/netboot/Makefile.in
--- release_2/netboot/Makefile.in 2004-06-21 10:38:31.000000000 +0800
+++ release_2_undi/netboot/Makefile.in 2004-07-03 14:30:10.000000000 +0800
@@ -55,13 +55,15 @@
libdrivers_a-fsys_tftp.$(OBJEXT) \
libdrivers_a-i386_timer.$(OBJEXT) libdrivers_a-misc.$(OBJEXT) \
libdrivers_a-nic.$(OBJEXT) libdrivers_a-pci.$(OBJEXT) \
- libdrivers_a-pci_io.$(OBJEXT) libdrivers_a-timer.$(OBJEXT)
+ libdrivers_a-pci_io.$(OBJEXT) libdrivers_a-timer.$(OBJEXT) \
+ libdrivers_a-pic8259.$(OBJEXT) libdrivers_a-basemem.$(OBJEXT)
libdrivers_a_OBJECTS = $(am_libdrivers_a_OBJECTS)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/libdrivers_a-3c595.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-3c90x.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-basemem.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-config.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-davicom.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-e1000.Po \
@@ -78,6 +80,7 @@
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-pci.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-pci_io.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-pcnet32.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-pic8259.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-pnic.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-pnic_api.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-r8169.Po \
@@ -88,6 +91,7 @@
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-timer.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-tlan.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-tulip.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-undi.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-via-rhine.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/libdrivers_a-w89c840.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
@@ -220,13 +224,14 @@
if_arp.h if_ether.h igmp.h in.h io.h ip.h isa.h latch.h \
little_bswap.h misc.c nic.c nic.h osdep.h pci.c pci.h \
pci_ids.h pci_io.c stdint.h tftp.h timer.c timer.h \
- types.h udp.h mii.h
+ types.h udp.h mii.h pic8259.c pic8259.h pxe.h basemem.c segoff.h
EXTRA_libdrivers_a_SOURCES = 3c595.c 3c595.h 3c90x.c davicom.c \
e1000.c e1000_hw.h eepro100.c epic100.c epic100.h natsemi.c \
ns8390.c ns8390.h pcnet32.c rtl8139.c sis900.c sis900.h \
sundance.c tg3.c tg3.h tlan.c tlan.h tulip.c via-rhine.c \
- w89c840.c r8169.c forcedeth.c ns83820.c pnic.c pnic_api.c
+ w89c840.c r8169.c forcedeth.c ns83820.c pnic.c pnic_api.c \
+ undi.c undi.h
libdrivers_a_CFLAGS = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
-DFSYS_TFTP=1 $(NET_CFLAGS) $(NET_EXTRAFLAGS)
@@ -271,6 +276,7 @@
#tiara_drivers = tiara.o
tlan_drivers = tlan.o
tulip_drivers = tulip.o
+undi_drivers = undi.o
via_rhine_drivers = via_rhine.o
w89c840_drivers = w89c840.o
@@ -314,6 +320,7 @@
tg3_o_CFLAGS = -DINCLUDE_TG3=1
tlan_o_CFLAGS = -DINCLUDE_TLAN=1
tulip_o_CFLAGS = -DINCLUDE_TULIP=1
+undi_o_CFLAGS = -DINCLUDE_UNDI=1
via_rhine_o_CFLAGS = -DINCLUDE_VIA_RHINE=1
w89c840_o_CFLAGS = -DINCLUDE_W89C840=1
all: all-am
@@ -365,6 +372,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-3c595.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-3c90x.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-basemem.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-config.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-davicom.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-e1000.Po@am__quote@
@@ -381,6 +389,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-pci.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-pci_io.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-pcnet32.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-pic8259.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-pnic.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-pnic_api.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-r8169.Po@am__quote@
@@ -391,6 +400,7 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-timer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-tlan.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-tulip.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-undi.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-via-rhine.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdrivers_a-w89c840.Po@am__quote@
@@ -538,6 +548,38 @@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-timer.obj `if test -f 'timer.c'; then $(CYGPATH_W) 'timer.c'; else $(CYGPATH_W) '$(srcdir)/timer.c'; fi`
+libdrivers_a-pic8259.o: pic8259.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -MT libdrivers_a-pic8259.o -MD -MP -MF "$(DEPDIR)/libdrivers_a-pic8259.Tpo" -c -o libdrivers_a-pic8259.o `test -f 'pic8259.c' || echo '$(srcdir)/'`pic8259.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libdrivers_a-pic8259.Tpo" "$(DEPDIR)/libdrivers_a-pic8259.Po"; else rm -f "$(DEPDIR)/libdrivers_a-pic8259.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pic8259.c' object='libdrivers_a-pic8259.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/libdrivers_a-pic8259.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-pic8259.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-pic8259.o `test -f 'pic8259.c' || echo '$(srcdir)/'`pic8259.c
+
+libdrivers_a-pic8259.obj: pic8259.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -MT libdrivers_a-pic8259.obj -MD -MP -MF "$(DEPDIR)/libdrivers_a-pic8259.Tpo" -c -o libdrivers_a-pic8259.obj `if test -f 'pic8259.c'; then $(CYGPATH_W) 'pic8259.c'; else $(CYGPATH_W) '$(srcdir)/pic8259.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libdrivers_a-pic8259.Tpo" "$(DEPDIR)/libdrivers_a-pic8259.Po"; else rm -f "$(DEPDIR)/libdrivers_a-pic8259.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pic8259.c' object='libdrivers_a-pic8259.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/libdrivers_a-pic8259.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-pic8259.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-pic8259.obj `if test -f 'pic8259.c'; then $(CYGPATH_W) 'pic8259.c'; else $(CYGPATH_W) '$(srcdir)/pic8259.c'; fi`
+
+libdrivers_a-basemem.o: basemem.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -MT libdrivers_a-basemem.o -MD -MP -MF "$(DEPDIR)/libdrivers_a-basemem.Tpo" -c -o libdrivers_a-basemem.o `test -f 'basemem.c' || echo '$(srcdir)/'`basemem.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libdrivers_a-basemem.Tpo" "$(DEPDIR)/libdrivers_a-basemem.Po"; else rm -f "$(DEPDIR)/libdrivers_a-basemem.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='basemem.c' object='libdrivers_a-basemem.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/libdrivers_a-basemem.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-basemem.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-basemem.o `test -f 'basemem.c' || echo '$(srcdir)/'`basemem.c
+
+libdrivers_a-basemem.obj: basemem.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -MT libdrivers_a-basemem.obj -MD -MP -MF "$(DEPDIR)/libdrivers_a-basemem.Tpo" -c -o libdrivers_a-basemem.obj `if test -f 'basemem.c'; then $(CYGPATH_W) 'basemem.c'; else $(CYGPATH_W) '$(srcdir)/basemem.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libdrivers_a-basemem.Tpo" "$(DEPDIR)/libdrivers_a-basemem.Po"; else rm -f "$(DEPDIR)/libdrivers_a-basemem.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='basemem.c' object='libdrivers_a-basemem.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/libdrivers_a-basemem.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-basemem.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-basemem.obj `if test -f 'basemem.c'; then $(CYGPATH_W) 'basemem.c'; else $(CYGPATH_W) '$(srcdir)/basemem.c'; fi`
+
libdrivers_a-3c595.o: 3c595.c
@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -MT libdrivers_a-3c595.o -MD -MP -MF "$(DEPDIR)/libdrivers_a-3c595.Tpo" -c -o libdrivers_a-3c595.o `test -f '3c595.c' || echo '$(srcdir)/'`3c595.c; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libdrivers_a-3c595.Tpo" "$(DEPDIR)/libdrivers_a-3c595.Po"; else rm -f "$(DEPDIR)/libdrivers_a-3c595.Tpo"; exit 1; fi
@@ -889,6 +931,22 @@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/libdrivers_a-pnic_api.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-pnic_api.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-pnic_api.obj `if test -f 'pnic_api.c'; then $(CYGPATH_W) 'pnic_api.c'; else $(CYGPATH_W) '$(srcdir)/pnic_api.c'; fi`
+
+libdrivers_a-undi.o: undi.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -MT libdrivers_a-undi.o -MD -MP -MF "$(DEPDIR)/libdrivers_a-undi.Tpo" -c -o libdrivers_a-undi.o `test -f 'undi.c' || echo '$(srcdir)/'`undi.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libdrivers_a-undi.Tpo" "$(DEPDIR)/libdrivers_a-undi.Po"; else rm -f "$(DEPDIR)/libdrivers_a-undi.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='undi.c' object='libdrivers_a-undi.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/libdrivers_a-undi.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-undi.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-undi.o `test -f 'undi.c' || echo '$(srcdir)/'`undi.c
+
+libdrivers_a-undi.obj: undi.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -MT libdrivers_a-undi.obj -MD -MP -MF "$(DEPDIR)/libdrivers_a-undi.Tpo" -c -o libdrivers_a-undi.obj `if test -f 'undi.c'; then $(CYGPATH_W) 'undi.c'; else $(CYGPATH_W) '$(srcdir)/undi.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/libdrivers_a-undi.Tpo" "$(DEPDIR)/libdrivers_a-undi.Po"; else rm -f "$(DEPDIR)/libdrivers_a-undi.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='undi.c' object='libdrivers_a-undi.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/libdrivers_a-undi.Po' tmpdepfile='$(DEPDIR)/libdrivers_a-undi.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libdrivers_a_CFLAGS) $(CFLAGS) -c -o libdrivers_a-undi.obj `if test -f 'undi.c'; then $(CYGPATH_W) 'undi.c'; else $(CYGPATH_W) '$(srcdir)/undi.c'; fi`
uninstall-info-am:
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
@@ -1209,6 +1267,11 @@
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
$(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
+$(undi_drivers): undi.c undi.h
+$(undi_drivers): %.o: undi.c
+ $(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
+ $(NET_EXTRAFLAGS) $($(basename $@)_o_CFLAGS) -o $@ -c $<
+
$(via_rhine_drivers): via-rhine.c
$(via_rhine_drivers): %.o: via-rhine.c
$(COMPILE) $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
diff -urN release_2/netboot/pci.c release_2_undi/netboot/pci.c
--- release_2/netboot/pci.c 2004-06-30 14:12:00.000000000 +0800
+++ release_2_undi/netboot/pci.c 2004-07-03 14:52:13.000000000 +0800
@@ -77,6 +77,10 @@
extern struct pci_driver sis_bridge_driver;
#endif /* INCLUDE_SIS900 */
+#ifdef INCLUDE_SUNDANCE
+extern struct pci_driver sundance_driver;
+#endif /* INCLUDE_SUNDANCE */
+
#ifdef INCLUDE_TG3
extern struct pci_driver tg3_driver;
#endif /* INCLUDE_TG3 */
@@ -89,6 +93,10 @@
extern struct pci_driver tulip_driver;
#endif /* INCLUDE_TULIP */
+#ifdef INCLUDE_UNDI
+extern struct pci_driver undi_driver;
+#endif /* INCLUDE_UNDI */
+
#ifdef INCLUDE_VIA_RHINE
extern struct pci_driver rhine_driver;
#endif/* INCLUDE_VIA_RHINE */
@@ -97,10 +105,6 @@
extern struct pci_driver w89c840_driver;
#endif /* INCLUDE_W89C840 */
-#ifdef INCLUDE_SUNDANCE
-extern struct pci_driver sundance_driver;
-#endif
-
#ifdef INCLUDE_R8169
extern struct pci_driver r8169_driver;
#endif /* INCLUDE_R8169 */
@@ -166,7 +170,7 @@
#ifdef INCLUDE_SUNDANCE
&sundance_driver,
-#endif
+#endif /* INCLUDE_SUNDANCE */
#ifdef INCLUDE_TG3
& tg3_driver,
@@ -192,6 +196,11 @@
&r8169_driver,
#endif /* INCLUDE_R8169 */
+/* We must be the last one */
+#ifdef INCLUDE_UNDI
+ &undi_driver,
+#endif /* INCLUDE_UNDI */
+
0
};
diff -urN release_2/netboot/pic8259.c release_2_undi/netboot/pic8259.c
--- release_2/netboot/pic8259.c 1970-01-01 08:00:00.000000000 +0800
+++ release_2_undi/netboot/pic8259.c 2004-03-18 13:28:24.000000000 +0800
@@ -0,0 +1,267 @@
+/*
+ * Basic support for controlling the 8259 Programmable Interrupt Controllers.
+ *
+ * Initially written by Michael Brown (mcb30).
+ */
+
+#include <etherboot.h>
+#include <pic8259.h>
+
+#ifdef DEBUG_IRQ
+#define DBG(...) printf ( __VA_ARGS__ )
+#else
+#define DBG(...)
+#endif
+
+/* Current locations of trivial IRQ handler. These will change at
+ * runtime when relocation is used; the handler needs to be copied to
+ * base memory before being installed.
+ */
+void (*trivial_irq_handler)P((void)) = _trivial_irq_handler;
+uint16_t volatile *trivial_irq_trigger_count = &_trivial_irq_trigger_count;
+segoff_t *trivial_irq_chain_to = &_trivial_irq_chain_to;
+uint8_t *trivial_irq_chain = &_trivial_irq_chain;
+irq_t trivial_irq_installed_on = IRQ_NONE;
+
+/* Previous trigger count for trivial IRQ handler */
+static uint16_t trivial_irq_previous_trigger_count = 0;
+
+/* Install a handler for the specified IRQ. Address of previous
+ * handler will be stored in previous_handler. Enabled/disabled state
+ * of IRQ will be preserved across call, therefore if the handler does
+ * chaining, ensure that either (a) IRQ is disabled before call, or
+ * (b) previous_handler points directly to the place that the handler
+ * picks up its chain-to address.
+ */
+
+int install_irq_handler ( irq_t irq, segoff_t *handler,
+ uint8_t *previously_enabled,
+ segoff_t *previous_handler ) {
+ segoff_t *irq_vector = IRQ_VECTOR ( irq );
+ *previously_enabled = irq_enabled ( irq );
+
+ if ( irq > IRQ_MAX ) {
+ DBG ( "Invalid IRQ number %d\n" );
+ return 0;
+ }
+
+ previous_handler->segment = irq_vector->segment;
+ previous_handler->offset = irq_vector->offset;
+ if ( *previously_enabled ) disable_irq ( irq );
+ DBG ( "Installing handler at %hx:%hx for IRQ %d, leaving %s\n",
+ handler->segment, handler->offset, irq,
+ ( *previously_enabled ? "enabled" : "disabled" ) );
+ DBG ( "...(previous handler at %hx:%hx)\n",
+ previous_handler->segment, previous_handler->offset );
+ irq_vector->segment = handler->segment;
+ irq_vector->offset = handler->offset;
+ if ( *previously_enabled ) enable_irq ( irq );
+ return 1;
+}
+
+/* Remove handler for the specified IRQ. Routine checks that another
+ * handler has not been installed that chains to handler before
+ * uninstalling handler. Enabled/disabled state of the IRQ will be
+ * restored to that specified by previously_enabled.
+ */
+
+int remove_irq_handler ( irq_t irq, segoff_t *handler,
+ uint8_t *previously_enabled,
+ segoff_t *previous_handler ) {
+ segoff_t *irq_vector = IRQ_VECTOR ( irq );
+
+ if ( irq > IRQ_MAX ) {
+ DBG ( "Invalid IRQ number %d\n" );
+ return 0;
+ }
+ if ( ( irq_vector->segment != handler->segment ) ||
+ ( irq_vector->offset != handler->offset ) ) {
+ DBG ( "Cannot remove handler for IRQ %d\n" );
+ return 0;
+ }
+
+ DBG ( "Removing handler for IRQ %d\n", irq );
+ disable_irq ( irq );
+ irq_vector->segment = previous_handler->segment;
+ irq_vector->offset = previous_handler->offset;
+ if ( *previously_enabled ) enable_irq ( irq );
+ return 1;
+}
+
+/* Install the trivial IRQ handler. This routine installs the
+ * handler, tests it and enables the IRQ.
+ */
+
+int install_trivial_irq_handler ( irq_t irq ) {
+ segoff_t trivial_irq_handler_segoff = SEGOFF(trivial_irq_handler);
+
+ if ( trivial_irq_installed_on != IRQ_NONE ) {
+ DBG ( "Can install trivial IRQ handler only once\n" );
+ return 0;
+ }
+ if ( SEGMENT(trivial_irq_handler) > 0xffff ) {
+ DBG ( "Trivial IRQ handler not in base memory\n" );
+ return 0;
+ }
+
+ DBG ( "Installing trivial IRQ handler on IRQ %d\n", irq );
+ if ( ! install_irq_handler ( irq, &trivial_irq_handler_segoff,
+ trivial_irq_chain,
+ trivial_irq_chain_to ) )
+ return 0;
+ trivial_irq_installed_on = irq;
+
+ DBG ( "Testing trivial IRQ handler\n" );
+ disable_irq ( irq );
+ *trivial_irq_trigger_count = 0;
+ trivial_irq_previous_trigger_count = 0;
+ fake_irq ( irq );
+ if ( ! trivial_irq_triggered ( irq ) ) {
+ DBG ( "Installation of trivial IRQ handler failed\n" );
+ remove_trivial_irq_handler ( irq );
+ return 0;
+ }
+ DBG ( "Trivial IRQ handler installed successfully\n" );
+ enable_irq ( irq );
+ return 1;
+}
+
+/* Remove the trivial IRQ handler.
+ */
+
+int remove_trivial_irq_handler ( irq_t irq ) {
+ segoff_t trivial_irq_handler_segoff = SEGOFF(trivial_irq_handler);
+
+ if ( trivial_irq_installed_on == IRQ_NONE ) return 1;
+ if ( irq != trivial_irq_installed_on ) {
+ DBG ( "Cannot uninstall trivial IRQ handler from IRQ %d; "
+ "is installed on IRQ %d\n", irq,
+ trivial_irq_installed_on );
+ return 0;
+ }
+
+ if ( ! remove_irq_handler ( irq, &trivial_irq_handler_segoff,
+ trivial_irq_chain,
+ trivial_irq_chain_to ) )
+ return 0;
+
+ if ( trivial_irq_triggered ( trivial_irq_installed_on ) ) {
+ DBG ( "Sending EOI for unwanted trivial IRQ\n" );
+ send_specific_eoi ( trivial_irq_installed_on );
+ }
+
+ trivial_irq_installed_on = IRQ_NONE;
+ return 1;
+}
+
+/* Safe method to detect whether or not trivial IRQ has been
+ * triggered. Using this call avoids potential race conditions. This
+ * call will return success only once per trigger.
+ */
+
+int trivial_irq_triggered ( irq_t irq ) {
+ uint16_t trivial_irq_this_trigger_count = *trivial_irq_trigger_count;
+ int triggered = ( trivial_irq_this_trigger_count -
+ trivial_irq_previous_trigger_count );
+
+ /* irq is not used at present, but we have it in the API for
+ * future-proofing; in case we want the facility to have
+ * multiple trivial IRQ handlers installed simultaneously.
+ *
+ * Avoid compiler warning about unused variable.
+ */
+ if ( irq == IRQ_NONE ) {};
+
+ trivial_irq_previous_trigger_count = trivial_irq_this_trigger_count;
+ return triggered ? 1 : 0;
+}
+
+/* Copy trivial IRQ handler to a new location. Typically used to copy
+ * the handler into base memory; when relocation is being used we need
+ * to do this before installing the handler.
+ *
+ * Call with target=NULL in order to restore the handler to its
+ * original location.
+ */
+
+int copy_trivial_irq_handler ( void *target, size_t target_size ) {
+ irq_t currently_installed_on = trivial_irq_installed_on;
+ uint32_t offset = ( target == NULL ? 0 :
+ target - &_trivial_irq_handler_start );
+
+ if (( target != NULL ) && ( target_size < TRIVIAL_IRQ_HANDLER_SIZE )) {
+ DBG ( "Insufficient space to copy trivial IRQ handler\n" );
+ return 0;
+ }
+
+ if ( currently_installed_on != IRQ_NONE ) {
+ DBG ("WARNING: relocating trivial IRQ handler while in use\n");
+ if ( ! remove_trivial_irq_handler ( currently_installed_on ) )
+ return 0;
+ }
+
+ /* Do the actual copy */
+ if ( target != NULL ) {
+ DBG ( "Copying trivial IRQ handler to %hx:%hx\n",
+ SEGMENT(target), OFFSET(target) );
+ memcpy ( target, &_trivial_irq_handler_start,
+ TRIVIAL_IRQ_HANDLER_SIZE );
+ } else {
+ DBG ( "Restoring trivial IRQ handler to original location\n" );
+ }
+ /* Update all the pointers to structures within the handler */
+ trivial_irq_handler = ( void (*)P((void)) )
+ ( (void*)_trivial_irq_handler + offset );
+ trivial_irq_trigger_count = (uint16_t*)
+ ( (void*)&_trivial_irq_trigger_count + offset );
+ trivial_irq_chain_to = (segoff_t*)
+ ( (void*)&_trivial_irq_chain_to + offset );
+ trivial_irq_chain = (uint8_t*)
+ ( (void*)&_trivial_irq_chain + offset );
+
+ if ( currently_installed_on != IRQ_NONE ) {
+ if ( ! install_trivial_irq_handler ( currently_installed_on ) )
+ return 0;
+ }
+ return 1;
+}
+
+/* Send non-specific EOI(s). This seems to be inherently unsafe.
+ */
+
+void send_nonspecific_eoi ( irq_t irq ) {
+ DBG ( "Sending non-specific EOI for IRQ %d\n", irq );
+ if ( irq >= IRQ_PIC_CUTOFF ) {
+ outb ( ICR_EOI_NON_SPECIFIC, PIC2_ICR );
+ }
+ outb ( ICR_EOI_NON_SPECIFIC, PIC1_ICR );
+}
+
+/* Send specific EOI(s).
+ */
+
+void send_specific_eoi ( irq_t irq ) {
+ DBG ( "Sending specific EOI for IRQ %d\n", irq );
+ outb ( ICR_EOI_SPECIFIC | ICR_VALUE(irq), ICR_REG(irq) );
+ if ( irq >= IRQ_PIC_CUTOFF ) {
+ outb ( ICR_EOI_SPECIFIC | ICR_VALUE(CHAINED_IRQ),
+ ICR_REG(CHAINED_IRQ) );
+ }
+}
+
+/* Dump current 8259 status: enabled IRQs and handler addresses.
+ */
+
+#ifdef DEBUG_IRQ
+void dump_irq_status ( void ) {
+ int irq = 0;
+
+ for ( irq = 0; irq < 16; irq++ ) {
+ if ( irq_enabled ( irq ) ) {
+ printf ( "IRQ%d enabled, ISR at %hx:%hx\n", irq,
+ IRQ_VECTOR(irq)->segment,
+ IRQ_VECTOR(irq)->offset );
+ }
+ }
+}
+#endif
diff -urN release_2/netboot/pic8259.h release_2_undi/netboot/pic8259.h
--- release_2/netboot/pic8259.h 1970-01-01 08:00:00.000000000 +0800
+++ release_2_undi/netboot/pic8259.h 2004-03-17 22:29:24.000000000 +0800
@@ -0,0 +1,99 @@
+/*
+ * Basic support for controlling the 8259 Programmable Interrupt Controllers.
+ *
+ * Initially written by Michael Brown (mcb30).
+ */
+
+#ifndef PIC8259_H
+#define PIC8259_H
+
+/* For segoff_t */
+#include <segoff.h>
+
+#define IRQ_PIC_CUTOFF (8)
+
+/* 8259 register locations */
+#define PIC1_ICW1 (0x20)
+#define PIC1_OCW2 (0x20)
+#define PIC1_OCW3 (0x20)
+#define PIC1_ICR (0x20)
+#define PIC1_IRR (0x20)
+#define PIC1_ISR (0x20)
+#define PIC1_ICW2 (0x21)
+#define PIC1_ICW3 (0x21)
+#define PIC1_ICW4 (0x21)
+#define PIC1_IMR (0x21)
+#define PIC2_ICW1 (0xa0)
+#define PIC2_OCW2 (0xa0)
+#define PIC2_OCW3 (0xa0)
+#define PIC2_ICR (0xa0)
+#define PIC2_IRR (0xa0)
+#define PIC2_ISR (0xa0)
+#define PIC2_ICW2 (0xa1)
+#define PIC2_ICW3 (0xa1)
+#define PIC2_ICW4 (0xa1)
+#define PIC2_IMR (0xa1)
+
+/* Register command values */
+#define OCW3_ID (0x08)
+#define OCW3_READ_IRR (0x03)
+#define OCW3_READ_ISR (0x02)
+#define ICR_EOI_NON_SPECIFIC (0x20)
+#define ICR_EOI_NOP (0x40)
+#define ICR_EOI_SPECIFIC (0x60)
+#define ICR_EOI_SET_PRIORITY (0xc0)
+
+/* Macros to enable/disable IRQs */
+#define IMR_REG(x) ( (x) < IRQ_PIC_CUTOFF ? PIC1_IMR : PIC2_IMR )
+#define IMR_BIT(x) ( 1 << ( (x) % IRQ_PIC_CUTOFF ) )
+#define irq_enabled(x) ( ( inb ( IMR_REG(x) ) & IMR_BIT(x) ) == 0 )
+#define enable_irq(x) outb ( inb( IMR_REG(x) ) & ~IMR_BIT(x), IMR_REG(x) )
+#define disable_irq(x) outb ( inb( IMR_REG(x) ) | IMR_BIT(x), IMR_REG(x) )
+
+/* Macros for acknowledging IRQs */
+#define ICR_REG(x) ( (x) < IRQ_PIC_CUTOFF ? PIC1_ICR : PIC2_ICR )
+#define ICR_VALUE(x) ( (x) % IRQ_PIC_CUTOFF )
+#define CHAINED_IRQ 2
+
+/* Utility macros to convert IRQ numbers to INT numbers and INT vectors */
+#define IRQ_INT(x) ( (x)<IRQ_PIC_CUTOFF ? (x)+0x08 : (x)-IRQ_PIC_CUTOFF+0x70 )
+#define INT_VECTOR(x) ( (segoff_t*) phys_to_virt( 4 * (x) ) )
+#define IRQ_VECTOR(x) ( INT_VECTOR ( IRQ_INT(x) ) )
+
+/* Other constants */
+typedef uint8_t irq_t;
+#define IRQ_MAX (15)
+#define IRQ_NONE (0xff)
+
+/* Labels in assembly code (in pcbios.S)
+ */
+extern void _trivial_irq_handler_start;
+extern void _trivial_irq_handler ( void );
+extern volatile uint16_t _trivial_irq_trigger_count;
+extern segoff_t _trivial_irq_chain_to;
+extern uint8_t _trivial_irq_chain;
+extern void _trivial_irq_handler_end;
+#define TRIVIAL_IRQ_HANDLER_SIZE \
+ ((uint32_t)( &_trivial_irq_handler_end - &_trivial_irq_handler_start ))
+
+/* Function prototypes
+ */
+int install_irq_handler ( irq_t irq, segoff_t *handler,
+ uint8_t *previously_enabled,
+ segoff_t *previous_handler );
+int remove_irq_handler ( irq_t irq, segoff_t *handler,
+ uint8_t *previously_enabled,
+ segoff_t *previous_handler );
+int install_trivial_irq_handler ( irq_t irq );
+int remove_trivial_irq_handler ( irq_t irq );
+int trivial_irq_triggered ( irq_t irq );
+int copy_trivial_irq_handler ( void *target, size_t target_size );
+void send_non_specific_eoi ( irq_t irq );
+void send_specific_eoi ( irq_t irq );
+#ifdef DEBUG_IRQ
+void dump_irq_status ( void );
+#else
+#define dump_irq_status()
+#endif
+
+#endif /* PIC8259_H */
diff -urN release_2/netboot/pxe.h release_2_undi/netboot/pxe.h
--- release_2/netboot/pxe.h 1970-01-01 08:00:00.000000000 +0800
+++ release_2_undi/netboot/pxe.h 2004-03-17 22:29:24.000000000 +0800
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2000 Alfred Perlstein <alfred@freebsd.org>
+ * All rights reserved.
+ * Copyright (c) 2000 Paul Saab <ps@freebsd.org>
+ * All rights reserved.
+ * Copyright (c) 2000 John Baldwin <jhb@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/boot/i386/libi386/pxe.h,v 1.4.2.2 2000/09/10 02:52:18 ps Exp $
+ */
+
+/*
+ * The typedefs and structures declared in this file
+ * clearly violate style(9), the reason for this is to conform to the
+ * typedefs/structure-names used in the Intel literature to avoid confusion.
+ *
+ * It's for your own good. :)
+ */
+
+/* SEGOFF16_t defined in separate header for Etherboot
+ */
+#include <segoff.h>
+
+/* It seems that intel didn't think about ABI,
+ * either that or 16bit ABI != 32bit ABI (which seems reasonable)
+ * I have to thank Intel for the hair loss I incurred trying to figure
+ * out why PXE was mis-reading structures I was passing it (at least
+ * from my point of view)
+ *
+ * Solution: use gcc's '__attribute__ ((packed))' to correctly align
+ * structures passed into PXE
+ * Question: does this really work for PXE's expected ABI?
+ */
+#define PACKED __attribute__ ((packed))
+
+#define S_SIZE(s) s, sizeof(s) - 1
+
+#define IP_STR "%d.%d.%d.%d"
+#define IP_ARGS(ip) \
+ (int)(ip >> 24) & 0xff, (int)(ip >> 16) & 0xff, \
+ (int)(ip >> 8) & 0xff, (int)ip & 0xff
+
+#define MAC_STR "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARGS(mac) \
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
+
+#define PXENFSROOTPATH "/pxeroot"
+
+typedef struct {
+ uint16_t Seg_Addr;
+ uint32_t Phy_Addr;
+ uint16_t Seg_Size;
+} PACKED SEGDESC_t; /* PACKED is required, otherwise gcc pads this out to 12
+ bytes - mbrown@fensystems.co.uk (mcb30) 17/5/03 */
+
+typedef uint16_t SEGSEL_t;
+typedef uint16_t PXENV_STATUS_t;
+typedef uint32_t IP4_t;
+typedef uint32_t ADDR32_t;
+typedef uint16_t UDP_PORT_t;
+
+#define MAC_ADDR_LEN 16
+typedef uint8_t MAC_ADDR[MAC_ADDR_LEN];
+
+/* PXENV+ */
+typedef struct {
+ uint8_t Signature[6]; /* 'PXENV+' */
+ uint16_t Version; /* MSB = major, LSB = minor */
+ uint8_t Length; /* structure length */
+ uint8_t Checksum; /* checksum pad */
+ SEGOFF16_t RMEntry; /* SEG:OFF to PXE entry point */
+ /* don't use PMOffset and PMSelector (from the 2.1 PXE manual) */
+ uint32_t PMOffset; /* Protected mode entry */
+ SEGSEL_t PMSelector; /* Protected mode selector */
+ SEGSEL_t StackSeg; /* Stack segment address */
+ uint16_t StackSize; /* Stack segment size (bytes) */
+ SEGSEL_t BC_CodeSeg; /* BC Code segment address */
+ uint16_t BC_CodeSize; /* BC Code segment size (bytes) */
+ SEGSEL_t BC_DataSeg; /* BC Data segment address */
+ uint16_t BC_DataSize; /* BC Data segment size (bytes) */
+ SEGSEL_t UNDIDataSeg; /* UNDI Data segment address */
+ uint16_t UNDIDataSize; /* UNDI Data segment size (bytes) */
+ SEGSEL_t UNDICodeSeg; /* UNDI Code segment address */
+ uint16_t UNDICodeSize; /* UNDI Code segment size (bytes) */
+ SEGOFF16_t PXEPtr; /* SEG:OFF to !PXE struct,
+ only present when Version > 2.1 */
+} PACKED pxenv_t;
+
+/* !PXE */
+typedef struct {
+ uint8_t Signature[4];
+ uint8_t StructLength;
+ uint8_t StructCksum;
+ uint8_t StructRev;
+ uint8_t reserved_1;
+ SEGOFF16_t UNDIROMID;
+ SEGOFF16_t BaseROMID;
+ SEGOFF16_t EntryPointSP;
+ SEGOFF16_t EntryPointESP;
+ SEGOFF16_t StatusCallout;
+ uint8_t reserved_2;
+ uint8_t SegDescCn;
+ SEGSEL_t FirstSelector;
+ SEGDESC_t Stack;
+ SEGDESC_t UNDIData;
+ SEGDESC_t UNDICode;
+ SEGDESC_t UNDICodeWrite;
+ SEGDESC_t BC_Data;
+ SEGDESC_t BC_Code;
+ SEGDESC_t BC_CodeWrite;
+} PACKED pxe_t;
+
+#define PXENV_START_UNDI 0x0000
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t ax;
+ uint16_t bx;
+ uint16_t dx;
+ uint16_t di;
+ uint16_t es;
+} PACKED t_PXENV_START_UNDI;
+
+#define PXENV_UNDI_STARTUP 0x0001
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_UNDI_STARTUP;
+
+#define PXENV_UNDI_CLEANUP 0x0002
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_UNDI_CLEANUP;
+
+#define PXENV_UNDI_INITIALIZE 0x0003
+typedef struct {
+ PXENV_STATUS_t Status;
+ ADDR32_t ProtocolIni; /* Phys addr of a copy of the driver module */
+ uint8_t reserved[8];
+} PACKED t_PXENV_UNDI_INITIALIZE;
+
+
+#define MAXNUM_MCADDR 8
+typedef struct {
+ uint16_t MCastAddrCount;
+ MAC_ADDR McastAddr[MAXNUM_MCADDR];
+} PACKED t_PXENV_UNDI_MCAST_ADDRESS;
+
+#define PXENV_UNDI_RESET_ADAPTER 0x0004
+typedef struct {
+ PXENV_STATUS_t Status;
+ t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} PACKED t_PXENV_UNDI_RESET;
+
+#define PXENV_UNDI_SHUTDOWN 0x0005
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_UNDI_SHUTDOWN;
+
+#define PXENV_UNDI_OPEN 0x0006
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t OpenFlag;
+ uint16_t PktFilter;
+# define FLTR_DIRECTED 0x0001
+# define FLTR_BRDCST 0x0002
+# define FLTR_PRMSCS 0x0003
+# define FLTR_SRC_RTG 0x0004
+
+ t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} PACKED t_PXENV_UNDI_OPEN;
+
+#define PXENV_UNDI_CLOSE 0x0007
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_UNDI_CLOSE;
+
+#define PXENV_UNDI_TRANSMIT 0x0008
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t Protocol;
+# define P_UNKNOWN 0
+# define P_IP 1
+# define P_ARP 2
+# define P_RARP 3
+
+ uint8_t XmitFlag;
+# define XMT_DESTADDR 0x0000
+# define XMT_BROADCAST 0x0001
+
+ SEGOFF16_t DestAddr;
+ SEGOFF16_t TBD;
+ uint32_t Reserved[2];
+} PACKED t_PXENV_UNDI_TRANSMIT;
+
+#define MAX_DATA_BLKS 8
+typedef struct {
+ uint16_t ImmedLength;
+ SEGOFF16_t Xmit;
+ uint16_t DataBlkCount;
+ struct DataBlk {
+ uint8_t TDPtrType;
+ uint8_t TDRsvdByte;
+ uint16_t TDDataLen;
+ SEGOFF16_t TDDataPtr;
+ } DataBlock[MAX_DATA_BLKS];
+} PACKED t_PXENV_UNDI_TBD;
+
+#define PXENV_UNDI_SET_MCAST_ADDRESS 0x0009
+typedef struct {
+ PXENV_STATUS_t Status;
+ t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} PACKED t_PXENV_UNDI_SET_MCAST_ADDR;
+
+#define PXENV_UNDI_SET_STATION_ADDRESS 0x000A
+typedef struct {
+ PXENV_STATUS_t Status;
+ MAC_ADDR StationAddress; /* Temp MAC addres to use */
+} PACKED t_PXENV_UNDI_SET_STATION_ADDRESS;
+
+#define PXENV_UNDI_SET_PACKET_FILTER 0x000B
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t filter; /* see UNDI_OPEN (0x0006) */
+} PACKED t_PXENV_UNDI_SET_PACKET_FILTER;
+
+#define PXENV_UNDI_GET_INFORMATION 0x000C
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t BaseIo; /* Adapter base I/O address */
+ uint16_t IntNumber; /* Adapter IRQ number */
+ uint16_t MaxTranUnit; /* Adapter maximum transmit unit */
+ uint16_t HwType; /* Type of protocol at the hardware addr */
+# define ETHER_TYPE 1
+# define EXP_ETHER_TYPE 2
+# define IEEE_TYPE 6
+# define ARCNET_TYPE 7
+
+ uint16_t HwAddrLen; /* Length of hardware address */
+ MAC_ADDR CurrentNodeAddress; /* Current hardware address */
+ MAC_ADDR PermNodeAddress; /* Permanent hardware address */
+ SEGSEL_t ROMAddress; /* Real mode ROM segment address */
+ uint16_t RxBufCt; /* Receive queue length */
+ uint16_t TxBufCt; /* Transmit queue length */
+} PACKED t_PXENV_UNDI_GET_INFORMATION;
+
+#define PXENV_UNDI_GET_STATISTICS 0x000D
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint32_t XmitGoodFrames; /* Number of successful transmissions */
+ uint32_t RcvGoodFrames; /* Number of good frames received */
+ uint32_t RcvCRCErrors; /* Number of frames with CRC errors */
+ uint32_t RcvResourceErrors; /* Number of frames dropped */
+} PACKED t_PXENV_UNDI_GET_STATISTICS;
+
+#define PXENV_UNDI_CLEAR_STATISTICS 0x000E
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_UNDI_CLEAR_STATISTICS;
+
+#define PXENV_UNDI_INITIATE_DIAGS 0x000F
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_UNDI_INITIATE_DIAGS;
+
+#define PXENV_UNDI_FORCE_INTERRUPT 0x0010
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_UNDI_FORCE_INTERRUPT;
+
+#define PXENV_UNDI_GET_MCAST_ADDRESS 0x0011
+typedef struct {
+ PXENV_STATUS_t Status;
+ IP4_t InetAddr; /* IP mulicast address */
+ MAC_ADDR MediaAddr; /* MAC multicast address */
+} PACKED t_PXENV_UNDI_GET_MCAST_ADDR;
+
+#define PXENV_UNDI_GET_NIC_TYPE 0x0012
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t NicType; /* Type of NIC */
+# define PCI_NIC 2
+# define PnP_NIC 3
+# define CardBus_NIC 4
+
+ union {
+ struct {
+ uint16_t Vendor_ID;
+ uint16_t Dev_ID;
+ uint8_t Base_Class;
+ uint8_t Sub_Class;
+ uint8_t Prog_Intf;
+ uint8_t Rev;
+ uint16_t BusDevFunc;
+ uint16_t SubVendor_ID;
+ uint16_t SubDevice_ID;
+ } pci, cardbus;
+ struct {
+ uint32_t EISA_Dev_ID;
+ uint8_t Base_Class;
+ uint8_t Sub_Class;
+ uint8_t Prog_Intf;
+ uint16_t CardSelNum;
+ } pnp;
+ } info;
+} PACKED t_PXENV_UNDI_GET_NIC_TYPE;
+
+#define PXENV_UNDI_GET_IFACE_INFO 0x0013
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t IfaceType[16]; /* Name of MAC type in ASCII. */
+ uint32_t LinkSpeed; /* Defined in NDIS 2.0 spec */
+ uint32_t ServiceFlags; /* Defined in NDIS 2.0 spec */
+ uint32_t Reserved[4]; /* must be 0 */
+} PACKED t_PXENV_UNDI_GET_IFACE_INFO;
+
+#define PXENV_UNDI_ISR 0x0014
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t FuncFlag; /* PXENV_UNDI_ISR_OUT_xxx */
+ uint16_t BufferLength; /* Length of Frame */
+ uint16_t FrameLength; /* Total length of reciever frame */
+ uint16_t FrameHeaderLength; /* Length of the media header in Frame */
+ SEGOFF16_t Frame; /* receive buffer */
+ uint8_t ProtType; /* Protocol type */
+ uint8_t PktType; /* Packet Type */
+# define PXENV_UNDI_ISR_IN_START 1
+# define PXENV_UNDI_ISR_IN_PROCESS 2
+# define PXENV_UNDI_ISR_IN_GET_NEXT 3
+
+ /* one of these will be returned for PXENV_UNDI_ISR_IN_START */
+# define PXENV_UNDI_ISR_OUT_OURS 0
+# define PXENV_UNDI_ISR_OUT_NOT_OURS 1
+
+ /*
+ * one of these will bre returnd for PXEND_UNDI_ISR_IN_PROCESS
+ * and PXENV_UNDI_ISR_IN_GET_NEXT
+ */
+# define PXENV_UNDI_ISR_OUT_DONE 0
+# define PXENV_UNDI_ISR_OUT_TRANSMIT 2
+# define PXENV_UNDI_ISR_OUT_RECEIVE 3
+# define PXENV_UNDI_ISR_OUT_BUSY 4
+} PACKED t_PXENV_UNDI_ISR;
+
+#define PXENV_STOP_UNDI 0x0015
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_STOP_UNDI;
+
+#define PXENV_TFTP_OPEN 0x0020
+typedef struct {
+ PXENV_STATUS_t Status;
+ IP4_t ServerIPAddress;
+ IP4_t GatewayIPAddress;
+ uint8_t FileName[128];
+ UDP_PORT_t TFTPPort;
+ uint16_t PacketSize;
+} PACKED t_PXENV_TFTP_OPEN;
+
+#define PXENV_TFTP_CLOSE 0x0021
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_TFTP_CLOSE;
+
+#define PXENV_TFTP_READ 0x0022
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t PacketNumber;
+ uint16_t BufferSize;
+ SEGOFF16_t Buffer;
+} PACKED t_PXENV_TFTP_READ;
+
+#define PXENV_TFTP_READ_FILE 0x0023
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t FileName[128];
+ uint32_t BufferSize;
+ ADDR32_t Buffer;
+ IP4_t ServerIPAddress;
+ IP4_t GatewayIPAdress;
+ IP4_t McastIPAdress;
+ UDP_PORT_t TFTPClntPort;
+ UDP_PORT_t TFTPSrvPort;
+ uint16_t TFTPOpenTimeOut;
+ uint16_t TFTPReopenDelay;
+} PACKED t_PXENV_TFTP_READ_FILE;
+
+#define PXENV_TFTP_GET_FSIZE 0x0025
+typedef struct {
+ PXENV_STATUS_t Status;
+ IP4_t ServerIPAddress;
+ IP4_t GatewayIPAdress;
+ uint8_t FileName[128];
+ uint32_t FileSize;
+} PACKED t_PXENV_TFTP_GET_FSIZE;
+
+#define PXENV_UDP_OPEN 0x0030
+typedef struct {
+ PXENV_STATUS_t Status;
+ IP4_t src_ip; /* IP address of this station */
+} PACKED t_PXENV_UDP_OPEN;
+
+#define PXENV_UDP_CLOSE 0x0031
+typedef struct {
+ PXENV_STATUS_t status;
+} PACKED t_PXENV_UDP_CLOSE;
+
+#define PXENV_UDP_READ 0x0032
+typedef struct {
+ PXENV_STATUS_t status;
+ IP4_t src_ip; /* IP of sender */
+ IP4_t dest_ip; /* Only accept packets sent to this IP */
+ UDP_PORT_t s_port; /* UDP source port of sender */
+ UDP_PORT_t d_port; /* Only accept packets sent to this port */
+ uint16_t buffer_size; /* Size of the packet buffer */
+ SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */
+} PACKED t_PXENV_UDP_READ;
+
+#define PXENV_UDP_WRITE 0x0033
+typedef struct {
+ PXENV_STATUS_t status;
+ IP4_t ip; /* dest ip addr */
+ IP4_t gw; /* ip gateway */
+ UDP_PORT_t src_port; /* source udp port */
+ UDP_PORT_t dst_port; /* destination udp port */
+ uint16_t buffer_size; /* Size of the packet buffer */
+ SEGOFF16_t buffer; /* SEG:OFF to the packet buffer */
+} PACKED t_PXENV_UDP_WRITE;
+
+#define PXENV_UNLOAD_STACK 0x0070
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint8_t reserved[10];
+} PACKED t_PXENV_UNLOAD_STACK;
+
+
+#define PXENV_GET_CACHED_INFO 0x0071
+typedef struct {
+ PXENV_STATUS_t Status;
+ uint16_t PacketType; /* type (defined right here) */
+# define PXENV_PACKET_TYPE_DHCP_DISCOVER 1
+# define PXENV_PACKET_TYPE_DHCP_ACK 2
+# define PXENV_PACKET_TYPE_BINL_REPLY 3
+ uint16_t BufferSize; /* max to copy, leave at 0 for pointer */
+ SEGOFF16_t Buffer; /* copy to, leave at 0 for pointer */
+ uint16_t BufferLimit; /* max size of buffer in BC dataseg ? */
+} PACKED t_PXENV_GET_CACHED_INFO;
+
+
+/* structure filled in by PXENV_GET_CACHED_INFO
+ * (how we determine which IP we downloaded the initial bootstrap from)
+ * words can't describe...
+ */
+typedef struct {
+ uint8_t opcode;
+# define BOOTP_REQ 1
+# define BOOTP_REP 2
+ uint8_t Hardware; /* hardware type */
+ uint8_t Hardlen; /* hardware addr len */
+ uint8_t Gatehops; /* zero it */
+ uint32_t ident; /* random number chosen by client */
+ uint16_t seconds; /* seconds since did initial bootstrap */
+ uint16_t Flags; /* seconds since did initial bootstrap */
+# define BOOTP_BCAST 0x8000 /* ? */
+ IP4_t cip; /* Client IP */
+ IP4_t yip; /* Your IP */
+ IP4_t sip; /* IP to use for next boot stage */
+ IP4_t gip; /* Relay IP ? */
+ MAC_ADDR CAddr; /* Client hardware address */
+ uint8_t Sname[64]; /* Server's hostname (Optional) */
+ uint8_t bootfile[128]; /* boot filename */
+ union {
+# if 1
+# define BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size */
+# else
+# define BOOTP_DHCPVEND 312 /* DHCP standard vendor field size */
+# endif
+ uint8_t d[BOOTP_DHCPVEND]; /* raw array of vendor/dhcp options */
+ struct {
+ uint8_t magic[4]; /* DHCP magic cookie */
+# ifndef VM_RFC1048
+# define VM_RFC1048 0x63825363L /* ? */
+# endif
+ uint32_t flags; /* bootp flags/opcodes */
+ uint8_t pad[56]; /* I don't think intel knows what a
+ union does... */
+ } v;
+ } vendor;
+} PACKED BOOTPLAYER;
+
+#define PXENV_RESTART_TFTP 0x0073
+#define t_PXENV_RESTART_TFTP t_PXENV_TFTP_READ_FILE
+
+#define PXENV_START_BASE 0x0075
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_START_BASE;
+
+#define PXENV_STOP_BASE 0x0076
+typedef struct {
+ PXENV_STATUS_t Status;
+} PACKED t_PXENV_STOP_BASE;
diff -urN release_2/netboot/segoff.h release_2_undi/netboot/segoff.h
--- release_2/netboot/segoff.h 1970-01-01 08:00:00.000000000 +0800
+++ release_2_undi/netboot/segoff.h 2004-03-17 22:29:24.000000000 +0800
@@ -0,0 +1,43 @@
+/*
+ * Segment:offset types and macros
+ *
+ * Initially written by Michael Brown (mcb30).
+ */
+
+#ifndef SEGOFF_H
+#define SEGOFF_H
+
+#include <stdint.h>
+#include <io.h>
+
+/* Segment:offset structure. Note that the order within the structure
+ * is offset:segment.
+ */
+typedef struct {
+ uint16_t offset;
+ uint16_t segment;
+} segoff_t;
+
+/* For PXE stuff */
+typedef segoff_t SEGOFF16_t;
+
+/* Macros for converting from virtual to segment:offset addresses,
+ * when we don't actually care which of the many isomorphic results we
+ * get.
+ */
+#ifdef DEBUG_SEGMENT
+uint16_t SEGMENT ( const void * const ptr ) {
+ uint32_t phys = virt_to_phys ( ptr );
+ if ( phys > 0xfffff ) {
+ printf ( "FATAL ERROR: segment address out of range\n" );
+ }
+ return phys >> 4;
+}
+#else
+#define SEGMENT(x) ( virt_to_phys ( x ) >> 4 )
+#endif
+#define OFFSET(x) ( virt_to_phys ( x ) & 0xf )
+#define SEGOFF(x) { OFFSET(x), SEGMENT(x) }
+#define VIRTUAL(x,y) ( phys_to_virt ( ( ( x ) << 4 ) + ( y ) ) )
+
+#endif /* SEGOFF_H */
diff -urN release_2/netboot/undi.c release_2_undi/netboot/undi.c
--- release_2/netboot/undi.c 1970-01-01 08:00:00.000000000 +0800
+++ release_2_undi/netboot/undi.c 2004-06-17 20:48:08.000000000 +0800
@@ -0,0 +1,1177 @@
+/**************************************************************************
+Etherboot - BOOTP/TFTP Bootstrap Program
+UNDI NIC driver for Etherboot
+
+This file Copyright (C) 2003 Michael Brown <mbrown@fensystems.co.uk>
+of Fen Systems Ltd. (http://www.fensystems.co.uk/). All rights
+reserved.
+
+$Id: undi.c,v 1.8 2003/10/25 13:54:53 mcb30 Exp $
+***************************************************************************/
+
+/*
+ * 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, or (at
+ * your option) any later version.
+ */
+
+/* to get some global routines like printf */
+#include "etherboot.h"
+/* to get the interface to the body of the program */
+#include "nic.h"
+/* to get the PCI support functions, if this is a PCI NIC */
+#include "pci.h"
+/* UNDI and PXE defines. Includes pxe.h. */
+#include "undi.h"
+/* 8259 PIC defines */
+#include "pic8259.h"
+
+/* NIC specific static variables go here */
+static undi_t undi = { NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, 0, NULL, 0, NULL,
+ 0, 0, 0, 0,
+ { 0, 0, 0, NULL, 0, 0, 0, 0, 0, NULL },
+ IRQ_NONE };
+static undi_base_mem_data_t undi_base_mem_data;
+
+#define UNDI_HEAP (void *)(512 << 10)
+
+/* Function prototypes */
+int allocate_base_mem_data ( void );
+int free_base_mem_data ( void );
+int eb_pxenv_undi_shutdown ( void );
+int eb_pxenv_stop_undi ( void );
+int undi_unload_base_code ( void );
+int undi_full_shutdown ( void );
+
+/**************************************************************************
+ * Utility functions
+ **************************************************************************/
+
+/* Checksum a block.
+ */
+
+uint8_t checksum ( void *block, size_t size ) {
+ uint8_t sum = 0;
+ uint16_t i = 0;
+ for ( i = 0; i < size; i++ ) {
+ sum += ( ( uint8_t * ) block )[i];
+ }
+ return sum;
+}
+
+/* Print the status of a !PXE structure
+ */
+
+void pxe_dump ( void ) {
+ printf ( "API %hx:%hx St %hx:%hx UD %hx:%hx UC %hx:%hx "
+ "BD %hx:%hx BC %hx:%hx\n",
+ undi.pxe->EntryPointSP.segment, undi.pxe->EntryPointSP.offset,
+ undi.pxe->Stack.Seg_Addr, undi.pxe->Stack.Seg_Size,
+ undi.pxe->UNDIData.Seg_Addr, undi.pxe->UNDIData.Seg_Size,
+ undi.pxe->UNDICode.Seg_Addr, undi.pxe->UNDICode.Seg_Size,
+ undi.pxe->BC_Data.Seg_Addr, undi.pxe->BC_Data.Seg_Size,
+ undi.pxe->BC_Code.Seg_Addr, undi.pxe->BC_Code.Seg_Size );
+}
+
+/* Allocate/free space for structures that must reside in base memory
+ */
+
+int allocate_base_mem_data ( void ) {
+ /* In GRUB, anything is in base address, so we do not need
+ * allocate anything */
+ undi.base_mem_data = &undi_base_mem_data;
+ memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) );
+ undi.undi_call_info = &undi.base_mem_data->undi_call_info;
+ undi.pxs = &undi.base_mem_data->pxs;
+ undi.xmit_data = &undi.base_mem_data->xmit_data;
+ undi.xmit_buffer = undi.base_mem_data->xmit_buffer;
+#if 0 /* Etherboot Code */
+ /* Allocate space in base memory.
+ * Initialise pointers to base memory structures.
+ */
+ if ( undi.base_mem_data == NULL ) {
+ undi.base_mem_data =
+ allot_base_memory ( sizeof(undi_base_mem_data_t) +
+ TRIVIAL_IRQ_HANDLER_SIZE );
+ if ( undi.base_mem_data == NULL ) {
+ printf ( "Failed to allocate base memory\n" );
+ free_base_mem_data();
+ return 0;
+ }
+ memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) );
+ undi.undi_call_info = &undi.base_mem_data->undi_call_info;
+ undi.pxs = &undi.base_mem_data->pxs;
+ undi.xmit_data = &undi.base_mem_data->xmit_data;
+ undi.xmit_buffer = undi.base_mem_data->xmit_buffer;
+ copy_trivial_irq_handler ( undi.base_mem_data->irq_handler,
+ TRIVIAL_IRQ_HANDLER_SIZE );
+ }
+#endif /* Etherboot Code */
+ return 1;
+}
+
+int free_base_mem_data ( void ) {
+ /* Just pretend to free something :-) */
+ undi.base_mem_data = NULL;
+ undi.undi_call_info = NULL;
+ undi.pxs = NULL;
+ undi.xmit_data = NULL;
+ undi.xmit_buffer = NULL;
+#if 0 /* Etherboot Code */
+ if ( undi.base_mem_data != NULL ) {
+ forget_base_memory ( undi.base_mem_data,
+ sizeof(undi_base_mem_data_t) +
+ TRIVIAL_IRQ_HANDLER_SIZE );
+ undi.base_mem_data = NULL;
+ undi.undi_call_info = NULL;
+ undi.pxs = NULL;
+ undi.xmit_data = NULL;
+ undi.xmit_buffer = NULL;
+ copy_trivial_irq_handler ( NULL, 0 );
+ }
+#endif /* Etherboot Code */
+ return 1;
+}
+
+void assemble_firing_squad ( firing_squad_lineup_t *lineup,
+ void *start, size_t size,
+ firing_squad_shoot_t shoot ) {
+ int target;
+ int index;
+ int bit;
+ int start_kb = virt_to_phys(start) >> 10;
+ int end_kb = ( virt_to_phys(start+size) + (1<<10) - 1 ) >> 10;
+
+ for ( target = start_kb; target <= end_kb; target++ ) {
+ index = FIRING_SQUAD_TARGET_INDEX ( target );
+ bit = FIRING_SQUAD_TARGET_BIT ( target );
+ lineup->targets[index] = ( shoot << bit ) |
+ ( lineup->targets[index] & ~( 1 << bit ) );
+ }
+}
+
+void shoot_targets ( firing_squad_lineup_t *lineup ) {
+ int shoot_this_target = 0;
+ int shoot_last_target = 0;
+ int start_target = 0;
+ int target;
+
+ for ( target = 0; target <= 640; target++ ) {
+ shoot_this_target = ( target == 640 ? 0 :
+ ( 1 << FIRING_SQUAD_TARGET_BIT(target) ) &
+ lineup->targets[FIRING_SQUAD_TARGET_INDEX(target)] );
+ if ( shoot_this_target && !shoot_last_target ) {
+ start_target = target;
+ } else if ( shoot_last_target && !shoot_this_target ) {
+ size_t range_size = ( target - start_target ) << 10;
+ forget_base_memory ( phys_to_virt( start_target<<10 ),
+ range_size );
+ }
+ shoot_last_target = shoot_this_target;
+ }
+}
+
+/* Debug macros
+ */
+
+#ifdef TRACE_UNDI
+#define DBG(...) printf ( __VA_ARGS__ )
+#else
+#define DBG(...)
+#endif
+
+#define UNDI_STATUS(pxs) ( (pxs)->Status == PXENV_EXIT_SUCCESS ? \
+ "SUCCESS" : \
+ ( (pxs)->Status == PXENV_EXIT_FAILURE ? \
+ "FAILURE" : "UNKNOWN" ) )
+
+/**************************************************************************
+ * Base memory scanning functions
+ **************************************************************************/
+
+/* Locate the $PnP structure indicating a PnP BIOS.
+ */
+
+int hunt_pnp_bios ( void ) {
+ uint32_t off = 0x10000;
+
+ printf ( "Hunting for PnP BIOS..." );
+ while ( off > 0 ) {
+ off -= 16;
+ undi.pnp_bios = (pnp_bios_t *) phys_to_virt ( 0xf0000 + off );
+ if ( undi.pnp_bios->signature == PNP_BIOS_SIGNATURE ) {
+ printf ( "found $PnP at f000:%hx...", off );
+ if ( checksum(undi.pnp_bios,sizeof(pnp_bios_t)) !=0) {
+ printf ( "invalid checksum\n..." );
+ continue;
+ }
+ printf ( "ok\n" );
+ return 1;
+ }
+ }
+ printf ( "none found\n" );
+ undi.pnp_bios = NULL;
+ return 0;
+}
+
+/* Locate the !PXE structure indicating a loaded UNDI driver.
+ */
+
+int hunt_pixie ( void ) {
+ static uint32_t ptr = 0;
+ pxe_t *pxe = NULL;
+
+ printf ( "Hunting for pixies..." );
+ if ( ptr == 0 ) ptr = 0xa0000;
+ while ( ptr > 0x10000 ) {
+ ptr -= 16;
+ pxe = (pxe_t *) phys_to_virt ( ptr );
+ if ( memcmp ( pxe->Signature, "!PXE", 4 ) == 0 ) {
+ printf ( "found !PXE at %x...", ptr );
+ if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) {
+ printf ( "invalid checksum\n..." );
+ continue;
+ }
+ if ( ptr < get_free_base_memory() ) {
+ printf ( "in free base memory!\n\n"
+ "WARNING: a valid !PXE structure was "
+ "found in an area of memory marked "
+ "as free!\n\n" );
+ undi.pxe = pxe;
+ pxe_dump();
+ undi.pxe = NULL;
+ printf ( "\nIgnoring and continuing, but this "
+ "may cause problems later!\n\n" );
+ continue;
+ }
+ printf ( "ok\n" );
+ undi.pxe = pxe;
+ pxe_dump();
+ printf ( "Resetting pixie...\n" );
+ undi_unload_base_code();
+ eb_pxenv_stop_undi();
+ pxe_dump();
+ return 1;
+ }
+ }
+ printf ( "none found\n" );
+ ptr = 0;
+ return 0;
+}
+
+/* Locate PCI PnP ROMs.
+ */
+
+int hunt_rom ( void ) {
+ static uint32_t ptr = 0;
+
+ printf ( "Hunting for ROMs..." );
+ if ( ptr == 0 ) ptr = 0x100000;
+ while ( ptr > 0x0c0000 ) {
+ ptr -= 0x800;
+ undi.rom = ( rom_t * ) phys_to_virt ( ptr );
+ if ( undi.rom->signature == ROM_SIGNATURE ) {
+ pcir_header_t *pcir_header = NULL;
+ pnp_header_t *pnp_header = NULL;
+
+ printf ( "found 55AA at %x...", ptr );
+ if ( undi.rom->pcir_off == 0 ) {
+ printf ( "not a PCI ROM\n..." );
+ continue;
+ }
+ pcir_header = (pcir_header_t*)( ( void * ) undi.rom +
+ undi.rom->pcir_off );
+ if ( pcir_header->signature != PCIR_SIGNATURE ) {
+ printf ( "invalid PCI signature\n..." );
+ continue;
+ }
+ printf ( "PCI:%hx:%hx...", pcir_header->vendor_id,
+ pcir_header->device_id );
+ if ( ( pcir_header->vendor_id != undi.pci.vendor ) ||
+ ( pcir_header->device_id != undi.pci.dev_id ) ) {
+ printf ( "not me (%hx:%hx)\n...",
+ undi.pci.vendor,
+ undi.pci.dev_id );
+ continue;
+ }
+ if ( undi.rom->pnp_off == 0 ) {
+ printf ( "not a PnP ROM\n..." );
+ continue;
+ }
+ pnp_header = (pnp_header_t*)( ( void * ) undi.rom +
+ undi.rom->pnp_off );
+ if ( pnp_header->signature != PNP_SIGNATURE ) {
+ printf ( "invalid $PnP signature\n..." );
+ continue;
+ }
+ if ( checksum(pnp_header,sizeof(pnp_header_t)) != 0 ) {
+ printf ( "invalid PnP checksum\n..." );
+ continue;
+ }
+ printf ( "ok\nROM contains %s by %s\n",
+ pnp_header->product_str_off==0 ? "(unknown)" :
+ (void*)undi.rom+pnp_header->product_str_off,
+ pnp_header->manuf_str_off==0 ? "(unknown)" :
+ (void*)undi.rom+pnp_header->manuf_str_off );
+ return 1;
+ }
+ }
+ printf ( "none found\n" );
+ ptr = 0;
+ undi.rom = NULL;
+ return 0;
+}
+
+/* Locate ROMs containing UNDI drivers.
+ */
+
+int hunt_undi_rom ( void ) {
+ while ( hunt_rom() ) {
+ if ( undi.rom->undi_rom_id_off == 0 ) {
+ printf ( "Not a PXE ROM\n" );
+ continue;
+ }
+ undi.undi_rom_id = (undi_rom_id_t *)
+ ( (void *)undi.rom + undi.rom->undi_rom_id_off );
+ if ( undi.undi_rom_id->signature != UNDI_SIGNATURE ) {
+ printf ( "Invalid UNDI signature\n" );
+ continue;
+ }
+ printf ( "Located UNDI ROM supporting revision %d.%d.%d\n",
+ undi.undi_rom_id->undi_rev[2],
+ undi.undi_rom_id->undi_rev[1],
+ undi.undi_rom_id->undi_rev[0] );
+ return 1;
+ }
+ return 0;
+}
+
+/**************************************************************************
+ * Low-level UNDI API call wrappers
+ **************************************************************************/
+
+/* Make a real-mode UNDI API call to the UNDI routine at
+ * routine_seg:routine_off, passing in three uint16 parameters on the
+ * real-mode stack.
+ * Calls the assembler wrapper routine __undi_call.
+ */
+
+static inline PXENV_EXIT_t _undi_call ( uint16_t routine_seg,
+ uint16_t routine_off, uint16_t st0,
+ uint16_t st1, uint16_t st2 ) {
+ PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
+
+ undi.undi_call_info->routine.segment = routine_seg;
+ undi.undi_call_info->routine.offset = routine_off;
+ undi.undi_call_info->stack[0] = st0;
+ undi.undi_call_info->stack[1] = st1;
+ undi.undi_call_info->stack[2] = st2;
+ ret = __undi_call ( SEGMENT( undi.undi_call_info ),
+ OFFSET( undi.undi_call_info ) );
+
+ /* UNDI API calls may rudely change the status of A20 and not
+ * bother to restore it afterwards. Intel is known to be
+ * guilty of this.
+ *
+ * Note that we will return to this point even if A20 gets
+ * screwed up by the UNDI driver, because Etherboot always
+ * resides in an even megabyte of RAM.
+ */
+ gateA20_set();
+
+ return ret;
+}
+
+/* Make a real-mode call to the UNDI loader routine at
+ * routine_seg:routine_off, passing in the seg:off address of a
+ * pxenv_structure on the real-mode stack.
+ */
+
+int undi_call_loader ( void ) {
+ PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE;
+
+ pxenv_exit = _undi_call ( SEGMENT( undi.rom ),
+ undi.undi_rom_id->undi_loader_off,
+ OFFSET( undi.pxs ),
+ SEGMENT( undi.pxs ),
+ 0 /* Unused for UNDI loader API */ );
+ /* Return 1 for success, to be consistent with other routines */
+ if ( pxenv_exit == PXENV_EXIT_SUCCESS ) return 1;
+ printf ( "UNDI loader call failed with status %#hx\n",
+ undi.pxs->Status );
+ return 0;
+}
+
+/* Make a real-mode UNDI API call, passing in the opcode and the
+ * seg:off address of a pxenv_structure on the real-mode stack.
+ *
+ * Two versions: undi_call() will automatically report any failure
+ * codes, undi_call_silent() will not.
+ */
+
+int undi_call_silent ( uint16_t opcode ) {
+ PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE;
+
+ pxenv_exit = _undi_call ( undi.pxe->EntryPointSP.segment,
+ undi.pxe->EntryPointSP.offset,
+ opcode,
+ OFFSET( undi.pxs ),
+ SEGMENT( undi.pxs ) );
+ /* Return 1 for success, to be consistent with other routines */
+ return pxenv_exit == PXENV_EXIT_SUCCESS ? 1 : 0;
+}
+
+int undi_call ( uint16_t opcode ) {
+ if ( undi_call_silent ( opcode ) ) return 1;
+ printf ( "UNDI API call %#hx failed with status %#hx\n",
+ opcode, undi.pxs->Status );
+ return 0;
+}
+
+/**************************************************************************
+ * High-level UNDI API call wrappers
+ **************************************************************************/
+
+/* Install the UNDI driver from a located UNDI ROM.
+ */
+
+int undi_loader ( void ) {
+ pxe_t *pxe = NULL;
+
+ /* AX contains PCI bus:devfn (PCI specification) */
+ undi.pxs->loader.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn;
+ /* BX and DX set to 0xffff for non-ISAPnP devices
+ * (BIOS boot specification)
+ */
+ undi.pxs->loader.bx = 0xffff;
+ undi.pxs->loader.dx = 0xffff;
+ /* ES:DI points to PnP BIOS' $PnP structure
+ * (BIOS boot specification)
+ */
+ undi.pxs->loader.es = 0xf000;
+ undi.pxs->loader.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000;
+
+ /* Allocate space for UNDI driver's code and data segments */
+ undi.driver_code_size = undi.undi_rom_id->code_size;
+ undi.driver_code = UNDI_HEAP;
+ if ( undi.driver_code == NULL ) {
+ printf ( "Could not allocate %d bytes for UNDI code segment\n",
+ undi.driver_code_size );
+ return 0;
+ }
+ undi.pxs->loader.undi_cs = SEGMENT( undi.driver_code );
+
+ undi.driver_data_size = undi.undi_rom_id->data_size;
+ undi.driver_data = (void *)((((unsigned long)UNDI_HEAP + undi.undi_rom_id->code_size) | (1024 -1)) + 1);
+ if ( undi.driver_data == NULL ) {
+ printf ( "Could not allocate %d bytes for UNDI code segment\n",
+ undi.driver_data_size );
+ return 0;
+ }
+ undi.pxs->loader.undi_ds = SEGMENT( undi.driver_data );
+
+ printf ( "Installing UNDI driver code to %hx:0000, data at %hx:0000\n",
+ undi.pxs->loader.undi_cs, undi.pxs->loader.undi_ds );
+
+ /* Do the API call to install the loader */
+ if ( ! undi_call_loader () ) return 0;
+
+ pxe = VIRTUAL( undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off );
+ printf ( "UNDI driver created a pixie at %hx:%hx...",
+ undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_off );
+ if ( memcmp ( pxe->Signature, "!PXE", 4 ) != 0 ) {
+ printf ( "invalid signature\n" );
+ return 0;
+ }
+ if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) {
+ printf ( "invalid checksum\n" );
+ return 0;
+ }
+ printf ( "ok\n" );
+ undi.pxe = pxe;
+ pxe_dump();
+ return 1;
+}
+
+/* Start the UNDI driver.
+ */
+
+int eb_pxenv_start_undi ( void ) {
+ int success = 0;
+
+ /* AX contains PCI bus:devfn (PCI specification) */
+ undi.pxs->start_undi.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn;
+ /* BX and DX set to 0xffff for non-ISAPnP devices
+ * (BIOS boot specification)
+ */
+ undi.pxs->start_undi.bx = 0xffff;
+ undi.pxs->start_undi.dx = 0xffff;
+ /* ES:DI points to PnP BIOS' $PnP structure
+ * (BIOS boot specification)
+ */
+ undi.pxs->start_undi.es = 0xf000;
+ undi.pxs->start_undi.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000;
+
+ DBG ( "PXENV_START_UNDI => AX=%hx BX=%hx DX=%hx ES:DI=%hx:%hx\n",
+ undi.pxs->start_undi.ax,
+ undi.pxs->start_undi.bx, undi.pxs->start_undi.dx,
+ undi.pxs->start_undi.es, undi.pxs->start_undi.di );
+ success = undi_call ( PXENV_START_UNDI );
+ DBG ( "PXENV_START_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) );
+ if ( success ) undi.prestarted = 1;
+ return success;
+}
+
+int eb_pxenv_undi_startup ( void ) {
+ int success = 0;
+
+ DBG ( "PXENV_UNDI_STARTUP => (void)\n" );
+ success = undi_call ( PXENV_UNDI_STARTUP );
+ DBG ( "PXENV_UNDI_STARTUP <= Status=%s\n", UNDI_STATUS(undi.pxs) );
+ if ( success ) undi.started = 1;
+ return success;
+}
+
+int eb_pxenv_undi_cleanup ( void ) {
+ int success = 0;
+
+ DBG ( "PXENV_UNDI_CLEANUP => (void)\n" );
+ success = undi_call ( PXENV_UNDI_CLEANUP );
+ DBG ( "PXENV_UNDI_CLEANUP <= Status=%s\n", UNDI_STATUS(undi.pxs) );
+ return success;
+}
+
+int eb_pxenv_undi_initialize ( void ) {
+ int success = 0;
+
+ undi.pxs->undi_initialize.ProtocolIni = 0;
+ memset ( &undi.pxs->undi_initialize.reserved, 0,
+ sizeof ( undi.pxs->undi_initialize.reserved ) );
+ DBG ( "PXENV_UNDI_INITIALIZE => ProtocolIni=%x\n" );
+ success = undi_call ( PXENV_UNDI_INITIALIZE );
+ DBG ( "PXENV_UNDI_INITIALIZE <= Status=%s\n", UNDI_STATUS(undi.pxs) );
+ if ( success ) undi.initialized = 1;
+ return success;
+}
+
+int eb_pxenv_undi_shutdown ( void ) {
+ int success = 0;
+
+ DBG ( "PXENV_UNDI_SHUTDOWN => (void)\n" );
+ success = undi_call ( PXENV_UNDI_SHUTDOWN );
+ DBG ( "PXENV_UNDI_SHUTDOWN <= Status=%s\n", UNDI_STATUS(undi.pxs) );
+ if ( success ) {
+ undi.initialized = 0;
+ undi.started = 0;
+ }
+ return success;
+}
+
+int eb_pxenv_undi_open ( void ) {
+ int success = 0;
+
+ undi.pxs->undi_open.OpenFlag = 0;
+ undi.pxs->undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST;
+
+ /* Multicast support not yet implemented */
+ undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount = 0;
+ DBG ( "PXENV_UNDI_OPEN => OpenFlag=%hx PktFilter=%hx "
+ "MCastAddrCount=%hx\n",
+ undi.pxs->undi_open.OpenFlag, undi.pxs->undi_open.PktFilter,
+ undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount );
+ success = undi_call ( PXENV_UNDI_OPEN );
+ DBG ( "PXENV_UNDI_OPEN <= Status=%s\n", UNDI_STATUS(undi.pxs) );
+ if ( success ) undi.opened = 1;
+ return success;
+}
+
+int eb_pxenv_undi_close ( void ) {
+ int success = 0;
+
+ DBG ( "PXENV_UNDI_CLOSE => (void)\n" );
+ success = undi_call ( PXENV_UNDI_CLOSE );
+ DBG ( "PXENV_UNDI_CLOSE <= Status=%s\n", UNDI_STATUS(undi.pxs) );
+ if ( success ) undi.opened = 0;
+ return success;
+}
+
+int eb_pxenv_undi_transmit_packet ( void ) {
+ int success = 0;
+ static const uint8_t broadcast[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
+
+ /* XMitFlag selects unicast / broadcast */
+ if ( memcmp ( undi.xmit_data->destaddr, broadcast,
+ sizeof(broadcast) ) == 0 ) {
+ undi.pxs->undi_transmit.XmitFlag = XMT_BROADCAST;
+ } else {
+ undi.pxs->undi_transmit.XmitFlag = XMT_DESTADDR;
+ }
+
+ /* Zero reserved dwords */
+ undi.pxs->undi_transmit.Reserved[0] = 0;
+ undi.pxs->undi_transmit.Reserved[1] = 0;
+
+ /* Segment:offset pointer to DestAddr in base memory */
+ undi.pxs->undi_transmit.DestAddr.segment =
+ SEGMENT( undi.xmit_data->destaddr );
+ undi.pxs->undi_transmit.DestAddr.offset =
+ OFFSET( undi.xmit_data->destaddr );
+
+ /* Segment:offset pointer to TBD in base memory */
+ undi.pxs->undi_transmit.TBD.segment = SEGMENT( &undi.xmit_data->tbd );
+ undi.pxs->undi_transmit.TBD.offset = OFFSET( &undi.xmit_data->tbd );
+
+ /* Use only the "immediate" part of the TBD */
+ undi.xmit_data->tbd.DataBlkCount = 0;
+
+ DBG ( "PXENV_UNDI_TRANSMIT_PACKET => Protocol=%hx XmitFlag=%hx ...\n"
+ "... DestAddr=%hx:%hx TBD=%hx:%hx ...\n",
+ undi.pxs->undi_transmit.Protocol,
+ undi.pxs->undi_transmit.XmitFlag,
+ undi.pxs->undi_transmit.DestAddr.segment,
+ undi.pxs->undi_transmit.DestAddr.offset,
+ undi.pxs->undi_transmit.TBD.segment,
+ undi.pxs->undi_transmit.TBD.offset );
+ DBG ( "... TBD { ImmedLength=%hx Xmit=%hx:%hx DataBlkCount=%hx }\n",
+ undi.xmit_data->tbd.ImmedLength,
+ undi.xmit_data->tbd.Xmit.segment,
+ undi.xmit_data->tbd.Xmit.offset,
+ undi.xmit_data->tbd.DataBlkCount );
+ success = undi_call ( PXENV_UNDI_TRANSMIT );
+ DBG ( "PXENV_UNDI_TRANSMIT_PACKET <= Status=%s\n",
+ UNDI_STATUS(undi.pxs) );
+ return success;
+}
+
+int eb_pxenv_undi_set_station_address ( void ) {
+ /* This will spuriously fail on some cards. Ignore failures.
+ * We only ever use it to set the MAC address to the card's
+ * permanent value anyway, so it's a useless call (although we
+ * make it because PXE spec says we should).
+ */
+ DBG ( "PXENV_UNDI_SET_STATION_ADDRESS => "
+ "StationAddress=%!\n",
+ undi.pxs->undi_set_station_address.StationAddress );
+ undi_call_silent ( PXENV_UNDI_SET_STATION_ADDRESS );
+ DBG ( "PXENV_UNDI_SET_STATION_ADDRESS <= Status=%s\n",
+ UNDI_STATUS(undi.pxs) );
+ return 1;
+}
+
+int eb_pxenv_undi_get_information ( void ) {
+ int success = 0;
+ memset ( undi.pxs, 0, sizeof ( undi.pxs ) );
+ DBG ( "PXENV_UNDI_GET_INFORMATION => (void)\n" );
+ success = undi_call ( PXENV_UNDI_GET_INFORMATION );
+ DBG ( "PXENV_UNDI_GET_INFORMATION <= Status=%s "
+ "BaseIO=%hx IntNumber=%hx ...\n"
+ "... MaxTranUnit=%hx HwType=%hx HwAddrlen=%hx ...\n"
+ "... CurrentNodeAddress=%! PermNodeAddress=%! ...\n"
+ "... ROMAddress=%hx RxBufCt=%hx TxBufCt=%hx\n",
+ UNDI_STATUS(undi.pxs),
+ undi.pxs->undi_get_information.BaseIo,
+ undi.pxs->undi_get_information.IntNumber,
+ undi.pxs->undi_get_information.MaxTranUnit,
+ undi.pxs->undi_get_information.HwType,
+ undi.pxs->undi_get_information.HwAddrLen,
+ undi.pxs->undi_get_information.CurrentNodeAddress,
+ undi.pxs->undi_get_information.PermNodeAddress,
+ undi.pxs->undi_get_information.ROMAddress,
+ undi.pxs->undi_get_information.RxBufCt,
+ undi.pxs->undi_get_information.TxBufCt );
+ return success;
+}
+
+int eb_pxenv_undi_get_iface_info ( void ) {
+ int success = 0;
+
+ DBG ( "PXENV_UNDI_GET_IFACE_INFO => (void)\n" );
+ success = undi_call ( PXENV_UNDI_GET_IFACE_INFO );
+ DBG ( "PXENV_UNDI_GET_IFACE_INFO <= Status=%s IfaceType=%s ...\n"
+ "... LinkSpeed=%x ServiceFlags=%x\n",
+ UNDI_STATUS(undi.pxs),
+ undi.pxs->undi_get_iface_info.IfaceType,
+ undi.pxs->undi_get_iface_info.LinkSpeed,
+ undi.pxs->undi_get_iface_info.ServiceFlags );
+ return success;
+}
+
+int eb_pxenv_undi_isr ( void ) {
+ int success = 0;
+
+ DBG ( "PXENV_UNDI_ISR => FuncFlag=%hx\n",
+ undi.pxs->undi_isr.FuncFlag );
+ success = undi_call ( PXENV_UNDI_ISR );
+ DBG ( "PXENV_UNDI_ISR <= Status=%s FuncFlag=%hx BufferLength=%hx ...\n"
+ "... FrameLength=%hx FrameHeaderLength=%hx Frame=%hx:%hx "
+ "ProtType=%hhx ...\n... PktType=%hhx\n",
+ UNDI_STATUS(undi.pxs), undi.pxs->undi_isr.FuncFlag,
+ undi.pxs->undi_isr.BufferLength,
+ undi.pxs->undi_isr.FrameLength,
+ undi.pxs->undi_isr.FrameHeaderLength,
+ undi.pxs->undi_isr.Frame.segment,
+ undi.pxs->undi_isr.Frame.offset,
+ undi.pxs->undi_isr.ProtType,
+ undi.pxs->undi_isr.PktType );
+ return success;
+}
+
+int eb_pxenv_stop_undi ( void ) {
+ int success = 0;
+
+ DBG ( "PXENV_STOP_UNDI => (void)\n" );
+ success = undi_call ( PXENV_STOP_UNDI );
+ DBG ( "PXENV_STOP_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) );
+ if ( success ) undi.prestarted = 0;
+ return success;
+}
+
+int eb_pxenv_unload_stack ( void ) {
+ int success = 0;
+
+ memset ( undi.pxs, 0, sizeof ( undi.pxs ) );
+ DBG ( "PXENV_UNLOAD_STACK => (void)\n" );
+ success = undi_call_silent ( PXENV_UNLOAD_STACK );
+ DBG ( "PXENV_UNLOAD_STACK <= Status=%s ...\n... (%s)\n",
+ UNDI_STATUS(undi.pxs),
+ ( undi.pxs->Status == PXENV_STATUS_SUCCESS ?
+ "base-code is ready to be removed" :
+ ( undi.pxs->Status == PXENV_STATUS_FAILURE ?
+ "the size of free base memory has been changed" :
+ ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ?
+ "the NIC interrupt vector has been changed" :
+ "UNEXPECTED STATUS CODE" ) ) ) );
+ return success;
+}
+
+int eb_pxenv_stop_base ( void ) {
+ int success = 0;
+
+ DBG ( "PXENV_STOP_BASE => (void)\n" );
+ success = undi_call ( PXENV_STOP_BASE );
+ DBG ( "PXENV_STOP_BASE <= Status=%s\n", UNDI_STATUS(undi.pxs) );
+ return success;
+}
+
+/* Unload UNDI base code (if any present) and free memory.
+ */
+int undi_unload_base_code ( void ) {
+ /* In GRUB, we do not allocate anything, but we still can call
+ * to free the base space */
+ void *bc_code = VIRTUAL( undi.pxe->BC_Code.Seg_Addr, 0 );
+ size_t bc_code_size = undi.pxe->BC_Code.Seg_Size;
+ void *bc_data = VIRTUAL( undi.pxe->BC_Data.Seg_Addr, 0 );
+ size_t bc_data_size = undi.pxe->BC_Data.Seg_Size;
+ void *bc_stck = VIRTUAL( undi.pxe->Stack.Seg_Addr, 0 );
+ size_t bc_stck_size = undi.pxe->Stack.Seg_Size;
+ firing_squad_lineup_t lineup;
+
+ /* Don't unload if there is no base code present */
+ if ( undi.pxe->BC_Code.Seg_Addr == 0 ) return 1;
+
+ /* Since we never start the base code, the only time we should
+ * reach this is if we were loaded via PXE. There are many
+ * different and conflicting versions of the "correct" way to
+ * unload the PXE base code, several of which appear within
+ * the PXE specification itself. This one seems to work for
+ * our purposes.
+ */
+ eb_pxenv_stop_base();
+ //eb_pxenv_unload_stack();
+/* if ( ( undi.pxs->unload_stack.Status != PXENV_STATUS_SUCCESS ) &&
+ ( undi.pxs->unload_stack.Status != PXENV_STATUS_FAILURE ) ) {
+ printf ( "Could not free memory allocated to PXE base code: "
+ "possible memory leak\n" );
+ return 0;
+ }*/
+ /* Free data structures. Forget what the PXE specification
+ * says about how to calculate the new size of base memory;
+ * basemem.c takes care of all that for us. Note that we also
+ * have to free the stack (even though PXE spec doesn't say
+ * anything about it) because nothing else is going to do so.
+ *
+ * Structures will almost certainly not be kB-aligned and
+ * there's a reasonable chance that the UNDI code or data
+ * portions will lie in the same kB as the base code. Since
+ * forget_base_memory works only in 1kB increments, this means
+ * we have to do some arcane trickery.
+ */
+ memset ( &lineup, 0, sizeof(lineup) );
+ if ( SEGMENT(bc_code) != 0 )
+ assemble_firing_squad( &lineup, bc_code, bc_code_size, SHOOT );
+ if ( SEGMENT(bc_data) != 0 )
+ assemble_firing_squad( &lineup, bc_data, bc_data_size, SHOOT );
+ if ( SEGMENT(bc_stck) != 0 )
+ assemble_firing_squad( &lineup, bc_stck, bc_stck_size, SHOOT );
+ /* Don't shoot any bits of the UNDI driver code or data */
+ assemble_firing_squad ( &lineup,
+ VIRTUAL(undi.pxe->UNDICode.Seg_Addr, 0),
+ undi.pxe->UNDICode.Seg_Size, DONTSHOOT );
+ assemble_firing_squad ( &lineup,
+ VIRTUAL(undi.pxe->UNDIData.Seg_Addr, 0),
+ undi.pxe->UNDIData.Seg_Size, DONTSHOOT );
+ //shoot_targets ( &lineup );
+ //undi.pxe->BC_Code.Seg_Addr = 0;
+ //undi.pxe->BC_Data.Seg_Addr = 0;
+ //undi.pxe->Stack.Seg_Addr = 0;
+
+ /* Free and reallocate our own base memory data structures, to
+ * allow the freed base-code blocks to be fully released.
+ */
+ free_base_mem_data();
+ if ( ! allocate_base_mem_data() ) {
+ printf ( "FATAL: memory unaccountably lost\n" );
+ while ( 1 ) {};
+ }
+
+ return 1;
+}
+
+/* UNDI full initialization
+ *
+ * This calls all the various UNDI initialization routines in sequence.
+ */
+
+int undi_full_startup ( void ) {
+ if ( ! eb_pxenv_start_undi() ) return 0;
+ if ( ! eb_pxenv_undi_startup() ) return 0;
+ if ( ! eb_pxenv_undi_initialize() ) return 0;
+ if ( ! eb_pxenv_undi_get_information() ) return 0;
+ undi.irq = undi.pxs->undi_get_information.IntNumber;
+ if ( ! install_trivial_irq_handler ( undi.irq ) ) {
+ undi.irq = IRQ_NONE;
+ return 0;
+ }
+ memmove ( &undi.pxs->undi_set_station_address.StationAddress,
+ &undi.pxs->undi_get_information.PermNodeAddress,
+ sizeof (undi.pxs->undi_set_station_address.StationAddress) );
+ if ( ! eb_pxenv_undi_set_station_address() ) return 0;
+ if ( ! eb_pxenv_undi_open() ) return 0;
+ return 1;
+}
+
+/* UNDI full shutdown
+ *
+ * This calls all the various UNDI shutdown routines in sequence and
+ * also frees any memory that it can.
+ */
+
+int undi_full_shutdown ( void ) {
+ if ( undi.pxe != NULL ) {
+ /* In case we didn't allocate the driver's memory in the first
+ * place, try to grab the code and data segments and sizes
+ * from the !PXE structure.
+ */
+ if ( undi.driver_code == NULL ) {
+ undi.driver_code = VIRTUAL(undi.pxe->UNDICode.Seg_Addr,
+ 0 );
+ undi.driver_code_size = undi.pxe->UNDICode.Seg_Size;
+ }
+ if ( undi.driver_data == NULL ) {
+ undi.driver_data = VIRTUAL(undi.pxe->UNDIData.Seg_Addr,
+ 0 );
+ undi.driver_data_size = undi.pxe->UNDIData.Seg_Size;
+ }
+
+ /* Ignore errors and continue in the hope of shutting
+ * down anyway
+ */
+ if ( undi.opened ) eb_pxenv_undi_close();
+ if ( undi.started ) {
+ eb_pxenv_undi_cleanup();
+ /* We may get spurious UNDI API errors at this
+ * point. If startup() succeeded but
+ * initialize() failed then according to the
+ * spec, we should call shutdown(). However,
+ * some NICS will fail with a status code
+ * 0x006a (INVALID_STATE).
+ */
+ eb_pxenv_undi_shutdown();
+ }
+ if ( undi.irq != IRQ_NONE ) {
+ remove_trivial_irq_handler ( undi.irq );
+ undi.irq = IRQ_NONE;
+ }
+ undi_unload_base_code();
+ if ( undi.prestarted ) {
+ eb_pxenv_stop_undi();
+ /* Success OR Failure indicates that memory
+ * can be freed. Any other status code means
+ * that it can't.
+ */
+ if (( undi.pxs->Status == PXENV_STATUS_KEEP_UNDI ) ||
+ ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ) ) {
+ printf ("Could not free memory allocated to "
+ "UNDI driver: possible memory leak\n");
+ return 0;
+ }
+ }
+ }
+ /* Free memory allocated to UNDI driver */
+ if ( undi.driver_code != NULL ) {
+ /* Clear contents in order to eliminate !PXE and PXENV
+ * signatures to prevent spurious detection via base
+ * memory scan.
+ */
+ memset ( undi.driver_code, 0, undi.driver_code_size );
+ /* forget_base_memory ( undi.driver_code, undi.driver_code_size ); */
+ undi.driver_code = NULL;
+ undi.driver_code_size = 0;
+ }
+ if ( undi.driver_data != NULL ) {
+ /* forget_base_memory ( undi.driver_data, undi.driver_data_size ); */
+ undi.driver_data = NULL;
+ undi.driver_data_size = 0;
+ }
+ /* !PXE structure now gone; memory freed */
+ undi.pxe = NULL;
+ return 1;
+}
+
+/**************************************************************************
+POLL - Wait for a frame
+***************************************************************************/
+static int undi_poll(struct nic *nic)
+{
+ /* Fun, fun, fun. UNDI drivers don't use polling; they use
+ * interrupts. We therefore cheat and pretend that an
+ * interrupt has occurred every time undi_poll() is called.
+ * This isn't too much of a hack; PCI devices share IRQs and
+ * so the first thing that a proper ISR should do is call
+ * PXENV_UNDI_ISR to determine whether or not the UNDI NIC
+ * generated the interrupt; there is no harm done by spurious
+ * calls to PXENV_UNDI_ISR. Similarly, we wouldn't be
+ * handling them any more rapidly than the usual rate of
+ * undi_poll() being called even if we did implement a full
+ * ISR. So it should work. Ha!
+ *
+ * Addendum (21/10/03). Some cards don't play nicely with
+ * this trick, so instead of doing it the easy way we have to
+ * go to all the hassle of installing a genuine interrupt
+ * service routine and dealing with the wonderful 8259
+ * Programmable Interrupt Controller. Joy.
+ */
+
+ /* See if a hardware interrupt has occurred since the last poll().
+ */
+ if ( ! trivial_irq_triggered ( undi.irq ) ) return 0;
+
+ /* Ask the UNDI driver if this is "our" interrupt.
+ */
+ undi.pxs->undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
+ if ( ! eb_pxenv_undi_isr() ) return 0;
+ if ( undi.pxs->undi_isr.FuncFlag == PXENV_UNDI_ISR_OUT_NOT_OURS ) {
+ /* "Not our interrupt" translates to "no packet ready
+ * to read".
+ */
+ return 0;
+ }
+
+ /* At this stage, the device should have cleared its interrupt
+ * line so we can send EOI to the 8259.
+ */
+ send_specific_eoi ( undi.irq );
+
+ /* We might have received a packet, or this might be a
+ * "transmit completed" interrupt. Zero nic->packetlen,
+ * increment whenever we receive a bit of a packet, test
+ * nic->packetlen when we're done to see whether or not we
+ * actually received anything.
+ */
+ nic->packetlen = 0;
+ undi.pxs->undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
+ if ( ! eb_pxenv_undi_isr() ) return 0;
+ while ( undi.pxs->undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_DONE ) {
+ switch ( undi.pxs->undi_isr.FuncFlag ) {
+ case PXENV_UNDI_ISR_OUT_TRANSMIT:
+ /* We really don't care about transmission complete
+ * interrupts.
+ */
+ break;
+ case PXENV_UNDI_ISR_OUT_BUSY:
+ /* This should never happen.
+ */
+ printf ( "UNDI ISR thinks it's being re-entered!\n"
+ "Aborting receive\n" );
+ return 0;
+ case PXENV_UNDI_ISR_OUT_RECEIVE:
+ /* Copy data to receive buffer */
+ memcpy ( nic->packet + nic->packetlen,
+ VIRTUAL( undi.pxs->undi_isr.Frame.segment,
+ undi.pxs->undi_isr.Frame.offset ),
+ undi.pxs->undi_isr.BufferLength );
+ nic->packetlen += undi.pxs->undi_isr.BufferLength;
+ break;
+ default:
+ printf ( "UNDI ISR returned bizzare status code %d\n",
+ undi.pxs->undi_isr.FuncFlag );
+ }
+ undi.pxs->undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+ if ( ! eb_pxenv_undi_isr() ) return 0;
+ }
+ return nic->packetlen > 0 ? 1 : 0;
+}
+
+/**************************************************************************
+TRANSMIT - Transmit a frame
+***************************************************************************/
+static void undi_transmit(
+ struct nic *nic,
+ const char *d, /* Destination */
+ unsigned int t, /* Type */
+ unsigned int s, /* size */
+ const char *p) /* Packet */
+{
+ /* Inhibit compiler warning about unused parameter nic */
+ if ( nic == NULL ) {};
+
+ /* Copy destination to buffer in base memory */
+ memcpy ( undi.xmit_data->destaddr, d, sizeof(MAC_ADDR) );
+
+ /* Translate packet type to UNDI packet type */
+ switch ( t ) {
+ case IP : undi.pxs->undi_transmit.Protocol = P_IP; break;
+ case ARP: undi.pxs->undi_transmit.Protocol = P_ARP; break;
+ case RARP: undi.pxs->undi_transmit.Protocol = P_RARP; break;
+ default: printf ( "Unknown packet type %hx\n", t );
+ return;
+ }
+
+ /* Store packet length in TBD */
+ undi.xmit_data->tbd.ImmedLength = s;
+
+ /* Check to see if data to be transmitted is currently in base
+ * memory. If not, allocate temporary storage in base memory
+ * and copy it there.
+ */
+ if ( SEGMENT( p ) <= 0xffff ) {
+ undi.xmit_data->tbd.Xmit.segment = SEGMENT( p );
+ undi.xmit_data->tbd.Xmit.offset = OFFSET( p );
+ } else {
+ memcpy ( undi.xmit_buffer, p, s );
+ undi.xmit_data->tbd.Xmit.segment = SEGMENT( undi.xmit_buffer );
+ undi.xmit_data->tbd.Xmit.offset = OFFSET( undi.xmit_buffer );
+ }
+
+ eb_pxenv_undi_transmit_packet();
+}
+
+/**************************************************************************
+DISABLE - Turn off ethernet interface
+***************************************************************************/
+static void undi_disable(struct dev *dev)
+{
+ /* Inhibit compiler warning about unused parameter dev */
+ if ( dev == NULL ) {};
+ undi_full_shutdown();
+ free_base_mem_data();
+}
+
+/**************************************************************************
+PROBE - Look for an adapter, this routine's visible to the outside
+***************************************************************************/
+
+/* Locate an UNDI driver by first scanning through base memory for an
+ * installed driver and then by scanning for UNDI ROMs and attempting
+ * to install their drivers.
+ */
+
+int hunt_pixies_and_undi_roms ( void ) {
+ static uint8_t hunt_type = HUNT_FOR_PIXIES;
+
+ if ( hunt_type == HUNT_FOR_PIXIES ) {
+ if ( hunt_pixie() ) {
+ return 1;
+ }
+ }
+ hunt_type = HUNT_FOR_UNDI_ROMS;
+ while ( hunt_undi_rom() ) {
+ if ( undi_loader() ) {
+ return 1;
+ }
+ undi_full_shutdown(); /* Free any allocated memory */
+ }
+ hunt_type = HUNT_FOR_PIXIES;
+ return 0;
+}
+
+/* The actual Etherboot probe routine.
+ */
+
+static int undi_probe(struct dev *dev, struct pci_device *pci)
+{
+ struct nic *nic = (struct nic *)dev;
+
+ /* Zero out global undi structure */
+ memset ( &undi, 0, sizeof(undi) );
+
+ /* Store PCI parameters; we will need them to initialize the UNDI
+ * driver later.
+ */
+ memcpy ( &undi.pci, pci, sizeof(undi.pci) );
+
+ /* Find the BIOS' $PnP structure */
+ if ( ! hunt_pnp_bios() ) {
+ printf ( "No PnP BIOS found; aborting\n" );
+ return 0;
+ }
+
+ /* Allocate base memory data structures */
+ if ( ! allocate_base_mem_data() ) return 0;
+
+ /* Search thoroughly for UNDI drivers */
+ for ( ; hunt_pixies_and_undi_roms(); undi_full_shutdown() ) {
+ /* Try to initialise UNDI driver */
+ printf ( "Initializing UNDI driver. Please wait...\n" );
+ if ( ! undi_full_startup() ) {
+ if ( undi.pxs->Status ==
+ PXENV_STATUS_UNDI_MEDIATEST_FAILED ) {
+ printf ( "Cable not connected (code %#hx)\n",
+ PXENV_STATUS_UNDI_MEDIATEST_FAILED );
+ }
+ continue;
+ }
+ /* Basic information: MAC, IO addr, IRQ */
+ if ( ! eb_pxenv_undi_get_information() ) continue;
+ printf ( "Initialized UNDI NIC with IO %#hx, IRQ %d, MAC %!\n",
+ undi.pxs->undi_get_information.BaseIo,
+ undi.pxs->undi_get_information.IntNumber,
+ undi.pxs->undi_get_information.CurrentNodeAddress );
+ /* Fill out MAC address in nic structure */
+ memcpy ( nic->node_addr,
+ undi.pxs->undi_get_information.CurrentNodeAddress,
+ ETH_ALEN );
+ /* More diagnostic information including link speed */
+ if ( ! eb_pxenv_undi_get_iface_info() ) continue;
+ printf ( "NDIS type %s interface at %d Mbps\n",
+ undi.pxs->undi_get_iface_info.IfaceType,
+ undi.pxs->undi_get_iface_info.LinkSpeed / 1000000 );
+ printf("UNDI Stack at %#hx:%#hx",UNDI_STACK_SEG, UNDI_STACK_OFF);
+ dev->disable = undi_disable;
+ nic->poll = undi_poll;
+ nic->transmit = undi_transmit;
+ return 1;
+ }
+ undi_disable ( dev ); /* To free base memory structures */
+ return 0;
+}
+
+/* UNDI driver states that it is suitable for any PCI NIC (i.e. any
+ * PCI device of class PCI_CLASS_NETWORK_ETHERNET). If there are any
+ * obscure UNDI NICs that have the incorrect PCI class, add them to
+ * this list.
+ */
+static struct pci_id undi_nics[] = {
+ /* PCI_ROM(0x0000, 0x0000, "undi", "UNDI adaptor"), */
+};
+
+struct pci_driver undi_driver = {
+ .type = NIC_DRIVER,
+ .name = "UNDI",
+ .probe = undi_probe,
+ .ids = undi_nics,
+ .id_count = sizeof(undi_nics)/sizeof(undi_nics[0]),
+ .class = PCI_CLASS_NETWORK_ETHERNET,
+};
diff -urN release_2/netboot/undi.h release_2_undi/netboot/undi.h
--- release_2/netboot/undi.h 1970-01-01 08:00:00.000000000 +0800
+++ release_2_undi/netboot/undi.h 2004-03-17 22:29:24.000000000 +0800
@@ -0,0 +1,230 @@
+/**************************************************************************
+Etherboot - BOOTP/TFTP Bootstrap Program
+UNDI NIC driver for Etherboot - header file
+
+This file Copyright (C) 2003 Michael Brown <mbrown@fensystems.co.uk>
+of Fen Systems Ltd. (http://www.fensystems.co.uk/). All rights
+reserved.
+
+$Id: undi.h,v 1.5 2003/10/24 10:05:06 mcb30 Exp $
+***************************************************************************/
+
+/*
+ * 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, or (at
+ * your option) any later version.
+ */
+
+/* Include pxe.h from FreeBSD.
+ * pxe.h defines PACKED, which etherboot.h has already defined.
+ */
+
+#undef PACKED
+#include "pxe.h"
+#include "pic8259.h"
+
+/* __undi_call is the assembler wrapper to the real-mode UNDI calls.
+ * Pass it the real-mode segment:offset address of an undi_call_info_t
+ * structure. The parameters are only uint16_t, but GCC will push
+ * them on the stack as uint32_t anyway for the sake of alignment. We
+ * specify them here as uint32_t to remove ambiguity.
+ */
+
+typedef struct undi_call_info {
+ SEGOFF16_t routine;
+ uint16_t stack[3];
+} undi_call_info_t;
+
+typedef uint16_t PXENV_EXIT_t;
+#define PXENV_EXIT_SUCCESS 0x0000
+#define PXENV_EXIT_FAILURE 0x0001
+PXENV_EXIT_t __undi_call ( uint32_t, uint32_t );
+
+/* The UNDI loader parameter structure is not defined in pxe.h
+ */
+
+typedef struct undi_loader {
+ PXENV_STATUS_t status;
+ uint16_t ax;
+ uint16_t bx;
+ uint16_t dx;
+ uint16_t di;
+ uint16_t es;
+ uint16_t undi_ds;
+ uint16_t undi_cs;
+ uint16_t pxe_off;
+ uint16_t pxenv_off;
+} undi_loader_t;
+
+/* A union that can function as the parameter block for any UNDI API call.
+ */
+
+typedef union pxenv_structure {
+ PXENV_STATUS_t Status; /* Make it easy to read status
+ for any operation */
+ undi_loader_t loader;
+ t_PXENV_START_UNDI start_undi;
+ t_PXENV_UNDI_STARTUP undi_startup;
+ t_PXENV_UNDI_CLEANUP undi_cleanup;
+ t_PXENV_UNDI_INITIALIZE undi_initialize;
+ t_PXENV_UNDI_SHUTDOWN undi_shutdown;
+ t_PXENV_UNDI_OPEN undi_open;
+ t_PXENV_UNDI_CLOSE undi_close;
+ t_PXENV_UNDI_TRANSMIT undi_transmit;
+ t_PXENV_UNDI_SET_STATION_ADDRESS undi_set_station_address;
+ t_PXENV_UNDI_GET_INFORMATION undi_get_information;
+ t_PXENV_UNDI_GET_IFACE_INFO undi_get_iface_info;
+ t_PXENV_UNDI_ISR undi_isr;
+ t_PXENV_STOP_UNDI stop_undi;
+ t_PXENV_UNLOAD_STACK unload_stack;
+} pxenv_structure_t;
+
+/* UNDI status codes
+ */
+
+#define PXENV_STATUS_SUCCESS 0x0000
+#define PXENV_STATUS_FAILURE 0x0001
+#define PXENV_STATUS_KEEP_UNDI 0x0004
+#define PXENV_STATUS_KEEP_ALL 0x0005
+#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x0061
+
+/* BIOS PnP parameter block. We scan for this so that we can pass it
+ * to the UNDI driver.
+ */
+
+#define PNP_BIOS_SIGNATURE ( ('$'<<0) + ('P'<<8) + ('n'<<16) + ('P'<<24) )
+typedef struct pnp_bios {
+ uint32_t signature;
+ uint8_t version;
+ uint8_t length;
+ uint16_t control;
+ uint8_t checksum;
+ uint8_t dontcare[24];
+} PACKED pnp_bios_t;
+
+/* Structures within the PXE ROM.
+ */
+
+#define ROM_SIGNATURE 0xaa55
+typedef struct rom {
+ uint16_t signature;
+ uint8_t unused[0x14];
+ uint16_t undi_rom_id_off;
+ uint16_t pcir_off;
+ uint16_t pnp_off;
+} PACKED rom_t;
+
+#define PCIR_SIGNATURE ( ('P'<<0) + ('C'<<8) + ('I'<<16) + ('R'<<24) )
+typedef struct pcir_header {
+ uint32_t signature;
+ uint16_t vendor_id;
+ uint16_t device_id;
+} PACKED pcir_header_t;
+
+#define PNP_SIGNATURE ( ('$'<<0) + ('P'<<8) + ('n'<<16) + ('P'<<24) )
+typedef struct pnp_header {
+ uint32_t signature;
+ uint8_t struct_revision;
+ uint8_t length;
+ uint16_t next;
+ uint8_t reserved;
+ uint8_t checksum;
+ uint16_t id[2];
+ uint16_t manuf_str_off;
+ uint16_t product_str_off;
+ uint8_t base_type;
+ uint8_t sub_type;
+ uint8_t interface_type;
+ uint8_t indicator;
+ uint16_t boot_connect_off;
+ uint16_t disconnect_off;
+ uint16_t initialise_off;
+ uint16_t reserved2;
+ uint16_t info;
+} PACKED pnp_header_t;
+
+#define UNDI_SIGNATURE ( ('U'<<0) + ('N'<<8) + ('D'<<16) + ('I'<<24) )
+typedef struct undi_rom_id {
+ uint32_t signature;
+ uint8_t struct_length;
+ uint8_t struct_cksum;
+ uint8_t struct_rev;
+ uint8_t undi_rev[3];
+ uint16_t undi_loader_off;
+ uint16_t stack_size;
+ uint16_t data_size;
+ uint16_t code_size;
+} PACKED undi_rom_id_t;
+
+/* Storage buffers that we need in base memory. We collect these into
+ * a single structure to make allocation simpler.
+ */
+
+typedef struct undi_base_mem_xmit_data {
+ MAC_ADDR destaddr;
+ t_PXENV_UNDI_TBD tbd;
+} undi_base_mem_xmit_data_t;
+
+typedef struct undi_base_mem_data {
+ undi_call_info_t undi_call_info;
+ pxenv_structure_t pxs;
+ undi_base_mem_xmit_data_t xmit_data;
+ char xmit_buffer[ETH_FRAME_LEN];
+ char irq_handler[0]; /* Must be last in structure */
+} undi_base_mem_data_t;
+
+/* Macros and data structures used when freeing bits of base memory
+ * used by the UNDI driver.
+ */
+
+#define FIRING_SQUAD_TARGET_SIZE 8
+#define FIRING_SQUAD_TARGET_INDEX(x) ( (x) / FIRING_SQUAD_TARGET_SIZE )
+#define FIRING_SQUAD_TARGET_BIT(x) ( (x) % FIRING_SQUAD_TARGET_SIZE )
+typedef struct firing_squad_lineup {
+ uint8_t targets[ 640 / FIRING_SQUAD_TARGET_SIZE ];
+} firing_squad_lineup_t;
+typedef enum firing_squad_shoot {
+ DONTSHOOT = 0,
+ SHOOT = 1
+} firing_squad_shoot_t;
+
+/* Driver private data structure.
+ */
+
+typedef struct undi {
+ /* Pointers to various data structures */
+ pnp_bios_t *pnp_bios;
+ rom_t *rom;
+ undi_rom_id_t *undi_rom_id;
+ pxe_t *pxe;
+ undi_call_info_t *undi_call_info;
+ pxenv_structure_t *pxs;
+ undi_base_mem_xmit_data_t *xmit_data;
+ /* Pointers and sizes to keep track of allocated base memory */
+ undi_base_mem_data_t *base_mem_data;
+ void *driver_code;
+ size_t driver_code_size;
+ void *driver_data;
+ size_t driver_data_size;
+ char *xmit_buffer;
+ /* Flags. We keep our own instead of trusting the UNDI driver
+ * to have implemented PXENV_UNDI_GET_STATE correctly. Plus
+ * there's the small issue of PXENV_UNDI_GET_STATE being the
+ * same API call as PXENV_STOP_UNDI...
+ */
+ uint8_t prestarted; /* pxenv_start_undi() has been called */
+ uint8_t started; /* pxenv_undi_startup() has been called */
+ uint8_t initialized; /* pxenv_undi_initialize() has been called */
+ uint8_t opened; /* pxenv_undi_open() has been called */
+ /* Parameters that we need to store for future reference
+ */
+ struct pci_device pci;
+ irq_t irq;
+} undi_t;
+
+/* Constants
+ */
+
+#define HUNT_FOR_PIXIES 0
+#define HUNT_FOR_UNDI_ROMS 1
diff -urN release_2/stage2/asm.S release_2_undi/stage2/asm.S
--- release_2/stage2/asm.S 2004-06-18 10:22:35.000000000 +0800
+++ release_2_undi/stage2/asm.S 2004-07-03 14:10:25.000000000 +0800
@@ -204,6 +204,107 @@
jmp EXT_C(hard_stop)
#ifndef STAGE1_5
+
+/**************************************************************************
+UNDI_CALL - wrapper around real-mode UNDI API calls
+**************************************************************************/
+ENTRY(__undi_call)
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movw 8(%ebp),%cx /* Seg:off addr of undi_call_info_t struct */
+ movw 12(%ebp),%dx /* Pass to 16-bit code in %cx:%dx */
+
+ call EXT_C(prot_to_real)
+ .code16
+
+ movw %cx,%es /* Seg:off addr of undi_call_info_t struct */
+ movw %dx,%bx /* into %es:%bx */
+
+ movw %es:8(%bx),%ax /* Transfer contents of undi_call_info_t */
+ pushw %ax /* structure to the real-mode stack */
+ movw %es:6(%bx),%ax
+ pushw %ax
+ movw %es:4(%bx),%ax
+ pushw %ax
+
+ lcall *%es:0(%bx) /* Do the UNDI call */
+ cld /* Don't know whether or not we need this */
+ /* but pxelinux includes it for some reason, */
+ /* so we put it in just in case. */
+
+ popw %cx /* Tidy up the stack */
+ popw %cx
+ popw %cx
+ movw %ax,%cx /* Return %ax via %cx */
+
+ DATA32 call EXT_C(real_to_prot)
+ .code32
+
+ xorl %eax,%eax /* %ax is returned via %cx */
+ movw %cx,%ax
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ popl %ebp
+ ret
+
+/**************************************************************************
+TRIVIAL_IRQ_HANDLER - simple IRQ handler that just increments a counter
+**************************************************************************/
+ENTRY(_trivial_irq_handler_start)
+ENTRY(_trivial_irq_handler)
+ .code16
+ pushw %bx
+ call 1f /* Position-independent access to */
+1: popw %bx /* irq_triggered. */
+ incw %cs:(EXT_C(_trivial_irq_trigger_count)-1b)(%bx)
+ popw %bx
+ iret
+ENTRY(_trivial_irq_trigger_count)
+ .word 0
+ENTRY(_trivial_irq_chain_to)
+ .long 0
+ENTRY(_trivial_irq_chain)
+ .byte 0
+ENTRY(_trivial_irq_handler_end)
+ .code32
+
+/**************************************************************************
+FAKE_IRQ - fake a hardware IRQ
+**************************************************************************/
+ENTRY(fake_irq)
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movb 8(%ebp),%cl /* Convert IRQ number to INT number: */
+ subb $0x08,%cl /* Invert bit 3, set bits 4-7 iff irq < 8*/
+ xorb $0x70,%cl /* Invert bits 4-6 */
+ andb $0x7f,%cl /* Clear bit 7 */
+ movb %cl, fake_irq_int_instruction+1 /* Store in int instruction */
+
+ call EXT_C(prot_to_real)
+ .code16
+
+fake_irq_int_instruction:
+ int $0x00 /* Int no. gets replaced */
+
+ DATA32 call EXT_C(real_to_prot)
+ .code32
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ popl %ebp
+ ret
+
/*
* stop_floppy()
*