acpi.pci,pc,memory core fixes
Most notably this includes changes to exec to support full 64 bit addresses. This also flushes out patches that got queued during 1.7 freeze. There are new tests, and a bunch of bug fixes all over the place. There are also some changes mostly useful for downstreams. I'm also listing myself as pc co-maintainer. I'm doing this reluctantly, but this seems to be necessary to make sure patches are not lost or delayed too much, and posting the MAINTAINERS patch did not seem to make anyone else volunteer. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.15 (GNU/Linux) iQEcBAABAgAGBQJSqK0/AAoJECgfDbjSjVRpz0wH/2BCUmgQ8oZfe9PrRhdCpYbw 6RtDLVucIUNq3CYfeV+Lua1Dw62CPVNGUR1Y2sk9s5X0C/lHLXeUkZxYy0JezGmW k0EZAcVC4kXqyPbVh83I2pKtTwLGfI6I1qzsLZc+6CDT34YN7Lwe+wRJXQQNGcJc gEbe4U8xuufdPZO2zv9RWEwmI4tI38PxnDJw+MYNJOKNnweLBRKq10YEKrref7Ml 4O1GxAXfQd0wkAhr9Cm7ZBajOzy/ovLj/b7HmiCMOvGkOaVhzurqbOtxlsbVIF9T 26+HEhu+2H/NO4qk5VmZjSngayUySBdEbGLHiovd8Xl4zMFPFNfQXv1mR3Vzb20= =GPZ/ -----END PGP SIGNATURE----- Merge remote-tracking branch 'mst/tags/for_anthony' into staging acpi.pci,pc,memory core fixes Most notably this includes changes to exec to support full 64 bit addresses. This also flushes out patches that got queued during 1.7 freeze. There are new tests, and a bunch of bug fixes all over the place. There are also some changes mostly useful for downstreams. I'm also listing myself as pc co-maintainer. I'm doing this reluctantly, but this seems to be necessary to make sure patches are not lost or delayed too much, and posting the MAINTAINERS patch did not seem to make anyone else volunteer. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Wed 11 Dec 2013 10:21:51 AM PST using RSA key ID D28D5469 # gpg: Can't check signature: public key not found # By Michael S. Tsirkin (14) and others # Via Michael S. Tsirkin * mst/tags/for_anthony: (28 commits) pc: use macro for HPET type hpet: fix build with CONFIG_HPET off acpi unit-test: adjust the test data structure for better handling acpi unit-test: load and check facs table exec: separate sections and nodes per address space memory.c: bugfix - ref counting mismatch in memory_region_find hpet: enable to entitle more irq pins for hpet hpet: inverse polarity when pin above ISA_NUM_IRQS pci: fix pci bridge fw path ACPI DSDT: Make control method `IQCR` serialized acpi: strip compiler info in built-in DSDT acpi unit-test: verify signature and checksum smbios: Set system manufacturer, product & version by default exec: reduce L2_PAGE_SIZE exec: make address spaces 64-bit wide exec: memory radix tree page level compression exec: pass hw address to phys_page_find exec: extend skip field to 6 bit, page entry to 32 bit exec: replace leaf with skip split definitions for exec.c and translate-all.c radix trees ... Message-id: cover.1386786228.git.mst@redhat.com Signed-off-by: Anthony Liguori <aliguori@amazon.com>
This commit is contained in:
commit
5d0e2280cc
18
MAINTAINERS
18
MAINTAINERS
@ -500,9 +500,23 @@ X86 Machines
|
||||
------------
|
||||
PC
|
||||
M: Anthony Liguori <aliguori@amazon.com>
|
||||
M: Michael S. Tsirkin <mst@redhat.com>
|
||||
S: Supported
|
||||
F: hw/i386/pc.[ch]
|
||||
F: hw/i386/pc_piix.c
|
||||
F: include/hw/i386/
|
||||
F: hw/i386/
|
||||
F: hw/pci-host/piix.c
|
||||
F: hw/pci-host/q35.c
|
||||
F: hw/pci-host/pam.c
|
||||
F: include/hw/pci-host/q35.h
|
||||
F: include/hw/pci-host/pam.h
|
||||
F: hw/isa/piix4.c
|
||||
F: hw/isa/lpc_ich9.c
|
||||
F: hw/i2c/smbus_ich9.c
|
||||
F: hw/acpi/piix4.c
|
||||
F: hw/acpi/ich9.c
|
||||
F: include/hw/acpi/ich9.h
|
||||
F: include/hw/acpi/piix.h
|
||||
|
||||
|
||||
Xtensa Machines
|
||||
---------------
|
||||
|
280
exec.c
280
exec.c
@ -51,6 +51,8 @@
|
||||
|
||||
#include "exec/memory-internal.h"
|
||||
|
||||
#include "qemu/range.h"
|
||||
|
||||
//#define DEBUG_SUBPAGE
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
@ -83,20 +85,39 @@ int use_icount;
|
||||
typedef struct PhysPageEntry PhysPageEntry;
|
||||
|
||||
struct PhysPageEntry {
|
||||
uint16_t is_leaf : 1;
|
||||
/* index into phys_sections (is_leaf) or phys_map_nodes (!is_leaf) */
|
||||
uint16_t ptr : 15;
|
||||
/* How many bits skip to next level (in units of L2_SIZE). 0 for a leaf. */
|
||||
uint32_t skip : 6;
|
||||
/* index into phys_sections (!skip) or phys_map_nodes (skip) */
|
||||
uint32_t ptr : 26;
|
||||
};
|
||||
|
||||
typedef PhysPageEntry Node[L2_SIZE];
|
||||
#define PHYS_MAP_NODE_NIL (((uint32_t)~0) >> 6)
|
||||
|
||||
/* Size of the L2 (and L3, etc) page tables. */
|
||||
#define ADDR_SPACE_BITS 64
|
||||
|
||||
#define P_L2_BITS 9
|
||||
#define P_L2_SIZE (1 << P_L2_BITS)
|
||||
|
||||
#define P_L2_LEVELS (((ADDR_SPACE_BITS - TARGET_PAGE_BITS - 1) / P_L2_BITS) + 1)
|
||||
|
||||
typedef PhysPageEntry Node[P_L2_SIZE];
|
||||
|
||||
typedef struct PhysPageMap {
|
||||
unsigned sections_nb;
|
||||
unsigned sections_nb_alloc;
|
||||
unsigned nodes_nb;
|
||||
unsigned nodes_nb_alloc;
|
||||
Node *nodes;
|
||||
MemoryRegionSection *sections;
|
||||
} PhysPageMap;
|
||||
|
||||
struct AddressSpaceDispatch {
|
||||
/* This is a multi-level map on the physical address space.
|
||||
* The bottom level has pointers to MemoryRegionSections.
|
||||
*/
|
||||
PhysPageEntry phys_map;
|
||||
Node *nodes;
|
||||
MemoryRegionSection *sections;
|
||||
PhysPageMap map;
|
||||
AddressSpace *as;
|
||||
};
|
||||
|
||||
@ -113,20 +134,6 @@ typedef struct subpage_t {
|
||||
#define PHYS_SECTION_ROM 2
|
||||
#define PHYS_SECTION_WATCH 3
|
||||
|
||||
typedef struct PhysPageMap {
|
||||
unsigned sections_nb;
|
||||
unsigned sections_nb_alloc;
|
||||
unsigned nodes_nb;
|
||||
unsigned nodes_nb_alloc;
|
||||
Node *nodes;
|
||||
MemoryRegionSection *sections;
|
||||
} PhysPageMap;
|
||||
|
||||
static PhysPageMap *prev_map;
|
||||
static PhysPageMap next_map;
|
||||
|
||||
#define PHYS_MAP_NODE_NIL (((uint16_t)~0) >> 1)
|
||||
|
||||
static void io_mem_init(void);
|
||||
static void memory_map_init(void);
|
||||
|
||||
@ -135,63 +142,60 @@ static MemoryRegion io_mem_watch;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
||||
static void phys_map_node_reserve(unsigned nodes)
|
||||
static void phys_map_node_reserve(PhysPageMap *map, unsigned nodes)
|
||||
{
|
||||
if (next_map.nodes_nb + nodes > next_map.nodes_nb_alloc) {
|
||||
next_map.nodes_nb_alloc = MAX(next_map.nodes_nb_alloc * 2,
|
||||
16);
|
||||
next_map.nodes_nb_alloc = MAX(next_map.nodes_nb_alloc,
|
||||
next_map.nodes_nb + nodes);
|
||||
next_map.nodes = g_renew(Node, next_map.nodes,
|
||||
next_map.nodes_nb_alloc);
|
||||
if (map->nodes_nb + nodes > map->nodes_nb_alloc) {
|
||||
map->nodes_nb_alloc = MAX(map->nodes_nb_alloc * 2, 16);
|
||||
map->nodes_nb_alloc = MAX(map->nodes_nb_alloc, map->nodes_nb + nodes);
|
||||
map->nodes = g_renew(Node, map->nodes, map->nodes_nb_alloc);
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t phys_map_node_alloc(void)
|
||||
static uint32_t phys_map_node_alloc(PhysPageMap *map)
|
||||
{
|
||||
unsigned i;
|
||||
uint16_t ret;
|
||||
uint32_t ret;
|
||||
|
||||
ret = next_map.nodes_nb++;
|
||||
ret = map->nodes_nb++;
|
||||
assert(ret != PHYS_MAP_NODE_NIL);
|
||||
assert(ret != next_map.nodes_nb_alloc);
|
||||
for (i = 0; i < L2_SIZE; ++i) {
|
||||
next_map.nodes[ret][i].is_leaf = 0;
|
||||
next_map.nodes[ret][i].ptr = PHYS_MAP_NODE_NIL;
|
||||
assert(ret != map->nodes_nb_alloc);
|
||||
for (i = 0; i < P_L2_SIZE; ++i) {
|
||||
map->nodes[ret][i].skip = 1;
|
||||
map->nodes[ret][i].ptr = PHYS_MAP_NODE_NIL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void phys_page_set_level(PhysPageEntry *lp, hwaddr *index,
|
||||
hwaddr *nb, uint16_t leaf,
|
||||
static void phys_page_set_level(PhysPageMap *map, PhysPageEntry *lp,
|
||||
hwaddr *index, hwaddr *nb, uint16_t leaf,
|
||||
int level)
|
||||
{
|
||||
PhysPageEntry *p;
|
||||
int i;
|
||||
hwaddr step = (hwaddr)1 << (level * L2_BITS);
|
||||
hwaddr step = (hwaddr)1 << (level * P_L2_BITS);
|
||||
|
||||
if (!lp->is_leaf && lp->ptr == PHYS_MAP_NODE_NIL) {
|
||||
lp->ptr = phys_map_node_alloc();
|
||||
p = next_map.nodes[lp->ptr];
|
||||
if (lp->skip && lp->ptr == PHYS_MAP_NODE_NIL) {
|
||||
lp->ptr = phys_map_node_alloc(map);
|
||||
p = map->nodes[lp->ptr];
|
||||
if (level == 0) {
|
||||
for (i = 0; i < L2_SIZE; i++) {
|
||||
p[i].is_leaf = 1;
|
||||
for (i = 0; i < P_L2_SIZE; i++) {
|
||||
p[i].skip = 0;
|
||||
p[i].ptr = PHYS_SECTION_UNASSIGNED;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p = next_map.nodes[lp->ptr];
|
||||
p = map->nodes[lp->ptr];
|
||||
}
|
||||
lp = &p[(*index >> (level * L2_BITS)) & (L2_SIZE - 1)];
|
||||
lp = &p[(*index >> (level * P_L2_BITS)) & (P_L2_SIZE - 1)];
|
||||
|
||||
while (*nb && lp < &p[L2_SIZE]) {
|
||||
while (*nb && lp < &p[P_L2_SIZE]) {
|
||||
if ((*index & (step - 1)) == 0 && *nb >= step) {
|
||||
lp->is_leaf = true;
|
||||
lp->skip = 0;
|
||||
lp->ptr = leaf;
|
||||
*index += step;
|
||||
*nb -= step;
|
||||
} else {
|
||||
phys_page_set_level(lp, index, nb, leaf, level - 1);
|
||||
phys_page_set_level(map, lp, index, nb, leaf, level - 1);
|
||||
}
|
||||
++lp;
|
||||
}
|
||||
@ -202,25 +206,95 @@ static void phys_page_set(AddressSpaceDispatch *d,
|
||||
uint16_t leaf)
|
||||
{
|
||||
/* Wildly overreserve - it doesn't matter much. */
|
||||
phys_map_node_reserve(3 * P_L2_LEVELS);
|
||||
phys_map_node_reserve(&d->map, 3 * P_L2_LEVELS);
|
||||
|
||||
phys_page_set_level(&d->phys_map, &index, &nb, leaf, P_L2_LEVELS - 1);
|
||||
phys_page_set_level(&d->map, &d->phys_map, &index, &nb, leaf, P_L2_LEVELS - 1);
|
||||
}
|
||||
|
||||
static MemoryRegionSection *phys_page_find(PhysPageEntry lp, hwaddr index,
|
||||
Node *nodes, MemoryRegionSection *sections)
|
||||
/* Compact a non leaf page entry. Simply detect that the entry has a single child,
|
||||
* and update our entry so we can skip it and go directly to the destination.
|
||||
*/
|
||||
static void phys_page_compact(PhysPageEntry *lp, Node *nodes, unsigned long *compacted)
|
||||
{
|
||||
unsigned valid_ptr = P_L2_SIZE;
|
||||
int valid = 0;
|
||||
PhysPageEntry *p;
|
||||
int i;
|
||||
|
||||
for (i = P_L2_LEVELS - 1; i >= 0 && !lp.is_leaf; i--) {
|
||||
if (lp->ptr == PHYS_MAP_NODE_NIL) {
|
||||
return;
|
||||
}
|
||||
|
||||
p = nodes[lp->ptr];
|
||||
for (i = 0; i < P_L2_SIZE; i++) {
|
||||
if (p[i].ptr == PHYS_MAP_NODE_NIL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
valid_ptr = i;
|
||||
valid++;
|
||||
if (p[i].skip) {
|
||||
phys_page_compact(&p[i], nodes, compacted);
|
||||
}
|
||||
}
|
||||
|
||||
/* We can only compress if there's only one child. */
|
||||
if (valid != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(valid_ptr < P_L2_SIZE);
|
||||
|
||||
/* Don't compress if it won't fit in the # of bits we have. */
|
||||
if (lp->skip + p[valid_ptr].skip >= (1 << 3)) {
|
||||
return;
|
||||
}
|
||||
|
||||
lp->ptr = p[valid_ptr].ptr;
|
||||
if (!p[valid_ptr].skip) {
|
||||
/* If our only child is a leaf, make this a leaf. */
|
||||
/* By design, we should have made this node a leaf to begin with so we
|
||||
* should never reach here.
|
||||
* But since it's so simple to handle this, let's do it just in case we
|
||||
* change this rule.
|
||||
*/
|
||||
lp->skip = 0;
|
||||
} else {
|
||||
lp->skip += p[valid_ptr].skip;
|
||||
}
|
||||
}
|
||||
|
||||
static void phys_page_compact_all(AddressSpaceDispatch *d, int nodes_nb)
|
||||
{
|
||||
DECLARE_BITMAP(compacted, nodes_nb);
|
||||
|
||||
if (d->phys_map.skip) {
|
||||
phys_page_compact(&d->phys_map, d->map.nodes, compacted);
|
||||
}
|
||||
}
|
||||
|
||||
static MemoryRegionSection *phys_page_find(PhysPageEntry lp, hwaddr addr,
|
||||
Node *nodes, MemoryRegionSection *sections)
|
||||
{
|
||||
PhysPageEntry *p;
|
||||
hwaddr index = addr >> TARGET_PAGE_BITS;
|
||||
int i;
|
||||
|
||||
for (i = P_L2_LEVELS; lp.skip && (i -= lp.skip) >= 0;) {
|
||||
if (lp.ptr == PHYS_MAP_NODE_NIL) {
|
||||
return §ions[PHYS_SECTION_UNASSIGNED];
|
||||
}
|
||||
p = nodes[lp.ptr];
|
||||
lp = p[(index >> (i * L2_BITS)) & (L2_SIZE - 1)];
|
||||
lp = p[(index >> (i * P_L2_BITS)) & (P_L2_SIZE - 1)];
|
||||
}
|
||||
|
||||
if (sections[lp.ptr].size.hi ||
|
||||
range_covers_byte(sections[lp.ptr].offset_within_address_space,
|
||||
sections[lp.ptr].size.lo, addr)) {
|
||||
return §ions[lp.ptr];
|
||||
} else {
|
||||
return §ions[PHYS_SECTION_UNASSIGNED];
|
||||
}
|
||||
return §ions[lp.ptr];
|
||||
}
|
||||
|
||||
bool memory_region_is_unassigned(MemoryRegion *mr)
|
||||
@ -236,11 +310,10 @@ static MemoryRegionSection *address_space_lookup_region(AddressSpaceDispatch *d,
|
||||
MemoryRegionSection *section;
|
||||
subpage_t *subpage;
|
||||
|
||||
section = phys_page_find(d->phys_map, addr >> TARGET_PAGE_BITS,
|
||||
d->nodes, d->sections);
|
||||
section = phys_page_find(d->phys_map, addr, d->map.nodes, d->map.sections);
|
||||
if (resolve_subpage && section->mr->subpage) {
|
||||
subpage = container_of(section->mr, subpage_t, iomem);
|
||||
section = &d->sections[subpage->sub_section[SUBPAGE_IDX(addr)]];
|
||||
section = &d->map.sections[subpage->sub_section[SUBPAGE_IDX(addr)]];
|
||||
}
|
||||
return section;
|
||||
}
|
||||
@ -708,7 +781,7 @@ hwaddr memory_region_section_get_iotlb(CPUArchState *env,
|
||||
iotlb |= PHYS_SECTION_ROM;
|
||||
}
|
||||
} else {
|
||||
iotlb = section - address_space_memory.dispatch->sections;
|
||||
iotlb = section - address_space_memory.dispatch->map.sections;
|
||||
iotlb += xlat;
|
||||
}
|
||||
|
||||
@ -747,23 +820,23 @@ void phys_mem_set_alloc(void *(*alloc)(size_t))
|
||||
phys_mem_alloc = alloc;
|
||||
}
|
||||
|
||||
static uint16_t phys_section_add(MemoryRegionSection *section)
|
||||
static uint16_t phys_section_add(PhysPageMap *map,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
/* The physical section number is ORed with a page-aligned
|
||||
* pointer to produce the iotlb entries. Thus it should
|
||||
* never overflow into the page-aligned value.
|
||||
*/
|
||||
assert(next_map.sections_nb < TARGET_PAGE_SIZE);
|
||||
assert(map->sections_nb < TARGET_PAGE_SIZE);
|
||||
|
||||
if (next_map.sections_nb == next_map.sections_nb_alloc) {
|
||||
next_map.sections_nb_alloc = MAX(next_map.sections_nb_alloc * 2,
|
||||
16);
|
||||
next_map.sections = g_renew(MemoryRegionSection, next_map.sections,
|
||||
next_map.sections_nb_alloc);
|
||||
if (map->sections_nb == map->sections_nb_alloc) {
|
||||
map->sections_nb_alloc = MAX(map->sections_nb_alloc * 2, 16);
|
||||
map->sections = g_renew(MemoryRegionSection, map->sections,
|
||||
map->sections_nb_alloc);
|
||||
}
|
||||
next_map.sections[next_map.sections_nb] = *section;
|
||||
map->sections[map->sections_nb] = *section;
|
||||
memory_region_ref(section->mr);
|
||||
return next_map.sections_nb++;
|
||||
return map->sections_nb++;
|
||||
}
|
||||
|
||||
static void phys_section_destroy(MemoryRegion *mr)
|
||||
@ -785,7 +858,6 @@ static void phys_sections_free(PhysPageMap *map)
|
||||
}
|
||||
g_free(map->sections);
|
||||
g_free(map->nodes);
|
||||
g_free(map);
|
||||
}
|
||||
|
||||
static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *section)
|
||||
@ -793,8 +865,8 @@ static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *secti
|
||||
subpage_t *subpage;
|
||||
hwaddr base = section->offset_within_address_space
|
||||
& TARGET_PAGE_MASK;
|
||||
MemoryRegionSection *existing = phys_page_find(d->phys_map, base >> TARGET_PAGE_BITS,
|
||||
next_map.nodes, next_map.sections);
|
||||
MemoryRegionSection *existing = phys_page_find(d->phys_map, base,
|
||||
d->map.nodes, d->map.sections);
|
||||
MemoryRegionSection subsection = {
|
||||
.offset_within_address_space = base,
|
||||
.size = int128_make64(TARGET_PAGE_SIZE),
|
||||
@ -807,13 +879,14 @@ static void register_subpage(AddressSpaceDispatch *d, MemoryRegionSection *secti
|
||||
subpage = subpage_init(d->as, base);
|
||||
subsection.mr = &subpage->iomem;
|
||||
phys_page_set(d, base >> TARGET_PAGE_BITS, 1,
|
||||
phys_section_add(&subsection));
|
||||
phys_section_add(&d->map, &subsection));
|
||||
} else {
|
||||
subpage = container_of(existing->mr, subpage_t, iomem);
|
||||
}
|
||||
start = section->offset_within_address_space & ~TARGET_PAGE_MASK;
|
||||
end = start + int128_get64(section->size) - 1;
|
||||
subpage_register(subpage, start, end, phys_section_add(section));
|
||||
subpage_register(subpage, start, end,
|
||||
phys_section_add(&d->map, section));
|
||||
}
|
||||
|
||||
|
||||
@ -821,7 +894,7 @@ static void register_multipage(AddressSpaceDispatch *d,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
hwaddr start_addr = section->offset_within_address_space;
|
||||
uint16_t section_index = phys_section_add(section);
|
||||
uint16_t section_index = phys_section_add(&d->map, section);
|
||||
uint64_t num_pages = int128_get64(int128_rshift(section->size,
|
||||
TARGET_PAGE_BITS));
|
||||
|
||||
@ -1640,7 +1713,7 @@ static subpage_t *subpage_init(AddressSpace *as, hwaddr base)
|
||||
return mmio;
|
||||
}
|
||||
|
||||
static uint16_t dummy_section(MemoryRegion *mr)
|
||||
static uint16_t dummy_section(PhysPageMap *map, MemoryRegion *mr)
|
||||
{
|
||||
MemoryRegionSection section = {
|
||||
.mr = mr,
|
||||
@ -1649,12 +1722,13 @@ static uint16_t dummy_section(MemoryRegion *mr)
|
||||
.size = int128_2_64(),
|
||||
};
|
||||
|
||||
return phys_section_add(§ion);
|
||||
return phys_section_add(map, §ion);
|
||||
}
|
||||
|
||||
MemoryRegion *iotlb_to_region(hwaddr index)
|
||||
{
|
||||
return address_space_memory.dispatch->sections[index & ~TARGET_PAGE_MASK].mr;
|
||||
return address_space_memory.dispatch->map.sections[
|
||||
index & ~TARGET_PAGE_MASK].mr;
|
||||
}
|
||||
|
||||
static void io_mem_init(void)
|
||||
@ -1671,9 +1745,19 @@ static void io_mem_init(void)
|
||||
static void mem_begin(MemoryListener *listener)
|
||||
{
|
||||
AddressSpace *as = container_of(listener, AddressSpace, dispatch_listener);
|
||||
AddressSpaceDispatch *d = g_new(AddressSpaceDispatch, 1);
|
||||
AddressSpaceDispatch *d = g_new0(AddressSpaceDispatch, 1);
|
||||
uint16_t n;
|
||||
|
||||
d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .is_leaf = 0 };
|
||||
n = dummy_section(&d->map, &io_mem_unassigned);
|
||||
assert(n == PHYS_SECTION_UNASSIGNED);
|
||||
n = dummy_section(&d->map, &io_mem_notdirty);
|
||||
assert(n == PHYS_SECTION_NOTDIRTY);
|
||||
n = dummy_section(&d->map, &io_mem_rom);
|
||||
assert(n == PHYS_SECTION_ROM);
|
||||
n = dummy_section(&d->map, &io_mem_watch);
|
||||
assert(n == PHYS_SECTION_WATCH);
|
||||
|
||||
d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 };
|
||||
d->as = as;
|
||||
as->next_dispatch = d;
|
||||
}
|
||||
@ -1684,37 +1768,14 @@ static void mem_commit(MemoryListener *listener)
|
||||
AddressSpaceDispatch *cur = as->dispatch;
|
||||
AddressSpaceDispatch *next = as->next_dispatch;
|
||||
|
||||
next->nodes = next_map.nodes;
|
||||
next->sections = next_map.sections;
|
||||
phys_page_compact_all(next, next->map.nodes_nb);
|
||||
|
||||
as->dispatch = next;
|
||||
g_free(cur);
|
||||
}
|
||||
|
||||
static void core_begin(MemoryListener *listener)
|
||||
{
|
||||
uint16_t n;
|
||||
|
||||
prev_map = g_new(PhysPageMap, 1);
|
||||
*prev_map = next_map;
|
||||
|
||||
memset(&next_map, 0, sizeof(next_map));
|
||||
n = dummy_section(&io_mem_unassigned);
|
||||
assert(n == PHYS_SECTION_UNASSIGNED);
|
||||
n = dummy_section(&io_mem_notdirty);
|
||||
assert(n == PHYS_SECTION_NOTDIRTY);
|
||||
n = dummy_section(&io_mem_rom);
|
||||
assert(n == PHYS_SECTION_ROM);
|
||||
n = dummy_section(&io_mem_watch);
|
||||
assert(n == PHYS_SECTION_WATCH);
|
||||
}
|
||||
|
||||
/* This listener's commit run after the other AddressSpaceDispatch listeners'.
|
||||
* All AddressSpaceDispatch instances have switched to the next map.
|
||||
*/
|
||||
static void core_commit(MemoryListener *listener)
|
||||
{
|
||||
phys_sections_free(prev_map);
|
||||
if (cur) {
|
||||
phys_sections_free(&cur->map);
|
||||
g_free(cur);
|
||||
}
|
||||
}
|
||||
|
||||
static void tcg_commit(MemoryListener *listener)
|
||||
@ -1742,8 +1803,6 @@ static void core_log_global_stop(MemoryListener *listener)
|
||||
}
|
||||
|
||||
static MemoryListener core_memory_listener = {
|
||||
.begin = core_begin,
|
||||
.commit = core_commit,
|
||||
.log_global_start = core_log_global_start,
|
||||
.log_global_stop = core_log_global_stop,
|
||||
.priority = 1,
|
||||
@ -1778,7 +1837,8 @@ void address_space_destroy_dispatch(AddressSpace *as)
|
||||
static void memory_map_init(void)
|
||||
{
|
||||
system_memory = g_malloc(sizeof(*system_memory));
|
||||
memory_region_init(system_memory, NULL, "system", INT64_MAX);
|
||||
|
||||
memory_region_init(system_memory, NULL, "system", UINT64_MAX);
|
||||
address_space_init(&address_space_memory, system_memory, "memory");
|
||||
|
||||
system_io = g_malloc(sizeof(*system_io));
|
||||
|
@ -924,10 +924,16 @@ build_mcfg_q35(GArray *table_data, GArray *linker, AcpiMcfgInfo *info)
|
||||
static void
|
||||
build_dsdt(GArray *table_data, GArray *linker, AcpiMiscInfo *misc)
|
||||
{
|
||||
void *dsdt;
|
||||
AcpiTableHeader *dsdt;
|
||||
|
||||
assert(misc->dsdt_code && misc->dsdt_size);
|
||||
|
||||
dsdt = acpi_data_push(table_data, misc->dsdt_size);
|
||||
memcpy(dsdt, misc->dsdt_code, misc->dsdt_size);
|
||||
|
||||
memset(dsdt, 0, sizeof *dsdt);
|
||||
build_header(linker, table_data, dsdt, ACPI_DSDT_SIGNATURE,
|
||||
misc->dsdt_size, 1);
|
||||
}
|
||||
|
||||
/* Build final rsdt table */
|
||||
|
@ -235,7 +235,7 @@ DefinitionBlock (
|
||||
}
|
||||
Return (0x0B)
|
||||
}
|
||||
Method(IQCR, 1, NotSerialized) {
|
||||
Method(IQCR, 1, Serialized) {
|
||||
// _CRS method - get current settings
|
||||
Name(PRR0, ResourceTemplate() {
|
||||
Interrupt(, Level, ActiveHigh, Shared) { 0 }
|
||||
|
@ -8,7 +8,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
||||
0x0,
|
||||
0x0,
|
||||
0x1,
|
||||
0xe0,
|
||||
0xd8,
|
||||
0x42,
|
||||
0x58,
|
||||
0x50,
|
||||
@ -3379,7 +3379,7 @@ static unsigned char AcpiDsdtAmlCode[] = {
|
||||
0x51,
|
||||
0x43,
|
||||
0x52,
|
||||
0x1,
|
||||
0x9,
|
||||
0x8,
|
||||
0x50,
|
||||
0x52,
|
||||
|
39
hw/i386/pc.c
39
hw/i386/pc.c
@ -1093,21 +1093,13 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
|
||||
return guest_info;
|
||||
}
|
||||
|
||||
void pc_init_pci64_hole(PcPciInfo *pci_info, uint64_t pci_hole64_start,
|
||||
uint64_t pci_hole64_size)
|
||||
/* setup pci memory address space mapping into system address space */
|
||||
void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
|
||||
MemoryRegion *pci_address_space)
|
||||
{
|
||||
if ((sizeof(hwaddr) == 4) || (!pci_hole64_size)) {
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* BIOS does not set MTRR entries for the 64 bit window, so no need to
|
||||
* align address to power of two. Align address at 1G, this makes sure
|
||||
* it can be exactly covered with a PAT entry even when using huge
|
||||
* pages.
|
||||
*/
|
||||
pci_info->w64.begin = ROUND_UP(pci_hole64_start, 0x1ULL << 30);
|
||||
pci_info->w64.end = pci_info->w64.begin + pci_hole64_size;
|
||||
assert(pci_info->w64.begin <= pci_info->w64.end);
|
||||
/* Set to lower priority than RAM */
|
||||
memory_region_add_subregion_overlap(system_memory, 0x0,
|
||||
pci_address_space, -1);
|
||||
}
|
||||
|
||||
void pc_acpi_init(const char *default_dsdt)
|
||||
@ -1261,7 +1253,8 @@ static const MemoryRegionOps ioportF0_io_ops = {
|
||||
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
ISADevice **rtc_state,
|
||||
ISADevice **floppy,
|
||||
bool no_vmport)
|
||||
bool no_vmport,
|
||||
uint32 hpet_irqs)
|
||||
{
|
||||
int i;
|
||||
DriveInfo *fd[MAX_FD];
|
||||
@ -1288,9 +1281,21 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
* when the HPET wants to take over. Thus we have to disable the latter.
|
||||
*/
|
||||
if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) {
|
||||
hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
|
||||
|
||||
/* In order to set property, here not using sysbus_try_create_simple */
|
||||
hpet = qdev_try_create(NULL, TYPE_HPET);
|
||||
if (hpet) {
|
||||
/* For pc-piix-*, hpet's intcap is always IRQ2. For pc-q35-1.7
|
||||
* and earlier, use IRQ2 for compat. Otherwise, use IRQ16~23,
|
||||
* IRQ8 and IRQ2.
|
||||
*/
|
||||
uint8_t compat = object_property_get_int(OBJECT(hpet),
|
||||
HPET_INTCAP, NULL);
|
||||
if (!compat) {
|
||||
qdev_prop_set_uint32(hpet, HPET_INTCAP, hpet_irqs);
|
||||
}
|
||||
qdev_init_nofail(hpet);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(hpet), 0, HPET_BASE);
|
||||
|
||||
for (i = 0; i < GSI_NUM_PINS; i++) {
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(hpet), i, gsi[i]);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "hw/loader.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/i386/apic.h"
|
||||
#include "hw/i386/smbios.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_ids.h"
|
||||
#include "hw/usb.h"
|
||||
@ -59,6 +60,7 @@ static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
|
||||
|
||||
static bool has_pci_info;
|
||||
static bool has_acpi_build = true;
|
||||
static bool smbios_type1_defaults = true;
|
||||
|
||||
/* PC hardware initialisation */
|
||||
static void pc_init1(QEMUMachineInitArgs *args,
|
||||
@ -114,7 +116,7 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
|
||||
if (pci_enabled) {
|
||||
pci_memory = g_new(MemoryRegion, 1);
|
||||
memory_region_init(pci_memory, NULL, "pci", INT64_MAX);
|
||||
memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
|
||||
rom_memory = pci_memory;
|
||||
} else {
|
||||
pci_memory = NULL;
|
||||
@ -128,6 +130,12 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
guest_info->has_pci_info = has_pci_info;
|
||||
guest_info->isapc_ram_fw = !pci_enabled;
|
||||
|
||||
if (smbios_type1_defaults) {
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_type1_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
|
||||
args->machine->name);
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
if (!xen_enabled()) {
|
||||
fw_cfg = pc_memory_init(system_memory,
|
||||
@ -149,8 +157,6 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
if (pci_enabled) {
|
||||
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
|
||||
system_memory, system_io, args->ram_size,
|
||||
below_4g_mem_size,
|
||||
0x100000000ULL - below_4g_mem_size,
|
||||
above_4g_mem_size,
|
||||
pci_memory, ram_memory);
|
||||
} else {
|
||||
@ -183,7 +189,8 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
|
||||
|
||||
/* init basic PC hardware */
|
||||
pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled());
|
||||
pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled(),
|
||||
0x4);
|
||||
|
||||
pc_nic_init(isa_bus, pci_bus);
|
||||
|
||||
@ -235,8 +242,14 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
|
||||
pc_init1(args, 1, 1);
|
||||
}
|
||||
|
||||
static void pc_compat_1_7(QEMUMachineInitArgs *args)
|
||||
{
|
||||
smbios_type1_defaults = false;
|
||||
}
|
||||
|
||||
static void pc_compat_1_6(QEMUMachineInitArgs *args)
|
||||
{
|
||||
pc_compat_1_7(args);
|
||||
has_pci_info = false;
|
||||
rom_file_in_ram = false;
|
||||
has_acpi_build = false;
|
||||
@ -267,6 +280,12 @@ static void pc_compat_1_2(QEMUMachineInitArgs *args)
|
||||
disable_kvm_pv_eoi();
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_7(QEMUMachineInitArgs *args)
|
||||
{
|
||||
pc_compat_1_7(args);
|
||||
pc_init_pci(args);
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_6(QEMUMachineInitArgs *args)
|
||||
{
|
||||
pc_compat_1_6(args);
|
||||
@ -303,6 +322,7 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
|
||||
{
|
||||
has_pci_info = false;
|
||||
has_acpi_build = false;
|
||||
smbios_type1_defaults = false;
|
||||
disable_kvm_pv_eoi();
|
||||
enable_compat_apic_id_mode();
|
||||
pc_init1(args, 1, 0);
|
||||
@ -312,6 +332,7 @@ static void pc_init_isa(QEMUMachineInitArgs *args)
|
||||
{
|
||||
has_pci_info = false;
|
||||
has_acpi_build = false;
|
||||
smbios_type1_defaults = false;
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "486";
|
||||
}
|
||||
@ -356,7 +377,7 @@ static QEMUMachine pc_i440fx_machine_v2_0 = {
|
||||
static QEMUMachine pc_i440fx_machine_v1_7 = {
|
||||
PC_I440FX_1_7_MACHINE_OPTIONS,
|
||||
.name = "pc-i440fx-1.7",
|
||||
.init = pc_init_pci,
|
||||
.init = pc_init_pci_1_7,
|
||||
};
|
||||
|
||||
#define PC_I440FX_1_6_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "hw/pci-host/q35.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/i386/ich9.h"
|
||||
#include "hw/i386/smbios.h"
|
||||
#include "hw/ide/pci.h"
|
||||
#include "hw/ide/ahci.h"
|
||||
#include "hw/usb.h"
|
||||
@ -49,6 +50,7 @@
|
||||
|
||||
static bool has_pci_info;
|
||||
static bool has_acpi_build = true;
|
||||
static bool smbios_type1_defaults = true;
|
||||
|
||||
/* PC hardware initialisation */
|
||||
static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
@ -101,7 +103,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
/* pci enabled */
|
||||
if (pci_enabled) {
|
||||
pci_memory = g_new(MemoryRegion, 1);
|
||||
memory_region_init(pci_memory, NULL, "pci", INT64_MAX);
|
||||
memory_region_init(pci_memory, NULL, "pci", UINT64_MAX);
|
||||
rom_memory = pci_memory;
|
||||
} else {
|
||||
pci_memory = NULL;
|
||||
@ -113,6 +115,12 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
guest_info->isapc_ram_fw = false;
|
||||
guest_info->has_acpi_build = has_acpi_build;
|
||||
|
||||
if (smbios_type1_defaults) {
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_type1_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
|
||||
args->machine->name);
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
if (!xen_enabled()) {
|
||||
pc_memory_init(get_system_memory(),
|
||||
@ -182,7 +190,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
pc_register_ferr_irq(gsi[13]);
|
||||
|
||||
/* init basic PC hardware */
|
||||
pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false);
|
||||
pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false, 0xff0104);
|
||||
|
||||
/* connect pm stuff to lpc */
|
||||
ich9_lpc_pm_init(lpc);
|
||||
@ -217,8 +225,14 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
}
|
||||
}
|
||||
|
||||
static void pc_compat_1_7(QEMUMachineInitArgs *args)
|
||||
{
|
||||
smbios_type1_defaults = false;
|
||||
}
|
||||
|
||||
static void pc_compat_1_6(QEMUMachineInitArgs *args)
|
||||
{
|
||||
pc_compat_1_7(args);
|
||||
has_pci_info = false;
|
||||
rom_file_in_ram = false;
|
||||
has_acpi_build = false;
|
||||
@ -236,6 +250,12 @@ static void pc_compat_1_4(QEMUMachineInitArgs *args)
|
||||
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
|
||||
}
|
||||
|
||||
static void pc_q35_init_1_7(QEMUMachineInitArgs *args)
|
||||
{
|
||||
pc_compat_1_7(args);
|
||||
pc_q35_init(args);
|
||||
}
|
||||
|
||||
static void pc_q35_init_1_6(QEMUMachineInitArgs *args)
|
||||
{
|
||||
pc_compat_1_6(args);
|
||||
@ -275,7 +295,11 @@ static QEMUMachine pc_q35_machine_v2_0 = {
|
||||
static QEMUMachine pc_q35_machine_v1_7 = {
|
||||
PC_Q35_1_7_MACHINE_OPTIONS,
|
||||
.name = "pc-q35-1.7",
|
||||
.init = pc_q35_init,
|
||||
.init = pc_q35_init_1_7,
|
||||
.compat_props = (GlobalProperty[]) {
|
||||
PC_Q35_COMPAT_1_7,
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
#define PC_Q35_1_6_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
|
||||
@ -285,7 +309,7 @@ static QEMUMachine pc_q35_machine_v1_6 = {
|
||||
.name = "pc-q35-1.6",
|
||||
.init = pc_q35_init_1_6,
|
||||
.compat_props = (GlobalProperty[]) {
|
||||
PC_COMPAT_1_6,
|
||||
PC_Q35_COMPAT_1_6,
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@ -295,7 +319,7 @@ static QEMUMachine pc_q35_machine_v1_5 = {
|
||||
.name = "pc-q35-1.5",
|
||||
.init = pc_q35_init_1_5,
|
||||
.compat_props = (GlobalProperty[]) {
|
||||
PC_COMPAT_1_5,
|
||||
PC_Q35_COMPAT_1_5,
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
@ -333,7 +333,7 @@ DefinitionBlock (
|
||||
}
|
||||
Return (0x0B)
|
||||
}
|
||||
Method(IQCR, 1, NotSerialized) {
|
||||
Method(IQCR, 1, Serialized) {
|
||||
// _CRS method - get current settings
|
||||
Name(PRR0, ResourceTemplate() {
|
||||
Interrupt(, Level, ActiveHigh, Shared) { 0 }
|
||||
|
@ -8,7 +8,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
||||
0x0,
|
||||
0x0,
|
||||
0x1,
|
||||
0x6,
|
||||
0xfe,
|
||||
0x42,
|
||||
0x58,
|
||||
0x50,
|
||||
@ -5338,7 +5338,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = {
|
||||
0x51,
|
||||
0x43,
|
||||
0x52,
|
||||
0x1,
|
||||
0x9,
|
||||
0x8,
|
||||
0x50,
|
||||
0x52,
|
||||
|
@ -256,6 +256,20 @@ static void smbios_build_type_1_fields(void)
|
||||
}
|
||||
}
|
||||
|
||||
void smbios_set_type1_defaults(const char *manufacturer,
|
||||
const char *product, const char *version)
|
||||
{
|
||||
if (!type1.manufacturer) {
|
||||
type1.manufacturer = manufacturer;
|
||||
}
|
||||
if (!type1.product) {
|
||||
type1.product = product;
|
||||
}
|
||||
if (!type1.version) {
|
||||
type1.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *smbios_get_table(size_t *length)
|
||||
{
|
||||
if (!smbios_immutable) {
|
||||
|
@ -103,8 +103,6 @@ struct PCII440FXState {
|
||||
MemoryRegion *system_memory;
|
||||
MemoryRegion *pci_address_space;
|
||||
MemoryRegion *ram_memory;
|
||||
MemoryRegion pci_hole;
|
||||
MemoryRegion pci_hole_64bit;
|
||||
PAMMemoryRegion pam_regions[13];
|
||||
MemoryRegion smram_region;
|
||||
uint8_t smm_enabled;
|
||||
@ -313,8 +311,6 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
|
||||
MemoryRegion *address_space_mem,
|
||||
MemoryRegion *address_space_io,
|
||||
ram_addr_t ram_size,
|
||||
hwaddr pci_hole_start,
|
||||
hwaddr pci_hole_size,
|
||||
ram_addr_t above_4g_mem_size,
|
||||
MemoryRegion *pci_address_space,
|
||||
MemoryRegion *ram_memory)
|
||||
@ -327,7 +323,6 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
|
||||
PCII440FXState *f;
|
||||
unsigned i;
|
||||
I440FXState *i440fx;
|
||||
uint64_t pci_hole64_size;
|
||||
|
||||
dev = qdev_create(NULL, TYPE_I440FX_PCI_HOST_BRIDGE);
|
||||
s = PCI_HOST_BRIDGE(dev);
|
||||
@ -355,23 +350,10 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state,
|
||||
i440fx->pci_info.w32.begin = 0xe0000000;
|
||||
}
|
||||
|
||||
memory_region_init_alias(&f->pci_hole, OBJECT(d), "pci-hole", f->pci_address_space,
|
||||
pci_hole_start, pci_hole_size);
|
||||
memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole);
|
||||
/* setup pci memory mapping */
|
||||
pc_pci_as_mapping_init(OBJECT(f), f->system_memory,
|
||||
f->pci_address_space);
|
||||
|
||||
pci_hole64_size = pci_host_get_hole64_size(i440fx->pci_hole64_size);
|
||||
|
||||
pc_init_pci64_hole(&i440fx->pci_info, 0x100000000ULL + above_4g_mem_size,
|
||||
pci_hole64_size);
|
||||
memory_region_init_alias(&f->pci_hole_64bit, OBJECT(d), "pci-hole64",
|
||||
f->pci_address_space,
|
||||
i440fx->pci_info.w64.begin,
|
||||
pci_hole64_size);
|
||||
if (pci_hole64_size) {
|
||||
memory_region_add_subregion(f->system_memory,
|
||||
i440fx->pci_info.w64.begin,
|
||||
&f->pci_hole_64bit);
|
||||
}
|
||||
memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region",
|
||||
f->pci_address_space, 0xa0000, 0x20000);
|
||||
memory_region_add_subregion_overlap(f->system_memory, 0xa0000,
|
||||
|
@ -356,28 +356,11 @@ static int mch_init(PCIDevice *d)
|
||||
{
|
||||
int i;
|
||||
MCHPCIState *mch = MCH_PCI_DEVICE(d);
|
||||
uint64_t pci_hole64_size;
|
||||
|
||||
/* setup pci memory regions */
|
||||
memory_region_init_alias(&mch->pci_hole, OBJECT(mch), "pci-hole",
|
||||
mch->pci_address_space,
|
||||
mch->below_4g_mem_size,
|
||||
0x100000000ULL - mch->below_4g_mem_size);
|
||||
memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size,
|
||||
&mch->pci_hole);
|
||||
/* setup pci memory mapping */
|
||||
pc_pci_as_mapping_init(OBJECT(mch), mch->system_memory,
|
||||
mch->pci_address_space);
|
||||
|
||||
pci_hole64_size = pci_host_get_hole64_size(mch->pci_hole64_size);
|
||||
pc_init_pci64_hole(&mch->pci_info, 0x100000000ULL + mch->above_4g_mem_size,
|
||||
pci_hole64_size);
|
||||
memory_region_init_alias(&mch->pci_hole_64bit, OBJECT(mch), "pci-hole64",
|
||||
mch->pci_address_space,
|
||||
mch->pci_info.w64.begin,
|
||||
pci_hole64_size);
|
||||
if (pci_hole64_size) {
|
||||
memory_region_add_subregion(mch->system_memory,
|
||||
mch->pci_info.w64.begin,
|
||||
&mch->pci_hole_64bit);
|
||||
}
|
||||
/* smram */
|
||||
cpu_smm_register(&mch_set_smm, mch);
|
||||
memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region",
|
||||
|
@ -1330,7 +1330,7 @@ static const pci_class_desc pci_class_descriptions[] =
|
||||
{ 0x0601, "ISA bridge", "isa"},
|
||||
{ 0x0602, "EISA bridge", "eisa"},
|
||||
{ 0x0603, "MC bridge", "mca"},
|
||||
{ 0x0604, "PCI bridge", "pci"},
|
||||
{ 0x0604, "PCI bridge", "pci-bridge"},
|
||||
{ 0x0605, "PCMCIA bridge", "pcmcia"},
|
||||
{ 0x0606, "NUBUS bridge", "nubus"},
|
||||
{ 0x0607, "CARDBUS bridge", "cardbus"},
|
||||
|
@ -372,7 +372,7 @@ int pci_bridge_initfn(PCIDevice *dev, const char *typename)
|
||||
sec_bus->parent_dev = dev;
|
||||
sec_bus->map_irq = br->map_irq ? br->map_irq : pci_swizzle_map_irq_fn;
|
||||
sec_bus->address_space_mem = &br->address_space_mem;
|
||||
memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", INT64_MAX);
|
||||
memory_region_init(&br->address_space_mem, OBJECT(br), "pci_bridge_pci", UINT64_MAX);
|
||||
sec_bus->address_space_io = &br->address_space_io;
|
||||
memory_region_init(&br->address_space_io, OBJECT(br), "pci_bridge_io", 65536);
|
||||
br->windows = pci_bridge_region_init(br);
|
||||
|
@ -555,7 +555,7 @@ static int spapr_phb_init(SysBusDevice *s)
|
||||
|
||||
/* Initialize memory regions */
|
||||
sprintf(namebuf, "%s.mmio", sphb->dtbusname);
|
||||
memory_region_init(&sphb->memspace, OBJECT(sphb), namebuf, INT64_MAX);
|
||||
memory_region_init(&sphb->memspace, OBJECT(sphb), namebuf, UINT64_MAX);
|
||||
|
||||
sprintf(namebuf, "%s.mmio-alias", sphb->dtbusname);
|
||||
memory_region_init_alias(&sphb->memwindow, OBJECT(sphb),
|
||||
|
@ -42,7 +42,6 @@
|
||||
|
||||
#define HPET_MSI_SUPPORT 0
|
||||
|
||||
#define TYPE_HPET "hpet"
|
||||
#define HPET(obj) OBJECT_CHECK(HPETState, (obj), TYPE_HPET)
|
||||
|
||||
struct HPETState;
|
||||
@ -73,6 +72,7 @@ typedef struct HPETState {
|
||||
uint8_t rtc_irq_level;
|
||||
qemu_irq pit_enabled;
|
||||
uint8_t num_timers;
|
||||
uint32_t intcap;
|
||||
HPETTimer timer[HPET_MAX_TIMERS];
|
||||
|
||||
/* Memory-mapped, software visible registers */
|
||||
@ -198,13 +198,23 @@ static void update_irq(struct HPETTimer *timer, int set)
|
||||
if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) {
|
||||
s->isr &= ~mask;
|
||||
if (!timer_fsb_route(timer)) {
|
||||
qemu_irq_lower(s->irqs[route]);
|
||||
/* fold the ICH PIRQ# pin's internal inversion logic into hpet */
|
||||
if (route >= ISA_NUM_IRQS) {
|
||||
qemu_irq_raise(s->irqs[route]);
|
||||
} else {
|
||||
qemu_irq_lower(s->irqs[route]);
|
||||
}
|
||||
}
|
||||
} else if (timer_fsb_route(timer)) {
|
||||
stl_le_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
|
||||
} else if (timer->config & HPET_TN_TYPE_LEVEL) {
|
||||
s->isr |= mask;
|
||||
qemu_irq_raise(s->irqs[route]);
|
||||
/* fold the ICH PIRQ# pin's internal inversion logic into hpet */
|
||||
if (route >= ISA_NUM_IRQS) {
|
||||
qemu_irq_lower(s->irqs[route]);
|
||||
} else {
|
||||
qemu_irq_raise(s->irqs[route]);
|
||||
}
|
||||
} else {
|
||||
s->isr &= ~mask;
|
||||
qemu_irq_pulse(s->irqs[route]);
|
||||
@ -653,8 +663,8 @@ static void hpet_reset(DeviceState *d)
|
||||
if (s->flags & (1 << HPET_MSI_SUPPORT)) {
|
||||
timer->config |= HPET_TN_FSB_CAP;
|
||||
}
|
||||
/* advertise availability of ioapic inti2 */
|
||||
timer->config |= 0x00000004ULL << 32;
|
||||
/* advertise availability of ioapic int */
|
||||
timer->config |= (uint64_t)s->intcap << 32;
|
||||
timer->period = 0ULL;
|
||||
timer->wrap_flag = 0;
|
||||
}
|
||||
@ -703,6 +713,9 @@ static void hpet_realize(DeviceState *dev, Error **errp)
|
||||
int i;
|
||||
HPETTimer *timer;
|
||||
|
||||
if (!s->intcap) {
|
||||
error_printf("Hpet's intcap not initialized.\n");
|
||||
}
|
||||
if (hpet_cfg.count == UINT8_MAX) {
|
||||
/* first instance */
|
||||
hpet_cfg.count = 0;
|
||||
@ -743,6 +756,7 @@ static void hpet_realize(DeviceState *dev, Error **errp)
|
||||
static Property hpet_device_properties[] = {
|
||||
DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
|
||||
DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
|
||||
DEFINE_PROP_UINT32(HPET_INTCAP, HPETState, intcap, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -757,11 +771,6 @@ static void hpet_device_class_init(ObjectClass *klass, void *data)
|
||||
dc->props = hpet_device_properties;
|
||||
}
|
||||
|
||||
bool hpet_find(void)
|
||||
{
|
||||
return object_resolve_path_type("", TYPE_HPET, NULL);
|
||||
}
|
||||
|
||||
static const TypeInfo hpet_device_info = {
|
||||
.name = TYPE_HPET,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
|
@ -6,7 +6,10 @@
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/qdev.h"
|
||||
|
||||
typedef struct QEMUMachine QEMUMachine;
|
||||
|
||||
typedef struct QEMUMachineInitArgs {
|
||||
const QEMUMachine *machine;
|
||||
ram_addr_t ram_size;
|
||||
const char *boot_order;
|
||||
const char *kernel_filename;
|
||||
@ -21,7 +24,7 @@ typedef void QEMUMachineResetFunc(void);
|
||||
|
||||
typedef void QEMUMachineHotAddCPUFunc(const int64_t id, Error **errp);
|
||||
|
||||
typedef struct QEMUMachine {
|
||||
struct QEMUMachine {
|
||||
const char *name;
|
||||
const char *alias;
|
||||
const char *desc;
|
||||
@ -43,7 +46,7 @@ typedef struct QEMUMachine {
|
||||
GlobalProperty *compat_props;
|
||||
struct QEMUMachine *next;
|
||||
const char *hw_version;
|
||||
} QEMUMachine;
|
||||
};
|
||||
|
||||
int qemu_register_machine(QEMUMachine *m);
|
||||
QEMUMachine *find_default_machine(void);
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/pci/pci.h"
|
||||
|
||||
#define HPET_INTCAP "hpet-intcap"
|
||||
|
||||
/* PC-style peripherals (also used by other machines). */
|
||||
|
||||
typedef struct PcPciInfo {
|
||||
@ -128,17 +130,9 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
|
||||
#define PCI_HOST_PROP_PCI_HOLE64_SIZE "pci-hole64-size"
|
||||
#define DEFAULT_PCI_HOLE64_SIZE (~0x0ULL)
|
||||
|
||||
static inline uint64_t pci_host_get_hole64_size(uint64_t pci_hole64_size)
|
||||
{
|
||||
if (pci_hole64_size == DEFAULT_PCI_HOLE64_SIZE) {
|
||||
return 1ULL << 62;
|
||||
} else {
|
||||
return pci_hole64_size;
|
||||
}
|
||||
}
|
||||
|
||||
void pc_init_pci64_hole(PcPciInfo *pci_info, uint64_t pci_hole64_start,
|
||||
uint64_t pci_hole64_size);
|
||||
void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
|
||||
MemoryRegion *pci_address_space);
|
||||
|
||||
FWCfgState *pc_memory_init(MemoryRegion *system_memory,
|
||||
const char *kernel_filename,
|
||||
@ -154,7 +148,8 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus);
|
||||
void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
ISADevice **rtc_state,
|
||||
ISADevice **floppy,
|
||||
bool no_vmport);
|
||||
bool no_vmport,
|
||||
uint32 hpet_irqs);
|
||||
void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd);
|
||||
void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
const char *boot_device,
|
||||
@ -187,8 +182,6 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn,
|
||||
MemoryRegion *address_space_mem,
|
||||
MemoryRegion *address_space_io,
|
||||
ram_addr_t ram_size,
|
||||
hwaddr pci_hole_start,
|
||||
hwaddr pci_hole_size,
|
||||
ram_addr_t above_4g_mem_size,
|
||||
MemoryRegion *pci_memory,
|
||||
MemoryRegion *ram_memory);
|
||||
@ -246,6 +239,25 @@ uint16_t pvpanic_port(void);
|
||||
|
||||
int e820_add_entry(uint64_t, uint64_t, uint32_t);
|
||||
|
||||
#define PC_Q35_COMPAT_1_7 \
|
||||
{\
|
||||
.driver = "hpet",\
|
||||
.property = HPET_INTCAP,\
|
||||
.value = stringify(4),\
|
||||
}
|
||||
|
||||
#define PC_Q35_COMPAT_1_6 \
|
||||
PC_COMPAT_1_6, \
|
||||
PC_Q35_COMPAT_1_7
|
||||
|
||||
#define PC_Q35_COMPAT_1_5 \
|
||||
PC_COMPAT_1_5, \
|
||||
PC_Q35_COMPAT_1_6
|
||||
|
||||
#define PC_Q35_COMPAT_1_4 \
|
||||
PC_COMPAT_1_4, \
|
||||
PC_Q35_COMPAT_1_5
|
||||
|
||||
#define PC_COMPAT_1_6 \
|
||||
{\
|
||||
.driver = "e1000",\
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "qemu/option.h"
|
||||
|
||||
void smbios_entry_add(QemuOpts *opts);
|
||||
void smbios_set_type1_defaults(const char *manufacturer,
|
||||
const char *product, const char *version);
|
||||
uint8_t *smbios_get_table(size_t *length);
|
||||
|
||||
/*
|
||||
|
@ -53,8 +53,6 @@ typedef struct MCHPCIState {
|
||||
MemoryRegion *address_space_io;
|
||||
PAMMemoryRegion pam_regions[13];
|
||||
MemoryRegion smram_region;
|
||||
MemoryRegion pci_hole;
|
||||
MemoryRegion pci_hole_64bit;
|
||||
PcPciInfo pci_info;
|
||||
uint8_t smm_enabled;
|
||||
ram_addr_t below_4g_mem_size;
|
||||
|
@ -13,6 +13,8 @@
|
||||
#ifndef QEMU_HPET_EMUL_H
|
||||
#define QEMU_HPET_EMUL_H
|
||||
|
||||
#include "qom/object.h"
|
||||
|
||||
#define HPET_BASE 0xfed00000
|
||||
#define HPET_CLK_PERIOD 10000000ULL /* 10000000 femtoseconds == 10ns*/
|
||||
|
||||
@ -72,5 +74,11 @@ struct hpet_fw_config
|
||||
|
||||
extern struct hpet_fw_config hpet_cfg;
|
||||
|
||||
bool hpet_find(void);
|
||||
#define TYPE_HPET "hpet"
|
||||
|
||||
static inline bool hpet_find(void)
|
||||
{
|
||||
return object_resolve_path_type("", TYPE_HPET, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -16,38 +16,23 @@
|
||||
|
||||
#include "qemu-common.h"
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
extern bool qtest_allowed;
|
||||
extern const char *qtest_chrdev;
|
||||
extern const char *qtest_log;
|
||||
|
||||
static inline bool qtest_enabled(void)
|
||||
{
|
||||
return qtest_allowed;
|
||||
}
|
||||
|
||||
int qtest_init_accel(void);
|
||||
void qtest_init(const char *qtest_chrdev, const char *qtest_log);
|
||||
|
||||
static inline int qtest_available(void)
|
||||
{
|
||||
#ifdef CONFIG_POSIX
|
||||
return 1;
|
||||
}
|
||||
|
||||
int qtest_init(void);
|
||||
#else
|
||||
static inline bool qtest_enabled(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int qtest_available(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int qtest_init(void)
|
||||
{
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
1
memory.c
1
memory.c
@ -1596,6 +1596,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr,
|
||||
view = address_space_get_flatview(as);
|
||||
fr = flatview_lookup(view, range);
|
||||
if (!fr) {
|
||||
flatview_unref(view);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
20
qtest.c
20
qtest.c
@ -22,8 +22,6 @@
|
||||
|
||||
#define MAX_IRQ 256
|
||||
|
||||
const char *qtest_chrdev;
|
||||
const char *qtest_log;
|
||||
bool qtest_allowed;
|
||||
|
||||
static DeviceState *irq_intercept_dev;
|
||||
@ -406,7 +404,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
|
||||
|
||||
qtest_send_prefix(chr);
|
||||
qtest_send(chr, "OK\n");
|
||||
} else if (strcmp(words[0], "clock_step") == 0) {
|
||||
} else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
|
||||
int64_t ns;
|
||||
|
||||
if (words[1]) {
|
||||
@ -417,7 +415,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
|
||||
qtest_clock_warp(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns);
|
||||
qtest_send_prefix(chr);
|
||||
qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
|
||||
} else if (strcmp(words[0], "clock_set") == 0) {
|
||||
} else if (qtest_enabled() && strcmp(words[0], "clock_set") == 0) {
|
||||
int64_t ns;
|
||||
|
||||
g_assert(words[1]);
|
||||
@ -502,13 +500,17 @@ static void qtest_event(void *opaque, int event)
|
||||
}
|
||||
}
|
||||
|
||||
int qtest_init(void)
|
||||
int qtest_init_accel(void)
|
||||
{
|
||||
configure_icount("0");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qtest_init(const char *qtest_chrdev, const char *qtest_log)
|
||||
{
|
||||
CharDriverState *chr;
|
||||
|
||||
g_assert(qtest_chrdev != NULL);
|
||||
|
||||
configure_icount("0");
|
||||
chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
|
||||
|
||||
qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
|
||||
@ -525,6 +527,4 @@ int qtest_init(void)
|
||||
}
|
||||
|
||||
qtest_chr = chr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ check-qtest-i386-y += tests/ide-test$(EXESUF)
|
||||
check-qtest-i386-y += tests/hd-geo-test$(EXESUF)
|
||||
gcov-files-i386-y += hw/hd-geometry.c
|
||||
check-qtest-i386-y += tests/boot-order-test$(EXESUF)
|
||||
check-qtest-i386-y += tests/acpi-test$(EXESUF)
|
||||
check-qtest-i386-y += tests/rtc-test$(EXESUF)
|
||||
check-qtest-i386-y += tests/i440fx-test$(EXESUF)
|
||||
check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)
|
||||
@ -198,6 +199,7 @@ tests/fdc-test$(EXESUF): tests/fdc-test.o
|
||||
tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
|
||||
tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
|
||||
tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
|
||||
tests/acpi-test$(EXESUF): tests/acpi-test.o $(libqos-obj-y)
|
||||
tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
|
||||
tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
|
||||
tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
|
||||
|
394
tests/acpi-test.c
Normal file
394
tests/acpi-test.c
Normal file
@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Boot order test cases.
|
||||
*
|
||||
* Copyright (c) 2013 Red Hat Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Michael S. Tsirkin <mst@redhat.com>,
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
#include "qemu-common.h"
|
||||
#include "libqtest.h"
|
||||
#include "qemu/compiler.h"
|
||||
#include "hw/i386/acpi-defs.h"
|
||||
|
||||
/* DSDT and SSDTs format */
|
||||
typedef struct {
|
||||
AcpiTableHeader header;
|
||||
uint8_t *aml;
|
||||
int aml_len;
|
||||
} AcpiSdtTable;
|
||||
|
||||
typedef struct {
|
||||
uint32_t rsdp_addr;
|
||||
AcpiRsdpDescriptor rsdp_table;
|
||||
AcpiRsdtDescriptorRev1 rsdt_table;
|
||||
AcpiFadtDescriptorRev1 fadt_table;
|
||||
AcpiFacsDescriptorRev1 facs_table;
|
||||
uint32_t *rsdt_tables_addr;
|
||||
int rsdt_tables_nr;
|
||||
AcpiSdtTable dsdt_table;
|
||||
GArray *ssdt_tables;
|
||||
} test_data;
|
||||
|
||||
#define LOW(x) ((x) & 0xff)
|
||||
#define HIGH(x) ((x) >> 8)
|
||||
|
||||
#define SIGNATURE 0xdead
|
||||
#define SIGNATURE_OFFSET 0x10
|
||||
#define BOOT_SECTOR_ADDRESS 0x7c00
|
||||
|
||||
#define ACPI_READ_FIELD(field, addr) \
|
||||
do { \
|
||||
switch (sizeof(field)) { \
|
||||
case 1: \
|
||||
field = readb(addr); \
|
||||
break; \
|
||||
case 2: \
|
||||
field = le16_to_cpu(readw(addr)); \
|
||||
break; \
|
||||
case 4: \
|
||||
field = le32_to_cpu(readl(addr)); \
|
||||
break; \
|
||||
case 8: \
|
||||
field = le64_to_cpu(readq(addr)); \
|
||||
break; \
|
||||
default: \
|
||||
g_assert(false); \
|
||||
} \
|
||||
addr += sizeof(field); \
|
||||
} while (0);
|
||||
|
||||
#define ACPI_READ_ARRAY_PTR(arr, length, addr) \
|
||||
do { \
|
||||
int idx; \
|
||||
for (idx = 0; idx < length; ++idx) { \
|
||||
ACPI_READ_FIELD(arr[idx], addr); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define ACPI_READ_ARRAY(arr, addr) \
|
||||
ACPI_READ_ARRAY_PTR(arr, sizeof(arr)/sizeof(arr[0]), addr)
|
||||
|
||||
#define ACPI_READ_TABLE_HEADER(table, addr) \
|
||||
do { \
|
||||
ACPI_READ_FIELD((table)->signature, addr); \
|
||||
ACPI_READ_FIELD((table)->length, addr); \
|
||||
ACPI_READ_FIELD((table)->revision, addr); \
|
||||
ACPI_READ_FIELD((table)->checksum, addr); \
|
||||
ACPI_READ_ARRAY((table)->oem_id, addr); \
|
||||
ACPI_READ_ARRAY((table)->oem_table_id, addr); \
|
||||
ACPI_READ_FIELD((table)->oem_revision, addr); \
|
||||
ACPI_READ_ARRAY((table)->asl_compiler_id, addr); \
|
||||
ACPI_READ_FIELD((table)->asl_compiler_revision, addr); \
|
||||
} while (0);
|
||||
|
||||
/* Boot sector code: write SIGNATURE into memory,
|
||||
* then halt.
|
||||
*/
|
||||
static uint8_t boot_sector[0x200] = {
|
||||
/* 7c00: mov $0xdead,%ax */
|
||||
[0x00] = 0xb8,
|
||||
[0x01] = LOW(SIGNATURE),
|
||||
[0x02] = HIGH(SIGNATURE),
|
||||
/* 7c03: mov %ax,0x7c10 */
|
||||
[0x03] = 0xa3,
|
||||
[0x04] = LOW(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET),
|
||||
[0x05] = HIGH(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET),
|
||||
/* 7c06: cli */
|
||||
[0x06] = 0xfa,
|
||||
/* 7c07: hlt */
|
||||
[0x07] = 0xf4,
|
||||
/* 7c08: jmp 0x7c07=0x7c0a-3 */
|
||||
[0x08] = 0xeb,
|
||||
[0x09] = LOW(-3),
|
||||
/* We mov 0xdead here: set value to make debugging easier */
|
||||
[SIGNATURE_OFFSET] = LOW(0xface),
|
||||
[SIGNATURE_OFFSET + 1] = HIGH(0xface),
|
||||
/* End of boot sector marker */
|
||||
[0x1FE] = 0x55,
|
||||
[0x1FF] = 0xAA,
|
||||
};
|
||||
|
||||
static const char *disk = "tests/acpi-test-disk.raw";
|
||||
|
||||
static void free_test_data(test_data *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
g_free(data->rsdt_tables_addr);
|
||||
for (i = 0; i < data->ssdt_tables->len; ++i) {
|
||||
g_free(g_array_index(data->ssdt_tables, AcpiSdtTable, i).aml);
|
||||
}
|
||||
g_array_free(data->ssdt_tables, false);
|
||||
g_free(data->dsdt_table.aml);
|
||||
}
|
||||
|
||||
static uint8_t acpi_checksum(const uint8_t *data, int len)
|
||||
{
|
||||
int i;
|
||||
uint8_t sum = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
sum += data[i];
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static void test_acpi_rsdp_address(test_data *data)
|
||||
{
|
||||
uint32_t off;
|
||||
|
||||
/* OK, now find RSDP */
|
||||
for (off = 0xf0000; off < 0x100000; off += 0x10) {
|
||||
uint8_t sig[] = "RSD PTR ";
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof sig - 1; ++i) {
|
||||
sig[i] = readb(off + i);
|
||||
}
|
||||
|
||||
if (!memcmp(sig, "RSD PTR ", sizeof sig)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert_cmphex(off, <, 0x100000);
|
||||
data->rsdp_addr = off;
|
||||
}
|
||||
|
||||
static void test_acpi_rsdp_table(test_data *data)
|
||||
{
|
||||
AcpiRsdpDescriptor *rsdp_table = &data->rsdp_table;
|
||||
uint32_t addr = data->rsdp_addr;
|
||||
|
||||
ACPI_READ_FIELD(rsdp_table->signature, addr);
|
||||
g_assert_cmphex(rsdp_table->signature, ==, ACPI_RSDP_SIGNATURE);
|
||||
|
||||
ACPI_READ_FIELD(rsdp_table->checksum, addr);
|
||||
ACPI_READ_ARRAY(rsdp_table->oem_id, addr);
|
||||
ACPI_READ_FIELD(rsdp_table->revision, addr);
|
||||
ACPI_READ_FIELD(rsdp_table->rsdt_physical_address, addr);
|
||||
ACPI_READ_FIELD(rsdp_table->length, addr);
|
||||
|
||||
/* rsdp checksum is not for the whole table, but for the first 20 bytes */
|
||||
g_assert(!acpi_checksum((uint8_t *)rsdp_table, 20));
|
||||
}
|
||||
|
||||
static void test_acpi_rsdt_table(test_data *data)
|
||||
{
|
||||
AcpiRsdtDescriptorRev1 *rsdt_table = &data->rsdt_table;
|
||||
uint32_t addr = data->rsdp_table.rsdt_physical_address;
|
||||
uint32_t *tables;
|
||||
int tables_nr;
|
||||
uint8_t checksum;
|
||||
|
||||
/* read the header */
|
||||
ACPI_READ_TABLE_HEADER(rsdt_table, addr);
|
||||
g_assert_cmphex(rsdt_table->signature, ==, ACPI_RSDT_SIGNATURE);
|
||||
|
||||
/* compute the table entries in rsdt */
|
||||
tables_nr = (rsdt_table->length - sizeof(AcpiRsdtDescriptorRev1)) /
|
||||
sizeof(uint32_t);
|
||||
g_assert_cmpint(tables_nr, >, 0);
|
||||
|
||||
/* get the addresses of the tables pointed by rsdt */
|
||||
tables = g_new0(uint32_t, tables_nr);
|
||||
ACPI_READ_ARRAY_PTR(tables, tables_nr, addr);
|
||||
|
||||
checksum = acpi_checksum((uint8_t *)rsdt_table, rsdt_table->length) +
|
||||
acpi_checksum((uint8_t *)tables, tables_nr * sizeof(uint32_t));
|
||||
g_assert(!checksum);
|
||||
|
||||
/* SSDT tables after FADT */
|
||||
data->rsdt_tables_addr = tables;
|
||||
data->rsdt_tables_nr = tables_nr;
|
||||
}
|
||||
|
||||
static void test_acpi_fadt_table(test_data *data)
|
||||
{
|
||||
AcpiFadtDescriptorRev1 *fadt_table = &data->fadt_table;
|
||||
uint32_t addr;
|
||||
|
||||
/* FADT table comes first */
|
||||
addr = data->rsdt_tables_addr[0];
|
||||
ACPI_READ_TABLE_HEADER(fadt_table, addr);
|
||||
|
||||
ACPI_READ_FIELD(fadt_table->firmware_ctrl, addr);
|
||||
ACPI_READ_FIELD(fadt_table->dsdt, addr);
|
||||
ACPI_READ_FIELD(fadt_table->model, addr);
|
||||
ACPI_READ_FIELD(fadt_table->reserved1, addr);
|
||||
ACPI_READ_FIELD(fadt_table->sci_int, addr);
|
||||
ACPI_READ_FIELD(fadt_table->smi_cmd, addr);
|
||||
ACPI_READ_FIELD(fadt_table->acpi_enable, addr);
|
||||
ACPI_READ_FIELD(fadt_table->acpi_disable, addr);
|
||||
ACPI_READ_FIELD(fadt_table->S4bios_req, addr);
|
||||
ACPI_READ_FIELD(fadt_table->reserved2, addr);
|
||||
ACPI_READ_FIELD(fadt_table->pm1a_evt_blk, addr);
|
||||
ACPI_READ_FIELD(fadt_table->pm1b_evt_blk, addr);
|
||||
ACPI_READ_FIELD(fadt_table->pm1a_cnt_blk, addr);
|
||||
ACPI_READ_FIELD(fadt_table->pm1b_cnt_blk, addr);
|
||||
ACPI_READ_FIELD(fadt_table->pm2_cnt_blk, addr);
|
||||
ACPI_READ_FIELD(fadt_table->pm_tmr_blk, addr);
|
||||
ACPI_READ_FIELD(fadt_table->gpe0_blk, addr);
|
||||
ACPI_READ_FIELD(fadt_table->gpe1_blk, addr);
|
||||
ACPI_READ_FIELD(fadt_table->pm1_evt_len, addr);
|
||||
ACPI_READ_FIELD(fadt_table->pm1_cnt_len, addr);
|
||||
ACPI_READ_FIELD(fadt_table->pm2_cnt_len, addr);
|
||||
ACPI_READ_FIELD(fadt_table->pm_tmr_len, addr);
|
||||
ACPI_READ_FIELD(fadt_table->gpe0_blk_len, addr);
|
||||
ACPI_READ_FIELD(fadt_table->gpe1_blk_len, addr);
|
||||
ACPI_READ_FIELD(fadt_table->gpe1_base, addr);
|
||||
ACPI_READ_FIELD(fadt_table->reserved3, addr);
|
||||
ACPI_READ_FIELD(fadt_table->plvl2_lat, addr);
|
||||
ACPI_READ_FIELD(fadt_table->plvl3_lat, addr);
|
||||
ACPI_READ_FIELD(fadt_table->flush_size, addr);
|
||||
ACPI_READ_FIELD(fadt_table->flush_stride, addr);
|
||||
ACPI_READ_FIELD(fadt_table->duty_offset, addr);
|
||||
ACPI_READ_FIELD(fadt_table->duty_width, addr);
|
||||
ACPI_READ_FIELD(fadt_table->day_alrm, addr);
|
||||
ACPI_READ_FIELD(fadt_table->mon_alrm, addr);
|
||||
ACPI_READ_FIELD(fadt_table->century, addr);
|
||||
ACPI_READ_FIELD(fadt_table->reserved4, addr);
|
||||
ACPI_READ_FIELD(fadt_table->reserved4a, addr);
|
||||
ACPI_READ_FIELD(fadt_table->reserved4b, addr);
|
||||
ACPI_READ_FIELD(fadt_table->flags, addr);
|
||||
|
||||
g_assert_cmphex(fadt_table->signature, ==, ACPI_FACP_SIGNATURE);
|
||||
g_assert(!acpi_checksum((uint8_t *)fadt_table, fadt_table->length));
|
||||
}
|
||||
|
||||
static void test_acpi_facs_table(test_data *data)
|
||||
{
|
||||
AcpiFacsDescriptorRev1 *facs_table = &data->facs_table;
|
||||
uint32_t addr = data->fadt_table.firmware_ctrl;
|
||||
|
||||
ACPI_READ_FIELD(facs_table->signature, addr);
|
||||
ACPI_READ_FIELD(facs_table->length, addr);
|
||||
ACPI_READ_FIELD(facs_table->hardware_signature, addr);
|
||||
ACPI_READ_FIELD(facs_table->firmware_waking_vector, addr);
|
||||
ACPI_READ_FIELD(facs_table->global_lock, addr);
|
||||
ACPI_READ_FIELD(facs_table->flags, addr);
|
||||
ACPI_READ_ARRAY(facs_table->resverved3, addr);
|
||||
|
||||
g_assert_cmphex(facs_table->signature, ==, ACPI_FACS_SIGNATURE);
|
||||
}
|
||||
|
||||
static void test_dst_table(AcpiSdtTable *sdt_table, uint32_t addr)
|
||||
{
|
||||
uint8_t checksum;
|
||||
|
||||
ACPI_READ_TABLE_HEADER(&sdt_table->header, addr);
|
||||
|
||||
sdt_table->aml_len = sdt_table->header.length - sizeof(AcpiTableHeader);
|
||||
sdt_table->aml = g_malloc0(sdt_table->aml_len);
|
||||
ACPI_READ_ARRAY_PTR(sdt_table->aml, sdt_table->aml_len, addr);
|
||||
|
||||
checksum = acpi_checksum((uint8_t *)sdt_table, sizeof(AcpiTableHeader)) +
|
||||
acpi_checksum(sdt_table->aml, sdt_table->aml_len);
|
||||
g_assert(!checksum);
|
||||
}
|
||||
|
||||
static void test_acpi_dsdt_table(test_data *data)
|
||||
{
|
||||
AcpiSdtTable *dsdt_table = &data->dsdt_table;
|
||||
uint32_t addr = data->fadt_table.dsdt;
|
||||
|
||||
test_dst_table(dsdt_table, addr);
|
||||
g_assert_cmphex(dsdt_table->header.signature, ==, ACPI_DSDT_SIGNATURE);
|
||||
}
|
||||
|
||||
static void test_acpi_ssdt_tables(test_data *data)
|
||||
{
|
||||
GArray *ssdt_tables;
|
||||
int ssdt_tables_nr = data->rsdt_tables_nr - 1; /* fadt is first */
|
||||
int i;
|
||||
|
||||
ssdt_tables = g_array_sized_new(false, true, sizeof(AcpiSdtTable),
|
||||
ssdt_tables_nr);
|
||||
for (i = 0; i < ssdt_tables_nr; i++) {
|
||||
AcpiSdtTable ssdt_table;
|
||||
uint32_t addr = data->rsdt_tables_addr[i + 1]; /* fadt is first */
|
||||
test_dst_table(&ssdt_table, addr);
|
||||
g_array_append_val(ssdt_tables, ssdt_table);
|
||||
}
|
||||
data->ssdt_tables = ssdt_tables;
|
||||
}
|
||||
|
||||
static void test_acpi_one(const char *params, test_data *data)
|
||||
{
|
||||
char *args;
|
||||
uint8_t signature_low;
|
||||
uint8_t signature_high;
|
||||
uint16_t signature;
|
||||
int i;
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
args = g_strdup_printf("-net none -display none %s %s",
|
||||
params ? params : "", disk);
|
||||
qtest_start(args);
|
||||
|
||||
/* Wait at most 1 minute */
|
||||
#define TEST_DELAY (1 * G_USEC_PER_SEC / 10)
|
||||
#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1)
|
||||
|
||||
/* Poll until code has run and modified memory. Once it has we know BIOS
|
||||
* initialization is done. TODO: check that IP reached the halt
|
||||
* instruction.
|
||||
*/
|
||||
for (i = 0; i < TEST_CYCLES; ++i) {
|
||||
signature_low = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET);
|
||||
signature_high = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1);
|
||||
signature = (signature_high << 8) | signature_low;
|
||||
if (signature == SIGNATURE) {
|
||||
break;
|
||||
}
|
||||
g_usleep(TEST_DELAY);
|
||||
}
|
||||
g_assert_cmphex(signature, ==, SIGNATURE);
|
||||
|
||||
test_acpi_rsdp_address(data);
|
||||
test_acpi_rsdp_table(data);
|
||||
test_acpi_rsdt_table(data);
|
||||
test_acpi_fadt_table(data);
|
||||
test_acpi_facs_table(data);
|
||||
test_acpi_dsdt_table(data);
|
||||
test_acpi_ssdt_tables(data);
|
||||
|
||||
qtest_quit(global_qtest);
|
||||
g_free(args);
|
||||
}
|
||||
|
||||
static void test_acpi_tcg(void)
|
||||
{
|
||||
test_data data;
|
||||
|
||||
/* Supplying -machine accel argument overrides the default (qtest).
|
||||
* This is to make guest actually run.
|
||||
*/
|
||||
test_acpi_one("-machine accel=tcg", &data);
|
||||
|
||||
free_test_data(&data);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *arch = qtest_get_arch();
|
||||
FILE *f = fopen(disk, "w");
|
||||
fwrite(boot_sector, 1, sizeof boot_sector, f);
|
||||
fclose(f);
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
|
||||
qtest_add_func("acpi/tcg", test_acpi_tcg);
|
||||
}
|
||||
return g_test_run();
|
||||
}
|
@ -96,12 +96,16 @@ typedef struct PageDesc {
|
||||
# define L1_MAP_ADDR_SPACE_BITS TARGET_VIRT_ADDR_SPACE_BITS
|
||||
#endif
|
||||
|
||||
/* Size of the L2 (and L3, etc) page tables. */
|
||||
#define V_L2_BITS 10
|
||||
#define V_L2_SIZE (1 << V_L2_BITS)
|
||||
|
||||
/* The bits remaining after N lower levels of page tables. */
|
||||
#define V_L1_BITS_REM \
|
||||
((L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % L2_BITS)
|
||||
((L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % V_L2_BITS)
|
||||
|
||||
#if V_L1_BITS_REM < 4
|
||||
#define V_L1_BITS (V_L1_BITS_REM + L2_BITS)
|
||||
#define V_L1_BITS (V_L1_BITS_REM + V_L2_BITS)
|
||||
#else
|
||||
#define V_L1_BITS V_L1_BITS_REM
|
||||
#endif
|
||||
@ -395,18 +399,18 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
|
||||
lp = l1_map + ((index >> V_L1_SHIFT) & (V_L1_SIZE - 1));
|
||||
|
||||
/* Level 2..N-1. */
|
||||
for (i = V_L1_SHIFT / L2_BITS - 1; i > 0; i--) {
|
||||
for (i = V_L1_SHIFT / V_L2_BITS - 1; i > 0; i--) {
|
||||
void **p = *lp;
|
||||
|
||||
if (p == NULL) {
|
||||
if (!alloc) {
|
||||
return NULL;
|
||||
}
|
||||
ALLOC(p, sizeof(void *) * L2_SIZE);
|
||||
ALLOC(p, sizeof(void *) * V_L2_SIZE);
|
||||
*lp = p;
|
||||
}
|
||||
|
||||
lp = p + ((index >> (i * L2_BITS)) & (L2_SIZE - 1));
|
||||
lp = p + ((index >> (i * V_L2_BITS)) & (V_L2_SIZE - 1));
|
||||
}
|
||||
|
||||
pd = *lp;
|
||||
@ -414,13 +418,13 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)
|
||||
if (!alloc) {
|
||||
return NULL;
|
||||
}
|
||||
ALLOC(pd, sizeof(PageDesc) * L2_SIZE);
|
||||
ALLOC(pd, sizeof(PageDesc) * V_L2_SIZE);
|
||||
*lp = pd;
|
||||
}
|
||||
|
||||
#undef ALLOC
|
||||
|
||||
return pd + (index & (L2_SIZE - 1));
|
||||
return pd + (index & (V_L2_SIZE - 1));
|
||||
}
|
||||
|
||||
static inline PageDesc *page_find(tb_page_addr_t index)
|
||||
@ -655,14 +659,14 @@ static void page_flush_tb_1(int level, void **lp)
|
||||
if (level == 0) {
|
||||
PageDesc *pd = *lp;
|
||||
|
||||
for (i = 0; i < L2_SIZE; ++i) {
|
||||
for (i = 0; i < V_L2_SIZE; ++i) {
|
||||
pd[i].first_tb = NULL;
|
||||
invalidate_page_bitmap(pd + i);
|
||||
}
|
||||
} else {
|
||||
void **pp = *lp;
|
||||
|
||||
for (i = 0; i < L2_SIZE; ++i) {
|
||||
for (i = 0; i < V_L2_SIZE; ++i) {
|
||||
page_flush_tb_1(level - 1, pp + i);
|
||||
}
|
||||
}
|
||||
@ -673,7 +677,7 @@ static void page_flush_tb(void)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < V_L1_SIZE; i++) {
|
||||
page_flush_tb_1(V_L1_SHIFT / L2_BITS - 1, l1_map + i);
|
||||
page_flush_tb_1(V_L1_SHIFT / V_L2_BITS - 1, l1_map + i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1600,7 +1604,7 @@ static int walk_memory_regions_1(struct walk_memory_regions_data *data,
|
||||
if (level == 0) {
|
||||
PageDesc *pd = *lp;
|
||||
|
||||
for (i = 0; i < L2_SIZE; ++i) {
|
||||
for (i = 0; i < V_L2_SIZE; ++i) {
|
||||
int prot = pd[i].flags;
|
||||
|
||||
pa = base | (i << TARGET_PAGE_BITS);
|
||||
@ -1614,9 +1618,9 @@ static int walk_memory_regions_1(struct walk_memory_regions_data *data,
|
||||
} else {
|
||||
void **pp = *lp;
|
||||
|
||||
for (i = 0; i < L2_SIZE; ++i) {
|
||||
for (i = 0; i < V_L2_SIZE; ++i) {
|
||||
pa = base | ((abi_ulong)i <<
|
||||
(TARGET_PAGE_BITS + L2_BITS * level));
|
||||
(TARGET_PAGE_BITS + V_L2_BITS * level));
|
||||
rc = walk_memory_regions_1(data, pa, level - 1, pp + i);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
@ -1639,7 +1643,7 @@ int walk_memory_regions(void *priv, walk_memory_regions_fn fn)
|
||||
|
||||
for (i = 0; i < V_L1_SIZE; i++) {
|
||||
int rc = walk_memory_regions_1(&data, (abi_ulong)i << V_L1_SHIFT,
|
||||
V_L1_SHIFT / L2_BITS - 1, l1_map + i);
|
||||
V_L1_SHIFT / V_L2_BITS - 1, l1_map + i);
|
||||
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
|
@ -19,13 +19,6 @@
|
||||
#ifndef TRANSLATE_ALL_H
|
||||
#define TRANSLATE_ALL_H
|
||||
|
||||
/* Size of the L2 (and L3, etc) page tables. */
|
||||
#define L2_BITS 10
|
||||
#define L2_SIZE (1 << L2_BITS)
|
||||
|
||||
#define P_L2_LEVELS \
|
||||
(((TARGET_PHYS_ADDR_SPACE_BITS - TARGET_PAGE_BITS - 1) / L2_BITS) + 1)
|
||||
|
||||
/* translate-all.c */
|
||||
void tb_invalidate_phys_page_fast(tb_page_addr_t start, int len);
|
||||
void cpu_unlink_tb(CPUState *cpu);
|
||||
|
11
vl.c
11
vl.c
@ -2624,7 +2624,7 @@ static struct {
|
||||
{ "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed },
|
||||
{ "xen", "Xen", xen_available, xen_init, &xen_allowed },
|
||||
{ "kvm", "KVM", kvm_available, kvm_init, &kvm_allowed },
|
||||
{ "qtest", "QTest", qtest_available, qtest_init, &qtest_allowed },
|
||||
{ "qtest", "QTest", qtest_available, qtest_init_accel, &qtest_allowed },
|
||||
};
|
||||
|
||||
static int configure_accelerator(void)
|
||||
@ -2836,6 +2836,8 @@ int main(int argc, char **argv, char **envp)
|
||||
QEMUMachine *machine;
|
||||
const char *cpu_model;
|
||||
const char *vga_model = "none";
|
||||
const char *qtest_chrdev = NULL;
|
||||
const char *qtest_log = NULL;
|
||||
const char *pid_file = NULL;
|
||||
const char *incoming = NULL;
|
||||
#ifdef CONFIG_VNC
|
||||
@ -4043,8 +4045,8 @@ int main(int argc, char **argv, char **envp)
|
||||
|
||||
configure_accelerator();
|
||||
|
||||
if (!qtest_enabled() && qtest_chrdev) {
|
||||
qtest_init();
|
||||
if (qtest_chrdev) {
|
||||
qtest_init(qtest_chrdev, qtest_log);
|
||||
}
|
||||
|
||||
machine_opts = qemu_get_machine_opts();
|
||||
@ -4239,7 +4241,8 @@ int main(int argc, char **argv, char **envp)
|
||||
|
||||
qdev_machine_init();
|
||||
|
||||
QEMUMachineInitArgs args = { .ram_size = ram_size,
|
||||
QEMUMachineInitArgs args = { .machine = machine,
|
||||
.ram_size = ram_size,
|
||||
.boot_order = boot_order,
|
||||
.kernel_filename = kernel_filename,
|
||||
.kernel_cmdline = kernel_cmdline,
|
||||
|
Loading…
Reference in New Issue
Block a user