cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

shadowacpi.c (4001B)


      1/*
      2 * Copyright 2012 Red Hat Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 */
     23#include "priv.h"
     24
     25static int
     26acpi_read_bios(acpi_handle rom_handle, u8 *bios, u32 offset, u32 length)
     27{
     28#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
     29	acpi_status status;
     30	union acpi_object rom_arg_elements[2], *obj;
     31	struct acpi_object_list rom_arg;
     32	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
     33
     34	rom_arg.count = 2;
     35	rom_arg.pointer = &rom_arg_elements[0];
     36
     37	rom_arg_elements[0].type = ACPI_TYPE_INTEGER;
     38	rom_arg_elements[0].integer.value = offset;
     39
     40	rom_arg_elements[1].type = ACPI_TYPE_INTEGER;
     41	rom_arg_elements[1].integer.value = length;
     42
     43	status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer);
     44	if (ACPI_FAILURE(status)) {
     45		pr_info("failed to evaluate ROM got %s\n",
     46			acpi_format_exception(status));
     47		return -ENODEV;
     48	}
     49	obj = (union acpi_object *)buffer.pointer;
     50	length = min(length, obj->buffer.length);
     51	memcpy(bios+offset, obj->buffer.pointer, length);
     52	kfree(buffer.pointer);
     53	return length;
     54#else
     55	return -EINVAL;
     56#endif
     57}
     58
     59/* This version of the shadow function disobeys the ACPI spec and tries
     60 * to fetch in units of more than 4KiB at a time.  This is a LOT faster
     61 * on some systems, such as Lenovo W530.
     62 */
     63static u32
     64acpi_read_fast(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
     65{
     66	u32 limit = (offset + length + 0xfff) & ~0xfff;
     67	u32 start = offset & ~0x00000fff;
     68	u32 fetch = limit - start;
     69
     70	if (nvbios_extend(bios, limit) >= 0) {
     71		int ret = acpi_read_bios(data, bios->data, start, fetch);
     72		if (ret == fetch)
     73			return fetch;
     74	}
     75
     76	return 0;
     77}
     78
     79/* Other systems, such as the one in fdo#55948, will report a success
     80 * but only return 4KiB of data.  The common bios fetching logic will
     81 * detect an invalid image, and fall back to this version of the read
     82 * function.
     83 */
     84static u32
     85acpi_read_slow(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
     86{
     87	u32 limit = (offset + length + 0xfff) & ~0xfff;
     88	u32 start = offset & ~0xfff;
     89	u32 fetch = 0;
     90
     91	if (nvbios_extend(bios, limit) >= 0) {
     92		while (start + fetch < limit) {
     93			int ret = acpi_read_bios(data, bios->data,
     94						 start + fetch, 0x1000);
     95			if (ret != 0x1000)
     96				break;
     97			fetch += 0x1000;
     98		}
     99	}
    100
    101	return fetch;
    102}
    103
    104static void *
    105acpi_init(struct nvkm_bios *bios, const char *name)
    106{
    107#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
    108	acpi_status status;
    109	acpi_handle dhandle, rom_handle;
    110
    111	dhandle = ACPI_HANDLE(bios->subdev.device->dev);
    112	if (!dhandle)
    113		return ERR_PTR(-ENODEV);
    114
    115	status = acpi_get_handle(dhandle, "_ROM", &rom_handle);
    116	if (ACPI_FAILURE(status))
    117		return ERR_PTR(-ENODEV);
    118
    119	return rom_handle;
    120#else
    121	return ERR_PTR(-ENODEV);
    122#endif
    123}
    124
    125const struct nvbios_source
    126nvbios_acpi_fast = {
    127	.name = "ACPI",
    128	.init = acpi_init,
    129	.read = acpi_read_fast,
    130	.rw = false,
    131	.require_checksum = true,
    132};
    133
    134const struct nvbios_source
    135nvbios_acpi_slow = {
    136	.name = "ACPI",
    137	.init = acpi_init,
    138	.read = acpi_read_slow,
    139	.rw = false,
    140};