Changes between Version 72 and Version 73 of Developer/Simulators/QEMU/CANEmulation


Ignore:
Timestamp:
Sep 15, 2013, 10:57:53 AM (6 years ago)
Author:
Jinyang
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • Developer/Simulators/QEMU/CANEmulation

    v72 v73  
    203203There are some files that need to be modified to make a basic PCI-CAN device: default-configs/pci.mak, hw/Makefile.objs, qemu-char.c, hw/can-pci.c.
    204204 *  default-configs/pci.mak add default compiling options
     205 *  config-all-devices.mak add all compiling options
    205206 *  hw/Makefile.objs needs to be modified to add the object to the qemu build
    206207 *  qemu-char.c is the file that is used for the can-char driver
     
    216217=  Add the Default Compiling Files  =
    217218
    218 To get qemu to recognize new source files, it's necessary to add the new source files to the system. Below is the change to the hw/Makefile.objs and default-configs/pci.mak to get the qemu build system to recognize can-pci.o as one of the qemu objects.
    219 
    220 
    221 
    222 
    223   For simplicity of the project, instead of implementing CONFIG_CAN, it is hard-coded to y.
    224 
    225 '''Possible Improvement:''' In later summers of code, $(CONFIG_CAN) could be made configurable, to ease getting accepted into the qemu head. This would require tracing down all the changes needed to implement CONFIG_CAN
    226  
    227  hw/Makefile.objs
    228  
    229   @@ -27,6 +27,7 @@ common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
    230  
    231   common-obj-$(CONFIG_SERIAL) += serial.o serial-isa.o
    232   common-obj-$(CONFIG_SERIAL_PCI) += serial-pci.o
    233  +common-obj-y += can-pci.o
    234   common-obj-$(CONFIG_PARALLEL) += parallel.o
    235   common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
    236   common-obj-$(CONFIG_PCSPK) += pcspk.o
    237 
    238 
    239 
    240 
    241 
    242 
    243 
    244 
    245 
     219To get qemu to recognize new source files, it's necessary to add the new source files to the system. Below is the change to the hw/Makefile.objs, default-configs/pci.mak and config-all-devices.mak to get the qemu build system to recognize can-pci.o as one of the qemu objects.
    246220
    247221We want to compile the PCI-CAN device as default. To achieve this goal, we add the following code.
     
    249223  common-obj-$(CONFIG_CAN_PCI) += can-pci.o
    250224  # default-configs/pci.mak
     225  CONFIG_CAN_PCI=y
     226  # config-all-devices.mak
    251227  CONFIG_CAN_PCI=y
    252228=  Add the PCI-CAN structure  =
     
    339315
    340316
    341 
    342 
    343 
    344 
    345 ==   qemu-char.c  ==
    346 
    347 
    348 The first part of the patch is a custom '''DPRINTF''' for testing out the can simulation.
    349 
    350  #define READ_BUF_LEN 4096
    351  @@ -99,6 +99,81 @@
    352  +#define DEBUG_CAN
    353  +#ifdef DEBUG_CAN
    354  +#define DPRINTF(fmt, ...) \
    355  +   do { fprintf(stderr, "[mycan]: " fmt , ## __VA_ARGS__); } while (0)
    356  +#else
    357  +#define DPRINTF(fmt, ...) \
    358  +   do {} while (0)
    359  +#endif
    360 
    361 can_chr_write prints out information to the terminal.
    362  +static int can_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
    363  +{
    364  +  DPRINTF("%s-%s() called\n", __FILE__, __FUNCTION__);
    365  +    return 0;
    366  +}
    367 
    368 prints a debugging message
    369  +static void can_chr_close(struct CharDriverState *chr)
    370  +{
    371  +  DPRINTF("%s-%s() called\n", __FILE__, __FUNCTION__);
    372  +}
    373 
    374 prints a message, allocates a CharDriverState pointer, defines the chr_write and chr_close to be the debugging functions above.
    375  +static CharDriverState *qemu_chr_open_can(QemuOpts *opts)
    376  +{
    377  +    CharDriverState *chr;
    378  +    DPRINTF("%s-%s() called\n", __FILE__, __FUNCTION__);
    379  +
    380  +    chr = g_malloc0(sizeof(CharDriverState));
    381  +
    382  +    chr->chr_write = can_chr_write;
    383  +    chr->chr_close = can_chr_close;
    384  +
    385  +    return chr;
    386  +
    387  +}
    388  
    389 Next, add a device to the character device table, so that the device can be called when qemu is called.
    390 
    391 '''Note:''' add the use-case here.
    392 
    393  /* character device */
    394  
    395  @@ -2992,6 +3067,7 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
    396       { .name = "serial",    .open = qemu_chr_open_win },
    397       { .name = "stdio",     .open = qemu_chr_open_win_stdio },
    398  #else
    399  +    { .name = "can",       .open = qemu_chr_open_can },
    400       { .name = "file",      .open = qemu_chr_open_file_out },
    401       { .name = "pipe",      .open = qemu_chr_open_pipe },
    402       { .name = "stdio",     .open = qemu_chr_open_stdio },
    403 
    404 <!-- ==== hw/can-pci.c ====
    405 
    406 This adds the can-pci device
    407 
    408 Include the simulations for the bus (pci), device type (char), timer functions, and the address-spaces (for memory-mapped io?)
    409  @@ -0,0 +1,193 @@
    410  +#include "pci/pci.h"
    411  +#include "char/char.h"
    412  +#include "qemu/timer.h"
    413  +#include "exec/address-spaces.h"
    414 
    415 '''TODO:''' look up where these defines are from
    416  +#define PCI_MEM_SIZE                          16
    417  +#define PCI_DEVICE_ID_CANBUS          0xbeef
    418  +#define PCI_REVISION_ID_CANBUS                0x73
    419 
    420 
    421 +typedef struct CanState {
    422 +       /* Some registers ... */
    423 +    qemu_irq irq;
    424 +       void                    *mem_base;
    425 +
    426 +    CharDriverState *chr;
    427 +    MemoryRegion       portio;
    428 +    MemoryRegion       memio;
    429 +} CanState;
    430 +
    431 +typedef struct PCICanState {
    432 +    PCIDevice          dev;
    433 +    CanState           state;
    434 +} PCICanState;
    435 +
    436 +#define DEBUG_CAN
    437 +#ifdef DEBUG_CAN
    438 +#define DPRINTF(fmt, ...) \
    439 +   do { fprintf(stderr, "[mycan]: " fmt , ## __VA_ARGS__); } while (0)
    440 +#else
    441 +#define DPRINTF(fmt, ...) \
    442 +   do {} while (0)
    443 +#endif
    444 +
    445 +
    446 +const uint8_t whatever[] = "ttt";
    447 +static void can_ioport_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
    448 +{
    449 +    CanState *s = opaque;
    450 +    DPRINTF("write addr=0x%02x val=0x%02x\n", (unsigned int)addr, (unsigned int)val);
    451 +       qemu_chr_fe_write(s->chr, whatever, 3); // write to the backends.
    452 +}
    453 +
    454 +static uint64_t can_ioport_read(void *opaque, hwaddr addr, unsigned size)
    455 +{
    456 +       DPRINTF("%s-%s() called\n", __FILE__, __FUNCTION__);
    457 +    return 0;
    458 +}
    459 +
    460 +const MemoryRegionOps can_io_ops = {
    461 +    .read              = can_ioport_read,
    462 +    .write             = can_ioport_write,
    463 +    .endianness = DEVICE_LITTLE_ENDIAN,
    464 +    .impl              = {
    465 +        .min_access_size = 1,
    466 +        .max_access_size = 1,
    467 +    },
    468 +};
    469 +
    470 +static void can_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
    471 +{
    472 +    CanState                   *s = opaque;
    473 +       void                            *pci_mem_addr;
    474 +       int                             region_size;
    475 +
    476 +       pci_mem_addr = s->mem_base; 
    477 +       pci_mem_addr = ((char *)pci_mem_addr) + addr; 
    478 +       region_size  = (int)memory_region_size(&s->memio);
    479 +       if(addr > region_size)
    480 +               return ;
    481 +
    482 +       DPRINTF("write 0x%llx to %p\n", val, pci_mem_addr);
    483 +       memcpy(pci_mem_addr, (void *)&val, size);       
    484 +       DPRINTF("   pci_mem_addr 0x%llx\n", *(uint64_t *)pci_mem_addr);
    485 +
    486 +
    487 +} 
    488 +
    489 +static uint64_t can_mem_read(void *opaque, hwaddr addr, unsigned size)
    490 +{ 
    491 +    CanState                   *s = opaque;
    492 +       void                            *pci_mem_addr; 
    493 +       int                             region_size;
    494 +       unsigned int            temp;
    495 +
    496 +       pci_mem_addr = s->mem_base; 
    497 +       pci_mem_addr = ((char *)pci_mem_addr) + addr; 
    498 +       region_size  = memory_region_size(&s->memio);
    499 +       if(addr > region_size) 
    500 +               return 0;
    501 +
    502 +       memcpy(&temp, pci_mem_addr, size);
    503 +       DPRINTF("read %d bytes of 0x%x from %p\n", size, temp, pci_mem_addr);
    504 +
    505 +       return temp;
    506 +}
    507 +
    508 +static const MemoryRegionOps can_mem_ops = { 
    509 +       .read           = can_mem_read, 
    510 +       .write          = can_mem_write, 
    511 +       .endianness = DEVICE_LITTLE_ENDIAN,
    512 +    .impl              = {
    513 +               // how many bytes can we read/write every time.
    514 +        .min_access_size = 1,
    515 +        .max_access_size = 16,
    516 +    },
    517 +};
    518 +
    519 +
    520 +static int can_pci_init(PCIDevice *dev)
    521 +{
    522 +       // Get the address of PCICanState through PCIDevice.
    523 +    PCICanState *pci = DO_UPCAST(PCICanState, dev, dev);
    524 +    CanState *s = &pci->state;
    525 +
    526 +       DPRINTF("%s-%s() called\n", __FILE__, __FUNCTION__);
    527 +       if (!s->chr) {
    528 +        fprintf(stderr, "Can't create can device, empty char device\n");
    529 +               exit(1);
    530 +    }
    531 +       
    532 +       s->mem_base = g_malloc0(PCI_MEM_SIZE);
    533 +
    534 +    pci->dev.config[PCI_INTERRUPT_PIN] = 0x01;
    535 +    s->irq = pci->dev.irq[0];
    536 +
    537 +
    538 +       qemu_irq_lower(s->irq);
    539 +       
    540 +    memory_region_init_io(&s->portio, &can_io_ops, s, "can", 8);
    541 +    memory_region_init_io(&s->memio, &can_mem_ops, s, "can", PCI_MEM_SIZE);
    542 +    pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->portio);
    543 +    pci_register_bar(&pci->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->memio);
    544 +
    545 +//    memory_region_add_subregion(system_io, base, &s->io);
    546 +    return 0;
    547 +}
    548 +
    549 +static void can_pci_exit(PCIDevice *dev)
    550 +{
    551 +    PCICanState *pci = DO_UPCAST(PCICanState, dev, dev);
    552 +    CanState *s = &pci->state;
    553 +
    554 +    g_free(s->mem_base);
    555 +    memory_region_destroy(&s->memio);
    556 +    memory_region_destroy(&s->portio);
    557 +}
    558 +
    559 +
    560 +static const VMStateDescription vmstate_pci_can = {
    561 +    .name = "pci-can",
    562 +    .version_id = PCI_REVISION_ID_CANBUS,
    563 +    .minimum_version_id = 1,
    564 +    .fields      = (VMStateField[]) {
    565 +        VMSTATE_PCI_DEVICE(dev, PCICanState),
    566 +        VMSTATE_END_OF_LIST()
    567 +    }
    568 +};
    569 +
    570 +static Property can_pci_properties[] = {
    571 +    DEFINE_PROP_CHR("chardev",  PCICanState, state.chr),
    572 +    DEFINE_PROP_END_OF_LIST(),
    573 +};
    574 +
    575 +static void can_pci_class_initfn(ObjectClass *klass, void *data)
    576 +{
    577 +    DeviceClass *dc = DEVICE_CLASS(klass);
    578 +    PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
    579 +       
    580 +    pc->init = can_pci_init;
    581 +    pc->exit = can_pci_exit;
    582 +    pc->vendor_id = PCI_VENDOR_ID_REDHAT; // 0x1b36
    583 +    pc->device_id = PCI_DEVICE_ID_CANBUS;
    584 +    pc->revision = PCI_REVISION_ID_CANBUS;
    585 +    pc->class_id = PCI_CLASS_OTHERS;
    586 +
    587 +    dc->desc = "PCI CAN SJA1000";
    588 +    dc->vmsd = &vmstate_pci_can;
    589 +    dc->props = can_pci_properties;
    590 +}
    591 +
    592 +static const TypeInfo can_pci_info = {
    593 +    .name          = "pci-can",
    594 +    .parent        = TYPE_PCI_DEVICE,
    595 +    .instance_size = sizeof(PCICanState),
    596 +    .class_init    = can_pci_class_initfn,
    597 +};
    598 +
    599 +static void can_pci_register_types(void)
    600 +{
    601 +    type_register_static(&can_pci_info);
    602 +}
    603 +
    604 +type_init(can_pci_register_types)
    605 -->
    606 The above is an OLD one. You can get some newer update at [http://jin-yang.github.io/2013/07/24/build-minimal-linux-environment.html JinYang's Blog].
    607 =  Running the Example  =
     317=  Step 4: Write Linux driver  =
     318
     319Until now we have built the structure of PCI-CAN device the details about how the device works you can get from the source code. Here we will talk about the Linux driver.
     320
     321Unlike the SocketCAN driver which use the socket, we developed a new char device driver.
     322
     323
     324=  Step 5: Test  =
     325
     326You can get the test environment form site ''https://github.com/Jin-Yang/LINUX-QEMU.git''. There is a simple intruduce in README about what the files or directories for.
     327=  Add SocketCAN device  =
    608328
    609329The following commands should be executed in host.
     
    611331 $ sudo ip link add type vcan
    612332 $ sudo link set vcan0 up
    613 change your directory to can-utils,
    614  $ ./candump vcan0
    615 
    616 then start qemu, and input the following commands.
    617 <!-- where is the source code for a.out -->
    618  # cd /home/qemu_test_pci
    619  # ./load
    620  # ./a.out
    621 
    622 you will get the output from "./candump vcan0" command, like following
    623   vcan0  123   [3]  12 34 56
    624   vcan0  12345678   [6]  12 34 56 78 90 AB
    625 
    626 This means we send a SFF message and EFF message to the host through SocketCAN.
    627 =  Step 4: Write Linux driver  =
    628 
    629 Until now we have built the structure of PCI-CAN device the details about how the device works you can get from the source code. Here we will talk about the Linux driver.
    630 
    631 Unlike the SocketCAN driver which use the socket, we developed a new char device driver.
    632 
    633 
    634 =  Step 5: Test  =
    635 
    636 You can get the test environment form site ''https://github.com/Jin-Yang/LINUX-QEMU.git''. There is a simple intruduce in README about what the files or directories for.
    637333=  Start qemu  =
    638334
     
    698394
    699395Source file located at examples-v2/ and before runing, rtems-grub.cfg should be edited too.
    700 = =Adding Qemu to the RTEMS Source Builder ==
     396= Adding Qemu to the RTEMS Source Builder =
    701397
    702398Although not necessarily part of the CAN project one interesting issue that came up was the need to hook qemu into the RTEMS Source Builder for gcc-testing purposes.
     
    715411Some resources for building on Mac are:
    716412# http://www.rubenerd.com/qemu-1-macosx/
    717 = References ==
     413References  =
    718414
    719415# https://lists.gnu.org/archive/html/qemu-devel/2013-05/threads.html