[U-Boot] [PATCH 0/15] x86: Add cache and memory functions

This series adds some basic support for >4GB memory (including clearing it for security reasons), basic dcache control and coreboot time stamps.
Duncan Laurie (2): x86: Ignore memory >4GB when parsing Coreboot tables x86: Fix off-by-one error in do_elf_reloc_fixups()
Gabe Black (4): x86: Fill in the dram info using the e820 map on coreboot/x86 x86: Increase the size of the phys_size_t and phys_addr_t types Introduce arch_phys_memset which works like memset but on physical memory x86: Implement arch_phys_memset so that it can wipe memory above 4GB
Simon Glass (2): x86: Fix indirect jmp warning in zimage.c x86: Enable CONFIG_CMD_ZBOOT for coreboot
Stefan Reinauer (4): x86: Add basic cache operations x86: Provide a function to clean up just before booting a zimage x86: Add functions to access MSRs x86: Clean up MTRR 7 right before jumping to the kernel
Vadim Bendebury (3): x86: Add function to read time stamp counter x86: Enable coreboot timestamp facility support in u-boot. x86: Add a CBMEM timestamp generated right before the kernel startup.
arch/x86/cpu/coreboot/Makefile | 1 + arch/x86/cpu/coreboot/coreboot.c | 22 +++ arch/x86/cpu/coreboot/sdram.c | 19 ++ arch/x86/cpu/coreboot/timestamp.c | 61 +++++++ arch/x86/cpu/interrupts.c | 8 +- arch/x86/include/asm/arch-coreboot/timestamp.h | 52 ++++++ arch/x86/include/asm/cache.h | 47 +++++ arch/x86/include/asm/io.h | 6 +- arch/x86/include/asm/msr.h | 25 +++ arch/x86/include/asm/types.h | 4 +- arch/x86/include/asm/u-boot-x86.h | 12 ++ arch/x86/lib/Makefile | 1 + arch/x86/lib/physmem.c | 228 ++++++++++++++++++++++++ arch/x86/lib/relocate.c | 2 +- arch/x86/lib/timer.c | 17 ++ arch/x86/lib/zimage.c | 24 ++- include/configs/coreboot.h | 2 + include/physmem.h | 21 +++ lib/physmem.c | 24 +++ 19 files changed, 560 insertions(+), 16 deletions(-) create mode 100644 arch/x86/cpu/coreboot/timestamp.c create mode 100644 arch/x86/include/asm/arch-coreboot/timestamp.h create mode 100644 arch/x86/include/asm/msr.h create mode 100644 arch/x86/lib/physmem.c create mode 100644 include/physmem.h create mode 100644 lib/physmem.c

From: Vadim Bendebury vbendeb@chromium.org
Put this function in the u-boot-x86.h header file. We could instead create timer.h perhaps.
We support setting a base time, and reading the time relative to this base.
Signed-off-by: Vadim Bendebury vbendeb@chromium.org Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/include/asm/u-boot-x86.h | 12 ++++++++++++ arch/x86/lib/timer.c | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index a4a5ae0..11be5c3 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -68,4 +68,16 @@ int video_init(void); void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); void board_init_f_r(void) __attribute__ ((noreturn));
+/* Read the time stamp counter */ +static inline uint64_t rdtsc(void) +{ + uint32_t high, low; + __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)); + return (((uint64_t)high) << 32) | low; +} + +/* board/... */ +void timer_set_tsc_base(uint64_t new_base); +uint64_t timer_get_tsc(void); + #endif /* _U_BOOT_I386_H_ */ diff --git a/arch/x86/lib/timer.c b/arch/x86/lib/timer.c index fd7032e..a13424b 100644 --- a/arch/x86/lib/timer.c +++ b/arch/x86/lib/timer.c @@ -37,6 +37,7 @@ struct timer_isr_function {
static struct timer_isr_function *first_timer_isr; static unsigned long system_ticks; +static uint64_t base_value;
/* * register_timer_isr() allows multiple architecture and board specific @@ -98,3 +99,19 @@ ulong get_timer(ulong base) { return system_ticks - base; } + +void timer_set_tsc_base(uint64_t new_base) +{ + base_value = new_base; +} + +uint64_t timer_get_tsc(void) +{ + uint64_t time_now; + + time_now = rdtsc(); + if (!base_value) + base_value = time_now; + + return time_now - base_value; +}

Hi Simon,
On Wed, Oct 24, 2012 at 3:04 PM, Simon Glass sjg@chromium.org wrote:
From: Vadim Bendebury vbendeb@chromium.org
Put this function in the u-boot-x86.h header file. We could instead create timer.h perhaps.
We support setting a base time, and reading the time relative to this base.
Signed-off-by: Vadim Bendebury vbendeb@chromium.org Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/u-boot-x86.h | 12 ++++++++++++ arch/x86/lib/timer.c | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index a4a5ae0..11be5c3 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -68,4 +68,16 @@ int video_init(void); void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); void board_init_f_r(void) __attribute__ ((noreturn));
+/* Read the time stamp counter */ +static inline uint64_t rdtsc(void) +{
uint32_t high, low;
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
return (((uint64_t)high) << 32) | low;
+}
What CPUs support the rdtsc opcode? I know the AMD SC520 does not (it's a 486 core). Wikipedia tells me the Pentium CPU was the first to implement it. The Pentium was released in March 1993, so rdtsc is nearly 20 years now. But not all non-Intel CPUs are guaranteed to support it. Oh, and for CPUs that change speed, the internal clock read by rdtsc may not be constant.
I'm happy to draw a line in the sand and say 'x86 CPUs before xx/xx/xxx are not supported' - If someone comes along later wanting to add support, we can mess with the plumbing then (the likelyhood is practically zero, so I'm not too concerned about how hard that will be). Given that, perhaps we should look at HPET instead? I have a patch I worked on 6 month ago (attached below) if you feel like using it
+/* board/... */ +void timer_set_tsc_base(uint64_t new_base); +uint64_t timer_get_tsc(void);
#endif /* _U_BOOT_I386_H_ */ diff --git a/arch/x86/lib/timer.c b/arch/x86/lib/timer.c index fd7032e..a13424b 100644 --- a/arch/x86/lib/timer.c +++ b/arch/x86/lib/timer.c @@ -37,6 +37,7 @@ struct timer_isr_function {
static struct timer_isr_function *first_timer_isr; static unsigned long system_ticks; +static uint64_t base_value;
/*
- register_timer_isr() allows multiple architecture and board specific
@@ -98,3 +99,19 @@ ulong get_timer(ulong base) { return system_ticks - base; }
+void timer_set_tsc_base(uint64_t new_base) +{
base_value = new_base;
+}
+uint64_t timer_get_tsc(void) +{
uint64_t time_now;
time_now = rdtsc();
if (!base_value)
base_value = time_now;
return time_now - base_value;
+}
1.7.7.3
Here is the HPET driver patch:
--- Makefile | 1 + drivers/timer/Makefile | 46 ++++++++++++++++++++++ drivers/timer/hpet.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ include/hpet.h | 69 ++++++++++++++++++++++++++++++++ 4 files changed, 217 insertions(+), 0 deletions(-) create mode 100644 drivers/timer/Makefile create mode 100644 drivers/timer/hpet.c create mode 100644 include/hpet.h
diff --git a/Makefile b/Makefile index 4ddf8d6..c7b5245 100644 --- a/Makefile +++ b/Makefile @@ -285,6 +285,7 @@ LIBS += arch/powerpc/cpu/mpc8xxx/lib8xxx.o endif LIBS += drivers/rtc/librtc.o LIBS += drivers/serial/libserial.o +LIBS += drivers/timer/libtimer.o ifeq ($(CONFIG_GENERIC_LPC_TPM),y) LIBS += drivers/tpm/libtpm.o endif diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile new file mode 100644 index 0000000..a8b076a --- /dev/null +++ b/drivers/timer/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB := $(obj)libtimer.o + +COBJS-$(CONFIG_HPET_TIMER) += hpet.o + +COBJS := $(COBJS-y) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +all: $(LIB) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/timer/hpet.c b/drivers/timer/hpet.c new file mode 100644 index 0000000..b25f509 --- /dev/null +++ b/drivers/timer/hpet.c @@ -0,0 +1,101 @@ +/* + * (C) Copyright 2011 + * Graeme Russ, graeme.russ@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* High Precision Event Timers (HPET) */ + +#include <common.h> +#include <asm/io.h> +#include <hpet.h> +#include <div64.h> + +static struct hpet_regs *hpet_registers = (struct hpet_regs *)HPET_BASE_ADDR; + +int hpet_enable(void) +{ + u8 hpet8_val; + + hpet8_val = readb(&hpet_registers->general_config); + hpet8_val |= HPET_ENABLE; + writeb(hpet8_val, &hpet_registers->general_config); + + return 0; +} + +void hpet_udelay(unsigned long usec) +{ + u32 count_low; + u32 count_high; + u32 fs_per_tick; + u64 fs_to_wait = (u64)usec * 1000000000; + u64 ticks_to_wait; + u64 end_count; + + u32 end_count_low; + u32 end_count_high; + + count_low = readl(&hpet_registers->main_count_low); + count_high = readl(&hpet_registers->main_count_high); + fs_per_tick = readl(&hpet_registers->counter_clk_period); + + ticks_to_wait = lldiv(fs_to_wait, fs_per_tick); + + end_count = ((u64)count_high << 32) | ((u64)count_low); + end_count += ticks_to_wait; + + end_count_low = (u32)(end_count & 0x00000000ffffffffULL); + end_count_high = (u32)((end_count >> 32) & 0x00000000ffffffffULL); + + while (1) { + count_low = readl(&hpet_registers->main_count_low); + count_high = readl(&hpet_registers->main_count_high); + + if ((count_high > end_count_high) || + ((count_high == end_count_high) && + (count_low > end_count_low))) + break; + } +} + +ulong hpet_get_timer(ulong base) +{ + u32 count_low; + u32 count_high; + u32 fs_per_tick; + u64 ticks; + u64 fs; + u32 ms; + + count_low = readl(&hpet_registers->main_count_low); + count_high = readl(&hpet_registers->main_count_high); + fs_per_tick = readl(&hpet_registers->counter_clk_period); + + ticks = ((u64)count_high << 32) | ((u64)count_low); + + fs = fs_per_tick * ticks; + + /* Allow a 64/32 bit division by dividing by 4096 */ + ms = (u32)(lldiv(fs, 244140625) >> 12); + + return ms - base; +} + diff --git a/include/hpet.h b/include/hpet.h new file mode 100644 index 0000000..18769d0 --- /dev/null +++ b/include/hpet.h @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2011 + * Graeme Russ, graeme.russ@gmail.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* High Precision Event Timers (HPET) */ + +#ifndef __HPET_H__ +#define __HPET_H__ +#include <common.h> + +struct hpet_timer_regs { + u8 timer0_caps; + u8 timer0_cnf; + u16 timer0_reserved; + u32 timer0_int_route_cap; + u32 comparator_value; + u32 reserved_comparator_value; + u32 fsb_int_val; + u32 fsb_int_addr; + u8 reserved018[8]; +}; + +struct hpet_regs { + u8 rev_id; + u8 general_caps; + u16 vendor_id; + u32 counter_clk_period; + u8 reserved008[8]; + u8 general_config; + u8 reserved_manufacturer[3]; + u8 reserved018[8]; + u8 general_interupt_status; + u8 reserved_gen_int_sts[7]; + u8 reserved028[200]; + u32 main_count_high; + u32 main_count_low; + u8 reserved0f8[8]; + struct hpet_timer_regs timer_regs[3]; + u8 reserved160[672]; +}; + +int hpet_dump_info(void); +int hpet_enable(void); +void hpet_udelay(unsigned long usec); +ulong hpet_get_timer(ulong base); + +#define HPET_BASE_ADDR 0xfed00000 +#define HPET_ENABLE 0x01 + +#endif

Hi Graeme,
On Tue, Oct 23, 2012 at 9:24 PM, Graeme Russ graeme.russ@gmail.com wrote:
Hi Simon,
On Wed, Oct 24, 2012 at 3:04 PM, Simon Glass sjg@chromium.org wrote:
From: Vadim Bendebury vbendeb@chromium.org
Put this function in the u-boot-x86.h header file. We could instead create timer.h perhaps.
We support setting a base time, and reading the time relative to this base.
Signed-off-by: Vadim Bendebury vbendeb@chromium.org Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/u-boot-x86.h | 12 ++++++++++++ arch/x86/lib/timer.c | 17 +++++++++++++++++ 2 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index a4a5ae0..11be5c3 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -68,4 +68,16 @@ int video_init(void); void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); void board_init_f_r(void) __attribute__ ((noreturn));
+/* Read the time stamp counter */ +static inline uint64_t rdtsc(void) +{
uint32_t high, low;
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
return (((uint64_t)high) << 32) | low;
+}
What CPUs support the rdtsc opcode? I know the AMD SC520 does not (it's a 486 core). Wikipedia tells me the Pentium CPU was the first to implement it. The Pentium was released in March 1993, so rdtsc is nearly 20 years now. But not all non-Intel CPUs are guaranteed to support it. Oh, and for CPUs that change speed, the internal clock read by rdtsc may not be constant.
I'm happy to draw a line in the sand and say 'x86 CPUs before xx/xx/xxx are not supported' - If someone comes along later wanting to add support, we can mess with the plumbing then (the likelyhood is practically zero, so I'm not too concerned about how hard that will be). Given that, perhaps we should look at HPET instead? I have a patch I worked on 6 month ago (attached below) if you feel like using it
OK - well it seems that HPET is *very* new in comparison. Even so, it seems to me that it should be safe to move to this since we are probably not that interested in old hardware, but perhaps we should do this in the next release to give us a chance to test, etc.?
Regards, Simon

From: Vadim Bendebury vbendeb@chromium.org
This change turns on the code which allows u-boot to add timestamps to the timestamp table created by coreboot.
Since u-boot does not use the tsc_t like structure to represent HW counter readings, this structure is being replaced by 64 bit integer.
The timestamp_init() function is now initializing the base timer value used by u-boot to calculate the HW counter increments.
Timestamp facility is initialized as soon as the timestamp table pointer is found in the coreboot table. The u-boot generated timer events' ID will start at 1000 to clearly separate u-boot events from coreboot events in the timer trace.
Signed-off-by: Vadim Bendebury vbendeb@chromium.org Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/cpu/coreboot/Makefile | 1 + arch/x86/cpu/coreboot/coreboot.c | 4 ++ arch/x86/cpu/coreboot/timestamp.c | 61 ++++++++++++++++++++++++ arch/x86/include/asm/arch-coreboot/timestamp.h | 51 ++++++++++++++++++++ 4 files changed, 117 insertions(+), 0 deletions(-) create mode 100644 arch/x86/cpu/coreboot/timestamp.c create mode 100644 arch/x86/include/asm/arch-coreboot/timestamp.h
diff --git a/arch/x86/cpu/coreboot/Makefile b/arch/x86/cpu/coreboot/Makefile index 2afd30c..4612a3e 100644 --- a/arch/x86/cpu/coreboot/Makefile +++ b/arch/x86/cpu/coreboot/Makefile @@ -37,6 +37,7 @@ COBJS-$(CONFIG_SYS_COREBOOT) += coreboot.o COBJS-$(CONFIG_SYS_COREBOOT) += tables.o COBJS-$(CONFIG_SYS_COREBOOT) += ipchecksum.o COBJS-$(CONFIG_SYS_COREBOOT) += sdram.o +COBJS-$(CONFIG_SYS_COREBOOT) += timestamp.o COBJS-$(CONFIG_PCI) += pci.o
SOBJS-$(CONFIG_SYS_COREBOOT) += coreboot_car.o diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c index 22a643c..b942a3e 100644 --- a/arch/x86/cpu/coreboot/coreboot.c +++ b/arch/x86/cpu/coreboot/coreboot.c @@ -28,6 +28,7 @@ #include <netdev.h> #include <asm/arch-coreboot/tables.h> #include <asm/arch-coreboot/sysinfo.h> +#include <asm/arch/timestamp.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -41,6 +42,9 @@ int cpu_init_f(void) int ret = get_coreboot_info(&lib_sysinfo); if (ret != 0) printf("Failed to parse coreboot tables.\n"); + + timestamp_init(); + return ret; }
diff --git a/arch/x86/cpu/coreboot/timestamp.c b/arch/x86/cpu/coreboot/timestamp.c new file mode 100644 index 0000000..2ca7a57 --- /dev/null +++ b/arch/x86/cpu/coreboot/timestamp.c @@ -0,0 +1,61 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#include <common.h> +#include <asm/arch/timestamp.h> +#include <asm/arch/sysinfo.h> +#include <linux/compiler.h> + +struct timestamp_entry { + uint32_t entry_id; + uint64_t entry_stamp; +} __packed; + +struct timestamp_table { + uint64_t base_time; + uint32_t max_entries; + uint32_t num_entries; + struct timestamp_entry entries[0]; /* Variable number of entries */ +} __packed; + +static struct timestamp_table *ts_table __attribute__((section(".data"))); + +void timestamp_init(void) +{ + ts_table = lib_sysinfo.tstamp_table; + timer_set_tsc_base(ts_table->base_time); + timestamp_add_now(TS_U_BOOT_INITTED); +} + +void timestamp_add(enum timestamp_id id, uint64_t ts_time) +{ + struct timestamp_entry *tse; + + if (!ts_table || (ts_table->num_entries == ts_table->max_entries)) + return; + + tse = &ts_table->entries[ts_table->num_entries++]; + tse->entry_id = id; + tse->entry_stamp = ts_time - ts_table->base_time; +} + +void timestamp_add_now(enum timestamp_id id) +{ + timestamp_add(id, rdtsc()); +} diff --git a/arch/x86/include/asm/arch-coreboot/timestamp.h b/arch/x86/include/asm/arch-coreboot/timestamp.h new file mode 100644 index 0000000..e48ad86 --- /dev/null +++ b/arch/x86/include/asm/arch-coreboot/timestamp.h @@ -0,0 +1,51 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA + */ + +#ifndef __COREBOOT_TIMESTAMP_H__ +#define __COREBOOT_TIMESTAMP_H__ + +enum timestamp_id { + /* coreboot specific timestamp IDs */ + TS_START_ROMSTAGE = 1, + TS_BEFORE_INITRAM = 2, + TS_AFTER_INITRAM = 3, + TS_END_ROMSTAGE = 4, + TS_START_COPYRAM = 8, + TS_END_COPYRAM = 9, + TS_START_RAMSTAGE = 10, + TS_DEVICE_ENUMERATE = 30, + TS_DEVICE_CONFIGURE = 40, + TS_DEVICE_ENABLE = 50, + TS_DEVICE_INITIALIZE = 60, + TS_DEVICE_DONE = 70, + TS_CBMEM_POST = 75, + TS_WRITE_TABLES = 80, + TS_LOAD_PAYLOAD = 90, + TS_ACPI_WAKE_JUMP = 98, + TS_SELFBOOT_JUMP = 99, + + /* U-Boot entry IDs start at 1000 */ + TS_U_BOOT_INITTED = 1000, /* This is where u-boot starts */ +}; + +void timestamp_init(void); +void timestamp_add(enum timestamp_id id, uint64_t ts_time); +void timestamp_add_now(enum timestamp_id id); + +#endif

