[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

UNDI/PXE driver for GRUB

From: Patrick J. LoPresti
Subject: UNDI/PXE driver for GRUB
Date: 12 Aug 2002 12:46:49 -0400
User-agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2

(Note: To understand this message, it helps to have read the PXE 2.1
specification, especially chapter 3.  You can download it from

With hardware for which no Etherboot driver is available, it would be
nice if pxegrub could use the UNDI stack which is included with all
PXE-compliant network cards.  In principle, this would allow pxegrub
to support any such card, current or future.

Since I have some hardware (mostly laptops) which Etherboot does not
support, I decided to take a crack at writing UNDI/PXE support this

Let me describe what little I got working.

I began by adding a "pxe_trampoline" function to stage2/asm.S.  This
function translates a protected-mode call to the real-mode call
required by the UNDI stack.  (The PXE specification says that the UNDI
stack should work from protected mode, but that may mean 16-bit
protected mode (?).  Anyway, I was unable to invoke the stack
successfully from protected mode.)

The trampoline function is pretty short, so I include it here:

    /* Trampoline to call real-mode PXE functions.

       pxe_trampoline(SEGOFF16 entry, int opcode, SEGOFF16 argptr)


            pushl %ebp

            /* Copy arguments to scratch space */
            movl    0x8(%esp), %eax
            movl    %eax, SCRATCHADDR
            movl    0xc(%esp), %eax
            movl    %eax, SCRATCHADDR+4
            movl    0x10(%esp), %eax
            movl    %eax, SCRATCHADDR+8

            /* Drop to real mode */
            call    EXT_C(prot_to_real)

            /* Get arguments from scratch segment */
            movw    $SCRATCHSEG, %ax
            movw    %ax, %es
            /* segment of parameter block */
            pushw   %es:(10)
            /* offset of parameter block */
            pushw   %es:(8)
            /* PXE opcode (throwing away the high word) */
            pushw   %es:(4)
            /* call PXE entry point */
            lcall   *%es:0
            /* pop arguments */
            addw    $6, %sp
            /* remember return value */
            movw    %ax, %dx

            /* Return to protected mode */
            DATA32  call    EXT_C(real_to_prot)

            /* Recover return value */
            xorl    %eax, %eax
            movw    %dx, %ax
            popl    %ebp

Next, I began writing an "fsys_pxe" filesystem module.  My idea was to
use the high-level TFTP support in the UNDI stack, ignoring most of
the existing netboot code since it depends on low-level polling
drivers.  The low-level UNDI interface uses an interrupt-driven model.
I figured it would be easier to use the high-level UNDI TFTP interface
directly than to simulate the Etherboot polling model using the UNDI
interrupt-driven one.

The first thing my fsys_pxe module does is scan memory to find the
"!PXE" structure, which provides (among other things) the entry point
to the UNDI stack.

The next thing fsys_pxe does is call the PXENV_GET_CACHED_INFO routine
using the trampoline, requesting the DHCP ACK packet.  This actually
works!  It returns a valid and correct DHCP packet, complete with
gateway IP address, server IP address, client IP address, vendor
options, and so on.  In other words, my pxe_trampoline function works,
which is the good news.

The bad news is that almost nothing else works.  Most UNDI calls are
returning a failure code with the status field set to 0x01 ("general
failure").  Some calls (e.g., PXENV_TFTP_OPEN) pause for a while
before returning failure, but they do not actually emit any packets as
far as I can tell.  Without anything more telling than "general
failure", I am at a bit of a loss for how to proceed.

I would be happy to make the rest of my code available to anybody who
is interested.  I myself may end up using syslinux/pxelinux instead...

 - Pat

reply via email to

[Prev in Thread] Current Thread [Next in Thread]