diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2016-09-06 15:05:08 +0200 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2016-09-06 15:57:15 +0200 |
commit | 14b459a6f9c9c02a0901a8a3de5e7c706305ffdd (patch) | |
tree | 0cdc0dc8eff9dcc73c8b1d40cbe635342b6738c3 /fw_cfg.c | |
parent | 96dbb2c0a24fdc6bbe4d8d834f0b879e01fdcae3 (diff) | |
download | qboot-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.c | 47 |
1 files changed, 47 insertions, 0 deletions
@@ -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) |