diff options
Diffstat (limited to 'cmd/x86/mtrr.c')
-rw-r--r-- | cmd/x86/mtrr.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/cmd/x86/mtrr.c b/cmd/x86/mtrr.c new file mode 100644 index 00000000000..f632f495ede --- /dev/null +++ b/cmd/x86/mtrr.c @@ -0,0 +1,139 @@ +/* + * (C) Copyright 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/msr.h> +#include <asm/mtrr.h> + +static const char *const mtrr_type_name[MTRR_TYPE_COUNT] = { + "Uncacheable", + "Combine", + "2", + "3", + "Through", + "Protect", + "Back", +}; + +static int do_mtrr_list(void) +{ + int i; + + printf("Reg Valid Write-type %-16s %-16s %-16s\n", "Base ||", + "Mask ||", "Size ||"); + for (i = 0; i < MTRR_COUNT; i++) { + const char *type = "Invalid"; + uint64_t base, mask, size; + bool valid; + + base = native_read_msr(MTRR_PHYS_BASE_MSR(i)); + mask = native_read_msr(MTRR_PHYS_MASK_MSR(i)); + size = ~mask & ((1ULL << CONFIG_CPU_ADDR_BITS) - 1); + size |= (1 << 12) - 1; + size += 1; + valid = mask & MTRR_PHYS_MASK_VALID; + type = mtrr_type_name[base & MTRR_BASE_TYPE_MASK]; + printf("%d %-5s %-12s %016llx %016llx %016llx\n", i, + valid ? "Y" : "N", type, base & ~MTRR_BASE_TYPE_MASK, + mask & ~MTRR_PHYS_MASK_VALID, size); + } + + return 0; +} + +static int do_mtrr_set(uint reg, int argc, char * const argv[]) +{ + const char *typename = argv[0]; + struct mtrr_state state; + uint32_t start, size; + uint64_t base, mask; + int i, type = -1; + bool valid; + + if (argc < 3) + return CMD_RET_USAGE; + for (i = 0; i < MTRR_TYPE_COUNT; i++) { + if (*typename == *mtrr_type_name[i]) + type = i; + } + if (type == -1) { + printf("Invalid type name %s\n", typename); + return CMD_RET_USAGE; + } + start = simple_strtoul(argv[1], NULL, 16); + size = simple_strtoul(argv[2], NULL, 16); + + base = start | type; + valid = native_read_msr(MTRR_PHYS_MASK_MSR(reg)) & MTRR_PHYS_MASK_VALID; + mask = ~((uint64_t)size - 1); + mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1; + if (valid) + mask |= MTRR_PHYS_MASK_VALID; + + printf("base=%llx, mask=%llx\n", base, mask); + mtrr_open(&state); + wrmsrl(MTRR_PHYS_BASE_MSR(reg), base); + wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask); + mtrr_close(&state); + + return 0; +} + +static int mtrr_set_valid(int reg, bool valid) +{ + struct mtrr_state state; + uint64_t mask; + + mtrr_open(&state); + mask = native_read_msr(MTRR_PHYS_MASK_MSR(reg)); + if (valid) + mask |= MTRR_PHYS_MASK_VALID; + else + mask &= ~MTRR_PHYS_MASK_VALID; + wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask); + mtrr_close(&state); + + return 0; +} + +static int do_mtrr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + const char *cmd; + uint reg; + + cmd = argv[1]; + if (argc < 2 || *cmd == 'l') + return do_mtrr_list(); + argc -= 2; + argv += 2; + if (argc <= 0) + return CMD_RET_USAGE; + reg = simple_strtoul(argv[0], NULL, 16); + if (reg >= MTRR_COUNT) { + printf("Invalid register number\n"); + return CMD_RET_USAGE; + } + if (*cmd == 'e') + return mtrr_set_valid(reg, true); + else if (*cmd == 'd') + return mtrr_set_valid(reg, false); + else if (*cmd == 's') + return do_mtrr_set(reg, argc - 1, argv + 1); + else + return CMD_RET_USAGE; + + return 0; +} + +U_BOOT_CMD( + mtrr, 6, 1, do_mtrr, + "Use x86 memory type range registers (32-bit only)", + "[list] - list current registers\n" + "set <reg> <type> <start> <size> - set a register\n" + "\t<type> is Uncacheable, Combine, Through, Protect, Back\n" + "disable <reg> - disable a register\n" + "ensable <reg> - enable a register" +); |