Revision f0fc6f8f

b/hw/mips_mipssim.c
1
/*
2
 * QEMU/mipssim emulation
3
 *
4
 * Emulates a very simple machine model similiar to the one use by the
5
 * proprietary MIPS emulator.
6
 */
7
#include "vl.h"
8

  
9
#ifdef TARGET_WORDS_BIGENDIAN
10
#define BIOS_FILENAME "mips_bios.bin"
11
#else
12
#define BIOS_FILENAME "mipsel_bios.bin"
13
#endif
14

  
15
#ifdef TARGET_MIPS64
16
#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
17
#else
18
#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
19
#endif
20

  
21
#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
22

  
23
static void load_kernel (CPUState *env)
24
{
25
    int64_t entry, kernel_low, kernel_high;
26
    long kernel_size;
27
    long initrd_size;
28
    ram_addr_t initrd_offset;
29

  
30
    kernel_size = load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND,
31
                           &entry, &kernel_low, &kernel_high);
32
    if (kernel_size >= 0) {
33
        if ((entry & ~0x7fffffffULL) == 0x80000000)
34
            entry = (int32_t)entry;
35
        env->PC[env->current_tc] = entry;
36
    } else {
37
        fprintf(stderr, "qemu: could not load kernel '%s'\n",
38
                env->kernel_filename);
39
        exit(1);
40
    }
41

  
42
    /* load initrd */
43
    initrd_size = 0;
44
    initrd_offset = 0;
45
    if (env->initrd_filename) {
46
        initrd_size = get_image_size (env->initrd_filename);
47
        if (initrd_size > 0) {
48
            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
49
            if (initrd_offset + initrd_size > env->ram_size) {
50
                fprintf(stderr,
51
                        "qemu: memory too small for initial ram disk '%s'\n",
52
                        env->initrd_filename);
53
                exit(1);
54
            }
55
            initrd_size = load_image(env->initrd_filename,
56
                                     phys_ram_base + initrd_offset);
57
        }
58
        if (initrd_size == (target_ulong) -1) {
59
            fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
60
                    env->initrd_filename);
61
            exit(1);
62
        }
63
    }
64
}
65

  
66
static void main_cpu_reset(void *opaque)
67
{
68
    CPUState *env = opaque;
69
    cpu_reset(env);
70
    cpu_mips_register(env, NULL);
71

  
72
    if (env->kernel_filename)
73
        load_kernel (env);
74
}
75

  
76
static void
77
mips_mipssim_init (int ram_size, int vga_ram_size, int boot_device,
78
                   DisplayState *ds, const char **fd_filename, int snapshot,
79
                   const char *kernel_filename, const char *kernel_cmdline,
80
                   const char *initrd_filename, const char *cpu_model)
81
{
82
    char buf[1024];
83
    unsigned long bios_offset;
84
    CPUState *env;
85
    int ret;
86
    mips_def_t *def;
87

  
88
    /* Init CPUs. */
89
    if (cpu_model == NULL) {
90
#ifdef TARGET_MIPS64
91
        cpu_model = "5Kf";
92
#else
93
        cpu_model = "24Kf";
94
#endif
95
    }
96
    if (mips_find_by_name(cpu_model, &def) != 0)
97
        def = NULL;
98
    env = cpu_init();
99
    cpu_mips_register(env, def);
100
    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
101
    qemu_register_reset(main_cpu_reset, env);
102

  
103
    /* Allocate RAM. */
104
    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
105

  
106
    /* Map the BIOS / boot exception handler. */
107
    bios_offset = ram_size + vga_ram_size;
108

  
109
    /* Load a BIOS / boot exception handler image. */
110
    if (bios_name == NULL)
111
        bios_name = BIOS_FILENAME;
112
    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, bios_name);
113
    ret = load_image(buf, phys_ram_base + bios_offset);
114
    if ((ret < 0 || ret > BIOS_SIZE) && !kernel_filename) {
115
        /* Bail out if we have neither a kernel image nor boot vector code. */
116
        fprintf(stderr,
117
                "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
118
                buf);
119
        exit(1);
120
    } else {
121
        /* We have a boot vector start address. */
122
        env->PC[env->current_tc] = (target_long)0xbfc00000;
123
        cpu_register_physical_memory(0x1fc00000LL,
124
                                     ret, bios_offset | IO_MEM_ROM);
125
    }
