Revision 4040ab72

b/Makefile.target
231 231
obj-ppc-y += ppc_oldworld.o
232 232
# NewWorld PowerMac
233 233
obj-ppc-y += ppc_newworld.o
234
# IBM pSeries (sPAPR)i
234
# IBM pSeries (sPAPR)
235 235
ifeq ($(CONFIG_FDT)$(TARGET_PPC64),yy)
236
obj-ppc-y += spapr.o spapr_hcall.o
236
obj-ppc-y += spapr.o spapr_hcall.o spapr_vio.o
237
obj-ppc-y += spapr_vty.o
237 238
endif
238 239
# PowerPC 4xx boards
239 240
obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
b/hw/spapr.c
25 25
 *
26 26
 */
27 27
#include "sysemu.h"
28
#include "qemu-char.h"
29 28
#include "hw.h"
30 29
#include "elf.h"
31 30

  
......
34 33
#include "hw/loader.h"
35 34

  
36 35
#include "hw/spapr.h"
36
#include "hw/spapr_vio.h"
37 37

  
38 38
#include <libfdt.h>
39 39

  
......
60 60
    uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
61 61
    int i;
62 62
    char *modelname;
63
    int ret;
63 64

  
64 65
#define _FDT(exp) \
65 66
    do { \
......
159 160

  
160 161
    _FDT((fdt_end_node(fdt)));
161 162

  
163
    /* vdevice */
164
    _FDT((fdt_begin_node(fdt, "vdevice")));
165

  
166
    _FDT((fdt_property_string(fdt, "device_type", "vdevice")));
167
    _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
168
    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
169
    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
170

  
171
    _FDT((fdt_end_node(fdt)));
172

  
162 173
    _FDT((fdt_end_node(fdt))); /* close root node */
163 174
    _FDT((fdt_finish(fdt)));
164 175

  
176
    /* re-expand to allow for further tweaks */
177
    _FDT((fdt_open_into(fdt, fdt, FDT_MAX_SIZE)));
178

  
179
    ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
180
    if (ret < 0) {
181
        fprintf(stderr, "couldn't setup vio devices in fdt\n");
182
        exit(1);
183
    }
184

  
185
    _FDT((fdt_pack(fdt)));
186

  
165 187
    *fdt_size = fdt_totalsize(fdt);
166 188

  
167 189
    return fdt;
......
177 199
    env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]);
178 200
}
179 201

  
180
/* FIXME: hack until we implement the proper VIO console */
181
static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
182
                                    target_ulong opcode, target_ulong *args)
183
{
184
    uint8_t buf[16];
185

  
186
    stq_p(buf, args[2]);
187
    stq_p(buf + 8, args[3]);
188

  
189
    qemu_chr_write(serial_hds[0], buf, args[1]);
190

  
191
    return 0;
192
}
193

  
194

  
195 202
/* pSeries LPAR / sPAPR hardware init */
196 203
static void ppc_spapr_init(ram_addr_t ram_size,
197 204
                           const char *boot_device,
......
243 250
    ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size);
244 251
    cpu_register_physical_memory(0, ram_size, ram_offset);
245 252

  
246
    spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
253
    spapr->vio_bus = spapr_vio_bus_init();
254

  
255
    for (i = 0; i < MAX_SERIAL_PORTS; i++) {
256
        if (serial_hds[i]) {
257
            spapr_vty_create(spapr->vio_bus, i, serial_hds[i]);
258
        }
259
    }
247 260

  
248 261
    if (kernel_filename) {
249 262
        uint64_t lowaddr = 0;
......
276 289
            initrd_base = 0;
277 290
            initrd_size = 0;
278 291
        }
