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

hfi-events.c (6616B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Intel Speed Select -- Read HFI events for OOB
      4 * Copyright (c) 2022 Intel Corporation.
      5 */
      6
      7/*
      8 * This file incorporates work covered by the following copyright and
      9 * permission notice:
     10
     11 * WPA Supplicant - driver interaction with Linux nl80211/cfg80211
     12 * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
     13 *
     14 * This program is free software; you can redistribute it and/or modify
     15 * it under the terms of the GNU General Public License version 2 as
     16 * published by the Free Software Foundation.
     17 *
     18 * Alternatively, this software may be distributed under the terms of
     19 * BSD license.
     20 *
     21 * Requires
     22 * libnl-genl-3-dev
     23 *
     24 * For Fedora/CenOS
     25 * dnf install libnl3-devel
     26 * For Ubuntu
     27 * apt install libnl-3-dev libnl-genl-3-dev
     28 */
     29
     30#include <stdio.h>
     31#include <stdlib.h>
     32#include <stdarg.h>
     33#include <string.h>
     34#include <unistd.h>
     35#include <fcntl.h>
     36#include <sys/file.h>
     37#include <sys/types.h>
     38#include <sys/stat.h>
     39#include <errno.h>
     40#include <getopt.h>
     41#include <signal.h>
     42#include <netlink/genl/genl.h>
     43#include <netlink/genl/family.h>
     44#include <netlink/genl/ctrl.h>
     45
     46#include <linux/thermal.h>
     47#include "isst.h"
     48
     49struct hfi_event_data {
     50	struct nl_sock *nl_handle;
     51	struct nl_cb *nl_cb;
     52};
     53
     54struct hfi_event_data drv;
     55
     56static int ack_handler(struct nl_msg *msg, void *arg)
     57{
     58	int *err = arg;
     59	*err = 0;
     60	return NL_STOP;
     61}
     62
     63static int finish_handler(struct nl_msg *msg, void *arg)
     64{
     65	int *ret = arg;
     66	*ret = 0;
     67	return NL_SKIP;
     68}
     69
     70static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
     71			 void *arg)
     72{
     73	int *ret = arg;
     74	*ret = err->error;
     75	return NL_SKIP;
     76}
     77
     78static int seq_check_handler(struct nl_msg *msg, void *arg)
     79{
     80	return NL_OK;
     81}
     82
     83static int send_and_recv_msgs(struct hfi_event_data *drv,
     84			      struct nl_msg *msg,
     85			      int (*valid_handler)(struct nl_msg *, void *),
     86			      void *valid_data)
     87{
     88	struct nl_cb *cb;
     89	int err = -ENOMEM;
     90
     91	cb = nl_cb_clone(drv->nl_cb);
     92	if (!cb)
     93		goto out;
     94
     95	err = nl_send_auto_complete(drv->nl_handle, msg);
     96	if (err < 0)
     97		goto out;
     98
     99	err = 1;
    100
    101	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
    102	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
    103	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
    104
    105	if (valid_handler)
    106		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
    107			  valid_handler, valid_data);
    108
    109	while (err > 0)
    110		nl_recvmsgs(drv->nl_handle, cb);
    111 out:
    112	nl_cb_put(cb);
    113	nlmsg_free(msg);
    114	return err;
    115}
    116
    117struct family_data {
    118	const char *group;
    119	int id;
    120};
    121
    122static int family_handler(struct nl_msg *msg, void *arg)
    123{
    124	struct family_data *res = arg;
    125	struct nlattr *tb[CTRL_ATTR_MAX + 1];
    126	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
    127	struct nlattr *mcgrp;
    128	int i;
    129
    130	nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
    131		  genlmsg_attrlen(gnlh, 0), NULL);
    132	if (!tb[CTRL_ATTR_MCAST_GROUPS])
    133		return NL_SKIP;
    134
    135	nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
    136		struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
    137		nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
    138			  nla_len(mcgrp), NULL);
    139		if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
    140		    !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
    141		    strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
    142				res->group,
    143				nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
    144			continue;
    145		res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
    146		break;
    147	};
    148
    149	return 0;
    150}
    151
    152static int nl_get_multicast_id(struct hfi_event_data *drv,
    153			       const char *family, const char *group)
    154{
    155	struct nl_msg *msg;
    156	int ret = -1;
    157	struct family_data res = { group, -ENOENT };
    158
    159	msg = nlmsg_alloc();
    160	if (!msg)
    161		return -ENOMEM;
    162	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
    163		    0, 0, CTRL_CMD_GETFAMILY, 0);
    164	NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
    165
    166	ret = send_and_recv_msgs(drv, msg, family_handler, &res);
    167	msg = NULL;
    168	if (ret == 0)
    169		ret = res.id;
    170
    171nla_put_failure:
    172	nlmsg_free(msg);
    173	return ret;
    174}
    175
    176struct perf_cap {
    177	int cpu;
    178	int perf;
    179	int eff;
    180};
    181
    182static void process_hfi_event(struct perf_cap *perf_cap)
    183{
    184	process_level_change(perf_cap->cpu);
    185}
    186
    187static int handle_event(struct nl_msg *n, void *arg)
    188{
    189	struct nlmsghdr *nlh = nlmsg_hdr(n);
    190	struct genlmsghdr *genlhdr = genlmsg_hdr(nlh);
    191	struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
    192	int ret;
    193	struct perf_cap perf_cap = {0};
    194
    195	ret = genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
    196
    197	debug_printf("Received event %d parse_rer:%d\n", genlhdr->cmd, ret);
    198	if (genlhdr->cmd == THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE) {
    199		struct nlattr *cap;
    200		int j, index = 0;
    201
    202		debug_printf("THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE\n");
    203		nla_for_each_nested(cap, attrs[THERMAL_GENL_ATTR_CPU_CAPABILITY], j) {
    204			switch (index) {
    205			case 0:
    206				perf_cap.cpu = nla_get_u32(cap);
    207				break;
    208			case 1:
    209				perf_cap.perf = nla_get_u32(cap);
    210				break;
    211			case 2:
    212				perf_cap.eff = nla_get_u32(cap);
    213				break;
    214			default:
    215				break;
    216			}
    217			++index;
    218			if (index == 3) {
    219				index = 0;
    220				process_hfi_event(&perf_cap);
    221			}
    222		}
    223	}
    224
    225	return 0;
    226}
    227
    228static int _hfi_exit;
    229
    230static int check_hf_suport(void)
    231{
    232	unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
    233
    234	__cpuid(6, eax, ebx, ecx, edx);
    235	if (eax & BIT(19))
    236		return 1;
    237
    238	return 0;
    239}
    240
    241int hfi_main(void)
    242{
    243	struct nl_sock *sock;
    244	struct nl_cb *cb;
    245	int err = 0;
    246	int mcast_id;
    247	int no_block = 0;
    248
    249	if (!check_hf_suport()) {
    250		fprintf(stderr, "CPU Doesn't support HFI\n");
    251		return -1;
    252	}
    253
    254	sock = nl_socket_alloc();
    255	if (!sock) {
    256		fprintf(stderr, "nl_socket_alloc failed\n");
    257		return -1;
    258	}
    259
    260	if (genl_connect(sock)) {
    261		fprintf(stderr, "genl_connect(sk_event) failed\n");
    262		goto free_sock;
    263	}
    264
    265	drv.nl_handle = sock;
    266	drv.nl_cb = cb = nl_cb_alloc(NL_CB_DEFAULT);
    267	if (drv.nl_cb == NULL) {
    268		printf("Failed to allocate netlink callbacks");
    269		goto free_sock;
    270	}
    271
    272	mcast_id = nl_get_multicast_id(&drv, THERMAL_GENL_FAMILY_NAME,
    273				   THERMAL_GENL_EVENT_GROUP_NAME);
    274	if (mcast_id < 0) {
    275		fprintf(stderr, "nl_get_multicast_id failed\n");
    276		goto free_sock;
    277	}
    278
    279	if (nl_socket_add_membership(sock, mcast_id)) {
    280		fprintf(stderr, "nl_socket_add_membership failed");
    281		goto free_sock;
    282	}
    283
    284	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, seq_check_handler, 0);
    285	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handle_event, NULL);
    286
    287	if (no_block)
    288		nl_socket_set_nonblocking(sock);
    289
    290	debug_printf("hfi is initialized\n");
    291
    292	while (!_hfi_exit && !err) {
    293		err = nl_recvmsgs(sock, cb);
    294		debug_printf("nl_recv_message err:%d\n", err);
    295	}
    296
    297	return 0;
    298
    299	/* Netlink library doesn't have calls to dealloc cb or disconnect */
    300free_sock:
    301	nl_socket_free(sock);
    302
    303	return -1;
    304}
    305
    306void hfi_exit(void)
    307{
    308	_hfi_exit = 1;
    309}