174fe6c29SRuslan Bukin /*
2*85f87cf4SRuslan Bukin * Copyright (c) 2013-2019, Intel Corporation
374fe6c29SRuslan Bukin *
474fe6c29SRuslan Bukin * Redistribution and use in source and binary forms, with or without
574fe6c29SRuslan Bukin * modification, are permitted provided that the following conditions are met:
674fe6c29SRuslan Bukin *
774fe6c29SRuslan Bukin * * Redistributions of source code must retain the above copyright notice,
874fe6c29SRuslan Bukin * this list of conditions and the following disclaimer.
974fe6c29SRuslan Bukin * * Redistributions in binary form must reproduce the above copyright notice,
1074fe6c29SRuslan Bukin * this list of conditions and the following disclaimer in the documentation
1174fe6c29SRuslan Bukin * and/or other materials provided with the distribution.
1274fe6c29SRuslan Bukin * * Neither the name of Intel Corporation nor the names of its contributors
1374fe6c29SRuslan Bukin * may be used to endorse or promote products derived from this software
1474fe6c29SRuslan Bukin * without specific prior written permission.
1574fe6c29SRuslan Bukin *
1674fe6c29SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1774fe6c29SRuslan Bukin * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1874fe6c29SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1974fe6c29SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2074fe6c29SRuslan Bukin * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2174fe6c29SRuslan Bukin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2274fe6c29SRuslan Bukin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2374fe6c29SRuslan Bukin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2474fe6c29SRuslan Bukin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2574fe6c29SRuslan Bukin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2674fe6c29SRuslan Bukin * POSSIBILITY OF SUCH DAMAGE.
2774fe6c29SRuslan Bukin */
2874fe6c29SRuslan Bukin
2974fe6c29SRuslan Bukin #include "pt_packet.h"
3074fe6c29SRuslan Bukin #include "pt_opcodes.h"
3174fe6c29SRuslan Bukin
3274fe6c29SRuslan Bukin #include "intel-pt.h"
3374fe6c29SRuslan Bukin
3474fe6c29SRuslan Bukin #include <limits.h>
3574fe6c29SRuslan Bukin
3674fe6c29SRuslan Bukin
pt_pkt_read_value(const uint8_t * pos,int size)3774fe6c29SRuslan Bukin static uint64_t pt_pkt_read_value(const uint8_t *pos, int size)
3874fe6c29SRuslan Bukin {
3974fe6c29SRuslan Bukin uint64_t val;
4074fe6c29SRuslan Bukin int idx;
4174fe6c29SRuslan Bukin
4274fe6c29SRuslan Bukin for (val = 0, idx = 0; idx < size; ++idx) {
4374fe6c29SRuslan Bukin uint64_t byte = *pos++;
4474fe6c29SRuslan Bukin
4574fe6c29SRuslan Bukin byte <<= (idx * 8);
4674fe6c29SRuslan Bukin val |= byte;
4774fe6c29SRuslan Bukin }
4874fe6c29SRuslan Bukin
4974fe6c29SRuslan Bukin return val;
5074fe6c29SRuslan Bukin }
5174fe6c29SRuslan Bukin
pt_pkt_read_unknown(struct pt_packet * packet,const uint8_t * pos,const struct pt_config * config)5274fe6c29SRuslan Bukin int pt_pkt_read_unknown(struct pt_packet *packet, const uint8_t *pos,
5374fe6c29SRuslan Bukin const struct pt_config *config)
5474fe6c29SRuslan Bukin {
5574fe6c29SRuslan Bukin int (*decode)(struct pt_packet_unknown *, const struct pt_config *,
5674fe6c29SRuslan Bukin const uint8_t *, void *);
5774fe6c29SRuslan Bukin int size;
5874fe6c29SRuslan Bukin
5974fe6c29SRuslan Bukin if (!packet || !pos || !config)
6074fe6c29SRuslan Bukin return -pte_internal;
6174fe6c29SRuslan Bukin
6274fe6c29SRuslan Bukin decode = config->decode.callback;
6374fe6c29SRuslan Bukin if (!decode)
6474fe6c29SRuslan Bukin return -pte_bad_opc;
6574fe6c29SRuslan Bukin
6674fe6c29SRuslan Bukin /* Fill in some default values. */
6774fe6c29SRuslan Bukin packet->payload.unknown.packet = pos;
6874fe6c29SRuslan Bukin packet->payload.unknown.priv = NULL;
6974fe6c29SRuslan Bukin
7074fe6c29SRuslan Bukin /* We accept a size of zero to allow the callback to modify the
7174fe6c29SRuslan Bukin * trace buffer and resume normal decoding.
7274fe6c29SRuslan Bukin */
7374fe6c29SRuslan Bukin size = (*decode)(&packet->payload.unknown, config, pos,
7474fe6c29SRuslan Bukin config->decode.context);
7574fe6c29SRuslan Bukin if (size < 0)
7674fe6c29SRuslan Bukin return size;
7774fe6c29SRuslan Bukin
7874fe6c29SRuslan Bukin if (size > UCHAR_MAX)
7974fe6c29SRuslan Bukin return -pte_invalid;
8074fe6c29SRuslan Bukin
8174fe6c29SRuslan Bukin packet->type = ppt_unknown;
8274fe6c29SRuslan Bukin packet->size = (uint8_t) size;
8374fe6c29SRuslan Bukin
8474fe6c29SRuslan Bukin if (config->end < pos + size)
8574fe6c29SRuslan Bukin return -pte_eos;
8674fe6c29SRuslan Bukin
8774fe6c29SRuslan Bukin return size;
8874fe6c29SRuslan Bukin }
8974fe6c29SRuslan Bukin
pt_pkt_read_psb(const uint8_t * pos,const struct pt_config * config)9074fe6c29SRuslan Bukin int pt_pkt_read_psb(const uint8_t *pos, const struct pt_config *config)
9174fe6c29SRuslan Bukin {
9274fe6c29SRuslan Bukin int count;
9374fe6c29SRuslan Bukin
9474fe6c29SRuslan Bukin if (!pos || !config)
9574fe6c29SRuslan Bukin return -pte_internal;
9674fe6c29SRuslan Bukin
9774fe6c29SRuslan Bukin if (config->end < pos + ptps_psb)
9874fe6c29SRuslan Bukin return -pte_eos;
9974fe6c29SRuslan Bukin
10074fe6c29SRuslan Bukin pos += pt_opcs_psb;
10174fe6c29SRuslan Bukin
10274fe6c29SRuslan Bukin for (count = 0; count < pt_psb_repeat_count; ++count) {
10374fe6c29SRuslan Bukin if (*pos++ != pt_psb_hi)
10474fe6c29SRuslan Bukin return -pte_bad_packet;
10574fe6c29SRuslan Bukin if (*pos++ != pt_psb_lo)
10674fe6c29SRuslan Bukin return -pte_bad_packet;
10774fe6c29SRuslan Bukin }
10874fe6c29SRuslan Bukin
10974fe6c29SRuslan Bukin return ptps_psb;
11074fe6c29SRuslan Bukin }
11174fe6c29SRuslan Bukin
pt_pkt_ip_size(enum pt_ip_compression ipc)11274fe6c29SRuslan Bukin static int pt_pkt_ip_size(enum pt_ip_compression ipc)
11374fe6c29SRuslan Bukin {
11474fe6c29SRuslan Bukin switch (ipc) {
11574fe6c29SRuslan Bukin case pt_ipc_suppressed:
11674fe6c29SRuslan Bukin return 0;
11774fe6c29SRuslan Bukin
11874fe6c29SRuslan Bukin case pt_ipc_update_16:
11974fe6c29SRuslan Bukin return 2;
12074fe6c29SRuslan Bukin
12174fe6c29SRuslan Bukin case pt_ipc_update_32:
12274fe6c29SRuslan Bukin return 4;
12374fe6c29SRuslan Bukin
12474fe6c29SRuslan Bukin case pt_ipc_update_48:
12574fe6c29SRuslan Bukin case pt_ipc_sext_48:
12674fe6c29SRuslan Bukin return 6;
12774fe6c29SRuslan Bukin
12874fe6c29SRuslan Bukin case pt_ipc_full:
12974fe6c29SRuslan Bukin return 8;
13074fe6c29SRuslan Bukin }
13174fe6c29SRuslan Bukin
13274fe6c29SRuslan Bukin return -pte_bad_packet;
13374fe6c29SRuslan Bukin }
13474fe6c29SRuslan Bukin
pt_pkt_read_ip(struct pt_packet_ip * packet,const uint8_t * pos,const struct pt_config * config)13574fe6c29SRuslan Bukin int pt_pkt_read_ip(struct pt_packet_ip *packet, const uint8_t *pos,
13674fe6c29SRuslan Bukin const struct pt_config *config)
13774fe6c29SRuslan Bukin {
13874fe6c29SRuslan Bukin uint64_t ip;
13974fe6c29SRuslan Bukin uint8_t ipc;
14074fe6c29SRuslan Bukin int ipsize;
14174fe6c29SRuslan Bukin
14274fe6c29SRuslan Bukin if (!packet || !pos || !config)
14374fe6c29SRuslan Bukin return -pte_internal;
14474fe6c29SRuslan Bukin
14574fe6c29SRuslan Bukin ipc = (*pos++ >> pt_opm_ipc_shr) & pt_opm_ipc_shr_mask;
14674fe6c29SRuslan Bukin
14774fe6c29SRuslan Bukin ip = 0ull;
14874fe6c29SRuslan Bukin ipsize = pt_pkt_ip_size((enum pt_ip_compression) ipc);
14974fe6c29SRuslan Bukin if (ipsize < 0)
15074fe6c29SRuslan Bukin return ipsize;
15174fe6c29SRuslan Bukin
15274fe6c29SRuslan Bukin if (config->end < pos + ipsize)
15374fe6c29SRuslan Bukin return -pte_eos;
15474fe6c29SRuslan Bukin
15574fe6c29SRuslan Bukin if (ipsize)
15674fe6c29SRuslan Bukin ip = pt_pkt_read_value(pos, ipsize);
15774fe6c29SRuslan Bukin
15874fe6c29SRuslan Bukin packet->ipc = (enum pt_ip_compression) ipc;
15974fe6c29SRuslan Bukin packet->ip = ip;
16074fe6c29SRuslan Bukin
16174fe6c29SRuslan Bukin return ipsize + 1;
16274fe6c29SRuslan Bukin }
16374fe6c29SRuslan Bukin
pt_pkt_tnt_bit_size(uint64_t payload)16474fe6c29SRuslan Bukin static uint8_t pt_pkt_tnt_bit_size(uint64_t payload)
16574fe6c29SRuslan Bukin {
16674fe6c29SRuslan Bukin uint8_t size;
16774fe6c29SRuslan Bukin
16874fe6c29SRuslan Bukin /* The payload bit-size is the bit-index of the payload's stop-bit,
16974fe6c29SRuslan Bukin * which itself is not part of the payload proper.
17074fe6c29SRuslan Bukin */
17174fe6c29SRuslan Bukin for (size = 0; ; size += 1) {
17274fe6c29SRuslan Bukin payload >>= 1;
17374fe6c29SRuslan Bukin if (!payload)
17474fe6c29SRuslan Bukin break;
17574fe6c29SRuslan Bukin }
17674fe6c29SRuslan Bukin
17774fe6c29SRuslan Bukin return size;
17874fe6c29SRuslan Bukin }
17974fe6c29SRuslan Bukin
pt_pkt_read_tnt(struct pt_packet_tnt * packet,uint64_t payload)18074fe6c29SRuslan Bukin static int pt_pkt_read_tnt(struct pt_packet_tnt *packet, uint64_t payload)
18174fe6c29SRuslan Bukin {
18274fe6c29SRuslan Bukin uint8_t bit_size;
18374fe6c29SRuslan Bukin
18474fe6c29SRuslan Bukin if (!packet)
18574fe6c29SRuslan Bukin return -pte_internal;
18674fe6c29SRuslan Bukin
18774fe6c29SRuslan Bukin bit_size = pt_pkt_tnt_bit_size(payload);
18874fe6c29SRuslan Bukin if (!bit_size)
18974fe6c29SRuslan Bukin return -pte_bad_packet;
19074fe6c29SRuslan Bukin
19174fe6c29SRuslan Bukin /* Remove the stop bit from the payload. */
19274fe6c29SRuslan Bukin payload &= ~(1ull << bit_size);
19374fe6c29SRuslan Bukin
19474fe6c29SRuslan Bukin packet->payload = payload;
19574fe6c29SRuslan Bukin packet->bit_size = bit_size;
19674fe6c29SRuslan Bukin
19774fe6c29SRuslan Bukin return 0;
19874fe6c29SRuslan Bukin }
19974fe6c29SRuslan Bukin
pt_pkt_read_tnt_8(struct pt_packet_tnt * packet,const uint8_t * pos,const struct pt_config * config)20074fe6c29SRuslan Bukin int pt_pkt_read_tnt_8(struct pt_packet_tnt *packet, const uint8_t *pos,
20174fe6c29SRuslan Bukin const struct pt_config *config)
20274fe6c29SRuslan Bukin {
20374fe6c29SRuslan Bukin int errcode;
20474fe6c29SRuslan Bukin
20574fe6c29SRuslan Bukin (void) config;
20674fe6c29SRuslan Bukin
20774fe6c29SRuslan Bukin if (!pos)
20874fe6c29SRuslan Bukin return -pte_internal;
20974fe6c29SRuslan Bukin
21074fe6c29SRuslan Bukin errcode = pt_pkt_read_tnt(packet, pos[0] >> pt_opm_tnt_8_shr);
21174fe6c29SRuslan Bukin if (errcode < 0)
21274fe6c29SRuslan Bukin return errcode;
21374fe6c29SRuslan Bukin
21474fe6c29SRuslan Bukin return ptps_tnt_8;
21574fe6c29SRuslan Bukin }
21674fe6c29SRuslan Bukin
pt_pkt_read_tnt_64(struct pt_packet_tnt * packet,const uint8_t * pos,const struct pt_config * config)21774fe6c29SRuslan Bukin int pt_pkt_read_tnt_64(struct pt_packet_tnt *packet, const uint8_t *pos,
21874fe6c29SRuslan Bukin const struct pt_config *config)
21974fe6c29SRuslan Bukin {
22074fe6c29SRuslan Bukin uint64_t payload;
22174fe6c29SRuslan Bukin int errcode;
22274fe6c29SRuslan Bukin
22374fe6c29SRuslan Bukin if (!pos || !config)
22474fe6c29SRuslan Bukin return -pte_internal;
22574fe6c29SRuslan Bukin
22674fe6c29SRuslan Bukin if (config->end < pos + ptps_tnt_64)
22774fe6c29SRuslan Bukin return -pte_eos;
22874fe6c29SRuslan Bukin
22974fe6c29SRuslan Bukin payload = pt_pkt_read_value(pos + pt_opcs_tnt_64, pt_pl_tnt_64_size);
23074fe6c29SRuslan Bukin
23174fe6c29SRuslan Bukin errcode = pt_pkt_read_tnt(packet, payload);
23274fe6c29SRuslan Bukin if (errcode < 0)
23374fe6c29SRuslan Bukin return errcode;
23474fe6c29SRuslan Bukin
23574fe6c29SRuslan Bukin return ptps_tnt_64;
23674fe6c29SRuslan Bukin }
23774fe6c29SRuslan Bukin
pt_pkt_read_pip(struct pt_packet_pip * packet,const uint8_t * pos,const struct pt_config * config)23874fe6c29SRuslan Bukin int pt_pkt_read_pip(struct pt_packet_pip *packet, const uint8_t *pos,
23974fe6c29SRuslan Bukin const struct pt_config *config)
24074fe6c29SRuslan Bukin {
24174fe6c29SRuslan Bukin uint64_t payload;
24274fe6c29SRuslan Bukin
24374fe6c29SRuslan Bukin if (!packet || !pos || !config)
24474fe6c29SRuslan Bukin return -pte_internal;
24574fe6c29SRuslan Bukin
24674fe6c29SRuslan Bukin if (config->end < pos + ptps_pip)
24774fe6c29SRuslan Bukin return -pte_eos;
24874fe6c29SRuslan Bukin
24974fe6c29SRuslan Bukin /* Read the payload. */
25074fe6c29SRuslan Bukin payload = pt_pkt_read_value(pos + pt_opcs_pip, pt_pl_pip_size);
25174fe6c29SRuslan Bukin
25274fe6c29SRuslan Bukin /* Extract the non-root information from the payload. */
25374fe6c29SRuslan Bukin packet->nr = payload & pt_pl_pip_nr;
25474fe6c29SRuslan Bukin
25574fe6c29SRuslan Bukin /* Create the cr3 value. */
25674fe6c29SRuslan Bukin payload >>= pt_pl_pip_shr;
25774fe6c29SRuslan Bukin payload <<= pt_pl_pip_shl;
25874fe6c29SRuslan Bukin packet->cr3 = payload;
25974fe6c29SRuslan Bukin
26074fe6c29SRuslan Bukin return ptps_pip;
26174fe6c29SRuslan Bukin }
26274fe6c29SRuslan Bukin
pt_pkt_read_mode_exec(struct pt_packet_mode_exec * packet,uint8_t mode)26374fe6c29SRuslan Bukin static int pt_pkt_read_mode_exec(struct pt_packet_mode_exec *packet,
26474fe6c29SRuslan Bukin uint8_t mode)
26574fe6c29SRuslan Bukin {
26674fe6c29SRuslan Bukin if (!packet)
26774fe6c29SRuslan Bukin return -pte_internal;
26874fe6c29SRuslan Bukin
26974fe6c29SRuslan Bukin packet->csl = (mode & pt_mob_exec_csl) != 0;
27074fe6c29SRuslan Bukin packet->csd = (mode & pt_mob_exec_csd) != 0;
27174fe6c29SRuslan Bukin
27274fe6c29SRuslan Bukin return ptps_mode;
27374fe6c29SRuslan Bukin }
27474fe6c29SRuslan Bukin
pt_pkt_read_mode_tsx(struct pt_packet_mode_tsx * packet,uint8_t mode)27574fe6c29SRuslan Bukin static int pt_pkt_read_mode_tsx(struct pt_packet_mode_tsx *packet,
27674fe6c29SRuslan Bukin uint8_t mode)
27774fe6c29SRuslan Bukin {
27874fe6c29SRuslan Bukin if (!packet)
27974fe6c29SRuslan Bukin return -pte_internal;
28074fe6c29SRuslan Bukin
28174fe6c29SRuslan Bukin packet->intx = (mode & pt_mob_tsx_intx) != 0;
28274fe6c29SRuslan Bukin packet->abrt = (mode & pt_mob_tsx_abrt) != 0;
28374fe6c29SRuslan Bukin
28474fe6c29SRuslan Bukin return ptps_mode;
28574fe6c29SRuslan Bukin }
28674fe6c29SRuslan Bukin
pt_pkt_read_mode(struct pt_packet_mode * packet,const uint8_t * pos,const struct pt_config * config)28774fe6c29SRuslan Bukin int pt_pkt_read_mode(struct pt_packet_mode *packet, const uint8_t *pos,
28874fe6c29SRuslan Bukin const struct pt_config *config)
28974fe6c29SRuslan Bukin {
29074fe6c29SRuslan Bukin uint8_t payload, mode, leaf;
29174fe6c29SRuslan Bukin
29274fe6c29SRuslan Bukin if (!packet || !pos || !config)
29374fe6c29SRuslan Bukin return -pte_internal;
29474fe6c29SRuslan Bukin
29574fe6c29SRuslan Bukin if (config->end < pos + ptps_mode)
29674fe6c29SRuslan Bukin return -pte_eos;
29774fe6c29SRuslan Bukin
29874fe6c29SRuslan Bukin payload = pos[pt_opcs_mode];
29974fe6c29SRuslan Bukin leaf = payload & pt_mom_leaf;
30074fe6c29SRuslan Bukin mode = payload & pt_mom_bits;
30174fe6c29SRuslan Bukin
30274fe6c29SRuslan Bukin packet->leaf = (enum pt_mode_leaf) leaf;
30374fe6c29SRuslan Bukin switch (leaf) {
30474fe6c29SRuslan Bukin default:
30574fe6c29SRuslan Bukin return -pte_bad_packet;
30674fe6c29SRuslan Bukin
30774fe6c29SRuslan Bukin case pt_mol_exec:
30874fe6c29SRuslan Bukin return pt_pkt_read_mode_exec(&packet->bits.exec, mode);
30974fe6c29SRuslan Bukin
31074fe6c29SRuslan Bukin case pt_mol_tsx:
31174fe6c29SRuslan Bukin return pt_pkt_read_mode_tsx(&packet->bits.tsx, mode);
31274fe6c29SRuslan Bukin }
31374fe6c29SRuslan Bukin }
31474fe6c29SRuslan Bukin
pt_pkt_read_tsc(struct pt_packet_tsc * packet,const uint8_t * pos,const struct pt_config * config)31574fe6c29SRuslan Bukin int pt_pkt_read_tsc(struct pt_packet_tsc *packet, const uint8_t *pos,
31674fe6c29SRuslan Bukin const struct pt_config *config)
31774fe6c29SRuslan Bukin {
31874fe6c29SRuslan Bukin if (!packet || !pos || !config)
31974fe6c29SRuslan Bukin return -pte_internal;
32074fe6c29SRuslan Bukin
32174fe6c29SRuslan Bukin if (config->end < pos + ptps_tsc)
32274fe6c29SRuslan Bukin return -pte_eos;
32374fe6c29SRuslan Bukin
32474fe6c29SRuslan Bukin packet->tsc = pt_pkt_read_value(pos + pt_opcs_tsc, pt_pl_tsc_size);
32574fe6c29SRuslan Bukin
32674fe6c29SRuslan Bukin return ptps_tsc;
32774fe6c29SRuslan Bukin }
32874fe6c29SRuslan Bukin
pt_pkt_read_cbr(struct pt_packet_cbr * packet,const uint8_t * pos,const struct pt_config * config)32974fe6c29SRuslan Bukin int pt_pkt_read_cbr(struct pt_packet_cbr *packet, const uint8_t *pos,
33074fe6c29SRuslan Bukin const struct pt_config *config)
33174fe6c29SRuslan Bukin {
33274fe6c29SRuslan Bukin if (!packet || !pos || !config)
33374fe6c29SRuslan Bukin return -pte_internal;
33474fe6c29SRuslan Bukin
33574fe6c29SRuslan Bukin if (config->end < pos + ptps_cbr)
33674fe6c29SRuslan Bukin return -pte_eos;
33774fe6c29SRuslan Bukin
33874fe6c29SRuslan Bukin packet->ratio = pos[2];
33974fe6c29SRuslan Bukin
34074fe6c29SRuslan Bukin return ptps_cbr;
34174fe6c29SRuslan Bukin }
34274fe6c29SRuslan Bukin
pt_pkt_read_tma(struct pt_packet_tma * packet,const uint8_t * pos,const struct pt_config * config)34374fe6c29SRuslan Bukin int pt_pkt_read_tma(struct pt_packet_tma *packet, const uint8_t *pos,
34474fe6c29SRuslan Bukin const struct pt_config *config)
34574fe6c29SRuslan Bukin {
34674fe6c29SRuslan Bukin uint16_t ctc, fc;
34774fe6c29SRuslan Bukin
34874fe6c29SRuslan Bukin if (!packet || !pos || !config)
34974fe6c29SRuslan Bukin return -pte_internal;
35074fe6c29SRuslan Bukin
35174fe6c29SRuslan Bukin if (config->end < pos + ptps_tma)
35274fe6c29SRuslan Bukin return -pte_eos;
35374fe6c29SRuslan Bukin
35474fe6c29SRuslan Bukin ctc = pos[pt_pl_tma_ctc_0];
35574fe6c29SRuslan Bukin ctc |= pos[pt_pl_tma_ctc_1] << 8;
35674fe6c29SRuslan Bukin
35774fe6c29SRuslan Bukin fc = pos[pt_pl_tma_fc_0];
35874fe6c29SRuslan Bukin fc |= pos[pt_pl_tma_fc_1] << 8;
35974fe6c29SRuslan Bukin
36074fe6c29SRuslan Bukin if (fc & ~pt_pl_tma_fc_mask)
36174fe6c29SRuslan Bukin return -pte_bad_packet;
36274fe6c29SRuslan Bukin
36374fe6c29SRuslan Bukin packet->ctc = ctc;
36474fe6c29SRuslan Bukin packet->fc = fc;
36574fe6c29SRuslan Bukin
36674fe6c29SRuslan Bukin return ptps_tma;
36774fe6c29SRuslan Bukin }
36874fe6c29SRuslan Bukin
pt_pkt_read_mtc(struct pt_packet_mtc * packet,const uint8_t * pos,const struct pt_config * config)36974fe6c29SRuslan Bukin int pt_pkt_read_mtc(struct pt_packet_mtc *packet, const uint8_t *pos,
37074fe6c29SRuslan Bukin const struct pt_config *config)
37174fe6c29SRuslan Bukin {
37274fe6c29SRuslan Bukin if (!packet || !pos || !config)
37374fe6c29SRuslan Bukin return -pte_internal;
37474fe6c29SRuslan Bukin
37574fe6c29SRuslan Bukin if (config->end < pos + ptps_mtc)
37674fe6c29SRuslan Bukin return -pte_eos;
37774fe6c29SRuslan Bukin
37874fe6c29SRuslan Bukin packet->ctc = pos[pt_opcs_mtc];
37974fe6c29SRuslan Bukin
38074fe6c29SRuslan Bukin return ptps_mtc;
38174fe6c29SRuslan Bukin }
38274fe6c29SRuslan Bukin
pt_pkt_read_cyc(struct pt_packet_cyc * packet,const uint8_t * pos,const struct pt_config * config)38374fe6c29SRuslan Bukin int pt_pkt_read_cyc(struct pt_packet_cyc *packet, const uint8_t *pos,
38474fe6c29SRuslan Bukin const struct pt_config *config)
38574fe6c29SRuslan Bukin {
38674fe6c29SRuslan Bukin const uint8_t *begin, *end;
38774fe6c29SRuslan Bukin uint64_t value;
38874fe6c29SRuslan Bukin uint8_t cyc, ext, shl;
38974fe6c29SRuslan Bukin
39074fe6c29SRuslan Bukin if (!packet || !pos || !config)
39174fe6c29SRuslan Bukin return -pte_internal;
39274fe6c29SRuslan Bukin
39374fe6c29SRuslan Bukin begin = pos;
39474fe6c29SRuslan Bukin end = config->end;
39574fe6c29SRuslan Bukin
39674fe6c29SRuslan Bukin /* The first byte contains the opcode and part of the payload.
39774fe6c29SRuslan Bukin * We already checked that this first byte is within bounds.
39874fe6c29SRuslan Bukin */
39974fe6c29SRuslan Bukin cyc = *pos++;
40074fe6c29SRuslan Bukin
40174fe6c29SRuslan Bukin ext = cyc & pt_opm_cyc_ext;
40274fe6c29SRuslan Bukin cyc >>= pt_opm_cyc_shr;
40374fe6c29SRuslan Bukin
40474fe6c29SRuslan Bukin value = cyc;
40574fe6c29SRuslan Bukin shl = (8 - pt_opm_cyc_shr);
40674fe6c29SRuslan Bukin
40774fe6c29SRuslan Bukin while (ext) {
40874fe6c29SRuslan Bukin uint64_t bits;
40974fe6c29SRuslan Bukin
41074fe6c29SRuslan Bukin if (end <= pos)
41174fe6c29SRuslan Bukin return -pte_eos;
41274fe6c29SRuslan Bukin
41374fe6c29SRuslan Bukin bits = *pos++;
41474fe6c29SRuslan Bukin ext = bits & pt_opm_cycx_ext;
41574fe6c29SRuslan Bukin
41674fe6c29SRuslan Bukin bits >>= pt_opm_cycx_shr;
41774fe6c29SRuslan Bukin bits <<= shl;
41874fe6c29SRuslan Bukin
41974fe6c29SRuslan Bukin shl += (8 - pt_opm_cycx_shr);
42074fe6c29SRuslan Bukin if (sizeof(value) * 8 < shl)
42174fe6c29SRuslan Bukin return -pte_bad_packet;
42274fe6c29SRuslan Bukin
42374fe6c29SRuslan Bukin value |= bits;
42474fe6c29SRuslan Bukin }
42574fe6c29SRuslan Bukin
42674fe6c29SRuslan Bukin packet->value = value;
42774fe6c29SRuslan Bukin
42874fe6c29SRuslan Bukin return (int) (pos - begin);
42974fe6c29SRuslan Bukin }
43074fe6c29SRuslan Bukin
pt_pkt_read_vmcs(struct pt_packet_vmcs * packet,const uint8_t * pos,const struct pt_config * config)43174fe6c29SRuslan Bukin int pt_pkt_read_vmcs(struct pt_packet_vmcs *packet, const uint8_t *pos,
43274fe6c29SRuslan Bukin const struct pt_config *config)
43374fe6c29SRuslan Bukin {
43474fe6c29SRuslan Bukin uint64_t payload;
43574fe6c29SRuslan Bukin
43674fe6c29SRuslan Bukin if (!packet || !pos || !config)
43774fe6c29SRuslan Bukin return -pte_internal;
43874fe6c29SRuslan Bukin
43974fe6c29SRuslan Bukin if (config->end < pos + ptps_vmcs)
44074fe6c29SRuslan Bukin return -pte_eos;
44174fe6c29SRuslan Bukin
44274fe6c29SRuslan Bukin payload = pt_pkt_read_value(pos + pt_opcs_vmcs, pt_pl_vmcs_size);
44374fe6c29SRuslan Bukin
44474fe6c29SRuslan Bukin packet->base = payload << pt_pl_vmcs_shl;
44574fe6c29SRuslan Bukin
44674fe6c29SRuslan Bukin return ptps_vmcs;
44774fe6c29SRuslan Bukin }
44874fe6c29SRuslan Bukin
pt_pkt_read_mnt(struct pt_packet_mnt * packet,const uint8_t * pos,const struct pt_config * config)44974fe6c29SRuslan Bukin int pt_pkt_read_mnt(struct pt_packet_mnt *packet, const uint8_t *pos,
45074fe6c29SRuslan Bukin const struct pt_config *config)
45174fe6c29SRuslan Bukin {
45274fe6c29SRuslan Bukin if (!packet || !pos || !config)
45374fe6c29SRuslan Bukin return -pte_internal;
45474fe6c29SRuslan Bukin
45574fe6c29SRuslan Bukin if (config->end < pos + ptps_mnt)
45674fe6c29SRuslan Bukin return -pte_eos;
45774fe6c29SRuslan Bukin
45874fe6c29SRuslan Bukin packet->payload = pt_pkt_read_value(pos + pt_opcs_mnt, pt_pl_mnt_size);
45974fe6c29SRuslan Bukin
46074fe6c29SRuslan Bukin return ptps_mnt;
46174fe6c29SRuslan Bukin }
46274fe6c29SRuslan Bukin
pt_pkt_read_exstop(struct pt_packet_exstop * packet,const uint8_t * pos,const struct pt_config * config)46374fe6c29SRuslan Bukin int pt_pkt_read_exstop(struct pt_packet_exstop *packet, const uint8_t *pos,
46474fe6c29SRuslan Bukin const struct pt_config *config)
46574fe6c29SRuslan Bukin {
46674fe6c29SRuslan Bukin if (!packet || !pos || !config)
46774fe6c29SRuslan Bukin return -pte_internal;
46874fe6c29SRuslan Bukin
46974fe6c29SRuslan Bukin if (config->end < pos + ptps_exstop)
47074fe6c29SRuslan Bukin return -pte_eos;
47174fe6c29SRuslan Bukin
47274fe6c29SRuslan Bukin packet->ip = pos[1] & pt_pl_exstop_ip_mask ? 1 : 0;
47374fe6c29SRuslan Bukin
47474fe6c29SRuslan Bukin return ptps_exstop;
47574fe6c29SRuslan Bukin }
47674fe6c29SRuslan Bukin
pt_pkt_read_mwait(struct pt_packet_mwait * packet,const uint8_t * pos,const struct pt_config * config)47774fe6c29SRuslan Bukin int pt_pkt_read_mwait(struct pt_packet_mwait *packet, const uint8_t *pos,
47874fe6c29SRuslan Bukin const struct pt_config *config)
47974fe6c29SRuslan Bukin {
48074fe6c29SRuslan Bukin if (!packet || !pos || !config)
48174fe6c29SRuslan Bukin return -pte_internal;
48274fe6c29SRuslan Bukin
48374fe6c29SRuslan Bukin if (config->end < pos + ptps_mwait)
48474fe6c29SRuslan Bukin return -pte_eos;
48574fe6c29SRuslan Bukin
48674fe6c29SRuslan Bukin packet->hints = (uint32_t) pt_pkt_read_value(pos + pt_opcs_mwait,
48774fe6c29SRuslan Bukin pt_pl_mwait_hints_size);
48874fe6c29SRuslan Bukin packet->ext = (uint32_t) pt_pkt_read_value(pos + pt_opcs_mwait +
48974fe6c29SRuslan Bukin pt_pl_mwait_hints_size,
49074fe6c29SRuslan Bukin pt_pl_mwait_ext_size);
49174fe6c29SRuslan Bukin return ptps_mwait;
49274fe6c29SRuslan Bukin }
49374fe6c29SRuslan Bukin
pt_pkt_read_pwre(struct pt_packet_pwre * packet,const uint8_t * pos,const struct pt_config * config)49474fe6c29SRuslan Bukin int pt_pkt_read_pwre(struct pt_packet_pwre *packet, const uint8_t *pos,
49574fe6c29SRuslan Bukin const struct pt_config *config)
49674fe6c29SRuslan Bukin {
49774fe6c29SRuslan Bukin uint64_t payload;
49874fe6c29SRuslan Bukin
49974fe6c29SRuslan Bukin if (!packet || !pos || !config)
50074fe6c29SRuslan Bukin return -pte_internal;
50174fe6c29SRuslan Bukin
50274fe6c29SRuslan Bukin if (config->end < pos + ptps_pwre)
50374fe6c29SRuslan Bukin return -pte_eos;
50474fe6c29SRuslan Bukin
50574fe6c29SRuslan Bukin payload = pt_pkt_read_value(pos + pt_opcs_pwre, pt_pl_pwre_size);
50674fe6c29SRuslan Bukin
50774fe6c29SRuslan Bukin memset(packet, 0, sizeof(*packet));
50874fe6c29SRuslan Bukin packet->state = (uint8_t) ((payload & pt_pl_pwre_state_mask) >>
50974fe6c29SRuslan Bukin pt_pl_pwre_state_shr);
51074fe6c29SRuslan Bukin packet->sub_state = (uint8_t) ((payload & pt_pl_pwre_sub_state_mask) >>
51174fe6c29SRuslan Bukin pt_pl_pwre_sub_state_shr);
51274fe6c29SRuslan Bukin if (payload & pt_pl_pwre_hw_mask)
51374fe6c29SRuslan Bukin packet->hw = 1;
51474fe6c29SRuslan Bukin
51574fe6c29SRuslan Bukin return ptps_pwre;
51674fe6c29SRuslan Bukin }
51774fe6c29SRuslan Bukin
pt_pkt_read_pwrx(struct pt_packet_pwrx * packet,const uint8_t * pos,const struct pt_config * config)51874fe6c29SRuslan Bukin int pt_pkt_read_pwrx(struct pt_packet_pwrx *packet, const uint8_t *pos,
51974fe6c29SRuslan Bukin const struct pt_config *config)
52074fe6c29SRuslan Bukin {
52174fe6c29SRuslan Bukin uint64_t payload;
52274fe6c29SRuslan Bukin
52374fe6c29SRuslan Bukin if (!packet || !pos || !config)
52474fe6c29SRuslan Bukin return -pte_internal;
52574fe6c29SRuslan Bukin
52674fe6c29SRuslan Bukin if (config->end < pos + ptps_pwrx)
52774fe6c29SRuslan Bukin return -pte_eos;
52874fe6c29SRuslan Bukin
52974fe6c29SRuslan Bukin payload = pt_pkt_read_value(pos + pt_opcs_pwrx, pt_pl_pwrx_size);
53074fe6c29SRuslan Bukin
53174fe6c29SRuslan Bukin memset(packet, 0, sizeof(*packet));
53274fe6c29SRuslan Bukin packet->last = (uint8_t) ((payload & pt_pl_pwrx_last_mask) >>
53374fe6c29SRuslan Bukin pt_pl_pwrx_last_shr);
53474fe6c29SRuslan Bukin packet->deepest = (uint8_t) ((payload & pt_pl_pwrx_deepest_mask) >>
53574fe6c29SRuslan Bukin pt_pl_pwrx_deepest_shr);
53674fe6c29SRuslan Bukin if (payload & pt_pl_pwrx_wr_int)
53774fe6c29SRuslan Bukin packet->interrupt = 1;
53874fe6c29SRuslan Bukin if (payload & pt_pl_pwrx_wr_store)
53974fe6c29SRuslan Bukin packet->store = 1;
54074fe6c29SRuslan Bukin if (payload & pt_pl_pwrx_wr_hw)
54174fe6c29SRuslan Bukin packet->autonomous = 1;
54274fe6c29SRuslan Bukin
54374fe6c29SRuslan Bukin return ptps_pwrx;
54474fe6c29SRuslan Bukin }
54574fe6c29SRuslan Bukin
pt_pkt_read_ptw(struct pt_packet_ptw * packet,const uint8_t * pos,const struct pt_config * config)54674fe6c29SRuslan Bukin int pt_pkt_read_ptw(struct pt_packet_ptw *packet, const uint8_t *pos,
54774fe6c29SRuslan Bukin const struct pt_config *config)
54874fe6c29SRuslan Bukin {
54974fe6c29SRuslan Bukin uint8_t opc, plc;
55074fe6c29SRuslan Bukin int size;
55174fe6c29SRuslan Bukin
55274fe6c29SRuslan Bukin if (!packet || !pos || !config)
55374fe6c29SRuslan Bukin return -pte_internal;
55474fe6c29SRuslan Bukin
55574fe6c29SRuslan Bukin /* Skip the ext opcode. */
55674fe6c29SRuslan Bukin pos++;
55774fe6c29SRuslan Bukin
55874fe6c29SRuslan Bukin opc = *pos++;
55974fe6c29SRuslan Bukin plc = (opc >> pt_opm_ptw_pb_shr) & pt_opm_ptw_pb_shr_mask;
56074fe6c29SRuslan Bukin
56174fe6c29SRuslan Bukin size = pt_ptw_size(plc);
56274fe6c29SRuslan Bukin if (size < 0)
56374fe6c29SRuslan Bukin return size;
56474fe6c29SRuslan Bukin
56574fe6c29SRuslan Bukin if (config->end < pos + size)
56674fe6c29SRuslan Bukin return -pte_eos;
56774fe6c29SRuslan Bukin
56874fe6c29SRuslan Bukin packet->payload = pt_pkt_read_value(pos, size);
56974fe6c29SRuslan Bukin packet->plc = plc;
57074fe6c29SRuslan Bukin packet->ip = opc & pt_opm_ptw_ip ? 1 : 0;
57174fe6c29SRuslan Bukin
57274fe6c29SRuslan Bukin return pt_opcs_ptw + size;
57374fe6c29SRuslan Bukin }
574