From: Vadim Bendebury vbendeb@chromium.org
To maintain the initialization state of the timestamp facility, thesq pointer to the CBMEM section containing the timestamp table should be kept in the .data section (so that it is maintained across u-boot relocation).
Signed-off-by: Vadim Bendebury vbendeb@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/include/asm/arch-coreboot/timestamp.h | 1 + arch/x86/lib/zimage.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/arch/x86/include/asm/arch-coreboot/timestamp.h b/arch/x86/include/asm/arch-coreboot/timestamp.h index e48ad86..d104912 100644 --- a/arch/x86/include/asm/arch-coreboot/timestamp.h +++ b/arch/x86/include/asm/arch-coreboot/timestamp.h @@ -42,6 +42,7 @@ enum timestamp_id {
/* U-Boot entry IDs start at 1000 */ TS_U_BOOT_INITTED = 1000, /* This is where u-boot starts */ + TS_U_BOOT_START_KERNEL = 1100, /* Right before jumping to kernel. */ };
void timestamp_init(void); diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 2bbf5a8..1d6a0ed 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -36,6 +36,9 @@ #include <asm/realmode.h> #include <asm/byteorder.h> #include <asm/bootparam.h> +#ifdef CONFIG_SYS_COREBOOT_ +#include <asm/arch/timestamp.h> +#endif
/* * Memory lay-out: @@ -282,7 +285,9 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, void boot_zimage(void *setup_base, void *load_address) { printf("\nStarting kernel ...\n\n"); - +#ifdef CONFIG_SYS_COREBOOT_ + timestamp_add_now(TS_U_BOOT_START_KERNEL); +#endif #if !defined CONFIG_SYS_X86_REALMODE || defined CONFIG_ZBOOT_32 /* * Set %ebx, %ebp, and %edi to 0, %esi to point to the boot_params

From: Gabe Black gabeblack@chromium.org
This way when that dram "banks" are displayed, there's some useful information there. The number of "banks" we claim to have needs to be adjusted so that it covers the number of RAM e820 regions we expect to have/care about.
This needs to be done after "RAM" initialization even though we always run from RAM. The bd pointer in the global data structure doesn't automatically point to anything, and it isn't set up until "RAM" is available since, I assume, it would take too much space in the very constrained pre-RAM environment.
Signed-off-by: Gabe Black gabeblack@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/cpu/coreboot/sdram.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/arch/x86/cpu/coreboot/sdram.c b/arch/x86/cpu/coreboot/sdram.c index f8fdac6..93dccb8 100644 --- a/arch/x86/cpu/coreboot/sdram.c +++ b/arch/x86/cpu/coreboot/sdram.c @@ -71,5 +71,20 @@ int dram_init_f(void)
int dram_init(void) { + int i, j; + + if (CONFIG_NR_DRAM_BANKS) { + for (i = 0, j = 0; i < lib_sysinfo.n_memranges; i++) { + struct memrange *memrange = &lib_sysinfo.memrange[i]; + + if (memrange->type == CB_MEM_RAM) { + gd->bd->bi_dram[j].start = memrange->base; + gd->bd->bi_dram[j].size = memrange->size; + j++; + if (j >= CONFIG_NR_DRAM_BANKS) + break; + } + } + } return 0; }

From: Stefan Reinauer reinauer@chromium.org
Add functions to enable/disable the data cache.
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/cpu/interrupts.c | 8 +------ arch/x86/include/asm/cache.h | 47 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-)
diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index 43ec3f8..710b653 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -28,6 +28,7 @@ */
#include <common.h> +#include <asm/cache.h> #include <asm/interrupt.h> #include <asm/io.h> #include <asm/processor-flags.h> @@ -50,13 +51,6 @@ */ static unsigned long __force_order;
-static inline unsigned long read_cr0(void) -{ - unsigned long val; - asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order)); - return val; -} - static inline unsigned long read_cr2(void) { unsigned long val; diff --git a/arch/x86/include/asm/cache.h b/arch/x86/include/asm/cache.h index 87c9e0b..9836856 100644 --- a/arch/x86/include/asm/cache.h +++ b/arch/x86/include/asm/cache.h @@ -32,4 +32,51 @@ #define ARCH_DMA_MINALIGN 64 #endif
+/* The memory clobber prevents the GCC from reordering the read/write order + * of CR0 + */ +static inline unsigned long read_cr0(void) +{ + unsigned long cr0; + + asm volatile ("movl %%cr0, %0" : "=r" (cr0) : : "memory"); + return cr0; +} + +static inline void write_cr0(unsigned long cr0) +{ + asm volatile ("movl %0, %%cr0" : : "r" (cr0) : "memory"); +} + +static inline void wbinvd(void) +{ + asm volatile ("wbinvd" : : : "memory"); +} + +static inline void invd(void) +{ + asm volatile("invd" : : : "memory"); +} + +static inline void enable_cache(void) +{ + unsigned long cr0; + + cr0 = read_cr0(); + cr0 &= 0x9fffffff; + write_cr0(cr0); +} + +static inline void disable_cache(void) +{ + /* Disable and write back the cache */ + unsigned long cr0; + + cr0 = read_cr0(); + cr0 |= 0x40000000; + wbinvd(); + write_cr0(cr0); + wbinvd(); +} + #endif /* __X86_CACHE_H__ */

Hi Simon,
On Wed, Oct 24, 2012 at 3:04 PM, Simon Glass sjg@chromium.org wrote:
From: Stefan Reinauer reinauer@chromium.org
Add functions to enable/disable the data cache.
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/interrupts.c | 8 +------ arch/x86/include/asm/cache.h | 47 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-)
diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index 43ec3f8..710b653 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -28,6 +28,7 @@ */
#include <common.h> +#include <asm/cache.h> #include <asm/interrupt.h> #include <asm/io.h> #include <asm/processor-flags.h> @@ -50,13 +51,6 @@ */ static unsigned long __force_order;
-static inline unsigned long read_cr0(void) -{
unsigned long val;
asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order));
return val;
-}
Happy to move read_cr0 out of interrupts.c
static inline unsigned long read_cr2(void) { unsigned long val;
But please move them all...
diff --git a/arch/x86/include/asm/cache.h b/arch/x86/include/asm/cache.h index 87c9e0b..9836856 100644 --- a/arch/x86/include/asm/cache.h +++ b/arch/x86/include/asm/cache.h @@ -32,4 +32,51 @@ #define ARCH_DMA_MINALIGN 64 #endif
+/* The memory clobber prevents the GCC from reordering the read/write order
- of CR0
- */
+static inline unsigned long read_cr0(void) +{
unsigned long cr0;
asm volatile ("movl %%cr0, %0" : "=r" (cr0) : : "memory");
return cr0;
+}
+static inline void write_cr0(unsigned long cr0) +{
asm volatile ("movl %0, %%cr0" : : "r" (cr0) : "memory");
+}
...to another header (control_registers.h)
+static inline void wbinvd(void) +{
asm volatile ("wbinvd" : : : "memory");
+}
+static inline void invd(void) +{
asm volatile("invd" : : : "memory");
+}
+static inline void enable_cache(void) +{
unsigned long cr0;
cr0 = read_cr0();
cr0 &= 0x9fffffff;
write_cr0(cr0);
+}
+static inline void disable_cache(void) +{
/* Disable and write back the cache */
unsigned long cr0;
cr0 = read_cr0();
cr0 |= 0x40000000;
wbinvd();
write_cr0(cr0);
wbinvd();
+}
These already exist in cpu.c as weak functions (some systems need to do funky things when fiddling with caching, like updating MMTRs) with pure inline assembly. Please fix up those implementations to use the proper cr0 accessors
#endif /* __X86_CACHE_H__ */
1.7.7.3
Regards,
Graeme

Hi Graeme,
On Tue, Oct 23, 2012 at 9:44 PM, Graeme Russ graeme.russ@gmail.com wrote:
Hi Simon,
On Wed, Oct 24, 2012 at 3:04 PM, Simon Glass sjg@chromium.org wrote:
From: Stefan Reinauer reinauer@chromium.org
Add functions to enable/disable the data cache.
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/interrupts.c | 8 +------ arch/x86/include/asm/cache.h | 47 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 7 deletions(-)
diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index 43ec3f8..710b653 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -28,6 +28,7 @@ */
#include <common.h> +#include <asm/cache.h> #include <asm/interrupt.h> #include <asm/io.h> #include <asm/processor-flags.h> @@ -50,13 +51,6 @@ */ static unsigned long __force_order;
-static inline unsigned long read_cr0(void) -{
unsigned long val;
asm volatile("mov %%cr0,%0\n\t" : "=r" (val), "=m" (__force_order));
return val;
-}
Happy to move read_cr0 out of interrupts.c
static inline unsigned long read_cr2(void) { unsigned long val;
But please move them all...
diff --git a/arch/x86/include/asm/cache.h b/arch/x86/include/asm/cache.h index 87c9e0b..9836856 100644 --- a/arch/x86/include/asm/cache.h +++ b/arch/x86/include/asm/cache.h @@ -32,4 +32,51 @@ #define ARCH_DMA_MINALIGN 64 #endif
+/* The memory clobber prevents the GCC from reordering the read/write order
- of CR0
- */
+static inline unsigned long read_cr0(void) +{
unsigned long cr0;
asm volatile ("movl %%cr0, %0" : "=r" (cr0) : : "memory");
return cr0;
+}
+static inline void write_cr0(unsigned long cr0) +{
asm volatile ("movl %0, %%cr0" : : "r" (cr0) : "memory");
+}
...to another header (control_registers.h)
Will do, that makes sense. I will move the debug registers also.
+static inline void wbinvd(void) +{
asm volatile ("wbinvd" : : : "memory");
+}
+static inline void invd(void) +{
asm volatile("invd" : : : "memory");
+}
+static inline void enable_cache(void) +{
unsigned long cr0;
cr0 = read_cr0();
cr0 &= 0x9fffffff;
write_cr0(cr0);
+}
+static inline void disable_cache(void) +{
/* Disable and write back the cache */
unsigned long cr0;
cr0 = read_cr0();
cr0 |= 0x40000000;
wbinvd();
write_cr0(cr0);
wbinvd();
+}
These already exist in cpu.c as weak functions (some systems need to do funky things when fiddling with caching, like updating MMTRs) with pure inline assembly. Please fix up those implementations to use the proper cr0 accessors
OK, I will send a new patch for this.
#endif /* __X86_CACHE_H__ */
1.7.7.3
Regards,
Graeme
Regards, Simon

From: Stefan Reinauer reinauer@chromium.org
This function can be used by boards which want to do some clean-up before booting a zImage.
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/lib/zimage.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index 1d6a0ed..a1366a1 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -39,6 +39,7 @@ #ifdef CONFIG_SYS_COREBOOT_ #include <asm/arch/timestamp.h> #endif +#include <linux/compiler.h>
/* * Memory lay-out: @@ -282,8 +283,18 @@ int setup_zimage(struct boot_params *setup_base, char *cmd_line, int auto_boot, return 0; }
+/* + * Implement a weak default function for boards that optionally + * need to clean up the system before jumping to the kernel. + */ +__weak void board_final_cleanup(void) +{ +} + void boot_zimage(void *setup_base, void *load_address) { + board_final_cleanup(); + printf("\nStarting kernel ...\n\n"); #ifdef CONFIG_SYS_COREBOOT_ timestamp_add_now(TS_U_BOOT_START_KERNEL);

From: Stefan Reinauer reinauer@chromium.org
Provide basic functions to access these registers.
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/include/asm/msr.h | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) create mode 100644 arch/x86/include/asm/msr.h
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h new file mode 100644 index 0000000..0a681d1 --- /dev/null +++ b/arch/x86/include/asm/msr.h @@ -0,0 +1,25 @@ +#ifndef CPU_X86_ASM_MSR_H +#define CPU_X86_ASM_MSR_H + +static inline uint64_t rdmsr(unsigned index) +{ + uint64_t result; + + asm volatile ( + "rdmsr" + : "=A" (result) + : "c" (index) + ); + return result; +} + +static inline void wrmsr(unsigned index, uint64_t msr) +{ + asm volatile ( + "wrmsr" + : /* No outputs */ + : "c" (index), "A" (msr) + ); +} + +#endif /* CPU_X86_ASM_MSR_H */

Hi Simon,
On Wed, Oct 24, 2012 at 3:04 PM, Simon Glass sjg@chromium.org wrote:
From: Stefan Reinauer reinauer@chromium.org
Provide basic functions to access these registers.
I really should have got my funk into gear and posted patches I created (on a side project) a long time ago :(
Anyways - I implemented the same, but I just stole the code from the Linux kernel (3.1 to be exact) - I've attached my patch below (may not apply cleanly now)
Regards,
Graeme
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/msr.h | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) create mode 100644 arch/x86/include/asm/msr.h
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h new file mode 100644 index 0000000..0a681d1 --- /dev/null +++ b/arch/x86/include/asm/msr.h @@ -0,0 +1,25 @@ +#ifndef CPU_X86_ASM_MSR_H +#define CPU_X86_ASM_MSR_H
+static inline uint64_t rdmsr(unsigned index) +{
uint64_t result;
asm volatile (
"rdmsr"
: "=A" (result)
: "c" (index)
);
return result;
+}
+static inline void wrmsr(unsigned index, uint64_t msr) +{
asm volatile (
"wrmsr"
: /* No outputs */
: "c" (index), "A" (msr)
);
+}
+#endif /* CPU_X86_ASM_MSR_H */
1.7.7.3
Zee Patch ;)
x86: Import MSR/MTRR code from Linux
Imported from Linux 3.1 with a few modifications to suit U-Boot --- arch/x86/include/asm/msr-index.h | 447 ++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/msr.h | 216 ++++++++++++++++++ arch/x86/include/asm/mtrr.h | 203 +++++++++++++++++ 3 files changed, 866 insertions(+), 0 deletions(-) create mode 100644 arch/x86/include/asm/msr-index.h create mode 100644 arch/x86/include/asm/msr.h create mode 100644 arch/x86/include/asm/mtrr.h
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h new file mode 100644 index 0000000..2d4a20a --- /dev/null +++ b/arch/x86/include/asm/msr-index.h @@ -0,0 +1,447 @@ +#ifndef _ASM_X86_MSR_INDEX_H +#define _ASM_X86_MSR_INDEX_H + +/* CPU model specific register (MSR) numbers */ + +/* x86-64 specific MSRs */ +#define MSR_EFER 0xc0000080 /* extended feature register */ +#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */ +#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */ +#define MSR_CSTAR 0xc0000083 /* compat mode SYSCALL target */ +#define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */ +#define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ +#define MSR_GS_BASE 0xc0000101 /* 64bit GS base */ +#define MSR_KERNEL_GS_BASE 0xc0000102 /* SwapGS GS shadow */ +#define MSR_TSC_AUX 0xc0000103 /* Auxiliary TSC */ + +/* EFER bits: */ +#define _EFER_SCE 0 /* SYSCALL/SYSRET */ +#define _EFER_LME 8 /* Long mode enable */ +#define _EFER_LMA 10 /* Long mode active (read-only) */ +#define _EFER_NX 11 /* No execute enable */ +#define _EFER_SVME 12 /* Enable virtualization */ +#define _EFER_LMSLE 13 /* Long Mode Segment Limit Enable */ +#define _EFER_FFXSR 14 /* Enable Fast FXSAVE/FXRSTOR */ + +#define EFER_SCE (1<<_EFER_SCE) +#define EFER_LME (1<<_EFER_LME) +#define EFER_LMA (1<<_EFER_LMA) +#define EFER_NX (1<<_EFER_NX) +#define EFER_SVME (1<<_EFER_SVME) +#define EFER_LMSLE (1<<_EFER_LMSLE) +#define EFER_FFXSR (1<<_EFER_FFXSR) + +/* Intel MSRs. Some also available on other CPUs */ +#define MSR_IA32_PERFCTR0 0x000000c1 +#define MSR_IA32_PERFCTR1 0x000000c2 +#define MSR_FSB_FREQ 0x000000cd + +#define MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2 +#define NHM_C3_AUTO_DEMOTE (1UL << 25) +#define NHM_C1_AUTO_DEMOTE (1UL << 26) +#define ATM_LNC_C6_AUTO_DEMOTE (1UL << 25) + +#define MSR_MTRRcap 0x000000fe +#define MSR_IA32_BBL_CR_CTL 0x00000119 +#define MSR_IA32_BBL_CR_CTL3 0x0000011e + +#define MSR_IA32_SYSENTER_CS 0x00000174 +#define MSR_IA32_SYSENTER_ESP 0x00000175 +#define MSR_IA32_SYSENTER_EIP 0x00000176 + +#define MSR_IA32_MCG_CAP 0x00000179 +#define MSR_IA32_MCG_STATUS 0x0000017a +#define MSR_IA32_MCG_CTL 0x0000017b + +#define MSR_OFFCORE_RSP_0 0x000001a6 +#define MSR_OFFCORE_RSP_1 0x000001a7 + +#define MSR_IA32_PEBS_ENABLE 0x000003f1 +#define MSR_IA32_DS_AREA 0x00000600 +#define MSR_IA32_PERF_CAPABILITIES 0x00000345 + +#define MSR_MTRRfix64K_00000 0x00000250 +#define MSR_MTRRfix16K_80000 0x00000258 +#define MSR_MTRRfix16K_A0000 0x00000259 +#define MSR_MTRRfix4K_C0000 0x00000268 +#define MSR_MTRRfix4K_C8000 0x00000269 +#define MSR_MTRRfix4K_D0000 0x0000026a +#define MSR_MTRRfix4K_D8000 0x0000026b +#define MSR_MTRRfix4K_E0000 0x0000026c +#define MSR_MTRRfix4K_E8000 0x0000026d +#define MSR_MTRRfix4K_F0000 0x0000026e +#define MSR_MTRRfix4K_F8000 0x0000026f +#define MSR_MTRRdefType 0x000002ff + +#define MSR_IA32_CR_PAT 0x00000277 + +#define MSR_IA32_DEBUGCTLMSR 0x000001d9 +#define MSR_IA32_LASTBRANCHFROMIP 0x000001db +#define MSR_IA32_LASTBRANCHTOIP 0x000001dc +#define MSR_IA32_LASTINTFROMIP 0x000001dd +#define MSR_IA32_LASTINTTOIP 0x000001de + +/* DEBUGCTLMSR bits (others vary by model): */ +#define DEBUGCTLMSR_LBR (1UL << 0) +#define DEBUGCTLMSR_BTF (1UL << 1) +#define DEBUGCTLMSR_TR (1UL << 6) +#define DEBUGCTLMSR_BTS (1UL << 7) +#define DEBUGCTLMSR_BTINT (1UL << 8) +#define DEBUGCTLMSR_BTS_OFF_OS (1UL << 9) +#define DEBUGCTLMSR_BTS_OFF_USR (1UL << 10) +#define DEBUGCTLMSR_FREEZE_LBRS_ON_PMI (1UL << 11) + +#define MSR_IA32_MC0_CTL 0x00000400 +#define MSR_IA32_MC0_STATUS 0x00000401 +#define MSR_IA32_MC0_ADDR 0x00000402 +#define MSR_IA32_MC0_MISC 0x00000403 + +#define MSR_AMD64_MC0_MASK 0xc0010044 + +#define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x)) +#define MSR_IA32_MCx_STATUS(x) (MSR_IA32_MC0_STATUS + 4*(x)) +#define MSR_IA32_MCx_ADDR(x) (MSR_IA32_MC0_ADDR + 4*(x)) +#define MSR_IA32_MCx_MISC(x) (MSR_IA32_MC0_MISC + 4*(x)) + +#define MSR_AMD64_MCx_MASK(x) (MSR_AMD64_MC0_MASK + (x)) + +/* These are consecutive and not in the normal 4er MCE bank block */ +#define MSR_IA32_MC0_CTL2 0x00000280 +#define MSR_IA32_MCx_CTL2(x) (MSR_IA32_MC0_CTL2 + (x)) + +#define MSR_P6_PERFCTR0 0x000000c1 +#define MSR_P6_PERFCTR1 0x000000c2 +#define MSR_P6_EVNTSEL0 0x00000186 +#define MSR_P6_EVNTSEL1 0x00000187 + +/* AMD64 MSRs. Not complete. See the architecture manual for a more + complete list. */ + +#define MSR_AMD64_PATCH_LEVEL 0x0000008b +#define MSR_AMD64_NB_CFG 0xc001001f +#define MSR_AMD64_PATCH_LOADER 0xc0010020 +#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 +#define MSR_AMD64_OSVW_STATUS 0xc0010141 +#define MSR_AMD64_DC_CFG 0xc0011022 +#define MSR_AMD64_IBSFETCHCTL 0xc0011030 +#define MSR_AMD64_IBSFETCHLINAD 0xc0011031 +#define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 +#define MSR_AMD64_IBSOPCTL 0xc0011033 +#define MSR_AMD64_IBSOPRIP 0xc0011034 +#define MSR_AMD64_IBSOPDATA 0xc0011035 +#define MSR_AMD64_IBSOPDATA2 0xc0011036 +#define MSR_AMD64_IBSOPDATA3 0xc0011037 +#define MSR_AMD64_IBSDCLINAD 0xc0011038 +#define MSR_AMD64_IBSDCPHYSAD 0xc0011039 +#define MSR_AMD64_IBSCTL 0xc001103a +#define MSR_AMD64_IBSBRTARGET 0xc001103b + +/* Fam 15h MSRs */ +#define MSR_F15H_PERF_CTL 0xc0010200 +#define MSR_F15H_PERF_CTR 0xc0010201 + +/* Fam 10h MSRs */ +#define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058 +#define FAM10H_MMIO_CONF_ENABLE (1<<0) +#define FAM10H_MMIO_CONF_BUSRANGE_MASK 0xf +#define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2 +#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffffULL +#define FAM10H_MMIO_CONF_BASE_SHIFT 20 +#define MSR_FAM10H_NODE_ID 0xc001100c + +/* K8 MSRs */ +#define MSR_K8_TOP_MEM1 0xc001001a +#define MSR_K8_TOP_MEM2 0xc001001d +#define MSR_K8_SYSCFG 0xc0010010 +#define MSR_K8_INT_PENDING_MSG 0xc0010055 +/* C1E active bits in int pending message */ +#define K8_INTP_C1E_ACTIVE_MASK 0x18000000 +#define MSR_K8_TSEG_ADDR 0xc0010112 +#define K8_MTRRFIXRANGE_DRAM_ENABLE 0x00040000 /* MtrrFixDramEn bit */ +#define K8_MTRRFIXRANGE_DRAM_MODIFY 0x00080000 /* MtrrFixDramModEn bit */ +#define K8_MTRR_RDMEM_WRMEM_MASK 0x18181818 /* Mask: RdMem|WrMem */ + +/* K7 MSRs */ +#define MSR_K7_EVNTSEL0 0xc0010000 +#define MSR_K7_PERFCTR0 0xc0010004 +#define MSR_K7_EVNTSEL1 0xc0010001 +#define MSR_K7_PERFCTR1 0xc0010005 +#define MSR_K7_EVNTSEL2 0xc0010002 +#define MSR_K7_PERFCTR2 0xc0010006 +#define MSR_K7_EVNTSEL3 0xc0010003 +#define MSR_K7_PERFCTR3 0xc0010007 +#define MSR_K7_CLK_CTL 0xc001001b +#define MSR_K7_HWCR 0xc0010015 +#define MSR_K7_FID_VID_CTL 0xc0010041 +#define MSR_K7_FID_VID_STATUS 0xc0010042 + +/* K6 MSRs */ +#define MSR_K6_WHCR 0xc0000082 +#define MSR_K6_UWCCR 0xc0000085 +#define MSR_K6_EPMR 0xc0000086 +#define MSR_K6_PSOR 0xc0000087 +#define MSR_K6_PFIR 0xc0000088 + +/* Centaur-Hauls/IDT defined MSRs. */ +#define MSR_IDT_FCR1 0x00000107 +#define MSR_IDT_FCR2 0x00000108 +#define MSR_IDT_FCR3 0x00000109 +#define MSR_IDT_FCR4 0x0000010a + +#define MSR_IDT_MCR0 0x00000110 +#define MSR_IDT_MCR1 0x00000111 +#define MSR_IDT_MCR2 0x00000112 +#define MSR_IDT_MCR3 0x00000113 +#define MSR_IDT_MCR4 0x00000114 +#define MSR_IDT_MCR5 0x00000115 +#define MSR_IDT_MCR6 0x00000116 +#define MSR_IDT_MCR7 0x00000117 +#define MSR_IDT_MCR_CTRL 0x00000120 + +/* VIA Cyrix defined MSRs*/ +#define MSR_VIA_FCR 0x00001107 +#define MSR_VIA_LONGHAUL 0x0000110a +#define MSR_VIA_RNG 0x0000110b +#define MSR_VIA_BCR2 0x00001147 + +/* Transmeta defined MSRs */ +#define MSR_TMTA_LONGRUN_CTRL 0x80868010 +#define MSR_TMTA_LONGRUN_FLAGS 0x80868011 +#define MSR_TMTA_LRTI_READOUT 0x80868018 +#define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a + +/* Intel defined MSRs. */ +#define MSR_IA32_P5_MC_ADDR 0x00000000 +#define MSR_IA32_P5_MC_TYPE 0x00000001 +#define MSR_IA32_TSC 0x00000010 +#define MSR_IA32_PLATFORM_ID 0x00000017 +#define MSR_IA32_EBL_CR_POWERON 0x0000002a +#define MSR_EBC_FREQUENCY_ID 0x0000002c +#define MSR_IA32_FEATURE_CONTROL 0x0000003a + +#define FEATURE_CONTROL_LOCKED (1<<0) +#define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1) +#define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2) + +#define MSR_IA32_APICBASE 0x0000001b +#define MSR_IA32_APICBASE_BSP (1<<8) +#define MSR_IA32_APICBASE_ENABLE (1<<11) +#define MSR_IA32_APICBASE_BASE (0xfffff<<12) + +#define MSR_IA32_UCODE_WRITE 0x00000079 +#define MSR_IA32_UCODE_REV 0x0000008b + +#define MSR_IA32_PERF_STATUS 0x00000198 +#define MSR_IA32_PERF_CTL 0x00000199 + +#define MSR_IA32_MPERF 0x000000e7 +#define MSR_IA32_APERF 0x000000e8 + +#define MSR_IA32_THERM_CONTROL 0x0000019a +#define MSR_IA32_THERM_INTERRUPT 0x0000019b + +#define THERM_INT_HIGH_ENABLE (1 << 0) +#define THERM_INT_LOW_ENABLE (1 << 1) +#define THERM_INT_PLN_ENABLE (1 << 24) + +#define MSR_IA32_THERM_STATUS 0x0000019c + +#define THERM_STATUS_PROCHOT (1 << 0) +#define THERM_STATUS_POWER_LIMIT (1 << 10) + +#define MSR_THERM2_CTL 0x0000019d + +#define MSR_THERM2_CTL_TM_SELECT (1ULL << 16) + +#define MSR_IA32_MISC_ENABLE 0x000001a0 + +#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 + +#define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0 + +#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 + +#define PACKAGE_THERM_STATUS_PROCHOT (1 << 0) +#define PACKAGE_THERM_STATUS_POWER_LIMIT (1 << 10) + +#define MSR_IA32_PACKAGE_THERM_INTERRUPT 0x000001b2 + +#define PACKAGE_THERM_INT_HIGH_ENABLE (1 << 0) +#define PACKAGE_THERM_INT_LOW_ENABLE (1 << 1) +#define PACKAGE_THERM_INT_PLN_ENABLE (1 << 24) + +/* Thermal Thresholds Support */ +#define THERM_INT_THRESHOLD0_ENABLE (1 << 15) +#define THERM_SHIFT_THRESHOLD0 8 +#define THERM_MASK_THRESHOLD0 (0x7f << THERM_SHIFT_THRESHOLD0) +#define THERM_INT_THRESHOLD1_ENABLE (1 << 23) +#define THERM_SHIFT_THRESHOLD1 16 +#define THERM_MASK_THRESHOLD1 (0x7f << THERM_SHIFT_THRESHOLD1) +#define THERM_STATUS_THRESHOLD0 (1 << 6) +#define THERM_LOG_THRESHOLD0 (1 << 7) +#define THERM_STATUS_THRESHOLD1 (1 << 8) +#define THERM_LOG_THRESHOLD1 (1 << 9) + +/* MISC_ENABLE bits: architectural */ +#define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << 0) +#define MSR_IA32_MISC_ENABLE_TCC (1ULL << 1) +#define MSR_IA32_MISC_ENABLE_EMON (1ULL << 7) +#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1ULL << 11) +#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1ULL << 12) +#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP (1ULL << 16) +#define MSR_IA32_MISC_ENABLE_MWAIT (1ULL << 18) +#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1ULL << 22) +#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1ULL << 23) +#define MSR_IA32_MISC_ENABLE_XD_DISABLE (1ULL << 34) + +/* MISC_ENABLE bits: model-specific, meaning may vary from core to core */ +#define MSR_IA32_MISC_ENABLE_X87_COMPAT (1ULL << 2) +#define MSR_IA32_MISC_ENABLE_TM1 (1ULL << 3) +#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE (1ULL << 4) +#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE (1ULL << 6) +#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK (1ULL << 8) +#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE (1ULL << 9) +#define MSR_IA32_MISC_ENABLE_FERR (1ULL << 10) +#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX (1ULL << 10) +#define MSR_IA32_MISC_ENABLE_TM2 (1ULL << 13) +#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE (1ULL << 19) +#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK (1ULL << 20) +#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT (1ULL << 24) +#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << 37) +#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << 38) +#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << 39) + +/* P4/Xeon+ specific */ +#define MSR_IA32_MCG_EAX 0x00000180 +#define MSR_IA32_MCG_EBX 0x00000181 +#define MSR_IA32_MCG_ECX 0x00000182 +#define MSR_IA32_MCG_EDX 0x00000183 +#define MSR_IA32_MCG_ESI 0x00000184 +#define MSR_IA32_MCG_EDI 0x00000185 +#define MSR_IA32_MCG_EBP 0x00000186 +#define MSR_IA32_MCG_ESP 0x00000187 +#define MSR_IA32_MCG_EFLAGS 0x00000188 +#define MSR_IA32_MCG_EIP 0x00000189 +#define MSR_IA32_MCG_RESERVED 0x0000018a + +/* Pentium IV performance counter MSRs */ +#define MSR_P4_BPU_PERFCTR0 0x00000300 +#define MSR_P4_BPU_PERFCTR1 0x00000301 +#define MSR_P4_BPU_PERFCTR2 0x00000302 +#define MSR_P4_BPU_PERFCTR3 0x00000303 +#define MSR_P4_MS_PERFCTR0 0x00000304 +#define MSR_P4_MS_PERFCTR1 0x00000305 +#define MSR_P4_MS_PERFCTR2 0x00000306 +#define MSR_P4_MS_PERFCTR3 0x00000307 +#define MSR_P4_FLAME_PERFCTR0 0x00000308 +#define MSR_P4_FLAME_PERFCTR1 0x00000309 +#define MSR_P4_FLAME_PERFCTR2 0x0000030a +#define MSR_P4_FLAME_PERFCTR3 0x0000030b +#define MSR_P4_IQ_PERFCTR0 0x0000030c +#define MSR_P4_IQ_PERFCTR1 0x0000030d +#define MSR_P4_IQ_PERFCTR2 0x0000030e +#define MSR_P4_IQ_PERFCTR3 0x0000030f +#define MSR_P4_IQ_PERFCTR4 0x00000310 +#define MSR_P4_IQ_PERFCTR5 0x00000311 +#define MSR_P4_BPU_CCCR0 0x00000360 +#define MSR_P4_BPU_CCCR1 0x00000361 +#define MSR_P4_BPU_CCCR2 0x00000362 +#define MSR_P4_BPU_CCCR3 0x00000363 +#define MSR_P4_MS_CCCR0 0x00000364 +#define MSR_P4_MS_CCCR1 0x00000365 +#define MSR_P4_MS_CCCR2 0x00000366 +#define MSR_P4_MS_CCCR3 0x00000367 +#define MSR_P4_FLAME_CCCR0 0x00000368 +#define MSR_P4_FLAME_CCCR1 0x00000369 +#define MSR_P4_FLAME_CCCR2 0x0000036a +#define MSR_P4_FLAME_CCCR3 0x0000036b +#define MSR_P4_IQ_CCCR0 0x0000036c +#define MSR_P4_IQ_CCCR1 0x0000036d +#define MSR_P4_IQ_CCCR2 0x0000036e +#define MSR_P4_IQ_CCCR3 0x0000036f +#define MSR_P4_IQ_CCCR4 0x00000370 +#define MSR_P4_IQ_CCCR5 0x00000371 +#define MSR_P4_ALF_ESCR0 0x000003ca +#define MSR_P4_ALF_ESCR1 0x000003cb +#define MSR_P4_BPU_ESCR0 0x000003b2 +#define MSR_P4_BPU_ESCR1 0x000003b3 +#define MSR_P4_BSU_ESCR0 0x000003a0 +#define MSR_P4_BSU_ESCR1 0x000003a1 +#define MSR_P4_CRU_ESCR0 0x000003b8 +#define MSR_P4_CRU_ESCR1 0x000003b9 +#define MSR_P4_CRU_ESCR2 0x000003cc +#define MSR_P4_CRU_ESCR3 0x000003cd +#define MSR_P4_CRU_ESCR4 0x000003e0 +#define MSR_P4_CRU_ESCR5 0x000003e1 +#define MSR_P4_DAC_ESCR0 0x000003a8 +#define MSR_P4_DAC_ESCR1 0x000003a9 +#define MSR_P4_FIRM_ESCR0 0x000003a4 +#define MSR_P4_FIRM_ESCR1 0x000003a5 +#define MSR_P4_FLAME_ESCR0 0x000003a6 +#define MSR_P4_FLAME_ESCR1 0x000003a7 +#define MSR_P4_FSB_ESCR0 0x000003a2 +#define MSR_P4_FSB_ESCR1 0x000003a3 +#define MSR_P4_IQ_ESCR0 0x000003ba +#define MSR_P4_IQ_ESCR1 0x000003bb +#define MSR_P4_IS_ESCR0 0x000003b4 +#define MSR_P4_IS_ESCR1 0x000003b5 +#define MSR_P4_ITLB_ESCR0 0x000003b6 +#define MSR_P4_ITLB_ESCR1 0x000003b7 +#define MSR_P4_IX_ESCR0 0x000003c8 +#define MSR_P4_IX_ESCR1 0x000003c9 +#define MSR_P4_MOB_ESCR0 0x000003aa +#define MSR_P4_MOB_ESCR1 0x000003ab +#define MSR_P4_MS_ESCR0 0x000003c0 +#define MSR_P4_MS_ESCR1 0x000003c1 +#define MSR_P4_PMH_ESCR0 0x000003ac +#define MSR_P4_PMH_ESCR1 0x000003ad +#define MSR_P4_RAT_ESCR0 0x000003bc +#define MSR_P4_RAT_ESCR1 0x000003bd +#define MSR_P4_SAAT_ESCR0 0x000003ae +#define MSR_P4_SAAT_ESCR1 0x000003af +#define MSR_P4_SSU_ESCR0 0x000003be +#define MSR_P4_SSU_ESCR1 0x000003bf /* guess: not in manual */ + +#define MSR_P4_TBPU_ESCR0 0x000003c2 +#define MSR_P4_TBPU_ESCR1 0x000003c3 +#define MSR_P4_TC_ESCR0 0x000003c4 +#define MSR_P4_TC_ESCR1 0x000003c5 +#define MSR_P4_U2L_ESCR0 0x000003b0 +#define MSR_P4_U2L_ESCR1 0x000003b1 + +#define MSR_P4_PEBS_MATRIX_VERT 0x000003f2 + +/* Intel Core-based CPU performance counters */ +#define MSR_CORE_PERF_FIXED_CTR0 0x00000309 +#define MSR_CORE_PERF_FIXED_CTR1 0x0000030a +#define MSR_CORE_PERF_FIXED_CTR2 0x0000030b +#define MSR_CORE_PERF_FIXED_CTR_CTRL 0x0000038d +#define MSR_CORE_PERF_GLOBAL_STATUS 0x0000038e +#define MSR_CORE_PERF_GLOBAL_CTRL 0x0000038f +#define MSR_CORE_PERF_GLOBAL_OVF_CTRL 0x00000390 + +/* Geode defined MSRs */ +#define MSR_GEODE_BUSCONT_CONF0 0x00001900 + +/* Intel VT MSRs */ +#define MSR_IA32_VMX_BASIC 0x00000480 +#define MSR_IA32_VMX_PINBASED_CTLS 0x00000481 +#define MSR_IA32_VMX_PROCBASED_CTLS 0x00000482 +#define MSR_IA32_VMX_EXIT_CTLS 0x00000483 +#define MSR_IA32_VMX_ENTRY_CTLS 0x00000484 +#define MSR_IA32_VMX_MISC 0x00000485 +#define MSR_IA32_VMX_CR0_FIXED0 0x00000486 +#define MSR_IA32_VMX_CR0_FIXED1 0x00000487 +#define MSR_IA32_VMX_CR4_FIXED0 0x00000488 +#define MSR_IA32_VMX_CR4_FIXED1 0x00000489 +#define MSR_IA32_VMX_VMCS_ENUM 0x0000048a +#define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b +#define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c + +/* AMD-V MSRs */ + +#define MSR_VM_CR 0xc0010114 +#define MSR_VM_IGNNE 0xc0010115 +#define MSR_VM_HSAVE_PA 0xc0010117 + +#endif /* _ASM_X86_MSR_INDEX_H */ diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h new file mode 100644 index 0000000..1865c64 --- /dev/null +++ b/arch/x86/include/asm/msr.h @@ -0,0 +1,216 @@ +#ifndef _ASM_X86_MSR_H +#define _ASM_X86_MSR_H + +#include <asm/msr-index.h> + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> +#include <linux/ioctl.h> + +#define X86_IOC_RDMSR_REGS _IOWR('c', 0xA0, __u32[8]) +#define X86_IOC_WRMSR_REGS _IOWR('c', 0xA1, __u32[8]) + +#ifdef __KERNEL__ + +#include <asm/errno.h> + +struct msr { + union { + struct { + u32 l; + u32 h; + }; + u64 q; + }; +}; + +struct msr_info { + u32 msr_no; + struct msr reg; + struct msr *msrs; + int err; +}; + +struct msr_regs_info { + u32 *regs; + int err; +}; + +static inline unsigned long long native_read_tscp(unsigned int *aux) +{ + unsigned long low, high; + asm volatile(".byte 0x0f,0x01,0xf9" + : "=a" (low), "=d" (high), "=c" (*aux)); + return low | ((u64)high << 32); +} + +/* + * both i386 and x86_64 returns 64-bit value in edx:eax, but gcc's "A" + * constraint has different meanings. For i386, "A" means exactly + * edx:eax, while for x86_64 it doesn't mean rdx:rax or edx:eax. Instead, + * it means rax *or* rdx. + */ +#ifdef CONFIG_X86_64 +#define DECLARE_ARGS(val, low, high) unsigned low, high +#define EAX_EDX_VAL(val, low, high) ((low) | ((u64)(high) << 32)) +#define EAX_EDX_ARGS(val, low, high) "a" (low), "d" (high) +#define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high) +#else +#define DECLARE_ARGS(val, low, high) unsigned long long val +#define EAX_EDX_VAL(val, low, high) (val) +#define EAX_EDX_ARGS(val, low, high) "A" (val) +#define EAX_EDX_RET(val, low, high) "=A" (val) +#endif + +static inline unsigned long long native_read_msr(unsigned int msr) +{ + DECLARE_ARGS(val, low, high); + + asm volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr)); + return EAX_EDX_VAL(val, low, high); +} + +static inline void native_write_msr(unsigned int msr, + unsigned low, unsigned high) +{ + asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory"); +} + +extern unsigned long long native_read_tsc(void); + +extern int native_rdmsr_safe_regs(u32 regs[8]); +extern int native_wrmsr_safe_regs(u32 regs[8]); + +static inline unsigned long long native_read_pmc(int counter) +{ + DECLARE_ARGS(val, low, high); + + asm volatile("rdpmc" : EAX_EDX_RET(val, low, high) : "c" (counter)); + return EAX_EDX_VAL(val, low, high); +} + +#ifdef CONFIG_PARAVIRT +#include <asm/paravirt.h> +#else +#include <errno.h> +/* + * Access to machine-specific registers (available on 586 and better only) + * Note: the rd* operations modify the parameters directly (without using + * pointer indirection), this allows gcc to optimize better + */ + +#define rdmsr(msr, val1, val2) \ +do { \ + u64 __val = native_read_msr((msr)); \ + (void)((val1) = (u32)__val); \ + (void)((val2) = (u32)(__val >> 32)); \ +} while (0) + +static inline void wrmsr(unsigned msr, unsigned low, unsigned high) +{ + native_write_msr(msr, low, high); +} + +#define rdmsrl(msr, val) \ + ((val) = native_read_msr((msr))) + +#define wrmsrl(msr, val) \ + native_write_msr((msr), (u32)((u64)(val)), (u32)((u64)(val) >> 32)) + +/* rdmsr with exception handling */ +#define rdmsr_safe(msr, p1, p2) \ +({ \ + int __err; \ + u64 __val = native_read_msr_safe((msr), &__err); \ + (*p1) = (u32)__val; \ + (*p2) = (u32)(__val >> 32); \ + __err; \ +}) + +static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) +{ + u32 gprs[8] = { 0 }; + int err; + + gprs[1] = msr; + gprs[7] = 0x9c5a203a; + + err = native_rdmsr_safe_regs(gprs); + + *p = gprs[0] | ((u64)gprs[2] << 32); + + return err; +} + +static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val) +{ + u32 gprs[8] = { 0 }; + + gprs[0] = (u32)val; + gprs[1] = msr; + gprs[2] = val >> 32; + gprs[7] = 0x9c5a203a; + + return native_wrmsr_safe_regs(gprs); +} + +static inline int rdmsr_safe_regs(u32 regs[8]) +{ + return native_rdmsr_safe_regs(regs); +} + +static inline int wrmsr_safe_regs(u32 regs[8]) +{ + return native_wrmsr_safe_regs(regs); +} + +#define rdtscl(low) \ + ((low) = (u32)__native_read_tsc()) + +#define rdtscll(val) \ + ((val) = __native_read_tsc()) + +#define rdpmc(counter, low, high) \ +do { \ + u64 _l = native_read_pmc((counter)); \ + (low) = (u32)_l; \ + (high) = (u32)(_l >> 32); \ +} while (0) + +#define rdtscp(low, high, aux) \ +do { \ + unsigned long long _val = native_read_tscp(&(aux)); \ + (low) = (u32)_val; \ + (high) = (u32)(_val >> 32); \ +} while (0) + +#define rdtscpll(val, aux) (val) = native_read_tscp(&(aux)) + +#endif /* !CONFIG_PARAVIRT */ + + +#define checking_wrmsrl(msr, val) wrmsr_safe((msr), (u32)(val), \ + (u32)((val) >> 32)) + +#define write_tsc(val1, val2) wrmsr(MSR_IA32_TSC, (val1), (val2)) + +#define write_rdtscp_aux(val) wrmsr(MSR_TSC_AUX, (val), 0) + +struct msr *msrs_alloc(void); +void msrs_free(struct msr *msrs); + +#ifdef CONFIG_SMP +int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); +int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); +void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); +void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); +int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); +int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); +int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); +int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); + +#endif /* CONFIG_SMP */ +#endif /* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_X86_MSR_H */ diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h new file mode 100644 index 0000000..b75203c --- /dev/null +++ b/arch/x86/include/asm/mtrr.h @@ -0,0 +1,203 @@ +/* Generic MTRR (Memory Type Range Register) ioctls. + + Copyright (C) 1997-1999 Richard Gooch + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Richard Gooch may be reached by email at rgooch@atnf.csiro.au + The postal address is: + Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. +*/ +#ifndef _ASM_X86_MTRR_H +#define _ASM_X86_MTRR_H + +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg)) +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) + +#ifndef __ASSEMBLY__ + +#include <linux/types.h> +#include <linux/ioctl.h> +#include <errno.h> + +#define MTRR_IOCTL_BASE 'M' + +struct mtrr_sentry { + unsigned long base; /* Base address */ + unsigned int size; /* Size of region */ + unsigned int type; /* Type of region */ +}; + +/* + * Warning: this structure has a different order from i386 + * on x86-64. The 32bit emulation code takes care of that. + * But you need to use this for 64bit, otherwise your X server + * will break. + */ + +#ifdef __i386__ +struct mtrr_gentry { + unsigned int regnum; /* Register number */ + unsigned long base; /* Base address */ + unsigned int size; /* Size of region */ + unsigned int type; /* Type of region */ +}; + +#else /* __i386__ */ + +struct mtrr_gentry { + unsigned long base; /* Base address */ + unsigned int size; /* Size of region */ + unsigned int regnum; /* Register number */ + unsigned int type; /* Type of region */ +}; +#endif /* !__i386__ */ + +struct mtrr_var_range { + __u32 base_lo; + __u32 base_hi; + __u32 mask_lo; + __u32 mask_hi; +}; + +/* + * In the Intel processor's MTRR interface, the MTRR type is always held in + * an 8 bit field: + */ +typedef __u8 mtrr_type; + +#define MTRR_NUM_FIXED_RANGES 88 +#define MTRR_MAX_VAR_RANGES 256 + +struct mtrr_state_type { + struct mtrr_var_range var_ranges[MTRR_MAX_VAR_RANGES]; + mtrr_type fixed_ranges[MTRR_NUM_FIXED_RANGES]; + unsigned char enabled; + unsigned char have_fixed; + mtrr_type def_type; +}; + +/* These are the various ioctls */ +#define MTRRIOC_ADD_ENTRY _IOW(MTRR_IOCTL_BASE, 0, struct mtrr_sentry) +#define MTRRIOC_SET_ENTRY _IOW(MTRR_IOCTL_BASE, 1, struct mtrr_sentry) +#define MTRRIOC_DEL_ENTRY _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry) +#define MTRRIOC_GET_ENTRY _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry) +#define MTRRIOC_KILL_ENTRY _IOW(MTRR_IOCTL_BASE, 4, struct mtrr_sentry) +#define MTRRIOC_ADD_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 5, struct mtrr_sentry) +#define MTRRIOC_SET_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 6, struct mtrr_sentry) +#define MTRRIOC_DEL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 7, struct mtrr_sentry) +#define MTRRIOC_GET_PAGE_ENTRY _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry) +#define MTRRIOC_KILL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 9, struct mtrr_sentry) + +/* These are the region types */ +#define MTRR_TYPE_UNCACHABLE 0 +#define MTRR_TYPE_WRCOMB 1 +/*#define MTRR_TYPE_ 2*/ +/*#define MTRR_TYPE_ 3*/ +#define MTRR_TYPE_WRTHROUGH 4 +#define MTRR_TYPE_WRPROT 5 +#define MTRR_TYPE_WRBACK 6 +#define MTRR_NUM_TYPES 7 + +#ifdef __KERNEL__ + +/* The following functions are for use by other drivers */ +# ifdef CONFIG_MTRR +extern u8 mtrr_type_lookup(u64 addr, u64 end); +extern void mtrr_save_fixed_ranges(void *); +extern void mtrr_save_state(void); +extern int mtrr_add(unsigned long base, unsigned long size, + unsigned int type, bool increment); +extern int mtrr_add_page(unsigned long base, unsigned long size, + unsigned int type, bool increment); +extern int mtrr_del(int reg, unsigned long base, unsigned long size); +extern int mtrr_del_page(int reg, unsigned long base, unsigned long size); +extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); +extern void mtrr_ap_init(void); +extern void mtrr_bp_init(void); +extern void set_mtrr_aps_delayed_init(void); +extern void mtrr_aps_init(void); +extern void mtrr_bp_restore(void); +extern int mtrr_trim_uncached_memory(unsigned long end_pfn); +extern int amd_special_default_mtrr(void); +# else +static inline u8 mtrr_type_lookup(u64 addr, u64 end) +{ + /* + * Return no-MTRRs: + */ + return 0xff; +} +#define mtrr_save_fixed_ranges(arg) do {} while (0) +#define mtrr_save_state() do {} while (0) +static inline int mtrr_del(int reg, unsigned long base, unsigned long size) +{ + return -ENODEV; +} +static inline int mtrr_del_page(int reg, unsigned long base, unsigned long size) +{ + return -ENODEV; +} +static inline int mtrr_trim_uncached_memory(unsigned long end_pfn) +{ + return 0; +} +static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) +{ +} + +#define mtrr_ap_init() do {} while (0) +#define mtrr_bp_init() do {} while (0) +#define set_mtrr_aps_delayed_init() do {} while (0) +#define mtrr_aps_init() do {} while (0) +#define mtrr_bp_restore() do {} while (0) +# endif + +#ifdef CONFIG_COMPAT +#include <linux/compat.h> + +struct mtrr_sentry32 { + compat_ulong_t base; /* Base address */ + compat_uint_t size; /* Size of region */ + compat_uint_t type; /* Type of region */ +}; + +struct mtrr_gentry32 { + compat_ulong_t regnum; /* Register number */ + compat_uint_t base; /* Base address */ + compat_uint_t size; /* Size of region */ + compat_uint_t type; /* Type of region */ +}; + +#define MTRR_IOCTL_BASE 'M' + +#define MTRRIOC32_ADD_ENTRY _IOW(MTRR_IOCTL_BASE, 0, struct mtrr_sentry32) +#define MTRRIOC32_SET_ENTRY _IOW(MTRR_IOCTL_BASE, 1, struct mtrr_sentry32) +#define MTRRIOC32_DEL_ENTRY _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry32) +#define MTRRIOC32_GET_ENTRY _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry32) +#define MTRRIOC32_KILL_ENTRY _IOW(MTRR_IOCTL_BASE, 4, struct mtrr_sentry32) +#define MTRRIOC32_ADD_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 5, struct mtrr_sentry32) +#define MTRRIOC32_SET_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 6, struct mtrr_sentry32) +#define MTRRIOC32_DEL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 7, struct mtrr_sentry32) +#define MTRRIOC32_GET_PAGE_ENTRY _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry32) +#define MTRRIOC32_KILL_PAGE_ENTRY \ + _IOW(MTRR_IOCTL_BASE, 9, struct mtrr_sentry32) +#endif /* CONFIG_COMPAT */ + +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_X86_MTRR_H */

Graeme,
Reusing code from the Linux kernel is generally a great idea. However for simplicity I'd rather have 25 lines than 870 lines for reading MSRs. It seems a lot of code in those files doesn't really apply for u-boot
Stefan
On Tue, Oct 23, 2012 at 9:34 PM, Graeme Russ graeme.russ@gmail.com wrote:
Hi Simon,
On Wed, Oct 24, 2012 at 3:04 PM, Simon Glass sjg@chromium.org wrote:
From: Stefan Reinauer reinauer@chromium.org
Provide basic functions to access these registers.
I really should have got my funk into gear and posted patches I created (on a side project) a long time ago :(
Anyways - I implemented the same, but I just stole the code from the Linux kernel (3.1 to be exact) - I've attached my patch below (may not apply cleanly now)
Regards,
Graeme
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/msr.h | 25 +++++++++++++++++++++++++ 1 files changed, 25 insertions(+), 0 deletions(-) create mode 100644 arch/x86/include/asm/msr.h
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h new file mode 100644 index 0000000..0a681d1 --- /dev/null +++ b/arch/x86/include/asm/msr.h @@ -0,0 +1,25 @@ +#ifndef CPU_X86_ASM_MSR_H +#define CPU_X86_ASM_MSR_H
+static inline uint64_t rdmsr(unsigned index) +{
uint64_t result;
asm volatile (
"rdmsr"
: "=A" (result)
: "c" (index)
);
return result;
+}
+static inline void wrmsr(unsigned index, uint64_t msr) +{
asm volatile (
"wrmsr"
: /* No outputs */
: "c" (index), "A" (msr)
);
+}
+#endif /* CPU_X86_ASM_MSR_H */
1.7.7.3
Zee Patch ;)
x86: Import MSR/MTRR code from Linux
Imported from Linux 3.1 with a few modifications to suit U-Boot
arch/x86/include/asm/msr-index.h | 447 ++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/msr.h | 216 ++++++++++++++++++ arch/x86/include/asm/mtrr.h | 203 +++++++++++++++++ 3 files changed, 866 insertions(+), 0 deletions(-) create mode 100644 arch/x86/include/asm/msr-index.h create mode 100644 arch/x86/include/asm/msr.h create mode 100644 arch/x86/include/asm/mtrr.h
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h new file mode 100644 index 0000000..2d4a20a --- /dev/null +++ b/arch/x86/include/asm/msr-index.h @@ -0,0 +1,447 @@ +#ifndef _ASM_X86_MSR_INDEX_H +#define _ASM_X86_MSR_INDEX_H
+/* CPU model specific register (MSR) numbers */
+/* x86-64 specific MSRs */ +#define MSR_EFER 0xc0000080 /* extended feature register */ +#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */ +#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */ +#define MSR_CSTAR 0xc0000083 /* compat mode SYSCALL target */ +#define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */ +#define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ +#define MSR_GS_BASE 0xc0000101 /* 64bit GS base */ +#define MSR_KERNEL_GS_BASE 0xc0000102 /* SwapGS GS shadow */ +#define MSR_TSC_AUX 0xc0000103 /* Auxiliary TSC */
+/* EFER bits: */ +#define _EFER_SCE 0 /* SYSCALL/SYSRET */ +#define _EFER_LME 8 /* Long mode enable */ +#define _EFER_LMA 10 /* Long mode active (read-only) */ +#define _EFER_NX 11 /* No execute enable */ +#define _EFER_SVME 12 /* Enable virtualization */ +#define _EFER_LMSLE 13 /* Long Mode Segment Limit Enable */ +#define _EFER_FFXSR 14 /* Enable Fast FXSAVE/FXRSTOR */
+#define EFER_SCE (1<<_EFER_SCE) +#define EFER_LME (1<<_EFER_LME) +#define EFER_LMA (1<<_EFER_LMA) +#define EFER_NX (1<<_EFER_NX) +#define EFER_SVME (1<<_EFER_SVME) +#define EFER_LMSLE (1<<_EFER_LMSLE) +#define EFER_FFXSR (1<<_EFER_FFXSR)
+/* Intel MSRs. Some also available on other CPUs */ +#define MSR_IA32_PERFCTR0 0x000000c1 +#define MSR_IA32_PERFCTR1 0x000000c2 +#define MSR_FSB_FREQ 0x000000cd
+#define MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2 +#define NHM_C3_AUTO_DEMOTE (1UL << 25) +#define NHM_C1_AUTO_DEMOTE (1UL << 26) +#define ATM_LNC_C6_AUTO_DEMOTE (1UL << 25)
+#define MSR_MTRRcap 0x000000fe +#define MSR_IA32_BBL_CR_CTL 0x00000119 +#define MSR_IA32_BBL_CR_CTL3 0x0000011e
+#define MSR_IA32_SYSENTER_CS 0x00000174 +#define MSR_IA32_SYSENTER_ESP 0x00000175 +#define MSR_IA32_SYSENTER_EIP 0x00000176
+#define MSR_IA32_MCG_CAP 0x00000179 +#define MSR_IA32_MCG_STATUS 0x0000017a +#define MSR_IA32_MCG_CTL 0x0000017b
+#define MSR_OFFCORE_RSP_0 0x000001a6 +#define MSR_OFFCORE_RSP_1 0x000001a7
+#define MSR_IA32_PEBS_ENABLE 0x000003f1 +#define MSR_IA32_DS_AREA 0x00000600 +#define MSR_IA32_PERF_CAPABILITIES 0x00000345
+#define MSR_MTRRfix64K_00000 0x00000250 +#define MSR_MTRRfix16K_80000 0x00000258 +#define MSR_MTRRfix16K_A0000 0x00000259 +#define MSR_MTRRfix4K_C0000 0x00000268 +#define MSR_MTRRfix4K_C8000 0x00000269 +#define MSR_MTRRfix4K_D0000 0x0000026a +#define MSR_MTRRfix4K_D8000 0x0000026b +#define MSR_MTRRfix4K_E0000 0x0000026c +#define MSR_MTRRfix4K_E8000 0x0000026d +#define MSR_MTRRfix4K_F0000 0x0000026e +#define MSR_MTRRfix4K_F8000 0x0000026f +#define MSR_MTRRdefType 0x000002ff
+#define MSR_IA32_CR_PAT 0x00000277
+#define MSR_IA32_DEBUGCTLMSR 0x000001d9 +#define MSR_IA32_LASTBRANCHFROMIP 0x000001db +#define MSR_IA32_LASTBRANCHTOIP 0x000001dc +#define MSR_IA32_LASTINTFROMIP 0x000001dd +#define MSR_IA32_LASTINTTOIP 0x000001de
+/* DEBUGCTLMSR bits (others vary by model): */ +#define DEBUGCTLMSR_LBR (1UL << 0) +#define DEBUGCTLMSR_BTF (1UL << 1) +#define DEBUGCTLMSR_TR (1UL << 6) +#define DEBUGCTLMSR_BTS (1UL << 7) +#define DEBUGCTLMSR_BTINT (1UL << 8) +#define DEBUGCTLMSR_BTS_OFF_OS (1UL << 9) +#define DEBUGCTLMSR_BTS_OFF_USR (1UL << 10) +#define DEBUGCTLMSR_FREEZE_LBRS_ON_PMI (1UL << 11)
+#define MSR_IA32_MC0_CTL 0x00000400 +#define MSR_IA32_MC0_STATUS 0x00000401 +#define MSR_IA32_MC0_ADDR 0x00000402 +#define MSR_IA32_MC0_MISC 0x00000403
+#define MSR_AMD64_MC0_MASK 0xc0010044
+#define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x)) +#define MSR_IA32_MCx_STATUS(x) (MSR_IA32_MC0_STATUS + 4*(x)) +#define MSR_IA32_MCx_ADDR(x) (MSR_IA32_MC0_ADDR + 4*(x)) +#define MSR_IA32_MCx_MISC(x) (MSR_IA32_MC0_MISC + 4*(x))
+#define MSR_AMD64_MCx_MASK(x) (MSR_AMD64_MC0_MASK + (x))
+/* These are consecutive and not in the normal 4er MCE bank block */ +#define MSR_IA32_MC0_CTL2 0x00000280 +#define MSR_IA32_MCx_CTL2(x) (MSR_IA32_MC0_CTL2 + (x))
+#define MSR_P6_PERFCTR0 0x000000c1 +#define MSR_P6_PERFCTR1 0x000000c2 +#define MSR_P6_EVNTSEL0 0x00000186 +#define MSR_P6_EVNTSEL1 0x00000187
+/* AMD64 MSRs. Not complete. See the architecture manual for a more
- complete list. */
+#define MSR_AMD64_PATCH_LEVEL 0x0000008b +#define MSR_AMD64_NB_CFG 0xc001001f +#define MSR_AMD64_PATCH_LOADER 0xc0010020 +#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 +#define MSR_AMD64_OSVW_STATUS 0xc0010141 +#define MSR_AMD64_DC_CFG 0xc0011022 +#define MSR_AMD64_IBSFETCHCTL 0xc0011030 +#define MSR_AMD64_IBSFETCHLINAD 0xc0011031 +#define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 +#define MSR_AMD64_IBSOPCTL 0xc0011033 +#define MSR_AMD64_IBSOPRIP 0xc0011034 +#define MSR_AMD64_IBSOPDATA 0xc0011035 +#define MSR_AMD64_IBSOPDATA2 0xc0011036 +#define MSR_AMD64_IBSOPDATA3 0xc0011037 +#define MSR_AMD64_IBSDCLINAD 0xc0011038 +#define MSR_AMD64_IBSDCPHYSAD 0xc0011039 +#define MSR_AMD64_IBSCTL 0xc001103a +#define MSR_AMD64_IBSBRTARGET 0xc001103b
+/* Fam 15h MSRs */ +#define MSR_F15H_PERF_CTL 0xc0010200 +#define MSR_F15H_PERF_CTR 0xc0010201
+/* Fam 10h MSRs */ +#define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058 +#define FAM10H_MMIO_CONF_ENABLE (1<<0) +#define FAM10H_MMIO_CONF_BUSRANGE_MASK 0xf +#define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2 +#define FAM10H_MMIO_CONF_BASE_MASK 0xfffffffULL +#define FAM10H_MMIO_CONF_BASE_SHIFT 20 +#define MSR_FAM10H_NODE_ID 0xc001100c
+/* K8 MSRs */ +#define MSR_K8_TOP_MEM1 0xc001001a +#define MSR_K8_TOP_MEM2 0xc001001d +#define MSR_K8_SYSCFG 0xc0010010 +#define MSR_K8_INT_PENDING_MSG 0xc0010055 +/* C1E active bits in int pending message */ +#define K8_INTP_C1E_ACTIVE_MASK 0x18000000 +#define MSR_K8_TSEG_ADDR 0xc0010112 +#define K8_MTRRFIXRANGE_DRAM_ENABLE 0x00040000 /* MtrrFixDramEn bit */ +#define K8_MTRRFIXRANGE_DRAM_MODIFY 0x00080000 /* MtrrFixDramModEn bit */ +#define K8_MTRR_RDMEM_WRMEM_MASK 0x18181818 /* Mask: RdMem|WrMem */
+/* K7 MSRs */ +#define MSR_K7_EVNTSEL0 0xc0010000 +#define MSR_K7_PERFCTR0 0xc0010004 +#define MSR_K7_EVNTSEL1 0xc0010001 +#define MSR_K7_PERFCTR1 0xc0010005 +#define MSR_K7_EVNTSEL2 0xc0010002 +#define MSR_K7_PERFCTR2 0xc0010006 +#define MSR_K7_EVNTSEL3 0xc0010003 +#define MSR_K7_PERFCTR3 0xc0010007 +#define MSR_K7_CLK_CTL 0xc001001b +#define MSR_K7_HWCR 0xc0010015 +#define MSR_K7_FID_VID_CTL 0xc0010041 +#define MSR_K7_FID_VID_STATUS 0xc0010042
+/* K6 MSRs */ +#define MSR_K6_WHCR 0xc0000082 +#define MSR_K6_UWCCR 0xc0000085 +#define MSR_K6_EPMR 0xc0000086 +#define MSR_K6_PSOR 0xc0000087 +#define MSR_K6_PFIR 0xc0000088
+/* Centaur-Hauls/IDT defined MSRs. */ +#define MSR_IDT_FCR1 0x00000107 +#define MSR_IDT_FCR2 0x00000108 +#define MSR_IDT_FCR3 0x00000109 +#define MSR_IDT_FCR4 0x0000010a
+#define MSR_IDT_MCR0 0x00000110 +#define MSR_IDT_MCR1 0x00000111 +#define MSR_IDT_MCR2 0x00000112 +#define MSR_IDT_MCR3 0x00000113 +#define MSR_IDT_MCR4 0x00000114 +#define MSR_IDT_MCR5 0x00000115 +#define MSR_IDT_MCR6 0x00000116 +#define MSR_IDT_MCR7 0x00000117 +#define MSR_IDT_MCR_CTRL 0x00000120
+/* VIA Cyrix defined MSRs*/ +#define MSR_VIA_FCR 0x00001107 +#define MSR_VIA_LONGHAUL 0x0000110a +#define MSR_VIA_RNG 0x0000110b +#define MSR_VIA_BCR2 0x00001147
+/* Transmeta defined MSRs */ +#define MSR_TMTA_LONGRUN_CTRL 0x80868010 +#define MSR_TMTA_LONGRUN_FLAGS 0x80868011 +#define MSR_TMTA_LRTI_READOUT 0x80868018 +#define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a
+/* Intel defined MSRs. */ +#define MSR_IA32_P5_MC_ADDR 0x00000000 +#define MSR_IA32_P5_MC_TYPE 0x00000001 +#define MSR_IA32_TSC 0x00000010 +#define MSR_IA32_PLATFORM_ID 0x00000017 +#define MSR_IA32_EBL_CR_POWERON 0x0000002a +#define MSR_EBC_FREQUENCY_ID 0x0000002c +#define MSR_IA32_FEATURE_CONTROL 0x0000003a
+#define FEATURE_CONTROL_LOCKED (1<<0) +#define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1) +#define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2)
+#define MSR_IA32_APICBASE 0x0000001b +#define MSR_IA32_APICBASE_BSP (1<<8) +#define MSR_IA32_APICBASE_ENABLE (1<<11) +#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
+#define MSR_IA32_UCODE_WRITE 0x00000079 +#define MSR_IA32_UCODE_REV 0x0000008b
+#define MSR_IA32_PERF_STATUS 0x00000198 +#define MSR_IA32_PERF_CTL 0x00000199
+#define MSR_IA32_MPERF 0x000000e7 +#define MSR_IA32_APERF 0x000000e8
+#define MSR_IA32_THERM_CONTROL 0x0000019a +#define MSR_IA32_THERM_INTERRUPT 0x0000019b
+#define THERM_INT_HIGH_ENABLE (1 << 0) +#define THERM_INT_LOW_ENABLE (1 << 1) +#define THERM_INT_PLN_ENABLE (1 << 24)
+#define MSR_IA32_THERM_STATUS 0x0000019c
+#define THERM_STATUS_PROCHOT (1 << 0) +#define THERM_STATUS_POWER_LIMIT (1 << 10)
+#define MSR_THERM2_CTL 0x0000019d
+#define MSR_THERM2_CTL_TM_SELECT (1ULL << 16)
+#define MSR_IA32_MISC_ENABLE 0x000001a0
+#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2
+#define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0
+#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1
+#define PACKAGE_THERM_STATUS_PROCHOT (1 << 0) +#define PACKAGE_THERM_STATUS_POWER_LIMIT (1 << 10)
+#define MSR_IA32_PACKAGE_THERM_INTERRUPT 0x000001b2
+#define PACKAGE_THERM_INT_HIGH_ENABLE (1 << 0) +#define PACKAGE_THERM_INT_LOW_ENABLE (1 << 1) +#define PACKAGE_THERM_INT_PLN_ENABLE (1 << 24)
+/* Thermal Thresholds Support */ +#define THERM_INT_THRESHOLD0_ENABLE (1 << 15) +#define THERM_SHIFT_THRESHOLD0 8 +#define THERM_MASK_THRESHOLD0 (0x7f << THERM_SHIFT_THRESHOLD0) +#define THERM_INT_THRESHOLD1_ENABLE (1 << 23) +#define THERM_SHIFT_THRESHOLD1 16 +#define THERM_MASK_THRESHOLD1 (0x7f << THERM_SHIFT_THRESHOLD1) +#define THERM_STATUS_THRESHOLD0 (1 << 6) +#define THERM_LOG_THRESHOLD0 (1 << 7) +#define THERM_STATUS_THRESHOLD1 (1 << 8) +#define THERM_LOG_THRESHOLD1 (1 << 9)
+/* MISC_ENABLE bits: architectural */ +#define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << 0) +#define MSR_IA32_MISC_ENABLE_TCC (1ULL << 1) +#define MSR_IA32_MISC_ENABLE_EMON (1ULL << 7) +#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1ULL << 11) +#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1ULL << 12) +#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP (1ULL << 16) +#define MSR_IA32_MISC_ENABLE_MWAIT (1ULL << 18) +#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1ULL << 22) +#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1ULL << 23) +#define MSR_IA32_MISC_ENABLE_XD_DISABLE (1ULL << 34)
+/* MISC_ENABLE bits: model-specific, meaning may vary from core to core */ +#define MSR_IA32_MISC_ENABLE_X87_COMPAT (1ULL << 2) +#define MSR_IA32_MISC_ENABLE_TM1 (1ULL << 3) +#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE (1ULL << 4) +#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE (1ULL << 6) +#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK (1ULL << 8) +#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE (1ULL << 9) +#define MSR_IA32_MISC_ENABLE_FERR (1ULL << 10) +#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX (1ULL << 10) +#define MSR_IA32_MISC_ENABLE_TM2 (1ULL << 13) +#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE (1ULL << 19) +#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK (1ULL << 20) +#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT (1ULL << 24) +#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << 37) +#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << 38) +#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << 39)
+/* P4/Xeon+ specific */ +#define MSR_IA32_MCG_EAX 0x00000180 +#define MSR_IA32_MCG_EBX 0x00000181 +#define MSR_IA32_MCG_ECX 0x00000182 +#define MSR_IA32_MCG_EDX 0x00000183 +#define MSR_IA32_MCG_ESI 0x00000184 +#define MSR_IA32_MCG_EDI 0x00000185 +#define MSR_IA32_MCG_EBP 0x00000186 +#define MSR_IA32_MCG_ESP 0x00000187 +#define MSR_IA32_MCG_EFLAGS 0x00000188 +#define MSR_IA32_MCG_EIP 0x00000189 +#define MSR_IA32_MCG_RESERVED 0x0000018a
+/* Pentium IV performance counter MSRs */ +#define MSR_P4_BPU_PERFCTR0 0x00000300 +#define MSR_P4_BPU_PERFCTR1 0x00000301 +#define MSR_P4_BPU_PERFCTR2 0x00000302 +#define MSR_P4_BPU_PERFCTR3 0x00000303 +#define MSR_P4_MS_PERFCTR0 0x00000304 +#define MSR_P4_MS_PERFCTR1 0x00000305 +#define MSR_P4_MS_PERFCTR2 0x00000306 +#define MSR_P4_MS_PERFCTR3 0x00000307 +#define MSR_P4_FLAME_PERFCTR0 0x00000308 +#define MSR_P4_FLAME_PERFCTR1 0x00000309 +#define MSR_P4_FLAME_PERFCTR2 0x0000030a +#define MSR_P4_FLAME_PERFCTR3 0x0000030b +#define MSR_P4_IQ_PERFCTR0 0x0000030c +#define MSR_P4_IQ_PERFCTR1 0x0000030d +#define MSR_P4_IQ_PERFCTR2 0x0000030e +#define MSR_P4_IQ_PERFCTR3 0x0000030f +#define MSR_P4_IQ_PERFCTR4 0x00000310 +#define MSR_P4_IQ_PERFCTR5 0x00000311 +#define MSR_P4_BPU_CCCR0 0x00000360 +#define MSR_P4_BPU_CCCR1 0x00000361 +#define MSR_P4_BPU_CCCR2 0x00000362 +#define MSR_P4_BPU_CCCR3 0x00000363 +#define MSR_P4_MS_CCCR0 0x00000364 +#define MSR_P4_MS_CCCR1 0x00000365 +#define MSR_P4_MS_CCCR2 0x00000366 +#define MSR_P4_MS_CCCR3 0x00000367 +#define MSR_P4_FLAME_CCCR0 0x00000368 +#define MSR_P4_FLAME_CCCR1 0x00000369 +#define MSR_P4_FLAME_CCCR2 0x0000036a +#define MSR_P4_FLAME_CCCR3 0x0000036b +#define MSR_P4_IQ_CCCR0 0x0000036c +#define MSR_P4_IQ_CCCR1 0x0000036d +#define MSR_P4_IQ_CCCR2 0x0000036e +#define MSR_P4_IQ_CCCR3 0x0000036f +#define MSR_P4_IQ_CCCR4 0x00000370 +#define MSR_P4_IQ_CCCR5 0x00000371 +#define MSR_P4_ALF_ESCR0 0x000003ca +#define MSR_P4_ALF_ESCR1 0x000003cb +#define MSR_P4_BPU_ESCR0 0x000003b2 +#define MSR_P4_BPU_ESCR1 0x000003b3 +#define MSR_P4_BSU_ESCR0 0x000003a0 +#define MSR_P4_BSU_ESCR1 0x000003a1 +#define MSR_P4_CRU_ESCR0 0x000003b8 +#define MSR_P4_CRU_ESCR1 0x000003b9 +#define MSR_P4_CRU_ESCR2 0x000003cc +#define MSR_P4_CRU_ESCR3 0x000003cd +#define MSR_P4_CRU_ESCR4 0x000003e0 +#define MSR_P4_CRU_ESCR5 0x000003e1 +#define MSR_P4_DAC_ESCR0 0x000003a8 +#define MSR_P4_DAC_ESCR1 0x000003a9 +#define MSR_P4_FIRM_ESCR0 0x000003a4 +#define MSR_P4_FIRM_ESCR1 0x000003a5 +#define MSR_P4_FLAME_ESCR0 0x000003a6 +#define MSR_P4_FLAME_ESCR1 0x000003a7 +#define MSR_P4_FSB_ESCR0 0x000003a2 +#define MSR_P4_FSB_ESCR1 0x000003a3 +#define MSR_P4_IQ_ESCR0 0x000003ba +#define MSR_P4_IQ_ESCR1 0x000003bb +#define MSR_P4_IS_ESCR0 0x000003b4 +#define MSR_P4_IS_ESCR1 0x000003b5 +#define MSR_P4_ITLB_ESCR0 0x000003b6 +#define MSR_P4_ITLB_ESCR1 0x000003b7 +#define MSR_P4_IX_ESCR0 0x000003c8 +#define MSR_P4_IX_ESCR1 0x000003c9 +#define MSR_P4_MOB_ESCR0 0x000003aa +#define MSR_P4_MOB_ESCR1 0x000003ab +#define MSR_P4_MS_ESCR0 0x000003c0 +#define MSR_P4_MS_ESCR1 0x000003c1 +#define MSR_P4_PMH_ESCR0 0x000003ac +#define MSR_P4_PMH_ESCR1 0x000003ad +#define MSR_P4_RAT_ESCR0 0x000003bc +#define MSR_P4_RAT_ESCR1 0x000003bd +#define MSR_P4_SAAT_ESCR0 0x000003ae +#define MSR_P4_SAAT_ESCR1 0x000003af +#define MSR_P4_SSU_ESCR0 0x000003be +#define MSR_P4_SSU_ESCR1 0x000003bf /* guess: not in manual */
+#define MSR_P4_TBPU_ESCR0 0x000003c2 +#define MSR_P4_TBPU_ESCR1 0x000003c3 +#define MSR_P4_TC_ESCR0 0x000003c4 +#define MSR_P4_TC_ESCR1 0x000003c5 +#define MSR_P4_U2L_ESCR0 0x000003b0 +#define MSR_P4_U2L_ESCR1 0x000003b1
+#define MSR_P4_PEBS_MATRIX_VERT 0x000003f2
+/* Intel Core-based CPU performance counters */ +#define MSR_CORE_PERF_FIXED_CTR0 0x00000309 +#define MSR_CORE_PERF_FIXED_CTR1 0x0000030a +#define MSR_CORE_PERF_FIXED_CTR2 0x0000030b +#define MSR_CORE_PERF_FIXED_CTR_CTRL 0x0000038d +#define MSR_CORE_PERF_GLOBAL_STATUS 0x0000038e +#define MSR_CORE_PERF_GLOBAL_CTRL 0x0000038f +#define MSR_CORE_PERF_GLOBAL_OVF_CTRL 0x00000390
+/* Geode defined MSRs */ +#define MSR_GEODE_BUSCONT_CONF0 0x00001900
+/* Intel VT MSRs */ +#define MSR_IA32_VMX_BASIC 0x00000480 +#define MSR_IA32_VMX_PINBASED_CTLS 0x00000481 +#define MSR_IA32_VMX_PROCBASED_CTLS 0x00000482 +#define MSR_IA32_VMX_EXIT_CTLS 0x00000483 +#define MSR_IA32_VMX_ENTRY_CTLS 0x00000484 +#define MSR_IA32_VMX_MISC 0x00000485 +#define MSR_IA32_VMX_CR0_FIXED0 0x00000486 +#define MSR_IA32_VMX_CR0_FIXED1 0x00000487 +#define MSR_IA32_VMX_CR4_FIXED0 0x00000488 +#define MSR_IA32_VMX_CR4_FIXED1 0x00000489 +#define MSR_IA32_VMX_VMCS_ENUM 0x0000048a +#define MSR_IA32_VMX_PROCBASED_CTLS2 0x0000048b +#define MSR_IA32_VMX_EPT_VPID_CAP 0x0000048c
+/* AMD-V MSRs */
+#define MSR_VM_CR 0xc0010114 +#define MSR_VM_IGNNE 0xc0010115 +#define MSR_VM_HSAVE_PA 0xc0010117
+#endif /* _ASM_X86_MSR_INDEX_H */ diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h new file mode 100644 index 0000000..1865c64 --- /dev/null +++ b/arch/x86/include/asm/msr.h @@ -0,0 +1,216 @@ +#ifndef _ASM_X86_MSR_H +#define _ASM_X86_MSR_H
+#include <asm/msr-index.h>
+#ifndef __ASSEMBLY__
+#include <linux/types.h> +#include <linux/ioctl.h>
+#define X86_IOC_RDMSR_REGS _IOWR('c', 0xA0, __u32[8]) +#define X86_IOC_WRMSR_REGS _IOWR('c', 0xA1, __u32[8])
+#ifdef __KERNEL__
+#include <asm/errno.h>
+struct msr {
union {
struct {
u32 l;
u32 h;
};
u64 q;
};
+};
+struct msr_info {
u32 msr_no;
struct msr reg;
struct msr *msrs;
int err;
+};
+struct msr_regs_info {
u32 *regs;
int err;
+};
+static inline unsigned long long native_read_tscp(unsigned int *aux) +{
unsigned long low, high;
asm volatile(".byte 0x0f,0x01,0xf9"
: "=a" (low), "=d" (high), "=c" (*aux));
return low | ((u64)high << 32);
+}
+/*
- both i386 and x86_64 returns 64-bit value in edx:eax, but gcc's "A"
- constraint has different meanings. For i386, "A" means exactly
- edx:eax, while for x86_64 it doesn't mean rdx:rax or edx:eax. Instead,
- it means rax *or* rdx.
- */
+#ifdef CONFIG_X86_64 +#define DECLARE_ARGS(val, low, high) unsigned low, high +#define EAX_EDX_VAL(val, low, high) ((low) | ((u64)(high) << 32)) +#define EAX_EDX_ARGS(val, low, high) "a" (low), "d" (high) +#define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high) +#else +#define DECLARE_ARGS(val, low, high) unsigned long long val +#define EAX_EDX_VAL(val, low, high) (val) +#define EAX_EDX_ARGS(val, low, high) "A" (val) +#define EAX_EDX_RET(val, low, high) "=A" (val) +#endif
+static inline unsigned long long native_read_msr(unsigned int msr) +{
DECLARE_ARGS(val, low, high);
asm volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr));
return EAX_EDX_VAL(val, low, high);
+}
+static inline void native_write_msr(unsigned int msr,
unsigned low, unsigned high)
+{
asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) :
"memory"); +}
+extern unsigned long long native_read_tsc(void);
+extern int native_rdmsr_safe_regs(u32 regs[8]); +extern int native_wrmsr_safe_regs(u32 regs[8]);
+static inline unsigned long long native_read_pmc(int counter) +{
DECLARE_ARGS(val, low, high);
asm volatile("rdpmc" : EAX_EDX_RET(val, low, high) : "c"
(counter));
return EAX_EDX_VAL(val, low, high);
+}
+#ifdef CONFIG_PARAVIRT +#include <asm/paravirt.h> +#else +#include <errno.h> +/*
- Access to machine-specific registers (available on 586 and better only)
- Note: the rd* operations modify the parameters directly (without using
- pointer indirection), this allows gcc to optimize better
- */
+#define rdmsr(msr, val1, val2) \ +do { \
u64 __val = native_read_msr((msr)); \
(void)((val1) = (u32)__val); \
(void)((val2) = (u32)(__val >> 32)); \
+} while (0)
+static inline void wrmsr(unsigned msr, unsigned low, unsigned high) +{
native_write_msr(msr, low, high);
+}
+#define rdmsrl(msr, val) \
((val) = native_read_msr((msr)))
+#define wrmsrl(msr, val) \
native_write_msr((msr), (u32)((u64)(val)), (u32)((u64)(val) >> 32))
+/* rdmsr with exception handling */ +#define rdmsr_safe(msr, p1, p2) \ +({ \
int __err; \
u64 __val = native_read_msr_safe((msr), &__err); \
(*p1) = (u32)__val; \
(*p2) = (u32)(__val >> 32); \
__err; \
+})
+static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) +{
u32 gprs[8] = { 0 };
int err;
gprs[1] = msr;
gprs[7] = 0x9c5a203a;
err = native_rdmsr_safe_regs(gprs);
*p = gprs[0] | ((u64)gprs[2] << 32);
return err;
+}
+static inline int wrmsrl_amd_safe(unsigned msr, unsigned long long val) +{
u32 gprs[8] = { 0 };
gprs[0] = (u32)val;
gprs[1] = msr;
gprs[2] = val >> 32;
gprs[7] = 0x9c5a203a;
return native_wrmsr_safe_regs(gprs);
+}
+static inline int rdmsr_safe_regs(u32 regs[8]) +{
return native_rdmsr_safe_regs(regs);
+}
+static inline int wrmsr_safe_regs(u32 regs[8]) +{
return native_wrmsr_safe_regs(regs);
+}
+#define rdtscl(low) \
((low) = (u32)__native_read_tsc())
+#define rdtscll(val) \
((val) = __native_read_tsc())
+#define rdpmc(counter, low, high) \ +do { \
u64 _l = native_read_pmc((counter)); \
(low) = (u32)_l; \
(high) = (u32)(_l >> 32); \
+} while (0)
+#define rdtscp(low, high, aux) \ +do { \
unsigned long long _val = native_read_tscp(&(aux)); \
(low) = (u32)_val; \
(high) = (u32)(_val >> 32); \
+} while (0)
+#define rdtscpll(val, aux) (val) = native_read_tscp(&(aux))
+#endif /* !CONFIG_PARAVIRT */
+#define checking_wrmsrl(msr, val) wrmsr_safe((msr), (u32)(val), \
(u32)((val) >> 32))
+#define write_tsc(val1, val2) wrmsr(MSR_IA32_TSC, (val1), (val2))
+#define write_rdtscp_aux(val) wrmsr(MSR_TSC_AUX, (val), 0)
+struct msr *msrs_alloc(void); +void msrs_free(struct msr *msrs);
+#ifdef CONFIG_SMP +int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); +int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); +void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); +void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); +int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); +int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); +int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); +int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]);
+#endif /* CONFIG_SMP */ +#endif /* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_X86_MSR_H */ diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h new file mode 100644 index 0000000..b75203c --- /dev/null +++ b/arch/x86/include/asm/mtrr.h @@ -0,0 +1,203 @@ +/* Generic MTRR (Memory Type Range Register) ioctls.
- Copyright (C) 1997-1999 Richard Gooch
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with this library; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- Richard Gooch may be reached by email at rgooch@atnf.csiro.au
- The postal address is:
Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121,
Australia. +*/ +#ifndef _ASM_X86_MTRR_H +#define _ASM_X86_MTRR_H
+#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg)) +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1)
+#ifndef __ASSEMBLY__
+#include <linux/types.h> +#include <linux/ioctl.h> +#include <errno.h>
+#define MTRR_IOCTL_BASE 'M'
+struct mtrr_sentry {
unsigned long base; /* Base address */
unsigned int size; /* Size of region */
unsigned int type; /* Type of region */
+};
+/*
- Warning: this structure has a different order from i386
- on x86-64. The 32bit emulation code takes care of that.
- But you need to use this for 64bit, otherwise your X server
- will break.
- */
+#ifdef __i386__ +struct mtrr_gentry {
unsigned int regnum; /* Register number */
unsigned long base; /* Base address */
unsigned int size; /* Size of region */
unsigned int type; /* Type of region */
+};
+#else /* __i386__ */
+struct mtrr_gentry {
unsigned long base; /* Base address */
unsigned int size; /* Size of region */
unsigned int regnum; /* Register number */
unsigned int type; /* Type of region */
+}; +#endif /* !__i386__ */
+struct mtrr_var_range {
__u32 base_lo;
__u32 base_hi;
__u32 mask_lo;
__u32 mask_hi;
+};
+/*
- In the Intel processor's MTRR interface, the MTRR type is always held
in
- an 8 bit field:
- */
+typedef __u8 mtrr_type;
+#define MTRR_NUM_FIXED_RANGES 88 +#define MTRR_MAX_VAR_RANGES 256
+struct mtrr_state_type {
struct mtrr_var_range var_ranges[MTRR_MAX_VAR_RANGES];
mtrr_type fixed_ranges[MTRR_NUM_FIXED_RANGES];
unsigned char enabled;
unsigned char have_fixed;
mtrr_type def_type;
+};
+/* These are the various ioctls */ +#define MTRRIOC_ADD_ENTRY _IOW(MTRR_IOCTL_BASE, 0, struct mtrr_sentry) +#define MTRRIOC_SET_ENTRY _IOW(MTRR_IOCTL_BASE, 1, struct mtrr_sentry) +#define MTRRIOC_DEL_ENTRY _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry) +#define MTRRIOC_GET_ENTRY _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry) +#define MTRRIOC_KILL_ENTRY _IOW(MTRR_IOCTL_BASE, 4, struct mtrr_sentry) +#define MTRRIOC_ADD_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 5, struct mtrr_sentry) +#define MTRRIOC_SET_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 6, struct mtrr_sentry) +#define MTRRIOC_DEL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 7, struct mtrr_sentry) +#define MTRRIOC_GET_PAGE_ENTRY _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry) +#define MTRRIOC_KILL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 9, struct mtrr_sentry)
+/* These are the region types */ +#define MTRR_TYPE_UNCACHABLE 0 +#define MTRR_TYPE_WRCOMB 1 +/*#define MTRR_TYPE_ 2*/ +/*#define MTRR_TYPE_ 3*/ +#define MTRR_TYPE_WRTHROUGH 4 +#define MTRR_TYPE_WRPROT 5 +#define MTRR_TYPE_WRBACK 6 +#define MTRR_NUM_TYPES 7
+#ifdef __KERNEL__
+/* The following functions are for use by other drivers */ +# ifdef CONFIG_MTRR +extern u8 mtrr_type_lookup(u64 addr, u64 end); +extern void mtrr_save_fixed_ranges(void *); +extern void mtrr_save_state(void); +extern int mtrr_add(unsigned long base, unsigned long size,
unsigned int type, bool increment);
+extern int mtrr_add_page(unsigned long base, unsigned long size,
unsigned int type, bool increment);
+extern int mtrr_del(int reg, unsigned long base, unsigned long size); +extern int mtrr_del_page(int reg, unsigned long base, unsigned long size); +extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); +extern void mtrr_ap_init(void); +extern void mtrr_bp_init(void); +extern void set_mtrr_aps_delayed_init(void); +extern void mtrr_aps_init(void); +extern void mtrr_bp_restore(void); +extern int mtrr_trim_uncached_memory(unsigned long end_pfn); +extern int amd_special_default_mtrr(void); +# else +static inline u8 mtrr_type_lookup(u64 addr, u64 end) +{
/*
* Return no-MTRRs:
*/
return 0xff;
+} +#define mtrr_save_fixed_ranges(arg) do {} while (0) +#define mtrr_save_state() do {} while (0) +static inline int mtrr_del(int reg, unsigned long base, unsigned long size) +{
return -ENODEV;
+} +static inline int mtrr_del_page(int reg, unsigned long base, unsigned long size) +{
return -ENODEV;
+} +static inline int mtrr_trim_uncached_memory(unsigned long end_pfn) +{
return 0;
+} +static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) +{ +}
+#define mtrr_ap_init() do {} while (0) +#define mtrr_bp_init() do {} while (0) +#define set_mtrr_aps_delayed_init() do {} while (0) +#define mtrr_aps_init() do {} while (0) +#define mtrr_bp_restore() do {} while (0) +# endif
+#ifdef CONFIG_COMPAT +#include <linux/compat.h>
+struct mtrr_sentry32 {
compat_ulong_t base; /* Base address */
compat_uint_t size; /* Size of region */
compat_uint_t type; /* Type of region */
+};
+struct mtrr_gentry32 {
compat_ulong_t regnum; /* Register number */
compat_uint_t base; /* Base address */
compat_uint_t size; /* Size of region */
compat_uint_t type; /* Type of region */
+};
+#define MTRR_IOCTL_BASE 'M'
+#define MTRRIOC32_ADD_ENTRY _IOW(MTRR_IOCTL_BASE, 0, struct mtrr_sentry32) +#define MTRRIOC32_SET_ENTRY _IOW(MTRR_IOCTL_BASE, 1, struct mtrr_sentry32) +#define MTRRIOC32_DEL_ENTRY _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry32) +#define MTRRIOC32_GET_ENTRY _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry32) +#define MTRRIOC32_KILL_ENTRY _IOW(MTRR_IOCTL_BASE, 4, struct mtrr_sentry32) +#define MTRRIOC32_ADD_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 5, struct mtrr_sentry32) +#define MTRRIOC32_SET_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 6, struct mtrr_sentry32) +#define MTRRIOC32_DEL_PAGE_ENTRY _IOW(MTRR_IOCTL_BASE, 7, struct mtrr_sentry32) +#define MTRRIOC32_GET_PAGE_ENTRY _IOWR(MTRR_IOCTL_BASE, 8, struct mtrr_gentry32) +#define MTRRIOC32_KILL_PAGE_ENTRY \
_IOW(MTRR_IOCTL_BASE, 9, struct
mtrr_sentry32) +#endif /* CONFIG_COMPAT */
+#endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_X86_MTRR_H */
1.7.7.6