279

  
280 292
    } else {
281 293
        fprintf(stderr, "pSeries machine needs -kernel for now");
282 294
        exit(1);
b/hw/spapr.h
1 1
#if !defined(__HW_SPAPR_H__)
2 2
#define __HW_SPAPR_H__
3 3

  
4
struct VIOsPAPRBus;
5

  
4 6
typedef struct sPAPREnvironment {
7
    struct VIOsPAPRBus *vio_bus;
5 8
} sPAPREnvironment;
6 9

  
7 10
#define H_SUCCESS         0
b/hw/spapr_vio.c
1
/*
2
 * QEMU sPAPR VIO code
3
 *
4
 * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
5
 * Based on the s390 virtio bus code:
6
 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20
 */
21

  
22
#include "hw.h"
23
#include "sysemu.h"
24
#include "boards.h"
25
#include "monitor.h"
26
#include "loader.h"
27
#include "elf.h"
28
#include "hw/sysbus.h"
29
#include "kvm.h"
30
#include "device_tree.h"
31

  
32
#include "hw/spapr.h"
33
#include "hw/spapr_vio.h"
34

  
35
#ifdef CONFIG_FDT
36
#include <libfdt.h>
37
#endif /* CONFIG_FDT */
38

  
39
/* #define DEBUG_SPAPR */
40

  
41
#ifdef DEBUG_SPAPR
42
#define dprintf(fmt, ...) \
43
    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
44
#else
45
#define dprintf(fmt, ...) \
46
    do { } while (0)
47
#endif
48

  
49
static struct BusInfo spapr_vio_bus_info = {
50
    .name       = "spapr-vio",
51
    .size       = sizeof(VIOsPAPRBus),
52
};
53

  
54
VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
55
{
56
    DeviceState *qdev;
57
    VIOsPAPRDevice *dev = NULL;
58

  
59
    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
60
        dev = (VIOsPAPRDevice *)qdev;
61
        if (dev->reg == reg) {
62
            break;
63
        }
64
    }
65

  
66
    return dev;
67
}
68

  
69
#ifdef CONFIG_FDT
70
static int vio_make_devnode(VIOsPAPRDevice *dev,
71
                            void *fdt)
72
{
73
    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
74
    int vdevice_off, node_off;
75
    int ret;
76

  
77
    vdevice_off = fdt_path_offset(fdt, "/vdevice");
78
    if (vdevice_off < 0) {
79
        return vdevice_off;
80
    }
81

  
82
    node_off = fdt_add_subnode(fdt, vdevice_off, dev->qdev.id);
83
    if (node_off < 0) {
84
        return node_off;
85
    }
86

  
87
    ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
88
    if (ret < 0) {
89
        return ret;
90
    }
91

  
92
    if (info->dt_type) {
93
        ret = fdt_setprop_string(fdt, node_off, "device_type",
94
                                 info->dt_type);
95
        if (ret < 0) {
96
            return ret;
97
        }
98
    }
99

  
100
    if (info->dt_compatible) {
101
        ret = fdt_setprop_string(fdt, node_off, "compatible",
102
                                 info->dt_compatible);
103
        if (ret < 0) {
104
            return ret;
105
        }
106
    }
107

  
108
    if (info->devnode) {
109
        ret = (info->devnode)(dev, fdt, node_off);
110
        if (ret < 0) {
111
            return ret;
112
        }
113
    }
114

  
115
    return node_off;
116
}
117
#endif /* CONFIG_FDT */
118

  
119
static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
120
{
121
    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
122
    VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
123
    char *id;
124

  
125
    if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) {
126
        return -1;
127
    }
128

  
129
    dev->qdev.id = id;
130

  
131
    return info->init(dev);
