Merge branch 'ppc-next' of git://repo.or.cz/qemu/agraf

* 'ppc-next' of git://repo.or.cz/qemu/agraf:
  PPC: Add description for the Freescale e500mc core.
  pseries: Check for duplicate addresses on the spapr-vio bus
  pseries: Populate "/chosen/linux,stdout-path" in the FDT
  pseries: Add a routine to find a stable "default" vty and use it
  pseries: Emit device tree nodes in reg order
  pseries: FDT NUMA extensions to support multi-node guests
  pseries: Remove hcalls callback
  kvm-ppc: halt secondary cpus when guest reset
  console: Fix segfault on screendump without VGA adapter
  PPC: monitor: add ability to dump SLB entries
This commit is contained in:
Aurelien Jarno 2012-01-07 22:01:57 +01:00
commit 15f43ccda1
11 changed files with 347 additions and 65 deletions

View File

@ -186,7 +186,9 @@ void vga_hw_screen_dump(const char *filename)
consoles[0]->hw_screen_dump(consoles[0]->hw, filename); consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
} }
console_select(previous_active_console->index); if (previous_active_console) {
console_select(previous_active_console->index);
}
} }
void vga_hw_text_update(console_ch_t *chardata) void vga_hw_text_update(console_ch_t *chardata)

View File

@ -112,6 +112,7 @@ static void spin_kick(void *data)
env->halted = 0; env->halted = 0;
env->exception_index = -1; env->exception_index = -1;
env->stopped = 0;
qemu_cpu_kick(env); qemu_cpu_kick(env);
} }

View File

