Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some size-independent MMIO access does not work as intended #91

Open
JayFoxRox opened this issue Jul 24, 2018 · 2 comments
Open

Some size-independent MMIO access does not work as intended #91

JayFoxRox opened this issue Jul 24, 2018 · 2 comments

Comments

@JayFoxRox
Copy link
Member

QEMUs MMIO design is quite horrible. Let me provide an example MMIO interface with address, type and use:

0x01000000: uint8_t control_a
0x01000001: uint8_t control_b
0x01000002: uint16_t control_c

The issue is that writing 32 bit to 0x01000000 will only trigger one MMIO callback. As the size is wrong for control_a some code might choose to ignore this. In other cases, the size is not checked, and control_a gets a value which is far too big for it to handle.

Also, given the example from before, there is no additional callback for access to control_b and control_c as the code often looks like:

switch(address) {
  case CONTROL_A:
    if (size == 1) { ... }
    break; 
  case CONTROL_B:
    ...
}

(Callback is only executed for address == CONTROL_A)


The first time I've encountered this was in AC97 when trying to use OpenXDK.
The OpenXDK audio code does access more than 1 register at a time atomically by writing 32 bits at once (almost exactly like my example above).
The AC97 issue in particular should be fixed upstream, as it also affects QEMU.

However, I'm sure we have other cases in our own Xbox specific code too.

These problems are insanely hard to track and we should always at least assert for the expected size.
I did not look for other existing solutions to this problem.
It's possible that QEMU already has some way of dealing with this somehow.
My workaround for AC97 (not implemented in XQEMU at time of writing), was to manually loop over all affected registers.

The reason we don't see this problem more often is because most operating systems have only one function to access such standard hardware registers. So implementing only one way to access a register is fine most of the time.

@PatrickvL
Copy link

PatrickvL commented Jul 25, 2018

86box handles this by doing all MMIO at byte granularity. (Especially the 32 bit accesses become very cumbersome because of that)

@fuel-pcbox
Copy link

@PatrickvL Only for the nVidia cards and only for reads. 86Box actually deals with this by having up to 6 MMIO handlers. One is 8-bit reads, one is 8-bit writes, one is 16-bit reads, and so on.

@JayFoxRox JayFoxRox mentioned this issue Nov 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants