Original patches are from Lasse Collin <[email protected]>

Signed-off-by: YU Jincheng <[email protected]>
---
 archival/libarchive/unxz/xz_config.h  |   2 +
 archival/libarchive/unxz/xz_dec_bcj.c | 152 +++++++++++++++++++++++++-
 2 files changed, 153 insertions(+), 1 deletion(-)

diff --git a/archival/libarchive/unxz/xz_config.h 
b/archival/libarchive/unxz/xz_config.h
index 187e1cbed..95d1817c8 100644
--- a/archival/libarchive/unxz/xz_config.h
+++ b/archival/libarchive/unxz/xz_config.h
@@ -17,6 +17,8 @@
 /* #define XZ_DEC_ARM */
 /* #define XZ_DEC_ARMTHUMB */
 /* #define XZ_DEC_SPARC */
+/* #define XZ_DEC_ARM64 */
+/* #define XZ_DEC_RISCV */
 
 #include <stdbool.h>
 #include <stdlib.h>
diff --git a/archival/libarchive/unxz/xz_dec_bcj.c 
b/archival/libarchive/unxz/xz_dec_bcj.c
index e0f913a94..5565dc773 100644
--- a/archival/libarchive/unxz/xz_dec_bcj.c
+++ b/archival/libarchive/unxz/xz_dec_bcj.c
@@ -24,7 +24,9 @@ struct xz_dec_bcj {
                BCJ_IA64 = 6,       /* Big or little endian */
                BCJ_ARM = 7,        /* Little endian only */
                BCJ_ARMTHUMB = 8,   /* Little endian only */
-               BCJ_SPARC = 9       /* Big or little endian */
+               BCJ_SPARC = 9,      /* Big or little endian */
+               BCJ_ARM64 = 10,     /* AArch64 */
+               BCJ_RISCV = 11      /* RV32GQC_Zfh, RV64GQC_Zfh */
        } type;
 
        /*
@@ -340,6 +342,138 @@ static noinline_for_stack size_t XZ_FUNC bcj_sparc(
 }
 #endif
 
+#ifdef XZ_DEC_ARM64
+static size_t bcj_arm64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+       size_t i;
+       uint32_t instr;
+       uint32_t addr;
+
+       for (i = 0; i + 4 <= size; i += 4) {
+               instr = get_unaligned_le32(buf + i);
+
+               if ((instr >> 26) == 0x25) {
+                       /* BL instruction */
+                       addr = instr - ((s->pos + (uint32_t)i) >> 2);
+                       instr = 0x94000000 | (addr & 0x03FFFFFF);
+                       put_unaligned_le32(instr, buf + i);
+
+               } else if ((instr & 0x9F000000) == 0x90000000) {
+                       /* ADRP instruction */
+                       addr = ((instr >> 29) & 3) | ((instr >> 3) & 0x1FFFFC);
+
+                       /* Only convert values in the range +/-512 MiB. */
+                       if ((addr + 0x020000) & 0x1C0000)
+                               continue;
+
+                       addr -= (s->pos + (uint32_t)i) >> 12;
+
+                       instr &= 0x9000001F;
+                       instr |= (addr & 3) << 29;
+                       instr |= (addr & 0x03FFFC) << 3;
+                       instr |= (0U - (addr & 0x020000)) & 0xE00000;
+
+                       put_unaligned_le32(instr, buf + i);
+               }
+       }
+
+       return i;
+}
+#endif
+
+#ifdef XZ_DEC_RISCV
+static size_t bcj_riscv(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+       size_t i;
+       uint32_t b1;
+       uint32_t b2;
+       uint32_t b3;
+       uint32_t instr;
+       uint32_t instr2;
+       uint32_t instr2_rs1;
+       uint32_t addr;
+
+       if (size < 8)
+               return 0;
+
+       size -= 8;
+
+       for (i = 0; i <= size; i += 2) {
+               instr = buf[i];
+
+               if (instr == 0xEF) {
+                       /* JAL */
+                       b1 = buf[i + 1];
+                       if ((b1 & 0x0D) != 0)
+                               continue;
+
+                       b2 = buf[i + 2];
+                       b3 = buf[i + 3];
+
+                       addr = ((b1 & 0xF0) << 13) | (b2 << 9) | (b3 << 1);
+                       addr -= s->pos + (uint32_t)i;
+
+                       buf[i + 1] = (uint8_t)((b1 & 0x0F)
+                                       | ((addr >> 8) & 0xF0));
+
+                       buf[i + 2] = (uint8_t)(((addr >> 16) & 0x0F)
+                                       | ((addr >> 7) & 0x10)
+                                       | ((addr << 4) & 0xE0));
+
+                       buf[i + 3] = (uint8_t)(((addr >> 4) & 0x7F)
+                                       | ((addr >> 13) & 0x80));
+
+                       i += 4 - 2;
+
+               } else if ((instr & 0x7F) == 0x17) {
+                       /* AUIPC */
+                       instr |= (uint32_t)buf[i + 1] << 8;
+                       instr |= (uint32_t)buf[i + 2] << 16;
+                       instr |= (uint32_t)buf[i + 3] << 24;
+
+                       if (instr & 0xE80) {
+                               /* AUIPC's rd doesn't equal x0 or x2. */
+                               instr2 = get_unaligned_le32(buf + i + 4);
+
+                               if (((instr << 8) ^ (instr2 - 3)) & 0xF8003) {
+                                       i += 6 - 2;
+                                       continue;
+                               }
+
+                               addr = (instr & 0xFFFFF000) + (instr2 >> 20);
+
+                               instr = 0x17 | (2 << 7) | (instr2 << 12);
+                               instr2 = addr;
+                       } else {
+                               /* AUIPC's rd equals x0 or x2. */
+                               instr2_rs1 = instr >> 27;
+
+                               if ((uint32_t)((instr - 0x3117) << 18)
+                                               >= (instr2_rs1 & 0x1D)) {
+                                       i += 4 - 2;
+                                       continue;
+                               }
+
+                               addr = get_unaligned_be32(buf + i + 4);
+                               addr -= s->pos + (uint32_t)i;
+
+                               instr2 = (instr >> 12) | (addr << 20);
+
+                               instr = 0x17 | (instr2_rs1 << 7)
+                                       | ((addr + 0x800) & 0xFFFFF000);
+                       }
+
+                       put_unaligned_le32(instr, buf + i);
+                       put_unaligned_le32(instr2, buf + i + 4);
+
+                       i += 8 - 2;
+               }
+       }
+
+       return i;
+}
+#endif
+
 /*
  * Apply the selected BCJ filter. Update *pos and s->pos to match the amount
  * of data that got filtered.
@@ -386,6 +520,16 @@ static void XZ_FUNC bcj_apply(struct xz_dec_bcj *s,
        case BCJ_SPARC:
                filtered = bcj_sparc(s, buf, size);
                break;
+#endif
+#ifdef XZ_DEC_ARM64
+       case BCJ_ARM64:
+               filtered = bcj_arm64(s, buf, size);
+               break;
+#endif
+#ifdef XZ_DEC_RISCV
+       case BCJ_RISCV:
+               filtered = bcj_riscv(s, buf, size);
+               break;
 #endif
        default:
                /* Never reached but silence compiler warnings. */
@@ -559,6 +703,12 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset(
 #endif
 #ifdef XZ_DEC_SPARC
        case BCJ_SPARC:
+#endif
+#ifdef XZ_DEC_ARM64
+       case BCJ_ARM64:
+#endif
+#ifdef XZ_DEC_RISCV
+       case BCJ_RISCV:
 #endif
                break;
 
-- 
2.43.0

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to