Hi Stefan,
On Thu, Oct 25, 2012 at 8:15 AM, Stefan Reinauer reinauer@google.com wrote:
Graeme,
Reusing code from the Linux kernel is generally a great idea. However for simplicity I'd rather have 25 lines than 870 lines for reading MSRs. It seems a lot of code in those files doesn't really apply for u-boot
Understood, however the code I extracted from the Linux kernel: - Makes it more likely that all the corner cases have been dealt with - Brings in all the 'magic numbers' for a wide range of CPUs, thus avoiding a continuing stream of patches (pulling them in from the Linux kernel code) - Includes MTTR functions and defines. I know coreboot is doing the memory init, but coreboot will not always be the only way to launch U-Boot and MTTRs will be needed - It's simply easier to keep synchronising with the Linux kernel when new defines and/or functions get added/removed/modified - I doubt it increases the compiled code size, and if it does, there's probably a good reason for it (corner cases)
Regards,
Graeme

Hi Graeme,
On Wed, Oct 24, 2012 at 3:22 PM, Graeme Russ graeme.russ@gmail.com wrote:
Hi Stefan,
On Thu, Oct 25, 2012 at 8:15 AM, Stefan Reinauer reinauer@google.com wrote:
Graeme,
Reusing code from the Linux kernel is generally a great idea. However for simplicity I'd rather have 25 lines than 870 lines for reading MSRs. It seems a lot of code in those files doesn't really apply for u-boot
Understood, however the code I extracted from the Linux kernel:
- Makes it more likely that all the corner cases have been dealt with
- Brings in all the 'magic numbers' for a wide range of CPUs, thus
avoiding a continuing stream of patches (pulling them in from the Linux kernel code)
- Includes MTTR functions and defines. I know coreboot is doing the
memory init, but coreboot will not always be the only way to launch U-Boot and MTTRs will be needed
- It's simply easier to keep synchronising with the Linux kernel when
new defines and/or functions get added/removed/modified
- I doubt it increases the compiled code size, and if it does,
there's probably a good reason for it (corner cases)
Thanks for your comments.
I will bring in the full MTTR implementation from your patch. However, first I need to test it and integrate with everything else here. So it might take me a few weeks to get everything straight again.
I have one more lot of x86 patches queued up (about 20 patches), so I will send these out based on what is there now. One of them does use MTRR but it may be independent of this change anyway. More testing will tell.
My initial goal is to get mainline booting properly on several x86 Chromebooks, using coreboot.
We also need to address moving coreboot code into a library directory or whatever.
Regards, Simon
Regards,
Graeme

