diff mbox series

riscv: Work to remove kernel dependence on the M-extension

Message ID 20220309052842.247031-1-michael@michaelkloos.com (mailing list archive)
State New, archived
Headers show
Series riscv: Work to remove kernel dependence on the M-extension | expand

Commit Message

Michael T. Kloos March 9, 2022, 5:28 a.m. UTC
Added a new config symbol RISCV_ISA_M to enable the usage of the
multiplication, division, and remainder (modulus) instructions
from the M-extension.  This configures the march build flag to
either include or omit it.

I didn't find any assembly using any of the instructions from
the M-extension.  However, the BPF JIT is a complicating factor.
Currently, it emits M-extension instructions to implement various
BPF operations.  For now, I have made HAVE_EBPF_JIT depend on
CONFIG_RISCV_ISA_M.

I have added the supplementary integer arithmetic functions in
the file "arch/riscv/lib/ext_m_supplement.c".  All the code
contained in this file is wrapped in an ifndef contingent on the
presence of CONFIG_RISCV_ISA_M.

Signed-off-by: Michael T. Kloos <michael@michaelkloos.com>
---
 arch/riscv/Kconfig                |  20 +-
 arch/riscv/Makefile               |   6 +-
 arch/riscv/lib/Makefile           |   1 +
 arch/riscv/lib/ext_m_supplement.c | 588 ++++++++++++++++++++++++++++++
 4 files changed, 608 insertions(+), 7 deletions(-)
 create mode 100644 arch/riscv/lib/ext_m_supplement.c

Comments

Arnd Bergmann March 9, 2022, 10:02 a.m. UTC | #1
On Wed, Mar 9, 2022 at 6:28 AM Michael T. Kloos
<michael@michaelkloos.com> wrote:
>
> Added a new config symbol RISCV_ISA_M to enable the usage of the
> multiplication, division, and remainder (modulus) instructions
> from the M-extension.  This configures the march build flag to
> either include or omit it.
>
> I didn't find any assembly using any of the instructions from
> the M-extension.  However, the BPF JIT is a complicating factor.
> Currently, it emits M-extension instructions to implement various
> BPF operations.  For now, I have made HAVE_EBPF_JIT depend on
> CONFIG_RISCV_ISA_M.
>
> I have added the supplementary integer arithmetic functions in
> the file "arch/riscv/lib/ext_m_supplement.c".  All the code
> contained in this file is wrapped in an ifndef contingent on the
> presence of CONFIG_RISCV_ISA_M.
>
> Signed-off-by: Michael T. Kloos <michael@michaelkloos.com>

The patch looks fine to me, but I increasingly get the feeling that the
entire platform feature selection in Kconfig should be guarded with
a global flag that switches between "fully generic" and "fully custom"
builds, where the generic kernel assumes that all the standard
features (64-bit, C, M, FPU, MMU, UEFI, ...) are present, the
incompatible options (XIP, PHYS_RAM_BASE_FIXED,
CMDLINE_FORCE, BUILTIN_DTB, ...) are force-disabled,
and all optional features (V/B/P/H extensions, custom instructions,
platform specific device drivers, ...) are runtime detected.

At the moment, those three types are listed at the same level,
which gives the impression that they can be freely mixed.

         Arnd
Michael T. Kloos March 9, 2022, 11:43 a.m. UTC | #2
Thank you for your feedback.  I don't really have much of an
opinion about that right now aside from that I know where things
are in the current structure and am comfortable.  My goal with this
contribution was to keep it in-line with the current config
structure.  Hence, I put it right next to the menuconfig option
to control CONFIG_RISCV_ISA_C under Platform Type.

I wouldn't necessarily be opposed to rethinking the way platform
feature selection is presented in menuconfig.  If people feel that
most users will be looking for an rv64gc config and that it should
be made for clear, perhaps it could be done.  I would need to do
more thinking about how exactly that would look.

I do think that it is outside the scope of this patch.  Were you
working on something like that and worried about a merge conflict?

	Michael

On 3/9/22 05:02, Arnd Bergmann wrote:

> On Wed, Mar 9, 2022 at 6:28 AM Michael T. Kloos
> <michael@michaelkloos.com> wrote:
>> Added a new config symbol RISCV_ISA_M to enable the usage of the
>> multiplication, division, and remainder (modulus) instructions
>> from the M-extension.  This configures the march build flag to
>> either include or omit it.
>>
>> I didn't find any assembly using any of the instructions from
>> the M-extension.  However, the BPF JIT is a complicating factor.
>> Currently, it emits M-extension instructions to implement various
>> BPF operations.  For now, I have made HAVE_EBPF_JIT depend on
>> CONFIG_RISCV_ISA_M.
>>
>> I have added the supplementary integer arithmetic functions in
>> the file "arch/riscv/lib/ext_m_supplement.c".  All the code
>> contained in this file is wrapped in an ifndef contingent on the
>> presence of CONFIG_RISCV_ISA_M.
>>
>> Signed-off-by: Michael T. Kloos <michael@michaelkloos.com>
> The patch looks fine to me, but I increasingly get the feeling that the
> entire platform feature selection in Kconfig should be guarded with
> a global flag that switches between "fully generic" and "fully custom"
> builds, where the generic kernel assumes that all the standard
> features (64-bit, C, M, FPU, MMU, UEFI, ...) are present, the
> incompatible options (XIP, PHYS_RAM_BASE_FIXED,
> CMDLINE_FORCE, BUILTIN_DTB, ...) are force-disabled,
> and all optional features (V/B/P/H extensions, custom instructions,
> platform specific device drivers, ...) are runtime detected.
>
> At the moment, those three types are listed at the same level,
> which gives the impression that they can be freely mixed.
>
>           Arnd
Arnd Bergmann March 9, 2022, 11:47 a.m. UTC | #3
On Wed, Mar 9, 2022 at 12:43 PM Michael T. Kloos
<michael@michaelkloos.com> wrote:
>
> Thank you for your feedback.  I don't really have much of an
> opinion about that right now aside from that I know where things
> are in the current structure and am comfortable.  My goal with this
> contribution was to keep it in-line with the current config
> structure.  Hence, I put it right next to the menuconfig option
> to control CONFIG_RISCV_ISA_C under Platform Type.
>
> I wouldn't necessarily be opposed to rethinking the way platform
> feature selection is presented in menuconfig.  If people feel that
> most users will be looking for an rv64gc config and that it should
> be made for clear, perhaps it could be done.  I would need to do
> more thinking about how exactly that would look.
>
> I do think that it is outside the scope of this patch.  Were you
> working on something like that and worried about a merge conflict?