126

  
127
    if (kernel_filename) {
128
        env->ram_size = ram_size;
129
        env->kernel_filename = kernel_filename;
130
        env->kernel_cmdline = kernel_cmdline;
131
        env->initrd_filename = initrd_filename;
132
        load_kernel(env);
133
    }
134

  
135
    /* Init CPU internal devices. */
136
    cpu_mips_irq_init_cpu(env);
137
    cpu_mips_clock_init(env);
138
    cpu_mips_irqctrl_init();
139

  
140
    /* Register 64 KB of ISA IO space at 0x1fd00000. */
141
    isa_mmio_init(0x1fd00000, 0x00010000);
142

  
143
    /* A single 16450 sits at offset 0x3f8. It is attached to
144
       MIPS CPU INT2, which is interrupt 4. */
145
    if (serial_hds[0])
146
        serial_init(0x3f8, env->irq[4], serial_hds[0]);
147

  
148
    if (nd_table[0].vlan) {
149
        if (nd_table[0].model == NULL
150
            || strcmp(nd_table[0].model, "mipsnet") == 0) {
151
            /* MIPSnet uses the MIPS CPU INT0, which is interrupt 2. */
152
            mipsnet_init(0x4200, env->irq[2], &nd_table[0]);
153
        } else if (strcmp(nd_table[0].model, "?") == 0) {
154
            fprintf(stderr, "qemu: Supported NICs: mipsnet\n");
155
            exit (1);
156
        } else {
157
            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
158
            exit (1);
159
        }
160
    }
161
}
162

  
163
QEMUMachine mips_mipssim_machine = {
164
    "mipssim",
165
    "MIPS MIPSsim platform",
166
    mips_mipssim_init,
167
};
b/hw/mipsnet.c
1
#include "vl.h"
2

  
3
#define DEBUG_MIPSNET_SEND
4
#define DEBUG_MIPSNET_RECEIVE
5
//#define DEBUG_MIPSNET_DATA
6
#define DEBUG_MIPSNET_IRQ
7

  
8
/* MIPSnet register offsets */
9

  
10
#define MIPSNET_DEV_ID		0x00
11
# define MIPSNET_DEV_ID_STRING	"MIPSNET0"
12
#define MIPSNET_BUSY		0x08
13
#define MIPSNET_RX_DATA_COUNT	0x0c
14
#define MIPSNET_TX_DATA_COUNT	0x10
15
#define MIPSNET_INT_CTL		0x14
16
# define MIPSNET_INTCTL_TXDONE		0x00000001
17
# define MIPSNET_INTCTL_RXDONE		0x00000002
18
# define MIPSNET_INTCTL_TESTBIT		0x80000000
19
#define MIPSNET_INTERRUPT_INFO	0x18
20
#define MIPSNET_RX_DATA_BUFFER	0x1c
21
#define MIPSNET_TX_DATA_BUFFER	0x20
22

  
23
#define MAX_ETH_FRAME_SIZE	1514
24

  
25
typedef struct MIPSnetState {
26
    uint32_t busy;
27
    uint32_t rx_count;
28
    uint32_t rx_read;
29
    uint32_t tx_count;
30
    uint32_t tx_written;
31
    uint32_t intctl;
32
    uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
33
    uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
34
    qemu_irq irq;
35
    VLANClientState *vc;
36
    NICInfo *nd;
37
} MIPSnetState;
38

  
39
static void mipsnet_reset(MIPSnetState *s)
40
{
41
    s->busy = 1;
42
    s->rx_count = 0;
43
    s->rx_read = 0;
44
    s->tx_count = 0;
45
    s->tx_written = 0;
46
    s->intctl = 0;
47
    memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
48
    memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
49
}
50

  
51
static void mipsnet_update_irq(MIPSnetState *s)
52
{
53
    int isr = !!s->intctl;
54
#ifdef DEBUG_MIPSNET_IRQ
55
    printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl);
