aboutsummaryrefslogtreecommitdiff
path: root/fw_cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'fw_cfg.c')
-rw-r--r--fw_cfg.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/fw_cfg.c b/fw_cfg.c
index 85a2639..329311a 100644
--- a/fw_cfg.c
+++ b/fw_cfg.c
@@ -4,6 +4,7 @@
#include "ioport.h"
#include "string.h"
#include "fw_cfg.h"
+#include "bswap.h"
#include "linuxboot.h"
#include "multiboot.h"
@@ -13,6 +14,7 @@ struct fw_cfg_file {
char name[57];
};
+static int version;
static int filecnt;
static struct fw_cfg_file *files;
@@ -20,6 +22,9 @@ void fw_cfg_setup(void)
{
int i, n;
+ fw_cfg_select(FW_CFG_ID);
+ version = fw_cfg_readl_le();
+
fw_cfg_select(FW_CFG_FILE_DIR);
n = fw_cfg_readl_be();
filecnt = n;
@@ -56,6 +61,48 @@ void fw_cfg_file_select(int id)
fw_cfg_select(files[id].select);
}
+void fw_cfg_read_file(int id, void *buf, int len)
+{
+ fw_cfg_read_entry(files[id].select, buf, len);
+}
+
+struct fw_cfg_dma_descriptor {
+ uint32_t control;
+ uint32_t length;
+ uint64_t address;
+} __attribute__((packed));
+
+void fw_cfg_dma(int control, void *buf, int len)
+{
+ volatile struct fw_cfg_dma_descriptor dma;
+ uint32_t dma_desc_addr;
+
+ dma.control = bswap32(control);
+ dma.length = bswap32(len);
+ dma.address = bswap64((uintptr_t)buf);
+
+ dma_desc_addr = (uint32_t)&dma;
+ outl(FW_CFG_DMA_ADDR_LOW, bswap32(dma_desc_addr));
+ while (bswap32(dma.control) & ~FW_CFG_DMA_CTL_ERROR) {
+ asm("");
+ }
+}
+
+void
+fw_cfg_read_entry(int e, void *buf, int len)
+{
+ if (version & FW_CFG_VERSION_DMA) {
+ int control;
+ control = (e << 16);
+ control |= FW_CFG_DMA_CTL_SELECT;
+ control |= FW_CFG_DMA_CTL_READ;
+ fw_cfg_dma(control, buf, len);
+ } else {
+ fw_cfg_select(e);
+ fw_cfg_read(buf, len);
+ }
+}
+
/* Multiboot trampoline. QEMU does the ELF parsing. */
static void boot_multiboot_from_fw_cfg(void)