As I said, I think your patch is ok, and I have no objections to it
being merged. It's just one more option among others that
can cause problems if users get it wrong.

       Arnd
Christoph Hellwig March 10, 2022, 7:06 a.m. UTC | #4
Why?
Palmer Dabbelt March 10, 2022, 7:34 a.m. UTC | #5
On Wed, 09 Mar 2022 23:06:22 PST (-0800), Christoph Hellwig wrote:
> Why?

I have no idea, but this has come up a few times before.

IIRC the original port had a no-M flavor (don't remember if it even made 
it to the original patch submission, but it was around for a bit).  We 
decided to drop this under the theory that nobody would use it: 
essentially, if you can afford the handful of MiB of memory required to 
run Linux then you've probably got a multiplier.

If someone has hardware that lacks M and users care about running Linux 
on that then I'm happy to support it.  I'll still point out the 
silliness of that decision, but if it's too late to change things then 
I'd rather support the hardware.  If it's one of these "fill out every 
possible allowed ISA flavor, even if nobody has one that runs Linux" 
then I don't see a reason to bother -- there's an infinite amount of 
allowable RISC-V implementations, we'll all go crazy chasing them 
around.

FWIW: to a first order, that applies to the no-A stuff as well (though 
that got dropped because the Arm folks pointed out a way to support that 
was way better than ours).
Palmer Dabbelt March 10, 2022, 7:34 a.m. UTC | #6
On Wed, 09 Mar 2022 02:02:27 PST (-0800), Arnd Bergmann wrote:
> On Wed, Mar 9, 2022 at 6:28 AM Michael T. Kloos
> <michael@michaelkloos.com> wrote:
>>
>> Added a new config symbol RISCV_ISA_M to enable the usage of the
>> multiplication, division, and remainder (modulus) instructions
>> from the M-extension.  This configures the march build flag to
>> either include or omit it.
>>
>> I didn't find any assembly using any of the instructions from
>> the M-extension.  However, the BPF JIT is a complicating factor.
>> Currently, it emits M-extension instructions to implement various
>> BPF operations.  For now, I have made HAVE_EBPF_JIT depend on
>> CONFIG_RISCV_ISA_M.
>>
>> I have added the supplementary integer arithmetic functions in
>> the file "arch/riscv/lib/ext_m_supplement.c".  All the code
>> contained in this file is wrapped in an ifndef contingent on the
>> presence of CONFIG_RISCV_ISA_M.
>>
>> Signed-off-by: Michael T. Kloos <michael@michaelkloos.com>
>
> The patch looks fine to me, but I increasingly get the feeling that the
> entire platform feature selection in Kconfig should be guarded with
> a global flag that switches between "fully generic" and "fully custom"
> builds, where the generic kernel assumes that all the standard
> features (64-bit, C, M, FPU, MMU, UEFI, ...) are present, the
> incompatible options (XIP, PHYS_RAM_BASE_FIXED,
> CMDLINE_FORCE, BUILTIN_DTB, ...) are force-disabled,
> and all optional features (V/B/P/H extensions, custom instructions,
> platform specific device drivers, ...) are runtime detected.

That'd be wonderful, but unfortunately we're trending the other way -- 
we're at the point where "words in the specification have meaning" is 
controversial, so trying to talk about which flavors of the 
specification are standard is just meaningless.  I obviously hope that 
gets sorted out, as we've clearly been pointed straight off a cliff for 
a while now, but LMKL isn't the place to have that discussion.  We've 
all seen this before, nobody needs to be convinced this leads to a mess.

Until we get to the point where "I wrote 'RISC-V' on that potato I found 
in my couch" can be conclusively determined not compliant with the spec, 
it's just silly to try and talk about what is.

> At the moment, those three types are listed at the same level,
> which gives the impression that they can be freely mixed.
>
>          Arnd
Arnd Bergmann March 10, 2022, 7:54 a.m. UTC | #7
On Thu, Mar 10, 2022 at 8:34 AM Palmer Dabbelt <palmer@dabbelt.com> wrote:
> On Wed, 09 Mar 2022 02:02:27 PST (-0800), Arnd Bergmann wrote:
> > On Wed, Mar 9, 2022 at 6:28 AM Michael T. Kloos <michael@michaelkloos.com> wrote:
>
> That'd be wonderful, but unfortunately we're trending the other way --
> we're at the point where "words in the specification have meaning" is
> controversial, so trying to talk about which flavors of the
> specification are standard is just meaningless.  I obviously hope that
> gets sorted out, as we've clearly been pointed straight off a cliff for
> a while now, but LMKL isn't the place to have that discussion.  We've
> all seen this before, nobody needs to be convinced this leads to a mess.
>
> Until we get to the point where "I wrote 'RISC-V' on that potato I found
> in my couch" can be conclusively determined not compliant with the spec,
> it's just silly to try and talk about what is.

I would argue that codifying the required extensions through kernel source
code is much stronger than interpreting a specification. Ideally the
specification
would match what the kernel requires, but it's not the end of the world if
the kernel ends up making decisions that are different: If Linux can do
runtime detection of non-M, non-A or pre-standard extensions and handle
them correctly without a notable performance impact, it can do that. Or
Linux could end up requiring things that are normally there but not
in the scope of the spec.

Regardless of who determines what the compatible subset is, I think there
is value in splitting out Kconfig options that prevent booting on normal
RV64GC machines (XIP, NOMMU, 32-bit, ...). This would probably
not include the non-M option, as long as a non-M kernel works as
expected on CPUs with the M instructions.

        Arnd