From: Stefan Reinauer reinauer@chromium.org
This cleans up the rom caching optimization implemented in coreboot (and needed throughout U-Boot runtime).
Signed-off-by: Stefan Reinauer reinauer@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/cpu/coreboot/coreboot.c | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c index b942a3e..d1be8ff 100644 --- a/arch/x86/cpu/coreboot/coreboot.c +++ b/arch/x86/cpu/coreboot/coreboot.c @@ -26,6 +26,8 @@ #include <asm/u-boot-x86.h> #include <flash.h> #include <netdev.h> +#include <asm/msr.h> +#include <asm/cache.h> #include <asm/arch-coreboot/tables.h> #include <asm/arch-coreboot/sysinfo.h> #include <asm/arch/timestamp.h> @@ -89,3 +91,19 @@ int board_eth_init(bd_t *bis) void setup_pcat_compatibility() { } + +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg)) +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) + +int board_final_cleanup(void) +{ + /* Un-cache the ROM so the kernel has one + * more MTRR available. + */ + disable_cache(); + wrmsr(MTRRphysBase_MSR(7), 0); + wrmsr(MTRRphysMask_MSR(7), 0); + enable_cache(); + + return 0; +}

This fixes the following warning:
zimage.c:312: Warning: indirect jmp without `*'
Also fixed these warnings to keep checkpatch quiet:
warning: arch/x86/lib/zimage.c,311: unnecessary whitespace before a quoted newline warning: arch/x86/lib/zimage.c,312: unnecessary whitespace before a quoted newline warning: arch/x86/lib/zimage.c,313: unnecessary whitespace before a quoted newline
Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/lib/zimage.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index a1366a1..7661a58 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -308,9 +308,9 @@ void boot_zimage(void *setup_base, void *load_address) * itself in arch/i386/cpu/cpu.c. */ __asm__ __volatile__ ( - "movl $0, %%ebp \n" - "cli \n" - "jmp %[kernel_entry] \n" + "movl $0, %%ebp\n" + "cli\n" + "jmp *%[kernel_entry]\n" :: [kernel_entry]"a"(load_address), [boot_params] "S"(setup_base), "b"(0), "D"(0)

Hi Simon,
On Wed, Oct 24, 2012 at 3:04 PM, Simon Glass sjg@chromium.org wrote:
This fixes the following warning:
zimage.c:312: Warning: indirect jmp without `*'
Also fixed these warnings to keep checkpatch quiet:
warning: arch/x86/lib/zimage.c,311: unnecessary whitespace before a quoted newline warning: arch/x86/lib/zimage.c,312: unnecessary whitespace before a quoted newline warning: arch/x86/lib/zimage.c,313: unnecessary whitespace before a quoted newline
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/zimage.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c index a1366a1..7661a58 100644 --- a/arch/x86/lib/zimage.c +++ b/arch/x86/lib/zimage.c @@ -308,9 +308,9 @@ void boot_zimage(void *setup_base, void *load_address) * itself in arch/i386/cpu/cpu.c. */ __asm__ __volatile__ (
"movl $0, %%ebp \n"
"cli \n"
"jmp %[kernel_entry] \n"
"movl $0, %%ebp\n"
"cli\n"
"jmp *%[kernel_entry]\n" :: [kernel_entry]"a"(load_address), [boot_params] "S"(setup_base), "b"(0), "D"(0)
To be honest, I have never liked this implementation. I can't find it, but I did have a patch that moved this into a function defined in a .S file - much cleaner.
I'll have a poke around and see if I can find it again
Regards,
Graeme

Enable this option to support booting a zImage.
Signed-off-by: Simon Glass sjg@chromium.org --- include/configs/coreboot.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h index 78a34b8..9222ca9 100644 --- a/include/configs/coreboot.h +++ b/include/configs/coreboot.h @@ -148,6 +148,8 @@ #define CONFIG_CMD_EXT2 #define CONFIG_CMD_EXT4
+#define CONFIG_CMD_ZBOOT + #define CONFIG_BOOTDELAY 2 #define CONFIG_BOOTARGS "root=/dev/mtdblock0 console=ttyS0,9600"

From: Duncan Laurie dlaurie@chromium.org
U-boot is unable to actually use that memory and it can cause problems with relocation if it tries to.
Signed-off-by: Duncan Laurie dlaurie@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/cpu/coreboot/sdram.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/arch/x86/cpu/coreboot/sdram.c b/arch/x86/cpu/coreboot/sdram.c index 93dccb8..5d3da99 100644 --- a/arch/x86/cpu/coreboot/sdram.c +++ b/arch/x86/cpu/coreboot/sdram.c @@ -60,6 +60,10 @@ int dram_init_f(void) struct memrange *memrange = &lib_sysinfo.memrange[i]; unsigned long long end = memrange->base + memrange->size;
+ /* Ignore memory over 4GB, we can't use it. */ + if (memrange->base > 0xffffffff) + continue; + if (memrange->type == CB_MEM_RAM && end > ram_size) ram_size = end; }

