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 (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 +#include + +#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 + +#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) + * All rights reserved. + * Copyright (c) 2000 Paul Saab + * All rights reserved. + * Copyright (c) 2000 John Baldwin + * 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 + +/* 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 +#include + +/* 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 +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 +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() *