-
Notifications
You must be signed in to change notification settings - Fork 0
/
qemu_dma.c
111 lines (87 loc) · 3.23 KB
/
qemu_dma.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include "qemu_dma.h"
#include "serial.h"
int memcmp_str(void *str1, void *str2, uint64_t count) {
unsigned char *s1 = (unsigned char*)str1;
unsigned char *s2 = (unsigned char*)str2;
while (count-- > 0) {
if (*s1++ != *s2++)
return s1[-1] < s2[-1] ? -1 : 1;
}
return 0;
}
static void mmio_write_bsw64(uint64_t addr, uint64_t val) {
volatile uint64_t *mmio_w = (volatile uint64_t*)addr;
*mmio_w = __builtin_bswap64(val);
}
static void mmio_write64(uint64_t addr, uint64_t val) {
volatile uint64_t *mmio_w = (volatile uint64_t*)addr;
*mmio_w = val;
}
static void mmio_write_bsw16(uint64_t addr, uint16_t val) {
volatile uint16_t *mmio_w = (volatile uint16_t*)addr;
*mmio_w = __builtin_bswap16(val);
}
static void mmio_write16(uint64_t addr, uint16_t val) {
volatile uint16_t *mmio_w = (volatile uint16_t*)addr;
*mmio_w = val;
}
static uint64_t mmio_read_bsw64(uint64_t addr) {
return __builtin_bswap64(*((volatile uint64_t*)addr));
}
static uint64_t mmio_read64(uint64_t addr) {
return *((volatile uint64_t*)addr);
}
static uint16_t mmio_read_bsw16(uint64_t addr) {
return __builtin_bswap16(*((volatile uint16_t*)addr));
}
static uint16_t mmio_read16(uint64_t addr) {
return *((volatile uint16_t*)addr);
}
static uint16_t mmio_read_bsw32(uint64_t addr) {
return __builtin_bswap32(*((volatile uint32_t*)addr));
}
static uint16_t mmio_read32(uint64_t addr) {
return *((volatile uint32_t*)addr);
}
static void qemu_cfg_dma_transfer(void *address, uint32_t length, uint32_t control) {
QemuCfgDmaAccess access = { .address = __builtin_bswap64((uint64_t)address), .length = __builtin_bswap32(length), .control = __builtin_bswap32(control) };
if (length == 0) {
return;
}
__asm__("ISB");
mmio_write_bsw64(BASE_ADDR_ADDR, (uint64_t)&access);
while(__builtin_bswap32(access.control) & ~QEMU_CFG_DMA_CTL_ERROR) {}
}
static void qemu_cfg_read(void *buf, int len) {
qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_READ);
}
static void qemu_cfg_read_entry(void *buf, int e, int len) {
uint32_t control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT | QEMU_CFG_DMA_CTL_READ;
qemu_cfg_dma_transfer(buf, len, control);
}
void qemu_cfg_write_entry(void *buf, uint32_t e, uint32_t len) {
uint32_t control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT | QEMU_CFG_DMA_CTL_WRITE;
qemu_cfg_dma_transfer(buf, len, control);
}
int qemu_cfg_find_file() {
uint32_t count, e, select;
qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
count = __builtin_bswap32(count);
for (select = 0, e = 0; e < count; e++) {
struct QemuCfgFile qfile;
qemu_cfg_read(&qfile, sizeof(qfile));
if (memcmp_str(qfile.name, "etc/ramfb", 10) == 0)
select = __builtin_bswap16(qfile.select);
}
return select;
}
int check_fw_cfg_dma() {
mmio_write16(BASE_ADDR_SELECTOR, 0x0000);
union FwCfgSigRead cfg_sig_read;
cfg_sig_read.theInt = *((volatile uint32_t*)BASE_ADDR_DATA);
if (cfg_sig_read.bytes[0] == 'Q' && cfg_sig_read.bytes[1] == 'E' && cfg_sig_read.bytes[2] == 'M' && cfg_sig_read.bytes[3] == 'U') {
if (mmio_read_bsw64(BASE_ADDR_ADDR) == 0x51454d5520434647) {
return 1;
}
} return 0;
}