| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,313 @@ | ||
| # Intel DPTF implementations in coreboot | ||
|
|
||
| ## Introduction | ||
|
|
||
| Intel Dynamic Platform and Thermal Framework is a framework that can be used to | ||
| help regulate the thermal properties (i.e., temperature) of an Intel-based | ||
| computer. It does this by allowing the system designer to specify the different | ||
| components that can generate heat, and/or dissipate heat. Under DPTF, the | ||
| different components are referred to as `participants`. The different types of | ||
| functionality available in DPTF are specified in terms of different `policies`. | ||
|
|
||
| ## Components ("Participants") | ||
|
|
||
| The participants that can be involved in the current implementation are: | ||
| - CPU (monolithic from a DPTF point-of-view) | ||
| - Note that the CPU's internal temperature sensor is used here | ||
| - 1 fan | ||
| - Up to 4 temperature sensors (TSRs) | ||
| - Battery charger | ||
|
|
||
| ## Policies | ||
|
|
||
| In the current implementation, there are 3 different policies available: | ||
|
|
||
| ### Passive Policy | ||
|
|
||
| The purpose of this policy is to monitor participant temperatures and is capable | ||
| of controlling performance and throttling available on platform devices in order | ||
| to regulate the temperatures of each participant. The temperature threshold | ||
| points are defined by a `_PSV` ACPI object within each participant. | ||
|
|
||
| ### Critical Policy | ||
|
|
||
| The Critical Policy is used for gracefully suspending or powering off the system | ||
| when the temperature of participants exceeds critical threshold | ||
| temperatures. Suspend is effected by specifying temperatures in a `_CRT` object | ||
| for a participant, and poweroff is effected by specifying a temperature | ||
| threshold in a `_HOT` ACPI object. | ||
|
|
||
| ### Active Policy | ||
|
|
||
| This policy monitors the temperature of participants and controls fans to spin | ||
| at varying speeds. These speeds are defined by the platform, and will be enabled | ||
| depending on the various temperatures reported by participants. | ||
|
|
||
| # Note about units | ||
|
|
||
| ACPI uses unusual units for specifying various physical measurements. For | ||
| example, temperatures are specified in 10ths of a degree K, and time is measured | ||
| in tenths of a second. Those oddities are abstracted away in the DPTF library, | ||
| by using degrees C for temperature, milliseconds for time, mW for power, and mA | ||
| for current. | ||
|
|
||
| ## Differences from the static ASL files (soc/intel/common/acpi/dptf/*.asl) | ||
|
|
||
| 1) TCPU had many redundant methods. The many references to \_SB.CP00._* are not | ||
| created anymore in recent SoCs and the ACPI spec says these are optional objects | ||
| anyway. The defaults that were returned by these methods were redundant (all | ||
| data was a 0). The following Methods were removed: | ||
|
|
||
| * _TSS | ||
| * _TPC | ||
| * _PTC | ||
| * _TSD | ||
| * _TDL | ||
| * _PSS | ||
| * _PDL | ||
|
|
||
| 2) There is no more implicit inclusion of _ACn methods for TCPU (these must be | ||
| specified in the devicetree entries or by calling the DPTF acpigen API). | ||
|
|
||
| # ACPI Tables | ||
|
|
||
| DPTF relies on an assortment of ACPI tables to provide parameters to the DPTF | ||
| application. We will discuss the more important ones here. | ||
|
|
||
| 1) _TRT - Thermal Relationship Table | ||
|
|
||
| This table is used when the Passive Policy is enabled, and is used to represent | ||
| the thermal relationships in the system that can be controlled passively (i.e., | ||
| by throttling participants). A passive policy is defined by a Source (which | ||
| generates heat), a Target (typically a temperature sensor), a Sampling Period | ||
| (how often to check the temperature), an activation temperature threshold (for | ||
| when to begin throttling), and a relative priority. | ||
|
|
||
| 2) _ART - Active Relationship Table | ||
|
|
||
| This table is used when the Active Policy is enabled, and is used to represent | ||
| active cooling relationships (i.e., which TSRs the fan can cool). An active | ||
| policy contains a Target (the device the fan can cool), a Weight to control | ||
| which participant needs more attention than others, and a list of temperature / | ||
| fan percentage pairs. The list of pairs defines the fan control percentage that | ||
| should be applied when the TSR reaches each successive threshold (_AC0 is the | ||
| highest threshold, and represents the highest fan control percentage). | ||
|
|
||
| 3) PPCC - Participant Power Control Capabilities | ||
|
|
||
| This table is used to describe parameters for controlling the SoC's Running | ||
| Average Power Limits (RAPL, see below). | ||
|
|
||
| 4) _FPS - Fan Performance States | ||
|
|
||
| This table describes the various fan speeds available for DPTF to use, along with | ||
| various informational properties. | ||
|
|
||
| 5) PPSS - Participant Performance Supported States | ||
|
|
||
| This table describes performance states supported by a participant (typically | ||
| the battery charger). | ||
|
|
||
| # ACPI Methods | ||
|
|
||
| The Active and Passive policies also provide for short Methods to define | ||
| different kinds of temperature thresholds. | ||
|
|
||
| 1) _AC0, _AC1, _AC2, _AC3, ..., _AC9 | ||
|
|
||
| These Methods can provide up to 10 temperature thresholds. What these do is set | ||
| temperatures which act as the thresholds to active rows (fan speeds) in the | ||
| ART. _AC0 is intended to be the highest temperature thresholds, and the lowest | ||
| one can be any of them; leave the rest defined as 0 and they will be omitted | ||
| from the output. | ||
|
|
||
| These are optional and are enabled by selecting the Active Policy. | ||
|
|
||
| 2) _PSV | ||
|
|
||
| _PSV is a temperature threshold that is used to indicate to DPTF that it should | ||
| begin taking passive measures (i.e., throttling of the Source) in order to | ||
| reduce the temperature of the Target in question. It will check on the | ||
| temperature according to the given sampling period. | ||
|
|
||
| This is optional and is enabled by selecting the Passive Policy. | ||
|
|
||
| 3) _CRT and _HOT | ||
|
|
||
| When the temperature of the Source reaches the threshold specified in _CRT, then | ||
| the system is supposed to execute a "graceful suspend". Similarly, when the Source | ||
| reaches the temperature specified in _HOT, then the system is supposed to execute | ||
| a "graceful shutdown". | ||
|
|
||
| These are optional, and are enabled by selecting the Critical Policy. | ||
|
|
||
| # How to use the devicetree entries | ||
|
|
||
| The `drivers/intel/dptf` chip driver is organized into several sections: | ||
| - Policies | ||
| - Controls | ||
| - Options | ||
|
|
||
| The Policies section (`policies.active`, `policies.passive`, and | ||
| `policies.critical`) is where the components of each policy are defined. | ||
|
|
||
| ## Active Policy | ||
|
|
||
| Each Active Policy is defined in terms of 4 parts: | ||
| 1) A Source (this is implicitly defined as TFN1, the system fan) | ||
| 2) A Target (this is the device that can be affected by the policy, i.e., | ||
| this is a device that can be cooled by the fan) | ||
| 3) A 'Weight', which is defined as the Source's contribution to the Target's | ||
| cooling capability (as a percentage, 0-100, often just left at 100). | ||
| 4) A list of temperature-fan percentage pairs, which define temperature | ||
| thresholds that, when the Target reaches, the fan is defined to spin | ||
| at the corresponding percentage of full duty cycle. | ||
|
|
||
| An example definition in the devicetree: | ||
| ```C | ||
| register "policies.active[0]" = "{ | ||
| .target=DPTF_CPU, | ||
| .weight=100, | ||
| .thresholds={TEMP_PCT(85, 90), | ||
| TEMP_PCT(80, 69), | ||
| TEMP_PCT(75, 56), | ||
| TEMP_PCT(70, 46), | ||
| TEMP_PCT(65, 36),}}" | ||
| ``` | ||
|
|
||
| This example sets up a policy wherein the CPU temperature sensor can be cooled | ||
| by the fan. The 'weight' of this policy is 100% (this policy contributes 100% of | ||
| the CPU's active cooling capability). When the CPU temperature first crosses | ||
| 65C, the fan is defined to spin at 36% of its duty cycle, and so forth up the | ||
| rest of the table (note that it *must* be defined from highest temperature/ | ||
| percentage on down to the lowest). | ||
|
|
||
| ## Passive Policy | ||
|
|
||
| Each Passive Policy is defined in terms of 5 parts: | ||
| 1) Source - The device that can be throttled | ||
| 2) Target - The device that controls the amount of throttling | ||
| 3) Period - How often to check the temperature of the Target | ||
| 4) Trip point - What temperature threshold to start throttling | ||
| 5) Priority - A number indicating the relative priority between different | ||
| Policies | ||
|
|
||
| An example definition in the devicetree: | ||
| ```C | ||
| register "policies.passive[0]" = "DPTF_PASSIVE(CHARGER, TEMP_SENSOR_1, 65, 60000)" | ||
| ``` | ||
|
|
||
| This example sets up a policy to begin throttling the charger performance when | ||
| temperature sensor 1 reaches 65C. The sampling period here is 60000 ms (60 s). | ||
| The Priority is defaulted to 100 in this case. | ||
|
|
||
| ## Critical Policy | ||
|
|
||
| Each Critical Policy is defined in terms of 3 parts: | ||
| 1) Source - A device that can trigger a critical event | ||
| 2) Type - What type of critical event to trigger (S4-entry or shutdown) | ||
| 3) Temperature - The temperature threshold that will cause the entry into S4 or | ||
| to shutdown the system. | ||
|
|
||
| An example definition in the devicetree: | ||
|
|
||
| ```C | ||
| register "policies.critical[1]" = "DPTF_CRITICAL(CPU, 75, SHUTDOWN)" | ||
| ``` | ||
|
|
||
| This example sets up a policy wherein ACPI will cause the system to shutdown | ||
| (in a "graceful" manner) when the CPU temperature reaches 75C. | ||
|
|
||
| ## Power Limits | ||
|
|
||
| Control over the SoC's Running Average Power Limits (RAPL) is one of the tools | ||
| that DPTF uses to enact Passive policies. DPTF can control both PL1 and PL2, if | ||
| the PPCC table is provided for the TCPU object. Each power limit is given the | ||
| following options: | ||
| 1) Minimum power (in mW) | ||
| 2) Maximum power (in mW) | ||
| 3) Minimum time window (in ms) | ||
| 4) Maximum time window (in ms) | ||
| 5) Granularity, or minimum step size to control limits (in mW) | ||
|
|
||
| An example: | ||
| ```C | ||
| register "controls.power_limits.pl1" = "{ | ||
| .min_power = 3000, | ||
| .max_power = 15000, | ||
| .time_window_min = 28 * MSECS_PER_SEC, | ||
| .time_window_max = 32 * MSECS_PER_SEC, | ||
| .granularity = 200,}" | ||
| ``` | ||
|
|
||
| This example allow DPTF to control the SoC's PL1 level to between 3W and 15W, | ||
| over a time interval ranging from 28 to 32 seconds, and it can move PL1 in | ||
| increments of 200 mW. | ||
|
|
||
| ## Charger Performance | ||
|
|
||
| The battery charger can be a large contributor of unwanted heat in a system that | ||
| has one. Controlling the rate of charging is another tool that DPTF uses to enact | ||
| Passive Policies. Each entry in the PPSS table consists of: | ||
| 1) A 'Control' value - an opaque value that the platform firmware uses | ||
| to initiate a transition to the specified performance state. DPTF will call an | ||
| ACPI method called `TCHG.SPPC` (Set Participant Performance Capability) if | ||
| applicable, and will pass this opaque control value as its argument. | ||
| 2) The intended charging rate (in mA). | ||
|
|
||
| Example: | ||
| ```C | ||
| register "controls.charger_perf[0]" = "{ 255, 1700 }" | ||
| register "controls.charger_perf[1]" = "{ 24, 1500 }" | ||
| register "controls.charger_perf[2]" = "{ 16, 1000 }" | ||
| register "controls.charger_perf[3]" = "{ 8, 500 }" | ||
| ``` | ||
|
|
||
| In this example, when DPTF decides to throttle the charger, it has four different | ||
| performance states to choose from. | ||
|
|
||
| ## Fan Performance | ||
|
|
||
| When using DPTF, the system fan (`TFN1`) is the device responsible for actively | ||
| cooling the other temperature sensors on the mainboard. A fan speed table can be | ||
| provided to DPTF to assist with fan control. Each entry holds the following: | ||
| 1) Percentage of full duty to spin the fan at | ||
| 2) Speed - Speed of the fan at that percentage; informational only, but given in | ||
| RPM | ||
| 3) Noise - Amount of noise created by the fan at that percentage; informational | ||
| only, but given in tenths of a decibel (centibel). | ||
| 4) Power - Amount of power consumed by the fan at that percentage; informational | ||
| only, but given in mA. | ||
|
|
||
| Example: | ||
| ```C | ||
| register "controls.fan_perf[0]" = "{ 90, 6700, 220, 2200, }" | ||
| register "controls.fan_perf[1]" = "{ 80, 5800, 180, 1800, }" | ||
| register "controls.fan_perf[2]" = "{ 70, 5000, 145, 1450, }" | ||
| register "controls.fan_perf[3]" = "{ 60, 4900, 115, 1150, }" | ||
| register "controls.fan_perf[4]" = "{ 50, 3838, 90, 900, }" | ||
| register "controls.fan_perf[5]" = "{ 40, 2904, 55, 550, }" | ||
| register "controls.fan_perf[6]" = "{ 30, 2337, 30, 300, }" | ||
| register "controls.fan_perf[7]" = "{ 20, 1608, 15, 150, }" | ||
| register "controls.fan_perf[8]" = "{ 10, 800, 10, 100, }" | ||
| register "controls.fan_perf[9]" = "{ 0, 0, 0, 50, }" | ||
| ``` | ||
|
|
||
| In this example, the fan has 10 different performance states, each in an even | ||
| increment of 10 percentage points. This is common when specifying fine-grained | ||
| control of the fan, wherein DPTF will interpolate between the percentages in the | ||
| table for a given temperature threshold. | ||
|
|
||
| ## Options | ||
|
|
||
| ### Fan | ||
| 1) Fine-grained control - a boolean (see Fan Performance section above) | ||
| 2) Step-size - Recommended minimum step size (in percentage points) to adjust | ||
| the fan speed when using fine-grained control (ranges from 1 - 9). | ||
| 3) Low-speed notify - If true, the platform will issue a `Notify (0x80)` to the | ||
| fan device if a low fan speed is detected. | ||
|
|
||
| ### Temperature sensors | ||
| 1) Hysteresis - The amount of hysteresis implemented in either circuitry or | ||
| the firmware that reads the temperature sensor (in degrees C). | ||
| 2) Name - This name is applied to the _STR property of the sensor |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # ThinkPad Lenovo X230s | ||
|
|
||
| ## Disassembly Instructions | ||
|
|
||
| You must remove the following parts to access the SPI flash chip: | ||
|
|
||
|  | ||
|
|
||
| * Base cover | ||
|
|
||
| The [Hardware Maintenance Manual](https://download.lenovo.com/ibmdl/pub/pc/pccbbs/ | ||
| mobiles_pdf/x230s_hmm_en_0c10860_01.pdf) could be used as a guidance of disassembly. | ||
|
|
||
| The SPI flash chip (W25Q128.V in the form of SOIC-8 for the author's X230s, but varying is possible) | ||
| is located at the circled place. | ||
|
|
||
| Unlike [most Ivy Bridge ThinkPads](Ivy_Bridge_series.md), X230s has a single 16MiB SPI flash chip. | ||
|
|
||
| The general [flashing tutorial](../../flash_tutorial/index.md) has more details. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| # OCP Delta Lake | ||
|
|
||
| This page describes coreboot support status for the [OCP] (Open Compute Project) | ||
| Delta Lake server platform. | ||
|
|
||
| ## Introduction | ||
|
|
||
| OCP Delta Lake server platform is a component of multi-host server system | ||
| Yosemite-V3. Both were announced by Facebook and Intel in [OCP virtual summit 2020]. | ||
|
|
||
| Delta Lake server is a single socket Cooper Lake Scalable Processor server. | ||
|
|
||
| Yosemite-V3 has multiple configurations. Depending on configurations, it may | ||
| host up to 4 Delta Lake servers in one sled. | ||
|
|
||
| Yosemite-V3 and Delta Lake are currently in DVT phase. Facebook, Intel and partners | ||
| jointly develop FSP/coreboot/LinuxBoot stack on Delta Lake as an alternative solution. | ||
|
|
||
| ## Required blobs | ||
|
|
||
| This board currently requires: | ||
| - FSP blob: The blob (Intel Cooper Lake Scalable Processor Firmware Support Package) | ||
| is not yet available to the public. It will be made public some time after the MP | ||
| (Mass Production) of CooperLake Scalable Processor when the FSP is mature. | ||
| - Microcode: Not yet available to the public. | ||
| - ME binary: Not yet available to the public. | ||
|
|
||
| ## Payload | ||
| - LinuxBoot: This is necessary only if you use LinuxBoot as coreboot payload. | ||
| U-root as initramfs, is used in the joint development. It can be built | ||
| following [All about u-root]. | ||
|
|
||
| ## Flashing coreboot | ||
|
|
||
| To do in-band FW image update, use [flashrom]: | ||
| flashrom -p internal:ich_spi_mode=hwseq -c "Opaque flash chip" --ifd \ | ||
| -i bios --noverify-all -w <path to coreboot image> | ||
|
|
||
| From OpenBMC, to update FW image: | ||
| fw-util slotx --update bios <path to coreboot image> | ||
|
|
||
| To power off/on the host: | ||
| power-util slotx off | ||
| power-util slotx on | ||
|
|
||
| To connect to console through SOL (Serial Over Lan): | ||
| sol-util slotx | ||
|
|
||
| ## Working features | ||
| The solution is developed using LinuxBoot payload with Linux kernel 5.2.9, and [u-root] | ||
| as initramfs. | ||
| - SMBIOS: | ||
| - Type 0 -- BIOS Information | ||
| - Type 1 -- System Information | ||
| - Type 2 -- Baseboard Information | ||
| - Type 3 -- System Enclosure or Chassis | ||
| - Type 4 -- Processor Information | ||
| - Type 8 -- Port Connector Information | ||
| - Type 9 -- PCI Slot Information | ||
| - Type 11 -- OEM String | ||
| - Type 13 -- BIOS Language Information | ||
| - Type 16 -- Physical Memory Array | ||
| - Type 19 -- Memory Array Mapped Address | ||
| - Type 127 -- End-of-Table | ||
|
|
||
| - BMC integration: | ||
| - BMC readiness check | ||
| - IPMI commands | ||
| - watchdog timer | ||
| - POST complete pin acknowledgement | ||
| - SEL record generation | ||
| - Early serial output | ||
| - port 80h direct to GPIO | ||
| - ACPI tables: APIC/DSDT/FACP/FACS/HPET/MCFG/SPMI/SRAT/SLIT/SSDT | ||
| - Skipping memory training upon subsequent reboots by using MRC cache | ||
| - BMC crash dump | ||
| - Error injection through ITP | ||
|
|
||
| ## Firmware configurations | ||
| [ChromeOS VPD] is used to store most of the firmware configurations. | ||
| RO_VPD region holds default values, while RW_VPD region holds customized | ||
| values. | ||
|
|
||
| VPD variables supported are: | ||
| - firmware_version: This variable holds overall firmware version. coreboot | ||
| uses that value to populate smbios type 1 version field. | ||
|
|
||
| ## Known issues | ||
| - Even though CPX-SP FSP is based on FSP 2.2 framework, it does not | ||
| support FSP_USES_CB_STACK. An IPS ticket is filed with Intel. | ||
| - VT-d is not supported. An IPS ticket is filed with Intel. | ||
| - PCIe bifuration is not supported. An IPS ticket is filed with Intel. | ||
| - ME based power capping. This is a bug in ME. An IPS ticket is filed | ||
| with Intel. | ||
| - RO_VPD region as well as other RO regions are not write protected. | ||
| - HECI is not set up correctly, so BMC is not able to get PCH and DIMM | ||
| temperature sensor readings. | ||
|
|
||
| ## Feature gaps | ||
| - Delta Lake DVT is not supported, as we only have Delta Lake EVT servers | ||
| at the moment. | ||
| - SMBIOS: | ||
| - Type 7 -- Cache Information | ||
| - Type 17 -- Memory Device | ||
| - Type 38 -- IPMI Device Information | ||
| - Type 41 -- Onboard Devices Extended Information | ||
| - ACPI: | ||
| - DMAR | ||
| - PFR/CBnT | ||
|
|
||
| ## Technology | ||
|
|
||
| ```eval_rst | ||
| +------------------------+---------------------------------------------+ | ||
| | Processor (1 socket) | Intel Cooper Lake Scalable Processor | | ||
| +------------------------+---------------------------------------------+ | ||
| | BMC | Aspeed AST 2500 | | ||
| +------------------------+---------------------------------------------+ | ||
| | PCH | Intel Lewisburg C621 | | ||
| +------------------------+---------------------------------------------+ | ||
| ``` | ||
|
|
||
| [OCP]: https://www.opencompute.org | ||
| [OCP virtual summit 2020]: https://www.opencompute.org/summit/virtual-summit/schedule | ||
| [flashrom]: https://flashrom.org/Flashrom | ||
| [All about u-root]: https://github.com/linuxboot/book/tree/master/u-root | ||
| [u-root]: https://u-root.org/ | ||
| [ChromeOS VPD]: https://chromium.googlesource.com/chromiumos/platform/vpd/+/master/README.md |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,234 @@ | ||
| /* | ||
| * | ||
| * Copyright (C) 2020 Google, Inc. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * 3. The name of the author may not be used to endorse or promote products | ||
| * derived from this software without specific prior written permission. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
| * SUCH DAMAGE. | ||
| */ | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| /* | ||
| * This file implements operations for a simple 32.32 fixed-point math type. | ||
| * This is intended for speed-critical stuff (e.g. graphics) so there are | ||
| * intentionally no overflow checks or assertions, and operations are written | ||
| * to prefer speed over precision (e.g. multiplying by 1 may lose precision). | ||
| * For best results, only use for applications where 16.16 would fit. | ||
| */ | ||
|
|
||
| typedef struct { /* wrap in struct to prevent direct access */ | ||
| int64_t v; | ||
| } fpmath_t; | ||
|
|
||
| #define FPMATH_SHIFT 32 /* define where to place the decimal point */ | ||
|
|
||
| /* Turn an integer into an fpmath_t. */ | ||
| static inline fpmath_t fp(int32_t a) | ||
| { | ||
| return (fpmath_t){ .v = (int64_t)a << FPMATH_SHIFT }; | ||
| } | ||
|
|
||
| /* Create an fpmath_t from a fraction. (numerator / denominator) */ | ||
| static inline fpmath_t fpfrac(int32_t numerator, int32_t denominator) | ||
| { | ||
| return (fpmath_t){ .v = ((int64_t)numerator << FPMATH_SHIFT) / denominator }; | ||
| } | ||
|
|
||
| /* Turn an fpmath_t back into an integer, rounding towards -INF. */ | ||
| static inline int32_t fpfloor(fpmath_t a) | ||
| { | ||
| return a.v >> FPMATH_SHIFT; | ||
| } | ||
|
|
||
| /* Turn an fpmath_t back into an integer, rounding towards nearest. */ | ||
| static inline int32_t fpround(fpmath_t a) | ||
| { | ||
| return (a.v + ((int64_t)1 << (FPMATH_SHIFT - 1))) >> FPMATH_SHIFT; | ||
| } | ||
|
|
||
| /* Turn an fpmath_t back into an integer, rounding towards +INF. */ | ||
| static inline int32_t fpceil(fpmath_t a) | ||
| { | ||
| return (a.v + ((int64_t)1 << FPMATH_SHIFT) - 1) >> FPMATH_SHIFT; | ||
| } | ||
|
|
||
| /* Add two fpmath_t. (a + b) */ | ||
| static inline fpmath_t fpadd(fpmath_t a, fpmath_t b) | ||
| { | ||
| return (fpmath_t){ .v = a.v + b.v }; | ||
| } | ||
|
|
||
| /* Add an fpmath_t and an integer. (a + b) */ | ||
| static inline fpmath_t fpaddi(fpmath_t a, int32_t b) | ||
| { | ||
| return (fpmath_t){ .v = a.v + ((int64_t)b << FPMATH_SHIFT) }; | ||
| } | ||
|
|
||
| /* Subtract one fpmath_t from another. (a + b) */ | ||
| static inline fpmath_t fpsub(fpmath_t a, fpmath_t b) | ||
| { | ||
| return (fpmath_t){ .v = a.v - b.v }; | ||
| } | ||
|
|
||
| /* Subtract an integer from an fpmath_t. (a - b) */ | ||
| static inline fpmath_t fpsubi(fpmath_t a, int32_t b) | ||
| { | ||
| return (fpmath_t){ .v = a.v - ((int64_t)b << FPMATH_SHIFT) }; | ||
| } | ||
|
|
||
| /* Subtract an fpmath_t from an integer. (a - b) */ | ||
| static inline fpmath_t fpisub(int32_t a, fpmath_t b) | ||
| { | ||
| return (fpmath_t){ .v = ((int64_t)a << FPMATH_SHIFT) - b.v }; | ||
| } | ||
|
|
||
| /* Multiply two fpmath_t. (a * b) | ||
| Looses 16 bits fractional precision on each. */ | ||
| static inline fpmath_t fpmul(fpmath_t a, fpmath_t b) | ||
| { | ||
| return (fpmath_t){ .v = (a.v >> (FPMATH_SHIFT/2)) * (b.v >> (FPMATH_SHIFT/2)) }; | ||
| } | ||
|
|
||
| /* Multiply an fpmath_t and an integer. (a * b) */ | ||
| static inline fpmath_t fpmuli(fpmath_t a, int32_t b) | ||
| { | ||
| return (fpmath_t){ .v = a.v * b }; | ||
| } | ||
|
|
||
| /* Divide an fpmath_t by another. (a / b) | ||
| Truncates integral part of a to 16 bits! Careful with this one! */ | ||
| static inline fpmath_t fpdiv(fpmath_t a, fpmath_t b) | ||
| { | ||
| return (fpmath_t){ .v = (a.v << (FPMATH_SHIFT/2)) / (b.v >> (FPMATH_SHIFT/2)) }; | ||
| } | ||
|
|
||
| /* Divide an fpmath_t by an integer. (a / b) */ | ||
| static inline fpmath_t fpdivi(fpmath_t a, int32_t b) | ||
| { | ||
| return (fpmath_t){ .v = a.v / b }; | ||
| } | ||
|
|
||
| /* Calculate absolute value of an fpmath_t. (ABS(a)) */ | ||
| static inline fpmath_t fpabs(fpmath_t a) | ||
| { | ||
| return (fpmath_t){ .v = (a.v < 0 ? -a.v : a.v) }; | ||
| } | ||
|
|
||
| /* Return true iff two fpmath_t are exactly equal. (a == b) | ||
| Like with floats, you probably don't want to use this most of the time. */ | ||
| static inline int fpequals(fpmath_t a, fpmath_t b) | ||
| { | ||
| return a.v == b.v; | ||
| } | ||
|
|
||
| /* Return true iff one fpmath_t is less than another. (a < b) */ | ||
| static inline int fpless(fpmath_t a, fpmath_t b) | ||
| { | ||
| return a.v < b.v; | ||
| } | ||
|
|
||
| /* Return true iff one fpmath_t is more than another. (a > b) */ | ||
| static inline int fpmore(fpmath_t a, fpmath_t b) | ||
| { | ||
| return a.v > b.v; | ||
| } | ||
|
|
||
| /* Return the smaller of two fpmath_t. (MIN(a, b)) */ | ||
| static inline fpmath_t fpmin(fpmath_t a, fpmath_t b) | ||
| { | ||
| if (a.v < b.v) | ||
| return a; | ||
| else | ||
| return b; | ||
| } | ||
|
|
||
| /* Return the larger of two fpmath_t. (MAX(a, b)) */ | ||
| static inline fpmath_t fpmax(fpmath_t a, fpmath_t b) | ||
| { | ||
| if (a.v > b.v) | ||
| return a; | ||
| else | ||
| return b; | ||
| } | ||
|
|
||
| /* Return the constant PI as an fpmath_t. */ | ||
| static inline fpmath_t fppi(void) | ||
| { | ||
| /* Rounded (uint64_t)(M_PI * (1UL << 60)) to nine hex digits. */ | ||
| return (fpmath_t){ .v = 0x3243f6a89 }; | ||
| } | ||
|
|
||
| /* | ||
| * Returns the "one-based" sine of an fpmath_t, meaning the input is interpreted as if the range | ||
| * 0.0-1.0 corresponded to 0.0-PI/2 for radians. This is mostly here as the base primitives for | ||
| * the other trig stuff, but it may be useful to use directly if your input value already needs | ||
| * to be multiplied by some factor of PI and you want to save the instructions (and precision) | ||
| * for multiplying it in just so that the trig functions can divide it right out again. | ||
| */ | ||
| fpmath_t fpsin1(fpmath_t x); | ||
|
|
||
| /* Returns the "one-based" cosine of an fpmath_t (analogous definition to fpsin1()). */ | ||
| static inline fpmath_t fpcos1(fpmath_t x) | ||
| { | ||
| return fpsin1(fpaddi(x, 1)); | ||
| } | ||
|
|
||
| /* Returns the sine of an fpmath_t interpreted as radians. */ | ||
| static inline fpmath_t fpsinr(fpmath_t radians) | ||
| { | ||
| return fpsin1(fpdiv(radians, fpdivi(fppi(), 2))); | ||
| } | ||
|
|
||
| /* Returns the sine of an fpmath_t interpreted as degrees. */ | ||
| static inline fpmath_t fpsind(fpmath_t degrees) | ||
| { | ||
| return fpsin1(fpdivi(degrees, 90)); | ||
| } | ||
|
|
||
| /* Returns the cosine of an fpmath_t interpreted as radians. */ | ||
| static inline fpmath_t fpcosr(fpmath_t radians) | ||
| { | ||
| return fpcos1(fpdiv(radians, fpdivi(fppi(), 2))); | ||
| } | ||
|
|
||
| /* Returns the cosine of an fpmath_t interpreted as degrees. */ | ||
| static inline fpmath_t fpcosd(fpmath_t degrees) | ||
| { | ||
| return fpcos1(fpdivi(degrees, 90)); | ||
| } | ||
|
|
||
| /* Returns the tangent of an fpmath_t interpreted as radians. | ||
| No guard rails, don't call this at the poles or you'll divide by 0! */ | ||
| static inline fpmath_t fptanr(fpmath_t radians) | ||
| { | ||
| fpmath_t one_based = fpdiv(radians, fpdivi(fppi(), 2)); | ||
| return fpdiv(fpsin1(one_based), fpcos1(one_based)); | ||
| } | ||
|
|
||
| /* Returns the tangent of an fpmath_t interpreted as degrees. | ||
| No guard rails, don't call this at the poles or you'll divide by 0! */ | ||
| static inline fpmath_t fptand(fpmath_t degrees) | ||
| { | ||
| fpmath_t one_based = fpdivi(degrees, 90); | ||
| return fpdiv(fpsin1(one_based), fpcos1(one_based)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,149 @@ | ||
| /* | ||
| * | ||
| * Copyright (C) 2020 Google, Inc. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * 3. The name of the author may not be used to endorse or promote products | ||
| * derived from this software without specific prior written permission. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
| * SUCH DAMAGE. | ||
| */ | ||
|
|
||
| #include <fpmath.h> | ||
|
|
||
| /* | ||
| * This table represents one ascending arc of the sine curve, i.e. the values sin(x) for | ||
| * 0.0 <= x < PI/2. We divide that range into 256 equidistant points and store the corresponding | ||
| * sine values for those points. Since the values lie in the range 0.0 <= sin(x) < 1.0, in order | ||
| * to make the most use of the bytes we store, we map them to the range from 0 to 2^16. | ||
| * | ||
| * Generated with: | ||
| * | ||
| * for (i = 0; i < 256; i++) { | ||
| * double s = sin((double)i * M_PI / 2 / 256); | ||
| * uint16_t u = fmin(round(s * (1 << 16)), (1 << 16)); | ||
| * printf("0x%04x,%s", u, i % 8 == 7 ? "\n" : " "); | ||
| * } | ||
| * | ||
| * In order to make sure the second access for linear interpolation (see below) cannot overrun | ||
| * the array, we stick a final 257th value 0xffff at the end. (It should really be 0x10000, | ||
| * but... this is good enough.) | ||
| */ | ||
|
|
||
| /* Table size as power of two. If we ever want to change the table size, updating this value | ||
| should make everything else fall back into place again (hopefully). */ | ||
| #define TP2 8 | ||
|
|
||
| static const uint16_t fpsin_table[(1 << TP2) + 1] = { | ||
| 0x0000, 0x0192, 0x0324, 0x04b6, 0x0648, 0x07da, 0x096c, 0x0afe, | ||
| 0x0c90, 0x0e21, 0x0fb3, 0x1144, 0x12d5, 0x1466, 0x15f7, 0x1787, | ||
| 0x1918, 0x1aa8, 0x1c38, 0x1dc7, 0x1f56, 0x20e5, 0x2274, 0x2402, | ||
| 0x2590, 0x271e, 0x28ab, 0x2a38, 0x2bc4, 0x2d50, 0x2edc, 0x3067, | ||
| 0x31f1, 0x337c, 0x3505, 0x368e, 0x3817, 0x399f, 0x3b27, 0x3cae, | ||
| 0x3e34, 0x3fba, 0x413f, 0x42c3, 0x4447, 0x45cb, 0x474d, 0x48cf, | ||
| 0x4a50, 0x4bd1, 0x4d50, 0x4ecf, 0x504d, 0x51cb, 0x5348, 0x54c3, | ||
| 0x563e, 0x57b9, 0x5932, 0x5aaa, 0x5c22, 0x5d99, 0x5f0f, 0x6084, | ||
| 0x61f8, 0x636b, 0x64dd, 0x664e, 0x67be, 0x692d, 0x6a9b, 0x6c08, | ||
| 0x6d74, 0x6edf, 0x7049, 0x71b2, 0x731a, 0x7480, 0x75e6, 0x774a, | ||
| 0x78ad, 0x7a10, 0x7b70, 0x7cd0, 0x7e2f, 0x7f8c, 0x80e8, 0x8243, | ||
| 0x839c, 0x84f5, 0x864c, 0x87a1, 0x88f6, 0x8a49, 0x8b9a, 0x8ceb, | ||
| 0x8e3a, 0x8f88, 0x90d4, 0x921f, 0x9368, 0x94b0, 0x95f7, 0x973c, | ||
| 0x9880, 0x99c2, 0x9b03, 0x9c42, 0x9d80, 0x9ebc, 0x9ff7, 0xa130, | ||
| 0xa268, 0xa39e, 0xa4d2, 0xa605, 0xa736, 0xa866, 0xa994, 0xaac1, | ||
| 0xabeb, 0xad14, 0xae3c, 0xaf62, 0xb086, 0xb1a8, 0xb2c9, 0xb3e8, | ||
| 0xb505, 0xb620, 0xb73a, 0xb852, 0xb968, 0xba7d, 0xbb8f, 0xbca0, | ||
| 0xbdaf, 0xbebc, 0xbfc7, 0xc0d1, 0xc1d8, 0xc2de, 0xc3e2, 0xc4e4, | ||
| 0xc5e4, 0xc6e2, 0xc7de, 0xc8d9, 0xc9d1, 0xcac7, 0xcbbc, 0xccae, | ||
| 0xcd9f, 0xce8e, 0xcf7a, 0xd065, 0xd14d, 0xd234, 0xd318, 0xd3fb, | ||
| 0xd4db, 0xd5ba, 0xd696, 0xd770, 0xd848, 0xd91e, 0xd9f2, 0xdac4, | ||
| 0xdb94, 0xdc62, 0xdd2d, 0xddf7, 0xdebe, 0xdf83, 0xe046, 0xe107, | ||
| 0xe1c6, 0xe282, 0xe33c, 0xe3f4, 0xe4aa, 0xe55e, 0xe610, 0xe6bf, | ||
| 0xe76c, 0xe817, 0xe8bf, 0xe966, 0xea0a, 0xeaab, 0xeb4b, 0xebe8, | ||
| 0xec83, 0xed1c, 0xedb3, 0xee47, 0xeed9, 0xef68, 0xeff5, 0xf080, | ||
| 0xf109, 0xf18f, 0xf213, 0xf295, 0xf314, 0xf391, 0xf40c, 0xf484, | ||
| 0xf4fa, 0xf56e, 0xf5df, 0xf64e, 0xf6ba, 0xf724, 0xf78c, 0xf7f1, | ||
| 0xf854, 0xf8b4, 0xf913, 0xf96e, 0xf9c8, 0xfa1f, 0xfa73, 0xfac5, | ||
| 0xfb15, 0xfb62, 0xfbad, 0xfbf5, 0xfc3b, 0xfc7f, 0xfcc0, 0xfcfe, | ||
| 0xfd3b, 0xfd74, 0xfdac, 0xfde1, 0xfe13, 0xfe43, 0xfe71, 0xfe9c, | ||
| 0xfec4, 0xfeeb, 0xff0e, 0xff30, 0xff4e, 0xff6b, 0xff85, 0xff9c, | ||
| 0xffb1, 0xffc4, 0xffd4, 0xffe1, 0xffec, 0xfff5, 0xfffb, 0xffff, | ||
| 0xffff, | ||
| }; | ||
|
|
||
| /* x is in the "one-based" scale, so x == 1.0 is the top of the curve (PI/2 in radians). */ | ||
| fpmath_t fpsin1(fpmath_t x) | ||
| { | ||
| /* | ||
| * When doing things like sin(x)/x, tiny errors can quickly become big problems, so just | ||
| * returning the nearest table value we have is not good enough (our fpmath_t has four | ||
| * times as much fractional precision as the sine table). A good and fast enough remedy | ||
| * is to linearly interpolate between the two nearest table values v1 and v2. | ||
| * (There are better but slower interpolations so we intentionally choose this one.) | ||
| * | ||
| * Most of this math can be done in 32 bits (because we're just operating on fractional | ||
| * parts in the 0.0-1.0 range anyway), so to help our 32-bit platforms a bit we keep it | ||
| * there as long as possible and only go back to an int64_t at the end. | ||
| */ | ||
| uint32_t v1, v2; | ||
|
|
||
| /* | ||
| * Since x is "one-based" the part that maps to our curve (0.0 to PI/2 in radians) just | ||
| * happens to be exactly the fractional part of the fpmath_t, easy to extract. | ||
| */ | ||
| int index = (x.v >> (FPMATH_SHIFT - TP2)) & ((1 << TP2) - 1); | ||
|
|
||
| /* | ||
| * In our one-based input domain, the period of the sine function is exactly 4.0. By | ||
| * extracting the first bit of the integral part of the fpmath_t we can check if it is | ||
| * odd-numbered (1.0-2.0, 3.0-4.0, etc.) or even numbered (0.0-1.0, 2.0-3.0, etc.), and | ||
| * that tells us whether we are in a "rising" (away from 0) or "falling" (towards 0) | ||
| * part of the sine curve. Our table curve is rising, so for the falling parts we have | ||
| * to mirror the curve horizontally by using the complement of our input index. | ||
| */ | ||
| if (x.v & ((int64_t)1 << FPMATH_SHIFT)) { | ||
| v1 = fpsin_table[(1 << TP2) - index]; | ||
| v2 = fpsin_table[(1 << TP2) - index - 1]; | ||
| } else { | ||
| v1 = fpsin_table[index]; | ||
| v2 = fpsin_table[index + 1]; | ||
| } | ||
|
|
||
| /* | ||
| * Linear interpolation: sin(x) is interpolated as the closest number sin(x0) to the | ||
| * left of x we have in our table, plus the distance of that value to the closest number | ||
| * to the right of x (sin(x1)) times the fractional distance of x to x0. Since the table | ||
| * is conveniently exactly 256 values, x0 is exactly the upper 8 bits of the fractional | ||
| * part of x, meaning all fractional bits below that represent exactly the distance we | ||
| * need to interpolate over. (There are 24 of them but we need to multiply them with | ||
| * 16-bit table values to fit exactly 32 bits, so we discard the lowest 8 bits.) | ||
| */ | ||
| uint32_t val = (v1 << (FPMATH_SHIFT - 16)) + | ||
| (v2 - v1) * ((x.v >> (16 - TP2)) & 0xffff); | ||
|
|
||
| /* | ||
| * Just like the first integral bit told us whether we need to mirror horizontally, the | ||
| * second can tell us to mirror vertically. In 2.0-4.0, 6.0-8.0, etc. of the input range | ||
| * the sine is negative, and in 0.0-2.0, 4.0-6.0, etc. it is positive. | ||
| */ | ||
| if (x.v & ((int64_t)2 << FPMATH_SHIFT)) | ||
| return (fpmath_t){ .v = -(int64_t)val }; | ||
| else | ||
| return (fpmath_t){ .v = val }; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,6 @@ | |
| #define ARM_CACHE_H | ||
|
|
||
| #include <stddef.h> | ||
|
|
||
| /* | ||
| * Cache maintenance API | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,6 @@ | |
|
|
||
| #ifndef ARMV7_H | ||
| #define ARMV7_H | ||
|
|
||
| /* Cortex-A9 revisions */ | ||
| #define MIDR_CORTEX_A9_R0P1 0x410FC091 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -133,12 +133,6 @@ config NUM_IPI_STARTS | |
| int | ||
| default 2 | ||
|
|
||
| config PRERAM_CBMEM_CONSOLE_SIZE | ||
| hex | ||
| default 0xc00 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| #include <acpi/acpi.h> | ||
| #include <cf9_reset.h> | ||
|
|
||
| void arch_fill_fadt(acpi_fadt_t *fadt) | ||
| { | ||
| if (CONFIG(HAVE_CF9_RESET)) { | ||
| fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO; | ||
| fadt->reset_reg.bit_width = 8; | ||
| fadt->reset_reg.bit_offset = 0; | ||
| fadt->reset_reg.access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS; | ||
| fadt->reset_reg.addrl = RST_CNT; | ||
| fadt->reset_reg.addrh = 0; | ||
|
|
||
| fadt->reset_value = RST_CPU | SYS_RST; | ||
|
|
||
| fadt->flags |= ACPI_FADT_RESET_REGISTER; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,5 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| /* | ||
| * 0x80: POST_BASE | ||
| * 0x3F8: DEBCOM_BASE | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,6 @@ | |
| #ifndef __ARCH_EBDA_H | ||
| #define __ARCH_EBDA_H | ||
|
|
||
| #include <stddef.h> | ||
|
|
||
| #define X86_BDA_SIZE 0x200 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,4 @@ | ||
| ramstage-y += haswell_init.c | ||
| romstage-y += ../car/romstage.c | ||
|
|
||
| ramstage-y += acpi.c | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,43 +4,6 @@ | |
| #include <cpu/x86/msr.h> | ||
| #include "haswell.h" | ||
|
|
||
| void intel_cpu_haswell_finalize_smm(void) | ||
| { | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,5 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| #include <cpu/x86/msr.h> | ||
| #include "model_206ax.h" | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||
|
|
||
| /* | ||
| * For droping from long mode to protected mode. | ||
| * | ||
| * For reference see "AMD64 ArchitectureProgrammer's Manual Volume 2", | ||
| * Document 24593-Rev. 3.31-July 2019 Chapter 5.3 | ||
| * | ||
| * Clobbers: rax, rbx, rcx, rdx | ||
| */ | ||
| .code64 | ||
|
|
||
| #include <cpu/x86/msr.h> | ||
| #include <cpu/x86/cr.h> | ||
| #include <arch/rom_segs.h> | ||
|
|
||
| drop_longmode: | ||
| /* Ensure cache is clean. */ | ||
| wbinvd | ||
|
|
||
| /* Set 32-bit code segment and ss */ | ||
| mov $ROM_CODE_SEG, %rcx | ||
| /* SetCodeSelector32 will drop us to protected mode on return */ | ||
| call SetCodeSelector32 | ||
|
|
||
| /* Skip SetCodeSelector32 */ | ||
| .code32 | ||
| jmp __longmode_compatibility | ||
|
|
||
| .align 8 | ||
| .code64 | ||
| SetCodeSelector32: | ||
| # pop the return address from stack | ||
| pop %rbx | ||
|
|
||
| # save rsp because we need to push it after ss | ||
| mov %rsp, %rdx | ||
|
|
||
| # use iret to jump to a 32-bit offset in a new code segment | ||
| # iret will pop cs:rip, flags, then ss:rsp | ||
| mov %ss, %ax # need to push ss, but push ss instuction | ||
| push %rax # not valid in x64 mode, so use ax | ||
| push %rdx # the rsp to load | ||
| pushfq # push rflags | ||
| push %rcx # cx is code segment selector from caller | ||
| push %rbx # push the IP for the next instruction | ||
|
|
||
| # the iretq will behave like ret, with the new cs/ss value loaded | ||
| iretq | ||
|
|
||
| .align 4 | ||
| .code32 | ||
| __longmode_compatibility: | ||
| /* Running in 32-bit compatibility mode */ | ||
|
|
||
| /* Use flat data segment */ | ||
| movl $ROM_DATA_SEG, %eax | ||
| movl %eax, %ds | ||
| movl %eax, %es | ||
| movl %eax, %ss | ||
| movl %eax, %fs | ||
| movl %eax, %gs | ||
|
|
||
| /* Disable paging. */ | ||
| movl %cr0, %eax | ||
| andl $(~CR0_PG), %eax | ||
| movl %eax, %cr0 | ||
|
|
||
| /* Disable long mode. */ | ||
| movl $(IA32_EFER), %ecx | ||
| rdmsr | ||
| andl $(~EFER_LME), %eax | ||
| wrmsr | ||
|
|
||
| /* Disable PAE. */ | ||
| movl %cr4, %eax | ||
| andl $(~CR4_PAE), %eax | ||
| movl %eax, %cr4 | ||
|
|
||
| /* Clear page table register */ | ||
| xor %eax, %eax | ||
| movl %eax, %cr3 | ||
|
|
||
| __longmode_exit: |