diff options
-rw-r--r-- | cbfs.c | 15 | ||||
-rw-r--r-- | fw_cfg.c | 47 | ||||
-rw-r--r-- | include/bswap.h | 29 | ||||
-rw-r--r-- | include/fw_cfg.h | 31 |
4 files changed, 93 insertions, 29 deletions
@@ -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; @@ -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 |