@ -97,6 +97,44 @@ qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num)
return qirq; return qirq;
} }
static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr)
{
int ret = 0, offset;
CPUState *env;
char cpu_model[32];
int smt = kvmppc_smt_threads();
assert(spapr->cpu_model);
for (env = first_cpu; env != NULL; env = env->next_cpu) {
uint32_t associativity[] = {cpu_to_be32(0x5),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(env->numa_node),
cpu_to_be32(env->cpu_index)};
if ((env->cpu_index % smt) != 0) {
continue;
}
snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model,
env->cpu_index);
offset = fdt_path_offset(fdt, cpu_model);
if (offset < 0) {
return offset;
}
ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity,
sizeof(associativity));
if (ret < 0) {
return ret;
}
}
return ret;
}
static void *spapr_create_fdt_skel(const char *cpu_model, static void *spapr_create_fdt_skel(const char *cpu_model,
target_phys_addr_t rma_size, target_phys_addr_t rma_size,
target_phys_addr_t initrd_base, target_phys_addr_t initrd_base,
@ -107,9 +145,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
{ {
void *fdt; void *fdt;
CPUState *env; CPUState *env;
uint64_t mem_reg_property_rma[] = { 0, cpu_to_be64(rma_size) }; uint64_t mem_reg_property[2];
uint64_t mem_reg_property_nonrma[] = { cpu_to_be64(rma_size),
cpu_to_be64(ram_size - rma_size) };
uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t start_prop = cpu_to_be32(initrd_base);
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
@ -119,6 +155,13 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
int i; int i;
char *modelname; char *modelname;
int smt = kvmppc_smt_threads(); int smt = kvmppc_smt_threads();
unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0),
cpu_to_be32(0x0), cpu_to_be32(0x0),
cpu_to_be32(0x0)};
char mem_name[32];
target_phys_addr_t node0_size, mem_start;
#define _FDT(exp) \ #define _FDT(exp) \
do { \ do { \
@ -146,6 +189,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
/* /chosen */ /* /chosen */
_FDT((fdt_begin_node(fdt, "chosen"))); _FDT((fdt_begin_node(fdt, "chosen")));
/* Set Form1_affinity */
_FDT((fdt_property(fdt, "ibm,architecture-vec-5", vec5, sizeof(vec5))));
_FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline))); _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
_FDT((fdt_property(fdt, "linux,initrd-start", _FDT((fdt_property(fdt, "linux,initrd-start",
&start_prop, sizeof(start_prop)))); &start_prop, sizeof(start_prop))));
@ -164,24 +210,54 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
_FDT((fdt_end_node(fdt))); _FDT((fdt_end_node(fdt)));
/* memory node(s) */ /* memory node(s) */
_FDT((fdt_begin_node(fdt, "memory@0"))); node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size;
if (rma_size > node0_size) {
rma_size = node0_size;
}
/* RMA */
mem_reg_property[0] = 0;
mem_reg_property[1] = cpu_to_be64(rma_size);
_FDT((fdt_begin_node(fdt, "memory@0")));
_FDT((fdt_property_string(fdt, "device_type", "memory"))); _FDT((fdt_property_string(fdt, "device_type", "memory")));
_FDT((fdt_property(fdt, "reg", mem_reg_property_rma, _FDT((fdt_property(fdt, "reg", mem_reg_property,
sizeof(mem_reg_property_rma)))); sizeof(mem_reg_property))));
_FDT((fdt_property(fdt, "ibm,associativity", associativity,
sizeof(associativity))));
_FDT((fdt_end_node(fdt))); _FDT((fdt_end_node(fdt)));
if (ram_size > rma_size) { /* RAM: Node 0 */
char mem_name[32]; if (node0_size > rma_size) {
mem_reg_property[0] = cpu_to_be64(rma_size);
mem_reg_property[1] = cpu_to_be64(node0_size - rma_size);
sprintf(mem_name, "memory@%" PRIx64, (uint64_t)rma_size); sprintf(mem_name, "memory@" TARGET_FMT_lx, rma_size);
_FDT((fdt_begin_node(fdt, mem_name))); _FDT((fdt_begin_node(fdt, mem_name)));
_FDT((fdt_property_string(fdt, "device_type", "memory"))); _FDT((fdt_property_string(fdt, "device_type", "memory")));
_FDT((fdt_property(fdt, "reg", mem_reg_property_nonrma, _FDT((fdt_property(fdt, "reg", mem_reg_property,
sizeof(mem_reg_property_nonrma)))); sizeof(mem_reg_property))));
_FDT((fdt_property(fdt, "ibm,associativity", associativity,
sizeof(associativity))));
_FDT((fdt_end_node(fdt))); _FDT((fdt_end_node(fdt)));
} }
/* RAM: Node 1 and beyond */
mem_start = node0_size;
for (i = 1; i < nb_numa_nodes; i++) {
mem_reg_property[0] = cpu_to_be64(mem_start);
mem_reg_property[1] = cpu_to_be64(node_mem[i]);
associativity[3] = associativity[4] = cpu_to_be32(i);
sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start);
_FDT((fdt_begin_node(fdt, mem_name)));
_FDT((fdt_property_string(fdt, "device_type", "memory")));
_FDT((fdt_property(fdt, "reg", mem_reg_property,
sizeof(mem_reg_property))));
_FDT((fdt_property(fdt, "ibm,associativity", associativity,
sizeof(associativity))));
_FDT((fdt_end_node(fdt)));
mem_start += node_mem[i];
}
/* cpus */ /* cpus */
_FDT((fdt_begin_node(fdt, "cpus"))); _FDT((fdt_begin_node(fdt, "cpus")));
@ -194,6 +270,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
modelname[i] = toupper(modelname[i]); modelname[i] = toupper(modelname[i]);
} }
/* This is needed during FDT finalization */
spapr->cpu_model = g_strdup(modelname);
for (env = first_cpu; env != NULL; env = env->next_cpu) { for (env = first_cpu; env != NULL; env = env->next_cpu) {
int index = env->cpu_index; int index = env->cpu_index;
uint32_t servers_prop[smp_threads]; uint32_t servers_prop[smp_threads];
@ -280,6 +359,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
_FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop, _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
sizeof(hypertas_prop)))); sizeof(hypertas_prop))));
_FDT((fdt_property(fdt, "ibm,associativity-reference-points",
refpoints, sizeof(refpoints))));
_FDT((fdt_end_node(fdt))); _FDT((fdt_end_node(fdt)));
/* interrupt controller */ /* interrupt controller */
@ -351,6 +433,16 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
fprintf(stderr, "Couldn't set up RTAS device tree properties\n"); fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
} }
/* Advertise NUMA via ibm,associativity */
if (nb_numa_nodes > 1) {
ret = spapr_set_associativity(fdt, spapr);
if (ret < 0) {
fprintf(stderr, "Couldn't set up NUMA device tree properties\n");
}
}
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
_FDT((fdt_pack(fdt))); _FDT((fdt_pack(fdt)));
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));

