aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Huth <thuth@redhat.com>2018-05-26 08:06:05 +0200
committerAlexey Kardashevskiy <aik@ozlabs.ru>2018-05-29 19:06:45 +1000
commit08e22e4019030b2f643f65c192c64f3a939fec24 (patch)
tree31b73ab866e1b205282a8a74d8b483f67cda1587
parent696e2036f44788769038e998a4465dfe58906d29 (diff)
downloadSLOF-08e22e4019030b2f643f65c192c64f3a939fec24.zip
SLOF-08e22e4019030b2f643f65c192c64f3a939fec24.tar.gz
SLOF-08e22e4019030b2f643f65c192c64f3a939fec24.tar.bz2
libnet: Wire up pxelinux.cfg network booting
In case the normal network loading failed, try to load a pxelinux.cfg config file. If that succeeds, load the kernel and initrd with the information that could be found in this file. Signed-off-by: Thomas Huth <thuth@redhat.com> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
-rw-r--r--include/helpers.h2
-rw-r--r--lib/libnet/netload.c84
-rw-r--r--slof/helpers.c15
3 files changed, 96 insertions, 5 deletions
diff --git a/include/helpers.h b/include/helpers.h
index 04ee771..9dfe3ae 100644
--- a/include/helpers.h
+++ b/include/helpers.h
@@ -36,6 +36,8 @@ extern void SLOF_pci_config_write16(long offset, long value);
extern void SLOF_pci_config_write8(long offset, long value);
extern void *SLOF_translate_my_address(void *addr);
extern int write_mm_log(char *data, unsigned int len, unsigned short type);
+extern void SLOF_set_chosen_int(const char *s, long val);
+extern void SLOF_set_chosen_bytes(const char *s, const char *addr, size_t size);
extern void SLOF_encode_bootp_response(void *addr, size_t size);
extern void SLOF_encode_dhcp_response(void *addr, size_t size);
diff --git a/lib/libnet/netload.c b/lib/libnet/netload.c
index f06c2fd..8a38771 100644
--- a/lib/libnet/netload.c
+++ b/lib/libnet/netload.c
@@ -26,6 +26,7 @@
#include <helpers.h>
#include "args.h"
#include "netapps.h"
+#include "pxelinux.h"
#define IP_INIT_DEFAULT 5
#define IP_INIT_NONE 0
@@ -426,6 +427,75 @@ static int tftp_load(filename_ip_t *fnip, void *buffer, int len,
return rc;
}
+#define CFG_BUF_SIZE 2048
+#define MAX_PL_CFG_ENTRIES 16
+static int net_pxelinux_load(filename_ip_t *fnip, char *loadbase,
+ int maxloadlen, uint8_t *mac, int retries)
+{
+ struct pl_cfg_entry entries[MAX_PL_CFG_ENTRIES];
+ int def, rc, ilen;
+ static char *cfgbuf;
+
+ cfgbuf = malloc(CFG_BUF_SIZE);
+ if (!cfgbuf) {
+ puts("Not enough memory for pxelinux config file buffer!");
+ return -1;
+ }
+
+ rc = pxelinux_load_parse_cfg(fnip, mac, retries, cfgbuf, CFG_BUF_SIZE,
+ entries, MAX_PL_CFG_ENTRIES, &def);
+ if (rc < 0)
+ goto out_free;
+ if (rc == 0) {
+ puts("No valid entries in pxelinux config file.");
+ rc = -1;
+ goto out_free;
+ }
+
+ /* Load kernel */
+ strncpy(fnip->filename, entries[def].kernel,
+ sizeof(fnip->filename) - 1);
+ fnip->filename[sizeof(fnip->filename) - 1] = 0;
+ rc = tftp_load(fnip, loadbase, maxloadlen, retries);
+ if (rc <= 0)
+ goto out_free;
+
+ /* Load ramdisk */
+ if (entries[def].initrd) {
+ loadbase += rc;
+ maxloadlen -= rc;
+ if (maxloadlen <= 0) {
+ puts(" Not enough space for loading the initrd!");
+ rc = -1;
+ goto out_free;
+ }
+ strncpy(fnip->filename, entries[def].initrd,
+ sizeof(fnip->filename) - 1);
+ ilen = tftp_load(fnip, loadbase, maxloadlen, retries);
+ if (ilen < 0) {
+ rc = ilen;
+ goto out_free;
+ }
+ /* The ELF loader will move the kernel to some spot in low mem
+ * later, thus move the initrd to the end of the RAM instead */
+ memmove(loadbase + maxloadlen - ilen, loadbase, ilen);
+ /* Encode the initrd information in the device tree */
+ SLOF_set_chosen_int("linux,initrd-start",
+ (long)loadbase + maxloadlen - ilen);
+ SLOF_set_chosen_int("linux,initrd-end",
+ (long)loadbase + maxloadlen);
+ }
+
+ if (entries[def].append) {
+ SLOF_set_chosen_bytes("bootargs", entries[def].append,
+ strlen(entries[def].append) + 1);
+ }
+
+out_free:
+ free(cfgbuf);
+ return rc;
+}
+
static void encode_response(char *pkt_buffer, size_t size, int ip_init)
{
switch(ip_init) {
@@ -444,7 +514,7 @@ static void encode_response(char *pkt_buffer, size_t size, int ip_init)
int netload(char *buffer, int len, char *args_fs, int alen)
{
- int rc;
+ int rc, filename_len;
filename_ip_t fn_ip;
int fd_device;
obp_tftp_args_t obp_tftp_args;
@@ -687,7 +757,17 @@ int netload(char *buffer, int len, char *args_fs, int alen)
}
/* Do the TFTP load and print error message if necessary */
- rc = tftp_load(&fn_ip, buffer, len, obp_tftp_args.tftp_retries);
+ rc = 0;
+ filename_len = strlen(fn_ip.filename);
+ if (filename_len > 0 && fn_ip.filename[filename_len - 1] != '/') {
+ rc = tftp_load(&fn_ip, buffer, len, obp_tftp_args.tftp_retries);
+ }
+
+ if (rc <= 0 && !obp_tftp_args.filename[0] &&
+ (!filename_len || fn_ip.filename[filename_len - 1] == '/')) {
+ rc = net_pxelinux_load(&fn_ip, buffer, len, own_mac,
+ obp_tftp_args.tftp_retries);
+ }
if (obp_tftp_args.ip_init == IP_INIT_DHCP)
dhcp_send_release(fn_ip.fd);
diff --git a/slof/helpers.c b/slof/helpers.c
index a8d575c..bd0742e 100644
--- a/slof/helpers.c
+++ b/slof/helpers.c
@@ -181,7 +181,16 @@ int write_mm_log(char *data, unsigned int len, unsigned short type)
return forth_eval_pop("write-mm-log");
}
-static void SLOF_encode_response(void *addr, size_t size,char *s)
+void SLOF_set_chosen_int(const char *s, long val)
+{
+ forth_push(val);
+ forth_eval("encode-int");
+ forth_push((unsigned long)s);
+ forth_push(strlen(s));
+ forth_eval("set-chosen");
+}
+
+void SLOF_set_chosen_bytes(const char *s, const char *addr, size_t size)
{
forth_push((unsigned long)addr);
forth_push(size);
@@ -193,10 +202,10 @@ static void SLOF_encode_response(void *addr, size_t size,char *s)
void SLOF_encode_bootp_response(void *addr, size_t size)
{
- SLOF_encode_response(addr, size, "bootp-response");
+ SLOF_set_chosen_bytes("bootp-response", addr, size);
}
void SLOF_encode_dhcp_response(void *addr, size_t size)
{
- SLOF_encode_response(addr, size, "dhcp-response");
+ SLOF_set_chosen_bytes("dhcp-response", addr, size);
}