From: Duncan Laurie dlaurie@chromium.org
The use of post-increment with a do-while loop results in the loop going one step too far when handling relocation fixups.
In about 1/100 cases this would cause it to hang.
Signed-off-by: Duncan Laurie dlaurie@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/lib/relocate.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index 200baab..c0b9b29 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -85,7 +85,7 @@ int do_elf_reloc_fixups(void) *offset_ptr_ram += gd->reloc_off; } } - } while (re_src++ < re_end); + } while (++re_src < re_end);
return 0; }

From: Gabe Black gabeblack@chromium.org
These types should be 64 bits long to reflect the fact that physical addresses and the size of physical areas of memory are more than 32 bits long.
Signed-off-by: Gabe Black gabeblack@chromium.org Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/include/asm/io.h | 6 ++++-- arch/x86/include/asm/types.h | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index 84a638d..86bac90 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -1,6 +1,8 @@ #ifndef _ASM_IO_H #define _ASM_IO_H
+#include <compiler.h> + /* * This file contains the definitions for the x86 IO instructions * inb/inw/inl/outb/outw/outl and the "string versions" of the same @@ -220,7 +222,7 @@ static inline void sync(void) static inline void * map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) { - return (void *)paddr; + return (void *)(uintptr_t)paddr; }
/* @@ -233,7 +235,7 @@ static inline void unmap_physmem(void *vaddr, unsigned long flags)
static inline phys_addr_t virt_to_phys(void * vaddr) { - return (phys_addr_t)(vaddr); + return (phys_addr_t)(uintptr_t)(vaddr); }
/* diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h index 9a40e38..e9fde88 100644 --- a/arch/x86/include/asm/types.h +++ b/arch/x86/include/asm/types.h @@ -45,8 +45,8 @@ typedef unsigned long long u64;
typedef u32 dma_addr_t;
-typedef unsigned long phys_addr_t; -typedef unsigned long phys_size_t; +typedef unsigned long long phys_addr_t; +typedef unsigned long long phys_size_t;
#endif /* __KERNEL__ */

