]> git.baikalelectronics.ru Git - kernel.git/commit
riscv: Fix auipc+jalr relocation range checks
authorEmil Renner Berthing <kernel@esmil.dk>
Wed, 23 Feb 2022 19:12:57 +0000 (20:12 +0100)
committerPalmer Dabbelt <palmer@rivosinc.com>
Fri, 11 Mar 2022 04:37:44 +0000 (20:37 -0800)
commit5a83c770fd4615b62347f0bf605dfc1a6aa2bfb8
tree6445790fff7991592508a59bbce1082e1fd8d74b
parenta3961025892d044367dc4d6afcdc38bc93c16e05
riscv: Fix auipc+jalr relocation range checks

RISC-V can do PC-relative jumps with a 32bit range using the following
two instructions:

auipc t0, imm20 ; t0 = PC + imm20 * 2^12
jalr ra, t0, imm12 ; ra = PC + 4, PC = t0 + imm12

Crucially both the 20bit immediate imm20 and the 12bit immediate imm12
are treated as two's-complement signed values. For this reason the
immediates are usually calculated like this:

imm20 = (offset + 0x800) >> 12
imm12 = offset & 0xfff

..where offset is the signed offset from the auipc instruction. When
the 11th bit of offset is 0 the addition of 0x800 doesn't change the top
20 bits and imm12 considered positive. When the 11th bit is 1 the carry
of the addition by 0x800 means imm20 is one higher, but since imm12 is
then considered negative the two's complement representation means it
all cancels out nicely.

However, this addition by 0x800 (2^11) means an offset greater than or
equal to 2^31 - 2^11 would overflow so imm20 is considered negative and
result in a backwards jump. Similarly the lower range of offset is also
moved down by 2^11 and hence the true 32bit range is

[-2^31 - 2^11, 2^31 - 2^11)

Signed-off-by: Emil Renner Berthing <kernel@esmil.dk>
Fixes: 84df39b7f5b8 ("RISC-V: User-facing API")
Cc: stable@vger.kernel.org
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
arch/riscv/kernel/module.c