aboutsummaryrefslogtreecommitdiffstats
path: root/com32/modules
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-10-24 14:41:00 +0100
committerMatt Fleming <matt.fleming@intel.com>2012-10-24 14:41:00 +0100
commita7115d314dda45324baccee6898a561ed253c8e1 (patch)
tree02db40f456aa512205e06480611da3569692afef /com32/modules
parentc5d8c3f1676afb21cc9f780b6161eaaab35730fc (diff)
parent7307d60063ee4303da4de45f9d984fdc8df92146 (diff)
downloadsyslinux-a7115d314dda45324baccee6898a561ed253c8e1.tar.gz
syslinux-a7115d314dda45324baccee6898a561ed253c8e1.tar.xz
syslinux-a7115d314dda45324baccee6898a561ed253c8e1.zip
Merge branch 'master' into elflink
The following conflict is a result of the fact comapi_chainboot was only stubbed out on the 'elflink' branch but was properly marked as obsolete in 'master'. Conflicts: core/comboot.inc
Diffstat (limited to 'com32/modules')
-rw-r--r--com32/modules/Makefile2
-rw-r--r--com32/modules/kontron_wdt.c414
-rw-r--r--com32/modules/kontron_wdt.h117
-rw-r--r--com32/modules/prdhcp.c164
-rw-r--r--com32/modules/pxechn.c49
5 files changed, 740 insertions, 6 deletions
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index fcdf0471..ee428e30 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -24,7 +24,7 @@ MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 \
kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 ls.c32 gpxecmd.c32 \
ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \
- whichsys.c32 pxechn.c32
+ whichsys.c32 prdhcp.c32 pxechn.c32 kontron_wdt.c32 ifmemdsk.c32
TESTFILES =
diff --git a/com32/modules/kontron_wdt.c b/com32/modules/kontron_wdt.c
new file mode 100644
index 00000000..4e1d2535
--- /dev/null
+++ b/com32/modules/kontron_wdt.c
@@ -0,0 +1,414 @@
+/*
+ * kempld_wdt.c - Kontron PLD watchdog driver
+ *
+ * Copyright (c) 2010 Kontron Embedded Modules GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ * Author: Erwan Velu <erwan.velu@zodiacaerospace.com>
+ *
+ * Note: From the PLD watchdog point of view timeout and pretimeout are
+ * defined differently than in the kernel.
+ * First the pretimeout stage runs out before the timeout stage gets
+ * active. This has to be kept in mind.
+ *
+ * Kernel/API: P-----| pretimeout
+ * |-----------------------T timeout
+ * Watchdog: |-----------------P pretimeout_stage
+ * |-----T timeout_stage
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <sys/io.h>
+#include <unistd.h>
+#include <syslinux/boot.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <console.h>
+#include "kontron_wdt.h"
+
+struct kempld_device_data pld;
+struct kempld_watchdog_data wdt;
+uint8_t status;
+char default_label[255];
+
+/* Default Timeout is 60sec */
+#define TIMEOUT 60
+#define PRETIMEOUT 0
+
+#define do_div(n,base) ({ \
+ int __res; \
+ __res = ((unsigned long) n) % (unsigned) base; \
+ n = ((unsigned long) n) / (unsigned) base; \
+ __res; })
+
+
+/* Basic Wrappers to get code as less changed as possible */
+void iowrite8(uint8_t val, uint16_t addr) { outb(val,addr); }
+void iowrite16(uint16_t val, uint16_t addr) { outw(val,addr); }
+void iowrite32(uint32_t val, uint16_t addr) { outl(val,addr);}
+uint8_t ioread8(uint16_t addr) { return inb(addr);}
+uint16_t ioread16(uint16_t addr) { return inw(addr);}
+uint32_t ioread32(uint32_t addr) { return inl(addr);}
+
+
+/**
+ * kempld_set_index - change the current register index of the PLD
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ *
+ * This function changes the register index of the PLD.
+ */
+void kempld_set_index(struct kempld_device_data *pld, uint8_t index)
+{
+ if (pld->last_index != index) {
+ iowrite8(index, pld->io_index);
+ pld->last_index = index;
+ }
+}
+
+
+uint8_t kempld_read8(struct kempld_device_data *pld, uint8_t index) {
+ kempld_set_index(pld, index);
+ return ioread8(pld->io_data);
+}
+
+
+void kempld_write8(struct kempld_device_data *pld, uint8_t index, uint8_t data) {
+ kempld_set_index(pld, index);
+ iowrite8(data, pld->io_data);
+}
+
+
+uint16_t kempld_read16(struct kempld_device_data *pld, uint8_t index)
+{
+ return kempld_read8(pld, index) | kempld_read8(pld, index+1) << 8;
+}
+
+
+void kempld_write16(struct kempld_device_data *pld, uint8_t index, uint16_t data)
+{
+ kempld_write8(pld, index, (uint8_t)data);
+ kempld_write8(pld, index+1, (uint8_t)(data>>8));
+}
+
+uint32_t kempld_read32(struct kempld_device_data *pld, uint8_t index)
+{
+ return kempld_read16(pld, index) | kempld_read16(pld, index+2) << 16;
+}
+
+void kempld_write32(struct kempld_device_data *pld, uint8_t index, uint32_t data)
+{
+ kempld_write16(pld, index, (uint16_t)data);
+ kempld_write16(pld, index+2, (uint16_t)(data>>16));
+}
+
+static void kempld_release_mutex(struct kempld_device_data *pld)
+{
+ iowrite8(pld->last_index | KEMPLD_MUTEX_KEY, pld->io_index);
+}
+
+void init_structure(void) {
+ /* set default values for the case we start the watchdog or change
+ * the configuration */
+ memset(&wdt,0,sizeof(wdt));
+ memset(&pld,0,sizeof(pld));
+ memset(&default_label,0,sizeof(default_label));
+ wdt.timeout = TIMEOUT;
+ wdt.pretimeout = PRETIMEOUT;
+ wdt.pld = &pld;
+
+ pld.io_base=KEMPLD_IOPORT;
+ pld.io_index=KEMPLD_IOPORT;
+ pld.io_data=KEMPLD_IODATA;
+ pld.pld_clock=33333333;
+}
+
+static int kempld_probe(void) {
+ /* Check for empty IO space */
+ int ret=0;
+ uint8_t index_reg = ioread8(pld.io_index);
+ if ((index_reg == 0xff) && (ioread8(pld.io_data) == 0xff)) {
+ ret = 1;
+ goto err_empty_io;
+ }
+ printf("Kempld structure found at 0x%X (data @ 0x%X)\n",pld.io_base,pld.io_data);
+ return 0;
+
+err_empty_io:
+ printf("No IO Found !\n");
+ return ret;
+}
+
+static int kempld_wdt_probe_stages(struct kempld_watchdog_data *wdt)
+{
+ struct kempld_device_data *pld = wdt->pld;
+ int i, ret;
+ uint32_t timeout;
+ uint32_t timeout_mask;
+ struct kempld_watchdog_stage *stage;
+
+ wdt->stages = 0;
+ wdt->timeout_stage = NULL;
+ wdt->pretimeout_stage = NULL;
+
+ for (i = 0; i < KEMPLD_WDT_MAX_STAGES; i++) {
+
+ timeout = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i));
+ kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i), 0x00000000);
+ timeout_mask = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i));
+ kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i), timeout);
+
+ if (timeout_mask != 0xffffffff) {
+ stage = malloc(sizeof(struct kempld_watchdog_stage));
+ if (stage == NULL) {
+ ret = -1;
+ goto err_alloc_stages;
+ }
+ stage->num = i;
+ stage->timeout_mask = ~timeout_mask;
+ wdt->stage[i] = stage;
+ wdt->stages++;
+
+ /* assign available stages to timeout and pretimeout */
+ if (wdt->stages == 1)
+ wdt->timeout_stage = stage;
+ else if (wdt->stages == 2) {
+ wdt->pretimeout_stage = wdt->timeout_stage;
+ wdt->timeout_stage = stage;
+ }
+ } else {
+ wdt->stage[i] = NULL;
+ }
+ }
+
+ return 0;
+err_alloc_stages:
+ kempld_release_mutex(pld);
+ printf("Cannot allocate stages\n");
+ return ret;
+}
+
+static int kempld_wdt_keepalive(struct kempld_watchdog_data *wdt)
+{
+ struct kempld_device_data *pld = wdt->pld;
+
+ kempld_write8(pld, KEMPLD_WDT_KICK, 'K');
+
+ return 0;
+}
+
+static int kempld_wdt_setstageaction(struct kempld_watchdog_data *wdt,
+ struct kempld_watchdog_stage *stage,
+ int action)
+{
+ struct kempld_device_data *pld = wdt->pld;
+ uint8_t stage_cfg;
+
+ if (stage == NULL)
+ return -1;
+
+ stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->num));
+ stage_cfg &= ~KEMPLD_WDT_STAGE_CFG_ACTION_MASK;
+ stage_cfg |= (action & KEMPLD_WDT_STAGE_CFG_ACTION_MASK);
+ if (action == KEMPLD_WDT_ACTION_RESET)
+ stage_cfg |= KEMPLD_WDT_STAGE_CFG_ASSERT;
+ else
+ stage_cfg &= ~KEMPLD_WDT_STAGE_CFG_ASSERT;
+
+ kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->num), stage_cfg);
+ stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->num));
+
+ return 0;
+}
+
+static int kempld_wdt_setstagetimeout(struct kempld_watchdog_data *wdt,
+ struct kempld_watchdog_stage *stage,
+ int timeout)
+{
+ struct kempld_device_data *pld = wdt->pld;
+ uint8_t stage_cfg;
+ uint8_t prescaler;
+ uint64_t stage_timeout64;
+ uint32_t stage_timeout;
+
+ if (stage == NULL)
+ return -1;
+
+ prescaler = KEMPLD_WDT_PRESCALER_21BIT;
+
+ stage_timeout64 = ((uint64_t)timeout*pld->pld_clock);
+ do_div(stage_timeout64, KEMPLD_PRESCALER(prescaler));
+ stage_timeout = stage_timeout64 & stage->timeout_mask;
+
+ if (stage_timeout64 != (uint64_t)stage_timeout)
+ return -1;
+
+ stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->num));
+ stage_cfg &= ~KEMPLD_WDT_STAGE_CFG_PRESCALER_MASK;
+ stage_cfg |= KEMPLD_WDT_STAGE_CFG_SET_PRESCALER(prescaler);
+ kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->num), stage_cfg);
+ kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->num),
+ stage_timeout);
+
+ return 0;
+}
+
+
+static int kempld_wdt_settimeout(struct kempld_watchdog_data *wdt)
+{
+ int stage_timeout;
+ int stage_pretimeout;
+ int ret;
+ if ((wdt->timeout <= 0) ||
+ (wdt->pretimeout < 0) ||
+ (wdt->pretimeout > wdt->timeout)) {
+ ret = -1;
+ goto err_check_values;
+ }
+
+ if ((wdt->pretimeout == 0) || (wdt->pretimeout_stage == NULL)) {
+ if (wdt->pretimeout != 0)
+ printf("No pretimeout stage available, only enabling reset!\n");
+ stage_pretimeout = 0;
+ stage_timeout = wdt->timeout;
+ } else {
+ stage_pretimeout = wdt->timeout - wdt->pretimeout;
+ stage_timeout = wdt->pretimeout;
+ }
+
+ if (stage_pretimeout != 0) {
+ ret = kempld_wdt_setstageaction(wdt, wdt->pretimeout_stage,
+ KEMPLD_WDT_ACTION_NMI);
+ } else if ((stage_pretimeout == 0)
+ && (wdt->pretimeout_stage != NULL)) {
+ ret = kempld_wdt_setstageaction(wdt, wdt->pretimeout_stage,
+ KEMPLD_WDT_ACTION_NONE);
+ } else
+ ret = 0;
+ if (ret)
+ goto err_setstage;
+
+ if (stage_pretimeout != 0) {
+ ret = kempld_wdt_setstagetimeout(wdt, wdt->pretimeout_stage,
+ stage_pretimeout);
+ if (ret)
+ goto err_setstage;
+ }
+
+ ret = kempld_wdt_setstageaction(wdt, wdt->timeout_stage,
+ KEMPLD_WDT_ACTION_RESET);
+ if (ret)
+ goto err_setstage;
+
+ ret = kempld_wdt_setstagetimeout(wdt, wdt->timeout_stage,
+ stage_timeout);
+ if (ret)
+ goto err_setstage;
+
+ return 0;
+err_setstage:
+err_check_values:
+ return ret;
+}
+
+static int kempld_wdt_start(struct kempld_watchdog_data *wdt)
+{
+ struct kempld_device_data *pld = wdt->pld;
+ uint8_t status;
+
+ status = kempld_read8(pld, KEMPLD_WDT_CFG);
+ status |= KEMPLD_WDT_CFG_ENABLE;
+ kempld_write8(pld, KEMPLD_WDT_CFG, status);
+ status = kempld_read8(pld, KEMPLD_WDT_CFG);
+
+ /* check if the watchdog was enabled */
+ if (!(status & KEMPLD_WDT_CFG_ENABLE))
+ return -1;
+
+ return 0;
+}
+
+/* A regular configuration file looks like
+
+ LABEL WDT
+ COM32 wdt.c32
+ APPEND timeout=120 default_label=local
+*/
+void detect_parameters(const int argc, const char *argv[]) {
+ for (int i = 1; i < argc; i++) {
+ /* Override the timeout if specified on the cmdline */
+ if (!strncmp(argv[i], "timeout=", 8)) {
+ wdt.timeout=atoi(argv[i]+8);
+ } else
+ /* Define which boot entry shall be used */
+ if (!strncmp(argv[i], "default_label=", 14)) {
+ strlcpy(default_label, argv[i] + 14, sizeof(default_label));
+ }
+ }
+}
+
+int main(int argc, const char *argv[]) {
+ int ret=0;
+ openconsole(&dev_rawcon_r, &dev_stdcon_w);
+ init_structure();
+ detect_parameters(argc,argv);
+ kempld_probe();
+
+ /* probe how many usable stages we have */
+ if (kempld_wdt_probe_stages(&wdt)) {
+ printf("Cannot Probe Stages\n");
+ return -1;
+ }
+
+ /* Useless but who knows */
+ wdt.ident.firmware_version = KEMPLD_WDT_REV_GET(kempld_read8(&pld, KEMPLD_WDT_REV));
+
+ status = kempld_read8(&pld, KEMPLD_WDT_CFG);
+ /* kick the watchdog if it is already enabled, otherwise start it */
+ if (status & KEMPLD_WDT_CFG_ENABLE) {
+ /* Maybye the BIOS did setup a first timer
+ * in this case, let's enforce the timeout
+ * to be sure we do have the proper value */
+ kempld_wdt_settimeout(&wdt);
+ kempld_wdt_keepalive(&wdt);
+ } else {
+ ret = kempld_wdt_settimeout(&wdt);
+ if (ret) {
+ printf("Unable to setup timeout !\n");
+ goto booting;
+ }
+
+ ret = kempld_wdt_start(&wdt);
+ if (ret) {
+ printf("Unable to start watchdog !\n");
+ goto booting;
+ }
+
+ }
+
+ printf("Watchog armed ! Rebooting in %d seconds if no feed occurs !\n",wdt.timeout);
+
+booting:
+ /* Release Mutex to let Linux's Driver taking control */
+ kempld_release_mutex(&pld);
+
+ /* Let's boot the default entry if specified */
+ if (strlen(default_label)>0) {
+ printf("Executing default label = '%s'\n",default_label);
+ syslinux_run_command(default_label);
+ } else {
+ return ret;
+ }
+}
diff --git a/com32/modules/kontron_wdt.h b/com32/modules/kontron_wdt.h
new file mode 100644
index 00000000..e916de30
--- /dev/null
+++ b/com32/modules/kontron_wdt.h
@@ -0,0 +1,117 @@
+/*
+ * kempld_wdt.h - Kontron PLD watchdog driver definitions
+ *
+ * Copyright (c) 2010 Kontron Embedded Modules GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _KEMPLD_WDT_H_
+#define _KEMPLD_WDT_H_
+#include <stdint.h>
+
+#define KEMPLD_IOPORT 0x0a80
+#define KEMPLD_IODATA (KEMPLD_IOPORT+1)
+
+#define KEMPLD_MUTEX_KEY 0x80
+
+/* watchdog register definitions */
+#define KEMPLD_WDT_KICK 0x16
+#define KEMPLD_WDT_REV 0x16
+#define KEMPLD_WDT_REV_GET(x) (x & 0xf)
+#define KEMPLD_WDT_CFG 0x17
+#define KEMPLD_WDT_CFG_STAGE_TIMEOUT_OCCURED(x) (1<<x)
+#define KEMPLD_WDT_CFG_ENABLE_LOCK 0x8
+#define KEMPLD_WDT_CFG_ENABLE 0x10
+#define KEMPLD_WDT_CFG_AUTO_RELOAD 0x40
+#define KEMPLD_WDT_CFG_GLOBAL_LOCK 0x80
+#define KEMPLD_WDT_STAGE_CFG(x) (0x18+x)
+#define KEMPLD_WDT_STAGE_CFG_ACTION_MASK 0x7
+#define KEMPLD_WDT_STAGE_CFG_GET_ACTION(x) (x & 0x7)
+#define KEMPLD_WDT_STAGE_CFG_ASSERT 0x8
+#define KEMPLD_WDT_STAGE_CFG_PRESCALER_MASK 0x30
+#define KEMPLD_WDT_STAGE_CFG_GET_PRESCALER(x) ((x & 0x30)>>4)
+#define KEMPLD_WDT_STAGE_CFG_SET_PRESCALER(x) ((x & 0x30)<<4)
+#define KEMPLD_WDT_STAGE_TIMEOUT(x) (0x1b+x*4)
+#define KEMPLD_WDT_MAX_STAGES 3
+
+#define KEMPLD_WDT_ACTION_NONE 0x0
+#define KEMPLD_WDT_ACTION_RESET 0x1
+#define KEMPLD_WDT_ACTION_NMI 0x2
+#define KEMPLD_WDT_ACTION_SMI 0x3
+#define KEMPLD_WDT_ACTION_SCI 0x4
+#define KEMPLD_WDT_ACTION_DELAY 0x5
+
+#define KEMPLD_WDT_PRESCALER_21BIT 0x0
+#define KEMPLD_WDT_PRESCALER_17BIT 0x1
+#define KEMPLD_WDT_PRESCALER_12BIT 0x2
+
+const int kempld_prescaler_bits[] = { 21, 17, 12 };
+
+struct kempld_watchdog_stage {
+ int num;
+ uint32_t timeout_mask;
+};
+
+/**
+ * struct kempld_device_data - Internal representation of the PLD device
+ * @io_base: Pointer to the IO memory
+ * @io_index: Pointer to the IO index register
+ * @io_data: Pointer to the IO data register
+ * @pld_clock: PLD clock frequency
+ * @lock: PLD spin-lock
+ * @lock_flags: PLD spin-lock flags
+ * @have_mutex: Bool value that indicates if mutex is aquired
+ * @last_index: Last written index value
+ * @rscr: Kernel resource structure
+ * @dev: Pointer to kernel device structure
+ * @info: KEMPLD info structure
+ */
+struct kempld_device_data {
+ uint16_t io_base;
+ uint16_t io_index;
+ uint16_t io_data;
+ uint32_t pld_clock;
+/* spinlock_t lock;
+ unsigned long lock_flags; */
+ int have_mutex;
+ uint8_t last_index;
+/* struct resource rscr;
+ struct device *dev;
+ struct kempld_info info;*/
+};
+
+struct watchdog_info {
+ uint32_t options; /* Options the card/driver supports */
+ uint32_t firmware_version; /* Firmware version of the card */
+ uint8_t identity[32]; /* Identity of the board */
+};
+
+struct kempld_watchdog_data {
+ unsigned int revision;
+ int timeout;
+ int pretimeout;
+ unsigned long is_open;
+ unsigned long expect_close;
+ int stages;
+ struct kempld_watchdog_stage *timeout_stage;
+ struct kempld_watchdog_stage *pretimeout_stage;
+ struct kempld_device_data *pld;
+ struct kempld_watchdog_stage *stage[KEMPLD_WDT_MAX_STAGES];
+ struct watchdog_info ident;
+};
+
+#endif /* _KEMPLD_WDT_H_ */
+#define KEMPLD_PRESCALER(x) (0xffffffff>>(32-kempld_prescaler_bits[x]))
diff --git a/com32/modules/prdhcp.c b/com32/modules/prdhcp.c
new file mode 100644
index 00000000..e1785a03
--- /dev/null
+++ b/com32/modules/prdhcp.c
@@ -0,0 +1,164 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010-2011 Gene Cumm - All Rights Reserved
+ *
+ * Portions from chain.c:
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Significant portions copyright (C) 2010 Shao Miller
+ * [partition iteration, GPT, "fs"]
+ *
+ * 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, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * prdhcp.c
+ *
+ * Print the contents of the 3 DHCP packets
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <consoles.h>
+#include <console.h>
+#include <errno.h>
+#include <string.h>
+#include <syslinux/config.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/video.h>
+#include <com32.h>
+#include <stdint.h>
+#include <syslinux/pxe.h>
+#include <sys/gpxe.h>
+#include <unistd.h>
+#include <getkey.h>
+
+#define DEBUG 0
+
+#define dprintf0(f, ...) ((void)0)
+
+#ifdef DEBUG
+# define dpressanykey pressanykey
+# define dprintf printf
+# define dprint_pxe_bootp_t print_pxe_bootp_t
+# define dprint_pxe_vendor_blk print_pxe_vendor_blk
+# define dprint_pxe_vendor_raw print_pxe_vendor_raw
+#else
+# define dpressanykey(void) ((void)0)
+# define dprintf(f, ...) ((void)0)
+# define dprint_pxe_bootp_t(p, l) ((void)0)
+# define dprint_pxe_vendor_blk(p, l) ((void)0)
+# define dprint_pxe_vendor_raw(p, l) ((void)0)
+#endif
+
+#define dprintf_opt_cp dprintf0
+#define dprintf_opt_inj dprintf
+
+
+const char app_name_str[] = "prdhcp.c32";
+
+
+int pressanykey(void) {
+ int inc;
+
+ printf("Press any key to continue. ");
+ inc = KEY_NONE;
+ while (inc == KEY_NONE)
+ inc = get_key(stdin, 6000);
+ puts("");
+ return inc;
+}
+
+void print_pxe_vendor_blk(pxe_bootp_t *p, size_t len)
+{
+ int i, vlen, oplen, j;
+ uint8_t *d;
+ uint32_t magic;
+ if (!p) {
+ printf(" packet pointer is null\n");
+ return;
+ }
+ vlen = len - ((void *)&(p->vendor) - (void *)p);
+ printf(" Vendor Data: Len=%d", vlen);
+ d = p->vendor.d;
+ /* Print only 256 characters of the vendor/option data */
+ /*
+ print_pxe_vendor_raw(p, (len - vlen) + 256);
+ vlen = 0;
+ */
+ magic = ntohl(*((uint32_t *)d));
+ printf(" Magic: %08X", ntohl(*((uint32_t *)d)));
+ if (magic != VM_RFC1048) /* Invalid DHCP packet */
+ vlen = 0;
+ for (i = 4; i < vlen; i++) {
+ if (d[i]) /* Skip the padding */
+ printf("\n @%03X-%3d", i, d[i]);
+ if (d[i] == 255) /* End of list */
+ break;
+ if (d[i]) {
+ oplen = d[++i];
+ printf(" l=%3d:", oplen);
+ for (j = (++i + oplen); i < vlen && i < j; i++) {
+ printf(" %02X", d[i]);
+ }
+ i--;
+ }
+ }
+ printf("\n");
+}
+
+void print_pxe_bootp_t(pxe_bootp_t *p, size_t len)
+{
+ if (!p) {
+ printf(" packet pointer is null\n");
+ return;
+ }
+ printf(" op:%02X hw:%02X hl:%02X gh:%02X id:%08X se:%04X f:%04X"
+ " cip:%08X\n", p->opcode, p->Hardware, p->Hardlen, p->Gatehops,
+ ntohl(p->ident), ntohs(p->seconds), ntohs(p->Flags), ntohl(p->cip));
+ printf(" yip:%08X sip:%08X gip:%08X",
+ ntohl(p->yip), ntohl(p->sip), ntohl(p->gip));
+ printf(" caddr-%02X:%02X:%02X:%02X:%02X:%02X\n", p->CAddr[0],
+ p->CAddr[1], p->CAddr[2], p->CAddr[3], p->CAddr[4], p->CAddr[5]);
+ printf(" sName: '%s'\n", p->Sname);
+ printf(" bootfile: '%s'\n", p->bootfile);
+ print_pxe_vendor_blk(p, len);
+}
+
+void print_dhcp_pkt_all(void)
+{
+ pxe_bootp_t *p;
+ size_t len;
+ int i;
+ int ptype[3] = {PXENV_PACKET_TYPE_DHCP_DISCOVER, PXENV_PACKET_TYPE_DHCP_ACK, PXENV_PACKET_TYPE_CACHED_REPLY};
+
+ for (i = 0; i < 3; i++) {
+ if (!pxe_get_cached_info(ptype[i],
+ (void **)&(p), &(len))) {
+ dprintf("Got packet #%d/%d\n", (i + 1), ptype[i]);
+ print_pxe_bootp_t(p, len);
+ pressanykey();
+ }
+ }
+}
+
+int main(void)
+{
+ int rv= -1;
+ const struct syslinux_version *sv;
+
+ console_ansi_raw();
+ sv = syslinux_version();
+ if (sv->filesystem != SYSLINUX_FS_PXELINUX) {
+ printf("%s: May only run in PXELINUX\n", app_name_str);
+ return -2;
+ }
+ print_dhcp_pkt_all();
+ return rv;
+}
diff --git a/com32/modules/pxechn.c b/com32/modules/pxechn.c
index 39ac72ea..7f2002db 100644
--- a/com32/modules/pxechn.c
+++ b/com32/modules/pxechn.c
@@ -43,7 +43,11 @@
#include <limits.h>
-#define PXECHN_DEBUG 1
+#ifdef DEBUG
+# define PXECHN_DEBUG 1
+#else
+# define PXECHN_DEBUG 0
+#endif
typedef union {
uint64_t q;
@@ -54,15 +58,21 @@ typedef union {
#define dprintf0(f, ...) ((void)0)
+#ifndef dprintf
+# if (PXECHN_DEBUG > 0)
+# define dprintf printf
+# else
+# define dprintf(f, ...) ((void)0)
+# endif
+#endif
+
#if (PXECHN_DEBUG > 0)
# define dpressanykey pressanykey
-# define dprintf printf
# define dprint_pxe_bootp_t print_pxe_bootp_t
# define dprint_pxe_vendor_blk print_pxe_vendor_blk
# define dprint_pxe_vendor_raw print_pxe_vendor_raw
#else
# define dpressanykey(tm) ((void)0)
-# define dprintf(f, ...) ((void)0)
# define dprint_pxe_bootp_t(p, l) ((void)0)
# define dprint_pxe_vendor_blk(p, l) ((void)0)
# define dprint_pxe_vendor_raw(p, l) ((void)0)
@@ -107,6 +117,7 @@ struct pxelinux_opt {
uint32_t force;
uint32_t wait; /* Additional decision to wait before boot */
int32_t wds; /* WDS option/level */
+ in_addr_t sip; /* siaddr: Next Server IP Address */
struct dhcp_option p[PXECHN_NUM_PKT_AVAIL];
/* original _DHCP_DISCOVER, _DHCP_ACK, _CACHED_REPLY then modified packets */
char host[PXECHN_HOST_LEN];
@@ -453,6 +464,7 @@ void pxechn_init(struct pxelinux_opt *pxe)
pxe->wait = 0;
pxe->gip = 0;
pxe->wds = 0;
+ pxe->sip = 0;
pxe->host[0] = 0;
pxe->host[((NUM_DHCP_OPTS) - 1)] = 0;
for (int j = 0; j < PXECHN_NUM_PKT_TYPE; j++){
@@ -731,7 +743,7 @@ int pxechn_parse_args(int argc, char *argv[], struct pxelinux_opt *pxe,
{
int arg, optnum, rv = 0;
char *p = NULL;
- const char optstr[] = "c:f:g:o:p:t:uwW";
+ const char optstr[] = "c:f:g:o:p:St:uwW";
struct dhcp_option iopt;
if (pxe->p[5].data)
@@ -765,6 +777,9 @@ int pxechn_parse_args(int argc, char *argv[], struct pxelinux_opt *pxe,
case 'p': /* prefix */
pxechn_setopt_str(&(opts[210]), optarg);
break;
+ case 'S': /* sip from sName */
+ pxe->sip = 1;
+ break;
case 't': /* timeout */
optnum = strtoul(optarg, &p, 0);
if (p != optarg) {
@@ -809,6 +824,7 @@ int pxechn_args(int argc, char *argv[], struct pxelinux_opt *pxe)
pxe_bootp_t *bootp0, *bootp1;
int ret = 0;
struct dhcp_option *opts;
+ char *str;
opts = pxe->opts[2];
/* Start filling packet #1 */
@@ -826,7 +842,30 @@ int pxechn_args(int argc, char *argv[], struct pxelinux_opt *pxe)
ret = pxechn_parse_args(argc, argv, pxe, opts);
if (ret)
return ret;
- bootp1->sip = pxe->fip;
+ if (pxe->sip > 0xFFFFFF) { /* a real IPv4 address */
+ bootp1->sip = pxe->sip;
+ } else if ((pxe->sip == 1)
+ && (opts[66].len > 0)){
+ /* unterminated? */
+ if (strnlen(opts[66].data, opts[66].len) == (size_t)opts[66].len) {
+ str = malloc(opts[66].len + 1);
+ if (str) {
+ memcpy(str, opts[66].data, opts[66].len);
+ str[opts[66].len] = 0;
+ }
+ } else {
+ str = opts[66].data;
+ }
+ if (str) {
+ bootp1->sip = pxe_dns(str);
+ if (str != opts[66].data)
+ free(str);
+ } else {
+ bootp1->sip = pxe->fip;
+ }
+ } else {
+ bootp1->sip = pxe->fip;
+ }
bootp1->gip = pxe->gip;
ret = dhcp_pack_packet(bootp1, (size_t *)&(pxe->p[5].len), opts);