aboutsummaryrefslogtreecommitdiff
path: root/fw_cfg.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2016-09-06 15:05:08 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2016-09-06 15:57:15 +0200
commit14b459a6f9c9c02a0901a8a3de5e7c706305ffdd (patch)
tree0cdc0dc8eff9dcc73c8b1d40cbe635342b6738c3 /fw_cfg.c
parent96dbb2c0a24fdc6bbe4d8d834f0b879e01fdcae3 (diff)
downloadqboot-14b459a6f9c9c02a0901a8a3de5e7c706305ffdd.zip
qboot-14b459a6f9c9c02a0901a8a3de5e7c706305ffdd.tar.gz
qboot-14b459a6f9c9c02a0901a8a3de5e7c706305ffdd.tar.bz2
use fw_cfg DMA for fw_cfg_read_entry
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
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)