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

vmid.c (4565B)


      1/*
      2 * Copyright 2019 Advanced Micro Devices, 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 * Authors: AMD
     23 *
     24 */
     25
     26#include "mod_vmid.h"
     27
     28struct core_vmid {
     29	struct mod_vmid public;
     30	struct dc *dc;
     31
     32	unsigned int num_vmid;
     33	unsigned int num_vmids_available;
     34	uint64_t ptb_assigned_to_vmid[MAX_VMID];
     35	struct dc_virtual_addr_space_config base_config;
     36};
     37
     38#define MOD_VMID_TO_CORE(mod_vmid)\
     39		container_of(mod_vmid, struct core_vmid, public)
     40
     41static void add_ptb_to_table(struct core_vmid *core_vmid, unsigned int vmid, uint64_t ptb)
     42{
     43	if (vmid < MAX_VMID) {
     44		core_vmid->ptb_assigned_to_vmid[vmid] = ptb;
     45		core_vmid->num_vmids_available--;
     46	}
     47}
     48
     49static void clear_entry_from_vmid_table(struct core_vmid *core_vmid, unsigned int vmid)
     50{
     51	if (vmid < MAX_VMID) {
     52		core_vmid->ptb_assigned_to_vmid[vmid] = 0;
     53		core_vmid->num_vmids_available++;
     54	}
     55}
     56
     57static void evict_vmids(struct core_vmid *core_vmid)
     58{
     59	int i;
     60	uint16_t ord = dc_get_vmid_use_vector(core_vmid->dc);
     61
     62	// At this point any positions with value 0 are unused vmids, evict them
     63	for (i = 1; i < core_vmid->num_vmid; i++) {
     64		if (!(ord & (1u << i)))
     65			clear_entry_from_vmid_table(core_vmid, i);
     66	}
     67}
     68
     69// Return value of -1 indicates vmid table unitialized or ptb dne in the table
     70static int get_existing_vmid_for_ptb(struct core_vmid *core_vmid, uint64_t ptb)
     71{
     72	int i;
     73
     74	for (i = 0; i < core_vmid->num_vmid; i++) {
     75		if (core_vmid->ptb_assigned_to_vmid[i] == ptb)
     76			return i;
     77	}
     78
     79	return -1;
     80}
     81
     82// Expected to be called only when there's an available vmid
     83static int get_next_available_vmid(struct core_vmid *core_vmid)
     84{
     85	int i;
     86
     87	for (i = 1; i < core_vmid->num_vmid; i++) {
     88		if (core_vmid->ptb_assigned_to_vmid[i] == 0)
     89			return i;
     90	}
     91
     92	return -1;
     93}
     94
     95uint8_t mod_vmid_get_for_ptb(struct mod_vmid *mod_vmid, uint64_t ptb)
     96{
     97	struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid);
     98	int vmid = 0;
     99
    100	// Physical address gets vmid 0
    101	if (ptb == 0)
    102		return 0;
    103
    104	vmid = get_existing_vmid_for_ptb(core_vmid, ptb);
    105
    106	if (vmid == -1) {
    107		struct dc_virtual_addr_space_config va_config = core_vmid->base_config;
    108
    109		va_config.page_table_base_addr = ptb;
    110
    111		if (core_vmid->num_vmids_available == 0)
    112			evict_vmids(core_vmid);
    113
    114		vmid = get_next_available_vmid(core_vmid);
    115		if (vmid != -1) {
    116			add_ptb_to_table(core_vmid, vmid, ptb);
    117
    118			dc_setup_vm_context(core_vmid->dc, &va_config, vmid);
    119		} else
    120			ASSERT(0);
    121	}
    122
    123	return vmid;
    124}
    125
    126void mod_vmid_reset(struct mod_vmid *mod_vmid)
    127{
    128	struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid);
    129
    130	core_vmid->num_vmids_available = core_vmid->num_vmid - 1;
    131	memset(core_vmid->ptb_assigned_to_vmid, 0, sizeof(core_vmid->ptb_assigned_to_vmid[0]) * MAX_VMID);
    132}
    133
    134struct mod_vmid *mod_vmid_create(
    135		struct dc *dc,
    136		unsigned int num_vmid,
    137		struct dc_virtual_addr_space_config *va_config)
    138{
    139	struct core_vmid *core_vmid;
    140
    141	if (num_vmid <= 1)
    142		goto fail_no_vm_ctx;
    143
    144	if (dc == NULL)
    145		goto fail_dc_null;
    146
    147	core_vmid = kzalloc(sizeof(struct core_vmid), GFP_KERNEL);
    148
    149	if (core_vmid == NULL)
    150		goto fail_alloc_context;
    151
    152	core_vmid->dc = dc;
    153	core_vmid->num_vmid = num_vmid;
    154	core_vmid->num_vmids_available = num_vmid - 1;
    155	core_vmid->base_config = *va_config;
    156
    157	memset(core_vmid->ptb_assigned_to_vmid, 0, sizeof(core_vmid->ptb_assigned_to_vmid[0]) * MAX_VMID);
    158
    159	return &core_vmid->public;
    160
    161fail_no_vm_ctx:
    162fail_alloc_context:
    163fail_dc_null:
    164	return NULL;
    165}
    166
    167void mod_vmid_destroy(struct mod_vmid *mod_vmid)
    168{
    169	if (mod_vmid != NULL) {
    170		struct core_vmid *core_vmid = MOD_VMID_TO_CORE(mod_vmid);
    171
    172		kfree(core_vmid);
    173	}
    174}