Christoph Hellwig March 10, 2022, 8:04 a.m. UTC | #8
On Wed, Mar 09, 2022 at 11:34:25PM -0800, Palmer Dabbelt wrote:
> If someone has hardware that lacks M and users care about running Linux on
> that then I'm happy to support it.  I'll still point out the silliness of
> that decision, but if it's too late to change things then I'd rather support
> the hardware.  If it's one of these "fill out every possible allowed ISA
> flavor, even if nobody has one that runs Linux" then I don't see a reason to
> bother -- there's an infinite amount of allowable RISC-V implementations,
> we'll all go crazy chasing them around.

It's not like Linux had required M mode since the RISC-V port was merged
upstream, so any new implementor really should know about it.  And
performance on anything that requires Linux will just be horrible.
I could see a bit of an excuse for a nommu port.

Anyway, this kind of patch really does need to state the why.  And it
better be a really good reason.
Michael T. Kloos March 10, 2022, 9:31 a.m. UTC | #9
As far as I can tell, it's simply a compiler flag to enable or disable it.
The only complicating issue that I found was the BPF JIT.  That is a
special case amounting to a compiler within the kernel itself and can be
patched or set to depend on M.  There is still the BPF interpreter.  The
kernel doesn't depend on the C-extension.  I have grepped through the
source code where that symbol is referenced, the checking of instruction
alignment constraints, and various checks used to make that work are much
more extensive than I expected, yet that is supported.  To quote the
commentary from the beginning of chapter 2 (Base-I) of the RISC-V spec:

> "RV32I was designed to be sufficient to form a compiler target and to
> support modern operating system environments. The ISA was also designed
> to reduce the hardware required in a minimal implementation. RV32I
> contains 40 unique instructions, though a simple implementation might
> cover the ECALL/EBREAK instructions with a single SYSTEM hardware
> instruction that always traps and might be able to implement the FENCE
> instruction as a NOP, reducing base instruction count to 38 total.
> RV32I can emulate almost any other ISA extension (except the A extension,
> which requires additional hardware support for atomicity).
>
> In practice, a hardware implementation including the machine-mode
> privileged architecture will also require the 6 CSR instructions.
>
> Subsets of the base integer ISA might be useful for pedagogical purposes,
> but the base has been defined such that there should be little incentive
> to subset a real hardware implementation beyond omitting support for
> misaligned memory accesses and treating all SYSTEM instructions
> as a single trap."

This is all a noble goal of RISC-V, to create a minimal, yet robust ISA.
I'm not arguing to support no-A, as stated in the commentary, atomic can
not be emulated (I mean, maybe you could by taking over sscratch) and
the atomic properties of the CSR instructions.  But that does seem hacky.)
and everything else is handled in the Base-I (Not including Zicsr).  The
kernel supports rv(32/64)ima so to draw the line in the sand that
rv(32/64)ia is unacceptable seems silly.

One of my concerns here is that if support is not added, that people may
start writing assembly that uses M instructions and other non-portable
stuff.  This will make a future port more difficult.

I do not have real hardware like this but I do have an emulator that
implements rv32iasu.  Eventually I want to build a HART implementation
out of real hardware logic chips.  Adding M, adds hardware complexity and
I think that it is better to do in software for such a minimal case.
Sure it will be slower than having native hardware M support.  Firmware
emulation will be even slower than that.  I'd much rather have the option
in the kernel to switch this on or off.

I am not trying to argue that the kernel should bend over to support my
pet projects, but it seems quite strange and arbitrary to draw the line
here over such a beautifully modular and minimal ISA.

> there's an infinite amount of
> allowable RISC-V implementations, we'll all go crazy chasing them
> around.
2 points on that:

1) Then it would seem logical to have the kernel target the most minimal
implementation to get the widest support.

2) I actually don't think this is entirely true, or at least not in the
sense that it is relevant to the kernel.  Atomics are needed for a modern
system.  The kernel needs to know about the floating-point support because
it needs to handle the clean-up and context-switching of the additional
floating point registers.  The kernel needs to know about the C extension
because of the ramifications to alignment.  Everything else is just gravy.
If sometime in the future the L-extension or the B-extension are finished
and implemented in future hardware, unless they make some very strange
decisions, I don't see why a kernel built today couldn't run on that
hardware with userspace software taking advantage of those native features.
Sure, in that situation, the kernel binary wouldn't be taking advantage of
them.  But then wouldn't you want to add CONFIG_RISCV_ISA_L and
CONFIG_RISCV_ISA_B in said future kernel so that the compiler is passed an
-march value such that the kernel can take advantage of these new native
hardware features?

It seems to me that this is the grand vision in the modularity of both the
RISC-V ISA and the C programming language.  We aren't writing everything in
assembly for a reason.  I don't think it makes sense to stop one extension
away from what the RISC-V spec documents themselves state is the intended
minimal system capable of running a full modern operating system.  I think
it is an arbitrary limit to the portability of the kernel.

	Michael

On 3/10/2022 2:34 AM, Palmer Dabbelt wrote:

> On Wed, 09 Mar 2022 23:06:22 PST (-0800), Christoph Hellwig wrote:
>> Why?
> I have no idea, but this has come up a few times before.
> IIRC the original port had a no-M flavor (don't remember if it even made
> it to the original patch submission, but it was around for a bit).  We
> decided to drop this under the theory that nobody would use it:
> essentially, if you can afford the handful of MiB of memory required to
> run Linux then you've probably got a multiplier.
> If someone has hardware that lacks M and users care about running Linux
> on that then I'm happy to support it.  I'll still point out the
> silliness of that decision, but if it's too late to change things then
> I'd rather support the hardware.  If it's one of these "fill out every
> possible allowed ISA flavor, even if nobody has one that runs Linux"
> then I don't see a reason to bother -- there's an infinite amount of
> allowable RISC-V implementations, we'll all go crazy chasing them
> around.
> FWIW: to a first order, that applies to the no-A stuff as well (though
> that got dropped because the Arm folks pointed out a way to support that
> was way better than ours).
Michael T. Kloos March 10, 2022, 1:22 p.m. UTC | #10
Some other thoughts:
It sounds like I am not the first person to want this feature and I
probably won't be the last.  I created the change for my own reasons, the
same as any other contributor.  I think we all know that I can not pull
out some chart and say, "This many people want this and here is why."  I
live in central Ohio and have been doing this as a hobby.  I don't even
know anyone else who knows about systems and operating system development.
If the justification that you are looking for is that I as some
hypothetical developer at a major tech company is about to release a new
RISC-V chip without M support but we want it to run Linux, I can not
provide that answer.  It sounds a bit like some software or hardware,
chicken or the egg anyway.  Trying to maintain my own fork if people
start contributing patches with incompatible assembly scares me.

	Michael

