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  }