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

arm-spe-decoder.c (5780B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * arm_spe_decoder.c: ARM SPE support
      4 */
      5
      6#ifndef _GNU_SOURCE
      7#define _GNU_SOURCE
      8#endif
      9#include <errno.h>
     10#include <inttypes.h>
     11#include <stdbool.h>
     12#include <string.h>
     13#include <stdint.h>
     14#include <stdlib.h>
     15#include <linux/bitops.h>
     16#include <linux/compiler.h>
     17#include <linux/zalloc.h>
     18
     19#include "../auxtrace.h"
     20#include "../debug.h"
     21#include "../util.h"
     22
     23#include "arm-spe-decoder.h"
     24
     25static u64 arm_spe_calc_ip(int index, u64 payload)
     26{
     27	u64 ns, el, val;
     28
     29	/* Instruction virtual address or Branch target address */
     30	if (index == SPE_ADDR_PKT_HDR_INDEX_INS ||
     31	    index == SPE_ADDR_PKT_HDR_INDEX_BRANCH) {
     32		ns = SPE_ADDR_PKT_GET_NS(payload);
     33		el = SPE_ADDR_PKT_GET_EL(payload);
     34
     35		/* Clean highest byte */
     36		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
     37
     38		/* Fill highest byte for EL1 or EL2 (VHE) mode */
     39		if (ns && (el == SPE_ADDR_PKT_EL1 || el == SPE_ADDR_PKT_EL2))
     40			payload |= 0xffULL << SPE_ADDR_PKT_ADDR_BYTE7_SHIFT;
     41
     42	/* Data access virtual address */
     43	} else if (index == SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT) {
     44
     45		/* Clean tags */
     46		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
     47
     48		/*
     49		 * Armv8 ARM (ARM DDI 0487F.c), chapter "D10.2.1 Address packet"
     50		 * defines the data virtual address payload format, the top byte
     51		 * (bits [63:56]) is assigned as top-byte tag; so we only can
     52		 * retrieve address value from bits [55:0].
     53		 *
     54		 * According to Documentation/arm64/memory.rst, if detects the
     55		 * specific pattern in bits [55:52] of payload which falls in
     56		 * the kernel space, should fixup the top byte and this allows
     57		 * perf tool to parse DSO symbol for data address correctly.
     58		 *
     59		 * For this reason, if detects the bits [55:52] is 0xf, will
     60		 * fill 0xff into the top byte.
     61		 */
     62		val = SPE_ADDR_PKT_ADDR_GET_BYTE_6(payload);
     63		if ((val & 0xf0ULL) == 0xf0ULL)
     64			payload |= 0xffULL << SPE_ADDR_PKT_ADDR_BYTE7_SHIFT;
     65
     66	/* Data access physical address */
     67	} else if (index == SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS) {
     68		/* Clean highest byte */
     69		payload = SPE_ADDR_PKT_ADDR_GET_BYTES_0_6(payload);
     70	} else {
     71		pr_err("unsupported address packet index: 0x%x\n", index);
     72	}
     73
     74	return payload;
     75}
     76
     77struct arm_spe_decoder *arm_spe_decoder_new(struct arm_spe_params *params)
     78{
     79	struct arm_spe_decoder *decoder;
     80
     81	if (!params->get_trace)
     82		return NULL;
     83
     84	decoder = zalloc(sizeof(struct arm_spe_decoder));
     85	if (!decoder)
     86		return NULL;
     87
     88	decoder->get_trace = params->get_trace;
     89	decoder->data = params->data;
     90
     91	return decoder;
     92}
     93
     94void arm_spe_decoder_free(struct arm_spe_decoder *decoder)
     95{
     96	free(decoder);
     97}
     98
     99static int arm_spe_get_data(struct arm_spe_decoder *decoder)
    100{
    101	struct arm_spe_buffer buffer = { .buf = 0, };
    102	int ret;
    103
    104	pr_debug("Getting more data\n");
    105	ret = decoder->get_trace(&buffer, decoder->data);
    106	if (ret < 0)
    107		return ret;
    108
    109	decoder->buf = buffer.buf;
    110	decoder->len = buffer.len;
    111
    112	if (!decoder->len)
    113		pr_debug("No more data\n");
    114
    115	return decoder->len;
    116}
    117
    118static int arm_spe_get_next_packet(struct arm_spe_decoder *decoder)
    119{
    120	int ret;
    121
    122	do {
    123		if (!decoder->len) {
    124			ret = arm_spe_get_data(decoder);
    125
    126			/* Failed to read out trace data */
    127			if (ret <= 0)
    128				return ret;
    129		}
    130
    131		ret = arm_spe_get_packet(decoder->buf, decoder->len,
    132					 &decoder->packet);
    133		if (ret <= 0) {
    134			/* Move forward for 1 byte */
    135			decoder->buf += 1;
    136			decoder->len -= 1;
    137			return -EBADMSG;
    138		}
    139
    140		decoder->buf += ret;
    141		decoder->len -= ret;
    142	} while (decoder->packet.type == ARM_SPE_PAD);
    143
    144	return 1;
    145}
    146
    147static int arm_spe_read_record(struct arm_spe_decoder *decoder)
    148{
    149	int err;
    150	int idx;
    151	u64 payload, ip;
    152
    153	memset(&decoder->record, 0x0, sizeof(decoder->record));
    154	decoder->record.context_id = (u64)-1;
    155
    156	while (1) {
    157		err = arm_spe_get_next_packet(decoder);
    158		if (err <= 0)
    159			return err;
    160
    161		idx = decoder->packet.index;
    162		payload = decoder->packet.payload;
    163
    164		switch (decoder->packet.type) {
    165		case ARM_SPE_TIMESTAMP:
    166			decoder->record.timestamp = payload;
    167			return 1;
    168		case ARM_SPE_END:
    169			return 1;
    170		case ARM_SPE_ADDRESS:
    171			ip = arm_spe_calc_ip(idx, payload);
    172			if (idx == SPE_ADDR_PKT_HDR_INDEX_INS)
    173				decoder->record.from_ip = ip;
    174			else if (idx == SPE_ADDR_PKT_HDR_INDEX_BRANCH)
    175				decoder->record.to_ip = ip;
    176			else if (idx == SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT)
    177				decoder->record.virt_addr = ip;
    178			else if (idx == SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS)
    179				decoder->record.phys_addr = ip;
    180			break;
    181		case ARM_SPE_COUNTER:
    182			if (idx == SPE_CNT_PKT_HDR_INDEX_TOTAL_LAT)
    183				decoder->record.latency = payload;
    184			break;
    185		case ARM_SPE_CONTEXT:
    186			decoder->record.context_id = payload;
    187			break;
    188		case ARM_SPE_OP_TYPE:
    189			if (idx == SPE_OP_PKT_HDR_CLASS_LD_ST_ATOMIC) {
    190				if (payload & 0x1)
    191					decoder->record.op = ARM_SPE_ST;
    192				else
    193					decoder->record.op = ARM_SPE_LD;
    194			}
    195			break;
    196		case ARM_SPE_EVENTS:
    197			if (payload & BIT(EV_L1D_REFILL))
    198				decoder->record.type |= ARM_SPE_L1D_MISS;
    199
    200			if (payload & BIT(EV_L1D_ACCESS))
    201				decoder->record.type |= ARM_SPE_L1D_ACCESS;
    202
    203			if (payload & BIT(EV_TLB_WALK))
    204				decoder->record.type |= ARM_SPE_TLB_MISS;
    205
    206			if (payload & BIT(EV_TLB_ACCESS))
    207				decoder->record.type |= ARM_SPE_TLB_ACCESS;
    208
    209			if (payload & BIT(EV_LLC_MISS))
    210				decoder->record.type |= ARM_SPE_LLC_MISS;
    211
    212			if (payload & BIT(EV_LLC_ACCESS))
    213				decoder->record.type |= ARM_SPE_LLC_ACCESS;
    214
    215			if (payload & BIT(EV_REMOTE_ACCESS))
    216				decoder->record.type |= ARM_SPE_REMOTE_ACCESS;
    217
    218			if (payload & BIT(EV_MISPRED))
    219				decoder->record.type |= ARM_SPE_BRANCH_MISS;
    220
    221			break;
    222		case ARM_SPE_DATA_SOURCE:
    223			break;
    224		case ARM_SPE_BAD:
    225			break;
    226		case ARM_SPE_PAD:
    227			break;
    228		default:
    229			pr_err("Get packet error!\n");
    230			return -1;
    231		}
    232	}
    233
    234	return 0;
    235}
    236
    237int arm_spe_decode(struct arm_spe_decoder *decoder)
    238{
    239	return arm_spe_read_record(decoder);
    240}