Home > Software engineering >  Can't Write to Arm Coprocessor Register on Qemu-Arm
Can't Write to Arm Coprocessor Register on Qemu-Arm

Time:04-21

I'm emulating arm1176jzf-s on qemu-system-arm. Because I'm trying to develop a simple barebones operating system for raspberry pi zero, for that I'm using a boot code from wiki.osdev.org to jump to c code. Inside it, I'm trying to write some data to a coprocessor register, "coprocessor control access register" to be exact. I can read as fine but when I try to write, value doesn't change. Code is something like this:

    uint32_t dest = 0, tmp = 0;
   /* Read the coprocessor access control register. */
    __asm ("mrc p15, 0, %[dst], c1, c0, 2"
          : [dst] "=r" (dst));

    log_uint(dst, 'h');
    log_uint(dst, 'b');

   /* Enable access for domain control access register.
     Modifies dst to be 0xC0000040. */
    SETBIT(dst, 6);

    log_uint(dst, 'h');
    log_uint(dst, 'b');

    /* Write the changed value. */
    __asm ("mcr p15, 0, %[dst], c1, c0, 2"
          :
          : [dst] "r" (dst));

    /* Read the coprocessor access control register. */
    __asm ("mrc p15, 0, %[tmp], c1, c0, 2"
          : [tmp] "=r" (tmp));

    log_uint(tmp, 'h');
    log_uint(tmp, 'b');  

log_uint, prints an integer in binary or hexadecimal form using uart.

Outputs follow as:

C0000000
11000000000000000000000000000000
C0000040
11000000000000000000000001000000
C0000000
11000000000000000000000000000000

According to technical reference manual of the processor: You must perform an Instruction Memory Barrier (IMB) sequence immediately after an update of the Coprocessor Access Control Register. I've tried many combinations of Data Synchronization Barrier operation and Flush operations of Prefetch Buffer together. But that didn't work so I'm not sure how to do this IMB sequence, and I wasn't able to find it.

But one more thing that bugs me is that, according to the processor manual, coprocessor access control register has to have the reset value 0x00000000, but I read 0xC0000000.

In kernel, before this code, I just initialize uart, and nothing else, so everything should be at reset value.

CodePudding user response:

This problem has been clarified by klange from osdev subreddit explanation is in the comments.

CodePudding user response:

You're trying to set the CPACR bits corresponding to coprocessor 4. That doesn't exist in QEMU's 1176 CPU, so the CPACR bits for it are RAZ/WI. I'm not sure what you're trying to do this for -- the comment mentions a "domain control access register", but the 1176 domain access control register (DACR) is in cp15, not cp4. If the code you're copying really needs to access a "coprocessor 4" then you'll need to modify it to not do that, because whatever it is, QEMU doesn't implement it.

The always-1 bits in the top bits are strictly speaking a QEMU bug, but they're harmless -- we're implementing "ASEDIS and D32DIS are RAO if the CPU doesn't have Neon or D16-D31" for all v7 cores, but earlier ones like the 1176 didn't have those fields and the bits should really read as zero.

  • Related