qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Re: [RFC] API change for pci_set_word and related functions


From: Stefan Weil
Subject: [Qemu-devel] Re: [RFC] API change for pci_set_word and related functions
Date: Mon, 11 Jan 2010 20:38:53 +0100
User-agent: Mozilla-Thunderbird 2.0.0.22 (X11/20090707)

Michael S. Tsirkin schrieb:
> On Thu, Jan 07, 2010 at 04:07:26PM +0100, Stefan Weil wrote:
>> Michael S. Tsirkin schrieb:
>>> On Thu, Jan 07, 2010 at 12:15:25PM +0100, Stefan Weil wrote:
>>> ...
>>>> ---
>>>> hw/eepro100.c | 4 +---
>>>> 1 files changed, 1 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/hw/eepro100.c b/hw/eepro100.c
>>>> index 336ca49..a21c984 100644
>>>> --- a/hw/eepro100.c
>>>> +++ b/hw/eepro100.c
>>>> @@ -420,10 +420,8 @@ static void pci_reset(EEPRO100State * s)
>>>> /* TODO: this is the default, do not override. */
>>>> PCI_CONFIG_16(PCI_COMMAND, 0x0000);
>>>> /* PCI Status */
>>>> - /* TODO: this seems to make no sense. */
>>>> /* TODO: Value at RST# should be 0. */
>>> So this second todo can go too. I've removed it in my tree.
>>>
>>>> - PCI_CONFIG_16(PCI_STATUS,
>>>> - PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_SIG_TARGET_ABORT);
>>>> + PCI_CONFIG_16(PCI_STATUS, PCI_STATUS_DEVSEL_MEDIUM |
>>>> PCI_STATUS_FAST_BACK);
>>>> /* PCI Revision ID */
>>>> PCI_CONFIG_8(PCI_REVISION_ID, 0x08);
>>> BTW if you are not afraid of churn, there's no reason
>>> for PCI_CONFIG_8 and friends anymore, because pci.h
>>> has much nicer pci_set_byte etc.
>> Hello Michael,
>>
>> I already noticed pci_set_byte, pci_set_word, pci_set_long and
>> the corresponding pci_get_xxx functions and thought about using them.
>>
>> I did not start it because I want to suggest a different API
>> for use in PCI device emulations:
>>
>> instead of
>>
>> pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_CAP_LIST);
>>
>> or
>>
>> pci_set_word(&pci_conf[PCI_STATUS], PCI_STATUS_CAP_LIST);
>>
>> it would be better to call
>>
>> pci_set_word(pci_conf, PCI_STATUS, PCI_STATUS_CAP_LIST);
>>
>>
>> The prototypes would look like this:
>>
>> /* Set PCI config value. */
>> void pci_set_word(PCIDevice *s, uint8_t offset, uint16_t val);
>>
>> /* Set PCI cmask value. */
>> void pci_set_cmask_word(PCIDevice *s, uint8_t offset, uint16_t val);
>>
>> /* Set PCI wmask value. */
>> void pci_set_wmask_word(PCIDevice *s, uint8_t offset, uint16_t val);
>>
>> What are the advantages?
>> * strict type checking (the old API takes any uint8_t *)
>
> So IMO it's easier to make mistakes with your proposed API because if
> you confuse offset and value compiler does not complain. More
> importantly, if you want to pass some other uint8_t pointer to e.g.
> pci_set_word, you can *and nothing unexpected will happen*
> it will set the word to the given value. So the current
> API is more type safe than what you propose.
>

No. The current API takes any uint8_t pointer to read or write
a value. This is not safe.

The proposed API only takes a PCIDevice pointer
and reads or writes only configuration (or cmask or
wmask) values. Yes, you can take offset for value.
If you are lucky and value is an uint16_t or uint32_t,
your compiler will complain. And even if your compiler
does not complain, it is wrong but still safe, because
the code will only access the PCI configuration data.


>> * many other pci_* functions also have a first parameter of type PCIDevice
>
> So what would make sense IMO is higer level abstraction,
> for example similar to what we have with capabilities
> and msix, I think we could have something like this
> for e.g. power management.
>
> For low-level bit tweaking, the advantages of current API is that same
> thing can be used to set wmask, cmask, config itself, and whatever else
> we will come up with.

The low level API can be used where low level is
adequate: in pci.c for example.

To implement emulated PCI devices, a more robust API
would be better. Think of the number of devices which
are still missing, think of people who want to write
a new PCI device emulation for QEMU without being
a QEMU expert.

>
>> * calls look nicer (at least in my opinion)
>
> What I value is the fact that it's obvious which
> data is changed.

Here there is no difference between current and
proposed API:

old: pci_set_word(&pci_conf[PCI_STATUS], PCI_STATUS_CAP_LIST);
new: pci_set_word(pci_conf, PCI_STATUS, PCI_STATUS_CAP_LIST);

Every function call hides what happens. If you really wanted
to see which data is changed, you would have to write

*(uint16_t *)&pci_conf[PCI_STATUS] = cpu_to_le16(PCI_STATUS_CAP_LIST);

>
>> * strict range checking (offset is limited to 0...255, additional
>>   assertions possible - the old API is unsafe because it just takes
>>   a pointer)
>
> I don't think we want to add return status, so there wouldn't
> be a benefit to range checking as we can't act on it.
> Anyway, it's very unusual to use anything but a constant
> as an offset, so range errors are very uncommon.

There is an implicit range checking in the proposed
API because the offset is uint8_t, so it cannot
exceed the range which is valid for configuration
offsets.

A more elaborated check could require that
configuration byte values are only addressed
using pci_set_byte (not pci_set_long)
and raise a fatal runtime error otherwise.

Runtime checks without return values
are well established in QEMU's code,
and they are very useful for code writers.

>
>> The functions are inline, so the resulting code won't differ.
>>
>> Instead of _byte, _word and _long I personally prefer something
>> like _8, _16, _32 because _word and _long need interpretation.
>> But this is only a matter of taste - the API change is more important.
>>
>>
>> Regards,
>>
>> Stefan Weil







reply via email to

[Prev in Thread] Current Thread [Next in Thread]