On 3/10/2022 4:31 AM, Michael T. Kloos wrote:

> As far as I can tell, it's simply a compiler flag to enable or disable it.
> The only complicating issue that I found was the BPF JIT.  That is a
> special case amounting to a compiler within the kernel itself and can be
> patched or set to depend on M.  There is still the BPF interpreter.  The
> kernel doesn't depend on the C-extension.  I have grepped through the
> source code where that symbol is referenced, the checking of instruction
> alignment constraints, and various checks used to make that work are much
> more extensive than I expected, yet that is supported.  To quote the
> commentary from the beginning of chapter 2 (Base-I) of the RISC-V spec:
>> "RV32I was designed to be sufficient to form a compiler target and to
>> support modern operating system environments. The ISA was also designed
>> to reduce the hardware required in a minimal implementation. RV32I
>> contains 40 unique instructions, though a simple implementation might
>> cover the ECALL/EBREAK instructions with a single SYSTEM hardware
>> instruction that always traps and might be able to implement the FENCE
>> instruction as a NOP, reducing base instruction count to 38 total.
>> RV32I can emulate almost any other ISA extension (except the A extension,
>> which requires additional hardware support for atomicity).
>> In practice, a hardware implementation including the machine-mode
>> privileged architecture will also require the 6 CSR instructions.
>> Subsets of the base integer ISA might be useful for pedagogical purposes,
>> but the base has been defined such that there should be little incentive
>> to subset a real hardware implementation beyond omitting support for
>> misaligned memory accesses and treating all SYSTEM instructions
>> as a single trap."
> This is all a noble goal of RISC-V, to create a minimal, yet robust ISA.
> I'm not arguing to support no-A, as stated in the commentary, atomic can
> not be emulated (I mean, maybe you could by taking over sscratch) and
> the atomic properties of the CSR instructions.  But that does seem hacky.)
> and everything else is handled in the Base-I (Not including Zicsr).  The
> kernel supports rv(32/64)ima so to draw the line in the sand that
> rv(32/64)ia is unacceptable seems silly.
> One of my concerns here is that if support is not added, that people may
> start writing assembly that uses M instructions and other non-portable
> stuff.  This will make a future port more difficult.
> I do not have real hardware like this but I do have an emulator that
> implements rv32iasu.  Eventually I want to build a HART implementation
> out of real hardware logic chips.  Adding M, adds hardware complexity and
> I think that it is better to do in software for such a minimal case.
> Sure it will be slower than having native hardware M support.  Firmware
> emulation will be even slower than that.  I'd much rather have the option
> in the kernel to switch this on or off.
> I am not trying to argue that the kernel should bend over to support my
> pet projects, but it seems quite strange and arbitrary to draw the line
> here over such a beautifully modular and minimal ISA.
>> there's an infinite amount of
>> allowable RISC-V implementations, we'll all go crazy chasing them
>> around.
> 2 points on that:
> 1) Then it would seem logical to have the kernel target the most minimal
> implementation to get the widest support.
> 2) I actually don't think this is entirely true, or at least not in the
> sense that it is relevant to the kernel.  Atomics are needed for a modern
> system.  The kernel needs to know about the floating-point support because
> it needs to handle the clean-up and context-switching of the additional
> floating point registers.  The kernel needs to know about the C extension
> because of the ramifications to alignment.  Everything else is just gravy.
> If sometime in the future the L-extension or the B-extension are finished
> and implemented in future hardware, unless they make some very strange
> decisions, I don't see why a kernel built today couldn't run on that
> hardware with userspace software taking advantage of those native features.
> Sure, in that situation, the kernel binary wouldn't be taking advantage of
> them.  But then wouldn't you want to add CONFIG_RISCV_ISA_L and
> CONFIG_RISCV_ISA_B in said future kernel so that the compiler is passed an
> -march value such that the kernel can take advantage of these new native
> hardware features?
> It seems to me that this is the grand vision in the modularity of both the
> RISC-V ISA and the C programming language.  We aren't writing everything in
> assembly for a reason.  I don't think it makes sense to stop one extension
> away from what the RISC-V spec documents themselves state is the intended
> minimal system capable of running a full modern operating system.  I think
> it is an arbitrary limit to the portability of the kernel.
>      Michael
> On 3/10/2022 2:34 AM, Palmer Dabbelt wrote:
>> On Wed, 09 Mar 2022 23:06:22 PST (-0800), Christoph Hellwig wrote:
>>> Why?
>> I have no idea, but this has come up a few times before.
>> IIRC the original port had a no-M flavor (don't remember if it even made
>> it to the original patch submission, but it was around for a bit).  We
>> decided to drop this under the theory that nobody would use it:
>> essentially, if you can afford the handful of MiB of memory required to
>> run Linux then you've probably got a multiplier.
>> If someone has hardware that lacks M and users care about running Linux
>> on that then I'm happy to support it.  I'll still point out the
>> silliness of that decision, but if it's too late to change things then
>> I'd rather support the hardware.  If it's one of these "fill out every
>> possible allowed ISA flavor, even if nobody has one that runs Linux"
>> then I don't see a reason to bother -- there's an infinite amount of
>> allowable RISC-V implementations, we'll all go crazy chasing them
>> around.
>> FWIW: to a first order, that applies to the no-A stuff as well (though
>> that got dropped because the Arm folks pointed out a way to support that
>> was way better than ours).
> _______________________________________________
> linux-riscv mailing list
> linux-riscv@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
Michael T. Kloos March 10, 2022, 1:37 p.m. UTC | #11
Is there something I can do that would help alleviate your concerns or
apprehension?

On 3/10/2022 8:22 AM, Michael T. Kloos wrote:

