qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] MIPS Initial support of Godson-3a multicore CPU


From: chen huacai
Subject: Re: [Qemu-devel] [PATCH] MIPS Initial support of Godson-3a multicore CPU
Date: Tue, 7 Dec 2010 22:13:07 +0800

1, signed-off-by and reviewed-by should put after the introduction and
before the code, not at first.
2, You'd better split the big patch to 2~3 small patches,  E.g. CPU
definition and board emulation should be split. The format of email
title will be [Patch 0/3], [Patch 1/3] and so on. [Patch 0/3] give a
general introduction and others are real patches.
3, You should tell us how to test you code. E.g., you should provide
PMON/BIOS, OS kernel or tell us how to build them in [patch 0/3].

For more information, you can search for my patch series about Loongson-2E.
Good luck!

Huacai Chen

On Tue, Dec 7, 2010 at 5:32 PM, Jin Guojie <address@hidden> wrote:
> Signed-off-by: "Jin Guojie" <address@hidden>
> Reviewed-by: "Gao Xiang" <address@hidden>
> Reviewed-by: "Chen Huacai" <address@hidden>
>
>  A patch for Godson-3a CPU simulation.
>  Godson-3a is a newly developed MIPS-III like, multicore CPU by ICT, China.
>  We believe this patch could be helpful for other Godson developers.
>  For you review. Any comment is welcomed.
>
> Jin Guojie
> www.loongson.cn
> ---
>  Makefile.target              |    2 +-
>  hw/mips_godson3a.c           |  507 
> ++++++++++++++++++++++++++++++++++++++++++
>  target-mips/mips-defs.h      |    4 +-
>  target-mips/translate_init.c |   26 +++
>  4 files changed, 536 insertions(+), 3 deletions(-)
>  create mode 100755 hw/mips_godson3a.c
>
> diff --git a/Makefile.target b/Makefile.target
> index 91e6e74..8f29aeb 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -230,7 +230,7 @@ obj-ppc-y += xilinx_timer.o
>  obj-ppc-y += xilinx_uartlite.o
>  obj-ppc-y += xilinx_ethlite.o
>
> -obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
> +obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o 
> mips_godson3a.o
>  obj-mips-y += mips_addr.o mips_timer.o mips_int.o
>  obj-mips-y += vga.o i8259.o
>  obj-mips-y += g364fb.o jazz_led.o
> diff --git a/hw/mips_godson3a.c b/hw/mips_godson3a.c
> new file mode 100755
> index 0000000..4085db2
> --- /dev/null
> +++ b/hw/mips_godson3a.c
> @@ -0,0 +1,507 @@
> +/*
> + * QEMU godson 3a developing board support
> + *
> + * Copyright (c) 2009 Gao Xiang (address@hidden)
> + * Copyright (c) 2010 Jin Guojie (address@hidden)
> + * This code is licensed under the GNU GPL v2.
> + */
> +
> +/*
> + * Godson 3a developing board is based on ICT/ST Godson-3a.
> + * Godson-3a CPU is a MIPS-III like, multicore processor.
> + * It can be configured to contain 4 or 8 cores. Every 4
> + * cores are grouped into one on-chip 'node'. SMP mechanism
> + * is supported by Godson IPI(inter-processors interrupt)
> + * specification.
> + *
> + * Godson 3a CPU intro:
> + *   http://en.wikipedia.org/wiki/Loongson
> + *
> + * Godson 3a user manual:
> + *   http://www.loongsondeveloper.com/doc/Loongson3AUserGuide.pdf
> + */
> +#include "hw.h"
> +#include "mips.h"
> +#include "pc.h"
> +#include "isa.h"
> +#include "net.h"
> +#include "sysemu.h"
> +#include "boards.h"
> +#include "ide.h"
> +#include "mips-bios.h"
> +#include "elf.h"
> +#include "loader.h"
> +#include "blockdev.h"
> +#include "mips_cpudevs.h"
> +#include "mc146818rtc.h"
> +
> +static target_ulong PHYS_TO_VIRT(target_ulong phys)
> +{
> +    if (smp_cpus > 1)
> +        return ((phys) | 0x9800000000000000ULL);
> +    else
> +        return ((phys) | ~(target_ulong)0x7fffffff);
> +}
> +
> +#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
> +
> +#define MAX_IDE_BUS 2
> +
> +static const int ide_iobase[2] = { 0x1f0, 0x170 };
> +static const int ide_iobase2[2] = { 0x3f6, 0x376 };
> +static const int ide_irq[2] = { 14, 15 };
> +
> +static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
> +
> +static PITState *pit; /* PIT i8254 */
> +
> +/* i8254 PIT is attached to the IRQ0 at PIC i8259 */
> +
> +static struct _loaderparams {
> +    int ram_size;
> +    const char *kernel_filename;
> +    const char *kernel_cmdline;
> +    const char *initrd_filename;
> +} loaderparams;
> +
> +static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
> +                             uint32_t val)
> +{
> +    if ((addr & 0xffff) == 0 && val == 42)
> +        qemu_system_reset_request();
> +    else if ((addr & 0xffff) == 4 && val == 42)
> +        qemu_system_shutdown_request();
> +}
> +
> +static uint32_t mips_qemu_readl (void *opaque, target_phys_addr_t addr)
> +{
> +    return 0;
> +}
> +
> +static CPUWriteMemoryFunc *mips_qemu_write[] = {
> +    &mips_qemu_writel,
> +    &mips_qemu_writel,
> +    &mips_qemu_writel,
> +};
> +
> +static CPUReadMemoryFunc *mips_qemu_read[] = {
> +    &mips_qemu_readl,
> +    &mips_qemu_readl,
> +    &mips_qemu_readl,
> +};
> +
> +static int mips_qemu_iomemtype = 0;
> +
> +typedef struct ResetData {
> +    CPUState *env;
> +    uint64_t vector;
> +} ResetData;
> +
> +static int64_t load_kernel (CPUState *env)
> +{
> +    int64_t entry, kernel_high;
> +    long kernel_size, initrd_size, params_size;
> +    ram_addr_t initrd_offset;
> +    uint32_t *params_buf;
> +    int big_endian;
> +
> +#ifdef TARGET_WORDS_BIGENDIAN
> +    big_endian = 1;
> +#else
> +    big_endian = 0;
> +#endif
> +
> +    kernel_size = load_elf(loaderparams.kernel_filename,
> cpu_mips_kseg0_to_phys, NULL,
> +                           (uint64_t *)&entry, NULL, (uint64_t 
> *)&kernel_high,
> +                          big_endian, ELF_MACHINE, 1);
> +    if (kernel_size >= 0) {
> +        if ((entry & ~0x7fffffffULL) == 0x80000000)
> +            entry = (int32_t)entry;
> +        env->active_tc.PC = entry;
> +        env = first_cpu;
> +    } else {
> +        fprintf(stderr, "qemu: could not load kernel '%s'\n",
> +                loaderparams.kernel_filename);
> +        exit(1);
> +    }
> +
> +    /* load initrd */
> +    initrd_size = 0;
> +    initrd_offset = 0;
> +    if (loaderparams.initrd_filename) {
> +        initrd_size = get_image_size (loaderparams.initrd_filename);
> +       if (initrd_size > 0) {
> +           if(initrd_size < 0x10000000)
> +               initrd_offset = 0x1000000;
> +           else
> +               initrd_offset = 0x20000000;
> +
> +           if (initrd_offset + initrd_size > ram_size) {
> +               fprintf(stderr,
> +                   "qemu: memory too small for initial ram disk '%s'\n",
> +                   loaderparams.initrd_filename);
> +               exit(1);
> +           }
> +
> +           initrd_size = load_image_targphys(loaderparams.initrd_filename,
> +                   initrd_offset,
> +                   ram_size - initrd_offset);
> +       }
> +
> +       if (initrd_size == (target_ulong)-1) {
> +           fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
> +                           loaderparams.initrd_filename);
> +           exit(1);
> +       }
> +    }
> +
> +    /* Store command line.  */
> +    params_size = 264;
> +    params_buf = qemu_malloc(params_size);
> +
> +    params_buf[0] = tswap32(ram_size);
> +    params_buf[1] = tswap32(0x12345678);
> +
> +    if (initrd_size > 0) {
> +        snprintf((char *)params_buf + 8, 256,
> +               "rd_start=0x" TARGET_FMT_lx " rd_size=%li ramdisk_size=%li 
> %s",
> +                 PHYS_TO_VIRT((uint32_t)initrd_offset),
> +                 initrd_size, initrd_size>>10, loaderparams.kernel_cmdline);
> +    } else {
> +        snprintf((char *)params_buf + 8, 256, "%s",
> loaderparams.kernel_cmdline);
> +    }
> +
> +    rom_add_blob_fixed("params", params_buf, params_size, (16 << 20) - 264);
> +    return entry;
> +}
> +
> +static void main_cpu_reset(void *opaque)
> +{
> +    ResetData *s = (ResetData *)opaque;
> +    CPUState *env = s->env;
> +
> +    env->active_tc.PC = s->vector;
> +}
> +
> +/*
> + * Godson3A Inter-processor interrupt addresses:
> + *  STATUS_OFF       0x000
> + *  EN_OFF           0x004
> + *  SET_OFF          0x008
> + *  CLEAR_OFF        0x00c
> + *  BUF_20           0x020
> + *  BUF_28           0x028
> + *  BUF_30           0x030
> + *  BUF_38           0x038
> +*/
> +typedef struct {
> +    uint32_t status;
> +    uint32_t en;
> +    uint32_t set;
> +    uint32_t clear;
> +    uint32_t buf[4];
> +    qemu_irq irq;
> +} GodsonCoreState;
> +
> +GodsonCoreState core_states[8];
> +
> +static void gipi_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
> +{
> +    GodsonCoreState * s = (GodsonCoreState *)((long)opaque & ~3);
> +    int node = (long)opaque & 3;
> +
> +    int core = (addr >> 8) & 3;
> +    if (node == 1)
> +       core += 4;
> +
> +    switch(addr & 0xFF)
> +    {
> +       case 0x0:
> +            hw_error("CORE: STATUS_OFF Can't be written\n");
> +            break;
> +       case 0x04:
> +           s[core].en = val;
> +           break;
> +       case 0x08:
> +           s[core].status |= val;
> +            qemu_irq_raise(s[core].irq);
> +           break;
> +       case 0x0C:
> +            s[core].status ^= val;
> +            qemu_irq_lower(s[core].irq);
> +            break;
> +       case 0x20:
> +            s[core].buf[0] = val;
> +            break;
> +        case 0x28:
> +            s[core].buf[1] = val;
> +            break;
> +        case 0x30:
> +            s[core].buf[2] = val;
> +            break;
> +        case 0x38:
> +            s[core].buf[3] = val;
> +            break;
> +        default:
> +            break;
> +    }
> +}
> +
> +static uint32_t gipi_readl(void *opaque, target_phys_addr_t addr)
> +{
> +    GodsonCoreState * s = (GodsonCoreState *)((long)opaque & ~3);
> +    int node = (long)opaque & 3;
> +    uint32_t ret = -1;
> +
> +    int core = (addr >> 8) & 3;
> +    if (node == 1)
> +       core += 4;
> +
> +    switch(addr & 0xFF)
> +    {
> +       case 0x0:
> +            ret = s[core].status;
> +            break;
> +       case 0x04:
> +            ret = s[core].en;
> +           break;
> +       case 0x08:
> +            hw_error("CORE: SET_OFF Can't be read\n");
> +           break;
> +       case 0x0C:
> +            hw_error("CORE: CLEAR_OFF Can't be read\n");
> +            break;
> +       case 0x20:
> +            ret = s[core].buf[0];
> +            break;
> +        case 0x28:
> +            ret = s[core].buf[1];
> +            break;
> +        case 0x30:
> +            ret = s[core].buf[2];
> +            break;
> +        case 0x38:
> +            ret = s[core].buf[3];
> +            break;
> +        default:
> +            break;
> +    }
> +
> +    return ret;
> +}
> +
> +static void gipi_save(QEMUFile *f, void *opaque)
> +{
> +    /* TODO */
> +    hw_error("gipi_save not implemented\n");
> +}
> +
> +static int gipi_load(QEMUFile *f, void *opaque, int version_id)
> +{
> +    /* TODO */
> +    hw_error("gipi_load not implemented\n");
> +}
> +
> +static void gipi_reset(void *opaque)
> +{
> +}
> +
> +static CPUWriteMemoryFunc *gipi_write[] = {
> +    &gipi_writel,
> +    &gipi_writel,
> +    &gipi_writel,
> +};
> +
> +static CPUReadMemoryFunc *gipi_read[] = {
> +    &gipi_readl,
> +    &gipi_readl,
> +    &gipi_readl,
> +};
> +
> +static int godson_ipi_init(qemu_irq parent_irq , int core, GodsonCoreState 
> *s)
> +{
> +    int size = 0x1000;
> +    target_phys_addr_t ipi_addr;
> +    s[core].irq = parent_irq;
> +    int gipi_iomemtype;
> +    void *opaque;
> +
> +    if(core == 0 || core == 4) {
> +        opaque = (void *)((long)s | (core / 4));
> +        gipi_iomemtype = cpu_register_io_memory(gipi_read, gipi_write, 
> opaque);
> +
> +        ipi_addr = 0x3ff01000LL | ((target_phys_addr_t)(core/4) << 44);
> +        cpu_register_physical_memory(ipi_addr, size, gipi_iomemtype);
> +    }
> +
> +    if(core == 0) {
> +        register_savevm(NULL, "gipi", 0, 1, gipi_save, gipi_load, s);
> +        qemu_register_reset(gipi_reset, s);
> +    }
> +    return 0;
> +}
> +
> +static CPUState *mycpu[8];
> +
> +static
> +void mips_godson3a_init (ram_addr_t ram_size,
> +                    const char *boot_device,
> +                    const char *kernel_filename, const char *kernel_cmdline,
> +                    const char *initrd_filename, const char *cpu_model)
> +{
> +    int i;
> +    char *filename;
> +    ram_addr_t ram_offset;
> +    ram_addr_t bios_offset;
> +    int bios_size;
> +    CPUState *env;
> +    ResetData *reset_info = NULL;
> +    ResetData *main_reset_info = NULL;
> +    qemu_irq *i8259;
> +    DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
> +
> +    /* init CPUs */
> +    if (cpu_model == NULL) {
> +        cpu_model = "godson3a";
> +    }
> +
> +    GodsonCoreState * gipis =qemu_mallocz(sizeof(core_states));
> +
> +    for(i = 0; i < smp_cpus; i++) {
> +        env = cpu_init(cpu_model);
> +        mycpu[i] = env;
> +
> +        env->CP0_EBase |= env->cpu_index;
> +
> +        if (i != 0)
> +            env->halted = 0;
> +
> +        register_savevm(NULL, "cpu", i, 3, cpu_save, cpu_load, env);
> +        env->CP0_Status |= (1 << CP0St_KX);
> +        env->CP0_PRid   |= 0x6303;
> +
> +        /* Init CPU internal devices */
> +        cpu_mips_irq_init_cpu(env);
> +        cpu_mips_clock_init(env);
> +
> +        godson_ipi_init(env->irq[6], env->cpu_index, gipis);
> +
> +        reset_info = qemu_mallocz(sizeof(ResetData));
> +        reset_info->env = env;
> +        reset_info->vector = env->active_tc.PC;
> +        qemu_register_reset(main_cpu_reset, reset_info);
> +
> +        if (i == 0)
> +            main_reset_info = reset_info;
> +    }
> +
> +    env = mycpu[0];
> +
> +    /* allocate RAM */
> +    ram_offset = qemu_ram_alloc(NULL, "godson3a.ram", ram_size);
> +    cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
> +
> +    if (!mips_qemu_iomemtype) {
> +        mips_qemu_iomemtype = cpu_register_io_memory(mips_qemu_read,
> +                                                     mips_qemu_write, NULL);
> +    }
> +    cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);
> +
> +    /* Try to load a BIOS image. If this fails, we continue regardless,
> +       but initialize the hardware ourselves. When a kernel gets
> +       preloaded we also initialize the hardware, since the BIOS wasn't
> +       run. */
> +    if (bios_name == NULL)
> +        bios_name = BIOS_FILENAME;
> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
> +    if (filename) {
> +        bios_size = get_image_size(filename);
> +    } else {
> +        bios_size = -1;
> +    }
> +
> +    if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
> +        bios_offset = qemu_ram_alloc(NULL, "godson3a.bios", BIOS_SIZE);
> +       cpu_register_physical_memory(0x1fc00000, BIOS_SIZE,
> +                                     bios_offset | IO_MEM_ROM);
> +
> +        load_image_targphys(filename, 0x1fc00000, BIOS_SIZE);
> +
> +        for(i = 0; i < smp_cpus; i++)
> +           mycpu[i]->active_tc.PC = (target_long)(int32_t)0xbfc00000;
> +
> +    } else {
> +       /* not fatal */
> +        fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
> +               bios_name);
> +    }
> +
> +    if (filename) {
> +        qemu_free(filename);
> +    }
> +
> +    if (kernel_filename) {
> +        loaderparams.ram_size = ram_size * 2;
> +        loaderparams.kernel_filename = kernel_filename;
> +        loaderparams.kernel_cmdline = kernel_cmdline;
> +        loaderparams.initrd_filename = initrd_filename;
> +       main_reset_info->vector = load_kernel(env);
> +    }
> +
> +    /* The PIC is attached to the MIPS CPU INT0 pin */
> +    i8259 = i8259_init(env->irq[2]);
> +    isa_bus_new(NULL);
> +    isa_bus_irqs(i8259);
> +
> +    rtc_init(2000, NULL);
> +
> +    /* Register 64 KB of ISA IO space at 0x14000000 */
> +    isa_mmio_init(0x1fe00000, 0x00010000, 0);
> +    isa_mmio_init(0x1ff00000, 0x00010000, 1);
> +    isa_mem_base = 0x10000000;
> +
> +    pit = pit_init(0x40, i8259[0]);
> +
> +    serial_init(serial_io[0], env->irq[2], 115200, serial_hds[0]);
> +
> +    if (nd_table[0].vlan) {
> +        if (nd_table[0].model == NULL
> +            || strcmp(nd_table[0].model, "ne2k_isa") == 0) {
> +            isa_ne2000_init(0x300, 9, &nd_table[0]);
> +        } else if (strcmp(nd_table[0].model, "?") == 0) {
> +            fprintf(stderr, "qemu: Supported NICs: ne2k_isa\n");
> +            exit (1);
> +        } else {
> +            fprintf(stderr, "qemu: Unsupported NIC: %s\n", 
> nd_table[0].model);
> +            exit (1);
> +        }
> +    }
> +
> +    if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
> +        fprintf(stderr, "qemu: too many IDE bus\n");
> +        exit(1);
> +    }
> +
> +    for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
> +        hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
> +    }
> +
> +    for(i = 0; i < MAX_IDE_BUS; i++)
> +        isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
> +                     hd[MAX_IDE_DEVS * i],
> +                    hd[MAX_IDE_DEVS * i + 1]);
> +}
> +
> +QEMUMachine mips_godson3a_machine = {
> +    .name = "godson3a",
> +    .desc = "Godson3A Multicore platform",
> +    .init = mips_godson3a_init,
> +    .max_cpus = 8,
> +};
> +
> +static void mips_godson3a_machine_init(void)
> +{
> +    qemu_register_machine(&mips_godson3a_machine);
> +}
> +
> +machine_init(mips_godson3a_machine_init);
> diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h
> index bf094a3..36444f0 100644
> --- a/target-mips/mips-defs.h
> +++ b/target-mips/mips-defs.h
> @@ -10,8 +10,8 @@
>
>  #if defined(TARGET_MIPS64)
>  #define TARGET_LONG_BITS 64
> -#define TARGET_PHYS_ADDR_SPACE_BITS 36
> -#define TARGET_VIRT_ADDR_SPACE_BITS 42
> +#define TARGET_PHYS_ADDR_SPACE_BITS 48
> +#define TARGET_VIRT_ADDR_SPACE_BITS 64
>  #else
>  #define TARGET_LONG_BITS 32
>  #define TARGET_PHYS_ADDR_SPACE_BITS 36
> diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
> index 590e092..fe02206 100644
> --- a/target-mips/translate_init.c
> +++ b/target-mips/translate_init.c
> @@ -484,6 +484,32 @@ static const mips_def_t mips_defs[] =
>       .insn_flags = CPU_LOONGSON2F,
>       .mmu_type = MMU_TYPE_R4000,
>     },
> +    {
> +        /* godson3a CPU */
> +        .name = "godson3a",
> +        .CP0_PRid = 0x6303,
> +        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
> +                       (MMU_TYPE_R4000 << CP0C0_MT),
> +        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
> +                       (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
> +                       (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
> +                       (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
> +        .CP0_Config2 = MIPS_CONFIG2,
> +        .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA),
> +        .SYNCI_Step = 32,
> +        .CCRes = 2,
> +        .CP0_Status_rw_bitmask = 0x36FBFFFF,
> +        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_3D) | (1 << FCR0_PS) |
> +                    (1 << FCR0_L) | (1 << FCR0_W) | (1 << FCR0_D) |
> +                    (1 << FCR0_S) | (0x00 << FCR0_PRID) | (0x0 << FCR0_REV),
> +        .SEGBITS = 42,
> +        /* The architectural limit is 59, but we have hardcoded 36 bit
> +           in some places...
> +        .PABITS = 59, */ /* the architectural limit */
> +        .PABITS = 48,
> +        .insn_flags = CPU_MIPS64R2 | ASE_MIPS3D,
> +        .mmu_type = MMU_TYPE_R4000,
> +    },
>
>  #endif
>  };
> --
> 1.5.2.3
>
>



-- 
Huacai Chen



reply via email to

[Prev in Thread] Current Thread [Next in Thread]