diff options
Diffstat (limited to 'arch/x86/lib/cmd_mtrr.c')
| -rw-r--r-- | arch/x86/lib/cmd_mtrr.c | 138 | 
1 files changed, 138 insertions, 0 deletions
| diff --git a/arch/x86/lib/cmd_mtrr.c b/arch/x86/lib/cmd_mtrr.c new file mode 100644 index 00000000000..7e0506b75d2 --- /dev/null +++ b/arch/x86/lib/cmd_mtrr.c @@ -0,0 +1,138 @@ +/* + * (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, mask, 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" +); | 