132
}
133

  
134
void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
135
{
136
    info->qdev.init = spapr_vio_busdev_init;
137
    info->qdev.bus_info = &spapr_vio_bus_info;
138

  
139
    assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
140
    qdev_register(&info->qdev);
141
}
142

  
143
VIOsPAPRBus *spapr_vio_bus_init(void)
144
{
145
    VIOsPAPRBus *bus;
146
    BusState *qbus;
147
    DeviceState *dev;
148
    DeviceInfo *qinfo;
149

  
150
    /* Create bridge device */
151
    dev = qdev_create(NULL, "spapr-vio-bridge");
152
    qdev_init_nofail(dev);
153

  
154
    /* Create bus on bridge device */
155

  
156
    qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
157
    bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
158

  
159
    for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
160
        VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
161

  
162
        if (qinfo->bus_info != &spapr_vio_bus_info) {
163
            continue;
164
        }
165

  
166
        if (info->hcalls) {
167
            info->hcalls(bus);
168
        }
169
    }
170

  
171
    return bus;
172
}
173

  
174
/* Represents sPAPR hcall VIO devices */
175

  
176
static int spapr_vio_bridge_init(SysBusDevice *dev)
177
{
178
    /* nothing */
179
    return 0;
180
}
181

  
182
static SysBusDeviceInfo spapr_vio_bridge_info = {
183
    .init = spapr_vio_bridge_init,
184
    .qdev.name  = "spapr-vio-bridge",
185
    .qdev.size  = sizeof(SysBusDevice),
186
    .qdev.no_user = 1,
187
};
188

  
189
static void spapr_vio_register_devices(void)
190
{
191
    sysbus_register_withprop(&spapr_vio_bridge_info);
192
}
193

  
194
device_init(spapr_vio_register_devices)
195

  
196
#ifdef CONFIG_FDT
197
int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
198
{
199
    DeviceState *qdev;
200
    int ret = 0;
201

  
202
    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
203
        VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
204

  
205
        ret = vio_make_devnode(dev, fdt);
206

  
207
        if (ret < 0) {
208
            return ret;
209
        }
210
    }
211

  
212
    return 0;
213
}
214
#endif /* CONFIG_FDT */
b/hw/spapr_vio.h
1
#ifndef _HW_SPAPR_VIO_H
2
#define _HW_SPAPR_VIO_H
3
/*
4
 * QEMU sPAPR VIO bus definitions
5
 *
6
 * Copyright (c) 2010 David Gibson, IBM Corporation <david@gibson.dropbear.id.au>
7
 * Based on the s390 virtio bus definitions:
8
 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
9
 *
10
 * This library is free software; you can redistribute it and/or
11
 * modify it under the terms of the GNU Lesser General Public
12
 * License as published by the Free Software Foundation; either
13
 * version 2 of the License, or (at your option) any later version.
14
 *
15
 * This library is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
 * Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public
21
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
22
 */
23

  
24
typedef struct VIOsPAPRDevice {
25
    DeviceState qdev;
26
    uint32_t reg;
27
} VIOsPAPRDevice;
28

  
29
typedef struct VIOsPAPRBus {
30
    BusState bus;
31
} VIOsPAPRBus;
32

  
33
typedef struct {
34
    DeviceInfo qdev;
35
    const char *dt_name, *dt_type, *dt_compatible;
36
    int (*init)(VIOsPAPRDevice *dev);
37
    void (*hcalls)(VIOsPAPRBus *bus);
38
    int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
39
} VIOsPAPRDeviceInfo;
40

  
41
extern VIOsPAPRBus *spapr_vio_bus_init(void);
42
extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
43
extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
44
extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
45

  
46
void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
47
void spapr_vty_create(VIOsPAPRBus *bus,
48
                      uint32_t reg, CharDriverState *chardev);
