aboutsummaryrefslogtreecommitdiff
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
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>
-rw-r--r--cbfs.c15
-rw-r--r--fw_cfg.c47
-rw-r--r--include/bswap.h29
-rw-r--r--include/fw_cfg.h31
4 files changed, 93 insertions, 29 deletions
diff --git a/cbfs.c b/cbfs.c
index 6c6a8cf..b4c235e 100644
--- a/cbfs.c
+++ b/cbfs.c
@@ -2,6 +2,7 @@
#include "stdio.h"
#include "ioport.h"
#include "string.h"
+#include "bswap.h"
#include "linuxboot.h"
#define CBFS_HEADER_MAGIC 0x4F524243 // ORBC
@@ -38,20 +39,6 @@ struct cbfs_file {
static struct cbfs_file *files;
-static inline uint32_t ldl_le_p(const void *p)
-{
- uint32_t val;
- memcpy(&val, p, 4);
- return val;
-}
-
-static inline uint32_t ldl_be_p(const void *p)
-{
- uint32_t val;
- memcpy(&val, p, 4);
- return __builtin_bswap32(val);
-}
-
static bool cbfs_setup(const char *base, size_t sz)
{
uint32_t ofs;
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)
diff --git a/include/bswap.h b/include/bswap.h
new file mode 100644
index 0000000..2a72bd0
--- /dev/null
+++ b/include/bswap.h
@@ -0,0 +1,29 @@
+#ifndef BSWAP_H
+#define BSWAP_H 1
+
+static inline uint32_t bswap32(uint32_t x)
+{
+ return __builtin_bswap32(x);
+}
+
+static inline uint64_t bswap64(uint64_t x)
+{
+ return __builtin_bswap64(x);
+}
+
+static inline uint32_t ldl_le_p(const void *p)
+{
+ uint32_t val;
+ memcpy(&val, p, 4);
+ return val;
+}
+
+static inline uint32_t ldl_be_p(const void *p)
+{
+ uint32_t val;
+ memcpy(&val, p, 4);
+ return bswap32(val);
+}
+
+
+#endif
diff --git a/include/fw_cfg.h b/include/fw_cfg.h
index 46fa869..52ed4e3 100644
--- a/include/fw_cfg.h
+++ b/include/fw_cfg.h
@@ -36,8 +36,18 @@
#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
-#define FW_CFG_CTL 0x510
-#define FW_CFG_DATA 0x511
+#define FW_CFG_VERSION 0x01
+#define FW_CFG_VERSION_DMA 0x02
+
+#define FW_CFG_DMA_CTL_ERROR 0x01
+#define FW_CFG_DMA_CTL_READ 0x02
+#define FW_CFG_DMA_CTL_SKIP 0x04
+#define FW_CFG_DMA_CTL_SELECT 0x08
+
+#define FW_CFG_CTL 0x510
+#define FW_CFG_DATA 0x511
+#define FW_CFG_DMA_ADDR_HIGH 0x514
+#define FW_CFG_DMA_ADDR_LOW 0x518
#include "ioport.h"
@@ -102,23 +112,14 @@ static inline void fw_cfg_skip(int len)
inb(FW_CFG_DATA);
}
-static inline void
-fw_cfg_read_entry(int e, void *buf, int len)
-{
- fw_cfg_select(e);
- fw_cfg_read(buf, len);
-}
-
void fw_cfg_setup(void);
int fw_cfg_file_id(char *name);
uint32_t fw_cfg_file_size(int id);
void fw_cfg_file_select(int id);
-static inline void
-fw_cfg_read_file(int id, void *buf, int len)
-{
- fw_cfg_file_select(id);
- fw_cfg_read(buf, len);
-}
+void fw_cfg_read(void *buf, int len);
+void fw_cfg_read_entry(int e, void *buf, int len);
+void fw_cfg_dma(int control, void *buf, int len);
+void fw_cfg_read_file(int e, void *buf, int len);
#endif