github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/core/msr/msr_linux.go (about) 1 // Copyright 2010-2019 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build !plan9 6 // +build !plan9 7 8 // msr reads and writes msrs using a Forth interpreter on argv 9 // 10 // Synopsis: 11 // 12 // To see what is available: 13 // msr words 14 // 15 // Description: 16 // 17 // msr provides a set of Forth words that let you manage MSRs. 18 // You can add new ones of your own. 19 // For a start, it provides some pre-defined words for well-known MSRs 20 // 21 // push a [] of MSR names and the 0x3a register on the stack 22 // IA32_FEATURE_CONTROL -- equivalent to * msr 0x3a reg 23 // The next two commands use IA32_FEATURE_CONTROL: 24 // READ_IA32_FEATURE_CONTROL -- equivalent to IA32_FEATURE_CONTROL rd 25 // LOCK IA32_FEATURE_CONTROL -- equivalent to IA32_FEATURE_CONTROL rd IA32_FEATURE_CONTROL 1 u64 or wr 26 // e.g. 27 // 28 // ./msr IA32_FEATURE_CONTROL 29 // [[/dev/cpu/0/msr /dev/cpu/1/msr /dev/cpu/2/msr /dev/cpu/3/msr] 58] 30 // 31 // As a special convenience, we have two useful cases: 32 // r glob register -- read the MSR 'register' from cores matching 'glob' 33 // w glob register value -- write the value to 'register' on all cores matching 'glob' 34 // 35 // Examples: 36 // 37 // Show the IA32 feature MSR on all cores 38 // sudo fio READ_IA32_FEATURE_CONTROL 39 // [[5 5 5 5]] 40 // lock the registers 41 // sudo fio LOCK_IA32_FEATURE_CONTROL 42 // Just see it one core 0 and 1 43 // sudo ./fio '[01]' msr 0x3a reg rd 44 // [[5 5]] 45 package main 46 47 import ( 48 "flag" 49 "fmt" 50 "log" 51 "strconv" 52 53 "github.com/mvdan/u-root-coreutils/pkg/forth" 54 "github.com/mvdan/u-root-coreutils/pkg/msr" 55 ) 56 57 // let's just do MSRs for now 58 59 var ( 60 debug = flag.Bool("d", false, "debug messages") 61 words = []struct { 62 name string 63 w []forth.Cell 64 }{ 65 // Architectural MSR. All systems. 66 // Enables features like VMX. 67 {name: "MSR_IA32_FEATURE_CONTROL", w: []forth.Cell{"'*", "cpu", "0x3a", "reg"}}, 68 {name: "READ_MSR_IA32_FEATURE_CONTROL", w: []forth.Cell{"MSR_IA32_FEATURE_CONTROL", "rd"}}, 69 {name: "LOCK_MSR_IA32_FEATURE_CONTROL", w: []forth.Cell{"MSR_IA32_FEATURE_CONTROL", "READ_MSR_IA32_FEATURE_CONTROL", "1", "u64", "or", "wr"}}, 70 // Silvermont, Airmont, Nehalem... 71 // Controls Processor C States. 72 {name: "MSR_PKG_CST_CONFIG_CONTROL", w: []forth.Cell{"'*", "cpu", "0xe2", "reg"}}, 73 {name: "READ_MSR_PKG_CST_CONFIG_CONTROL", w: []forth.Cell{"MSR_PKG_CST_CONFIG_CONTROL", "rd"}}, 74 {name: "LOCK_MSR_PKG_CST_CONFIG_CONTROL", w: []forth.Cell{"MSR_PKG_CST_CONFIG_CONTROL", "READ_MSR_PKG_CST_CONFIG_CONTROL", uint64(1 << 15), "or", "wr"}}, 75 // Westmere onwards. 76 // Note that this turns on AES instructions, however 77 // 3 will turn off AES until reset. 78 {name: "MSR_FEATURE_CONFIG", w: []forth.Cell{"'*", "cpu", "0x13c", "reg"}}, 79 {name: "READ_MSR_FEATURE_CONFIG", w: []forth.Cell{"MSR_FEATURE_CONFIG", "rd"}}, 80 {name: "LOCK_MSR_FEATURE_CONFIG", w: []forth.Cell{"MSR_FEATURE_CONFIG", "READ_MSR_FEATURE_CONFIG", uint64(1 << 0), "or", "wr"}}, 81 // Goldmont, SandyBridge 82 // Controls DRAM power limits. See Intel SDM 83 {name: "MSR_DRAM_POWER_LIMIT", w: []forth.Cell{"'*", "cpu", "0x618", "reg"}}, 84 {name: "READ_MSR_DRAM_POWER_LIMIT", w: []forth.Cell{"MSR_DRAM_POWER_LIMIT", "rd"}}, 85 {name: "LOCK_MSR_DRAM_POWER_LIMIT", w: []forth.Cell{"MSR_DRAM_POWER_LIMIT", "READ_MSR_DRAM_POWER_LIMIT", uint64(1 << 31), "or", "wr"}}, 86 // IvyBridge Onwards. 87 // Not much information in the SDM, seems to control power limits 88 {name: "MSR_CONFIG_TDP_CONTROL", w: []forth.Cell{"'*", "cpu", "0xe2", "reg"}}, 89 {name: "READ_MSR_CONFIG_TDP_CONTROL", w: []forth.Cell{"MSR_CONFIG_TDP_CONTROL", "rd"}}, 90 {name: "LOCK_MSR_CONFIG_TDP_CONTROL", w: []forth.Cell{"MSR_CONFIG_TDP_CONTROL", "READ_MSR_CONFIG_TDP_CONTROL", uint64(1 << 31), "or", "wr"}}, 91 // Architectural MSR. All systems. 92 // This is the actual spelling of the MSR in the manual. 93 // Controls availability of silicon debug interfaces 94 {name: "IA32_DEBUG_INTERFACE", w: []forth.Cell{"'*", "cpu", "0xe2", "reg"}}, 95 {name: "READ_IA32_DEBUG_INTERFACE", w: []forth.Cell{"IA32_DEBUG_INTERFACE", "rd"}}, 96 {name: "LOCK_IA32_DEBUG_INTERFACE", w: []forth.Cell{"IA32_DEBUG_INTERFACE", "READ_IA32_DEBUG_INTERFACE", uint64(1 << 15), "or", "wr"}}, 97 // Locks all known msrs to lock 98 {name: "LOCK_KNOWN_MSRS", w: []forth.Cell{"LOCK_MSR_IA32_FEATURE_CONTROL", "LOCK_MSR_PKG_CST_CONFIG_CONTROL", "LOCK_MSR_FEATURE_CONFIG", "LOCK_MSR_DRAM_POWER_LIMIT", "LOCK_MSR_CONFIG_TDP_CONTROL", "LOCK_IA32_DEBUG_INTERFACE"}}, 99 } 100 ops = []struct { 101 name string 102 op forth.Op 103 }{ 104 {name: "cpu", op: cpus}, 105 {name: "reg", op: reg}, 106 {name: "u64", op: u64}, 107 {name: "rd", op: rd}, 108 {name: "wr", op: wr}, 109 {name: "swr", op: swr}, 110 {name: "and", op: and}, 111 {name: "or", op: or}, 112 } 113 ) 114 115 // The great panic discussion. 116 // Rob has given talks on using panic for parsers. 117 // I have talked to Russ about using panic for parsers. 118 // Short form: it's ok. In general, don't panic. 119 // But parsers are special: using panic 120 // in a parser makes the code tons cleaner. 121 122 // Note that if any type asserts fail the forth interpret loop catches 123 // it. It also catches stack underflow, all that stuff. 124 func cpus(f forth.Forth) { 125 forth.Debug("cpu") 126 g := f.Pop().(string) 127 c, errs := msr.GlobCPUs(g) 128 if errs != nil { 129 panic(fmt.Sprintf("%v", errs)) 130 } 131 forth.Debug("CPUs are %v", c) 132 f.Push(c) 133 } 134 135 func reg(f forth.Forth) { 136 n, err := strconv.ParseUint(f.Pop().(string), 0, 32) 137 if err != nil { 138 panic(fmt.Sprintf("%v", err)) 139 } 140 f.Push(msr.MSR(n)) 141 } 142 143 func u64(f forth.Forth) { 144 n, err := strconv.ParseUint(f.Pop().(string), 0, 64) 145 if err != nil { 146 panic(fmt.Sprintf("%v", err)) 147 } 148 f.Push(uint64(n)) 149 } 150 151 func rd(f forth.Forth) { 152 r := f.Pop().(msr.MSR) 153 c := f.Pop().(msr.CPUs) 154 forth.Debug("rd: cpus %v, msr %v", c, r) 155 data, errs := r.Read(c) 156 forth.Debug("data %v errs %v", data, errs) 157 if errs != nil { 158 panic(fmt.Sprintf("%v", errs)) 159 } 160 f.Push(data) 161 } 162 163 // the standard msr api takes one value for all msrs. 164 // That's arguably substandard. We're going to require 165 // a []uint64. It's naive to expect every core to have 166 // exactly the same msr values for each msr in our 167 // modern world. 168 // If you're determined to write a fixed value, the same 169 // for all, it's easy: 170 // fio "'"* msr 0x3a reg rd 0 val and your-value new-val val or wr 171 // Then you'll have a fixed value. 172 func wr(f forth.Forth) { 173 v := f.Pop().([]uint64) 174 r := f.Pop().(msr.MSR) 175 c := f.Pop().(msr.CPUs) 176 forth.Debug("wr: cpus %v, msr %v, values %v", c, r, v) 177 errs := r.Write(c, v...) 178 forth.Debug("errs %v", errs) 179 if errs != nil { 180 f.Push(errs) 181 } 182 } 183 184 // We had been counting on doing a rd, which would produce a nice 185 // []u64 at TOS which we could use in a write. Problem is, some MSRs 186 // can not be read. There are write-only MSRs. This really 187 // complicates the picture: we can't just read them, change them, and 188 // write them; we would not even know if reading is side-effect free. 189 // 190 // Write now accepts a single value 191 func swr(f forth.Forth) { 192 v := f.Pop().(uint64) 193 r := f.Pop().(msr.MSR) 194 c := f.Pop().(msr.CPUs) 195 196 forth.Debug("swr: cpus %v, msr %v, %v", c, r, v) 197 errs := r.Write(c, v) 198 forth.Debug("errs %v", errs) 199 if errs != nil { 200 f.Push(errs) 201 } 202 } 203 204 func and(f forth.Forth) { 205 v := f.Pop().(uint64) 206 m := f.Pop().([]uint64) 207 forth.Debug("and: %v(%T) %v(%T)", m, m, v, v) 208 for i := range m { 209 m[i] &= v 210 } 211 f.Push(m) 212 } 213 214 func or(f forth.Forth) { 215 v := f.Pop().(uint64) 216 m := f.Pop().([]uint64) 217 forth.Debug("or: %v(%T) %v(%T)", m, m, v, v) 218 for i := range m { 219 m[i] |= v 220 } 221 f.Push(m) 222 } 223 224 func main() { 225 flag.Parse() 226 if *debug { 227 forth.Debug = log.Printf 228 } 229 230 // TODO: probably can do this by just having two passes, and write 231 // in the first pass is a no op. Which will fail to catch the problem 232 // of read-only and write-only MSRs but there's only so much you can do. 233 // 234 // To avoid the command list from being partially executed when the 235 // args fail to parse, queue them up and run all at once at the end. 236 //queue := []func(){} etc. etc. 237 f := forth.New() 238 for _, o := range ops { 239 forth.Putop(o.name, o.op) 240 } 241 for _, w := range words { 242 forth.NewWord(f, w.name, w.w[0], w.w[1:]...) 243 } 244 a := flag.Args() 245 // If the first arg is r or w, we're going to assume they're not doing Forth. 246 // It is too confusing otherwise if they type a wrong r or w command and 247 // see the Forth stack and nothing else. 248 switch a[0] { 249 case "r": 250 if len(a) != 3 { 251 log.Fatal("Usage for r: r <msr-glob> <register>") 252 } 253 // Because the msr arg is a glob and may have things like * in it (* being the 254 // most common) gratuitiously add a Forth ' before it (i.e. quote it). 255 if err := forth.EvalString(f, fmt.Sprintf("'%s cpu %s reg rd", a[1], a[2])); err != nil { 256 log.Fatal(err) 257 } 258 case "w": 259 if len(a) != 4 { 260 log.Fatal("Usage for w: w <msr-glob> <register> <value>") 261 } 262 // Because the msr arg is a glob and may have things like * in it (* being the 263 // most common) gratuitiously add a Forth ' before it (i.e. quote it). 264 if err := forth.EvalString(f, fmt.Sprintf("'%s cpu %s reg %s u64 swr", a[1], a[2], a[3])); err != nil { 265 log.Fatal(err) 266 } 267 case "lock": 268 if len(a) != 4 { 269 log.Fatal("Usage for lock: lock <msr-glob> <register> <bit>") 270 } 271 if err := forth.EvalString(f, fmt.Sprintf("'%s cpu %s reg '%s msr %s reg rd %s u64 or wr", a[1], a[2], a[1], a[2], a[3])); err != nil { 272 log.Fatal(err) 273 } 274 default: 275 for _, a := range flag.Args() { 276 if err := forth.EvalString(f, a); err != nil { 277 log.Fatal(err) 278 } 279 forth.Debug("%vOK\n", f.Stack()) 280 } 281 } 282 // special case: if the length of stack is 1, just print out stack[0]. 283 s := f.Stack() 284 if len(s) == 1 { 285 fmt.Printf("%v\n", s[0]) 286 } else { 287 fmt.Printf("%v\n", s) 288 } 289 }