49

  
50
#endif /* _HW_SPAPR_VIO_H */
b/hw/spapr_vty.c
1
#include "qdev.h"
2
#include "qemu-char.h"
3
#include "hw/spapr.h"
4
#include "hw/spapr_vio.h"
5

  
6
#define VTERM_BUFSIZE   16
7

  
8
typedef struct VIOsPAPRVTYDevice {
9
    VIOsPAPRDevice sdev;
10
    CharDriverState *chardev;
11
    uint32_t in, out;
12
    uint8_t buf[VTERM_BUFSIZE];
13
} VIOsPAPRVTYDevice;
14

  
15
static int vty_can_receive(void *opaque)
16
{
17
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
18

  
19
    return (dev->in - dev->out) < VTERM_BUFSIZE;
20
}
21

  
22
static void vty_receive(void *opaque, const uint8_t *buf, int size)
23
{
24
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
25
    int i;
26

  
27
    for (i = 0; i < size; i++) {
28
        assert((dev->in - dev->out) < VTERM_BUFSIZE);
29
        dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
30
    }
31
}
32

  
33
static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
34
{
35
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
36
    int n = 0;
37

  
38
    while ((n < max) && (dev->out != dev->in)) {
39
        buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
40
    }
41

  
42
    return n;
43
}
44

  
45
void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
46
{
47
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
48

  
49
    /* FIXME: should check the qemu_chr_write() return value */
50
    qemu_chr_write(dev->chardev, buf, len);
51
}
52

  
53
static int spapr_vty_init(VIOsPAPRDevice *sdev)
54
{
55
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
56

  
57
    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
58
                          vty_receive, NULL, dev);
59

  
60
    return 0;
61
}
62

  
63
static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
64
                                    target_ulong opcode, target_ulong *args)
65
{
66
    target_ulong reg = args[0];
67
    target_ulong len = args[1];
68
    target_ulong char0_7 = args[2];
69
    target_ulong char8_15 = args[3];
70
    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
71
    uint8_t buf[16];
72

  
73
    if (!sdev) {
74
        return H_PARAMETER;
75
    }
76

  
77
    if (len > 16) {
78
        return H_PARAMETER;
79
    }
80

  
81
    *((uint64_t *)buf) = cpu_to_be64(char0_7);
82
    *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
83

  
84
    vty_putchars(sdev, buf, len);
85

  
86
    return H_SUCCESS;
87
}
88

  
89
static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
90
                                    target_ulong opcode, target_ulong *args)
91
{
92
    target_ulong reg = args[0];
93
    target_ulong *len = args + 0;
94
    target_ulong *char0_7 = args + 1;
95
    target_ulong *char8_15 = args + 2;
96
    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
97
    uint8_t buf[16];
98

  
99
    if (!sdev) {
100
        return H_PARAMETER;
101
    }
102

  
103
    *len = vty_getchars(sdev, buf, sizeof(buf));
104
    if (*len < 16) {
105
        memset(buf + *len, 0, 16 - *len);
106
    }
107

  
108
    *char0_7 = be64_to_cpu(*((uint64_t *)buf));
109
    *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
110

  
111
    return H_SUCCESS;
112
}
113

  
114
void spapr_vty_create(VIOsPAPRBus *bus,
115
                      uint32_t reg, CharDriverState *chardev)
116
{
117
    DeviceState *dev;
118

  
119
    dev = qdev_create(&bus->bus, "spapr-vty");
120
    qdev_prop_set_uint32(dev, "reg", reg);
121
    qdev_prop_set_chr(dev, "chardev", chardev);
122
    qdev_init_nofail(dev);
123
}
124

  
125
static void vty_hcalls(VIOsPAPRBus *bus)
126
{
127
    spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
128
    spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
129
}
130

  
131
static VIOsPAPRDeviceInfo spapr_vty = {
132
    .init = spapr_vty_init,
133
    .dt_name = "vty",
134
    .dt_type = "serial",
135
    .dt_compatible = "hvterm1",
136
    .hcalls = vty_hcalls,
137
    .qdev.name = "spapr-vty",
138
    .qdev.size = sizeof(VIOsPAPRVTYDevice),
139
    .qdev.props = (Property[]) {
140
        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0),
141
        DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
142
        DEFINE_PROP_END_OF_LIST(),
143
    },
144
};
145

  
146
static void spapr_vty_register(void)
147
{
148
    spapr_vio_bus_register_withprop(&spapr_vty);
149
}
150
device_init(spapr_vty_register);

Also available in: Unified diff