> Some other thoughts:
> It sounds like I am not the first person to want this feature and I
> probably won't be the last.  I created the change for my own reasons, the
> same as any other contributor.  I think we all know that I can not pull
> out some chart and say, "This many people want this and here is why."  I
> live in central Ohio and have been doing this as a hobby.  I don't even
> know anyone else who knows about systems and operating system development.
> If the justification that you are looking for is that I as some
> hypothetical developer at a major tech company is about to release a new
> RISC-V chip without M support but we want it to run Linux, I can not
> provide that answer.  It sounds a bit like some software or hardware,
> chicken or the egg anyway.  Trying to maintain my own fork if people
> start contributing patches with incompatible assembly scares me.
>      Michael
Palmer Dabbelt March 10, 2022, 5:09 p.m. UTC | #12
On Wed, 09 Mar 2022 23:54:17 PST (-0800), Arnd Bergmann wrote:
> On Thu, Mar 10, 2022 at 8:34 AM Palmer Dabbelt <palmer@dabbelt.com> wrote:
>> On Wed, 09 Mar 2022 02:02:27 PST (-0800), Arnd Bergmann wrote:
>> > On Wed, Mar 9, 2022 at 6:28 AM Michael T. Kloos <michael@michaelkloos.com> wrote:
>>
>> That'd be wonderful, but unfortunately we're trending the other way --
>> we're at the point where "words in the specification have meaning" is
>> controversial, so trying to talk about which flavors of the
>> specification are standard is just meaningless.  I obviously hope that
>> gets sorted out, as we've clearly been pointed straight off a cliff for
>> a while now, but LMKL isn't the place to have that discussion.  We've
>> all seen this before, nobody needs to be convinced this leads to a mess.
>>
>> Until we get to the point where "I wrote 'RISC-V' on that potato I found
>> in my couch" can be conclusively determined not compliant with the spec,
>> it's just silly to try and talk about what is.
>
> I would argue that codifying the required extensions through kernel source

The problem here isn't the required extensions, it's that vendors can 
claim to implement an extension on hardware that doesn't exhibit any of 
the behavior the specification expresses that systems with those 
extensions must have.  The D1 is a very concrete example of this.

> code is much stronger than interpreting a specification. Ideally the
> specification
> would match what the kernel requires, but it's not the end of the world if
> the kernel ends up making decisions that are different: If Linux can do
> runtime detection of non-M, non-A or pre-standard extensions and handle
> them correctly without a notable performance impact, it can do that. Or
> Linux could end up requiring things that are normally there but not
> in the scope of the spec.
>
> Regardless of who determines what the compatible subset is, I think there
> is value in splitting out Kconfig options that prevent booting on normal
> RV64GC machines (XIP, NOMMU, 32-bit, ...). This would probably
> not include the non-M option, as long as a non-M kernel works as
> expected on CPUs with the M instructions.

I get the value to having an option hiding these things, as users might 
shoot themselves in the foot.  I sent a patch, not sure it's exactly 
what we want but at least it's something concrete to discuss.
Palmer Dabbelt March 11, 2022, 4:29 a.m. UTC | #13
On Thu, 10 Mar 2022 05:37:27 PST (-0800), Michael@MichaelKloos.com wrote:
> Is there something I can do that would help alleviate your concerns or
> apprehension?

IMO this is one of those cases where having hardware is required.

I can understand the goal of providing a Linux port for the minimal 
RISC-V compatible system, but IIUC the minimal RISC-V compatible system 
is any object associated with a member of the RISC-V foundation that 
said member attests is a RISC-V system.  There's really no way to 
implement Linux on all such systems so we have to set the bar somewhere, 
and bar is generally set at "more time will be spent using this than 
maintaining it".  Systems without M have generally not met that bar, and 
I don't see anything changing now.

If you have users then I'm happy to reconsider, the goal here is to make 
real systems work.  That said: we've already got enough trouble trying 
to make actual shipping hardware function correctly, we're all going to 
lose our minds trying to chase around everything that could in theory be 
a RISC-V system but doesn't actually exist.

>
> On 3/10/2022 8:22 AM, Michael T. Kloos wrote:
>
>> Some other thoughts:
>> It sounds like I am not the first person to want this feature and I
>> probably won't be the last.  I created the change for my own reasons, the
>> same as any other contributor.  I think we all know that I can not pull
>> out some chart and say, "This many people want this and here is why."  I
>> live in central Ohio and have been doing this as a hobby.  I don't even
>> know anyone else who knows about systems and operating system development.
>> If the justification that you are looking for is that I as some
>> hypothetical developer at a major tech company is about to release a new
>> RISC-V chip without M support but we want it to run Linux, I can not
>> provide that answer.  It sounds a bit like some software or hardware,
>> chicken or the egg anyway.  Trying to maintain my own fork if people
>> start contributing patches with incompatible assembly scares me.
>>      Michael
Michael T. Kloos March 11, 2022, 4:54 a.m. UTC | #14
Well at least I can take some satisfaction in that it seems that on my
2nd patch sent to the Linux kernel, I got it right the first time.  No
one has complained about problems with the code itself, just that they
don't want the feature.  I have also received no errors back from the
build bot.

For now, I will try to maintain this port on my own.  Thank you for the
consideration Palmer.

	Michael

On Thu, 2022-03-10 at 20:29 -0800, Palmer Dabbelt wrote:
> On Thu, 10 Mar 2022 05:37:27 PST (-0800), Michael@MichaelKloos.com wrote:
> > Is there something I can do that would help alleviate your concerns or
> > apprehension?
> 
> IMO this is one of those cases where having hardware is required.
> 
> I can understand the goal of providing a Linux port for the minimal 
> RISC-V compatible system, but IIUC the minimal RISC-V compatible system 
> is any object associated with a member of the RISC-V foundation that 
> said member attests is a RISC-V system.  There's really no way to 
> implement Linux on all such systems so we have to set the bar somewhere, 
> and bar is generally set at "more time will be spent using this than 
> maintaining it".  Systems without M have generally not met that bar, and 
> I don't see anything changing now.
> 
> If you have users then I'm happy to reconsider, the goal here is to make 
> real systems work.  That said: we've already got enough trouble trying 
> to make actual shipping hardware function correctly, we're all going to 
> lose our minds trying to chase around everything that could in theory be 
> a RISC-V system but doesn't actually exist.
> 
> > 
> > On 3/10/2022 8:22 AM, Michael T. Kloos wrote:
> > 
> > > Some other thoughts:
> > > It sounds like I am not the first person to want this feature and I
> > > probably won't be the last.  I created the change for my own reasons, the
> > > same as any other contributor.  I think we all know that I can not pull
> > > out some chart and say, "This many people want this and here is why."  I
> > > live in central Ohio and have been doing this as a hobby.  I don't even
> > > know anyone else who knows about systems and operating system development.
> > > If the justification that you are looking for is that I as some
> > > hypothetical developer at a major tech company is about to release a new
> > > RISC-V chip without M support but we want it to run Linux, I can not
> > > provide that answer.  It sounds a bit like some software or hardware,
> > > chicken or the egg anyway.  Trying to maintain my own fork if people
> > > start contributing patches with incompatible assembly scares me.
> > >      Michael
Pavel Machek April 2, 2022, 10:18 a.m. UTC | #15
Hi!

