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