Commit f0fc6f8fbc195424af8bb9ca7409748f665d7b07

Authored by ths
1 parent 6bf5b4e8

Second half of mipssim support, plus documentation improvements.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3401 c046a42c-6fe2-441c-8c8c-71466251a162
hw/mips_mipssim.c 0 → 100644
  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 +};
... ...
hw/mipsnet.c 0 → 100644
  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 +}
... ...
qemu-doc.texi
... ... @@ -2037,7 +2037,7 @@ The MIPS Malta prototype board &quot;malta&quot;
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,7 +2085,9 @@ PC Keyboard
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
... ...