> >>That'd be wonderful, but unfortunately we're trending the other way --
> >>we're at the point where "words in the specification have meaning" is
> >>controversial, so trying to talk about which flavors of the
> >>specification are standard is just meaningless.  I obviously hope that
> >>gets sorted out, as we've clearly been pointed straight off a cliff for
> >>a while now, but LMKL isn't the place to have that discussion.  We've
> >>all seen this before, nobody needs to be convinced this leads to a mess.
> >>
> >>Until we get to the point where "I wrote 'RISC-V' on that potato I found
> >>in my couch" can be conclusively determined not compliant with the spec,
> >>it's just silly to try and talk about what is.
> >
> >I would argue that codifying the required extensions through kernel source
> 
> The problem here isn't the required extensions, it's that vendors can claim
> to implement an extension on hardware that doesn't exhibit any of the
> behavior the specification expresses that systems with those extensions must
> have.  The D1 is a very concrete example of this.

Sounds like someone interested should make a webpage listing available
CPUs that claim RISC-V compatibility but far short of advertised
claims?

I'd like to get RISC-V board to play with sometime soon, and some help
in what board to get would be welcome...

Best regards,
								Pavel
diff mbox series

Patch

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 5adcbd9b5e88..40e1110a405c 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -83,7 +83,7 @@  config RISCV
 	select HAVE_CONTEXT_TRACKING
 	select HAVE_DEBUG_KMEMLEAK
 	select HAVE_DMA_CONTIGUOUS if MMU
-	select HAVE_EBPF_JIT if MMU
+	select HAVE_EBPF_JIT if (MMU && RISCV_ISA_M)
 	select HAVE_FUNCTION_ERROR_INJECTION
 	select HAVE_GCC_PLUGINS
 	select HAVE_GENERIC_VDSO if MMU && 64BIT
@@ -323,15 +323,25 @@  config NODES_SHIFT
 	  Specify the maximum number of NUMA Nodes available on the target
 	  system.  Increases memory reserved to accommodate various tables.
 
+config RISCV_ISA_M
+	bool "Emit multiplication instructions when building Linux"
+	default y
+	help
+	  Adds "M" to the ISA subsets that the toolchain is allowed to emit
+	  when building Linux, which results in multiplication, division, and
+	  remainder instructions in the Linux binary.
+
+	  If you don't know what to do here, say Y.
+
 config RISCV_ISA_C
 	bool "Emit compressed instructions when building Linux"
 	default y
 	help
-	   Adds "C" to the ISA subsets that the toolchain is allowed to emit
-	   when building Linux, which results in compressed instructions in the
-	   Linux binary.
+	  Adds "C" to the ISA subsets that the toolchain is allowed to emit
+	  when building Linux, which results in compressed instructions in the
+	  Linux binary.
 
-	   If you don't know what to do here, say Y.
+	  If you don't know what to do here, say Y.
 
 menu "supported PMU type"
 	depends on PERF_EVENTS
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 7d81102cffd4..7e24cfe51ef7 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -46,8 +46,10 @@  endif
 endif
 
 # ISA string setting
-riscv-march-$(CONFIG_ARCH_RV32I)	:= rv32ima
-riscv-march-$(CONFIG_ARCH_RV64I)	:= rv64ima
+riscv-march-$(CONFIG_ARCH_RV32I)	:= rv32i
+riscv-march-$(CONFIG_ARCH_RV64I)	:= rv64i
+riscv-march-$(CONFIG_RISCV_ISA_M)	:= $(riscv-march-y)m
+riscv-march-y				:= $(riscv-march-y)a
 riscv-march-$(CONFIG_FPU)		:= $(riscv-march-y)fd
 riscv-march-$(CONFIG_RISCV_ISA_C)	:= $(riscv-march-y)c
 
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index 25d5c9664e57..965eebaaa1ce 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -5,5 +5,6 @@  lib-y			+= memset.o
 lib-y			+= memmove.o
 lib-$(CONFIG_MMU)	+= uaccess.o
 lib-$(CONFIG_64BIT)	+= tishift.o
+lib-y			+= ext_m_supplement.o
 
 obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