From: Gabe Black gabeblack@chromium.org
The default implementation of this function is just memset, but other implementations will be needed when physical memory isn't accessible by U-Boot using normal addressing mechanisms.
Signed-off-by: Gabe Black gabeblack@chromium.org
Signed-off-by: Simon Glass sjg@chromium.org --- include/physmem.h | 21 +++++++++++++++++++++ lib/physmem.c | 24 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 0 deletions(-) create mode 100644 include/physmem.h create mode 100644 lib/physmem.c
diff --git a/include/physmem.h b/include/physmem.h new file mode 100644 index 0000000..03d3a78 --- /dev/null +++ b/include/physmem.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +/* + * These functions work like memset but operate on physical memory which may + * not be accessible directly. + * + * @param s The physical address to start setting memory at. + * @param c The character to set each byte of the region to. + * @param n The number of bytes to set. + * + * @return The physical address of the memory which was set. + */ +phys_addr_t arch_phys_memset(phys_addr_t s, int c, phys_size_t n); diff --git a/lib/physmem.c b/lib/physmem.c new file mode 100644 index 0000000..0f035ed --- /dev/null +++ b/lib/physmem.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +#include <common.h> +#include <physmem.h> + +static phys_addr_t __arch_phys_memset(phys_addr_t s, int c, phys_size_t n) +{ + void *s_ptr = (void *)(uintptr_t)s; + + assert(((phys_addr_t)(uintptr_t)s) == s); + assert(((phys_addr_t)(uintptr_t)(s + n)) == s + n); + return (phys_addr_t)(uintptr_t)memset(s_ptr, c, n); +} + +phys_addr_t arch_phys_memset(phys_addr_t s, int c, phys_size_t n) + __attribute__((weak, alias("__arch_phys_memset")));

