On 06.02.2025 16:00, Oleksii Kurochko wrote:
>
> On 2/6/25 12:10 PM, Jan Beulich wrote:
>>>>> + case 's':
>>>>> + /*
>>>>> + * Workaround for invalid single-letter 's' & 'u' (QEMU):
>>>>> + * Before QEMU 7.1 it was an issue with misa to ISA string
>>>>> + * conversion:
>>>>> +
>>>>> *https://patchwork.kernel.org/project/qemu-devel/patch/dee09d708405075420b29115c1e9e87910b8da55.1648270894.git.research_tra...@irq.a4lg.com/#24792587
>>>>> + * Additional details of the workaround on Linux kernel
>>>>> side:
>>>>> +
>>>>> *https://lore.kernel.org/linux-riscv/[email protected]/#t
>>>>> + *
>>>>> + * No need to set the bit in riscv_isa as 's' & 'u' are
>>>>> + * not valid ISA extensions. It works unless the first
>>>>> + * multi-letter extension in the ISA string begins with
>>>>> + * "Su" and is not prefixed with an underscore.
>>>>> + */
>>>>> + if ( ext[-1] != '_' && ext[1] == 'u' )
>>>>> + {
>>>>> + ++isa;
>>>>> + ext_err = true;
>>>>> + break;
>>>>> + }
>>>>> + fallthrough;
>>>>> + case 'z':
>>>>> + /*
>>>>> + * Before attempting to parse the extension itself, we find
>>>>> its end.
>>>>> + * As multi-letter extensions must be split from other
>>>>> multi-letter
>>>>> + * extensions with an "_", the end of a multi-letter
>>>>> extension will
>>>>> + * either be the null character or the "_" at the start of
>>>>> the next
>>>>> + * multi-letter extension.
>>>>> + *
>>>>> + * Next, as the extensions version is currently ignored, we
>>>>> + * eliminate that portion. This is done by parsing backwards
>>>>> from
>>>>> + * the end of the extension, removing any numbers. This may
>>>>> be a
>>>>> + * major or minor number however, so the process is repeated
>>>>> if a
>>>>> + * minor number was found.
>>>>> + *
>>>>> + * ext_end is intended to represent the first character
>>>>> *after* the
>>>>> + * name portion of an extension, but will be decremented to
>>>>> the last
>>>>> + * character itself while eliminating the extensions version
>>>>> number.
>>>>> + * A simple re-increment solves this problem.
>>>>> + */
>>>>> + for ( ; *isa && *isa != '_'; ++isa )
>>>>> + if ( unlikely(!isalnum(*isa)) )
>>>>> + ext_err = true;
>>>>> +
>>>>> + ext_end = isa;
>>>>> + if ( unlikely(ext_err) )
>>>>> + break;
>>>> This, otoh, is an error. Which probably shouldn't go silently.
>>> It is actually not an error, what it means that if version is mentioned or
>>> not, so
>>> (1) rv32..._zbb_zbc
>>> (2) rv32..._zbb1p2_zbc
>>>
>>> For (1), ext_err = true and it means that version isn't mentioned for _zbb
>>> and after it
>>> immediately another extension name is going, so there is no any sense in
>>> ignoring (or parsing) version
>>> numbers.
>>> For (2), ext_err = false (because it ends on number ) so we have to ignore
>>> (or parse) version nubmers.
>> I don't follow. Why would ext_err be true for (1)? That's a well-formed
>> specifier, isn't it? rv32..._zbb.zbc (with the last dot meaning a literal
>> one, unlike the earlier ...) is an example of what would cause ext_err to
>> be true.
>
> My fault, you are right, ext_err will be false for (1).
>
> For your example, rv32..._zbb.zbc we have to do panic(), haven't we?
That's what I was trying to suggest earlier on. From anything we can't parse
we can't possibly infer whether we're able to run with the properties the
system has.
>>>>> + default:
>>>>> + /*
>>>>> + * Things are a little easier for single-letter extensions,
>>>>> as they
>>>>> + * are parsed forwards.
>>>>> + *
>>>>> + * After checking that our starting position is valid, we
>>>>> need to
>>>>> + * ensure that, when isa was incremented at the start of the
>>>>> loop,
>>>>> + * that it arrived at the start of the next extension.
>>>>> + *
>>>>> + * If we are already on a non-digit, there is nothing to do.
>>>>> Either
>>>>> + * we have a multi-letter extension's _, or the start of an
>>>>> + * extension.
>>>>> + *
>>>>> + * Otherwise we have found the current extension's major
>>>>> version
>>>>> + * number. Parse past it, and a subsequent p/minor version
>>>>> number
>>>>> + * if present. The `p` extension must not appear immediately
>>>>> after
>>>>> + * a number, so there is no fear of missing it.
>>>>> + */
>>>>> + if ( unlikely(!isalpha(*ext)) )
>>>>> + {
>>>>> + ext_err = true;
>>>>> + break;
>>>>> + }
>>>> Like above this also looks to be a situation that maybe better would be
>>>> left go entirely silently. I even wonder whether you can safely continue
>>>> the parsing in that case: How do you know whether what follows is indeed
>>>> the start of an extension name?
>>> Lets consider examples:
>>> (1) riscv,isa=im
>>> (2) riscv,isa=i1p2m
>>> (3) riscv,isa=i1m
>>>
>>> (4) riscv,isa=i1_m1
>>>
>>> Note: Underscores "_" may be used to separate ISA extensions to improve
>>> readability
>>> and to provide disambiguation, e.g., "RV32I2_M2_A2".
>>>
>>> (1) isa="i" so ext = "m" => no minor and major version between "i" and "m"
>>> => `ext` contains the name
>>> of the next extension name, thereby we will break a loop and go for
>>> parsing of the next extension
>>> which is "m" in this example
>>> (2) isa="i" => ext="1" => algorithm will go further and will just skip
>>> minor and major version for
>>> this extension (1p2 => 1.2 version of extension "i")
>>> (3) just the same as (2) but will stop earlier as minor version isn't set.
>>>
>>> Note: having "_" is legal from specification point of view, but it is
>>> illegal to use it between single letter
>>> extension from device tree binding point of view.
>>> (4) just the same as (2) and (3) but using "_" separator, so the if above
>>> will just skip "_" and the next
>>> after "_" is an extension name again.
>>>
>>> Considering that "_" is illegal from device tree point of view between
>>> single letter extensions we should have
>>> ASSERT(*ext != "_") and then only cases (1) - (3) will be possible to have.
>>> Probably it also will make a sense to have an array with legal single
>>> letter extensions and check that *ext is
>>> in this array.
>>>
>>> Interesting that device tree binding doesn't cover this case:
>>> ```
>>> Because the "P" extension for Packed SIMD can be confused for the decimal
>>> point in a version number,
>>> it must be preceded by an underscore if it follows a number. For example,
>>> "rv32i2p2" means version
>>> 2.2 of RV32I, whereas "rv32i2_p2" means version 2.0 of RV32I with version
>>> 2.0 of the P extension.
>>> ```
>>> if I correctly interpreted the
>>> pattern:pattern:^rv(?:64|32)imaf?d?q?c?b?k?j?p?v?h?(?:[hsxz](?:[0-9a-z])+)?(?:_[hsxz](?:[0-9a-z])+)*$
>>> And it also doesn't support versions for single letter extensions.
>>> So "rv32i2_m2_a2" or with using "p" is impossible?
>>> Then riscv_isa_parse_string() could be simplified ( probably when it was
>>> implemented in Linux kernel they don't have the binding for riscv,isa and
>>> they
>>> just tried to follow RISC-V specification ) for the case of single letter
>>> extensions (or just keep it as is to be in sync with Linux kernel).
>> All fine, but what about e.g.
>>
>> (5) riscv,isa=i?m1
>
> It is impossible from device tree point of view:
> 1. According to DT's patter after single letter extension couldn't be version.
> 2. Between "ima" can't be anything.
>
> But it shouldn't break an algorithm because:
> (1) parse "i" and nothing wrong with that.
> (2) "?" will be ignored because we have a check at the start of single letter
> extension case:
> if ( unlikely(!isalpha(*ext)) )
> so ext_err will be set to true
> (3) "?" will be ignored and go just to "m" because of set ext_err=true at the
> step (2).
> (4) Then "m" will be parsed successfully and 1 will be just ignored.
>
> Does it make sense?
See above - I don't think we should continue to run if parsing fails. Of
course we might, after tainting the system, in a best effort manner.
Jan