diff --git a/arch/riscv/lib/ext_m_supplement.c b/arch/riscv/lib/ext_m_supplement.c
new file mode 100644
index 000000000000..42ced0ea9fe2
--- /dev/null
+++ b/arch/riscv/lib/ext_m_supplement.c
@@ -0,0 +1,588 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Michael T. Kloos <michael@michaelkloos.com>
+ */
+
+/*
+ * The GNU manual page here:
+ * https://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html
+ * describes these functions in terms of signed and unsigned, int and long.
+ * However, these prototypes are wrong when the size of int and long are
+ * considered per the RISC-V ABI specification.  The RISC-V port of the GCC
+ * complier does not follow the standard of those prototypes.  This is
+ * discussed in this thread:
+ * https://github.com/riscv-collab/riscv-gcc/issues/324
+ *
+ * On the RISC-V Architecture:
+ * - __xyyysi3 always refers to  32-bit integers.
+ * - __xyyydi3 always refers to  64-bit integers.
+ * - __xyyyti3 always refers to 128-bit integers. (Only implemented for rv64)
+ *
+ * Per the RISC-V ABI specification, the C base types are:
+ * - int:       32-bits wide.
+ * - long:      XLEN-bits wide.  It matches the register width.
+ * - long long: 64-bits wide.
+ *
+ * Therefore, the correct RISC-V function prototypes are:
+ * - signed int __mulsi3(signed int a, signed int b);
+ * - signed long long __muldi3(signed long long a, signed long long b);
+ * - signed __int128 __multi3(signed __int128 a, signed __int128 b);
+ *
+ * - signed int __divsi3(signed int a, signed int b);
+ * - signed long long __divdi3(signed long long a, signed long long b);
+ * - signed __int128 __divti3(signed __int128 a, signed __int128 b);
+ *
+ * - unsigned int __udivsi3(unsigned int a, unsigned int b);
+ * - unsigned long long __udivdi3(unsigned long long a, unsigned long long b);
+ * - unsigned __int128 __udivti3(unsigned __int128 a, unsigned __int128 b);
+ *
+ * - signed int __modsi3(signed int a, signed int b);
+ * - signed long long __moddi3(signed long long a, signed long long b);
+ * - signed __int128 __modti3(signed __int128 a, signed __int128 b);
+ *
+ * - unsigned int __umodsi3(unsigned int a, unsigned int b);
+ * - unsigned long long __umoddi3(unsigned long long a, unsigned long long b);
+ * - unsigned __int128 __umodti3(unsigned __int128 a, unsigned __int128 b);
+ */
+
+/*
+ * This C code is not portable across architectures.  It is RISC-V specific.
+ */
+
+#ifndef CONFIG_RISCV_ISA_M
+
+#include <linux/export.h>
+
+signed int __mulsi3(signed int a, signed int b)
+{
+	unsigned int ua;
+	unsigned int ub;
+	unsigned int j;
+	unsigned int i;
+	signed int r;
+
+	ua = a;
+	ub = b;
+
+	j = 0;
+	for (i = 0; i < sizeof(signed int) * 8; i++) {
+		if (!ua || !ub)
+			break;
+		if (ua & 0x1)
+			j += ub;
+		ua >>= 1;
+		ub <<= 1;
+	}
+
+	r = j;
+
+	return r;
+}
+EXPORT_SYMBOL(__mulsi3);
+
+signed long long __muldi3(signed long long a, signed long long b)
+{
+	unsigned long long ua;
+	unsigned long long ub;
+	unsigned long long j;
+	unsigned int i;
+	signed long long r;
+
+	ua = a;
+	ub = b;
+
+	j = 0;
+	for (i = 0; i < sizeof(signed long long) * 8; i++) {
+		if (!ua || !ub)
+			break;
+		if (ua & 0x1)
+			j += ub;
+		ua >>= 1;
+		ub <<= 1;
+	}
+
+	r = j;
+
+	return r;
+}
+EXPORT_SYMBOL(__muldi3);
+
+#ifdef CONFIG_64BIT
+signed __int128 __multi3(signed __int128 a, signed __int128 b)
+{
+	unsigned __int128 ua;
+	unsigned __int128 ub;
+	unsigned __int128 j;
+	unsigned int i;
+	signed __int128 r;
+
+	ua = a;
+	ub = b;
+
+	j = 0;
+	for (i = 0; i < sizeof(signed __int128) * 8; i++) {
+		if (!ua || !ub)
+			break;
+		if (ua & 0x1)
+			j += ub;
+		ua >>= 1;
+		ub <<= 1;
+	}
+
+	r = j;
+
+	return r;
+}
+EXPORT_SYMBOL(__multi3);
+#endif
+
+signed int __divsi3(signed int a, signed int b)
+{
+	unsigned int ua;
+	unsigned int ub;
+	unsigned int j;
+	unsigned int i;
+	signed int r;
+
+	if (b == 0)
+		return (signed int)(-1);
+
+	ua = a;
+	ub = b;
+	if (a < 0)
+		ua = -a;
+	if (b < 0)
+		ub = -b;
+
+	j = 0;
+	i = 0;
+	while (ua >= ub) {
+		if ((signed int)ub < 0) {
+			ua -= ub;
+			j |= 1u << i;
+			break;
+		}
+		ub <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		ub >>= 1;
+		if (ua >= ub) {
+			ua -= ub;
+			j |= 1u << i;
+		}
+	}
+
+	r = j;
+	a ^= b;
+	if (a < 0)
+		r = -r;
+
+	return r;
+}
+EXPORT_SYMBOL(__divsi3);
+
+signed long long __divdi3(signed long long a, signed long long b)
+{
+	unsigned long long ua;
+	unsigned long long ub;
+	unsigned long long j;
+	unsigned int i;
+	signed long long r;
+
+	if (b == 0)
+		return (signed long long)(-1);
+
+	ua = a;
+	ub = b;
+	if (a < 0)
+		ua = -a;
+	if (b < 0)
+		ub = -b;
+
+	j = 0;
+	i = 0;
+	while (ua >= ub) {
+		if ((signed long long)ub < 0) {
+			ua -= ub;
+			j |= 1ull << i;
+			break;
+		}
+		ub <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		ub >>= 1;
+		if (ua >= ub) {
+			ua -= ub;
+			j |= 1ull << i;
+		}
+	}
+
+	r = j;
+	a ^= b;
+	if (a < 0)
+		r = -r;
+
+	return r;
+}
+EXPORT_SYMBOL(__divdi3);
+
+#ifdef CONFIG_64BIT
+signed __int128 __divti3(signed __int128 a, signed __int128 b)
+{
+	unsigned __int128 ua;
+	unsigned __int128 ub;
+	unsigned __int128 j;
+	unsigned int i;
+	signed __int128 r;
+
+	if (b == 0)
+		return (signed __int128)(-1);
+
+	ua = a;
+	ub = b;
+	if (a < 0)
+		ua = -a;
+	if (b < 0)
+		ub = -b;
+
+	j = 0;
+	i = 0;
+	while (ua >= ub) {
+		if ((signed __int128)ub < 0) {
+			ua -= ub;
+			j |= ((unsigned __int128)1) << i;
+			break;
+		}
+		ub <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		ub >>= 1;
+		if (ua >= ub) {
+			ua -= ub;
+			j |= ((unsigned __int128)1) << i;
+		}
+	}
+
+	r = j;
+	a ^= b;
+	if (a < 0)
+		r = -r;
+
+	return r;
+}
+EXPORT_SYMBOL(__divti3);
+#endif
+
+unsigned int __udivsi3(unsigned int a, unsigned int b)
+{
+	unsigned int j;
+	unsigned int i;
+
+	if (b == 0)
+		return (signed int)(-1);
+
+	j = 0;
+	i = 0;
+	while (a >= b) {
+		if ((signed int)b < 0) {
+			a -= b;
+			j |= 1u << i;
+			break;
+		}
+		b <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		b >>= 1;
+		if (a >= b) {
+			a -= b;
+			j |= 1u << i;
+		}
+	}
+
+	return j;
+}
+EXPORT_SYMBOL(__udivsi3);
+
+unsigned long long __udivdi3(unsigned long long a, unsigned long long b)
+{
+	unsigned long long j;
+	unsigned long long i;
+
+	if (b == 0)
+		return (signed long long)(-1);
+
+	j = 0;
+	i = 0;
+	while (a >= b) {
+		if ((signed long long)b < 0) {
+			a -= b;
+			j |= 1ull << i;
+			break;
+		}
+		b <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		b >>= 1;
+		if (a >= b) {
+			a -= b;
+			j |= 1ull << i;
+		}
+	}
+
+	return j;
+}
+EXPORT_SYMBOL(__udivdi3);
+
+#ifdef CONFIG_64BIT
+unsigned __int128 __udivti3(unsigned __int128 a, unsigned __int128 b)
+{
+	unsigned __int128 j;
+	unsigned __int128 i;
+
+	if (b == 0)
+		return (signed __int128)(-1);
+
+	j = 0;
+	i = 0;
+	while (a >= b) {
+		if ((signed __int128)b < 0) {
+			a -= b;
+			j |= ((unsigned __int128)1) << i;
+			break;
+		}
+		b <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		b >>= 1;
+		if (a >= b) {
+			a -= b;
+			j |= ((unsigned __int128)1) << i;
+		}
+	}
+
+	return j;
+}
+EXPORT_SYMBOL(__udivti3);
+#endif
+
+signed int __modsi3(signed int a, signed int b)
+{
+	unsigned int ua;
+	unsigned int ub;
+	unsigned int i;
+	signed int r;
+
+	if (b == 0)
+		return a;
+
+	ua = a;
+	ub = b;
+	if (a < 0)
+		ua = -a;
+	if (b < 0)
+		ub = -b;
+
+	i = 0;
+	while (ua >= ub) {
+		if ((signed int)ub < 0) {
+			ua -= ub;
+			break;
+		}
+		ub <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		ub >>= 1;
+		if (ua >= ub)
+			ua -= ub;
+	}
+
+	r = ua;
+	if (a < 0)
+		r = -r;
+
+	return r;
+}
+EXPORT_SYMBOL(__modsi3);
+
+signed long long __moddi3(signed long long a, signed long long b)
+{
+	unsigned long long ua;
+	unsigned long long ub;
+	unsigned int i;
+	signed long long r;
+
+	if (b == 0)
+		return a;
+
+	ua = a;
+	ub = b;
+	if (a < 0)
+		ua = -a;
+	if (b < 0)
+		ub = -b;
+
+	i = 0;
+	while (ua >= ub) {
+		if ((signed long long)ub < 0) {
+			ua -= ub;
+			break;
+		}
+		ub <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		ub >>= 1;
+		if (ua >= ub)
+			ua -= ub;
+	}
+
+	r = ua;
+	if (a < 0)
+		r = -r;
+
+	return r;
+}
+EXPORT_SYMBOL(__moddi3);
+
+#ifdef CONFIG_64BIT
+signed __int128 __modti3(signed __int128 a, signed __int128 b)
+{
+	unsigned __int128 ua;
+	unsigned __int128 ub;
+	unsigned int i;
+	signed __int128 r;
+
+	if (b == 0)
+		return a;
+
+	ua = a;
+	ub = b;
+	if (a < 0)
+		ua = -a;
+	if (b < 0)
+		ub = -b;
+
+	i = 0;
+	while (ua >= ub) {
+		if ((signed __int128)ub < 0) {
+			ua -= ub;
+			break;
+		}
+		ub <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		ub >>= 1;
+		if (ua >= ub)
+			ua -= ub;
+	}
+
+	r = ua;
+	if (a < 0)
+		r = -r;
+
+	return r;
+}
+EXPORT_SYMBOL(__modti3);
+#endif
+
+unsigned int __umodsi3(unsigned int a, unsigned int b)
+{
+	unsigned int i;
+
+	if (b == 0)
+		return a;
+
+	i = 0;
+	while (a >= b) {
+		if ((signed int)b < 0) {
+			a -= b;
+			break;
+		}
+		b <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		b >>= 1;
+		if (a >= b)
+			a -= b;
+	}
+
+	return a;
+}
+EXPORT_SYMBOL(__umodsi3);
+
+unsigned long long __umoddi3(unsigned long long a, unsigned long long b)
+{
+	unsigned long long i;
+
+	if (b == 0)
+		return a;
+
+	i = 0;
+	while (a >= b) {
+		if ((signed long long)b < 0) {
+			a -= b;
+			break;
+		}
+		b <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		b >>= 1;
+		if (a >= b)
+			a -= b;
+	}
+
+	return a;
+}
+EXPORT_SYMBOL(__umoddi3);
+
+#ifdef CONFIG_64BIT
+unsigned __int128 __umodti3(unsigned __int128 a, unsigned __int128 b)
+{
+	unsigned __int128 i;
+
+	if (b == 0)
+		return a;
+
+	i = 0;
+	while (a >= b) {
+		if ((signed __int128)b < 0) {
+			a -= b;
+			break;
+		}
+		b <<= 1;
+		i++;
+	}
+	while (i > 0) {
+		i--;
+		b >>= 1;
+		if (a >= b)
+			a -= b;
+	}
+
+	return a;
+}
+EXPORT_SYMBOL(__umodti3);
+#endif
+
+#endif