View File

@ -21,6 +21,7 @@ typedef struct sPAPREnvironment {
target_ulong entry_point; target_ulong entry_point;
int next_irq; int next_irq;
int rtc_offset; int rtc_offset;
char *cpu_model;
} sPAPREnvironment; } sPAPREnvironment;
#define H_SUCCESS 0 #define H_SUCCESS 0

View File

@ -474,16 +474,6 @@ static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
return H_SUCCESS; return H_SUCCESS;
} }
static void vlan_hcalls(VIOsPAPRBus *bus)
{
spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
h_add_logical_lan_buffer);
spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
}
static VIOsPAPRDeviceInfo spapr_vlan = { static VIOsPAPRDeviceInfo spapr_vlan = {
.init = spapr_vlan_init, .init = spapr_vlan_init,
.devnode = spapr_vlan_devnode, .devnode = spapr_vlan_devnode,
@ -491,7 +481,6 @@ static VIOsPAPRDeviceInfo spapr_vlan = {
.dt_type = "network", .dt_type = "network",
.dt_compatible = "IBM,l-lan", .dt_compatible = "IBM,l-lan",
.signal_mask = 0x1, .signal_mask = 0x1,
.hcalls = vlan_hcalls,
.qdev.name = "spapr-vlan", .qdev.name = "spapr-vlan",
.qdev.size = sizeof(VIOsPAPRVLANDevice), .qdev.size = sizeof(VIOsPAPRVLANDevice),
.qdev.props = (Property[]) { .qdev.props = (Property[]) {
@ -504,5 +493,11 @@ static VIOsPAPRDeviceInfo spapr_vlan = {
static void spapr_vlan_register(void) static void spapr_vlan_register(void)
{ {
spapr_vio_bus_register_withprop(&spapr_vlan); spapr_vio_bus_register_withprop(&spapr_vlan);
spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
h_add_logical_lan_buffer);
spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
} }
device_init(spapr_vlan_register); device_init(spapr_vlan_register);

View File

@ -621,11 +621,43 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
rtas_st(rets, 0, 0); rtas_st(rets, 0, 0);
} }
static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
{
VIOsPAPRDevice *other_sdev;
DeviceState *qdev;
VIOsPAPRBus *sbus;
sbus = DO_UPCAST(VIOsPAPRBus, bus, sdev->qdev.parent_bus);
/*
* Check two device aren't given clashing addresses by the user (or some
* other mechanism). We have to open code this because we have to check
* for matches with devices other than us.
*/
QTAILQ_FOREACH(qdev, &sbus->bus.children, sibling) {
other_sdev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
if (other_sdev != sdev && other_sdev->reg == sdev->reg) {
fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n",
info->qdev.name, other_sdev->qdev.info->name, sdev->reg);
return -EEXIST;
}
}
return 0;
}
static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo) static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
{ {
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo; VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
char *id; char *id;
int ret;
ret = spapr_vio_check_reg(dev, info);
if (ret) {
return ret;
}
/* Don't overwrite ids assigned on the command line */ /* Don't overwrite ids assigned on the command line */
if (!dev->qdev.id) { if (!dev->qdev.id) {
@ -684,7 +716,6 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
VIOsPAPRBus *bus; VIOsPAPRBus *bus;
BusState *qbus; BusState *qbus;
DeviceState *dev; DeviceState *dev;
DeviceInfo *qinfo;
/* Create bridge device */ /* Create bridge device */
dev = qdev_create(NULL, "spapr-vio-bridge"); dev = qdev_create(NULL, "spapr-vio-bridge");
@ -711,18 +742,6 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass); spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
spapr_rtas_register("quiesce", rtas_quiesce); spapr_rtas_register("quiesce", rtas_quiesce);
for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
if (qinfo->bus_info != &spapr_vio_bus_info) {
continue;
}
if (info->hcalls) {
info->hcalls(bus);
}
}
return bus; return bus;
} }
@ -749,21 +768,95 @@ static void spapr_vio_register_devices(void)
device_init(spapr_vio_register_devices) device_init(spapr_vio_register_devices)
#ifdef CONFIG_FDT #ifdef CONFIG_FDT
static int compare_reg(const void *p1, const void *p2)
{
VIOsPAPRDevice const *dev1, *dev2;
dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
if (dev1->reg < dev2->reg) {
return -1;
}
if (dev1->reg == dev2->reg) {
return 0;
}
/* dev1->reg > dev2->reg */
return 1;
}
int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt) int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
{ {
DeviceState *qdev; DeviceState *qdev, **qdevs;
int ret = 0; int i, num, ret = 0;
/* Count qdevs on the bus list */
num = 0;
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) { QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; num++;
}
/* Copy out into an array of pointers */
qdevs = g_malloc(sizeof(qdev) * num);
num = 0;
QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
qdevs[num++] = qdev;
}
/* Sort the array */
qsort(qdevs, num, sizeof(qdev), compare_reg);
/* Hack alert. Give the devices to libfdt in reverse order, we happen
* to know that will mean they are in forward order in the tree. */
for (i = num - 1; i >= 0; i--) {
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
ret = vio_make_devnode(dev, fdt); ret = vio_make_devnode(dev, fdt);
if (ret < 0) { if (ret < 0) {
return ret; goto out;
} }
} }
return 0; ret = 0;
out:
free(qdevs);
return ret;
}
int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
{
VIOsPAPRDevice *dev;
char *name, *path;
int ret, offset;
dev = spapr_vty_get_default(bus);
if (!dev)
return 0;
offset = fdt_path_offset(fdt, "/chosen");
if (offset < 0) {
return offset;
}
name = vio_format_dev_name(dev);
if (!name) {
return -ENOMEM;
}
if (asprintf(&path, "/vdevice/%s", name) < 0) {
path = NULL;
ret = -ENOMEM;
goto out;
}
ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
out:
free(name);
free(path);
return ret;
} }
#endif /* CONFIG_FDT */ #endif /* CONFIG_FDT */

