aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <thierry.reding@avionic-design.de>2012-05-31 17:41:35 +0200
committerH. Peter Anvin <hpa@linux.intel.com>2012-06-29 14:42:11 -0700
commit1eb311caecf1452a78013640db828fd40c9055d2 (patch)
tree8ce54fa4a136ca50e81e050df3f222a3a25fa2de
parent8804b0e5eb2b64c6e49025f5599552e8f00d9c33 (diff)
downloadsyslinux-1eb311caecf1452a78013640db828fd40c9055d2.tar.gz
syslinux-1eb311caecf1452a78013640db828fd40c9055d2.tar.xz
syslinux-1eb311caecf1452a78013640db828fd40c9055d2.zip
com32: Add device tree support
This commit adds support for passing a Flattened Device Tree (FDT) blob to the Linux kernel. Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--com32/gfxboot/gfxboot.c2
-rw-r--r--com32/include/syslinux/linux.h25
-rw-r--r--com32/lib/Makefile4
-rw-r--r--com32/lib/syslinux/fdt.c28
-rw-r--r--com32/lib/syslinux/load_linux.c41
-rw-r--r--com32/lua/src/syslinux.c4
6 files changed, 98 insertions, 6 deletions
diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c
index 35d180a6..aa05caf8 100644
--- a/com32/gfxboot/gfxboot.c
+++ b/com32/gfxboot/gfxboot.c
@@ -962,7 +962,7 @@ void boot_entry(menu_t *menu_ptr, char *arg)
gfx_done();
- syslinux_boot_linux(kernel, kernel_size, initrd, arg);
+ syslinux_boot_linux(kernel, kernel_size, initrd, NULL, arg);
}
diff --git a/com32/include/syslinux/linux.h b/com32/include/syslinux/linux.h
index 754d1b64..6a5c2dbb 100644
--- a/com32/include/syslinux/linux.h
+++ b/com32/include/syslinux/linux.h
@@ -51,8 +51,26 @@ struct initramfs {
};
#define INITRAMFS_MAX_ALIGN 4096
+struct fdt {
+ void *data;
+ size_t len;
+};
+#define DEVICETREE_MAX_ALIGN 4096
+
+struct setup_data {
+ uint64_t next;
+ uint32_t type;
+ uint32_t len;
+ uint8_t data[0];
+};
+
+#define SETUP_NONE 0
+#define SETUP_E820_EXT 1
+#define SETUP_DTB 2
+
int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs, char *cmdline);
+ struct initramfs *initramfs, struct fdt *fdt,
+ char *cmdline);
/* Initramfs manipulation functions */
@@ -70,4 +88,9 @@ int initramfs_load_file(struct initramfs *ihead, const char *src_filename,
int initramfs_add_trailer(struct initramfs *ihead);
int initramfs_load_archive(struct initramfs *ihead, const char *filename);
+/* Device Tree manipulation functions */
+
+struct fdt *fdt_init(void);
+int fdt_load(struct fdt *fdt, const char *filename);
+
#endif /* _SYSLINUX_LINUX_H */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index eace321b..a4959f6f 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -129,7 +129,9 @@ LIBOBJS = \
syslinux/video/fontquery.o syslinux/video/forcetext.o \
syslinux/video/reportmode.o \
\
- syslinux/disk.o
+ syslinux/disk.o \
+ \
+ syslinux/fdt.o
# These are the objects which are also imported into the core
LIBCOREOBJS = \
diff --git a/com32/lib/syslinux/fdt.c b/com32/lib/syslinux/fdt.c
new file mode 100644
index 00000000..1bcd90b9
--- /dev/null
+++ b/com32/lib/syslinux/fdt.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+#include <syslinux/linux.h>
+#include <syslinux/loadfile.h>
+
+struct fdt *fdt_init(void)
+{
+ struct fdt *fdt;
+
+ fdt = calloc(1, sizeof(*fdt));
+ if (!fdt)
+ return NULL;
+
+ return fdt;
+}
+
+int fdt_load(struct fdt *fdt, const char *filename)
+{
+ void *data;
+ size_t len;
+
+ if (loadfile(filename, &data, &len))
+ return -1;
+
+ fdt->data = data;
+ fdt->len = len;
+
+ return 0;
+}
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index 45cd6965..b68aef7b 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -180,7 +180,8 @@ static int map_initramfs(struct syslinux_movelist **fraglist,
}
int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs, char *cmdline)
+ struct initramfs *initramfs, struct fdt *fdt,
+ char *cmdline)
{
struct linux_header hdr, *whdr;
size_t real_mode_size, prot_mode_size;
@@ -449,6 +450,44 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
}
}
+ if (fdt && fdt->len > 0) {
+ const addr_t align_mask = DEVICETREE_MAX_ALIGN - 1;
+ struct syslinux_memmap *ml;
+ struct setup_data *setup;
+ addr_t best_addr = 0;
+ size_t size;
+
+ size = sizeof(*setup) + fdt->len;
+
+ setup = malloc(size);
+ if (!setup)
+ goto bail;
+
+ setup->next = 0;
+ setup->type = SETUP_DTB;
+ setup->len = fdt->len;
+ memcpy(setup->data, fdt->data, fdt->len);
+
+ for (ml = amap; ml->type != SMT_END; ml = ml->next) {
+ addr_t adj_start = (ml->start + align_mask) & ~align_mask;
+ addr_t adj_end = ml->next->start & ~align_mask;
+
+ if (ml->type == SMT_FREE && adj_end - adj_start >= size)
+ best_addr = (adj_end - size) & ~align_mask;
+ }
+
+ if (!best_addr)
+ goto bail;
+
+ whdr->setup_data = best_addr;
+
+ if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC))
+ goto bail;
+
+ if (syslinux_add_movelist(&fraglist, best_addr, (addr_t) setup, size))
+ goto bail;
+ }
+
/* Set up the registers on entry */
memset(&regs, 0, sizeof regs);
regs.es = regs.ds = regs.ss = regs.fs = regs.gs = real_mode_base >> 4;
diff --git a/com32/lua/src/syslinux.c b/com32/lua/src/syslinux.c
index 9b207db7..af5db834 100644
--- a/com32/lua/src/syslinux.c
+++ b/com32/lua/src/syslinux.c
@@ -278,7 +278,7 @@ static int sl_boot_linux(lua_State * L)
msleep(10000);
*/
- ret = syslinux_boot_linux(kernel_data, kernel_len, initramfs, newcmdline);
+ ret = syslinux_boot_linux(kernel_data, kernel_len, initramfs, NULL, newcmdline);
printf("syslinux_boot_linux returned %d\n", ret);
@@ -405,7 +405,7 @@ static int sl_boot_it(lua_State * L)
(void)mem_limit;
return syslinux_boot_linux(kernel->data, kernel->size,
- initramfs, (char *)cmdline);
+ initramfs, NULL, (char *)cmdline);
}
static int sl_derivative(lua_State * L)