github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/tools/arm64/registers.go (about) 1 // Copyright 2024 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 // Generate KVM ARM64 register IDs for dev_kvm.txt 5 // Usage: 6 // 7 // go run registers.go msr_mrs.txt 8 package main 9 10 import ( 11 "bytes" 12 "fmt" 13 "os" 14 "regexp" 15 "strconv" 16 "strings" 17 18 "github.com/google/syzkaller/pkg/tool" 19 ) 20 21 func main() { 22 if len(os.Args) != 2 { 23 tool.Failf("usage: gen msr_mrs.txt") 24 } 25 input, err := os.ReadFile(os.Args[1]) 26 if err != nil { 27 tool.Failf("failed to open input file: %v", err) 28 } 29 30 fmt.Printf("# Register descriptions generated by tools/arm64/registers.go\n") 31 printSysRegIDs(input) 32 printCoreRegs() 33 fmt.Printf("# End of register descriptions generated by tools/arm64/registers.go\n") 34 } 35 36 // Process input lines and return a string containing the list of corresponding register IDs. 37 func printSysRegIDs(table []byte) { 38 ret := "" 39 for _, line := range bytes.Split(table, []byte("\n")) { 40 if bytes.HasPrefix(line, []byte("#")) { 41 continue 42 } 43 44 lineStr := strings.TrimSpace(string(line)) 45 if lineStr == "" { 46 continue 47 } 48 expandedLines := expandLine(lineStr) 49 for _, eline := range expandedLines { 50 value, err := processLine(eline) 51 if err == nil { 52 if ret != "" { 53 ret += ", " 54 } 55 ret += fmt.Sprintf("0x%x", value) 56 } else { 57 fmt.Fprintf(os.Stdout, "%v\n", err) 58 } 59 } 60 } 61 fmt.Printf("kvm_regs_arm64_sys = %s\n", ret) 62 } 63 64 // Process a single line of the following form: 65 // 66 // `0b10 0b000 0b0000 0b0010 0b000 MDCCINT_EL1 ...` 67 // 68 // or 69 // 70 // `0b00 0b000 0b0100 - 0b101 SPSel ...` 71 // 72 // - extract five operands from it (treat "-" as a zero) and generate a register ID from them. 73 func processLine(line string) (int64, error) { 74 fields := strings.Fields(line) 75 76 if len(fields) < 6 { 77 return 0, fmt.Errorf("line has too few fields: %s", line) 78 } 79 80 var operands []int 81 for i := 0; i < 5; i++ { 82 if fields[i] != "-" { 83 val, err := strconv.ParseInt(strings.TrimPrefix(fields[i], "0b"), 2, 64) 84 if err != nil { 85 return 0, fmt.Errorf("conversion error: %w", err) 86 } 87 operands = append(operands, int(val)) 88 } else { 89 operands = append(operands, 0) 90 } 91 } 92 id := arm64KVMRegID(operands) 93 94 return id, nil 95 } 96 97 // If a line contains bit wildcards, replace them with all possible bit permutations. 98 // 99 // E.g. the following line: 100 // 101 // `0b11 0b100 0b1100 0b1000 0b0:n[1:0] ICH_AP0R<n>_EL2 ...` 102 // 103 // will be expanded to: 104 // 105 // `0b11 0b100 0b1100 0b1000 0b000 ICH_AP0R<n>_EL2 ...` 106 // `0b11 0b100 0b1100 0b1000 0b001 ICH_AP0R<n>_EL2 ...` 107 // `0b11 0b100 0b1100 0b1000 0b010 ICH_AP0R<n>_EL2 ...` 108 // `0b11 0b100 0b1100 0b1000 0b011 ICH_AP0R<n>_EL2 ...` 109 func expandLine(line string) []string { 110 re := regexp.MustCompile(`(:)?n\[(\d+)(:(\d+))?\]`) 111 match := re.FindStringSubmatch(line) 112 if match == nil { 113 return []string{line} 114 } 115 116 prefix := "0b" 117 // If n[] is preceded by ":", there is a 0b prefix in front of it already. 118 if match[1] == ":" { 119 prefix = "" 120 } 121 start, _ := strconv.Atoi(match[2]) 122 end := start 123 if match[3] != "" { 124 end, _ = strconv.Atoi(match[4]) 125 } 126 m := start - end + 1 127 numPermutations := 1 << m 128 129 expandedLines := make([]string, 0, numPermutations) 130 for i := 0; i < numPermutations; i++ { 131 bits := fmt.Sprintf("%s%0*b", prefix, m, i) 132 newLine := strings.Replace(line, match[0], bits, 1) 133 if strings.Contains(newLine, "n[") { 134 secondary := expandLine(newLine) 135 expandedLines = append(expandedLines, secondary...) 136 } else { 137 expandedLines = append(expandedLines, newLine) 138 } 139 } 140 141 return expandedLines 142 } 143 144 const ( 145 // Constants from https://elixir.bootlin.com/linux/v6.10.2/source/arch/arm64/include/uapi/asm/kvm.h 146 kvmRegArmCoprocShift = 16 147 kvmRegArm64Sysreg int64 = (0x0013 << kvmRegArmCoprocShift) 148 kvmRegSizeU64 int64 = 0x0030000000000000 149 kvmRegArm64 int64 = 0x6000000000000000 150 ) 151 152 // Generate register ID from Op0, Op1, CRn, CRm, Op2. 153 // See https://elixir.bootlin.com/linux/v6.10.2/source/arch/arm64/include/uapi/asm/kvm.h#L257 for more details. 154 func arm64KVMRegID(operands []int) int64 { 155 shifts := [5]int64{14, 11, 7, 3, 0} 156 ret := kvmRegSizeU64 | kvmRegArm64 | kvmRegArm64Sysreg 157 for i := 0; i < 5; i++ { 158 ret |= (int64(operands[i]) << shifts[i]) 159 } 160 return ret 161 } 162 163 // Generate core register IDs. 164 // See https://docs.kernel.org/virt/kvm/api.html for more details. 165 func printCoreRegs() { 166 fmt.Printf("# Extra registers that KVM_GET_REG_LIST prints on QEMU\n") 167 // Some of these register IDs do not have corresponding registers, yet the kernel returns them. 168 // TODO(glider): figure out why this is happening. 169 fmt.Printf("kvm_regs_arm64_extra = 0x603000000013c01b, 0x603000000013c01f, 0x603000000013c022, 0x603000000013c023, " + 170 "0x603000000013c025, 0x603000000013c026, 0x603000000013c027, 0x603000000013c02a, 0x603000000013c02b, " + 171 "0x603000000013c02e, 0x603000000013c02f, 0x603000000013c033, 0x603000000013c034, 0x603000000013c035, " + 172 "0x603000000013c036, 0x603000000013c037, 0x603000000013c03b, 0x603000000013c03c, 0x603000000013c03d, " + 173 "0x603000000013c03e, 0x603000000013c03f, 0x603000000013c103, 0x603000000013c512, 0x603000000013c513\n") 174 }