arm: update hint instruction decoding to match ARMv8.5

This fixes:

- unallocated hints that have since been allocated
- unallocated and unimplemented hint instructions being treated as
  Unknown instead of the correct NOP
- missing encoding for DBG on A32

Unallocated and unimplemented hints give a warning if executed.

The most important fix was for the CSDB Spectre mitigation
instruction, which was added recently and previously unallocated and
treated as Unknown.

The Linux kernel v4.18 ARMv7 uses CSDB it and boot would
fail with "undefined instruction" since Linux commit
1d4238c56f9816ce0f9c8dbe42d7f2ad81cb6613

Change-Id: I283da3f08a9af4148edc6fb3ca2930cbb97126b8
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/13475
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
diff --git a/src/arch/arm/isa/formats/aarch64.isa b/src/arch/arm/isa/formats/aarch64.isa
index aa38fd4..cd106ab 100644
--- a/src/arch/arm/isa/formats/aarch64.isa
+++ b/src/arch/arm/isa/formats/aarch64.isa
@@ -292,22 +292,84 @@
                     if (rt != 0x1f || l)
                         return new Unknown64(machInst);
                     if (crn == 0x2 && op1 == 0x3) {
-                        switch (op2) {
+                        switch (crm) {
                           case 0x0:
-                            return new NopInst(machInst);
+                            switch (op2) {
+                              case 0x0:
+                                return new NopInst(machInst);
+                              case 0x1:
+                                return new YieldInst(machInst);
+                              case 0x2:
+                                return new WfeInst(machInst);
+                              case 0x3:
+                                return new WfiInst(machInst);
+                              case 0x4:
+                                return new SevInst(machInst);
+                              case 0x5:
+                                return new SevlInst(machInst);
+                            }
+                            break;
                           case 0x1:
-                            return new YieldInst(machInst);
+                            switch (op2) {
+                              case 0x0:
+                                return new WarnUnimplemented(
+                                        "pacia", machInst);
+                              case 0x2:
+                                return new WarnUnimplemented(
+                                        "pacib", machInst);
+                              case 0x4:
+                                return new WarnUnimplemented(
+                                        "autia", machInst);
+                              case 0x6:
+                                return new WarnUnimplemented(
+                                        "autib", machInst);
+                            }
+                            break;
                           case 0x2:
-                            return new WfeInst(machInst);
+                            switch (op2) {
+                              case 0x0:
+                                return new WarnUnimplemented(
+                                        "esb", machInst);
+                              case 0x1:
+                                return new WarnUnimplemented(
+                                        "psb csync", machInst);
+                              case 0x2:
+                                return new WarnUnimplemented(
+                                        "tsb csync", machInst);
+                              case 0x4:
+                                return new WarnUnimplemented(
+                                        "csdb", machInst);
+                            }
+                            break;
                           case 0x3:
-                            return new WfiInst(machInst);
+                            switch (op2) {
+                              case 0x0:
+                              case 0x1:
+                                return new WarnUnimplemented(
+                                        "pacia", machInst);
+                              case 0x2:
+                              case 0x3:
+                                return new WarnUnimplemented(
+                                        "pacib", machInst);
+                              case 0x4:
+                              case 0x5:
+                                return new WarnUnimplemented(
+                                        "autia", machInst);
+                              case 0x6:
+                              case 0x7:
+                                return new WarnUnimplemented(
+                                        "autib", machInst);
+                            }
+                            break;
                           case 0x4:
-                            return new SevInst(machInst);
-                          case 0x5:
-                            return new SevlInst(machInst);
-                          default:
-                            return new Unknown64(machInst);
+                            switch (op2 & 0x1) {
+                              case 0x0:
+                                return new WarnUnimplemented(
+                                        "bti", machInst);
+                            }
+                            break;
                         }
+                        return new Unknown64(machInst);
                     } else if (crn == 0x3 && op1 == 0x3) {
                         switch (op2) {
                           case 0x2:
diff --git a/src/arch/arm/isa/formats/branch.isa b/src/arch/arm/isa/formats/branch.isa
index df85b08..5f72113 100644
--- a/src/arch/arm/isa/formats/branch.isa
+++ b/src/arch/arm/isa/formats/branch.isa
@@ -1,6 +1,6 @@
 // -*- mode:c++ -*-
 
-// Copyright (c) 2010,2012-2013,2017 ARM Limited
+// Copyright (c) 2010,2012-2013,2017-2018 ARM Limited
 // All rights reserved
 //
 // The license below extends only to copyright in the software and shall
@@ -165,31 +165,51 @@
                   case 0x3a:
                     {
                         const uint32_t op1 = bits(machInst, 10, 8);
-                        const uint32_t op2 = bits(machInst, 7, 0);
+                        const uint32_t hint = bits(machInst, 7, 4);
+                        const uint32_t option = bits(machInst, 3, 0);
                         if (op1 != 0) {
                             const bool enable = bits(machInst, 10, 9) == 0x2;
                             const uint32_t mods = bits(machInst, 8, 0) |
                                                   ((enable ? 1 : 0) << 9);
                             return new Cps(machInst, mods);
-                        } else if ((op2 & 0xf0) == 0xf0) {
+                        } else if (hint == 0xf) {
                             return new Dbg(machInst);
                         } else {
-                            switch (op2) {
+                            switch (hint) {
                               case 0x0:
-                                return new NopInst(machInst);
+                                switch (option) {
+                                  case 0x0:
+                                    return new NopInst(machInst);
+                                  case 0x1:
+                                    return new YieldInst(machInst);
+                                  case 0x2:
+                                    return new WfeInst(machInst);
+                                  case 0x3:
+                                    return new WfiInst(machInst);
+                                  case 0x4:
+                                    return new SevInst(machInst);
+                                  case 0x5:
+                                    return new WarnUnimplemented(
+                                            "sevl", machInst);
+                                }
+                                break;
                               case 0x1:
-                                return new YieldInst(machInst);
-                              case 0x2:
-                                return new WfeInst(machInst);
-                              case 0x3:
-                                return new WfiInst(machInst);
-                              case 0x4:
-                                return new SevInst(machInst);
-                              default:
+                                switch (option) {
+                                  case 0x0:
+                                    return new WarnUnimplemented(
+                                            "esb", machInst);
+                                  case 0x2:
+                                    return new WarnUnimplemented(
+                                            "tsb csync", machInst);
+                                  case 0x4:
+                                    return new WarnUnimplemented(
+                                            "csdb", machInst);
+                                }
                                 break;
                             }
                         }
-                        break;
+                        return new WarnUnimplemented(
+                                "unallocated_hint", machInst);
                     }
                   case 0x3b:
                     {
diff --git a/src/arch/arm/isa/formats/data.isa b/src/arch/arm/isa/formats/data.isa
index b5e29c5..cff3d22 100644
--- a/src/arch/arm/isa/formats/data.isa
+++ b/src/arch/arm/isa/formats/data.isa
@@ -1114,19 +1114,36 @@
                     false);
           case 0x9:
             if (RN == 0) {
-                switch (IMM) {
-                  case 0x0:
-                    return new NopInst(machInst);
-                  case 0x1:
-                    return new YieldInst(machInst);
-                  case 0x2:
-                    return new WfeInst(machInst);
-                  case 0x3:
-                    return new WfiInst(machInst);
-                  case 0x4:
-                    return new SevInst(machInst);
-                  default:
-                    return new Unknown(machInst);
+                if ((IMM & 0xf0) == 0xf0) {
+                    return new Dbg(machInst);
+                } else {
+                    switch (IMM) {
+                      case 0x0:
+                        return new NopInst(machInst);
+                      case 0x1:
+                        return new YieldInst(machInst);
+                      case 0x2:
+                        return new WfeInst(machInst);
+                      case 0x3:
+                        return new WfiInst(machInst);
+                      case 0x4:
+                        return new SevInst(machInst);
+                      case 0x5:
+                        return new WarnUnimplemented(
+                                "sevl", machInst);
+                      case 0x10:
+                        return new WarnUnimplemented(
+                                "esb", machInst);
+                      case 0x12:
+                        return new WarnUnimplemented(
+                                "tsb csync", machInst);
+                      case 0x14:
+                        return new WarnUnimplemented(
+                                "csdb", machInst);
+                      default:
+                        return new WarnUnimplemented(
+                                "unallocated_hint", machInst);
+                    }
                 }
             } else {
                 return new MsrCpsrImm(machInst, imm, byteMask);