56
#endif
57
    qemu_set_irq(s->irq, isr);
58
}
59

  
60
static int mipsnet_buffer_full(MIPSnetState *s)
61
{
62
    if (s->rx_count >= MAX_ETH_FRAME_SIZE)
63
        return 1;
64
    return 0;
65
}
66

  
67
static int mipsnet_can_receive(void *opaque)
68
{
69
    MIPSnetState *s = opaque;
70

  
71
    if (s->busy)
72
        return 0;
73
    return !mipsnet_buffer_full(s);
74
}
75

  
76
static void mipsnet_receive(void *opaque, const uint8_t *buf, int size)
77
{
78
    MIPSnetState *s = opaque;
79

  
80
#ifdef DEBUG_MIPSNET_RECEIVE
81
    printf("mipsnet: receiving len=%d\n", size);
82
#endif
83
    if (!mipsnet_can_receive(opaque))
84
        return;
85

  
86
    s->busy = 1;
87

  
88
    /* Just accept everything. */
89

  
90
    /* Write packet data. */
91
    memcpy(s->rx_buffer, buf, size);
92

  
93
    s->rx_count = size;
94
    s->rx_read = 0;
95

  
96
    /* Now we can signal we have received something. */
97
    s->intctl |= MIPSNET_INTCTL_RXDONE;
98
    mipsnet_update_irq(s);
99
}
100

  
101
static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
102
{
103
    MIPSnetState *s = opaque;
104
    int ret = 0;
105
    const char *devid = MIPSNET_DEV_ID_STRING;
106

  
107
    addr &= 0x3f;
108
    switch (addr) {
109
    case MIPSNET_DEV_ID:
110
	ret = *((uint32_t *)&devid);
111
        break;
112
    case MIPSNET_DEV_ID + 4:
113
	ret = *((uint32_t *)(&devid + 4));
114
        break;
115
    case MIPSNET_BUSY:
116
	ret = s->busy;
117
        break;
118
    case MIPSNET_RX_DATA_COUNT:
119
	ret = s->rx_count;
120
        break;
121
    case MIPSNET_TX_DATA_COUNT:
122
	ret = s->tx_count;
123
        break;
124
    case MIPSNET_INT_CTL:
125
	ret = s->intctl;
126
        s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
127
        break;
128
    case MIPSNET_INTERRUPT_INFO:
129
        /* XXX: This seems to be a per-VPE interrupt number. */
130
	ret = 0;
131
        break;
132
    case MIPSNET_RX_DATA_BUFFER:
133
        if (s->rx_count) {
134
            s->rx_count--;
135
            ret = s->rx_buffer[s->rx_read++];
136
        }
137
        break;
138
    /* Reads as zero. */
139
    case MIPSNET_TX_DATA_BUFFER:
140
    default:
141
        break;
142
    }
143
#ifdef DEBUG_MIPSNET_DATA
144
    printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
145
#endif
146
    return ret;
147
}
148

  
149
static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
150
{
151
    MIPSnetState *s = opaque;
152

  
153
    addr &= 0x3f;
154
#ifdef DEBUG_MIPSNET_DATA
155
    printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
156
#endif
157
    switch (addr) {
158
    case MIPSNET_TX_DATA_COUNT:
159
	s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
160
        s->tx_written = 0;
161
        break;
162
    case MIPSNET_INT_CTL:
163
        if (val & MIPSNET_INTCTL_TXDONE) {
164
            s->intctl &= ~MIPSNET_INTCTL_TXDONE;
165
        } else if (val & MIPSNET_INTCTL_RXDONE) {
166
            s->intctl &= ~MIPSNET_INTCTL_RXDONE;
167
        } else if (val & MIPSNET_INTCTL_TESTBIT) {
168
            mipsnet_reset(s);
169
            s->intctl |= MIPSNET_INTCTL_TESTBIT;
170
        } else if (!val) {
171
            /* ACK testbit interrupt, flag was cleared on read. */
172
        }
173
        s->busy = !!s->intctl;
174
        mipsnet_update_irq(s);
175
        break;
176
    case MIPSNET_TX_DATA_BUFFER:
177
        s->tx_buffer[s->tx_written++] = val;
178
        if (s->tx_written == s->tx_count) {
179
            /* Send buffer. */
180
#ifdef DEBUG_MIPSNET_SEND
181
            printf("mipsnet: sending len=%d\n", s->tx_count);
182
#endif
183
            qemu_send_packet(s->vc, s->tx_buffer, s->tx_count);
184
            s->tx_count = s->tx_written = 0;
185
            s->intctl |= MIPSNET_INTCTL_TXDONE;
186
            s->busy = 1;
187
            mipsnet_update_irq(s);
188
        }
189
        break;
190
    /* Read-only registers */
191
    case MIPSNET_DEV_ID:
192
    case MIPSNET_BUSY:
193
    case MIPSNET_RX_DATA_COUNT:
194
    case MIPSNET_INTERRUPT_INFO:
195
    case MIPSNET_RX_DATA_BUFFER:
196
    default:
197
        break;
198
    }
199
}
200

  
201
static void mipsnet_save(QEMUFile *f, void *opaque)
202
{
203
    MIPSnetState *s = opaque;
204

  
205
    qemu_put_be32s(f, &s->busy);
206
    qemu_put_be32s(f, &s->rx_count);
207
    qemu_put_be32s(f, &s->rx_read);
208
    qemu_put_be32s(f, &s->tx_count);
209
    qemu_put_be32s(f, &s->tx_written);
210
    qemu_put_be32s(f, &s->intctl);
211
    qemu_put_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
212
    qemu_put_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
213
}
214

  
215
static int mipsnet_load(QEMUFile *f, void *opaque, int version_id)
216
{
217
    MIPSnetState *s = opaque;
218

  
219
    if (version_id > 0)
220
        return -EINVAL;
221

  
222
    qemu_get_be32s(f, &s->busy);
223
    qemu_get_be32s(f, &s->rx_count);
224
    qemu_get_be32s(f, &s->rx_read);
225
    qemu_get_be32s(f, &s->tx_count);
226
    qemu_get_be32s(f, &s->tx_written);
227
    qemu_get_be32s(f, &s->intctl);
228
    qemu_get_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
229
    qemu_get_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
230

  
231
    return 0;
232
}
233

  
234
void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
235
{
236
    MIPSnetState *s;
237

  
238
    s = qemu_mallocz(sizeof(MIPSnetState));
239
    if (!s)
240
        return;
241

  
242
    register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
243
    register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
244
    register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
245
    register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
246
    register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
247
    register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
248

  
249
    s->irq = irq;
250
    s->nd = nd;
251
    if (nd && nd->vlan) {
252
        s->vc = qemu_new_vlan_client(nd->vlan, mipsnet_receive,
253
                                     mipsnet_can_receive, s);
254
    } else {
255
        s->vc = NULL;
256
    }
257

  
258
    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
259
             "mipsnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
260
              s->nd->macaddr[0],
261
              s->nd->macaddr[1],
262
              s->nd->macaddr[2],
263
              s->nd->macaddr[3],
264
              s->nd->macaddr[4],
265
              s->nd->macaddr[5]);
266

  
267
    mipsnet_reset(s);
268
    register_savevm("mipsnet", 0, 0, mipsnet_save, mipsnet_load, s);
269
}
b/qemu-doc.texi
2037 2037
@item
2038 2038
An ACER Pica "pica61"
2039 2039
@item
2040
MIPS MIPSsim emulator pseudo board "mipssim"
2040
MIPS emulator pseudo board "mipssim"
2041 2041
@end itemize
2042 2042

  
2043 2043
The generic emulation is supported by Debian 'Etch' and is able to
......
2085 2085
IDE controller
2086 2086
@end itemize
2087 2087

  
2088
The MIPSsim emulation supports:
2088
The mipssim pseudo board emulation provides an environment similiar
2089
to what the proprietary MIPS emulator uses for running Linux.
2090
It supports:
2089 2091

  
2090 2092
@itemize @minus
2091 2093
@item

Also available in: Unified diff