Message ID | 1408726356-14420-3-git-send-email-kbastian@mail.uni-paderborn.de |
---|---|
State | New |
Headers | show |
On 22 August 2014 17:52, Bastian Koppelmann <kbastian@mail.uni-paderborn.de> wrote: > Add basic board to allow systemmode emulation > > Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> > --- > v5 -> v6: > - tricore_testboard: Fix machine name containing blanks. > > hw/tricore/Makefile.objs | 1 + > hw/tricore/tricore_testboard.c | 129 +++++++++++++++++++++++++++++++++++++++++ > include/hw/tricore/tricore.h | 54 +++++++++++++++++ > 3 files changed, 184 insertions(+) > create mode 100644 hw/tricore/Makefile.objs > create mode 100644 hw/tricore/tricore_testboard.c > create mode 100644 include/hw/tricore/tricore.h > > diff --git a/hw/tricore/Makefile.objs b/hw/tricore/Makefile.objs > new file mode 100644 > index 0000000..435e095 > --- /dev/null > +++ b/hw/tricore/Makefile.objs > @@ -0,0 +1 @@ > +obj-y += tricore_testboard.o > diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c > new file mode 100644 > index 0000000..04c0f89 > --- /dev/null > +++ b/hw/tricore/tricore_testboard.c > @@ -0,0 +1,129 @@ > +/* > + * TriCore Baseboard System emulation. > + * > + * Copyright (c) 2014 Bastian Koppelmann > + * > + * This code is licensed under the GPL. Please at least say "v2 or later" (or whatever you mean here); just "GPL" is ambiguous. > + */ > + > +#include "hw/hw.h" > +#include "hw/devices.h" > +#include "net/net.h" > +#include "sysemu/sysemu.h" > +#include "hw/boards.h" > +#include "hw/loader.h" > +#include "sysemu/blockdev.h" > +#include "exec/address-spaces.h" > +#include "hw/block/flash.h" > +#include "elf.h" > +#include "hw/tricore/tricore.h" > + > +#define TRICORE_FLASH_ADDR 0xa0000000 > +#define TRICORE_FLASH_SIZE (2 * 1024 * 1024) > +#define TRICORE_FLASH_SECT_SIZE (256 * 1024) > + > + > +/* Board init. */ > + > +static struct tricore_boot_info tricoretb_binfo; > + > +static void tricore_load_kernel(CPUTRICOREState *env) > +{ > + int64_t entry; Should this really be signed? It looks rather odd, especially given you immediately cast it below. > + long kernel_size; > + > + kernel_size = load_elf(tricoretb_binfo.kernel_filename, NULL, > + NULL, (uint64_t *)&entry, NULL, > + NULL, 0, > + ELF_MACHINE, 1); > + if (kernel_size <= 0) { > + fprintf(stderr, "qemu: no kernel file '%s'\n", > + tricoretb_binfo.kernel_filename); error_report() is preferred over directly printing to stderr (Note that it provides the trailing \n so you don't need to.) > + exit(1); > + } > + env->PC = entry; > + > +} > + > +static void tricore_testboard_init(MachineState *machine, int board_id) > +{ > + TRICORECPU *cpu; > + CPUTRICOREState *env; > + > + MemoryRegion *sysmem = get_system_memory(); > + MemoryRegion *ext_cram = g_new(MemoryRegion, 1); > + MemoryRegion *ext_dram = g_new(MemoryRegion, 1); > + MemoryRegion *int_cram = g_new(MemoryRegion, 1); > + MemoryRegion *int_dram = g_new(MemoryRegion, 1); > + MemoryRegion *pcp_data = g_new(MemoryRegion, 1); > + MemoryRegion *pcp_text = g_new(MemoryRegion, 1); > + DriveInfo *dinfo; > + > + if (!machine->cpu_model) { > + machine->cpu_model = "tc1796"; > + } > + cpu = cpu_tricore_init(machine->cpu_model); > + env = &cpu->env; > + if (!cpu) { > + fprintf(stderr, "Unable to find CPU definition\n"); error_report("Unable to find CPU definition"); > + exit(1); > + } > + memory_region_init_ram(ext_cram, NULL, "powerlink_ext_c.ram", 2*1024*1024); > + vmstate_register_ram_global(ext_cram); > + memory_region_init_ram(ext_dram, NULL, "powerlink_ext_d.ram", 4*1024*1024); > + vmstate_register_ram_global(ext_dram); > + memory_region_init_ram(int_cram, NULL, "powerlink_int_c.ram", 48*1024); > + vmstate_register_ram_global(int_cram); > + memory_region_init_ram(int_dram, NULL, "powerlink_int_d.ram", 48*1024); > + vmstate_register_ram_global(int_dram); > + memory_region_init_ram(pcp_data, NULL, "powerlink_pcp_data.ram", 16*1024); > + vmstate_register_ram_global(pcp_data); > + memory_region_init_ram(pcp_text, NULL, "powerlink_pcp_text.ram", 32*1024); > + vmstate_register_ram_global(pcp_text); > + > + memory_region_add_subregion(sysmem, 0x80000000, ext_cram); > + memory_region_add_subregion(sysmem, 0xa1000000, ext_dram); > + memory_region_add_subregion(sysmem, 0xd4000000, int_cram); > + memory_region_add_subregion(sysmem, 0xd0000000, int_dram); > + memory_region_add_subregion(sysmem, 0xf0050000, pcp_data); > + memory_region_add_subregion(sysmem, 0xf0060000, pcp_text); You could make this all data driven if you like, but I don't insist. > + > + dinfo = drive_get(IF_PFLASH, 0, 0); > + if (!pflash_cfi01_register(TRICORE_FLASH_ADDR, NULL, > + "tricore_testboard.flash", > + TRICORE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, > + TRICORE_FLASH_SECT_SIZE, > + TRICORE_FLASH_SIZE / TRICORE_FLASH_SECT_SIZE, > + 2, 0x00, 0x00, 0x0000, 0x0, 0)) { Don't use pflash_cfi01_register() in new code, it gives you a weird not-like-hardware flash device that we only have for backwards compatibility with existing board models. Instantiate and configure the flash device directly (compare vexpress.c's ve_pflash_cfi01_register(), but use the correct config for the hardware you're modelling, which might not be two parallel 16 bit wide flash chips). > + > + fprintf(stderr, "qemu: Error registering flash memory.\n"); error_report(). > + } else { > + env->PC = TRICORE_FLASH_ADDR; This looks bogus. You should let the emulated CPU reset to its own reset address as per whatever the architecture says CPUs reset to. If the CPU allows a board to configure the reset address (eg by setting input lines the CPU samples on reset) then you should model that by making the reset address a QOM property of the CPU. > + } > + > + tricoretb_binfo.ram_size = machine->ram_size; > + tricoretb_binfo.kernel_filename = machine->kernel_filename; > + > + if (machine->kernel_filename) { > + tricore_load_kernel(env); > + } > +} > + > +static void tricoreboard_init(MachineState *machine) > +{ > + tricore_testboard_init(machine, 0x183); > +} > + > +static QEMUMachine ttb_machine = { > + .name = "tricore_testboard", > + .desc = "Just for testing", > + .init = tricoreboard_init, > + .is_default = 1, > +}; The .desc text here appears in the user-visible help output, so can we have something slightly more useful to them, please? $ ./build/all/tricore-softmmu/qemu-system-tricore -M help Supported machines are: tricore_testboard Just for testing (default) none empty machine Also, think about whether you really want to set the is_default flag. Will all users of TriCore based boards always want the test board? > +++ b/include/hw/tricore/tricore.h > @@ -0,0 +1,54 @@ > +#ifndef TRICORE_MISC_H > +#define TRICORE_MISC_H 1 > + > +#include "exec/memory.h" > +#include "hw/irq.h" > + > +struct tricore_boot_info { > + uint64_t ram_size; > + const char *kernel_filename; > + const char *kernel_cmdline; > + const char *initrd_filename; > + const char *dtb_filename; > + hwaddr loader_start; > + /* multicore boards that use the default secondary core boot functions > + * need to put the address of the secondary boot code, the boot reg, > + * and the GIC address in the next 3 values, respectively. boards that > + * have their own boot functions can use these values as they want. > + */ > + hwaddr smp_loader_start; > + hwaddr smp_bootreg_addr; > + hwaddr gic_cpu_if_addr; > + int nb_cpus; > + int board_id; > + int (*atag_board)(const struct tricore_boot_info *info, void *p); > + /* multicore boards that use the default secondary core boot functions > + * can ignore these two function calls. If the default functions won't > + * work, then write_secondary_boot() should write a suitable blob of > + * code mimicking the secondary CPU startup process used by the board's > + * boot loader/boot ROM code, and secondary_cpu_reset_hook() should > + * perform any necessary CPU reset handling and set the PC for the > + * secondary CPUs to point at this boot blob. > + */ > + void (*write_secondary_boot)(TRICORECPU *cpu, > + const struct tricore_boot_info *info); > + void (*secondary_cpu_reset_hook)(TRICORECPU *cpu, > + const struct tricore_boot_info *info); > + /* if a board is able to create a dtb without a dtb file then it > + * sets get_dtb. This will only be used if no dtb file is provided > + * by the user. On success, sets *size to the length of the created > + * dtb, and returns a pointer to it. (The caller must free this memory > + * with g_free() when it has finished with it.) On failure, returns NULL. > + */ > + void *(*get_dtb)(const struct tricore_boot_info *info, int *size); > + /* if a board needs to be able to modify a device tree provided by > + * the user it should implement this hook. > + */ > + void (*modify_dtb)(const struct tricore_boot_info *info, void *fdt); > + /* Used internally by arm_boot.c */ > + int is_linux; > + hwaddr initrd_start; > + hwaddr initrd_size; > + hwaddr entry; > +}; This looks pretty obviously like you just copied it wholesale from the ARM board support code. Please only include struct fields you actually use. thanks -- PMM
On 29 August 2014 20:00, Bastian Koppelmann <kbastian@mail.uni-paderborn.de> wrote: > Hi Peter, > > > On 08/29/2014 03:30 PM, Peter Maydell wrote: >> Don't use pflash_cfi01_register() in new code, it gives you a >> weird not-like-hardware flash device that we only have for >> backwards compatibility with existing board models. Instantiate >> and configure the flash device directly (compare vexpress.c's >> ve_pflash_cfi01_register(), but use the correct config for the >> hardware you're modelling, which might not be two parallel >> 16 bit wide flash chips). > > > This board does not exists. It's purpose is just to be able to run TriCore > binaries. So I rather just get rid of the flash drive. OK, if you're not using it that's easy. >>> +static QEMUMachine ttb_machine = { >>> + .name = "tricore_testboard", >>> + .desc = "Just for testing", >>> + .init = tricoreboard_init, >>> + .is_default = 1, >>> +}; >> >> The .desc text here appears in the user-visible help output, so >> can we have something slightly more useful to them, please? >> >> $ ./build/all/tricore-softmmu/qemu-system-tricore -M help >> Supported machines are: >> tricore_testboard Just for testing (default) >> none empty machine > > > Same as above. The description shows exactly the board's purpose. It is just > for testing and not a real board. How about I change it to "a minimal > TriCore board"? Something like that would be OK, I just want it a bit more descriptive and less flippant. > I see your point about the default. For now I would leave it as is, since > there are not other boards and qemu would give an error, when launched > without -M. The thing about this is that it's hard to change the default later on, because it would mean that you'd break any existing command lines that didn't specify the machine but were expecting the test board. So personally I think it's best not to specify a default if there isn't one that makes sense. thanks -- PMM
Hi Peter, On 08/29/2014 03:30 PM, Peter Maydell wrote: > >> + >> + dinfo = drive_get(IF_PFLASH, 0, 0); >> + if (!pflash_cfi01_register(TRICORE_FLASH_ADDR, NULL, >> + "tricore_testboard.flash", >> + TRICORE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, >> + TRICORE_FLASH_SECT_SIZE, >> + TRICORE_FLASH_SIZE / TRICORE_FLASH_SECT_SIZE, >> + 2, 0x00, 0x00, 0x0000, 0x0, 0)) { > Don't use pflash_cfi01_register() in new code, it gives you a > weird not-like-hardware flash device that we only have for > backwards compatibility with existing board models. Instantiate > and configure the flash device directly (compare vexpress.c's > ve_pflash_cfi01_register(), but use the correct config for the > hardware you're modelling, which might not be two parallel > 16 bit wide flash chips). This board does not exists. It's purpose is just to be able to run TriCore binaries. So I rather just get rid of the flash drive. >> + } >> + >> + tricoretb_binfo.ram_size = machine->ram_size; >> + tricoretb_binfo.kernel_filename = machine->kernel_filename; >> + >> + if (machine->kernel_filename) { >> + tricore_load_kernel(env); >> + } >> +} >> + >> +static void tricoreboard_init(MachineState *machine) >> +{ >> + tricore_testboard_init(machine, 0x183); >> +} >> + >> +static QEMUMachine ttb_machine = { >> + .name = "tricore_testboard", >> + .desc = "Just for testing", >> + .init = tricoreboard_init, >> + .is_default = 1, >> +}; > The .desc text here appears in the user-visible help output, so > can we have something slightly more useful to them, please? > > $ ./build/all/tricore-softmmu/qemu-system-tricore -M help > Supported machines are: > tricore_testboard Just for testing (default) > none empty machine Same as above. The description shows exactly the board's purpose. It is just for testing and not a real board. How about I change it to "a minimal TriCore board"? I see your point about the default. For now I would leave it as is, since there are not other boards and qemu would give an error, when launched without -M. > Also, think about whether you really want to set the > is_default flag. Will all users of TriCore based boards > always want the test board? > >> +++ b/include/hw/tricore/tricore.h >> @@ -0,0 +1,54 @@ >> +#ifndef TRICORE_MISC_H >> +#define TRICORE_MISC_H 1 >> + >> +#include "exec/memory.h" >> +#include "hw/irq.h" >> + >> +struct tricore_boot_info { >> + uint64_t ram_size; >> + const char *kernel_filename; >> + const char *kernel_cmdline; >> + const char *initrd_filename; >> + const char *dtb_filename; >> + hwaddr loader_start; >> + /* multicore boards that use the default secondary core boot functions >> + * need to put the address of the secondary boot code, the boot reg, >> + * and the GIC address in the next 3 values, respectively. boards that >> + * have their own boot functions can use these values as they want. >> + */ >> + hwaddr smp_loader_start; >> + hwaddr smp_bootreg_addr; >> + hwaddr gic_cpu_if_addr; >> + int nb_cpus; >> + int board_id; >> + int (*atag_board)(const struct tricore_boot_info *info, void *p); >> + /* multicore boards that use the default secondary core boot functions >> + * can ignore these two function calls. If the default functions won't >> + * work, then write_secondary_boot() should write a suitable blob of >> + * code mimicking the secondary CPU startup process used by the board's >> + * boot loader/boot ROM code, and secondary_cpu_reset_hook() should >> + * perform any necessary CPU reset handling and set the PC for the >> + * secondary CPUs to point at this boot blob. >> + */ >> + void (*write_secondary_boot)(TRICORECPU *cpu, >> + const struct tricore_boot_info *info); >> + void (*secondary_cpu_reset_hook)(TRICORECPU *cpu, >> + const struct tricore_boot_info *info); >> + /* if a board is able to create a dtb without a dtb file then it >> + * sets get_dtb. This will only be used if no dtb file is provided >> + * by the user. On success, sets *size to the length of the created >> + * dtb, and returns a pointer to it. (The caller must free this memory >> + * with g_free() when it has finished with it.) On failure, returns NULL. >> + */ >> + void *(*get_dtb)(const struct tricore_boot_info *info, int *size); >> + /* if a board needs to be able to modify a device tree provided by >> + * the user it should implement this hook. >> + */ >> + void (*modify_dtb)(const struct tricore_boot_info *info, void *fdt); >> + /* Used internally by arm_boot.c */ >> + int is_linux; >> + hwaddr initrd_start; >> + hwaddr initrd_size; >> + hwaddr entry; >> +}; > This looks pretty obviously like you just copied it wholesale from > the ARM board support code. Please only include struct fields > you actually use. > > thanks > -- PMM > Thanks, Bastian
diff --git a/hw/tricore/Makefile.objs b/hw/tricore/Makefile.objs new file mode 100644 index 0000000..435e095 --- /dev/null +++ b/hw/tricore/Makefile.objs @@ -0,0 +1 @@ +obj-y += tricore_testboard.o diff --git a/hw/tricore/tricore_testboard.c b/hw/tricore/tricore_testboard.c new file mode 100644 index 0000000..04c0f89 --- /dev/null +++ b/hw/tricore/tricore_testboard.c @@ -0,0 +1,129 @@ +/* + * TriCore Baseboard System emulation. + * + * Copyright (c) 2014 Bastian Koppelmann + * + * This code is licensed under the GPL. + */ + +#include "hw/hw.h" +#include "hw/devices.h" +#include "net/net.h" +#include "sysemu/sysemu.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "sysemu/blockdev.h" +#include "exec/address-spaces.h" +#include "hw/block/flash.h" +#include "elf.h" +#include "hw/tricore/tricore.h" + +#define TRICORE_FLASH_ADDR 0xa0000000 +#define TRICORE_FLASH_SIZE (2 * 1024 * 1024) +#define TRICORE_FLASH_SECT_SIZE (256 * 1024) + + +/* Board init. */ + +static struct tricore_boot_info tricoretb_binfo; + +static void tricore_load_kernel(CPUTRICOREState *env) +{ + int64_t entry; + long kernel_size; + + kernel_size = load_elf(tricoretb_binfo.kernel_filename, NULL, + NULL, (uint64_t *)&entry, NULL, + NULL, 0, + ELF_MACHINE, 1); + if (kernel_size <= 0) { + fprintf(stderr, "qemu: no kernel file '%s'\n", + tricoretb_binfo.kernel_filename); + exit(1); + } + env->PC = entry; + +} + +static void tricore_testboard_init(MachineState *machine, int board_id) +{ + TRICORECPU *cpu; + CPUTRICOREState *env; + + MemoryRegion *sysmem = get_system_memory(); + MemoryRegion *ext_cram = g_new(MemoryRegion, 1); + MemoryRegion *ext_dram = g_new(MemoryRegion, 1); + MemoryRegion *int_cram = g_new(MemoryRegion, 1); + MemoryRegion *int_dram = g_new(MemoryRegion, 1); + MemoryRegion *pcp_data = g_new(MemoryRegion, 1); + MemoryRegion *pcp_text = g_new(MemoryRegion, 1); + DriveInfo *dinfo; + + if (!machine->cpu_model) { + machine->cpu_model = "tc1796"; + } + cpu = cpu_tricore_init(machine->cpu_model); + env = &cpu->env; + if (!cpu) { + fprintf(stderr, "Unable to find CPU definition\n"); + exit(1); + } + memory_region_init_ram(ext_cram, NULL, "powerlink_ext_c.ram", 2*1024*1024); + vmstate_register_ram_global(ext_cram); + memory_region_init_ram(ext_dram, NULL, "powerlink_ext_d.ram", 4*1024*1024); + vmstate_register_ram_global(ext_dram); + memory_region_init_ram(int_cram, NULL, "powerlink_int_c.ram", 48*1024); + vmstate_register_ram_global(int_cram); + memory_region_init_ram(int_dram, NULL, "powerlink_int_d.ram", 48*1024); + vmstate_register_ram_global(int_dram); + memory_region_init_ram(pcp_data, NULL, "powerlink_pcp_data.ram", 16*1024); + vmstate_register_ram_global(pcp_data); + memory_region_init_ram(pcp_text, NULL, "powerlink_pcp_text.ram", 32*1024); + vmstate_register_ram_global(pcp_text); + + memory_region_add_subregion(sysmem, 0x80000000, ext_cram); + memory_region_add_subregion(sysmem, 0xa1000000, ext_dram); + memory_region_add_subregion(sysmem, 0xd4000000, int_cram); + memory_region_add_subregion(sysmem, 0xd0000000, int_dram); + memory_region_add_subregion(sysmem, 0xf0050000, pcp_data); + memory_region_add_subregion(sysmem, 0xf0060000, pcp_text); + + dinfo = drive_get(IF_PFLASH, 0, 0); + if (!pflash_cfi01_register(TRICORE_FLASH_ADDR, NULL, + "tricore_testboard.flash", + TRICORE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL, + TRICORE_FLASH_SECT_SIZE, + TRICORE_FLASH_SIZE / TRICORE_FLASH_SECT_SIZE, + 2, 0x00, 0x00, 0x0000, 0x0, 0)) { + + fprintf(stderr, "qemu: Error registering flash memory.\n"); + } else { + env->PC = TRICORE_FLASH_ADDR; + } + + tricoretb_binfo.ram_size = machine->ram_size; + tricoretb_binfo.kernel_filename = machine->kernel_filename; + + if (machine->kernel_filename) { + tricore_load_kernel(env); + } +} + +static void tricoreboard_init(MachineState *machine) +{ + tricore_testboard_init(machine, 0x183); +} + +static QEMUMachine ttb_machine = { + .name = "tricore_testboard", + .desc = "Just for testing", + .init = tricoreboard_init, + .is_default = 1, +}; + +static void tricore_testboard_machine_init(void) +{ + qemu_register_machine(&ttb_machine); +} + +machine_init(tricore_testboard_machine_init); diff --git a/include/hw/tricore/tricore.h b/include/hw/tricore/tricore.h new file mode 100644 index 0000000..4e68174 --- /dev/null +++ b/include/hw/tricore/tricore.h @@ -0,0 +1,54 @@ +#ifndef TRICORE_MISC_H +#define TRICORE_MISC_H 1 + +#include "exec/memory.h" +#include "hw/irq.h" + +struct tricore_boot_info { + uint64_t ram_size; + const char *kernel_filename; + const char *kernel_cmdline; + const char *initrd_filename; + const char *dtb_filename; + hwaddr loader_start; + /* multicore boards that use the default secondary core boot functions + * need to put the address of the secondary boot code, the boot reg, + * and the GIC address in the next 3 values, respectively. boards that + * have their own boot functions can use these values as they want. + */ + hwaddr smp_loader_start; + hwaddr smp_bootreg_addr; + hwaddr gic_cpu_if_addr; + int nb_cpus; + int board_id; + int (*atag_board)(const struct tricore_boot_info *info, void *p); + /* multicore boards that use the default secondary core boot functions + * can ignore these two function calls. If the default functions won't + * work, then write_secondary_boot() should write a suitable blob of + * code mimicking the secondary CPU startup process used by the board's + * boot loader/boot ROM code, and secondary_cpu_reset_hook() should + * perform any necessary CPU reset handling and set the PC for the + * secondary CPUs to point at this boot blob. + */ + void (*write_secondary_boot)(TRICORECPU *cpu, + const struct tricore_boot_info *info); + void (*secondary_cpu_reset_hook)(TRICORECPU *cpu, + const struct tricore_boot_info *info); + /* if a board is able to create a dtb without a dtb file then it + * sets get_dtb. This will only be used if no dtb file is provided + * by the user. On success, sets *size to the length of the created + * dtb, and returns a pointer to it. (The caller must free this memory + * with g_free() when it has finished with it.) On failure, returns NULL. + */ + void *(*get_dtb)(const struct tricore_boot_info *info, int *size); + /* if a board needs to be able to modify a device tree provided by + * the user it should implement this hook. + */ + void (*modify_dtb)(const struct tricore_boot_info *info, void *fdt); + /* Used internally by arm_boot.c */ + int is_linux; + hwaddr initrd_start; + hwaddr initrd_size; + hwaddr entry; +}; +#endif
Add basic board to allow systemmode emulation Signed-off-by: Bastian Koppelmann <kbastian@mail.uni-paderborn.de> --- v5 -> v6: - tricore_testboard: Fix machine name containing blanks. hw/tricore/Makefile.objs | 1 + hw/tricore/tricore_testboard.c | 129 +++++++++++++++++++++++++++++++++++++++++ include/hw/tricore/tricore.h | 54 +++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 hw/tricore/Makefile.objs create mode 100644 hw/tricore/tricore_testboard.c create mode 100644 include/hw/tricore/tricore.h