From: Gabe Black gabeblack@chromium.org
Implement arch_phys_memset so that it can set memory at physical addresses above 4GB using PAE paging. Because there are only 5 page tables in PAE mode, 1 PDPT and 4 PDTs, those tables are statically allocated in the BSS. The tables must be 4K page aligned and are declared that way, and because U-Boot starts as 4K aligned and the relocation code relocates it to a 4K aligned address, the tables work as intended.
While paging is turned on, all 4GB are identity mapped except for one 2MB page which is used as the window into high memory. This way, U-Boot will continue to work as expected when running code that expects to access memory freely, but the code can still get at high memory through its window.
The window is put at 2MB so that it's 2MB page aligned, low in memory to be out of the way of things U-Boot is likely to care about, and above the lowest 1MB where lots of random things live.
Signed-off-by: Gabe Black gabeblack@chromium.org
Signed-off-by: Simon Glass sjg@chromium.org --- arch/x86/lib/Makefile | 1 + arch/x86/lib/physmem.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+), 0 deletions(-) create mode 100644 arch/x86/lib/physmem.c
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 1cb9155..ddd91c9 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -47,6 +47,7 @@ COBJS-$(CONFIG_SYS_GENERIC_TIMER) += pcat_timer.o COBJS-$(CONFIG_PCI) += pci.o COBJS-$(CONFIG_PCI) += pci_type1.o COBJS-y += relocate.o +COBJS-y += physmem.o COBJS-y += string.o COBJS-$(CONFIG_SYS_X86_ISR_TIMER) += timer.o COBJS-$(CONFIG_VIDEO) += video.o diff --git a/arch/x86/lib/physmem.c b/arch/x86/lib/physmem.c new file mode 100644 index 0000000..18f0e62 --- /dev/null +++ b/arch/x86/lib/physmem.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +#include <common.h> +#include <physmem.h> +#include <linux/compiler.h> + +/* Large pages are 2MB. */ +#define LARGE_PAGE_SIZE ((1 << 20) * 2) + +/* + * Paging data structures. + */ + +struct pdpe { + uint64_t p:1; + uint64_t mbz_0:2; + uint64_t pwt:1; + uint64_t pcd:1; + uint64_t mbz_1:4; + uint64_t avl:3; + uint64_t base:40; + uint64_t mbz_2:12; +}; + +typedef struct pdpe pdpt_t[512]; + +struct pde { + uint64_t p:1; /* present */ + uint64_t rw:1; /* read/write */ + uint64_t us:1; /* user/supervisor */ + uint64_t pwt:1; /* page-level writethrough */ + uint64_t pcd:1; /* page-level cache disable */ + uint64_t a:1; /* accessed */ + uint64_t d:1; /* dirty */ + uint64_t ps:1; /* page size */ + uint64_t g:1; /* global page */ + uint64_t avl:3; /* available to software */ + uint64_t pat:1; /* page-attribute table */ + uint64_t mbz_0:8; /* must be zero */ + uint64_t base:31; /* base address */ +}; + +typedef struct pde pdt_t[512]; + +static pdpt_t pdpt __aligned(4096); +static pdt_t pdts[4] __aligned(4096); + +/* + * Map a virtual address to a physical address and optionally invalidate any + * old mapping. + * + * @param virt The virtual address to use. + * @param phys The physical address to use. + * @param invlpg Whether to use invlpg to clear any old mappings. + */ +static void x86_phys_map_page(uintptr_t virt, phys_addr_t phys, int invlpg) +{ + /* Extract the two bit PDPT index and the 9 bit PDT index. */ + uintptr_t pdpt_idx = (virt >> 30) & 0x3; + uintptr_t pdt_idx = (virt >> 21) & 0x1ff; + + /* Set up a handy pointer to the appropriate PDE. */ + struct pde *pde = &(pdts[pdpt_idx][pdt_idx]); + + memset(pde, 0, sizeof(struct pde)); + pde->p = 1; + pde->rw = 1; + pde->us = 1; + pde->ps = 1; + pde->base = phys >> 21; + + if (invlpg) { + /* Flush any stale mapping out of the TLBs. */ + __asm__ __volatile__( + "invlpg %0\n\t" + : + : "m" (*(uint8_t *)virt) + ); + } +} + +/* Identity map the lower 4GB and turn on paging with PAE. */ +static void x86_phys_enter_paging(void) +{ + phys_addr_t page_addr; + unsigned i; + + /* Zero out the page tables. */ + memset(pdpt, 0, sizeof(pdpt)); + memset(pdts, 0, sizeof(pdts)); + + /* Set up the PDPT. */ + for (i = 0; i < ARRAY_SIZE(pdts); i++) { + pdpt[i].p = 1; + pdpt[i].base = ((uintptr_t)&pdts[i]) >> 12; + } + + /* Identity map everything up to 4GB. */ + for (page_addr = 0; page_addr < (1ULL << 32); + page_addr += LARGE_PAGE_SIZE) { + /* There's no reason to invalidate the TLB with paging off. */ + x86_phys_map_page(page_addr, page_addr, 0); + } + + /* Turn on paging */ + __asm__ __volatile__( + /* Load the page table address */ + "movl %0, %%cr3\n\t" + /* Enable pae */ + "movl %%cr4, %%eax\n\t" + "orl $0x00000020, %%eax\n\t" + "movl %%eax, %%cr4\n\t" + /* Enable paging */ + "movl %%cr0, %%eax\n\t" + "orl $0x80000000, %%eax\n\t" + "movl %%eax, %%cr0\n\t" + : + : "r" (pdpt) + : "eax" + ); +} + +/* Disable paging and PAE mode. */ +static void x86_phys_exit_paging(void) +{ + /* Turn off paging */ + __asm__ __volatile__ ( + /* Disable paging */ + "movl %%cr0, %%eax\n\t" + "andl $0x7fffffff, %%eax\n\t" + "movl %%eax, %%cr0\n\t" + /* Disable pae */ + "movl %%cr4, %%eax\n\t" + "andl $0xffffffdf, %%eax\n\t" + "movl %%eax, %%cr4\n\t" + : + : + : "eax" + ); +} + +/* + * Set physical memory to a particular value when the whole region fits on one + * page. + * + * @param map_addr The address that starts the physical page. + * @param offset How far into that page to start setting a value. + * @param c The value to set memory to. + * @param size The size in bytes of the area to set. + */ +static void x86_phys_memset_page(phys_addr_t map_addr, uintptr_t offset, int c, + unsigned size) +{ + /* + * U-Boot should be far away from the beginning of memory, so that's a + * good place to map our window on top of. + */ + const uintptr_t window = LARGE_PAGE_SIZE; + + /* Make sure the window is below U-Boot. */ + assert(window + LARGE_PAGE_SIZE < + gd->relocaddr - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_STACK_SIZE); + /* Map the page into the window and then memset the appropriate part. */ + x86_phys_map_page(window, map_addr, 1); + memset((void *)(window + offset), c, size); +} + +/* + * A physical memory anologue to memset with matching parameters and return + * value. + */ +phys_addr_t arch_phys_memset(phys_addr_t start, int c, phys_size_t size) +{ + const phys_addr_t max_addr = (phys_addr_t)~(uintptr_t)0; + const phys_addr_t orig_start = start; + + if (!size) + return orig_start; + + /* Handle memory below 4GB. */ + if (start <= max_addr) { + phys_size_t low_size = MIN(max_addr + 1 - start, size); + void *start_ptr = (void *)(uintptr_t)start; + + assert(((phys_addr_t)(uintptr_t)start) == start); + memset(start_ptr, c, low_size); + start += low_size; + size -= low_size; + } + + /* Use paging and PAE to handle memory above 4GB up to 64GB. */ + if (size) { + phys_addr_t map_addr = start & ~(LARGE_PAGE_SIZE - 1); + phys_addr_t offset = start - map_addr; + + x86_phys_enter_paging(); + + /* Handle the first partial page. */ + if (offset) { + phys_addr_t end = + MIN(map_addr + LARGE_PAGE_SIZE, start + size); + phys_size_t cur_size = end - start; + x86_phys_memset_page(map_addr, offset, c, cur_size); + size -= cur_size; + map_addr += LARGE_PAGE_SIZE; + } + /* Handle the complete pages. */ + while (size > LARGE_PAGE_SIZE) { + x86_phys_memset_page(map_addr, 0, c, LARGE_PAGE_SIZE); + size -= LARGE_PAGE_SIZE; + map_addr += LARGE_PAGE_SIZE; + } + /* Handle the last partial page. */ + if (size) + x86_phys_memset_page(map_addr, 0, c, size); + + x86_phys_exit_paging(); + } + return orig_start; +}
participants (3)
-
Graeme Russ
-
Simon Glass
-
Stefan Reinauer