diff options
author | Matt Fleming <matt.fleming@intel.com> | 2013-03-22 14:54:09 +0000 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2013-04-23 15:30:17 +0100 |
commit | fe283b78c973268f2d1f0309826ceeb5c9e8978d (patch) | |
tree | de90b141427ab9222bb3e82afef6f880778b3cf2 /core/fs/pxe/pxe.c | |
parent | bb229372b2c3f9fbb0cdd0a7221a6cc4aba5d2ed (diff) | |
download | syslinux-fe283b78c973268f2d1f0309826ceeb5c9e8978d.tar.gz |
efi: Add network supportsyslinux-6.00-pre5
Add TCP and UDP support to the EFI firmware backend. This necessitated
moving all tcp functions to a core_tcp_* prefix so that they could be
implemented differently for BIOS+lwip and EFI. Unfortunately, the tcp_*
prefix is already in use by the lwip code.
To maintain symmetry, the UDP functions were also moved from net_core_*
to core_udp_*. The net_core API was introduced in 5.x to allow the
legacy PXE and lwip stacks to live side by side, and the intention was
that net_core_init() would take a protocol argument to build a
protocol-specific object. It turned out to be easier to call either udp
or tcp functions directly because the semantics of read/write differ
between protocols.
Booting an IPv4 EFI PXE stack using tftp and http has been tested.
There are a couple of TODO items left,
o dns resolve code is missing
o ftp hasn't been tested
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'core/fs/pxe/pxe.c')
-rw-r--r-- | core/fs/pxe/pxe.c | 396 |
1 files changed, 1 insertions, 395 deletions
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c index 3f68e969..4591edc9 100644 --- a/core/fs/pxe/pxe.c +++ b/core/fs/pxe/pxe.c @@ -2,9 +2,7 @@ #include <stdio.h> #include <string.h> #include <core.h> -#include <bios.h> #include <fs.h> -#include <minmax.h> #include <fcntl.h> #include <sys/cpu.h> #include "pxe.h" @@ -16,8 +14,6 @@ __lowmem t_PXENV_UNDI_GET_INFORMATION pxe_undi_info; __lowmem t_PXENV_UNDI_GET_IFACE_INFO pxe_undi_iface; -static uint16_t real_base_mem; /* Amount of DOS memory after freeing */ - uint8_t MAC[MAC_MAX]; /* Actual MAC address */ uint8_t MAC_len; /* MAC address len */ uint8_t MAC_type; /* MAC address type */ @@ -25,8 +21,6 @@ uint8_t MAC_type; /* MAC address type */ char boot_file[256]; /* From DHCP */ char path_prefix[256]; /* From DHCP */ -static bool has_gpxe; -static uint32_t gpxe_funcs; bool have_uuid = false; /* @@ -131,32 +125,6 @@ __export int pxe_call(int opcode, void *data) return regs.eflags.l & EFLAGS_CF; /* CF SET if fail */ } -/** - * Get a DHCP packet from the PXE stack into a lowmem buffer - * - * @param: type, packet type - * @return: buffer size - * - */ -static int pxe_get_cached_info(int type, void *buf, size_t bufsiz) -{ - int err; - static __lowmem struct s_PXENV_GET_CACHED_INFO get_cached_info; - printf(" %02x", type); - - memset(&get_cached_info, 0, sizeof get_cached_info); - get_cached_info.PacketType = type; - get_cached_info.BufferSize = bufsiz; - get_cached_info.Buffer = FAR_PTR(buf); - err = pxe_call(PXENV_GET_CACHED_INFO, &get_cached_info); - if (err) { - printf("PXE API call failed, error %04x\n", err); - kaboom(); - } - - return get_cached_info.BufferSize; -} - /* * mangle a filename pointed to by _src_ into a buffer pointed * to by _dst_; ends on encountering any whitespace. @@ -568,289 +536,11 @@ static void ip_init(void) } /* - * Validity check on possible !PXE structure in buf - * return 1 for success, 0 for failure. - * - */ -static int is_pxe(const void *buf) -{ - const struct pxe_t *pxe = buf; - const uint8_t *p = buf; - int i = pxe->structlength; - uint8_t sum = 0; - - if (i < sizeof(struct pxe_t) || - memcmp(pxe->signature, "!PXE", 4)) - return 0; - - while (i--) - sum += *p++; - - return sum == 0; -} - -/* - * Just like is_pxe, it checks PXENV+ structure - * - */ -static int is_pxenv(const void *buf) -{ - const struct pxenv_t *pxenv = buf; - const uint8_t *p = buf; - int i = pxenv->length; - uint8_t sum = 0; - - /* The pxeptr field isn't present in old versions */ - if (i < offsetof(struct pxenv_t, pxeptr) || - memcmp(pxenv->signature, "PXENV+", 6)) - return 0; - - while (i--) - sum += *p++; - - return sum == 0; -} - - - -/* - * memory_scan_for_pxe_struct: - * memory_scan_for_pxenv_struct: - * - * If none of the standard methods find the !PXE/PXENV+ structure, - * look for it by scanning memory. - * - * return the corresponding pxe structure if found, or NULL; - */ -static const void *memory_scan(uintptr_t start, int (*func)(const void *)) -{ - const char *ptr; - - /* Scan each 16 bytes of conventional memory before the VGA region */ - for (ptr = (const char *)start; ptr < (const char *)0xA0000; ptr += 16) { - if (func(ptr)) - return ptr; /* found it! */ - ptr += 16; - } - return NULL; -} - -static const struct pxe_t *memory_scan_for_pxe_struct(void) -{ - uint16_t start = bios_fbm(); /* Starting segment */ - - return memory_scan(start << 10, is_pxe); -} - -static const struct pxenv_t *memory_scan_for_pxenv_struct(void) -{ - return memory_scan(0x10000, is_pxenv); -} - -/* - * Find the !PXE structure; we search for the following, in order: - * - * a. !PXE structure as SS:[SP + 4] - * b. PXENV+ structure at [ES:BX] - * c. INT 1Ah AX=0x5650 -> PXENV+ - * d. Search memory for !PXE - * e. Search memory for PXENV+ - * - * If we find a PXENV+ structure, we try to find a !PXE structure from - * if if the API version is 2.1 or later - * - */ -static int pxe_init(bool quiet) -{ - extern void pxe_int1a(void); - char plan = 'A'; - uint16_t seg, off; - uint16_t code_seg, code_len; - uint16_t data_seg, data_len; - const char *base = GET_PTR(InitStack); - com32sys_t regs; - const char *type; - const struct pxenv_t *pxenv; - const struct pxe_t *pxe; - - /* Assume API version 2.1 */ - APIVer = 0x201; - - /* Plan A: !PXE structure as SS:[SP + 4] */ - off = *(const uint16_t *)(base + 48); - seg = *(const uint16_t *)(base + 50); - pxe = MK_PTR(seg, off); - if (is_pxe(pxe)) - goto have_pxe; - - /* Plan B: PXENV+ structure at [ES:BX] */ - plan++; - off = *(const uint16_t *)(base + 24); /* Original BX */ - seg = *(const uint16_t *)(base + 4); /* Original ES */ - pxenv = MK_PTR(seg, off); - if (is_pxenv(pxenv)) - goto have_pxenv; - - /* Plan C: PXENV+ structure via INT 1Ah AX=5650h */ - plan++; - memset(®s, 0, sizeof regs); - regs.eax.w[0] = 0x5650; - call16(pxe_int1a, ®s, ®s); - if (!(regs.eflags.l & EFLAGS_CF) && (regs.eax.w[0] == 0x564e)) { - pxenv = MK_PTR(regs.es, regs.ebx.w[0]); - if (is_pxenv(pxenv)) - goto have_pxenv; - } - - /* Plan D: !PXE memory scan */ - plan++; - if ((pxe = memory_scan_for_pxe_struct())) - goto have_pxe; - - /* Plan E: PXENV+ memory scan */ - plan++; - if ((pxenv = memory_scan_for_pxenv_struct())) - goto have_pxenv; - - /* Found nothing at all !! */ - if (!quiet) - printf("No !PXE or PXENV+ API found; we're dead...\n"); - return -1; - - have_pxenv: - APIVer = pxenv->version; - if (!quiet) - printf("Found PXENV+ structure\nPXE API version is %04x\n", APIVer); - - /* if the API version number is 0x0201 or higher, use the !PXE structure */ - if (APIVer >= 0x201) { - if (pxenv->length >= sizeof(struct pxenv_t)) { - pxe = GET_PTR(pxenv->pxeptr); - if (is_pxe(pxe)) - goto have_pxe; - /* - * Nope, !PXE structure missing despite API 2.1+, or at least - * the pointer is missing. Do a last-ditch attempt to find it - */ - if ((pxe = memory_scan_for_pxe_struct())) - goto have_pxe; - } - APIVer = 0x200; /* PXENV+ only, assume version 2.00 */ - } - - /* Otherwise, no dice, use PXENV+ structure */ - data_len = pxenv->undidatasize; - data_seg = pxenv->undidataseg; - code_len = pxenv->undicodesize; - code_seg = pxenv->undicodeseg; - PXEEntry = pxenv->rmentry; - type = "PXENV+"; - goto have_entrypoint; - - have_pxe: - data_len = pxe->seg[PXE_Seg_UNDIData].size; - data_seg = pxe->seg[PXE_Seg_UNDIData].sel; - code_len = pxe->seg[PXE_Seg_UNDICode].size; - code_seg = pxe->seg[PXE_Seg_UNDICode].sel; - PXEEntry = pxe->entrypointsp; - type = "!PXE"; - - have_entrypoint: - if (!quiet) { - printf("%s entry point found (we hope) at %04X:%04X via plan %c\n", - type, PXEEntry.seg, PXEEntry.offs, plan); - printf("UNDI code segment at %04X len %04X\n", code_seg, code_len); - printf("UNDI data segment at %04X len %04X\n", data_seg, data_len); - } - - code_seg = code_seg + ((code_len + 15) >> 4); - data_seg = data_seg + ((data_len + 15) >> 4); - - real_base_mem = max(code_seg, data_seg) >> 6; /* Convert to kilobytes */ - - probe_undi(); - - return 0; -} - -/* - * See if we have gPXE - */ -static void gpxe_init(void) -{ - int err; - static __lowmem struct s_PXENV_FILE_API_CHECK api_check; - - if (APIVer >= 0x201) { - api_check.Size = sizeof api_check; - api_check.Magic = 0x91d447b2; - err = pxe_call(PXENV_FILE_API_CHECK, &api_check); - if (!err && api_check.Magic == 0xe9c17b20) - gpxe_funcs = api_check.APIMask; - } - - /* Necessary functions for us to use the gPXE file API */ - has_gpxe = (~gpxe_funcs & 0x4b) == 0; -} - -/* * Network-specific initialization */ static void network_init(void) { - int pkt_len; - struct bootp_t *bp; - const size_t dhcp_max_packet = 4096; - - bp = lmalloc(dhcp_max_packet); - if (!bp) { - printf("Out of low memory\n"); - kaboom(); - } - - *LocalDomain = 0; /* No LocalDomain received */ - - /* - * Get the DHCP client identifiers (query info 1) - */ - printf("Getting cached packet "); - pkt_len = pxe_get_cached_info(1, bp, dhcp_max_packet); - parse_dhcp(bp, pkt_len); - /* - * We don't use flags from the request packet, so - * this is a good time to initialize DHCPMagic... - * Initialize it to 1 meaning we will accept options found; - * in earlier versions of PXELINUX bit 0 was used to indicate - * we have found option 208 with the appropriate magic number; - * we no longer require that, but MAY want to re-introduce - * it in the future for vendor encapsulated options. - */ - *(char *)&DHCPMagic = 1; - - /* - * Get the BOOTP/DHCP packet that brought us file (and an IP - * address). This lives in the DHCPACK packet (query info 2) - */ - pkt_len = pxe_get_cached_info(2, bp, dhcp_max_packet); - parse_dhcp(bp, pkt_len); - /* - * Save away MAC address (assume this is in query info 2. If this - * turns out to be problematic it might be better getting it from - * the query info 1 packet - */ - MAC_len = bp->hardlen > 16 ? 0 : bp->hardlen; - MAC_type = bp->hardware; - memcpy(MAC, bp->macaddr, MAC_len); - - /* - * Get the boot file and other info. This lives in the CACHED_REPLY - * packet (query info 3) - */ - pkt_len = pxe_get_cached_info(3, bp, dhcp_max_packet); - parse_dhcp(bp, pkt_len); - printf("\n"); - - lfree(bp); + net_parse_dhcp(); make_bootif_string(); /* If DMI and DHCP disagree, which one should we set? */ @@ -981,90 +671,6 @@ static void install_int18_hack(void) } #endif -/* - * This function unloads the PXE and UNDI stacks and - * unclaims the memory. - */ -__export void unload_pxe(uint16_t flags) -{ - /* PXE unload sequences */ - /* - * iPXE does: - * UNDI_SHUTDOWN, UNDI_CLEANUP, STOP_UNDI - * Older Syslinux did: - * UDP_CLOSE, UNDI_SHUTDOWN, UNLOAD_STACK, STOP_UNDI/UNDI_CLEANUP - */ - static const uint8_t new_api_unload[] = { - PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_STOP_UNDI, 0 - }; - static const uint8_t old_api_unload[] = { - PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_UNDI_CLEANUP, 0 - }; - - unsigned int api; - const uint8_t *api_ptr; - int err; - size_t int_addr; - static __lowmem union { - struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; - struct s_PXENV_UNLOAD_STACK unload_stack; - struct s_PXENV_STOP_UNDI stop_undi; - struct s_PXENV_UNDI_CLEANUP undi_cleanup; - uint16_t Status; /* All calls have this as the first member */ - } unload_call; - - dprintf("Called unload_pxe()...\n"); - dprintf("FBM before unload = %d\n", bios_fbm()); - - err = reset_pxe(); - - dprintf("FBM after reset_pxe = %d, err = %d\n", bios_fbm(), err); - - /* If we want to keep PXE around, we still need to reset it */ - if (flags || err) - return; - - dprintf("APIVer = %04x\n", APIVer); - - api_ptr = APIVer >= 0x0200 ? new_api_unload : old_api_unload; - while((api = *api_ptr++)) { - dprintf("PXE call %04x\n", api); - memset(&unload_call, 0, sizeof unload_call); - err = pxe_call(api, &unload_call); - if (err || unload_call.Status != PXENV_STATUS_SUCCESS) { - printf("PXE unload API call %04x failed: 0x%x\n", - api, unload_call.Status); - goto cant_free; - } - } - - api = 0xff00; - if (real_base_mem <= bios_fbm()) { /* Sanity check */ - dprintf("FBM %d < real_base_mem %d\n", bios_fbm(), real_base_mem); - goto cant_free; - } - api++; - - /* Check that PXE actually unhooked the INT 0x1A chain */ - int_addr = (size_t)GET_PTR(*(far_ptr_t *)(4 * 0x1a)); - int_addr >>= 10; - if (int_addr >= real_base_mem || int_addr < bios_fbm()) { - set_bios_fbm(real_base_mem); - dprintf("FBM after unload_pxe = %d\n", bios_fbm()); - return; - } - - dprintf("Can't free FBM, real_base_mem = %d, " - "FBM = %d, INT 1A = %08x (%d)\n", - real_base_mem, bios_fbm(), - *(uint32_t *)(4 * 0x1a), int_addr); - -cant_free: - printf("Failed to free base memory error %04x-%08x (%d/%dK)\n", - api, *(uint32_t *)(4 * 0x1a), bios_fbm(), real_base_mem); - return; -} - static int pxe_readdir(struct file *file, struct dirent *dirent) { struct inode *inode = file->inode; |