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  }