summaryrefslogtreecommitdiff
path: root/core/fs/pxe/pxe.c
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-03-22 14:54:09 +0000
committerMatt Fleming <matt.fleming@intel.com>2013-04-23 15:30:17 +0100
commitfe283b78c973268f2d1f0309826ceeb5c9e8978d (patch)
treede90b141427ab9222bb3e82afef6f880778b3cf2 /core/fs/pxe/pxe.c
parentbb229372b2c3f9fbb0cdd0a7221a6cc4aba5d2ed (diff)
downloadsyslinux-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.c396
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(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x5650;
- call16(pxe_int1a, &regs, &regs);
- 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;