View File

@ -75,7 +75,6 @@ typedef struct {
const char *dt_name, *dt_type, *dt_compatible; const char *dt_name, *dt_type, *dt_compatible;
target_ulong signal_mask; target_ulong signal_mask;
int (*init)(VIOsPAPRDevice *dev); int (*init)(VIOsPAPRDevice *dev);
void (*hcalls)(VIOsPAPRBus *bus);
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off); int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
} VIOsPAPRDeviceInfo; } VIOsPAPRDeviceInfo;
@ -83,6 +82,7 @@ extern VIOsPAPRBus *spapr_vio_bus_init(void);
extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg); extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info); extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt); extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode); extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
@ -108,6 +108,8 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev);
void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd); void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd);
void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg); void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg);
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus);
int spapr_tce_set_bypass(uint32_t unit, uint32_t enable); int spapr_tce_set_bypass(uint32_t unit, uint32_t enable);
void spapr_vio_quiesce(void); void spapr_vio_quiesce(void);

View File

@ -135,18 +135,11 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
qdev_init_nofail(dev); qdev_init_nofail(dev);
} }
static void vty_hcalls(VIOsPAPRBus *bus)
{
spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
}
static VIOsPAPRDeviceInfo spapr_vty = { static VIOsPAPRDeviceInfo spapr_vty = {
.init = spapr_vty_init, .init = spapr_vty_init,
.dt_name = "vty", .dt_name = "vty",
.dt_type = "serial", .dt_type = "serial",
.dt_compatible = "hvterm1", .dt_compatible = "hvterm1",
.hcalls = vty_hcalls,
.qdev.name = "spapr-vty", .qdev.name = "spapr-vty",
.qdev.size = sizeof(VIOsPAPRVTYDevice), .qdev.size = sizeof(VIOsPAPRVTYDevice),
.qdev.props = (Property[]) { .qdev.props = (Property[]) {
@ -156,24 +149,53 @@ static VIOsPAPRDeviceInfo spapr_vty = {
}, },
}; };
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
{
VIOsPAPRDevice *sdev, *selected;
DeviceState *iter;
/*
* To avoid the console bouncing around we want one VTY to be
* the "default". We haven't really got anything to go on, so
* arbitrarily choose the one with the lowest reg value.
*/
selected = NULL;
QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
/* Only look at VTY devices */
if (iter->info != &spapr_vty.qdev) {
continue;
}
sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter);
/* First VTY we've found, so it is selected for now */
if (!selected) {
selected = sdev;
continue;
}
/* Choose VTY with lowest reg value */
if (sdev->reg < selected->reg) {
selected = sdev;
}
}
return selected;
}
static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg) static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
{ {
VIOsPAPRDevice *sdev; VIOsPAPRDevice *sdev;
sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
if (!sdev && reg == 0) { if (!sdev && reg == 0) {
DeviceState *qdev;
/* Hack for kernel early debug, which always specifies reg==0. /* Hack for kernel early debug, which always specifies reg==0.
* We search all VIO devices, and grab the first available vty * We search all VIO devices, and grab the vty with the lowest
* device. This attempts to mimic existing PowerVM behaviour * reg. This attempts to mimic existing PowerVM behaviour
* (early debug does work there, despite having no vty with * (early debug does work there, despite having no vty with
* reg==0. */ * reg==0. */
QTAILQ_FOREACH(qdev, &spapr->vio_bus->bus.children, sibling) { return spapr_vty_get_default(spapr->vio_bus);
if (qdev->info == &spapr_vty.qdev) {
return DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
}
}
} }
return sdev; return sdev;
@ -182,5 +204,7 @@ static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
static void spapr_vty_register(void) static void spapr_vty_register(void)
{ {
spapr_vio_bus_register_withprop(&spapr_vty); spapr_vio_bus_register_withprop(&spapr_vty);
spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
} }
device_init(spapr_vty_register); device_init(spapr_vty_register);

View File

@ -1545,12 +1545,40 @@ static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
} }
} }
#if defined(TARGET_PPC64)
static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
CPUState *env)
{
int i;
uint64_t slbe, slbv;
cpu_synchronize_state(env);
cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
for (i = 0; i < env->slb_nr; i++) {
slbe = env->slb[i].esid;
slbv = env->slb[i].vsid;
if (slbe == 0 && slbv == 0) {
continue;
}
cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
i, slbe, slbv);
}
}
#endif
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env) void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
{ {
switch (env->mmu_model) { switch (env->mmu_model) {
case POWERPC_MMU_BOOKE206: case POWERPC_MMU_BOOKE206:
mmubooke206_dump_mmu(f, cpu_fprintf, env); mmubooke206_dump_mmu(f, cpu_fprintf, env);
break; break;
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
case POWERPC_MMU_2_06:
mmubooks_dump_mmu(f, cpu_fprintf, env);
break;
#endif
default: default:
cpu_fprintf(f, "%s: unimplemented\n", __func__); cpu_fprintf(f, "%s: unimplemented\n", __func__);
} }

View File

@ -504,7 +504,7 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run)
int kvm_arch_process_async_events(CPUState *env) int kvm_arch_process_async_events(CPUState *env)
{ {
return 0; return env->halted;
} }
static int kvmppc_handle_halt(CPUState *env) static int kvmppc_handle_halt(CPUState *env)

View File

@ -2,6 +2,7 @@
* PowerPC CPU initialization for qemu. * PowerPC CPU initialization for qemu.
* *
* Copyright (c) 2003-2007 Jocelyn Mayer * Copyright (c) 2003-2007 Jocelyn Mayer
* Copyright 2011 Freescale Semiconductor, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -4399,6 +4400,33 @@ static void init_proc_e300 (CPUPPCState *env)
#define check_pow_e500v2 check_pow_hid0 #define check_pow_e500v2 check_pow_hid0
#define init_proc_e500v2 init_proc_e500v2 #define init_proc_e500v2 init_proc_e500v2
/* e500mc core */
#define POWERPC_INSNS_e500mc (PPC_INSNS_BASE | PPC_ISEL | \
PPC_WRTEE | PPC_RFDI | PPC_RFMCI | \
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
PPC_FLOAT | PPC_FLOAT_FRES | \
PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \
PPC_FLOAT_STFIWX | PPC_WAIT | \
PPC_MEM_TLBSYNC | PPC_TLBIVAX)
#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206)
#define POWERPC_MSRM_e500mc (0x000000001402FB36ULL)
#define POWERPC_MMU_e500mc (POWERPC_MMU_BOOKE206)
#define POWERPC_EXCP_e500mc (POWERPC_EXCP_BOOKE)
#define POWERPC_INPUT_e500mc (PPC_FLAGS_INPUT_BookE)
/* Fixme: figure out the correct flag for e500mc */
#define POWERPC_BFDM_e500mc (bfd_mach_ppc_e500)
#define POWERPC_FLAG_e500mc (POWERPC_FLAG_CE | POWERPC_FLAG_DE | \
POWERPC_FLAG_PMM | POWERPC_FLAG_BUS_CLK)
#define check_pow_e500mc check_pow_none
#define init_proc_e500mc init_proc_e500mc
enum fsl_e500_version {
fsl_e500v1,
fsl_e500v2,
fsl_e500mc,
};
static void init_proc_e500 (CPUPPCState *env, int version) static void init_proc_e500 (CPUPPCState *env, int version)
{ {
uint32_t tlbncfg[2]; uint32_t tlbncfg[2];
@ -4430,15 +4458,26 @@ static void init_proc_e500 (CPUPPCState *env, int version)
env->nb_ways = 2; env->nb_ways = 2;
env->id_tlbs = 0; env->id_tlbs = 0;
switch (version) { switch (version) {
case 1: case fsl_e500v1:
/* e500v1 */ /* e500v1 */
tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256); tlbncfg[0] = gen_tlbncfg(2, 1, 1, 0, 256);
tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); tlbncfg[1] = gen_tlbncfg(16, 1, 9, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
env->dcache_line_size = 32;
env->icache_line_size = 32;
break; break;
case 2: case fsl_e500v2:
/* e500v2 */ /* e500v2 */
tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512); tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16); tlbncfg[1] = gen_tlbncfg(16, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 16);
env->dcache_line_size = 32;
env->icache_line_size = 32;
break;
case fsl_e500mc:
/* e500mc */
tlbncfg[0] = gen_tlbncfg(4, 1, 1, 0, 512);
tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64);
env->dcache_line_size = 64;
env->icache_line_size = 64;
break; break;
default: default:
cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]); cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
@ -4522,20 +4561,23 @@ static void init_proc_e500 (CPUPPCState *env, int version)
#endif #endif
init_excp_e200(env); init_excp_e200(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
/* Allocate hardware IRQ controller */ /* Allocate hardware IRQ controller */
ppce500_irq_init(env); ppce500_irq_init(env);
} }
static void init_proc_e500v1(CPUPPCState *env) static void init_proc_e500v1(CPUPPCState *env)
{ {
init_proc_e500(env, 1); init_proc_e500(env, fsl_e500v1);
} }
static void init_proc_e500v2(CPUPPCState *env) static void init_proc_e500v2(CPUPPCState *env)
{ {
init_proc_e500(env, 2); init_proc_e500(env, fsl_e500v2);
}
static void init_proc_e500mc(CPUPPCState *env)
{
init_proc_e500(env, fsl_e500mc);
} }
/* Non-embedded PowerPC */ /* Non-embedded PowerPC */
@ -7070,6 +7112,7 @@ enum {
CPU_POWERPC_e500v2_v21 = 0x80210021, CPU_POWERPC_e500v2_v21 = 0x80210021,
CPU_POWERPC_e500v2_v22 = 0x80210022, CPU_POWERPC_e500v2_v22 = 0x80210022,
CPU_POWERPC_e500v2_v30 = 0x80210030, CPU_POWERPC_e500v2_v30 = 0x80210030,
CPU_POWERPC_e500mc = 0x80230020,
/* MPC85xx microcontrollers */ /* MPC85xx microcontrollers */
#define CPU_POWERPC_MPC8533 CPU_POWERPC_MPC8533_v11 #define CPU_POWERPC_MPC8533 CPU_POWERPC_MPC8533_v11
#define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21 #define CPU_POWERPC_MPC8533_v10 CPU_POWERPC_e500v2_v21
@ -8471,6 +8514,7 @@ static const ppc_def_t ppc_defs[] = {
POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2), POWERPC_DEF("e500v2_v22", CPU_POWERPC_e500v2_v22, e500v2),
/* PowerPC e500v2 v3.0 core */ /* PowerPC e500v2 v3.0 core */
POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2), POWERPC_DEF("e500v2_v30", CPU_POWERPC_e500v2_v30, e500v2),
POWERPC_DEF("e500mc", CPU_POWERPC_e500mc, e500mc),
/* PowerPC e500 microcontrollers */ /* PowerPC e500 microcontrollers */
/* MPC8533 */ /* MPC8533 */
POWERPC_DEF_SVR("MPC8533", POWERPC_DEF_SVR("MPC8533",