Thread: implement read only, read/write1 clear and read/write registers

  1. #1
    Tweaking master Aslaville's Avatar
    Join Date
    Sep 2012
    Location
    Rogueport
    Posts
    528

    implement read only, read/write1 clear and read/write registers

    I am trying to emulate a device's MMIO registers whereby some registers are read/write, read/write one to clear and finally read/write.

    I have currently implemented read/write - the easiest of course.

    Am looking to implement read only and read/write one to clear bytes (I have basically implemented the registers as an array of bytes ).

    How best could I implemented enforce read only registers and read/write one to clear bytes ?

    Say for instance I have:

    Code:
    #define SIZE 0x4000
    
    unsigned char[SIZE];
    The registers are 64-bit and say for instance the register at address 0x2000 has some read only and read write one to clear bytes. Register writes are in form of say 64-bit values. Normally if the register is read/write - I could just have written the value to the address but incase of say read write one to clear bits, how should I got about it ?

  2. #2
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Aslaville View Post
    I am trying to emulate a device's MMIO registers whereby some registers are read/write, read/write one to clear and finally read/write.
    On what level? I mean, are you emulating the entire machine, with your code reading the instruction stream and acting on it; or are you emulating the registers for a normal application you have little control over?

    Could you give some more context on what you are working on, please?

    In the first case, you should incorporate the logic to the load/store part in your emulator. I'd use a small array of flags, not available to the emulated code, to store the readable and writable bit (two bits per register) per register, that the load/store part of your emulator checks. You should also consider what your emulator should do, if the code does an "illegal" access.

    (I'm lazy, so I might instead use an array of two pointers per register, instead, so that each action on an MMIO register would call to a designated emulator function. Each 'read' function would return a full register word, with the load part picking only the proper subword of it if the load was narrower than a word. The 'write' functions would not return anything. I suspect this would be easier to maintain than a huge switch..case.)

    In the second case, you're in for a bit of pain. It is certainly doable, and I can explain several different approaches for POSIXy systems in userspace, and at least one if you are using a Linux kernel module for the emulation.
    Last edited by Nominal Animal; 10-23-2015 at 10:23 AM.

  3. #3
    Tweaking master Aslaville's Avatar
    Join Date
    Sep 2012
    Location
    Rogueport
    Posts
    528
    Could you give some more context on what you are working on, please?
    Sorry, Nominal Animal, I'd really love to, it's a cool project but you know NDAs and stuff

    Anyways, jokes aside. Sorry for late reply I got busy with schoolwork.

    Am trying to emulate a device with qemu. Actually I can already emulate the device am just polishing and stuff.

    This is what happens in Qemu.

    -Software reads/writes to MMIO trigger traps to which Qemu responds but calling calling an MMIO handler specific to the particular device and of course many other things happens but that's the basic overview.
    -A programmer emulating a device has to implement the MMIO read/write handler - it has a general prototype.

    I thought this was going to be hard to do, especially the ro/rw1c/rw1s but it proved too easy.

    I just did this

    Code:
    /* 
      @ addr: address of mmio register to write to
      @ s : structure representing a device (it contains a static array representing the MMIO region and others representing special masks)
      @val : value to write
    */
    
    static void mmio_write_long(struct device *s, uint64_t addr, uint32_t val)
    {
         uint64_t romask = s->romask[addr]; //get the read only mask
         uint64_t w1cmask = s->r1cmask[addr]; //get the write 1 clear mask
         s->mmio[addr] = ((val & ~ romask) | ( val & ~ w1cmask)); //store value disregarding read only bit and clearing w1c bits
    }
    
    //And of course the code's not exactly as I wrote above but that's basically how it works
    Last edited by Aslaville; 10-28-2015 at 11:09 AM. Reason: Fix smiley

  4. #4
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Aslaville View Post
    Am trying to emulate a device with qemu. Actually I can already emulate the device am just polishing and stuff. [...] I thought this was going to be hard to do, especially the ro/rw1c/rw1s but it proved too easy.
    Would have helped if you had mentioned qemu in the post..

    Yeah, qemu does all the hard work, and you only need to implement the callback handler.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 12-07-2014, 07:01 AM
  2. Is possible read text form keyboard using read() function?
    By Vanhapolle in forum C Programming
    Replies: 3
    Last Post: 12-08-2013, 11:51 PM
  3. Replies: 7
    Last Post: 12-07-2012, 10:44 PM
  4. read a number with scanf() and read char[] with fgets()
    By nutzu2010 in forum C Programming
    Replies: 5
    Last Post: 03-11-2011, 05:05 AM
  5. blocked on read/recv / how to read/send proper buffers
    By fudgecode in forum Networking/Device Communication
    Replies: 1
    Last Post: 11-02-2010, 11:42 PM