174fe6c29SRuslan Bukin /*
274fe6c29SRuslan Bukin  * Copyright (c) 2016-2018, 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_block_decoder.h"
3074fe6c29SRuslan Bukin #include "pt_block_cache.h"
3174fe6c29SRuslan Bukin #include "pt_section.h"
3274fe6c29SRuslan Bukin #include "pt_image.h"
3374fe6c29SRuslan Bukin #include "pt_insn.h"
3474fe6c29SRuslan Bukin #include "pt_config.h"
3574fe6c29SRuslan Bukin #include "pt_asid.h"
3674fe6c29SRuslan Bukin #include "pt_compiler.h"
3774fe6c29SRuslan Bukin 
3874fe6c29SRuslan Bukin #include "intel-pt.h"
3974fe6c29SRuslan Bukin 
4074fe6c29SRuslan Bukin #include <string.h>
4174fe6c29SRuslan Bukin #include <stdlib.h>
4274fe6c29SRuslan Bukin 
4374fe6c29SRuslan Bukin 
4474fe6c29SRuslan Bukin static int pt_blk_proceed_trailing_event(struct pt_block_decoder *,
4574fe6c29SRuslan Bukin 					 struct pt_block *);
4674fe6c29SRuslan Bukin 
4774fe6c29SRuslan Bukin 
4874fe6c29SRuslan Bukin static int pt_blk_status(const struct pt_block_decoder *decoder, int flags)
4974fe6c29SRuslan Bukin {
5074fe6c29SRuslan Bukin 	int status;
5174fe6c29SRuslan Bukin 
5274fe6c29SRuslan Bukin 	if (!decoder)
5374fe6c29SRuslan Bukin 		return -pte_internal;
5474fe6c29SRuslan Bukin 
5574fe6c29SRuslan Bukin 	status = decoder->status;
5674fe6c29SRuslan Bukin 
5774fe6c29SRuslan Bukin 	/* Indicate whether tracing is disabled or enabled.
5874fe6c29SRuslan Bukin 	 *
5974fe6c29SRuslan Bukin 	 * This duplicates the indication in struct pt_insn and covers the case
6074fe6c29SRuslan Bukin 	 * where we indicate the status after synchronizing.
6174fe6c29SRuslan Bukin 	 */
6274fe6c29SRuslan Bukin 	if (!decoder->enabled)
6374fe6c29SRuslan Bukin 		flags |= pts_ip_suppressed;
6474fe6c29SRuslan Bukin 
6574fe6c29SRuslan Bukin 	/* Forward end-of-trace indications.
6674fe6c29SRuslan Bukin 	 *
6774fe6c29SRuslan Bukin 	 * Postpone it as long as we're still processing events, though.
6874fe6c29SRuslan Bukin 	 */
6974fe6c29SRuslan Bukin 	if ((status & pts_eos) && !decoder->process_event)
7074fe6c29SRuslan Bukin 		flags |= pts_eos;
7174fe6c29SRuslan Bukin 
7274fe6c29SRuslan Bukin 	return flags;
7374fe6c29SRuslan Bukin }
7474fe6c29SRuslan Bukin 
7574fe6c29SRuslan Bukin static void pt_blk_reset(struct pt_block_decoder *decoder)
7674fe6c29SRuslan Bukin {
7774fe6c29SRuslan Bukin 	if (!decoder)
7874fe6c29SRuslan Bukin 		return;
7974fe6c29SRuslan Bukin 
8074fe6c29SRuslan Bukin 	decoder->mode = ptem_unknown;
8174fe6c29SRuslan Bukin 	decoder->ip = 0ull;
8274fe6c29SRuslan Bukin 	decoder->status = 0;
8374fe6c29SRuslan Bukin 	decoder->enabled = 0;
8474fe6c29SRuslan Bukin 	decoder->process_event = 0;
8574fe6c29SRuslan Bukin 	decoder->speculative = 0;
8674fe6c29SRuslan Bukin 	decoder->process_insn = 0;
8774fe6c29SRuslan Bukin 	decoder->bound_paging = 0;
8874fe6c29SRuslan Bukin 	decoder->bound_vmcs = 0;
8974fe6c29SRuslan Bukin 	decoder->bound_ptwrite = 0;
9074fe6c29SRuslan Bukin 
9174fe6c29SRuslan Bukin 	memset(&decoder->event, 0, sizeof(decoder->event));
9274fe6c29SRuslan Bukin 	pt_retstack_init(&decoder->retstack);
9374fe6c29SRuslan Bukin 	pt_asid_init(&decoder->asid);
9474fe6c29SRuslan Bukin }
9574fe6c29SRuslan Bukin 
9674fe6c29SRuslan Bukin /* Initialize the query decoder flags based on our flags. */
9774fe6c29SRuslan Bukin 
9874fe6c29SRuslan Bukin static int pt_blk_init_qry_flags(struct pt_conf_flags *qflags,
9974fe6c29SRuslan Bukin 				 const struct pt_conf_flags *flags)
10074fe6c29SRuslan Bukin {
10174fe6c29SRuslan Bukin 	if (!qflags || !flags)
10274fe6c29SRuslan Bukin 		return -pte_internal;
10374fe6c29SRuslan Bukin 
10474fe6c29SRuslan Bukin 	memset(qflags, 0, sizeof(*qflags));
10574fe6c29SRuslan Bukin 
10674fe6c29SRuslan Bukin 	return 0;
10774fe6c29SRuslan Bukin }
10874fe6c29SRuslan Bukin 
10974fe6c29SRuslan Bukin int pt_blk_decoder_init(struct pt_block_decoder *decoder,
11074fe6c29SRuslan Bukin 			const struct pt_config *uconfig)
11174fe6c29SRuslan Bukin {
11274fe6c29SRuslan Bukin 	struct pt_config config;
11374fe6c29SRuslan Bukin 	int errcode;
11474fe6c29SRuslan Bukin 
11574fe6c29SRuslan Bukin 	if (!decoder)
11674fe6c29SRuslan Bukin 		return -pte_internal;
11774fe6c29SRuslan Bukin 
11874fe6c29SRuslan Bukin 	errcode = pt_config_from_user(&config, uconfig);
11974fe6c29SRuslan Bukin 	if (errcode < 0)
12074fe6c29SRuslan Bukin 		return errcode;
12174fe6c29SRuslan Bukin 
12274fe6c29SRuslan Bukin 	/* The user supplied decoder flags. */
12374fe6c29SRuslan Bukin 	decoder->flags = config.flags;
12474fe6c29SRuslan Bukin 
12574fe6c29SRuslan Bukin 	/* Set the flags we need for the query decoder we use. */
12674fe6c29SRuslan Bukin 	errcode = pt_blk_init_qry_flags(&config.flags, &decoder->flags);
12774fe6c29SRuslan Bukin 	if (errcode < 0)
12874fe6c29SRuslan Bukin 		return errcode;
12974fe6c29SRuslan Bukin 
13074fe6c29SRuslan Bukin 	errcode = pt_qry_decoder_init(&decoder->query, &config);
13174fe6c29SRuslan Bukin 	if (errcode < 0)
13274fe6c29SRuslan Bukin 		return errcode;
13374fe6c29SRuslan Bukin 
13474fe6c29SRuslan Bukin 	pt_image_init(&decoder->default_image, NULL);
13574fe6c29SRuslan Bukin 	decoder->image = &decoder->default_image;
13674fe6c29SRuslan Bukin 
13774fe6c29SRuslan Bukin 	errcode = pt_msec_cache_init(&decoder->scache);
13874fe6c29SRuslan Bukin 	if (errcode < 0)
13974fe6c29SRuslan Bukin 		return errcode;
14074fe6c29SRuslan Bukin 
14174fe6c29SRuslan Bukin 	pt_blk_reset(decoder);
14274fe6c29SRuslan Bukin 
14374fe6c29SRuslan Bukin 	return 0;
14474fe6c29SRuslan Bukin }
14574fe6c29SRuslan Bukin 
14674fe6c29SRuslan Bukin void pt_blk_decoder_fini(struct pt_block_decoder *decoder)
14774fe6c29SRuslan Bukin {
14874fe6c29SRuslan Bukin 	if (!decoder)
14974fe6c29SRuslan Bukin 		return;
15074fe6c29SRuslan Bukin 
15174fe6c29SRuslan Bukin 	pt_msec_cache_fini(&decoder->scache);
15274fe6c29SRuslan Bukin 	pt_image_fini(&decoder->default_image);
15374fe6c29SRuslan Bukin 	pt_qry_decoder_fini(&decoder->query);
15474fe6c29SRuslan Bukin }
15574fe6c29SRuslan Bukin 
15674fe6c29SRuslan Bukin struct pt_block_decoder *
15774fe6c29SRuslan Bukin pt_blk_alloc_decoder(const struct pt_config *config)
15874fe6c29SRuslan Bukin {
15974fe6c29SRuslan Bukin 	struct pt_block_decoder *decoder;
16074fe6c29SRuslan Bukin 	int errcode;
16174fe6c29SRuslan Bukin 
16274fe6c29SRuslan Bukin 	decoder = malloc(sizeof(*decoder));
16374fe6c29SRuslan Bukin 	if (!decoder)
16474fe6c29SRuslan Bukin 		return NULL;
16574fe6c29SRuslan Bukin 
16674fe6c29SRuslan Bukin 	errcode = pt_blk_decoder_init(decoder, config);
16774fe6c29SRuslan Bukin 	if (errcode < 0) {
16874fe6c29SRuslan Bukin 		free(decoder);
16974fe6c29SRuslan Bukin 		return NULL;
17074fe6c29SRuslan Bukin 	}
17174fe6c29SRuslan Bukin 
17274fe6c29SRuslan Bukin 	return decoder;
17374fe6c29SRuslan Bukin }
17474fe6c29SRuslan Bukin 
17574fe6c29SRuslan Bukin void pt_blk_free_decoder(struct pt_block_decoder *decoder)
17674fe6c29SRuslan Bukin {
17774fe6c29SRuslan Bukin 	if (!decoder)
17874fe6c29SRuslan Bukin 		return;
17974fe6c29SRuslan Bukin 
18074fe6c29SRuslan Bukin 	pt_blk_decoder_fini(decoder);
18174fe6c29SRuslan Bukin 	free(decoder);
18274fe6c29SRuslan Bukin }
18374fe6c29SRuslan Bukin 
18474fe6c29SRuslan Bukin /* Maybe synthesize a tick event.
18574fe6c29SRuslan Bukin  *
18674fe6c29SRuslan Bukin  * If we're not already processing events, check the current time against the
18774fe6c29SRuslan Bukin  * last event's time.  If it changed, synthesize a tick event with the new time.
18874fe6c29SRuslan Bukin  *
18974fe6c29SRuslan Bukin  * Returns zero if no tick event has been created.
19074fe6c29SRuslan Bukin  * Returns a positive integer if a tick event has been created.
19174fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
19274fe6c29SRuslan Bukin  */
19374fe6c29SRuslan Bukin static int pt_blk_tick(struct pt_block_decoder *decoder, uint64_t ip)
19474fe6c29SRuslan Bukin {
19574fe6c29SRuslan Bukin 	struct pt_event *ev;
19674fe6c29SRuslan Bukin 	uint64_t tsc;
19774fe6c29SRuslan Bukin 	uint32_t lost_mtc, lost_cyc;
19874fe6c29SRuslan Bukin 	int errcode;
19974fe6c29SRuslan Bukin 
20074fe6c29SRuslan Bukin 	if (!decoder)
20174fe6c29SRuslan Bukin 		return -pte_internal;
20274fe6c29SRuslan Bukin 
20374fe6c29SRuslan Bukin 	/* We're not generating tick events if tracing is disabled. */
20474fe6c29SRuslan Bukin 	if (!decoder->enabled)
20574fe6c29SRuslan Bukin 		return -pte_internal;
20674fe6c29SRuslan Bukin 
20774fe6c29SRuslan Bukin 	/* Events already provide a timestamp so there is no need to synthesize
20874fe6c29SRuslan Bukin 	 * an artificial tick event.  There's no room, either, since this would
20974fe6c29SRuslan Bukin 	 * overwrite the in-progress event.
21074fe6c29SRuslan Bukin 	 *
21174fe6c29SRuslan Bukin 	 * In rare cases where we need to proceed to an event location using
21274fe6c29SRuslan Bukin 	 * trace this may cause us to miss a timing update if the event is not
21374fe6c29SRuslan Bukin 	 * forwarded to the user.
21474fe6c29SRuslan Bukin 	 *
21574fe6c29SRuslan Bukin 	 * The only case I can come up with at the moment is a MODE.EXEC binding
21674fe6c29SRuslan Bukin 	 * to the TIP IP of a far branch.
21774fe6c29SRuslan Bukin 	 */
21874fe6c29SRuslan Bukin 	if (decoder->process_event)
21974fe6c29SRuslan Bukin 		return 0;
22074fe6c29SRuslan Bukin 
22174fe6c29SRuslan Bukin 	errcode = pt_qry_time(&decoder->query, &tsc, &lost_mtc, &lost_cyc);
22274fe6c29SRuslan Bukin 	if (errcode < 0) {
22374fe6c29SRuslan Bukin 		/* If we don't have wall-clock time, we use relative time. */
22474fe6c29SRuslan Bukin 		if (errcode != -pte_no_time)
22574fe6c29SRuslan Bukin 			return errcode;
22674fe6c29SRuslan Bukin 	}
22774fe6c29SRuslan Bukin 
22874fe6c29SRuslan Bukin 	ev = &decoder->event;
22974fe6c29SRuslan Bukin 
23074fe6c29SRuslan Bukin 	/* We're done if time has not changed since the last event. */
23174fe6c29SRuslan Bukin 	if (tsc == ev->tsc)
23274fe6c29SRuslan Bukin 		return 0;
23374fe6c29SRuslan Bukin 
23474fe6c29SRuslan Bukin 	/* Time has changed so we create a new tick event. */
23574fe6c29SRuslan Bukin 	memset(ev, 0, sizeof(*ev));
23674fe6c29SRuslan Bukin 	ev->type = ptev_tick;
23774fe6c29SRuslan Bukin 	ev->variant.tick.ip = ip;
23874fe6c29SRuslan Bukin 
23974fe6c29SRuslan Bukin 	/* Indicate if we have wall-clock time or only relative time. */
24074fe6c29SRuslan Bukin 	if (errcode != -pte_no_time)
24174fe6c29SRuslan Bukin 		ev->has_tsc = 1;
24274fe6c29SRuslan Bukin 	ev->tsc = tsc;
24374fe6c29SRuslan Bukin 	ev->lost_mtc = lost_mtc;
24474fe6c29SRuslan Bukin 	ev->lost_cyc = lost_cyc;
24574fe6c29SRuslan Bukin 
24674fe6c29SRuslan Bukin 	/* We now have an event to process. */
24774fe6c29SRuslan Bukin 	decoder->process_event = 1;
24874fe6c29SRuslan Bukin 
24974fe6c29SRuslan Bukin 	return 1;
25074fe6c29SRuslan Bukin }
25174fe6c29SRuslan Bukin 
25274fe6c29SRuslan Bukin /* Query an indirect branch.
25374fe6c29SRuslan Bukin  *
25474fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
25574fe6c29SRuslan Bukin  */
25674fe6c29SRuslan Bukin static int pt_blk_indirect_branch(struct pt_block_decoder *decoder,
25774fe6c29SRuslan Bukin 				  uint64_t *ip)
25874fe6c29SRuslan Bukin {
25974fe6c29SRuslan Bukin 	uint64_t evip;
26074fe6c29SRuslan Bukin 	int status, errcode;
26174fe6c29SRuslan Bukin 
26274fe6c29SRuslan Bukin 	if (!decoder)
26374fe6c29SRuslan Bukin 		return -pte_internal;
26474fe6c29SRuslan Bukin 
26574fe6c29SRuslan Bukin 	evip = decoder->ip;
26674fe6c29SRuslan Bukin 
26774fe6c29SRuslan Bukin 	status = pt_qry_indirect_branch(&decoder->query, ip);
26874fe6c29SRuslan Bukin 	if (status < 0)
26974fe6c29SRuslan Bukin 		return status;
27074fe6c29SRuslan Bukin 
27174fe6c29SRuslan Bukin 	if (decoder->flags.variant.block.enable_tick_events) {
27274fe6c29SRuslan Bukin 		errcode = pt_blk_tick(decoder, evip);
27374fe6c29SRuslan Bukin 		if (errcode < 0)
27474fe6c29SRuslan Bukin 			return errcode;
27574fe6c29SRuslan Bukin 	}
27674fe6c29SRuslan Bukin 
27774fe6c29SRuslan Bukin 	return status;
27874fe6c29SRuslan Bukin }
27974fe6c29SRuslan Bukin 
28074fe6c29SRuslan Bukin /* Query a conditional branch.
28174fe6c29SRuslan Bukin  *
28274fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
28374fe6c29SRuslan Bukin  */
28474fe6c29SRuslan Bukin static int pt_blk_cond_branch(struct pt_block_decoder *decoder, int *taken)
28574fe6c29SRuslan Bukin {
28674fe6c29SRuslan Bukin 	int status, errcode;
28774fe6c29SRuslan Bukin 
28874fe6c29SRuslan Bukin 	if (!decoder)
28974fe6c29SRuslan Bukin 		return -pte_internal;
29074fe6c29SRuslan Bukin 
29174fe6c29SRuslan Bukin 	status = pt_qry_cond_branch(&decoder->query, taken);
29274fe6c29SRuslan Bukin 	if (status < 0)
29374fe6c29SRuslan Bukin 		return status;
29474fe6c29SRuslan Bukin 
29574fe6c29SRuslan Bukin 	if (decoder->flags.variant.block.enable_tick_events) {
29674fe6c29SRuslan Bukin 		errcode = pt_blk_tick(decoder, decoder->ip);
29774fe6c29SRuslan Bukin 		if (errcode < 0)
29874fe6c29SRuslan Bukin 			return errcode;
29974fe6c29SRuslan Bukin 	}
30074fe6c29SRuslan Bukin 
30174fe6c29SRuslan Bukin 	return status;
30274fe6c29SRuslan Bukin }
30374fe6c29SRuslan Bukin 
30474fe6c29SRuslan Bukin static int pt_blk_start(struct pt_block_decoder *decoder, int status)
30574fe6c29SRuslan Bukin {
30674fe6c29SRuslan Bukin 	if (!decoder)
30774fe6c29SRuslan Bukin 		return -pte_internal;
30874fe6c29SRuslan Bukin 
30974fe6c29SRuslan Bukin 	if (status < 0)
31074fe6c29SRuslan Bukin 		return status;
31174fe6c29SRuslan Bukin 
31274fe6c29SRuslan Bukin 	decoder->status = status;
31374fe6c29SRuslan Bukin 	if (!(status & pts_ip_suppressed))
31474fe6c29SRuslan Bukin 		decoder->enabled = 1;
31574fe6c29SRuslan Bukin 
31674fe6c29SRuslan Bukin 	/* We will always have an event.
31774fe6c29SRuslan Bukin 	 *
31874fe6c29SRuslan Bukin 	 * If we synchronized onto an empty PSB+, tracing is disabled and we'll
31974fe6c29SRuslan Bukin 	 * process events until the enabled event.
32074fe6c29SRuslan Bukin 	 *
32174fe6c29SRuslan Bukin 	 * If tracing is enabled, PSB+ must at least provide the execution mode,
32274fe6c29SRuslan Bukin 	 * which we're going to forward to the user.
32374fe6c29SRuslan Bukin 	 */
32474fe6c29SRuslan Bukin 	return pt_blk_proceed_trailing_event(decoder, NULL);
32574fe6c29SRuslan Bukin }
32674fe6c29SRuslan Bukin 
32774fe6c29SRuslan Bukin static int pt_blk_sync_reset(struct pt_block_decoder *decoder)
32874fe6c29SRuslan Bukin {
32974fe6c29SRuslan Bukin 	if (!decoder)
33074fe6c29SRuslan Bukin 		return -pte_internal;
33174fe6c29SRuslan Bukin 
33274fe6c29SRuslan Bukin 	pt_blk_reset(decoder);
33374fe6c29SRuslan Bukin 
33474fe6c29SRuslan Bukin 	return 0;
33574fe6c29SRuslan Bukin }
33674fe6c29SRuslan Bukin 
33774fe6c29SRuslan Bukin int pt_blk_sync_forward(struct pt_block_decoder *decoder)
33874fe6c29SRuslan Bukin {
33974fe6c29SRuslan Bukin 	int errcode, status;
34074fe6c29SRuslan Bukin 
34174fe6c29SRuslan Bukin 	if (!decoder)
34274fe6c29SRuslan Bukin 		return -pte_invalid;
34374fe6c29SRuslan Bukin 
34474fe6c29SRuslan Bukin 	errcode = pt_blk_sync_reset(decoder);
34574fe6c29SRuslan Bukin 	if (errcode < 0)
34674fe6c29SRuslan Bukin 		return errcode;
34774fe6c29SRuslan Bukin 
34874fe6c29SRuslan Bukin 	status = pt_qry_sync_forward(&decoder->query, &decoder->ip);
34974fe6c29SRuslan Bukin 
35074fe6c29SRuslan Bukin 	return pt_blk_start(decoder, status);
35174fe6c29SRuslan Bukin }
35274fe6c29SRuslan Bukin 
35374fe6c29SRuslan Bukin int pt_blk_sync_backward(struct pt_block_decoder *decoder)
35474fe6c29SRuslan Bukin {
35574fe6c29SRuslan Bukin 	int errcode, status;
35674fe6c29SRuslan Bukin 
35774fe6c29SRuslan Bukin 	if (!decoder)
35874fe6c29SRuslan Bukin 		return -pte_invalid;
35974fe6c29SRuslan Bukin 
36074fe6c29SRuslan Bukin 	errcode = pt_blk_sync_reset(decoder);
36174fe6c29SRuslan Bukin 	if (errcode < 0)
36274fe6c29SRuslan Bukin 		return errcode;
36374fe6c29SRuslan Bukin 
36474fe6c29SRuslan Bukin 	status = pt_qry_sync_backward(&decoder->query, &decoder->ip);
36574fe6c29SRuslan Bukin 
36674fe6c29SRuslan Bukin 	return pt_blk_start(decoder, status);
36774fe6c29SRuslan Bukin }
36874fe6c29SRuslan Bukin 
36974fe6c29SRuslan Bukin int pt_blk_sync_set(struct pt_block_decoder *decoder, uint64_t offset)
37074fe6c29SRuslan Bukin {
37174fe6c29SRuslan Bukin 	int errcode, status;
37274fe6c29SRuslan Bukin 
37374fe6c29SRuslan Bukin 	if (!decoder)
37474fe6c29SRuslan Bukin 		return -pte_invalid;
37574fe6c29SRuslan Bukin 
37674fe6c29SRuslan Bukin 	errcode = pt_blk_sync_reset(decoder);
37774fe6c29SRuslan Bukin 	if (errcode < 0)
37874fe6c29SRuslan Bukin 		return errcode;
37974fe6c29SRuslan Bukin 
38074fe6c29SRuslan Bukin 	status = pt_qry_sync_set(&decoder->query, &decoder->ip, offset);
38174fe6c29SRuslan Bukin 
38274fe6c29SRuslan Bukin 	return pt_blk_start(decoder, status);
38374fe6c29SRuslan Bukin }
38474fe6c29SRuslan Bukin 
38574fe6c29SRuslan Bukin int pt_blk_get_offset(const struct pt_block_decoder *decoder, uint64_t *offset)
38674fe6c29SRuslan Bukin {
38774fe6c29SRuslan Bukin 	if (!decoder)
38874fe6c29SRuslan Bukin 		return -pte_invalid;
38974fe6c29SRuslan Bukin 
39074fe6c29SRuslan Bukin 	return pt_qry_get_offset(&decoder->query, offset);
39174fe6c29SRuslan Bukin }
39274fe6c29SRuslan Bukin 
39374fe6c29SRuslan Bukin int pt_blk_get_sync_offset(const struct pt_block_decoder *decoder,
39474fe6c29SRuslan Bukin 			   uint64_t *offset)
39574fe6c29SRuslan Bukin {
39674fe6c29SRuslan Bukin 	if (!decoder)
39774fe6c29SRuslan Bukin 		return -pte_invalid;
39874fe6c29SRuslan Bukin 
39974fe6c29SRuslan Bukin 	return pt_qry_get_sync_offset(&decoder->query, offset);
40074fe6c29SRuslan Bukin }
40174fe6c29SRuslan Bukin 
40274fe6c29SRuslan Bukin struct pt_image *pt_blk_get_image(struct pt_block_decoder *decoder)
40374fe6c29SRuslan Bukin {
40474fe6c29SRuslan Bukin 	if (!decoder)
40574fe6c29SRuslan Bukin 		return NULL;
40674fe6c29SRuslan Bukin 
40774fe6c29SRuslan Bukin 	return decoder->image;
40874fe6c29SRuslan Bukin }
40974fe6c29SRuslan Bukin 
41074fe6c29SRuslan Bukin int pt_blk_set_image(struct pt_block_decoder *decoder, struct pt_image *image)
41174fe6c29SRuslan Bukin {
41274fe6c29SRuslan Bukin 	if (!decoder)
41374fe6c29SRuslan Bukin 		return -pte_invalid;
41474fe6c29SRuslan Bukin 
41574fe6c29SRuslan Bukin 	if (!image)
41674fe6c29SRuslan Bukin 		image = &decoder->default_image;
41774fe6c29SRuslan Bukin 
41874fe6c29SRuslan Bukin 	decoder->image = image;
41974fe6c29SRuslan Bukin 	return 0;
42074fe6c29SRuslan Bukin }
42174fe6c29SRuslan Bukin 
42274fe6c29SRuslan Bukin const struct pt_config *
42374fe6c29SRuslan Bukin pt_blk_get_config(const struct pt_block_decoder *decoder)
42474fe6c29SRuslan Bukin {
42574fe6c29SRuslan Bukin 	if (!decoder)
42674fe6c29SRuslan Bukin 		return NULL;
42774fe6c29SRuslan Bukin 
42874fe6c29SRuslan Bukin 	return pt_qry_get_config(&decoder->query);
42974fe6c29SRuslan Bukin }
43074fe6c29SRuslan Bukin 
43174fe6c29SRuslan Bukin int pt_blk_time(struct pt_block_decoder *decoder, uint64_t *time,
43274fe6c29SRuslan Bukin 		uint32_t *lost_mtc, uint32_t *lost_cyc)
43374fe6c29SRuslan Bukin {
43474fe6c29SRuslan Bukin 	if (!decoder || !time)
43574fe6c29SRuslan Bukin 		return -pte_invalid;
43674fe6c29SRuslan Bukin 
43774fe6c29SRuslan Bukin 	return pt_qry_time(&decoder->query, time, lost_mtc, lost_cyc);
43874fe6c29SRuslan Bukin }
43974fe6c29SRuslan Bukin 
44074fe6c29SRuslan Bukin int pt_blk_core_bus_ratio(struct pt_block_decoder *decoder, uint32_t *cbr)
44174fe6c29SRuslan Bukin {
44274fe6c29SRuslan Bukin 	if (!decoder || !cbr)
44374fe6c29SRuslan Bukin 		return -pte_invalid;
44474fe6c29SRuslan Bukin 
44574fe6c29SRuslan Bukin 	return pt_qry_core_bus_ratio(&decoder->query, cbr);
44674fe6c29SRuslan Bukin }
44774fe6c29SRuslan Bukin 
44874fe6c29SRuslan Bukin int pt_blk_asid(const struct pt_block_decoder *decoder, struct pt_asid *asid,
44974fe6c29SRuslan Bukin 		size_t size)
45074fe6c29SRuslan Bukin {
45174fe6c29SRuslan Bukin 	if (!decoder || !asid)
45274fe6c29SRuslan Bukin 		return -pte_invalid;
45374fe6c29SRuslan Bukin 
45474fe6c29SRuslan Bukin 	return pt_asid_to_user(asid, &decoder->asid, size);
45574fe6c29SRuslan Bukin }
45674fe6c29SRuslan Bukin 
45774fe6c29SRuslan Bukin /* Fetch the next pending event.
45874fe6c29SRuslan Bukin  *
45974fe6c29SRuslan Bukin  * Checks for pending events.  If an event is pending, fetches it (if not
46074fe6c29SRuslan Bukin  * already in process).
46174fe6c29SRuslan Bukin  *
46274fe6c29SRuslan Bukin  * Returns zero if no event is pending.
46374fe6c29SRuslan Bukin  * Returns a positive integer if an event is pending or in process.
46474fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
46574fe6c29SRuslan Bukin  */
46674fe6c29SRuslan Bukin static inline int pt_blk_fetch_event(struct pt_block_decoder *decoder)
46774fe6c29SRuslan Bukin {
46874fe6c29SRuslan Bukin 	int status;
46974fe6c29SRuslan Bukin 
47074fe6c29SRuslan Bukin 	if (!decoder)
47174fe6c29SRuslan Bukin 		return -pte_internal;
47274fe6c29SRuslan Bukin 
47374fe6c29SRuslan Bukin 	if (decoder->process_event)
47474fe6c29SRuslan Bukin 		return 1;
47574fe6c29SRuslan Bukin 
47674fe6c29SRuslan Bukin 	if (!(decoder->status & pts_event_pending))
47774fe6c29SRuslan Bukin 		return 0;
47874fe6c29SRuslan Bukin 
47974fe6c29SRuslan Bukin 	status = pt_qry_event(&decoder->query, &decoder->event,
48074fe6c29SRuslan Bukin 			      sizeof(decoder->event));
48174fe6c29SRuslan Bukin 	if (status < 0)
48274fe6c29SRuslan Bukin 		return status;
48374fe6c29SRuslan Bukin 
48474fe6c29SRuslan Bukin 	decoder->process_event = 1;
48574fe6c29SRuslan Bukin 	decoder->status = status;
48674fe6c29SRuslan Bukin 
48774fe6c29SRuslan Bukin 	return 1;
48874fe6c29SRuslan Bukin }
48974fe6c29SRuslan Bukin 
49074fe6c29SRuslan Bukin static inline int pt_blk_block_is_empty(const struct pt_block *block)
49174fe6c29SRuslan Bukin {
49274fe6c29SRuslan Bukin 	if (!block)
49374fe6c29SRuslan Bukin 		return 1;
49474fe6c29SRuslan Bukin 
49574fe6c29SRuslan Bukin 	return !block->ninsn;
49674fe6c29SRuslan Bukin }
49774fe6c29SRuslan Bukin 
49874fe6c29SRuslan Bukin static inline int block_to_user(struct pt_block *ublock, size_t size,
49974fe6c29SRuslan Bukin 				const struct pt_block *block)
50074fe6c29SRuslan Bukin {
50174fe6c29SRuslan Bukin 	if (!ublock || !block)
50274fe6c29SRuslan Bukin 		return -pte_internal;
50374fe6c29SRuslan Bukin 
50474fe6c29SRuslan Bukin 	if (ublock == block)
50574fe6c29SRuslan Bukin 		return 0;
50674fe6c29SRuslan Bukin 
50774fe6c29SRuslan Bukin 	/* Zero out any unknown bytes. */
50874fe6c29SRuslan Bukin 	if (sizeof(*block) < size) {
50974fe6c29SRuslan Bukin 		memset(ublock + sizeof(*block), 0, size - sizeof(*block));
51074fe6c29SRuslan Bukin 
51174fe6c29SRuslan Bukin 		size = sizeof(*block);
51274fe6c29SRuslan Bukin 	}
51374fe6c29SRuslan Bukin 
51474fe6c29SRuslan Bukin 	memcpy(ublock, block, size);
51574fe6c29SRuslan Bukin 
51674fe6c29SRuslan Bukin 	return 0;
51774fe6c29SRuslan Bukin }
51874fe6c29SRuslan Bukin 
51974fe6c29SRuslan Bukin static int pt_insn_false(const struct pt_insn *insn,
52074fe6c29SRuslan Bukin 			 const struct pt_insn_ext *iext)
52174fe6c29SRuslan Bukin {
52274fe6c29SRuslan Bukin 	(void) insn;
52374fe6c29SRuslan Bukin 	(void) iext;
52474fe6c29SRuslan Bukin 
52574fe6c29SRuslan Bukin 	return 0;
52674fe6c29SRuslan Bukin }
52774fe6c29SRuslan Bukin 
52874fe6c29SRuslan Bukin /* Determine the next IP using trace.
52974fe6c29SRuslan Bukin  *
53074fe6c29SRuslan Bukin  * Tries to determine the IP of the next instruction using trace and provides it
53174fe6c29SRuslan Bukin  * in @pip.
53274fe6c29SRuslan Bukin  *
53374fe6c29SRuslan Bukin  * Not requiring trace to determine the IP is treated as an internal error.
53474fe6c29SRuslan Bukin  *
53574fe6c29SRuslan Bukin  * Does not update the return compression stack for indirect calls.  This is
53674fe6c29SRuslan Bukin  * expected to have been done, already, when trying to determine the next IP
53774fe6c29SRuslan Bukin  * without using trace.
53874fe6c29SRuslan Bukin  *
53974fe6c29SRuslan Bukin  * Does not update @decoder->status.  The caller is expected to do that.
54074fe6c29SRuslan Bukin  *
54174fe6c29SRuslan Bukin  * Returns a non-negative pt_status_flag bit-vector on success, a negative error
54274fe6c29SRuslan Bukin  * code otherwise.
54374fe6c29SRuslan Bukin  * Returns -pte_internal if @pip, @decoder, @insn, or @iext are NULL.
54474fe6c29SRuslan Bukin  * Returns -pte_internal if no trace is required.
54574fe6c29SRuslan Bukin  */
54674fe6c29SRuslan Bukin static int pt_blk_next_ip(uint64_t *pip, struct pt_block_decoder *decoder,
54774fe6c29SRuslan Bukin 			  const struct pt_insn *insn,
54874fe6c29SRuslan Bukin 			  const struct pt_insn_ext *iext)
54974fe6c29SRuslan Bukin {
55074fe6c29SRuslan Bukin 	int status, errcode;
55174fe6c29SRuslan Bukin 
55274fe6c29SRuslan Bukin 	if (!pip || !decoder || !insn || !iext)
55374fe6c29SRuslan Bukin 		return -pte_internal;
55474fe6c29SRuslan Bukin 
55574fe6c29SRuslan Bukin 	/* We handle non-taken conditional branches, and compressed returns
55674fe6c29SRuslan Bukin 	 * directly in the switch.
55774fe6c29SRuslan Bukin 	 *
55874fe6c29SRuslan Bukin 	 * All kinds of branches are handled below the switch.
55974fe6c29SRuslan Bukin 	 */
56074fe6c29SRuslan Bukin 	switch (insn->iclass) {
56174fe6c29SRuslan Bukin 	case ptic_cond_jump: {
56274fe6c29SRuslan Bukin 		uint64_t ip;
56374fe6c29SRuslan Bukin 		int taken;
56474fe6c29SRuslan Bukin 
56574fe6c29SRuslan Bukin 		status = pt_blk_cond_branch(decoder, &taken);
56674fe6c29SRuslan Bukin 		if (status < 0)
56774fe6c29SRuslan Bukin 			return status;
56874fe6c29SRuslan Bukin 
56974fe6c29SRuslan Bukin 		ip = insn->ip + insn->size;
57074fe6c29SRuslan Bukin 		if (taken)
57174fe6c29SRuslan Bukin 			ip += iext->variant.branch.displacement;
57274fe6c29SRuslan Bukin 
57374fe6c29SRuslan Bukin 		*pip = ip;
57474fe6c29SRuslan Bukin 		return status;
57574fe6c29SRuslan Bukin 	}
57674fe6c29SRuslan Bukin 
57774fe6c29SRuslan Bukin 	case ptic_return: {
57874fe6c29SRuslan Bukin 		int taken;
57974fe6c29SRuslan Bukin 
58074fe6c29SRuslan Bukin 		/* Check for a compressed return. */
58174fe6c29SRuslan Bukin 		status = pt_blk_cond_branch(decoder, &taken);
58274fe6c29SRuslan Bukin 		if (status < 0) {
58374fe6c29SRuslan Bukin 			if (status != -pte_bad_query)
58474fe6c29SRuslan Bukin 				return status;
58574fe6c29SRuslan Bukin 
58674fe6c29SRuslan Bukin 			break;
58774fe6c29SRuslan Bukin 		}
58874fe6c29SRuslan Bukin 
58974fe6c29SRuslan Bukin 		/* A compressed return is indicated by a taken conditional
59074fe6c29SRuslan Bukin 		 * branch.
59174fe6c29SRuslan Bukin 		 */
59274fe6c29SRuslan Bukin 		if (!taken)
59374fe6c29SRuslan Bukin 			return -pte_bad_retcomp;
59474fe6c29SRuslan Bukin 
59574fe6c29SRuslan Bukin 		errcode = pt_retstack_pop(&decoder->retstack, pip);
59674fe6c29SRuslan Bukin 		if (errcode < 0)
59774fe6c29SRuslan Bukin 			return errcode;
59874fe6c29SRuslan Bukin 
59974fe6c29SRuslan Bukin 		return status;
60074fe6c29SRuslan Bukin 	}
60174fe6c29SRuslan Bukin 
60274fe6c29SRuslan Bukin 	case ptic_jump:
60374fe6c29SRuslan Bukin 	case ptic_call:
60474fe6c29SRuslan Bukin 		/* A direct jump or call wouldn't require trace. */
60574fe6c29SRuslan Bukin 		if (iext->variant.branch.is_direct)
60674fe6c29SRuslan Bukin 			return -pte_internal;
60774fe6c29SRuslan Bukin 
60874fe6c29SRuslan Bukin 		break;
60974fe6c29SRuslan Bukin 
61074fe6c29SRuslan Bukin 	case ptic_far_call:
61174fe6c29SRuslan Bukin 	case ptic_far_return:
61274fe6c29SRuslan Bukin 	case ptic_far_jump:
61374fe6c29SRuslan Bukin 		break;
61474fe6c29SRuslan Bukin 
61574fe6c29SRuslan Bukin 	case ptic_ptwrite:
61674fe6c29SRuslan Bukin 	case ptic_other:
61774fe6c29SRuslan Bukin 		return -pte_internal;
61874fe6c29SRuslan Bukin 
61974fe6c29SRuslan Bukin 	case ptic_error:
62074fe6c29SRuslan Bukin 		return -pte_bad_insn;
62174fe6c29SRuslan Bukin 	}
62274fe6c29SRuslan Bukin 
62374fe6c29SRuslan Bukin 	/* Process an indirect branch.
62474fe6c29SRuslan Bukin 	 *
62574fe6c29SRuslan Bukin 	 * This covers indirect jumps and calls, non-compressed returns, and all
62674fe6c29SRuslan Bukin 	 * flavors of far transfers.
62774fe6c29SRuslan Bukin 	 */
62874fe6c29SRuslan Bukin 	return pt_blk_indirect_branch(decoder, pip);
62974fe6c29SRuslan Bukin }
63074fe6c29SRuslan Bukin 
63174fe6c29SRuslan Bukin /* Proceed to the next IP using trace.
63274fe6c29SRuslan Bukin  *
63374fe6c29SRuslan Bukin  * We failed to proceed without trace.  This ends the current block.  Now use
63474fe6c29SRuslan Bukin  * trace to do one final step to determine the start IP of the next block.
63574fe6c29SRuslan Bukin  *
63674fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
63774fe6c29SRuslan Bukin  */
63874fe6c29SRuslan Bukin static int pt_blk_proceed_with_trace(struct pt_block_decoder *decoder,
63974fe6c29SRuslan Bukin 				     const struct pt_insn *insn,
64074fe6c29SRuslan Bukin 				     const struct pt_insn_ext *iext)
64174fe6c29SRuslan Bukin {
64274fe6c29SRuslan Bukin 	int status;
64374fe6c29SRuslan Bukin 
64474fe6c29SRuslan Bukin 	if (!decoder)
64574fe6c29SRuslan Bukin 		return -pte_internal;
64674fe6c29SRuslan Bukin 
64774fe6c29SRuslan Bukin 	status = pt_blk_next_ip(&decoder->ip, decoder, insn, iext);
64874fe6c29SRuslan Bukin 	if (status < 0)
64974fe6c29SRuslan Bukin 		return status;
65074fe6c29SRuslan Bukin 
65174fe6c29SRuslan Bukin 	/* Preserve the query decoder's response which indicates upcoming
65274fe6c29SRuslan Bukin 	 * events.
65374fe6c29SRuslan Bukin 	 */
65474fe6c29SRuslan Bukin 	decoder->status = status;
65574fe6c29SRuslan Bukin 
65674fe6c29SRuslan Bukin 	/* We do need an IP in order to proceed. */
65774fe6c29SRuslan Bukin 	if (status & pts_ip_suppressed)
65874fe6c29SRuslan Bukin 		return -pte_noip;
65974fe6c29SRuslan Bukin 
66074fe6c29SRuslan Bukin 	return 0;
66174fe6c29SRuslan Bukin }
66274fe6c29SRuslan Bukin 
66374fe6c29SRuslan Bukin /* Decode one instruction in a known section.
66474fe6c29SRuslan Bukin  *
66574fe6c29SRuslan Bukin  * Decode the instruction at @insn->ip in @msec assuming execution mode
66674fe6c29SRuslan Bukin  * @insn->mode.
66774fe6c29SRuslan Bukin  *
66874fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
66974fe6c29SRuslan Bukin  */
67074fe6c29SRuslan Bukin static int pt_blk_decode_in_section(struct pt_insn *insn,
67174fe6c29SRuslan Bukin 				    struct pt_insn_ext *iext,
67274fe6c29SRuslan Bukin 				    const struct pt_mapped_section *msec)
67374fe6c29SRuslan Bukin {
67474fe6c29SRuslan Bukin 	int status;
67574fe6c29SRuslan Bukin 
67674fe6c29SRuslan Bukin 	if (!insn || !iext)
67774fe6c29SRuslan Bukin 		return -pte_internal;
67874fe6c29SRuslan Bukin 
67974fe6c29SRuslan Bukin 	/* We know that @ip is contained in @section.
68074fe6c29SRuslan Bukin 	 *
68174fe6c29SRuslan Bukin 	 * Note that we need to translate @ip into a section offset.
68274fe6c29SRuslan Bukin 	 */
68374fe6c29SRuslan Bukin 	status = pt_msec_read(msec, insn->raw, sizeof(insn->raw), insn->ip);
68474fe6c29SRuslan Bukin 	if (status < 0)
68574fe6c29SRuslan Bukin 		return status;
68674fe6c29SRuslan Bukin 
68774fe6c29SRuslan Bukin 	/* We initialize @insn->size to the maximal possible size.  It will be
68874fe6c29SRuslan Bukin 	 * set to the actual size during instruction decode.
68974fe6c29SRuslan Bukin 	 */
69074fe6c29SRuslan Bukin 	insn->size = (uint8_t) status;
69174fe6c29SRuslan Bukin 
69274fe6c29SRuslan Bukin 	return pt_ild_decode(insn, iext);
69374fe6c29SRuslan Bukin }
69474fe6c29SRuslan Bukin 
69574fe6c29SRuslan Bukin /* Update the return-address stack if @insn is a near call.
69674fe6c29SRuslan Bukin  *
69774fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
69874fe6c29SRuslan Bukin  */
69974fe6c29SRuslan Bukin static inline int pt_blk_log_call(struct pt_block_decoder *decoder,
70074fe6c29SRuslan Bukin 				  const struct pt_insn *insn,
70174fe6c29SRuslan Bukin 				  const struct pt_insn_ext *iext)
70274fe6c29SRuslan Bukin {
70374fe6c29SRuslan Bukin 	if (!decoder || !insn || !iext)
70474fe6c29SRuslan Bukin 		return -pte_internal;
70574fe6c29SRuslan Bukin 
70674fe6c29SRuslan Bukin 	if (insn->iclass != ptic_call)
70774fe6c29SRuslan Bukin 		return 0;
70874fe6c29SRuslan Bukin 
70974fe6c29SRuslan Bukin 	/* Ignore direct calls to the next instruction that are used for
71074fe6c29SRuslan Bukin 	 * position independent code.
71174fe6c29SRuslan Bukin 	 */
71274fe6c29SRuslan Bukin 	if (iext->variant.branch.is_direct &&
71374fe6c29SRuslan Bukin 	    !iext->variant.branch.displacement)
71474fe6c29SRuslan Bukin 		return 0;
71574fe6c29SRuslan Bukin 
71674fe6c29SRuslan Bukin 	return pt_retstack_push(&decoder->retstack, insn->ip + insn->size);
71774fe6c29SRuslan Bukin }
71874fe6c29SRuslan Bukin 
71974fe6c29SRuslan Bukin /* Proceed by one instruction.
72074fe6c29SRuslan Bukin  *
72174fe6c29SRuslan Bukin  * Tries to decode the instruction at @decoder->ip and, on success, adds it to
72274fe6c29SRuslan Bukin  * @block and provides it in @pinsn and @piext.
72374fe6c29SRuslan Bukin  *
72474fe6c29SRuslan Bukin  * The instruction will not be added if:
72574fe6c29SRuslan Bukin  *
72674fe6c29SRuslan Bukin  *   - the memory could not be read:  return error
72774fe6c29SRuslan Bukin  *   - it could not be decoded:       return error
72874fe6c29SRuslan Bukin  *   - @block is already full:        return zero
72974fe6c29SRuslan Bukin  *   - @block would switch sections:  return zero
73074fe6c29SRuslan Bukin  *
73174fe6c29SRuslan Bukin  * Returns a positive integer if the instruction was added.
73274fe6c29SRuslan Bukin  * Returns zero if the instruction didn't fit into @block.
73374fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
73474fe6c29SRuslan Bukin  */
73574fe6c29SRuslan Bukin static int pt_blk_proceed_one_insn(struct pt_block_decoder *decoder,
73674fe6c29SRuslan Bukin 				   struct pt_block *block,
73774fe6c29SRuslan Bukin 				   struct pt_insn *pinsn,
73874fe6c29SRuslan Bukin 				   struct pt_insn_ext *piext)
73974fe6c29SRuslan Bukin {
74074fe6c29SRuslan Bukin 	struct pt_insn_ext iext;
74174fe6c29SRuslan Bukin 	struct pt_insn insn;
74274fe6c29SRuslan Bukin 	uint16_t ninsn;
74374fe6c29SRuslan Bukin 	int status;
74474fe6c29SRuslan Bukin 
74574fe6c29SRuslan Bukin 	if (!decoder || !block || !pinsn || !piext)
74674fe6c29SRuslan Bukin 		return -pte_internal;
74774fe6c29SRuslan Bukin 
74874fe6c29SRuslan Bukin 	/* There's nothing to do if there is no room in @block. */
74974fe6c29SRuslan Bukin 	ninsn = block->ninsn + 1;
75074fe6c29SRuslan Bukin 	if (!ninsn)
75174fe6c29SRuslan Bukin 		return 0;
75274fe6c29SRuslan Bukin 
75374fe6c29SRuslan Bukin 	/* The truncated instruction must be last. */
75474fe6c29SRuslan Bukin 	if (block->truncated)
75574fe6c29SRuslan Bukin 		return 0;
75674fe6c29SRuslan Bukin 
75774fe6c29SRuslan Bukin 	memset(&insn, 0, sizeof(insn));
75874fe6c29SRuslan Bukin 	memset(&iext, 0, sizeof(iext));
75974fe6c29SRuslan Bukin 
76074fe6c29SRuslan Bukin 	insn.mode = decoder->mode;
76174fe6c29SRuslan Bukin 	insn.ip = decoder->ip;
76274fe6c29SRuslan Bukin 
76374fe6c29SRuslan Bukin 	status = pt_insn_decode(&insn, &iext, decoder->image, &decoder->asid);
76474fe6c29SRuslan Bukin 	if (status < 0)
76574fe6c29SRuslan Bukin 		return status;
76674fe6c29SRuslan Bukin 
76774fe6c29SRuslan Bukin 	/* We do not switch sections inside a block. */
76874fe6c29SRuslan Bukin 	if (insn.isid != block->isid) {
76974fe6c29SRuslan Bukin 		if (!pt_blk_block_is_empty(block))
77074fe6c29SRuslan Bukin 			return 0;
77174fe6c29SRuslan Bukin 
77274fe6c29SRuslan Bukin 		block->isid = insn.isid;
77374fe6c29SRuslan Bukin 	}
77474fe6c29SRuslan Bukin 
77574fe6c29SRuslan Bukin 	/* If we couldn't read @insn's memory in one chunk from @insn.isid, we
77674fe6c29SRuslan Bukin 	 * provide the memory in @block.
77774fe6c29SRuslan Bukin 	 */
77874fe6c29SRuslan Bukin 	if (insn.truncated) {
77974fe6c29SRuslan Bukin 		memcpy(block->raw, insn.raw, insn.size);
78074fe6c29SRuslan Bukin 		block->size = insn.size;
78174fe6c29SRuslan Bukin 		block->truncated = 1;
78274fe6c29SRuslan Bukin 	}
78374fe6c29SRuslan Bukin 
78474fe6c29SRuslan Bukin 	/* Log calls' return addresses for return compression. */
78574fe6c29SRuslan Bukin 	status = pt_blk_log_call(decoder, &insn, &iext);
78674fe6c29SRuslan Bukin 	if (status < 0)
78774fe6c29SRuslan Bukin 		return status;
78874fe6c29SRuslan Bukin 
78974fe6c29SRuslan Bukin 	/* We have a new instruction. */
79074fe6c29SRuslan Bukin 	block->iclass = insn.iclass;
79174fe6c29SRuslan Bukin 	block->end_ip = insn.ip;
79274fe6c29SRuslan Bukin 	block->ninsn = ninsn;
79374fe6c29SRuslan Bukin 
79474fe6c29SRuslan Bukin 	*pinsn = insn;
79574fe6c29SRuslan Bukin 	*piext = iext;
79674fe6c29SRuslan Bukin 
79774fe6c29SRuslan Bukin 	return 1;
79874fe6c29SRuslan Bukin }
79974fe6c29SRuslan Bukin 
80074fe6c29SRuslan Bukin 
80174fe6c29SRuslan Bukin /* Proceed to a particular type of instruction without using trace.
80274fe6c29SRuslan Bukin  *
80374fe6c29SRuslan Bukin  * Proceed until we reach an instruction for which @predicate returns a positive
80474fe6c29SRuslan Bukin  * integer or until:
80574fe6c29SRuslan Bukin  *
80674fe6c29SRuslan Bukin  *   - @predicate returns an error:  return error
80774fe6c29SRuslan Bukin  *   - @block is full:               return zero
80874fe6c29SRuslan Bukin  *   - @block would switch sections: return zero
80974fe6c29SRuslan Bukin  *   - we would need trace:          return -pte_bad_query
81074fe6c29SRuslan Bukin  *
81174fe6c29SRuslan Bukin  * Provide the last instruction that was reached in @insn and @iext.
81274fe6c29SRuslan Bukin  *
81374fe6c29SRuslan Bukin  * Update @decoder->ip to point to the last IP that was reached.  If we fail due
81474fe6c29SRuslan Bukin  * to lack of trace or if we reach a desired instruction, this is @insn->ip;
81574fe6c29SRuslan Bukin  * otherwise this is the next instruction's IP.
81674fe6c29SRuslan Bukin  *
81774fe6c29SRuslan Bukin  * Returns a positive integer if a suitable instruction was reached.
81874fe6c29SRuslan Bukin  * Returns zero if no such instruction was reached.
81974fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
82074fe6c29SRuslan Bukin  */
82174fe6c29SRuslan Bukin static int pt_blk_proceed_to_insn(struct pt_block_decoder *decoder,
82274fe6c29SRuslan Bukin 				  struct pt_block *block,
82374fe6c29SRuslan Bukin 				  struct pt_insn *insn,
82474fe6c29SRuslan Bukin 				  struct pt_insn_ext *iext,
82574fe6c29SRuslan Bukin 				  int (*predicate)(const struct pt_insn *,
82674fe6c29SRuslan Bukin 						   const struct pt_insn_ext *))
82774fe6c29SRuslan Bukin {
82874fe6c29SRuslan Bukin 	int status;
82974fe6c29SRuslan Bukin 
83074fe6c29SRuslan Bukin 	if (!decoder || !insn || !predicate)
83174fe6c29SRuslan Bukin 		return -pte_internal;
83274fe6c29SRuslan Bukin 
83374fe6c29SRuslan Bukin 	for (;;) {
83474fe6c29SRuslan Bukin 		status = pt_blk_proceed_one_insn(decoder, block, insn, iext);
83574fe6c29SRuslan Bukin 		if (status <= 0)
83674fe6c29SRuslan Bukin 			return status;
83774fe6c29SRuslan Bukin 
83874fe6c29SRuslan Bukin 		/* We're done if this instruction matches the spec (positive
83974fe6c29SRuslan Bukin 		 * status) or we run into an error (negative status).
84074fe6c29SRuslan Bukin 		 */
84174fe6c29SRuslan Bukin 		status = predicate(insn, iext);
84274fe6c29SRuslan Bukin 		if (status != 0)
84374fe6c29SRuslan Bukin 			return status;
84474fe6c29SRuslan Bukin 
84574fe6c29SRuslan Bukin 		/* Let's see if we can proceed to the next IP without trace. */
84674fe6c29SRuslan Bukin 		status = pt_insn_next_ip(&decoder->ip, insn, iext);
84774fe6c29SRuslan Bukin 		if (status < 0)
84874fe6c29SRuslan Bukin 			return status;
84974fe6c29SRuslan Bukin 
85074fe6c29SRuslan Bukin 		/* End the block if the user asked us to.
85174fe6c29SRuslan Bukin 		 *
85274fe6c29SRuslan Bukin 		 * We only need to take care about direct near branches.
85374fe6c29SRuslan Bukin 		 * Indirect and far branches require trace and will naturally
85474fe6c29SRuslan Bukin 		 * end a block.
85574fe6c29SRuslan Bukin 		 */
85674fe6c29SRuslan Bukin 		if ((decoder->flags.variant.block.end_on_call &&
85774fe6c29SRuslan Bukin 		     (insn->iclass == ptic_call)) ||
85874fe6c29SRuslan Bukin 		    (decoder->flags.variant.block.end_on_jump &&
85974fe6c29SRuslan Bukin 		     (insn->iclass == ptic_jump)))
86074fe6c29SRuslan Bukin 			return 0;
86174fe6c29SRuslan Bukin 	}
86274fe6c29SRuslan Bukin }
86374fe6c29SRuslan Bukin 
86474fe6c29SRuslan Bukin /* Proceed to a particular IP without using trace.
86574fe6c29SRuslan Bukin  *
86674fe6c29SRuslan Bukin  * Proceed until we reach @ip or until:
86774fe6c29SRuslan Bukin  *
86874fe6c29SRuslan Bukin  *   - @block is full:               return zero
86974fe6c29SRuslan Bukin  *   - @block would switch sections: return zero
87074fe6c29SRuslan Bukin  *   - we would need trace:          return -pte_bad_query
87174fe6c29SRuslan Bukin  *
87274fe6c29SRuslan Bukin  * Provide the last instruction that was reached in @insn and @iext.  If we
87374fe6c29SRuslan Bukin  * reached @ip, this is the instruction preceding it.
87474fe6c29SRuslan Bukin  *
87574fe6c29SRuslan Bukin  * Update @decoder->ip to point to the last IP that was reached.  If we fail due
87674fe6c29SRuslan Bukin  * to lack of trace, this is @insn->ip; otherwise this is the next instruction's
87774fe6c29SRuslan Bukin  * IP.
87874fe6c29SRuslan Bukin  *
87974fe6c29SRuslan Bukin  * Returns a positive integer if @ip was reached.
88074fe6c29SRuslan Bukin  * Returns zero if no such instruction was reached.
88174fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
88274fe6c29SRuslan Bukin  */
88374fe6c29SRuslan Bukin static int pt_blk_proceed_to_ip(struct pt_block_decoder *decoder,
88474fe6c29SRuslan Bukin 				struct pt_block *block, struct pt_insn *insn,
88574fe6c29SRuslan Bukin 				struct pt_insn_ext *iext, uint64_t ip)
88674fe6c29SRuslan Bukin {
88774fe6c29SRuslan Bukin 	int status;
88874fe6c29SRuslan Bukin 
88974fe6c29SRuslan Bukin 	if (!decoder || !insn)
89074fe6c29SRuslan Bukin 		return -pte_internal;
89174fe6c29SRuslan Bukin 
89274fe6c29SRuslan Bukin 	for (;;) {
89374fe6c29SRuslan Bukin 		/* We're done when we reach @ip.  We may not even have to decode
89474fe6c29SRuslan Bukin 		 * a single instruction in some cases.
89574fe6c29SRuslan Bukin 		 */
89674fe6c29SRuslan Bukin 		if (decoder->ip == ip)
89774fe6c29SRuslan Bukin 			return 1;
89874fe6c29SRuslan Bukin 
89974fe6c29SRuslan Bukin 		status = pt_blk_proceed_one_insn(decoder, block, insn, iext);
90074fe6c29SRuslan Bukin 		if (status <= 0)
90174fe6c29SRuslan Bukin 			return status;
90274fe6c29SRuslan Bukin 
90374fe6c29SRuslan Bukin 		/* Let's see if we can proceed to the next IP without trace. */
90474fe6c29SRuslan Bukin 		status = pt_insn_next_ip(&decoder->ip, insn, iext);
90574fe6c29SRuslan Bukin 		if (status < 0)
90674fe6c29SRuslan Bukin 			return status;
90774fe6c29SRuslan Bukin 
90874fe6c29SRuslan Bukin 		/* End the block if the user asked us to.
90974fe6c29SRuslan Bukin 		 *
91074fe6c29SRuslan Bukin 		 * We only need to take care about direct near branches.
91174fe6c29SRuslan Bukin 		 * Indirect and far branches require trace and will naturally
91274fe6c29SRuslan Bukin 		 * end a block.
91374fe6c29SRuslan Bukin 		 *
91474fe6c29SRuslan Bukin 		 * The call at the end of the block may have reached @ip; make
91574fe6c29SRuslan Bukin 		 * sure to indicate that.
91674fe6c29SRuslan Bukin 		 */
91774fe6c29SRuslan Bukin 		if ((decoder->flags.variant.block.end_on_call &&
91874fe6c29SRuslan Bukin 		     (insn->iclass == ptic_call)) ||
91974fe6c29SRuslan Bukin 		    (decoder->flags.variant.block.end_on_jump &&
92074fe6c29SRuslan Bukin 		     (insn->iclass == ptic_jump))) {
92174fe6c29SRuslan Bukin 			return (decoder->ip == ip ? 1 : 0);
92274fe6c29SRuslan Bukin 		}
92374fe6c29SRuslan Bukin 	}
92474fe6c29SRuslan Bukin }
92574fe6c29SRuslan Bukin 
92674fe6c29SRuslan Bukin /* Proceed to a particular IP with trace, if necessary.
92774fe6c29SRuslan Bukin  *
92874fe6c29SRuslan Bukin  * Proceed until we reach @ip or until:
92974fe6c29SRuslan Bukin  *
93074fe6c29SRuslan Bukin  *   - @block is full:               return zero
93174fe6c29SRuslan Bukin  *   - @block would switch sections: return zero
93274fe6c29SRuslan Bukin  *   - we need trace:                return zero
93374fe6c29SRuslan Bukin  *
93474fe6c29SRuslan Bukin  * Update @decoder->ip to point to the last IP that was reached.
93574fe6c29SRuslan Bukin  *
93674fe6c29SRuslan Bukin  * A return of zero ends @block.
93774fe6c29SRuslan Bukin  *
93874fe6c29SRuslan Bukin  * Returns a positive integer if @ip was reached.
93974fe6c29SRuslan Bukin  * Returns zero if no such instruction was reached.
94074fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
94174fe6c29SRuslan Bukin  */
94274fe6c29SRuslan Bukin static int pt_blk_proceed_to_ip_with_trace(struct pt_block_decoder *decoder,
94374fe6c29SRuslan Bukin 					   struct pt_block *block,
94474fe6c29SRuslan Bukin 					   uint64_t ip)
94574fe6c29SRuslan Bukin {
94674fe6c29SRuslan Bukin 	struct pt_insn_ext iext;
94774fe6c29SRuslan Bukin 	struct pt_insn insn;
94874fe6c29SRuslan Bukin 	int status;
94974fe6c29SRuslan Bukin 
95074fe6c29SRuslan Bukin 	/* Try to reach @ip without trace.
95174fe6c29SRuslan Bukin 	 *
95274fe6c29SRuslan Bukin 	 * We're also OK if @block overflowed or we switched sections and we
95374fe6c29SRuslan Bukin 	 * have to try again in the next iteration.
95474fe6c29SRuslan Bukin 	 */
95574fe6c29SRuslan Bukin 	status = pt_blk_proceed_to_ip(decoder, block, &insn, &iext, ip);
95674fe6c29SRuslan Bukin 	if (status != -pte_bad_query)
95774fe6c29SRuslan Bukin 		return status;
95874fe6c29SRuslan Bukin 
95974fe6c29SRuslan Bukin 	/* Needing trace is not an error.  We use trace to determine the next
96074fe6c29SRuslan Bukin 	 * start IP and end the block.
96174fe6c29SRuslan Bukin 	 */
96274fe6c29SRuslan Bukin 	return pt_blk_proceed_with_trace(decoder, &insn, &iext);
96374fe6c29SRuslan Bukin }
96474fe6c29SRuslan Bukin 
96574fe6c29SRuslan Bukin static int pt_insn_skl014(const struct pt_insn *insn,
96674fe6c29SRuslan Bukin 			  const struct pt_insn_ext *iext)
96774fe6c29SRuslan Bukin {
96874fe6c29SRuslan Bukin 	if (!insn || !iext)
96974fe6c29SRuslan Bukin 		return 0;
97074fe6c29SRuslan Bukin 
97174fe6c29SRuslan Bukin 	switch (insn->iclass) {
97274fe6c29SRuslan Bukin 	default:
97374fe6c29SRuslan Bukin 		return 0;
97474fe6c29SRuslan Bukin 
97574fe6c29SRuslan Bukin 	case ptic_call:
97674fe6c29SRuslan Bukin 	case ptic_jump:
97774fe6c29SRuslan Bukin 		return iext->variant.branch.is_direct;
97874fe6c29SRuslan Bukin 
97974fe6c29SRuslan Bukin 	case ptic_other:
98074fe6c29SRuslan Bukin 		return pt_insn_changes_cr3(insn, iext);
98174fe6c29SRuslan Bukin 	}
98274fe6c29SRuslan Bukin }
98374fe6c29SRuslan Bukin 
98474fe6c29SRuslan Bukin /* Proceed to the location of a synchronous disabled event with suppressed IP
98574fe6c29SRuslan Bukin  * considering SKL014.
98674fe6c29SRuslan Bukin  *
98774fe6c29SRuslan Bukin  * We have a (synchronous) disabled event pending.  Proceed to the event
98874fe6c29SRuslan Bukin  * location and indicate whether we were able to reach it.
98974fe6c29SRuslan Bukin  *
99074fe6c29SRuslan Bukin  * With SKL014 a TIP.PGD with suppressed IP may also be generated by a direct
99174fe6c29SRuslan Bukin  * unconditional branch that clears FilterEn by jumping out of a filter region
99274fe6c29SRuslan Bukin  * or into a TraceStop region.  Use the filter configuration to determine the
99374fe6c29SRuslan Bukin  * exact branch the event binds to.
99474fe6c29SRuslan Bukin  *
99574fe6c29SRuslan Bukin  * The last instruction that was reached is stored in @insn/@iext.
99674fe6c29SRuslan Bukin  *
99774fe6c29SRuslan Bukin  * Returns a positive integer if the event location was reached.
99874fe6c29SRuslan Bukin  * Returns zero if the event location was not reached.
99974fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
100074fe6c29SRuslan Bukin  */
100174fe6c29SRuslan Bukin static int pt_blk_proceed_skl014(struct pt_block_decoder *decoder,
100274fe6c29SRuslan Bukin 				 struct pt_block *block, struct pt_insn *insn,
100374fe6c29SRuslan Bukin 				 struct pt_insn_ext *iext)
100474fe6c29SRuslan Bukin {
100574fe6c29SRuslan Bukin 	const struct pt_conf_addr_filter *addr_filter;
100674fe6c29SRuslan Bukin 	int status;
100774fe6c29SRuslan Bukin 
100874fe6c29SRuslan Bukin 	if (!decoder || !block || !insn || !iext)
100974fe6c29SRuslan Bukin 		return -pte_internal;
101074fe6c29SRuslan Bukin 
101174fe6c29SRuslan Bukin 	addr_filter = &decoder->query.config.addr_filter;
101274fe6c29SRuslan Bukin 	for (;;) {
101374fe6c29SRuslan Bukin 		uint64_t ip;
101474fe6c29SRuslan Bukin 
101574fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_insn(decoder, block, insn, iext,
101674fe6c29SRuslan Bukin 						pt_insn_skl014);
101774fe6c29SRuslan Bukin 		if (status <= 0)
101874fe6c29SRuslan Bukin 			break;
101974fe6c29SRuslan Bukin 
102074fe6c29SRuslan Bukin 		/* The erratum doesn't apply if we can bind the event to a
102174fe6c29SRuslan Bukin 		 * CR3-changing instruction.
102274fe6c29SRuslan Bukin 		 */
102374fe6c29SRuslan Bukin 		if (pt_insn_changes_cr3(insn, iext))
102474fe6c29SRuslan Bukin 			break;
102574fe6c29SRuslan Bukin 
102674fe6c29SRuslan Bukin 		/* Check the filter against the branch target. */
102774fe6c29SRuslan Bukin 		status = pt_insn_next_ip(&ip, insn, iext);
102874fe6c29SRuslan Bukin 		if (status < 0)
102974fe6c29SRuslan Bukin 			break;
103074fe6c29SRuslan Bukin 
103174fe6c29SRuslan Bukin 		status = pt_filter_addr_check(addr_filter, ip);
103274fe6c29SRuslan Bukin 		if (status <= 0) {
103374fe6c29SRuslan Bukin 			/* We need to flip the indication.
103474fe6c29SRuslan Bukin 			 *
103574fe6c29SRuslan Bukin 			 * We reached the event location when @ip lies inside a
103674fe6c29SRuslan Bukin 			 * tracing-disabled region.
103774fe6c29SRuslan Bukin 			 */
103874fe6c29SRuslan Bukin 			if (!status)
103974fe6c29SRuslan Bukin 				status = 1;
104074fe6c29SRuslan Bukin 
104174fe6c29SRuslan Bukin 			break;
104274fe6c29SRuslan Bukin 		}
104374fe6c29SRuslan Bukin 
104474fe6c29SRuslan Bukin 		/* This is not the correct instruction.  Proceed past it and try
104574fe6c29SRuslan Bukin 		 * again.
104674fe6c29SRuslan Bukin 		 */
104774fe6c29SRuslan Bukin 		decoder->ip = ip;
104874fe6c29SRuslan Bukin 
104974fe6c29SRuslan Bukin 		/* End the block if the user asked us to.
105074fe6c29SRuslan Bukin 		 *
105174fe6c29SRuslan Bukin 		 * We only need to take care about direct near branches.
105274fe6c29SRuslan Bukin 		 * Indirect and far branches require trace and will naturally
105374fe6c29SRuslan Bukin 		 * end a block.
105474fe6c29SRuslan Bukin 		 */
105574fe6c29SRuslan Bukin 		if ((decoder->flags.variant.block.end_on_call &&
105674fe6c29SRuslan Bukin 		    (insn->iclass == ptic_call)) ||
105774fe6c29SRuslan Bukin 		    (decoder->flags.variant.block.end_on_jump &&
105874fe6c29SRuslan Bukin 		    (insn->iclass == ptic_jump)))
105974fe6c29SRuslan Bukin 			break;
106074fe6c29SRuslan Bukin 	}
106174fe6c29SRuslan Bukin 
106274fe6c29SRuslan Bukin 	return status;
106374fe6c29SRuslan Bukin }
106474fe6c29SRuslan Bukin 
106574fe6c29SRuslan Bukin /* Proceed to the event location for a disabled event.
106674fe6c29SRuslan Bukin  *
106774fe6c29SRuslan Bukin  * We have a (synchronous) disabled event pending.  Proceed to the event
106874fe6c29SRuslan Bukin  * location and indicate whether we were able to reach it.
106974fe6c29SRuslan Bukin  *
107074fe6c29SRuslan Bukin  * The last instruction that was reached is stored in @insn/@iext.
107174fe6c29SRuslan Bukin  *
107274fe6c29SRuslan Bukin  * Returns a positive integer if the event location was reached.
107374fe6c29SRuslan Bukin  * Returns zero if the event location was not reached.
107474fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
107574fe6c29SRuslan Bukin  */
107674fe6c29SRuslan Bukin static int pt_blk_proceed_to_disabled(struct pt_block_decoder *decoder,
107774fe6c29SRuslan Bukin 				      struct pt_block *block,
107874fe6c29SRuslan Bukin 				      struct pt_insn *insn,
107974fe6c29SRuslan Bukin 				      struct pt_insn_ext *iext,
108074fe6c29SRuslan Bukin 				      const struct pt_event *ev)
108174fe6c29SRuslan Bukin {
108274fe6c29SRuslan Bukin 	if (!decoder || !block || !ev)
108374fe6c29SRuslan Bukin 		return -pte_internal;
108474fe6c29SRuslan Bukin 
108574fe6c29SRuslan Bukin 	if (ev->ip_suppressed) {
108674fe6c29SRuslan Bukin 		/* Due to SKL014 the TIP.PGD payload may be suppressed also for
108774fe6c29SRuslan Bukin 		 * direct branches.
108874fe6c29SRuslan Bukin 		 *
108974fe6c29SRuslan Bukin 		 * If we don't have a filter configuration we assume that no
109074fe6c29SRuslan Bukin 		 * address filters were used and the erratum does not apply.
109174fe6c29SRuslan Bukin 		 *
109274fe6c29SRuslan Bukin 		 * We might otherwise disable tracing too early.
109374fe6c29SRuslan Bukin 		 */
109474fe6c29SRuslan Bukin 		if (decoder->query.config.addr_filter.config.addr_cfg &&
109574fe6c29SRuslan Bukin 		    decoder->query.config.errata.skl014)
109674fe6c29SRuslan Bukin 			return pt_blk_proceed_skl014(decoder, block, insn,
109774fe6c29SRuslan Bukin 						     iext);
109874fe6c29SRuslan Bukin 
109974fe6c29SRuslan Bukin 		/* A synchronous disabled event also binds to far branches and
110074fe6c29SRuslan Bukin 		 * CPL-changing instructions.  Both would require trace,
110174fe6c29SRuslan Bukin 		 * however, and are thus implicitly handled by erroring out.
110274fe6c29SRuslan Bukin 		 *
110374fe6c29SRuslan Bukin 		 * The would-require-trace error is handled by our caller.
110474fe6c29SRuslan Bukin 		 */
110574fe6c29SRuslan Bukin 		return pt_blk_proceed_to_insn(decoder, block, insn, iext,
110674fe6c29SRuslan Bukin 					      pt_insn_changes_cr3);
110774fe6c29SRuslan Bukin 	} else
110874fe6c29SRuslan Bukin 		return pt_blk_proceed_to_ip(decoder, block, insn, iext,
110974fe6c29SRuslan Bukin 					    ev->variant.disabled.ip);
111074fe6c29SRuslan Bukin }
111174fe6c29SRuslan Bukin 
111274fe6c29SRuslan Bukin /* Set the expected resume address for a synchronous disable.
111374fe6c29SRuslan Bukin  *
111474fe6c29SRuslan Bukin  * On a synchronous disable, @decoder->ip still points to the instruction to
111574fe6c29SRuslan Bukin  * which the event bound.  That's not where we expect tracing to resume.
111674fe6c29SRuslan Bukin  *
111774fe6c29SRuslan Bukin  * For calls, a fair assumption is that tracing resumes after returning from the
111874fe6c29SRuslan Bukin  * called function.  For other types of instructions, we simply don't know.
111974fe6c29SRuslan Bukin  *
112074fe6c29SRuslan Bukin  * Returns zero on success, a negative pt_error_code otherwise.
112174fe6c29SRuslan Bukin  */
112274fe6c29SRuslan Bukin static int pt_blk_set_disable_resume_ip(struct pt_block_decoder *decoder,
112374fe6c29SRuslan Bukin 					const struct pt_insn *insn)
112474fe6c29SRuslan Bukin {
112574fe6c29SRuslan Bukin 	if (!decoder || !insn)
112674fe6c29SRuslan Bukin 		return -pte_internal;
112774fe6c29SRuslan Bukin 
112874fe6c29SRuslan Bukin 	switch (insn->iclass) {
112974fe6c29SRuslan Bukin 	case ptic_call:
113074fe6c29SRuslan Bukin 	case ptic_far_call:
113174fe6c29SRuslan Bukin 		decoder->ip = insn->ip + insn->size;
113274fe6c29SRuslan Bukin 		break;
113374fe6c29SRuslan Bukin 
113474fe6c29SRuslan Bukin 	default:
113574fe6c29SRuslan Bukin 		decoder->ip = 0ull;
113674fe6c29SRuslan Bukin 		break;
113774fe6c29SRuslan Bukin 	}
113874fe6c29SRuslan Bukin 
113974fe6c29SRuslan Bukin 	return 0;
114074fe6c29SRuslan Bukin }
114174fe6c29SRuslan Bukin 
114274fe6c29SRuslan Bukin /* Proceed to the event location for an async paging event.
114374fe6c29SRuslan Bukin  *
114474fe6c29SRuslan Bukin  * We have an async paging event pending.  Proceed to the event location and
114574fe6c29SRuslan Bukin  * indicate whether we were able to reach it.  Needing trace in order to proceed
114674fe6c29SRuslan Bukin  * is not an error in this case but ends the block.
114774fe6c29SRuslan Bukin  *
114874fe6c29SRuslan Bukin  * Returns a positive integer if the event location was reached.
114974fe6c29SRuslan Bukin  * Returns zero if the event location was not reached.
115074fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
115174fe6c29SRuslan Bukin  */
115274fe6c29SRuslan Bukin static int pt_blk_proceed_to_async_paging(struct pt_block_decoder *decoder,
115374fe6c29SRuslan Bukin 					  struct pt_block *block,
115474fe6c29SRuslan Bukin 					  const struct pt_event *ev)
115574fe6c29SRuslan Bukin {
115674fe6c29SRuslan Bukin 	int status;
115774fe6c29SRuslan Bukin 
115874fe6c29SRuslan Bukin 	if (!decoder || !ev)
115974fe6c29SRuslan Bukin 		return -pte_internal;
116074fe6c29SRuslan Bukin 
116174fe6c29SRuslan Bukin 	/* Apply the event immediately if we don't have an IP. */
116274fe6c29SRuslan Bukin 	if (ev->ip_suppressed)
116374fe6c29SRuslan Bukin 		return 1;
116474fe6c29SRuslan Bukin 
116574fe6c29SRuslan Bukin 	status = pt_blk_proceed_to_ip_with_trace(decoder, block,
116674fe6c29SRuslan Bukin 						 ev->variant.async_paging.ip);
116774fe6c29SRuslan Bukin 	if (status < 0)
116874fe6c29SRuslan Bukin 		return status;
116974fe6c29SRuslan Bukin 
117074fe6c29SRuslan Bukin 	/* We may have reached the IP. */
117174fe6c29SRuslan Bukin 	return (decoder->ip == ev->variant.async_paging.ip ? 1 : 0);
117274fe6c29SRuslan Bukin }
117374fe6c29SRuslan Bukin 
117474fe6c29SRuslan Bukin /* Proceed to the event location for an async vmcs event.
117574fe6c29SRuslan Bukin  *
117674fe6c29SRuslan Bukin  * We have an async vmcs event pending.  Proceed to the event location and
117774fe6c29SRuslan Bukin  * indicate whether we were able to reach it.  Needing trace in order to proceed
117874fe6c29SRuslan Bukin  * is not an error in this case but ends the block.
117974fe6c29SRuslan Bukin  *
118074fe6c29SRuslan Bukin  * Returns a positive integer if the event location was reached.
118174fe6c29SRuslan Bukin  * Returns zero if the event location was not reached.
118274fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
118374fe6c29SRuslan Bukin  */
118474fe6c29SRuslan Bukin static int pt_blk_proceed_to_async_vmcs(struct pt_block_decoder *decoder,
118574fe6c29SRuslan Bukin 					struct pt_block *block,
118674fe6c29SRuslan Bukin 					const struct pt_event *ev)
118774fe6c29SRuslan Bukin {
118874fe6c29SRuslan Bukin 	int status;
118974fe6c29SRuslan Bukin 
119074fe6c29SRuslan Bukin 	if (!decoder || !ev)
119174fe6c29SRuslan Bukin 		return -pte_internal;
119274fe6c29SRuslan Bukin 
119374fe6c29SRuslan Bukin 	/* Apply the event immediately if we don't have an IP. */
119474fe6c29SRuslan Bukin 	if (ev->ip_suppressed)
119574fe6c29SRuslan Bukin 		return 1;
119674fe6c29SRuslan Bukin 
119774fe6c29SRuslan Bukin 	status = pt_blk_proceed_to_ip_with_trace(decoder, block,
119874fe6c29SRuslan Bukin 						 ev->variant.async_vmcs.ip);
119974fe6c29SRuslan Bukin 	if (status < 0)
120074fe6c29SRuslan Bukin 		return status;
120174fe6c29SRuslan Bukin 
120274fe6c29SRuslan Bukin 	/* We may have reached the IP. */
120374fe6c29SRuslan Bukin 	return (decoder->ip == ev->variant.async_vmcs.ip ? 1 : 0);
120474fe6c29SRuslan Bukin }
120574fe6c29SRuslan Bukin 
120674fe6c29SRuslan Bukin /* Proceed to the event location for an exec mode event.
120774fe6c29SRuslan Bukin  *
120874fe6c29SRuslan Bukin  * We have an exec mode event pending.  Proceed to the event location and
120974fe6c29SRuslan Bukin  * indicate whether we were able to reach it.  Needing trace in order to proceed
121074fe6c29SRuslan Bukin  * is not an error in this case but ends the block.
121174fe6c29SRuslan Bukin  *
121274fe6c29SRuslan Bukin  * Returns a positive integer if the event location was reached.
121374fe6c29SRuslan Bukin  * Returns zero if the event location was not reached.
121474fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
121574fe6c29SRuslan Bukin  */
121674fe6c29SRuslan Bukin static int pt_blk_proceed_to_exec_mode(struct pt_block_decoder *decoder,
121774fe6c29SRuslan Bukin 				       struct pt_block *block,
121874fe6c29SRuslan Bukin 				       const struct pt_event *ev)
121974fe6c29SRuslan Bukin {
122074fe6c29SRuslan Bukin 	int status;
122174fe6c29SRuslan Bukin 
122274fe6c29SRuslan Bukin 	if (!decoder || !ev)
122374fe6c29SRuslan Bukin 		return -pte_internal;
122474fe6c29SRuslan Bukin 
122574fe6c29SRuslan Bukin 	/* Apply the event immediately if we don't have an IP. */
122674fe6c29SRuslan Bukin 	if (ev->ip_suppressed)
122774fe6c29SRuslan Bukin 		return 1;
122874fe6c29SRuslan Bukin 
122974fe6c29SRuslan Bukin 	status = pt_blk_proceed_to_ip_with_trace(decoder, block,
123074fe6c29SRuslan Bukin 						 ev->variant.exec_mode.ip);
123174fe6c29SRuslan Bukin 	if (status < 0)
123274fe6c29SRuslan Bukin 		return status;
123374fe6c29SRuslan Bukin 
123474fe6c29SRuslan Bukin 	/* We may have reached the IP. */
123574fe6c29SRuslan Bukin 	return (decoder->ip == ev->variant.exec_mode.ip ? 1 : 0);
123674fe6c29SRuslan Bukin }
123774fe6c29SRuslan Bukin 
123874fe6c29SRuslan Bukin /* Proceed to the event location for a ptwrite event.
123974fe6c29SRuslan Bukin  *
124074fe6c29SRuslan Bukin  * We have a ptwrite event pending.  Proceed to the event location and indicate
124174fe6c29SRuslan Bukin  * whether we were able to reach it.
124274fe6c29SRuslan Bukin  *
124374fe6c29SRuslan Bukin  * In case of the event binding to a ptwrite instruction, we pass beyond that
124474fe6c29SRuslan Bukin  * instruction and update the event to provide the instruction's IP.
124574fe6c29SRuslan Bukin  *
124674fe6c29SRuslan Bukin  * In the case of the event binding to an IP provided in the event, we move
124774fe6c29SRuslan Bukin  * beyond the instruction at that IP.
124874fe6c29SRuslan Bukin  *
124974fe6c29SRuslan Bukin  * Returns a positive integer if the event location was reached.
125074fe6c29SRuslan Bukin  * Returns zero if the event location was not reached.
125174fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
125274fe6c29SRuslan Bukin  */
125374fe6c29SRuslan Bukin static int pt_blk_proceed_to_ptwrite(struct pt_block_decoder *decoder,
125474fe6c29SRuslan Bukin 				     struct pt_block *block,
125574fe6c29SRuslan Bukin 				     struct pt_insn *insn,
125674fe6c29SRuslan Bukin 				     struct pt_insn_ext *iext,
125774fe6c29SRuslan Bukin 				     struct pt_event *ev)
125874fe6c29SRuslan Bukin {
125974fe6c29SRuslan Bukin 	int status;
126074fe6c29SRuslan Bukin 
126174fe6c29SRuslan Bukin 	if (!insn || !ev)
126274fe6c29SRuslan Bukin 		return -pte_internal;
126374fe6c29SRuslan Bukin 
126474fe6c29SRuslan Bukin 	/* If we don't have an IP, the event binds to the next PTWRITE
126574fe6c29SRuslan Bukin 	 * instruction.
126674fe6c29SRuslan Bukin 	 *
126774fe6c29SRuslan Bukin 	 * If we have an IP it still binds to the next PTWRITE instruction but
126874fe6c29SRuslan Bukin 	 * now the IP tells us where that instruction is.  This makes most sense
126974fe6c29SRuslan Bukin 	 * when tracing is disabled and we don't have any other means of finding
127074fe6c29SRuslan Bukin 	 * the PTWRITE instruction.  We nevertheless distinguish the two cases,
127174fe6c29SRuslan Bukin 	 * here.
127274fe6c29SRuslan Bukin 	 *
127374fe6c29SRuslan Bukin 	 * In both cases, we move beyond the PTWRITE instruction, so it will be
127474fe6c29SRuslan Bukin 	 * the last instruction in the current block and @decoder->ip will point
127574fe6c29SRuslan Bukin 	 * to the instruction following it.
127674fe6c29SRuslan Bukin 	 */
127774fe6c29SRuslan Bukin 	if (ev->ip_suppressed) {
127874fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_insn(decoder, block, insn, iext,
127974fe6c29SRuslan Bukin 						pt_insn_is_ptwrite);
128074fe6c29SRuslan Bukin 		if (status <= 0)
128174fe6c29SRuslan Bukin 			return status;
128274fe6c29SRuslan Bukin 
128374fe6c29SRuslan Bukin 		/* We now know the IP of the PTWRITE instruction corresponding
128474fe6c29SRuslan Bukin 		 * to this event.  Fill it in to make it more convenient for the
128574fe6c29SRuslan Bukin 		 * user to process the event.
128674fe6c29SRuslan Bukin 		 */
128774fe6c29SRuslan Bukin 		ev->variant.ptwrite.ip = insn->ip;
128874fe6c29SRuslan Bukin 		ev->ip_suppressed = 0;
128974fe6c29SRuslan Bukin 	} else {
129074fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_ip(decoder, block, insn, iext,
129174fe6c29SRuslan Bukin 					      ev->variant.ptwrite.ip);
129274fe6c29SRuslan Bukin 		if (status <= 0)
129374fe6c29SRuslan Bukin 			return status;
129474fe6c29SRuslan Bukin 
129574fe6c29SRuslan Bukin 		/* We reached the PTWRITE instruction and @decoder->ip points to
129674fe6c29SRuslan Bukin 		 * it; @insn/@iext still contain the preceding instruction.
129774fe6c29SRuslan Bukin 		 *
129874fe6c29SRuslan Bukin 		 * Proceed beyond the PTWRITE to account for it.  Note that we
129974fe6c29SRuslan Bukin 		 * may still overflow the block, which would cause us to
130074fe6c29SRuslan Bukin 		 * postpone both instruction and event to the next block.
130174fe6c29SRuslan Bukin 		 */
130274fe6c29SRuslan Bukin 		status = pt_blk_proceed_one_insn(decoder, block, insn, iext);
130374fe6c29SRuslan Bukin 		if (status <= 0)
130474fe6c29SRuslan Bukin 			return status;
130574fe6c29SRuslan Bukin 	}
130674fe6c29SRuslan Bukin 
130774fe6c29SRuslan Bukin 	return 1;
130874fe6c29SRuslan Bukin }
130974fe6c29SRuslan Bukin 
131074fe6c29SRuslan Bukin /* Try to work around erratum SKD022.
131174fe6c29SRuslan Bukin  *
131274fe6c29SRuslan Bukin  * If we get an asynchronous disable on VMLAUNCH or VMRESUME, the FUP that
131374fe6c29SRuslan Bukin  * caused the disable to be asynchronous might have been bogous.
131474fe6c29SRuslan Bukin  *
131574fe6c29SRuslan Bukin  * Returns a positive integer if the erratum has been handled.
131674fe6c29SRuslan Bukin  * Returns zero if the erratum does not apply.
131774fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
131874fe6c29SRuslan Bukin  */
131974fe6c29SRuslan Bukin static int pt_blk_handle_erratum_skd022(struct pt_block_decoder *decoder,
132074fe6c29SRuslan Bukin 					struct pt_event *ev)
132174fe6c29SRuslan Bukin {
132274fe6c29SRuslan Bukin 	struct pt_insn_ext iext;
132374fe6c29SRuslan Bukin 	struct pt_insn insn;
132474fe6c29SRuslan Bukin 	int errcode;
132574fe6c29SRuslan Bukin 
132674fe6c29SRuslan Bukin 	if (!decoder || !ev)
132774fe6c29SRuslan Bukin 		return -pte_internal;
132874fe6c29SRuslan Bukin 
132974fe6c29SRuslan Bukin 	insn.mode = decoder->mode;
133074fe6c29SRuslan Bukin 	insn.ip = ev->variant.async_disabled.at;
133174fe6c29SRuslan Bukin 
133274fe6c29SRuslan Bukin 	errcode = pt_insn_decode(&insn, &iext, decoder->image, &decoder->asid);
133374fe6c29SRuslan Bukin 	if (errcode < 0)
133474fe6c29SRuslan Bukin 		return 0;
133574fe6c29SRuslan Bukin 
133674fe6c29SRuslan Bukin 	switch (iext.iclass) {
133774fe6c29SRuslan Bukin 	default:
133874fe6c29SRuslan Bukin 		/* The erratum does not apply. */
133974fe6c29SRuslan Bukin 		return 0;
134074fe6c29SRuslan Bukin 
134174fe6c29SRuslan Bukin 	case PTI_INST_VMLAUNCH:
134274fe6c29SRuslan Bukin 	case PTI_INST_VMRESUME:
134374fe6c29SRuslan Bukin 		/* The erratum may apply.  We can't be sure without a lot more
134474fe6c29SRuslan Bukin 		 * analysis.  Let's assume it does.
134574fe6c29SRuslan Bukin 		 *
134674fe6c29SRuslan Bukin 		 * We turn the async disable into a sync disable.  Our caller
134774fe6c29SRuslan Bukin 		 * will restart event processing.
134874fe6c29SRuslan Bukin 		 */
134974fe6c29SRuslan Bukin 		ev->type = ptev_disabled;
135074fe6c29SRuslan Bukin 		ev->variant.disabled.ip = ev->variant.async_disabled.ip;
135174fe6c29SRuslan Bukin 
135274fe6c29SRuslan Bukin 		return 1;
135374fe6c29SRuslan Bukin 	}
135474fe6c29SRuslan Bukin }
135574fe6c29SRuslan Bukin 
135674fe6c29SRuslan Bukin /* Postpone proceeding past @insn/@iext and indicate a pending event.
135774fe6c29SRuslan Bukin  *
135874fe6c29SRuslan Bukin  * There may be further events pending on @insn/@iext.  Postpone proceeding past
135974fe6c29SRuslan Bukin  * @insn/@iext until we processed all events that bind to it.
136074fe6c29SRuslan Bukin  *
136174fe6c29SRuslan Bukin  * Returns a non-negative pt_status_flag bit-vector indicating a pending event
136274fe6c29SRuslan Bukin  * on success, a negative pt_error_code otherwise.
136374fe6c29SRuslan Bukin  */
136474fe6c29SRuslan Bukin static int pt_blk_postpone_insn(struct pt_block_decoder *decoder,
136574fe6c29SRuslan Bukin 				const struct pt_insn *insn,
136674fe6c29SRuslan Bukin 				const struct pt_insn_ext *iext)
136774fe6c29SRuslan Bukin {
136874fe6c29SRuslan Bukin 	if (!decoder || !insn || !iext)
136974fe6c29SRuslan Bukin 		return -pte_internal;
137074fe6c29SRuslan Bukin 
137174fe6c29SRuslan Bukin 	/* Only one can be active. */
137274fe6c29SRuslan Bukin 	if (decoder->process_insn)
137374fe6c29SRuslan Bukin 		return -pte_internal;
137474fe6c29SRuslan Bukin 
137574fe6c29SRuslan Bukin 	decoder->process_insn = 1;
137674fe6c29SRuslan Bukin 	decoder->insn = *insn;
137774fe6c29SRuslan Bukin 	decoder->iext = *iext;
137874fe6c29SRuslan Bukin 
137974fe6c29SRuslan Bukin 	return pt_blk_status(decoder, pts_event_pending);
138074fe6c29SRuslan Bukin }
138174fe6c29SRuslan Bukin 
138274fe6c29SRuslan Bukin /* Remove any postponed instruction from @decoder.
138374fe6c29SRuslan Bukin  *
138474fe6c29SRuslan Bukin  * Returns zero on success, a negative pt_error_code otherwise.
138574fe6c29SRuslan Bukin  */
138674fe6c29SRuslan Bukin static int pt_blk_clear_postponed_insn(struct pt_block_decoder *decoder)
138774fe6c29SRuslan Bukin {
138874fe6c29SRuslan Bukin 	if (!decoder)
138974fe6c29SRuslan Bukin 		return -pte_internal;
139074fe6c29SRuslan Bukin 
139174fe6c29SRuslan Bukin 	decoder->process_insn = 0;
139274fe6c29SRuslan Bukin 	decoder->bound_paging = 0;
139374fe6c29SRuslan Bukin 	decoder->bound_vmcs = 0;
139474fe6c29SRuslan Bukin 	decoder->bound_ptwrite = 0;
139574fe6c29SRuslan Bukin 
139674fe6c29SRuslan Bukin 	return 0;
139774fe6c29SRuslan Bukin }
139874fe6c29SRuslan Bukin 
139974fe6c29SRuslan Bukin /* Proceed past a postponed instruction.
140074fe6c29SRuslan Bukin  *
140174fe6c29SRuslan Bukin  * If an instruction has been postponed in @decoder, proceed past it.
140274fe6c29SRuslan Bukin  *
140374fe6c29SRuslan Bukin  * Returns zero on success, a negative pt_error_code otherwise.
140474fe6c29SRuslan Bukin  */
140574fe6c29SRuslan Bukin static int pt_blk_proceed_postponed_insn(struct pt_block_decoder *decoder)
140674fe6c29SRuslan Bukin {
140774fe6c29SRuslan Bukin 	int status;
140874fe6c29SRuslan Bukin 
140974fe6c29SRuslan Bukin 	if (!decoder)
141074fe6c29SRuslan Bukin 		return -pte_internal;
141174fe6c29SRuslan Bukin 
141274fe6c29SRuslan Bukin 	/* There's nothing to do if we have no postponed instruction. */
141374fe6c29SRuslan Bukin 	if (!decoder->process_insn)
141474fe6c29SRuslan Bukin 		return 0;
141574fe6c29SRuslan Bukin 
141674fe6c29SRuslan Bukin 	/* There's nothing to do if tracing got disabled. */
141774fe6c29SRuslan Bukin 	if (!decoder->enabled)
141874fe6c29SRuslan Bukin 		return pt_blk_clear_postponed_insn(decoder);
141974fe6c29SRuslan Bukin 
142074fe6c29SRuslan Bukin 	status = pt_insn_next_ip(&decoder->ip, &decoder->insn, &decoder->iext);
142174fe6c29SRuslan Bukin 	if (status < 0) {
142274fe6c29SRuslan Bukin 		if (status != -pte_bad_query)
142374fe6c29SRuslan Bukin 			return status;
142474fe6c29SRuslan Bukin 
142574fe6c29SRuslan Bukin 		status = pt_blk_proceed_with_trace(decoder, &decoder->insn,
142674fe6c29SRuslan Bukin 						   &decoder->iext);
142774fe6c29SRuslan Bukin 		if (status < 0)
142874fe6c29SRuslan Bukin 			return status;
142974fe6c29SRuslan Bukin 	}
143074fe6c29SRuslan Bukin 
143174fe6c29SRuslan Bukin 	return pt_blk_clear_postponed_insn(decoder);
143274fe6c29SRuslan Bukin }
143374fe6c29SRuslan Bukin 
143474fe6c29SRuslan Bukin /* Proceed to the next event.
143574fe6c29SRuslan Bukin  *
143674fe6c29SRuslan Bukin  * We have an event pending.  Proceed to the event location and indicate the
143774fe6c29SRuslan Bukin  * event to the user.
143874fe6c29SRuslan Bukin  *
143974fe6c29SRuslan Bukin  * On our way to the event location we may also be forced to postpone the event
144074fe6c29SRuslan Bukin  * to the next block, e.g. if we overflow the number of instructions in the
144174fe6c29SRuslan Bukin  * block or if we need trace in order to reach the event location.
144274fe6c29SRuslan Bukin  *
144374fe6c29SRuslan Bukin  * If we're not able to reach the event location, we return zero.  This is what
144474fe6c29SRuslan Bukin  * pt_blk_status() would return since:
144574fe6c29SRuslan Bukin  *
144674fe6c29SRuslan Bukin  *   - we suppress pts_eos as long as we're processing events
144774fe6c29SRuslan Bukin  *   - we do not set pts_ip_suppressed since tracing must be enabled
144874fe6c29SRuslan Bukin  *
144974fe6c29SRuslan Bukin  * Returns a non-negative pt_status_flag bit-vector on success, a negative error
145074fe6c29SRuslan Bukin  * code otherwise.
145174fe6c29SRuslan Bukin  */
145274fe6c29SRuslan Bukin static int pt_blk_proceed_event(struct pt_block_decoder *decoder,
145374fe6c29SRuslan Bukin 				struct pt_block *block)
145474fe6c29SRuslan Bukin {
145574fe6c29SRuslan Bukin 	struct pt_insn_ext iext;
145674fe6c29SRuslan Bukin 	struct pt_insn insn;
145774fe6c29SRuslan Bukin 	struct pt_event *ev;
145874fe6c29SRuslan Bukin 	int status;
145974fe6c29SRuslan Bukin 
146074fe6c29SRuslan Bukin 	if (!decoder || !decoder->process_event || !block)
146174fe6c29SRuslan Bukin 		return -pte_internal;
146274fe6c29SRuslan Bukin 
146374fe6c29SRuslan Bukin 	ev = &decoder->event;
146474fe6c29SRuslan Bukin 	switch (ev->type) {
146574fe6c29SRuslan Bukin 	case ptev_enabled:
146674fe6c29SRuslan Bukin 		break;
146774fe6c29SRuslan Bukin 
146874fe6c29SRuslan Bukin 	case ptev_disabled:
146974fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_disabled(decoder, block, &insn,
147074fe6c29SRuslan Bukin 						    &iext, ev);
147174fe6c29SRuslan Bukin 		if (status <= 0) {
147274fe6c29SRuslan Bukin 			/* A synchronous disable event also binds to the next
147374fe6c29SRuslan Bukin 			 * indirect or conditional branch, i.e. to any branch
147474fe6c29SRuslan Bukin 			 * that would have required trace.
147574fe6c29SRuslan Bukin 			 */
147674fe6c29SRuslan Bukin 			if (status != -pte_bad_query)
147774fe6c29SRuslan Bukin 				return status;
147874fe6c29SRuslan Bukin 
147974fe6c29SRuslan Bukin 			status = pt_blk_set_disable_resume_ip(decoder, &insn);
148074fe6c29SRuslan Bukin 			if (status < 0)
148174fe6c29SRuslan Bukin 				return status;
148274fe6c29SRuslan Bukin 		}
148374fe6c29SRuslan Bukin 
148474fe6c29SRuslan Bukin 		break;
148574fe6c29SRuslan Bukin 
148674fe6c29SRuslan Bukin 	case ptev_async_disabled:
148774fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_ip(decoder, block, &insn, &iext,
148874fe6c29SRuslan Bukin 					      ev->variant.async_disabled.at);
148974fe6c29SRuslan Bukin 		if (status <= 0)
149074fe6c29SRuslan Bukin 			return status;
149174fe6c29SRuslan Bukin 
149274fe6c29SRuslan Bukin 		if (decoder->query.config.errata.skd022) {
149374fe6c29SRuslan Bukin 			status = pt_blk_handle_erratum_skd022(decoder, ev);
149474fe6c29SRuslan Bukin 			if (status != 0) {
149574fe6c29SRuslan Bukin 				if (status < 0)
149674fe6c29SRuslan Bukin 					return status;
149774fe6c29SRuslan Bukin 
149874fe6c29SRuslan Bukin 				/* If the erratum hits, we modify the event.
149974fe6c29SRuslan Bukin 				 * Try again.
150074fe6c29SRuslan Bukin 				 */
150174fe6c29SRuslan Bukin 				return pt_blk_proceed_event(decoder, block);
150274fe6c29SRuslan Bukin 			}
150374fe6c29SRuslan Bukin 		}
150474fe6c29SRuslan Bukin 
150574fe6c29SRuslan Bukin 		break;
150674fe6c29SRuslan Bukin 
150774fe6c29SRuslan Bukin 	case ptev_async_branch:
150874fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_ip(decoder, block, &insn, &iext,
150974fe6c29SRuslan Bukin 					      ev->variant.async_branch.from);
151074fe6c29SRuslan Bukin 		if (status <= 0)
151174fe6c29SRuslan Bukin 			return status;
151274fe6c29SRuslan Bukin 
151374fe6c29SRuslan Bukin 		break;
151474fe6c29SRuslan Bukin 
151574fe6c29SRuslan Bukin 	case ptev_paging:
151674fe6c29SRuslan Bukin 		if (!decoder->enabled)
151774fe6c29SRuslan Bukin 			break;
151874fe6c29SRuslan Bukin 
151974fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_insn(decoder, block, &insn, &iext,
152074fe6c29SRuslan Bukin 						pt_insn_binds_to_pip);
152174fe6c29SRuslan Bukin 		if (status <= 0)
152274fe6c29SRuslan Bukin 			return status;
152374fe6c29SRuslan Bukin 
152474fe6c29SRuslan Bukin 		/* We bound a paging event.  Make sure we do not bind further
152574fe6c29SRuslan Bukin 		 * paging events to this instruction.
152674fe6c29SRuslan Bukin 		 */
152774fe6c29SRuslan Bukin 		decoder->bound_paging = 1;
152874fe6c29SRuslan Bukin 
152974fe6c29SRuslan Bukin 		return pt_blk_postpone_insn(decoder, &insn, &iext);
153074fe6c29SRuslan Bukin 
153174fe6c29SRuslan Bukin 	case ptev_async_paging:
153274fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_async_paging(decoder, block, ev);
153374fe6c29SRuslan Bukin 		if (status <= 0)
153474fe6c29SRuslan Bukin 			return status;
153574fe6c29SRuslan Bukin 
153674fe6c29SRuslan Bukin 		break;
153774fe6c29SRuslan Bukin 
153874fe6c29SRuslan Bukin 	case ptev_vmcs:
153974fe6c29SRuslan Bukin 		if (!decoder->enabled)
154074fe6c29SRuslan Bukin 			break;
154174fe6c29SRuslan Bukin 
154274fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_insn(decoder, block, &insn, &iext,
154374fe6c29SRuslan Bukin 						pt_insn_binds_to_vmcs);
154474fe6c29SRuslan Bukin 		if (status <= 0)
154574fe6c29SRuslan Bukin 			return status;
154674fe6c29SRuslan Bukin 
154774fe6c29SRuslan Bukin 		/* We bound a vmcs event.  Make sure we do not bind further vmcs
154874fe6c29SRuslan Bukin 		 * events to this instruction.
154974fe6c29SRuslan Bukin 		 */
155074fe6c29SRuslan Bukin 		decoder->bound_vmcs = 1;
155174fe6c29SRuslan Bukin 
155274fe6c29SRuslan Bukin 		return pt_blk_postpone_insn(decoder, &insn, &iext);
155374fe6c29SRuslan Bukin 
155474fe6c29SRuslan Bukin 	case ptev_async_vmcs:
155574fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_async_vmcs(decoder, block, ev);
155674fe6c29SRuslan Bukin 		if (status <= 0)
155774fe6c29SRuslan Bukin 			return status;
155874fe6c29SRuslan Bukin 
155974fe6c29SRuslan Bukin 		break;
156074fe6c29SRuslan Bukin 
156174fe6c29SRuslan Bukin 	case ptev_overflow:
156274fe6c29SRuslan Bukin 		break;
156374fe6c29SRuslan Bukin 
156474fe6c29SRuslan Bukin 	case ptev_exec_mode:
156574fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_exec_mode(decoder, block, ev);
156674fe6c29SRuslan Bukin 		if (status <= 0)
156774fe6c29SRuslan Bukin 			return status;
156874fe6c29SRuslan Bukin 
156974fe6c29SRuslan Bukin 		break;
157074fe6c29SRuslan Bukin 
157174fe6c29SRuslan Bukin 	case ptev_tsx:
157274fe6c29SRuslan Bukin 		if (ev->ip_suppressed)
157374fe6c29SRuslan Bukin 			break;
157474fe6c29SRuslan Bukin 
157574fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_ip(decoder, block, &insn, &iext,
157674fe6c29SRuslan Bukin 					      ev->variant.tsx.ip);
157774fe6c29SRuslan Bukin 		if (status <= 0)
157874fe6c29SRuslan Bukin 			return status;
157974fe6c29SRuslan Bukin 
158074fe6c29SRuslan Bukin 		break;
158174fe6c29SRuslan Bukin 
158274fe6c29SRuslan Bukin 	case ptev_stop:
158374fe6c29SRuslan Bukin 		break;
158474fe6c29SRuslan Bukin 
158574fe6c29SRuslan Bukin 	case ptev_exstop:
158674fe6c29SRuslan Bukin 		if (!decoder->enabled || ev->ip_suppressed)
158774fe6c29SRuslan Bukin 			break;
158874fe6c29SRuslan Bukin 
158974fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_ip(decoder, block, &insn, &iext,
159074fe6c29SRuslan Bukin 					      ev->variant.exstop.ip);
159174fe6c29SRuslan Bukin 		if (status <= 0)
159274fe6c29SRuslan Bukin 			return status;
159374fe6c29SRuslan Bukin 
159474fe6c29SRuslan Bukin 		break;
159574fe6c29SRuslan Bukin 
159674fe6c29SRuslan Bukin 	case ptev_mwait:
159774fe6c29SRuslan Bukin 		if (!decoder->enabled || ev->ip_suppressed)
159874fe6c29SRuslan Bukin 			break;
159974fe6c29SRuslan Bukin 
160074fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_ip(decoder, block, &insn, &iext,
160174fe6c29SRuslan Bukin 					      ev->variant.mwait.ip);
160274fe6c29SRuslan Bukin 		if (status <= 0)
160374fe6c29SRuslan Bukin 			return status;
160474fe6c29SRuslan Bukin 
160574fe6c29SRuslan Bukin 		break;
160674fe6c29SRuslan Bukin 
160774fe6c29SRuslan Bukin 	case ptev_pwre:
160874fe6c29SRuslan Bukin 	case ptev_pwrx:
160974fe6c29SRuslan Bukin 		break;
161074fe6c29SRuslan Bukin 
161174fe6c29SRuslan Bukin 	case ptev_ptwrite:
161274fe6c29SRuslan Bukin 		if (!decoder->enabled)
161374fe6c29SRuslan Bukin 			break;
161474fe6c29SRuslan Bukin 
161574fe6c29SRuslan Bukin 		status = pt_blk_proceed_to_ptwrite(decoder, block, &insn,
161674fe6c29SRuslan Bukin 						   &iext, ev);
161774fe6c29SRuslan Bukin 		if (status <= 0)
161874fe6c29SRuslan Bukin 			return status;
161974fe6c29SRuslan Bukin 
162074fe6c29SRuslan Bukin 		/* We bound a ptwrite event.  Make sure we do not bind further
162174fe6c29SRuslan Bukin 		 * ptwrite events to this instruction.
162274fe6c29SRuslan Bukin 		 */
162374fe6c29SRuslan Bukin 		decoder->bound_ptwrite = 1;
162474fe6c29SRuslan Bukin 
162574fe6c29SRuslan Bukin 		return pt_blk_postpone_insn(decoder, &insn, &iext);
162674fe6c29SRuslan Bukin 
162774fe6c29SRuslan Bukin 	case ptev_tick:
162874fe6c29SRuslan Bukin 	case ptev_cbr:
162974fe6c29SRuslan Bukin 	case ptev_mnt:
163074fe6c29SRuslan Bukin 		break;
163174fe6c29SRuslan Bukin 	}
163274fe6c29SRuslan Bukin 
163374fe6c29SRuslan Bukin 	return pt_blk_status(decoder, pts_event_pending);
163474fe6c29SRuslan Bukin }
163574fe6c29SRuslan Bukin 
163674fe6c29SRuslan Bukin /* Proceed to the next decision point without using the block cache.
163774fe6c29SRuslan Bukin  *
163874fe6c29SRuslan Bukin  * Tracing is enabled and we don't have an event pending.  Proceed as far as
163974fe6c29SRuslan Bukin  * we get without trace.  Stop when we either:
164074fe6c29SRuslan Bukin  *
164174fe6c29SRuslan Bukin  *   - need trace in order to continue
164274fe6c29SRuslan Bukin  *   - overflow the max number of instructions in a block
164374fe6c29SRuslan Bukin  *
164474fe6c29SRuslan Bukin  * We actually proceed one instruction further to get the start IP for the next
164574fe6c29SRuslan Bukin  * block.  This only updates @decoder's internal state, though.
164674fe6c29SRuslan Bukin  *
164774fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
164874fe6c29SRuslan Bukin  */
164974fe6c29SRuslan Bukin static int pt_blk_proceed_no_event_uncached(struct pt_block_decoder *decoder,
165074fe6c29SRuslan Bukin 					    struct pt_block *block)
165174fe6c29SRuslan Bukin {
165274fe6c29SRuslan Bukin 	struct pt_insn_ext iext;
165374fe6c29SRuslan Bukin 	struct pt_insn insn;
165474fe6c29SRuslan Bukin 	int status;
165574fe6c29SRuslan Bukin 
165674fe6c29SRuslan Bukin 	if (!decoder || !block)
165774fe6c29SRuslan Bukin 		return -pte_internal;
165874fe6c29SRuslan Bukin 
165974fe6c29SRuslan Bukin 	/* This is overly conservative, really.  We shouldn't get a bad-query
166074fe6c29SRuslan Bukin 	 * status unless we decoded at least one instruction successfully.
166174fe6c29SRuslan Bukin 	 */
166274fe6c29SRuslan Bukin 	memset(&insn, 0, sizeof(insn));
166374fe6c29SRuslan Bukin 	memset(&iext, 0, sizeof(iext));
166474fe6c29SRuslan Bukin 
166574fe6c29SRuslan Bukin 	/* Proceed as far as we get without trace. */
166674fe6c29SRuslan Bukin 	status = pt_blk_proceed_to_insn(decoder, block, &insn, &iext,
166774fe6c29SRuslan Bukin 					pt_insn_false);
166874fe6c29SRuslan Bukin 	if (status < 0) {
166974fe6c29SRuslan Bukin 		if (status != -pte_bad_query)
167074fe6c29SRuslan Bukin 			return status;
167174fe6c29SRuslan Bukin 
167274fe6c29SRuslan Bukin 		return pt_blk_proceed_with_trace(decoder, &insn, &iext);
167374fe6c29SRuslan Bukin 	}
167474fe6c29SRuslan Bukin 
167574fe6c29SRuslan Bukin 	return 0;
167674fe6c29SRuslan Bukin }
167774fe6c29SRuslan Bukin 
167874fe6c29SRuslan Bukin /* Check if @ip is contained in @section loaded at @laddr.
167974fe6c29SRuslan Bukin  *
168074fe6c29SRuslan Bukin  * Returns non-zero if it is.
168174fe6c29SRuslan Bukin  * Returns zero if it isn't or of @section is NULL.
168274fe6c29SRuslan Bukin  */
168374fe6c29SRuslan Bukin static inline int pt_blk_is_in_section(const struct pt_mapped_section *msec,
168474fe6c29SRuslan Bukin 				       uint64_t ip)
168574fe6c29SRuslan Bukin {
168674fe6c29SRuslan Bukin 	uint64_t begin, end;
168774fe6c29SRuslan Bukin 
168874fe6c29SRuslan Bukin 	begin = pt_msec_begin(msec);
168974fe6c29SRuslan Bukin 	end = pt_msec_end(msec);
169074fe6c29SRuslan Bukin 
169174fe6c29SRuslan Bukin 	return (begin <= ip && ip < end);
169274fe6c29SRuslan Bukin }
169374fe6c29SRuslan Bukin 
169474fe6c29SRuslan Bukin /* Insert a trampoline block cache entry.
169574fe6c29SRuslan Bukin  *
169674fe6c29SRuslan Bukin  * Add a trampoline block cache entry at @ip to continue at @nip, where @nip
169774fe6c29SRuslan Bukin  * must be the next instruction after @ip.
169874fe6c29SRuslan Bukin  *
169974fe6c29SRuslan Bukin  * Both @ip and @nip must be section-relative
170074fe6c29SRuslan Bukin  *
170174fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
170274fe6c29SRuslan Bukin  */
170374fe6c29SRuslan Bukin static inline int pt_blk_add_trampoline(struct pt_block_cache *bcache,
170474fe6c29SRuslan Bukin 					uint64_t ip, uint64_t nip,
170574fe6c29SRuslan Bukin 					enum pt_exec_mode mode)
170674fe6c29SRuslan Bukin {
170774fe6c29SRuslan Bukin 	struct pt_bcache_entry bce;
170874fe6c29SRuslan Bukin 	int64_t disp;
170974fe6c29SRuslan Bukin 
171074fe6c29SRuslan Bukin 	/* The displacement from @ip to @nip for the trampoline. */
171174fe6c29SRuslan Bukin 	disp = (int64_t) (nip - ip);
171274fe6c29SRuslan Bukin 
171374fe6c29SRuslan Bukin 	memset(&bce, 0, sizeof(bce));
171474fe6c29SRuslan Bukin 	bce.displacement = (int32_t) disp;
171574fe6c29SRuslan Bukin 	bce.ninsn = 1;
171674fe6c29SRuslan Bukin 	bce.mode = mode;
171774fe6c29SRuslan Bukin 	bce.qualifier = ptbq_again;
171874fe6c29SRuslan Bukin 
171974fe6c29SRuslan Bukin 	/* If we can't reach @nip without overflowing the displacement field, we
172074fe6c29SRuslan Bukin 	 * have to stop and re-decode the instruction at @ip.
172174fe6c29SRuslan Bukin 	 */
172274fe6c29SRuslan Bukin 	if ((int64_t) bce.displacement != disp) {
172374fe6c29SRuslan Bukin 
172474fe6c29SRuslan Bukin 		memset(&bce, 0, sizeof(bce));
172574fe6c29SRuslan Bukin 		bce.ninsn = 1;
172674fe6c29SRuslan Bukin 		bce.mode = mode;
172774fe6c29SRuslan Bukin 		bce.qualifier = ptbq_decode;
172874fe6c29SRuslan Bukin 	}
172974fe6c29SRuslan Bukin 
173074fe6c29SRuslan Bukin 	return pt_bcache_add(bcache, ip, bce);
173174fe6c29SRuslan Bukin }
173274fe6c29SRuslan Bukin 
173374fe6c29SRuslan Bukin /* Insert a decode block cache entry.
173474fe6c29SRuslan Bukin  *
173574fe6c29SRuslan Bukin  * Add a decode block cache entry at @ioff.
173674fe6c29SRuslan Bukin  *
173774fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
173874fe6c29SRuslan Bukin  */
173974fe6c29SRuslan Bukin static inline int pt_blk_add_decode(struct pt_block_cache *bcache,
174074fe6c29SRuslan Bukin 				    uint64_t ioff, enum pt_exec_mode mode)
174174fe6c29SRuslan Bukin {
174274fe6c29SRuslan Bukin 	struct pt_bcache_entry bce;
174374fe6c29SRuslan Bukin 
174474fe6c29SRuslan Bukin 	memset(&bce, 0, sizeof(bce));
174574fe6c29SRuslan Bukin 	bce.ninsn = 1;
174674fe6c29SRuslan Bukin 	bce.mode = mode;
174774fe6c29SRuslan Bukin 	bce.qualifier = ptbq_decode;
174874fe6c29SRuslan Bukin 
174974fe6c29SRuslan Bukin 	return pt_bcache_add(bcache, ioff, bce);
175074fe6c29SRuslan Bukin }
175174fe6c29SRuslan Bukin 
175274fe6c29SRuslan Bukin enum {
175374fe6c29SRuslan Bukin 	/* The maximum number of steps when filling the block cache. */
175474fe6c29SRuslan Bukin 	bcache_fill_steps	= 0x400
175574fe6c29SRuslan Bukin };
175674fe6c29SRuslan Bukin 
175774fe6c29SRuslan Bukin /* Proceed to the next instruction and fill the block cache for @decoder->ip.
175874fe6c29SRuslan Bukin  *
175974fe6c29SRuslan Bukin  * Tracing is enabled and we don't have an event pending.  The current IP is not
176074fe6c29SRuslan Bukin  * yet cached.
176174fe6c29SRuslan Bukin  *
176274fe6c29SRuslan Bukin  * Proceed one instruction without using the block cache, then try to proceed
176374fe6c29SRuslan Bukin  * further using the block cache.
176474fe6c29SRuslan Bukin  *
176574fe6c29SRuslan Bukin  * On our way back, add a block cache entry for the IP before proceeding.  Note
176674fe6c29SRuslan Bukin  * that the recursion is bounded by @steps and ultimately by the maximum number
176774fe6c29SRuslan Bukin  * of instructions in a block.
176874fe6c29SRuslan Bukin  *
176974fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
177074fe6c29SRuslan Bukin  */
177174fe6c29SRuslan Bukin static int
177274fe6c29SRuslan Bukin pt_blk_proceed_no_event_fill_cache(struct pt_block_decoder *decoder,
177374fe6c29SRuslan Bukin 				   struct pt_block *block,
177474fe6c29SRuslan Bukin 				   struct pt_block_cache *bcache,
177574fe6c29SRuslan Bukin 				   const struct pt_mapped_section *msec,
177674fe6c29SRuslan Bukin 				   size_t steps)
177774fe6c29SRuslan Bukin {
177874fe6c29SRuslan Bukin 	struct pt_bcache_entry bce;
177974fe6c29SRuslan Bukin 	struct pt_insn_ext iext;
178074fe6c29SRuslan Bukin 	struct pt_insn insn;
178174fe6c29SRuslan Bukin 	uint64_t nip, dip;
178274fe6c29SRuslan Bukin 	int64_t disp, ioff, noff;
178374fe6c29SRuslan Bukin 	int status;
178474fe6c29SRuslan Bukin 
178574fe6c29SRuslan Bukin 	if (!decoder || !steps)
178674fe6c29SRuslan Bukin 		return -pte_internal;
178774fe6c29SRuslan Bukin 
178874fe6c29SRuslan Bukin 	/* Proceed one instruction by decoding and examining it.
178974fe6c29SRuslan Bukin 	 *
179074fe6c29SRuslan Bukin 	 * Note that we also return on a status of zero that indicates that the
179174fe6c29SRuslan Bukin 	 * instruction didn't fit into @block.
179274fe6c29SRuslan Bukin 	 */
179374fe6c29SRuslan Bukin 	status = pt_blk_proceed_one_insn(decoder, block, &insn, &iext);
179474fe6c29SRuslan Bukin 	if (status <= 0)
179574fe6c29SRuslan Bukin 		return status;
179674fe6c29SRuslan Bukin 
179774fe6c29SRuslan Bukin 	ioff = pt_msec_unmap(msec, insn.ip);
179874fe6c29SRuslan Bukin 
179974fe6c29SRuslan Bukin 	/* Let's see if we can proceed to the next IP without trace.
180074fe6c29SRuslan Bukin 	 *
180174fe6c29SRuslan Bukin 	 * If we can't, this is certainly a decision point.
180274fe6c29SRuslan Bukin 	 */
180374fe6c29SRuslan Bukin 	status = pt_insn_next_ip(&decoder->ip, &insn, &iext);
180474fe6c29SRuslan Bukin 	if (status < 0) {
180574fe6c29SRuslan Bukin 		if (status != -pte_bad_query)
180674fe6c29SRuslan Bukin 			return status;
180774fe6c29SRuslan Bukin 
180874fe6c29SRuslan Bukin 		memset(&bce, 0, sizeof(bce));
180974fe6c29SRuslan Bukin 		bce.ninsn = 1;
181074fe6c29SRuslan Bukin 		bce.mode = insn.mode;
181174fe6c29SRuslan Bukin 		bce.isize = insn.size;
181274fe6c29SRuslan Bukin 
181374fe6c29SRuslan Bukin 		/* Clear the instruction size in case of overflows. */
181474fe6c29SRuslan Bukin 		if ((uint8_t) bce.isize != insn.size)
181574fe6c29SRuslan Bukin 			bce.isize = 0;
181674fe6c29SRuslan Bukin 
181774fe6c29SRuslan Bukin 		switch (insn.iclass) {
181874fe6c29SRuslan Bukin 		case ptic_ptwrite:
181974fe6c29SRuslan Bukin 		case ptic_error:
182074fe6c29SRuslan Bukin 		case ptic_other:
182174fe6c29SRuslan Bukin 			return -pte_internal;
182274fe6c29SRuslan Bukin 
182374fe6c29SRuslan Bukin 		case ptic_jump:
182474fe6c29SRuslan Bukin 			/* A direct jump doesn't require trace. */
182574fe6c29SRuslan Bukin 			if (iext.variant.branch.is_direct)
182674fe6c29SRuslan Bukin 				return -pte_internal;
182774fe6c29SRuslan Bukin 
182874fe6c29SRuslan Bukin 			bce.qualifier = ptbq_indirect;
182974fe6c29SRuslan Bukin 			break;
183074fe6c29SRuslan Bukin 
183174fe6c29SRuslan Bukin 		case ptic_call:
183274fe6c29SRuslan Bukin 			/* A direct call doesn't require trace. */
183374fe6c29SRuslan Bukin 			if (iext.variant.branch.is_direct)
183474fe6c29SRuslan Bukin 				return -pte_internal;
183574fe6c29SRuslan Bukin 
183674fe6c29SRuslan Bukin 			bce.qualifier = ptbq_ind_call;
183774fe6c29SRuslan Bukin 			break;
183874fe6c29SRuslan Bukin 
183974fe6c29SRuslan Bukin 		case ptic_return:
184074fe6c29SRuslan Bukin 			bce.qualifier = ptbq_return;
184174fe6c29SRuslan Bukin 			break;
184274fe6c29SRuslan Bukin 
184374fe6c29SRuslan Bukin 		case ptic_cond_jump:
184474fe6c29SRuslan Bukin 			bce.qualifier = ptbq_cond;
184574fe6c29SRuslan Bukin 			break;
184674fe6c29SRuslan Bukin 
184774fe6c29SRuslan Bukin 		case ptic_far_call:
184874fe6c29SRuslan Bukin 		case ptic_far_return:
184974fe6c29SRuslan Bukin 		case ptic_far_jump:
185074fe6c29SRuslan Bukin 			bce.qualifier = ptbq_indirect;
185174fe6c29SRuslan Bukin 			break;
185274fe6c29SRuslan Bukin 		}
185374fe6c29SRuslan Bukin 
185474fe6c29SRuslan Bukin 		/* If the block was truncated, we have to decode its last
185574fe6c29SRuslan Bukin 		 * instruction each time.
185674fe6c29SRuslan Bukin 		 *
185774fe6c29SRuslan Bukin 		 * We could have skipped the above switch and size assignment in
185874fe6c29SRuslan Bukin 		 * this case but this is already a slow and hopefully infrequent
185974fe6c29SRuslan Bukin 		 * path.
186074fe6c29SRuslan Bukin 		 */
186174fe6c29SRuslan Bukin 		if (block->truncated)
186274fe6c29SRuslan Bukin 			bce.qualifier = ptbq_decode;
186374fe6c29SRuslan Bukin 
186474fe6c29SRuslan Bukin 		status = pt_bcache_add(bcache, ioff, bce);
186574fe6c29SRuslan Bukin 		if (status < 0)
186674fe6c29SRuslan Bukin 			return status;
186774fe6c29SRuslan Bukin 
186874fe6c29SRuslan Bukin 		return pt_blk_proceed_with_trace(decoder, &insn, &iext);
186974fe6c29SRuslan Bukin 	}
187074fe6c29SRuslan Bukin 
187174fe6c29SRuslan Bukin 	/* The next instruction's IP. */
187274fe6c29SRuslan Bukin 	nip = decoder->ip;
187374fe6c29SRuslan Bukin 	noff = pt_msec_unmap(msec, nip);
187474fe6c29SRuslan Bukin 
187574fe6c29SRuslan Bukin 	/* Even if we were able to proceed without trace, we might have to stop
187674fe6c29SRuslan Bukin 	 * here for various reasons:
187774fe6c29SRuslan Bukin 	 *
187874fe6c29SRuslan Bukin 	 *   - at near direct calls to update the return-address stack
187974fe6c29SRuslan Bukin 	 *
188074fe6c29SRuslan Bukin 	 *     We are forced to re-decode @insn to get the branch displacement.
188174fe6c29SRuslan Bukin 	 *
188274fe6c29SRuslan Bukin 	 *     Even though it is constant, we don't cache it to avoid increasing
188374fe6c29SRuslan Bukin 	 *     the size of a cache entry.  Note that the displacement field is
188474fe6c29SRuslan Bukin 	 *     zero for this entry and we might be tempted to use it - but other
188574fe6c29SRuslan Bukin 	 *     entries that point to this decision point will have non-zero
188674fe6c29SRuslan Bukin 	 *     displacement.
188774fe6c29SRuslan Bukin 	 *
188874fe6c29SRuslan Bukin 	 *     We could proceed after a near direct call but we migh as well
188974fe6c29SRuslan Bukin 	 *     postpone it to the next iteration.  Make sure to end the block if
189074fe6c29SRuslan Bukin 	 *     @decoder->flags.variant.block.end_on_call is set, though.
189174fe6c29SRuslan Bukin 	 *
189274fe6c29SRuslan Bukin 	 *   - at near direct backwards jumps to detect section splits
189374fe6c29SRuslan Bukin 	 *
189474fe6c29SRuslan Bukin 	 *     In case the current section is split underneath us, we must take
189574fe6c29SRuslan Bukin 	 *     care to detect that split.
189674fe6c29SRuslan Bukin 	 *
189774fe6c29SRuslan Bukin 	 *     There is one corner case where the split is in the middle of a
189874fe6c29SRuslan Bukin 	 *     linear sequence of instructions that branches back into the
189974fe6c29SRuslan Bukin 	 *     originating section.
190074fe6c29SRuslan Bukin 	 *
190174fe6c29SRuslan Bukin 	 *     Calls, indirect branches, and far branches are already covered
190274fe6c29SRuslan Bukin 	 *     since they either require trace or already require us to stop
190374fe6c29SRuslan Bukin 	 *     (i.e. near direct calls) for other reasons.  That leaves near
190474fe6c29SRuslan Bukin 	 *     direct backward jumps.
190574fe6c29SRuslan Bukin 	 *
190674fe6c29SRuslan Bukin 	 *     Instead of the decode stop at the jump instruction we're using we
190774fe6c29SRuslan Bukin 	 *     could have made sure that other block cache entries that extend
190874fe6c29SRuslan Bukin 	 *     this one insert a trampoline to the jump's entry.  This would
190974fe6c29SRuslan Bukin 	 *     have been a bit more complicated.
191074fe6c29SRuslan Bukin 	 *
191174fe6c29SRuslan Bukin 	 *   - if we switched sections
191274fe6c29SRuslan Bukin 	 *
191374fe6c29SRuslan Bukin 	 *     This ends a block just like a branch that requires trace.
191474fe6c29SRuslan Bukin 	 *
191574fe6c29SRuslan Bukin 	 *     We need to re-decode @insn in order to determine the start IP of
191674fe6c29SRuslan Bukin 	 *     the next block.
191774fe6c29SRuslan Bukin 	 *
191874fe6c29SRuslan Bukin 	 *   - if the block is truncated
191974fe6c29SRuslan Bukin 	 *
192074fe6c29SRuslan Bukin 	 *     We need to read the last instruction's memory from multiple
192174fe6c29SRuslan Bukin 	 *     sections and provide it to the user.
192274fe6c29SRuslan Bukin 	 *
192374fe6c29SRuslan Bukin 	 *     We could still use the block cache but then we'd have to handle
192474fe6c29SRuslan Bukin 	 *     this case for each qualifier.  Truncation is hopefully rare and
192574fe6c29SRuslan Bukin 	 *     having to read the memory for the instruction from multiple
192674fe6c29SRuslan Bukin 	 *     sections is already slow.  Let's rather keep things simple and
192774fe6c29SRuslan Bukin 	 *     route it through the decode flow, where we already have
192874fe6c29SRuslan Bukin 	 *     everything in place.
192974fe6c29SRuslan Bukin 	 */
193074fe6c29SRuslan Bukin 	switch (insn.iclass) {
193174fe6c29SRuslan Bukin 	case ptic_call:
193274fe6c29SRuslan Bukin 		return pt_blk_add_decode(bcache, ioff, insn.mode);
193374fe6c29SRuslan Bukin 
193474fe6c29SRuslan Bukin 	case ptic_jump:
193574fe6c29SRuslan Bukin 		/* An indirect branch requires trace and should have been
193674fe6c29SRuslan Bukin 		 * handled above.
193774fe6c29SRuslan Bukin 		 */
193874fe6c29SRuslan Bukin 		if (!iext.variant.branch.is_direct)
193974fe6c29SRuslan Bukin 			return -pte_internal;
194074fe6c29SRuslan Bukin 
194174fe6c29SRuslan Bukin 		if (iext.variant.branch.displacement < 0 ||
194274fe6c29SRuslan Bukin 		    decoder->flags.variant.block.end_on_jump)
194374fe6c29SRuslan Bukin 			return pt_blk_add_decode(bcache, ioff, insn.mode);
194474fe6c29SRuslan Bukin 
194574fe6c29SRuslan Bukin 		fallthrough;
194674fe6c29SRuslan Bukin 	default:
194774fe6c29SRuslan Bukin 		if (!pt_blk_is_in_section(msec, nip) || block->truncated)
194874fe6c29SRuslan Bukin 			return pt_blk_add_decode(bcache, ioff, insn.mode);
194974fe6c29SRuslan Bukin 
195074fe6c29SRuslan Bukin 		break;
195174fe6c29SRuslan Bukin 	}
195274fe6c29SRuslan Bukin 
195374fe6c29SRuslan Bukin 	/* We proceeded one instruction.  Let's see if we have a cache entry for
195474fe6c29SRuslan Bukin 	 * the next instruction.
195574fe6c29SRuslan Bukin 	 */
195674fe6c29SRuslan Bukin 	status = pt_bcache_lookup(&bce, bcache, noff);
195774fe6c29SRuslan Bukin 	if (status < 0)
195874fe6c29SRuslan Bukin 		return status;
195974fe6c29SRuslan Bukin 
196074fe6c29SRuslan Bukin 	/* If we don't have a valid cache entry, yet, fill the cache some more.
196174fe6c29SRuslan Bukin 	 *
196274fe6c29SRuslan Bukin 	 * On our way back, we add a cache entry for this instruction based on
196374fe6c29SRuslan Bukin 	 * the cache entry of the succeeding instruction.
196474fe6c29SRuslan Bukin 	 */
196574fe6c29SRuslan Bukin 	if (!pt_bce_is_valid(bce)) {
196674fe6c29SRuslan Bukin 		/* If we exceeded the maximum number of allowed steps, we insert
196774fe6c29SRuslan Bukin 		 * a trampoline to the next instruction.
196874fe6c29SRuslan Bukin 		 *
196974fe6c29SRuslan Bukin 		 * The next time we encounter the same code, we will use the
197074fe6c29SRuslan Bukin 		 * trampoline to jump directly to where we left off this time
197174fe6c29SRuslan Bukin 		 * and continue from there.
197274fe6c29SRuslan Bukin 		 */
197374fe6c29SRuslan Bukin 		steps -= 1;
197474fe6c29SRuslan Bukin 		if (!steps)
197574fe6c29SRuslan Bukin 			return pt_blk_add_trampoline(bcache, ioff, noff,
197674fe6c29SRuslan Bukin 						     insn.mode);
197774fe6c29SRuslan Bukin 
197874fe6c29SRuslan Bukin 		status = pt_blk_proceed_no_event_fill_cache(decoder, block,
197974fe6c29SRuslan Bukin 							    bcache, msec,
198074fe6c29SRuslan Bukin 							    steps);
198174fe6c29SRuslan Bukin 		if (status < 0)
198274fe6c29SRuslan Bukin 			return status;
198374fe6c29SRuslan Bukin 
198474fe6c29SRuslan Bukin 		/* Let's see if we have more luck this time. */
198574fe6c29SRuslan Bukin 		status = pt_bcache_lookup(&bce, bcache, noff);
198674fe6c29SRuslan Bukin 		if (status < 0)
198774fe6c29SRuslan Bukin 			return status;
198874fe6c29SRuslan Bukin 
198974fe6c29SRuslan Bukin 		/* If we still don't have a valid cache entry, we're done.  Most
199074fe6c29SRuslan Bukin 		 * likely, @block overflowed and we couldn't proceed past the
199174fe6c29SRuslan Bukin 		 * next instruction.
199274fe6c29SRuslan Bukin 		 */
199374fe6c29SRuslan Bukin 		if (!pt_bce_is_valid(bce))
199474fe6c29SRuslan Bukin 			return 0;
199574fe6c29SRuslan Bukin 	}
199674fe6c29SRuslan Bukin 
199774fe6c29SRuslan Bukin 	/* We must not have switched execution modes.
199874fe6c29SRuslan Bukin 	 *
199974fe6c29SRuslan Bukin 	 * This would require an event and we're on the no-event flow.
200074fe6c29SRuslan Bukin 	 */
200174fe6c29SRuslan Bukin 	if (pt_bce_exec_mode(bce) != insn.mode)
200274fe6c29SRuslan Bukin 		return -pte_internal;
200374fe6c29SRuslan Bukin 
200474fe6c29SRuslan Bukin 	/* The decision point IP and the displacement from @insn.ip. */
200574fe6c29SRuslan Bukin 	dip = nip + bce.displacement;
200674fe6c29SRuslan Bukin 	disp = (int64_t) (dip - insn.ip);
200774fe6c29SRuslan Bukin 
200874fe6c29SRuslan Bukin 	/* We may have switched sections if the section was split.  See
200974fe6c29SRuslan Bukin 	 * pt_blk_proceed_no_event_cached() for a more elaborate comment.
201074fe6c29SRuslan Bukin 	 *
201174fe6c29SRuslan Bukin 	 * We're not adding a block cache entry since this won't apply to the
201274fe6c29SRuslan Bukin 	 * original section which may be shared with other decoders.
201374fe6c29SRuslan Bukin 	 *
201474fe6c29SRuslan Bukin 	 * We will instead take the slow path until the end of the section.
201574fe6c29SRuslan Bukin 	 */
201674fe6c29SRuslan Bukin 	if (!pt_blk_is_in_section(msec, dip))
201774fe6c29SRuslan Bukin 		return 0;
201874fe6c29SRuslan Bukin 
201974fe6c29SRuslan Bukin 	/* Let's try to reach @nip's decision point from @insn.ip.
202074fe6c29SRuslan Bukin 	 *
202174fe6c29SRuslan Bukin 	 * There are two fields that may overflow: @bce.ninsn and
202274fe6c29SRuslan Bukin 	 * @bce.displacement.
202374fe6c29SRuslan Bukin 	 */
202474fe6c29SRuslan Bukin 	bce.ninsn += 1;
202574fe6c29SRuslan Bukin 	bce.displacement = (int32_t) disp;
202674fe6c29SRuslan Bukin 
202774fe6c29SRuslan Bukin 	/* If none of them overflowed, we're done.
202874fe6c29SRuslan Bukin 	 *
202974fe6c29SRuslan Bukin 	 * If one or both overflowed, let's try to insert a trampoline, i.e. we
203074fe6c29SRuslan Bukin 	 * try to reach @dip via a ptbq_again entry to @nip.
203174fe6c29SRuslan Bukin 	 */
203274fe6c29SRuslan Bukin 	if (!bce.ninsn || ((int64_t) bce.displacement != disp))
203374fe6c29SRuslan Bukin 		return pt_blk_add_trampoline(bcache, ioff, noff, insn.mode);
203474fe6c29SRuslan Bukin 
203574fe6c29SRuslan Bukin 	/* We're done.  Add the cache entry.
203674fe6c29SRuslan Bukin 	 *
203774fe6c29SRuslan Bukin 	 * There's a chance that other decoders updated the cache entry in the
203874fe6c29SRuslan Bukin 	 * meantime.  They should have come to the same conclusion as we,
203974fe6c29SRuslan Bukin 	 * though, and the cache entries should be identical.
204074fe6c29SRuslan Bukin 	 *
204174fe6c29SRuslan Bukin 	 * Cache updates are atomic so even if the two versions were not
204274fe6c29SRuslan Bukin 	 * identical, we wouldn't care because they are both correct.
204374fe6c29SRuslan Bukin 	 */
204474fe6c29SRuslan Bukin 	return pt_bcache_add(bcache, ioff, bce);
204574fe6c29SRuslan Bukin }
204674fe6c29SRuslan Bukin 
204774fe6c29SRuslan Bukin /* Proceed at a potentially truncated instruction.
204874fe6c29SRuslan Bukin  *
204974fe6c29SRuslan Bukin  * We were not able to decode the instruction at @decoder->ip in @decoder's
205074fe6c29SRuslan Bukin  * cached section.  This is typically caused by not having enough bytes.
205174fe6c29SRuslan Bukin  *
205274fe6c29SRuslan Bukin  * Try to decode the instruction again using the entire image.  If this succeeds
205374fe6c29SRuslan Bukin  * we expect to end up with an instruction that was truncated in the section it
205474fe6c29SRuslan Bukin  * started.  We provide the full instruction in this case and end the block.
205574fe6c29SRuslan Bukin  *
205674fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
205774fe6c29SRuslan Bukin  */
205874fe6c29SRuslan Bukin static int pt_blk_proceed_truncated(struct pt_block_decoder *decoder,
205974fe6c29SRuslan Bukin 				    struct pt_block *block)
206074fe6c29SRuslan Bukin {
206174fe6c29SRuslan Bukin 	struct pt_insn_ext iext;
206274fe6c29SRuslan Bukin 	struct pt_insn insn;
206374fe6c29SRuslan Bukin 	int errcode;
206474fe6c29SRuslan Bukin 
206574fe6c29SRuslan Bukin 	if (!decoder || !block)
206674fe6c29SRuslan Bukin 		return -pte_internal;
206774fe6c29SRuslan Bukin 
206874fe6c29SRuslan Bukin 	memset(&iext, 0, sizeof(iext));
206974fe6c29SRuslan Bukin 	memset(&insn, 0, sizeof(insn));
207074fe6c29SRuslan Bukin 
207174fe6c29SRuslan Bukin 	insn.mode = decoder->mode;
207274fe6c29SRuslan Bukin 	insn.ip = decoder->ip;
207374fe6c29SRuslan Bukin 
207474fe6c29SRuslan Bukin 	errcode = pt_insn_decode(&insn, &iext, decoder->image, &decoder->asid);
207574fe6c29SRuslan Bukin 	if (errcode < 0)
207674fe6c29SRuslan Bukin 		return errcode;
207774fe6c29SRuslan Bukin 
207874fe6c29SRuslan Bukin 	/* We shouldn't use this function if the instruction isn't truncated. */
207974fe6c29SRuslan Bukin 	if (!insn.truncated)
208074fe6c29SRuslan Bukin 		return -pte_internal;
208174fe6c29SRuslan Bukin 
208274fe6c29SRuslan Bukin 	/* Provide the instruction in the block.  This ends the block. */
208374fe6c29SRuslan Bukin 	memcpy(block->raw, insn.raw, insn.size);
208474fe6c29SRuslan Bukin 	block->iclass = insn.iclass;
208574fe6c29SRuslan Bukin 	block->size = insn.size;
208674fe6c29SRuslan Bukin 	block->truncated = 1;
208774fe6c29SRuslan Bukin 
208874fe6c29SRuslan Bukin 	/* Log calls' return addresses for return compression. */
208974fe6c29SRuslan Bukin 	errcode = pt_blk_log_call(decoder, &insn, &iext);
209074fe6c29SRuslan Bukin 	if (errcode < 0)
209174fe6c29SRuslan Bukin 		return errcode;
209274fe6c29SRuslan Bukin 
209374fe6c29SRuslan Bukin 	/* Let's see if we can proceed to the next IP without trace.
209474fe6c29SRuslan Bukin 	 *
209574fe6c29SRuslan Bukin 	 * The truncated instruction ends the block but we still need to get the
209674fe6c29SRuslan Bukin 	 * next block's start IP.
209774fe6c29SRuslan Bukin 	 */
209874fe6c29SRuslan Bukin 	errcode = pt_insn_next_ip(&decoder->ip, &insn, &iext);
209974fe6c29SRuslan Bukin 	if (errcode < 0) {
210074fe6c29SRuslan Bukin 		if (errcode != -pte_bad_query)
210174fe6c29SRuslan Bukin 			return errcode;
210274fe6c29SRuslan Bukin 
210374fe6c29SRuslan Bukin 		return pt_blk_proceed_with_trace(decoder, &insn, &iext);
210474fe6c29SRuslan Bukin 	}
210574fe6c29SRuslan Bukin 
210674fe6c29SRuslan Bukin 	return 0;
210774fe6c29SRuslan Bukin }
210874fe6c29SRuslan Bukin 
210974fe6c29SRuslan Bukin /* Proceed to the next decision point using the block cache.
211074fe6c29SRuslan Bukin  *
211174fe6c29SRuslan Bukin  * Tracing is enabled and we don't have an event pending.  We already set
211274fe6c29SRuslan Bukin  * @block's isid.  All reads are done within @msec as we're not switching
211374fe6c29SRuslan Bukin  * sections between blocks.
211474fe6c29SRuslan Bukin  *
211574fe6c29SRuslan Bukin  * Proceed as far as we get without trace.  Stop when we either:
211674fe6c29SRuslan Bukin  *
211774fe6c29SRuslan Bukin  *   - need trace in order to continue
211874fe6c29SRuslan Bukin  *   - overflow the max number of instructions in a block
211974fe6c29SRuslan Bukin  *
212074fe6c29SRuslan Bukin  * We actually proceed one instruction further to get the start IP for the next
212174fe6c29SRuslan Bukin  * block.  This only updates @decoder's internal state, though.
212274fe6c29SRuslan Bukin  *
212374fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
212474fe6c29SRuslan Bukin  */
212574fe6c29SRuslan Bukin static int pt_blk_proceed_no_event_cached(struct pt_block_decoder *decoder,
212674fe6c29SRuslan Bukin 					  struct pt_block *block,
212774fe6c29SRuslan Bukin 					  struct pt_block_cache *bcache,
212874fe6c29SRuslan Bukin 					  const struct pt_mapped_section *msec)
212974fe6c29SRuslan Bukin {
213074fe6c29SRuslan Bukin 	struct pt_bcache_entry bce;
213174fe6c29SRuslan Bukin 	uint16_t binsn, ninsn;
213274fe6c29SRuslan Bukin 	uint64_t offset, nip;
213374fe6c29SRuslan Bukin 	int status;
213474fe6c29SRuslan Bukin 
213574fe6c29SRuslan Bukin 	if (!decoder || !block)
213674fe6c29SRuslan Bukin 		return -pte_internal;
213774fe6c29SRuslan Bukin 
213874fe6c29SRuslan Bukin 	offset = pt_msec_unmap(msec, decoder->ip);
213974fe6c29SRuslan Bukin 	status = pt_bcache_lookup(&bce, bcache, offset);
214074fe6c29SRuslan Bukin 	if (status < 0)
214174fe6c29SRuslan Bukin 		return status;
214274fe6c29SRuslan Bukin 
214374fe6c29SRuslan Bukin 	/* If we don't find a valid cache entry, fill the cache. */
214474fe6c29SRuslan Bukin 	if (!pt_bce_is_valid(bce))
214574fe6c29SRuslan Bukin 		return pt_blk_proceed_no_event_fill_cache(decoder, block,
214674fe6c29SRuslan Bukin 							  bcache, msec,
214774fe6c29SRuslan Bukin 							  bcache_fill_steps);
214874fe6c29SRuslan Bukin 
214974fe6c29SRuslan Bukin 	/* If we switched sections, the origianl section must have been split
215074fe6c29SRuslan Bukin 	 * underneath us.  A split preserves the block cache of the original
215174fe6c29SRuslan Bukin 	 * section.
215274fe6c29SRuslan Bukin 	 *
215374fe6c29SRuslan Bukin 	 * Crossing sections requires ending the block so we can indicate the
215474fe6c29SRuslan Bukin 	 * proper isid for the entire block.
215574fe6c29SRuslan Bukin 	 *
215674fe6c29SRuslan Bukin 	 * Plus there's the chance that the new section that caused the original
215774fe6c29SRuslan Bukin 	 * section to split changed instructions.
215874fe6c29SRuslan Bukin 	 *
215974fe6c29SRuslan Bukin 	 * This check will also cover changes to a linear sequence of code we
216074fe6c29SRuslan Bukin 	 * would otherwise have jumped over as long as the start and end are in
216174fe6c29SRuslan Bukin 	 * different sub-sections.
216274fe6c29SRuslan Bukin 	 *
216374fe6c29SRuslan Bukin 	 * Since we stop on every (backwards) branch (through an artificial stop
216474fe6c29SRuslan Bukin 	 * in the case of a near direct backward branch) we will detect all
216574fe6c29SRuslan Bukin 	 * section splits.
216674fe6c29SRuslan Bukin 	 *
216774fe6c29SRuslan Bukin 	 * Switch to the slow path until we reach the end of this section.
216874fe6c29SRuslan Bukin 	 */
216974fe6c29SRuslan Bukin 	nip = decoder->ip + bce.displacement;
217074fe6c29SRuslan Bukin 	if (!pt_blk_is_in_section(msec, nip))
217174fe6c29SRuslan Bukin 		return pt_blk_proceed_no_event_uncached(decoder, block);
217274fe6c29SRuslan Bukin 
217374fe6c29SRuslan Bukin 	/* We have a valid cache entry.  Let's first check if the way to the
217474fe6c29SRuslan Bukin 	 * decision point still fits into @block.
217574fe6c29SRuslan Bukin 	 *
217674fe6c29SRuslan Bukin 	 * If it doesn't, we end the block without filling it as much as we
217774fe6c29SRuslan Bukin 	 * could since this would require us to switch to the slow path.
217874fe6c29SRuslan Bukin 	 *
217974fe6c29SRuslan Bukin 	 * On the next iteration, we will start with an empty block, which is
218074fe6c29SRuslan Bukin 	 * guaranteed to have enough room for at least one block cache entry.
218174fe6c29SRuslan Bukin 	 */
218274fe6c29SRuslan Bukin 	binsn = block->ninsn;
218374fe6c29SRuslan Bukin 	ninsn = binsn + (uint16_t) bce.ninsn;
218474fe6c29SRuslan Bukin 	if (ninsn < binsn)
218574fe6c29SRuslan Bukin 		return 0;
218674fe6c29SRuslan Bukin 
218774fe6c29SRuslan Bukin 	/* Jump ahead to the decision point and proceed from there.
218874fe6c29SRuslan Bukin 	 *
218974fe6c29SRuslan Bukin 	 * We're not switching execution modes so even if @block already has an
219074fe6c29SRuslan Bukin 	 * execution mode, it will be the one we're going to set.
219174fe6c29SRuslan Bukin 	 */
219274fe6c29SRuslan Bukin 	decoder->ip = nip;
219374fe6c29SRuslan Bukin 
219474fe6c29SRuslan Bukin 	/* We don't know the instruction class so we should be setting it to
219574fe6c29SRuslan Bukin 	 * ptic_error.  Since we will be able to fill it back in later in most
219674fe6c29SRuslan Bukin 	 * cases, we move the clearing to the switch cases that don't.
219774fe6c29SRuslan Bukin 	 */
219874fe6c29SRuslan Bukin 	block->end_ip = nip;
219974fe6c29SRuslan Bukin 	block->ninsn = ninsn;
220074fe6c29SRuslan Bukin 	block->mode = pt_bce_exec_mode(bce);
220174fe6c29SRuslan Bukin 
220274fe6c29SRuslan Bukin 
220374fe6c29SRuslan Bukin 	switch (pt_bce_qualifier(bce)) {
220474fe6c29SRuslan Bukin 	case ptbq_again:
220574fe6c29SRuslan Bukin 		/* We're not able to reach the actual decision point due to
220674fe6c29SRuslan Bukin 		 * overflows so we inserted a trampoline.
220774fe6c29SRuslan Bukin 		 *
220874fe6c29SRuslan Bukin 		 * We don't know the instruction and it is not guaranteed that
220974fe6c29SRuslan Bukin 		 * we will proceed further (e.g. if @block overflowed).  Let's
221074fe6c29SRuslan Bukin 		 * clear any previously stored instruction class which has
221174fe6c29SRuslan Bukin 		 * become invalid when we updated @block->ninsn.
221274fe6c29SRuslan Bukin 		 */
221374fe6c29SRuslan Bukin 		block->iclass = ptic_error;
221474fe6c29SRuslan Bukin 
221574fe6c29SRuslan Bukin 		return pt_blk_proceed_no_event_cached(decoder, block, bcache,
221674fe6c29SRuslan Bukin 						      msec);
221774fe6c29SRuslan Bukin 
221874fe6c29SRuslan Bukin 	case ptbq_cond:
221974fe6c29SRuslan Bukin 		/* We're at a conditional branch. */
222074fe6c29SRuslan Bukin 		block->iclass = ptic_cond_jump;
222174fe6c29SRuslan Bukin 
222274fe6c29SRuslan Bukin 		/* Let's first check whether we know the size of the
222374fe6c29SRuslan Bukin 		 * instruction.  If we do, we might get away without decoding
222474fe6c29SRuslan Bukin 		 * the instruction.
222574fe6c29SRuslan Bukin 		 *
222674fe6c29SRuslan Bukin 		 * If we don't know the size we might as well do the full decode
222774fe6c29SRuslan Bukin 		 * and proceed-with-trace flow we do for ptbq_decode.
222874fe6c29SRuslan Bukin 		 */
222974fe6c29SRuslan Bukin 		if (bce.isize) {
223074fe6c29SRuslan Bukin 			uint64_t ip;
223174fe6c29SRuslan Bukin 			int taken;
223274fe6c29SRuslan Bukin 
223374fe6c29SRuslan Bukin 			/* If the branch is not taken, we don't need to decode
223474fe6c29SRuslan Bukin 			 * the instruction at @decoder->ip.
223574fe6c29SRuslan Bukin 			 *
223674fe6c29SRuslan Bukin 			 * If it is taken, we have to implement everything here.
223774fe6c29SRuslan Bukin 			 * We can't use the normal decode and proceed-with-trace
223874fe6c29SRuslan Bukin 			 * flow since we already consumed the TNT bit.
223974fe6c29SRuslan Bukin 			 */
224074fe6c29SRuslan Bukin 			status = pt_blk_cond_branch(decoder, &taken);
224174fe6c29SRuslan Bukin 			if (status < 0)
224274fe6c29SRuslan Bukin 				return status;
224374fe6c29SRuslan Bukin 
224474fe6c29SRuslan Bukin 			/* Preserve the query decoder's response which indicates
224574fe6c29SRuslan Bukin 			 * upcoming events.
224674fe6c29SRuslan Bukin 			 */
224774fe6c29SRuslan Bukin 			decoder->status = status;
224874fe6c29SRuslan Bukin 
224974fe6c29SRuslan Bukin 			ip = decoder->ip;
225074fe6c29SRuslan Bukin 			if (taken) {
225174fe6c29SRuslan Bukin 				struct pt_insn_ext iext;
225274fe6c29SRuslan Bukin 				struct pt_insn insn;
225374fe6c29SRuslan Bukin 
225474fe6c29SRuslan Bukin 				memset(&iext, 0, sizeof(iext));
225574fe6c29SRuslan Bukin 				memset(&insn, 0, sizeof(insn));
225674fe6c29SRuslan Bukin 
225774fe6c29SRuslan Bukin 				insn.mode = pt_bce_exec_mode(bce);
225874fe6c29SRuslan Bukin 				insn.ip = ip;
225974fe6c29SRuslan Bukin 
226074fe6c29SRuslan Bukin 				status = pt_blk_decode_in_section(&insn, &iext,
226174fe6c29SRuslan Bukin 								  msec);
226274fe6c29SRuslan Bukin 				if (status < 0)
226374fe6c29SRuslan Bukin 					return status;
226474fe6c29SRuslan Bukin 
226574fe6c29SRuslan Bukin 				ip += iext.variant.branch.displacement;
226674fe6c29SRuslan Bukin 			}
226774fe6c29SRuslan Bukin 
226874fe6c29SRuslan Bukin 			decoder->ip = ip + bce.isize;
226974fe6c29SRuslan Bukin 			break;
227074fe6c29SRuslan Bukin 		}
227174fe6c29SRuslan Bukin 
227274fe6c29SRuslan Bukin 		fallthrough;
227374fe6c29SRuslan Bukin 	case ptbq_decode: {
227474fe6c29SRuslan Bukin 		struct pt_insn_ext iext;
227574fe6c29SRuslan Bukin 		struct pt_insn insn;
227674fe6c29SRuslan Bukin 
227774fe6c29SRuslan Bukin 		/* We need to decode the instruction at @decoder->ip and decide
227874fe6c29SRuslan Bukin 		 * what to do based on that.
227974fe6c29SRuslan Bukin 		 *
228074fe6c29SRuslan Bukin 		 * We already accounted for the instruction so we can't just
228174fe6c29SRuslan Bukin 		 * call pt_blk_proceed_one_insn().
228274fe6c29SRuslan Bukin 		 */
228374fe6c29SRuslan Bukin 
228474fe6c29SRuslan Bukin 		memset(&iext, 0, sizeof(iext));
228574fe6c29SRuslan Bukin 		memset(&insn, 0, sizeof(insn));
228674fe6c29SRuslan Bukin 
228774fe6c29SRuslan Bukin 		insn.mode = pt_bce_exec_mode(bce);
228874fe6c29SRuslan Bukin 		insn.ip = decoder->ip;
228974fe6c29SRuslan Bukin 
229074fe6c29SRuslan Bukin 		status = pt_blk_decode_in_section(&insn, &iext, msec);
229174fe6c29SRuslan Bukin 		if (status < 0) {
229274fe6c29SRuslan Bukin 			if (status != -pte_bad_insn)
229374fe6c29SRuslan Bukin 				return status;
229474fe6c29SRuslan Bukin 
229574fe6c29SRuslan Bukin 			return pt_blk_proceed_truncated(decoder, block);
229674fe6c29SRuslan Bukin 		}
229774fe6c29SRuslan Bukin 
229874fe6c29SRuslan Bukin 		/* We just decoded @insn so we know the instruction class. */
229974fe6c29SRuslan Bukin 		block->iclass = insn.iclass;
230074fe6c29SRuslan Bukin 
230174fe6c29SRuslan Bukin 		/* Log calls' return addresses for return compression. */
230274fe6c29SRuslan Bukin 		status = pt_blk_log_call(decoder, &insn, &iext);
230374fe6c29SRuslan Bukin 		if (status < 0)
230474fe6c29SRuslan Bukin 			return status;
230574fe6c29SRuslan Bukin 
230674fe6c29SRuslan Bukin 		/* Let's see if we can proceed to the next IP without trace.
230774fe6c29SRuslan Bukin 		 *
230874fe6c29SRuslan Bukin 		 * Note that we also stop due to displacement overflows or to
230974fe6c29SRuslan Bukin 		 * maintain the return-address stack for near direct calls.
231074fe6c29SRuslan Bukin 		 */
231174fe6c29SRuslan Bukin 		status = pt_insn_next_ip(&decoder->ip, &insn, &iext);
231274fe6c29SRuslan Bukin 		if (status < 0) {
231374fe6c29SRuslan Bukin 			if (status != -pte_bad_query)
231474fe6c29SRuslan Bukin 				return status;
231574fe6c29SRuslan Bukin 
231674fe6c29SRuslan Bukin 			/* We can't, so let's proceed with trace, which
231774fe6c29SRuslan Bukin 			 * completes the block.
231874fe6c29SRuslan Bukin 			 */
231974fe6c29SRuslan Bukin 			return pt_blk_proceed_with_trace(decoder, &insn, &iext);
232074fe6c29SRuslan Bukin 		}
232174fe6c29SRuslan Bukin 
232274fe6c29SRuslan Bukin 		/* End the block if the user asked us to.
232374fe6c29SRuslan Bukin 		 *
232474fe6c29SRuslan Bukin 		 * We only need to take care about direct near branches.
232574fe6c29SRuslan Bukin 		 * Indirect and far branches require trace and will naturally
232674fe6c29SRuslan Bukin 		 * end a block.
232774fe6c29SRuslan Bukin 		 */
232874fe6c29SRuslan Bukin 		if ((decoder->flags.variant.block.end_on_call &&
232974fe6c29SRuslan Bukin 		     (insn.iclass == ptic_call)) ||
233074fe6c29SRuslan Bukin 		    (decoder->flags.variant.block.end_on_jump &&
233174fe6c29SRuslan Bukin 		     (insn.iclass == ptic_jump)))
233274fe6c29SRuslan Bukin 			break;
233374fe6c29SRuslan Bukin 
233474fe6c29SRuslan Bukin 		/* If we can proceed without trace and we stay in @msec we may
233574fe6c29SRuslan Bukin 		 * proceed further.
233674fe6c29SRuslan Bukin 		 *
233774fe6c29SRuslan Bukin 		 * We're done if we switch sections, though.
233874fe6c29SRuslan Bukin 		 */
233974fe6c29SRuslan Bukin 		if (!pt_blk_is_in_section(msec, decoder->ip))
234074fe6c29SRuslan Bukin 			break;
234174fe6c29SRuslan Bukin 
234274fe6c29SRuslan Bukin 		return pt_blk_proceed_no_event_cached(decoder, block, bcache,
234374fe6c29SRuslan Bukin 						      msec);
234474fe6c29SRuslan Bukin 	}
234574fe6c29SRuslan Bukin 
234674fe6c29SRuslan Bukin 	case ptbq_ind_call: {
234774fe6c29SRuslan Bukin 		uint64_t ip;
234874fe6c29SRuslan Bukin 
234974fe6c29SRuslan Bukin 		/* We're at a near indirect call. */
235074fe6c29SRuslan Bukin 		block->iclass = ptic_call;
235174fe6c29SRuslan Bukin 
235274fe6c29SRuslan Bukin 		/* We need to update the return-address stack and query the
235374fe6c29SRuslan Bukin 		 * destination IP.
235474fe6c29SRuslan Bukin 		 */
235574fe6c29SRuslan Bukin 		ip = decoder->ip;
235674fe6c29SRuslan Bukin 
235774fe6c29SRuslan Bukin 		/* If we already know the size of the instruction, we don't need
235874fe6c29SRuslan Bukin 		 * to re-decode it.
235974fe6c29SRuslan Bukin 		 */
236074fe6c29SRuslan Bukin 		if (bce.isize)
236174fe6c29SRuslan Bukin 			ip += bce.isize;
236274fe6c29SRuslan Bukin 		else {
236374fe6c29SRuslan Bukin 			struct pt_insn_ext iext;
236474fe6c29SRuslan Bukin 			struct pt_insn insn;
236574fe6c29SRuslan Bukin 
236674fe6c29SRuslan Bukin 			memset(&iext, 0, sizeof(iext));
236774fe6c29SRuslan Bukin 			memset(&insn, 0, sizeof(insn));
236874fe6c29SRuslan Bukin 
236974fe6c29SRuslan Bukin 			insn.mode = pt_bce_exec_mode(bce);
237074fe6c29SRuslan Bukin 			insn.ip = ip;
237174fe6c29SRuslan Bukin 
237274fe6c29SRuslan Bukin 			status = pt_blk_decode_in_section(&insn, &iext, msec);
237374fe6c29SRuslan Bukin 			if (status < 0)
237474fe6c29SRuslan Bukin 				return status;
237574fe6c29SRuslan Bukin 
237674fe6c29SRuslan Bukin 			ip += insn.size;
237774fe6c29SRuslan Bukin 		}
237874fe6c29SRuslan Bukin 
237974fe6c29SRuslan Bukin 		status = pt_retstack_push(&decoder->retstack, ip);
238074fe6c29SRuslan Bukin 		if (status < 0)
238174fe6c29SRuslan Bukin 			return status;
238274fe6c29SRuslan Bukin 
238374fe6c29SRuslan Bukin 		status = pt_blk_indirect_branch(decoder, &decoder->ip);
238474fe6c29SRuslan Bukin 		if (status < 0)
238574fe6c29SRuslan Bukin 			return status;
238674fe6c29SRuslan Bukin 
238774fe6c29SRuslan Bukin 		/* Preserve the query decoder's response which indicates
238874fe6c29SRuslan Bukin 		 * upcoming events.
238974fe6c29SRuslan Bukin 		 */
239074fe6c29SRuslan Bukin 		decoder->status = status;
239174fe6c29SRuslan Bukin 		break;
239274fe6c29SRuslan Bukin 	}
239374fe6c29SRuslan Bukin 
239474fe6c29SRuslan Bukin 	case ptbq_return: {
239574fe6c29SRuslan Bukin 		int taken;
239674fe6c29SRuslan Bukin 
239774fe6c29SRuslan Bukin 		/* We're at a near return. */
239874fe6c29SRuslan Bukin 		block->iclass = ptic_return;
239974fe6c29SRuslan Bukin 
240074fe6c29SRuslan Bukin 		/* Check for a compressed return. */
240174fe6c29SRuslan Bukin 		status = pt_blk_cond_branch(decoder, &taken);
240274fe6c29SRuslan Bukin 		if (status < 0) {
240374fe6c29SRuslan Bukin 			if (status != -pte_bad_query)
240474fe6c29SRuslan Bukin 				return status;
240574fe6c29SRuslan Bukin 
240674fe6c29SRuslan Bukin 			/* The return is not compressed.  We need another query
240774fe6c29SRuslan Bukin 			 * to determine the destination IP.
240874fe6c29SRuslan Bukin 			 */
240974fe6c29SRuslan Bukin 			status = pt_blk_indirect_branch(decoder, &decoder->ip);
241074fe6c29SRuslan Bukin 			if (status < 0)
241174fe6c29SRuslan Bukin 				return status;
241274fe6c29SRuslan Bukin 
241374fe6c29SRuslan Bukin 			/* Preserve the query decoder's response which indicates
241474fe6c29SRuslan Bukin 			 * upcoming events.
241574fe6c29SRuslan Bukin 			 */
241674fe6c29SRuslan Bukin 			decoder->status = status;
241774fe6c29SRuslan Bukin 			break;
241874fe6c29SRuslan Bukin 		}
241974fe6c29SRuslan Bukin 
242074fe6c29SRuslan Bukin 		/* Preserve the query decoder's response which indicates
242174fe6c29SRuslan Bukin 		 * upcoming events.
242274fe6c29SRuslan Bukin 		 */
242374fe6c29SRuslan Bukin 		decoder->status = status;
242474fe6c29SRuslan Bukin 
242574fe6c29SRuslan Bukin 		/* A compressed return is indicated by a taken conditional
242674fe6c29SRuslan Bukin 		 * branch.
242774fe6c29SRuslan Bukin 		 */
242874fe6c29SRuslan Bukin 		if (!taken)
242974fe6c29SRuslan Bukin 			return -pte_bad_retcomp;
243074fe6c29SRuslan Bukin 
243174fe6c29SRuslan Bukin 		return pt_retstack_pop(&decoder->retstack, &decoder->ip);
243274fe6c29SRuslan Bukin 	}
243374fe6c29SRuslan Bukin 
243474fe6c29SRuslan Bukin 	case ptbq_indirect:
243574fe6c29SRuslan Bukin 		/* We're at an indirect jump or far transfer.
243674fe6c29SRuslan Bukin 		 *
243774fe6c29SRuslan Bukin 		 * We don't know the exact instruction class and there's no
243874fe6c29SRuslan Bukin 		 * reason to decode the instruction for any other purpose.
243974fe6c29SRuslan Bukin 		 *
244074fe6c29SRuslan Bukin 		 * Indicate that we don't know the instruction class and leave
244174fe6c29SRuslan Bukin 		 * it to our caller to decode the instruction if needed.
244274fe6c29SRuslan Bukin 		 */
244374fe6c29SRuslan Bukin 		block->iclass = ptic_error;
244474fe6c29SRuslan Bukin 
244574fe6c29SRuslan Bukin 		/* This is neither a near call nor return so we don't need to
244674fe6c29SRuslan Bukin 		 * touch the return-address stack.
244774fe6c29SRuslan Bukin 		 *
244874fe6c29SRuslan Bukin 		 * Just query the destination IP.
244974fe6c29SRuslan Bukin 		 */
245074fe6c29SRuslan Bukin 		status = pt_blk_indirect_branch(decoder, &decoder->ip);
245174fe6c29SRuslan Bukin 		if (status < 0)
245274fe6c29SRuslan Bukin 			return status;
245374fe6c29SRuslan Bukin 
245474fe6c29SRuslan Bukin 		/* Preserve the query decoder's response which indicates
245574fe6c29SRuslan Bukin 		 * upcoming events.
245674fe6c29SRuslan Bukin 		 */
245774fe6c29SRuslan Bukin 		decoder->status = status;
245874fe6c29SRuslan Bukin 		break;
245974fe6c29SRuslan Bukin 	}
246074fe6c29SRuslan Bukin 
246174fe6c29SRuslan Bukin 	return 0;
246274fe6c29SRuslan Bukin }
246374fe6c29SRuslan Bukin 
246474fe6c29SRuslan Bukin static int pt_blk_msec_fill(struct pt_block_decoder *decoder,
246574fe6c29SRuslan Bukin 			    const struct pt_mapped_section **pmsec)
246674fe6c29SRuslan Bukin {
246774fe6c29SRuslan Bukin 	const struct pt_mapped_section *msec;
246874fe6c29SRuslan Bukin 	struct pt_section *section;
246974fe6c29SRuslan Bukin 	int isid, errcode;
247074fe6c29SRuslan Bukin 
247174fe6c29SRuslan Bukin 	if (!decoder || !pmsec)
247274fe6c29SRuslan Bukin 		return -pte_internal;
247374fe6c29SRuslan Bukin 
247474fe6c29SRuslan Bukin 	isid = pt_msec_cache_fill(&decoder->scache, &msec,  decoder->image,
247574fe6c29SRuslan Bukin 				  &decoder->asid, decoder->ip);
247674fe6c29SRuslan Bukin 	if (isid < 0)
247774fe6c29SRuslan Bukin 		return isid;
247874fe6c29SRuslan Bukin 
247974fe6c29SRuslan Bukin 	section = pt_msec_section(msec);
248074fe6c29SRuslan Bukin 	if (!section)
248174fe6c29SRuslan Bukin 		return -pte_internal;
248274fe6c29SRuslan Bukin 
248374fe6c29SRuslan Bukin 	*pmsec = msec;
248474fe6c29SRuslan Bukin 
248574fe6c29SRuslan Bukin 	errcode = pt_section_request_bcache(section);
248674fe6c29SRuslan Bukin 	if (errcode < 0)
248774fe6c29SRuslan Bukin 		return errcode;
248874fe6c29SRuslan Bukin 
248974fe6c29SRuslan Bukin 	return isid;
249074fe6c29SRuslan Bukin }
249174fe6c29SRuslan Bukin 
249274fe6c29SRuslan Bukin static inline int pt_blk_msec_lookup(struct pt_block_decoder *decoder,
249374fe6c29SRuslan Bukin 				     const struct pt_mapped_section **pmsec)
249474fe6c29SRuslan Bukin {
249574fe6c29SRuslan Bukin 	int isid;
249674fe6c29SRuslan Bukin 
249774fe6c29SRuslan Bukin 	if (!decoder)
249874fe6c29SRuslan Bukin 		return -pte_internal;
249974fe6c29SRuslan Bukin 
250074fe6c29SRuslan Bukin 	isid = pt_msec_cache_read(&decoder->scache, pmsec, decoder->image,
250174fe6c29SRuslan Bukin 				  decoder->ip);
250274fe6c29SRuslan Bukin 	if (isid < 0) {
250374fe6c29SRuslan Bukin 		if (isid != -pte_nomap)
250474fe6c29SRuslan Bukin 			return isid;
250574fe6c29SRuslan Bukin 
250674fe6c29SRuslan Bukin 		return pt_blk_msec_fill(decoder, pmsec);
250774fe6c29SRuslan Bukin 	}
250874fe6c29SRuslan Bukin 
250974fe6c29SRuslan Bukin 	return isid;
251074fe6c29SRuslan Bukin }
251174fe6c29SRuslan Bukin 
251274fe6c29SRuslan Bukin /* Proceed to the next decision point - try using the cache.
251374fe6c29SRuslan Bukin  *
251474fe6c29SRuslan Bukin  * Tracing is enabled and we don't have an event pending.  Proceed as far as
251574fe6c29SRuslan Bukin  * we get without trace.  Stop when we either:
251674fe6c29SRuslan Bukin  *
251774fe6c29SRuslan Bukin  *   - need trace in order to continue
251874fe6c29SRuslan Bukin  *   - overflow the max number of instructions in a block
251974fe6c29SRuslan Bukin  *
252074fe6c29SRuslan Bukin  * We actually proceed one instruction further to get the start IP for the next
252174fe6c29SRuslan Bukin  * block.  This only updates @decoder's internal state, though.
252274fe6c29SRuslan Bukin  *
252374fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
252474fe6c29SRuslan Bukin  */
252574fe6c29SRuslan Bukin static int pt_blk_proceed_no_event(struct pt_block_decoder *decoder,
252674fe6c29SRuslan Bukin 				   struct pt_block *block)
252774fe6c29SRuslan Bukin {
252874fe6c29SRuslan Bukin 	const struct pt_mapped_section *msec;
252974fe6c29SRuslan Bukin 	struct pt_block_cache *bcache;
253074fe6c29SRuslan Bukin 	struct pt_section *section;
253174fe6c29SRuslan Bukin 	int isid;
253274fe6c29SRuslan Bukin 
253374fe6c29SRuslan Bukin 	if (!decoder || !block)
253474fe6c29SRuslan Bukin 		return -pte_internal;
253574fe6c29SRuslan Bukin 
253674fe6c29SRuslan Bukin 	isid = pt_blk_msec_lookup(decoder, &msec);
253774fe6c29SRuslan Bukin 	if (isid < 0) {
253874fe6c29SRuslan Bukin 		if (isid != -pte_nomap)
253974fe6c29SRuslan Bukin 			return isid;
254074fe6c29SRuslan Bukin 
254174fe6c29SRuslan Bukin 		/* Even if there is no such section in the image, we may still
254274fe6c29SRuslan Bukin 		 * read the memory via the callback function.
254374fe6c29SRuslan Bukin 		 */
254474fe6c29SRuslan Bukin 		return pt_blk_proceed_no_event_uncached(decoder, block);
254574fe6c29SRuslan Bukin 	}
254674fe6c29SRuslan Bukin 
254774fe6c29SRuslan Bukin 	/* We do not switch sections inside a block. */
254874fe6c29SRuslan Bukin 	if (isid != block->isid) {
254974fe6c29SRuslan Bukin 		if (!pt_blk_block_is_empty(block))
255074fe6c29SRuslan Bukin 			return 0;
255174fe6c29SRuslan Bukin 
255274fe6c29SRuslan Bukin 		block->isid = isid;
255374fe6c29SRuslan Bukin 	}
255474fe6c29SRuslan Bukin 
255574fe6c29SRuslan Bukin 	section = pt_msec_section(msec);
255674fe6c29SRuslan Bukin 	if (!section)
255774fe6c29SRuslan Bukin 		return -pte_internal;
255874fe6c29SRuslan Bukin 
255974fe6c29SRuslan Bukin 	bcache = pt_section_bcache(section);
256074fe6c29SRuslan Bukin 	if (!bcache)
256174fe6c29SRuslan Bukin 		return pt_blk_proceed_no_event_uncached(decoder, block);
256274fe6c29SRuslan Bukin 
256374fe6c29SRuslan Bukin 	return pt_blk_proceed_no_event_cached(decoder, block, bcache, msec);
256474fe6c29SRuslan Bukin }
256574fe6c29SRuslan Bukin 
256674fe6c29SRuslan Bukin /* Proceed to the next event or decision point.
256774fe6c29SRuslan Bukin  *
256874fe6c29SRuslan Bukin  * Returns a non-negative pt_status_flag bit-vector on success, a negative error
256974fe6c29SRuslan Bukin  * code otherwise.
257074fe6c29SRuslan Bukin  */
257174fe6c29SRuslan Bukin static int pt_blk_proceed(struct pt_block_decoder *decoder,
257274fe6c29SRuslan Bukin 			  struct pt_block *block)
257374fe6c29SRuslan Bukin {
257474fe6c29SRuslan Bukin 	int status;
257574fe6c29SRuslan Bukin 
257674fe6c29SRuslan Bukin 	status = pt_blk_fetch_event(decoder);
257774fe6c29SRuslan Bukin 	if (status != 0) {
257874fe6c29SRuslan Bukin 		if (status < 0)
257974fe6c29SRuslan Bukin 			return status;
258074fe6c29SRuslan Bukin 
258174fe6c29SRuslan Bukin 		return pt_blk_proceed_event(decoder, block);
258274fe6c29SRuslan Bukin 	}
258374fe6c29SRuslan Bukin 
258474fe6c29SRuslan Bukin 	/* If tracing is disabled we should either be out of trace or we should
258574fe6c29SRuslan Bukin 	 * have taken the event flow above.
258674fe6c29SRuslan Bukin 	 */
258774fe6c29SRuslan Bukin 	if (!decoder->enabled) {
258874fe6c29SRuslan Bukin 		if (decoder->status & pts_eos)
258974fe6c29SRuslan Bukin 			return -pte_eos;
259074fe6c29SRuslan Bukin 
259174fe6c29SRuslan Bukin 		return -pte_no_enable;
259274fe6c29SRuslan Bukin 	}
259374fe6c29SRuslan Bukin 
259474fe6c29SRuslan Bukin 	status = pt_blk_proceed_no_event(decoder, block);
259574fe6c29SRuslan Bukin 	if (status < 0)
259674fe6c29SRuslan Bukin 		return status;
259774fe6c29SRuslan Bukin 
259874fe6c29SRuslan Bukin 	return pt_blk_proceed_trailing_event(decoder, block);
259974fe6c29SRuslan Bukin }
260074fe6c29SRuslan Bukin 
260174fe6c29SRuslan Bukin enum {
260274fe6c29SRuslan Bukin 	/* The maximum number of steps to take when determining whether the
260374fe6c29SRuslan Bukin 	 * event location can be reached.
260474fe6c29SRuslan Bukin 	 */
260574fe6c29SRuslan Bukin 	bdm64_max_steps	= 0x100
260674fe6c29SRuslan Bukin };
260774fe6c29SRuslan Bukin 
260874fe6c29SRuslan Bukin /* Try to work around erratum BDM64.
260974fe6c29SRuslan Bukin  *
261074fe6c29SRuslan Bukin  * If we got a transaction abort immediately following a branch that produced
261174fe6c29SRuslan Bukin  * trace, the trace for that branch might have been corrupted.
261274fe6c29SRuslan Bukin  *
261374fe6c29SRuslan Bukin  * Returns a positive integer if the erratum was handled.
261474fe6c29SRuslan Bukin  * Returns zero if the erratum does not seem to apply.
261574fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
261674fe6c29SRuslan Bukin  */
261774fe6c29SRuslan Bukin static int pt_blk_handle_erratum_bdm64(struct pt_block_decoder *decoder,
261874fe6c29SRuslan Bukin 				       const struct pt_block *block,
261974fe6c29SRuslan Bukin 				       const struct pt_event *ev)
262074fe6c29SRuslan Bukin {
262174fe6c29SRuslan Bukin 	struct pt_insn_ext iext;
262274fe6c29SRuslan Bukin 	struct pt_insn insn;
262374fe6c29SRuslan Bukin 	int status;
262474fe6c29SRuslan Bukin 
262574fe6c29SRuslan Bukin 	if (!decoder || !block || !ev)
262674fe6c29SRuslan Bukin 		return -pte_internal;
262774fe6c29SRuslan Bukin 
262874fe6c29SRuslan Bukin 	/* This only affects aborts. */
262974fe6c29SRuslan Bukin 	if (!ev->variant.tsx.aborted)
263074fe6c29SRuslan Bukin 		return 0;
263174fe6c29SRuslan Bukin 
263274fe6c29SRuslan Bukin 	/* This only affects branches that require trace.
263374fe6c29SRuslan Bukin 	 *
263474fe6c29SRuslan Bukin 	 * If the erratum hits, that branch ended the current block and brought
263574fe6c29SRuslan Bukin 	 * us to the trailing event flow.
263674fe6c29SRuslan Bukin 	 */
263774fe6c29SRuslan Bukin 	if (pt_blk_block_is_empty(block))
263874fe6c29SRuslan Bukin 		return 0;
263974fe6c29SRuslan Bukin 
264074fe6c29SRuslan Bukin 	insn.mode = block->mode;
264174fe6c29SRuslan Bukin 	insn.ip = block->end_ip;
264274fe6c29SRuslan Bukin 
264374fe6c29SRuslan Bukin 	status = pt_insn_decode(&insn, &iext, decoder->image, &decoder->asid);
264474fe6c29SRuslan Bukin 	if (status < 0)
264574fe6c29SRuslan Bukin 		return 0;
264674fe6c29SRuslan Bukin 
264774fe6c29SRuslan Bukin 	if (!pt_insn_is_branch(&insn, &iext))
264874fe6c29SRuslan Bukin 		return 0;
264974fe6c29SRuslan Bukin 
265074fe6c29SRuslan Bukin 	/* Let's check if we can reach the event location from here.
265174fe6c29SRuslan Bukin 	 *
265274fe6c29SRuslan Bukin 	 * If we can, let's assume the erratum did not hit.  We might still be
265374fe6c29SRuslan Bukin 	 * wrong but we're not able to tell.
265474fe6c29SRuslan Bukin 	 */
265574fe6c29SRuslan Bukin 	status = pt_insn_range_is_contiguous(decoder->ip, ev->variant.tsx.ip,
265674fe6c29SRuslan Bukin 					     decoder->mode, decoder->image,
265774fe6c29SRuslan Bukin 					     &decoder->asid, bdm64_max_steps);
265874fe6c29SRuslan Bukin 	if (status > 0)
265974fe6c29SRuslan Bukin 		return status;
266074fe6c29SRuslan Bukin 
266174fe6c29SRuslan Bukin 	/* We can't reach the event location.  This could either mean that we
266274fe6c29SRuslan Bukin 	 * stopped too early (and status is zero) or that the erratum hit.
266374fe6c29SRuslan Bukin 	 *
266474fe6c29SRuslan Bukin 	 * We assume the latter and pretend that the previous branch brought us
266574fe6c29SRuslan Bukin 	 * to the event location, instead.
266674fe6c29SRuslan Bukin 	 */
266774fe6c29SRuslan Bukin 	decoder->ip = ev->variant.tsx.ip;
266874fe6c29SRuslan Bukin 
266974fe6c29SRuslan Bukin 	return 1;
267074fe6c29SRuslan Bukin }
267174fe6c29SRuslan Bukin 
267274fe6c29SRuslan Bukin /* Check whether a trailing TSX event should be postponed.
267374fe6c29SRuslan Bukin  *
267474fe6c29SRuslan Bukin  * This involves handling erratum BDM64.
267574fe6c29SRuslan Bukin  *
267674fe6c29SRuslan Bukin  * Returns a positive integer if the event is to be postponed.
267774fe6c29SRuslan Bukin  * Returns zero if the event should be processed.
267874fe6c29SRuslan Bukin  * Returns a negative error code otherwise.
267974fe6c29SRuslan Bukin  */
268074fe6c29SRuslan Bukin static inline int pt_blk_postpone_trailing_tsx(struct pt_block_decoder *decoder,
268174fe6c29SRuslan Bukin 					       struct pt_block *block,
268274fe6c29SRuslan Bukin 					       const struct pt_event *ev)
268374fe6c29SRuslan Bukin {
268474fe6c29SRuslan Bukin 	int status;
268574fe6c29SRuslan Bukin 
268674fe6c29SRuslan Bukin 	if (!decoder || !ev)
268774fe6c29SRuslan Bukin 		return -pte_internal;
268874fe6c29SRuslan Bukin 
268974fe6c29SRuslan Bukin 	if (ev->ip_suppressed)
269074fe6c29SRuslan Bukin 		return 0;
269174fe6c29SRuslan Bukin 
269274fe6c29SRuslan Bukin 	if (block && decoder->query.config.errata.bdm64) {
269374fe6c29SRuslan Bukin 		status = pt_blk_handle_erratum_bdm64(decoder, block, ev);
269474fe6c29SRuslan Bukin 		if (status < 0)
269574fe6c29SRuslan Bukin 			return 1;
269674fe6c29SRuslan Bukin 	}
269774fe6c29SRuslan Bukin 
269874fe6c29SRuslan Bukin 	if (decoder->ip != ev->variant.tsx.ip)
269974fe6c29SRuslan Bukin 		return 1;
270074fe6c29SRuslan Bukin 
270174fe6c29SRuslan Bukin 	return 0;
270274fe6c29SRuslan Bukin }
270374fe6c29SRuslan Bukin 
270474fe6c29SRuslan Bukin /* Proceed with events that bind to the current decoder IP.
270574fe6c29SRuslan Bukin  *
270674fe6c29SRuslan Bukin  * This function is used in the following scenarios:
270774fe6c29SRuslan Bukin  *
270874fe6c29SRuslan Bukin  *   - we just synchronized onto the trace stream
270974fe6c29SRuslan Bukin  *   - we ended a block and proceeded to the next IP
271074fe6c29SRuslan Bukin  *   - we processed an event that was indicated by this function
271174fe6c29SRuslan Bukin  *
271274fe6c29SRuslan Bukin  * Check if there is an event at the current IP that needs to be indicated to
271374fe6c29SRuslan Bukin  * the user.
271474fe6c29SRuslan Bukin  *
271574fe6c29SRuslan Bukin  * Returns a non-negative pt_status_flag bit-vector on success, a negative error
271674fe6c29SRuslan Bukin  * code otherwise.
271774fe6c29SRuslan Bukin  */
271874fe6c29SRuslan Bukin static int pt_blk_proceed_trailing_event(struct pt_block_decoder *decoder,
271974fe6c29SRuslan Bukin 					 struct pt_block *block)
272074fe6c29SRuslan Bukin {
272174fe6c29SRuslan Bukin 	struct pt_event *ev;
272274fe6c29SRuslan Bukin 	int status;
272374fe6c29SRuslan Bukin 
272474fe6c29SRuslan Bukin 	if (!decoder)
272574fe6c29SRuslan Bukin 		return -pte_internal;
272674fe6c29SRuslan Bukin 
272774fe6c29SRuslan Bukin 	status = pt_blk_fetch_event(decoder);
272874fe6c29SRuslan Bukin 	if (status <= 0) {
272974fe6c29SRuslan Bukin 		if (status < 0)
273074fe6c29SRuslan Bukin 			return status;
273174fe6c29SRuslan Bukin 
273274fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
273374fe6c29SRuslan Bukin 		if (status < 0)
273474fe6c29SRuslan Bukin 			return status;
273574fe6c29SRuslan Bukin 
273674fe6c29SRuslan Bukin 		return pt_blk_status(decoder, 0);
273774fe6c29SRuslan Bukin 	}
273874fe6c29SRuslan Bukin 
273974fe6c29SRuslan Bukin 	ev = &decoder->event;
274074fe6c29SRuslan Bukin 	switch (ev->type) {
274174fe6c29SRuslan Bukin 	case ptev_disabled:
274274fe6c29SRuslan Bukin 		/* Synchronous disable events are normally indicated on the
274374fe6c29SRuslan Bukin 		 * event flow.
274474fe6c29SRuslan Bukin 		 */
274574fe6c29SRuslan Bukin 		if (!decoder->process_insn)
274674fe6c29SRuslan Bukin 			break;
274774fe6c29SRuslan Bukin 
274874fe6c29SRuslan Bukin 		/* A sync disable may bind to a CR3 changing instruction. */
274974fe6c29SRuslan Bukin 		if (ev->ip_suppressed &&
275074fe6c29SRuslan Bukin 		    pt_insn_changes_cr3(&decoder->insn, &decoder->iext))
275174fe6c29SRuslan Bukin 			return pt_blk_status(decoder, pts_event_pending);
275274fe6c29SRuslan Bukin 
275374fe6c29SRuslan Bukin 		/* Or it binds to the next branch that would require trace.
275474fe6c29SRuslan Bukin 		 *
275574fe6c29SRuslan Bukin 		 * Try to complete processing the current instruction by
275674fe6c29SRuslan Bukin 		 * proceeding past it.  If that fails because it would require
275774fe6c29SRuslan Bukin 		 * trace, we can apply the disabled event.
275874fe6c29SRuslan Bukin 		 */
275974fe6c29SRuslan Bukin 		status = pt_insn_next_ip(&decoder->ip, &decoder->insn,
276074fe6c29SRuslan Bukin 					 &decoder->iext);
276174fe6c29SRuslan Bukin 		if (status < 0) {
276274fe6c29SRuslan Bukin 			if (status != -pte_bad_query)
276374fe6c29SRuslan Bukin 				return status;
276474fe6c29SRuslan Bukin 
276574fe6c29SRuslan Bukin 			status = pt_blk_set_disable_resume_ip(decoder,
276674fe6c29SRuslan Bukin 							      &decoder->insn);
276774fe6c29SRuslan Bukin 			if (status < 0)
276874fe6c29SRuslan Bukin 				return status;
276974fe6c29SRuslan Bukin 
277074fe6c29SRuslan Bukin 			return pt_blk_status(decoder, pts_event_pending);
277174fe6c29SRuslan Bukin 		}
277274fe6c29SRuslan Bukin 
277374fe6c29SRuslan Bukin 		/* We proceeded past the current instruction. */
277474fe6c29SRuslan Bukin 		status = pt_blk_clear_postponed_insn(decoder);
277574fe6c29SRuslan Bukin 		if (status < 0)
277674fe6c29SRuslan Bukin 			return status;
277774fe6c29SRuslan Bukin 
277874fe6c29SRuslan Bukin 		/* This might have brought us to the disable IP. */
277974fe6c29SRuslan Bukin 		if (!ev->ip_suppressed &&
278074fe6c29SRuslan Bukin 		    decoder->ip == ev->variant.disabled.ip)
278174fe6c29SRuslan Bukin 			return pt_blk_status(decoder, pts_event_pending);
278274fe6c29SRuslan Bukin 
278374fe6c29SRuslan Bukin 		break;
278474fe6c29SRuslan Bukin 
278574fe6c29SRuslan Bukin 	case ptev_enabled:
278674fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
278774fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
278874fe6c29SRuslan Bukin 		if (status < 0)
278974fe6c29SRuslan Bukin 			return status;
279074fe6c29SRuslan Bukin 
279174fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
279274fe6c29SRuslan Bukin 
279374fe6c29SRuslan Bukin 	case ptev_async_disabled:
279474fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
279574fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
279674fe6c29SRuslan Bukin 		if (status < 0)
279774fe6c29SRuslan Bukin 			return status;
279874fe6c29SRuslan Bukin 
279974fe6c29SRuslan Bukin 		if (decoder->ip != ev->variant.async_disabled.at)
280074fe6c29SRuslan Bukin 			break;
280174fe6c29SRuslan Bukin 
280274fe6c29SRuslan Bukin 		if (decoder->query.config.errata.skd022) {
280374fe6c29SRuslan Bukin 			status = pt_blk_handle_erratum_skd022(decoder, ev);
280474fe6c29SRuslan Bukin 			if (status != 0) {
280574fe6c29SRuslan Bukin 				if (status < 0)
280674fe6c29SRuslan Bukin 					return status;
280774fe6c29SRuslan Bukin 
280874fe6c29SRuslan Bukin 				/* If the erratum applies, the event is modified
280974fe6c29SRuslan Bukin 				 * to a synchronous disable event that will be
281074fe6c29SRuslan Bukin 				 * processed on the next pt_blk_proceed_event()
281174fe6c29SRuslan Bukin 				 * call.  We're done.
281274fe6c29SRuslan Bukin 				 */
281374fe6c29SRuslan Bukin 				break;
281474fe6c29SRuslan Bukin 			}
281574fe6c29SRuslan Bukin 		}
281674fe6c29SRuslan Bukin 
281774fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
281874fe6c29SRuslan Bukin 
281974fe6c29SRuslan Bukin 	case ptev_async_branch:
282074fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
282174fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
282274fe6c29SRuslan Bukin 		if (status < 0)
282374fe6c29SRuslan Bukin 			return status;
282474fe6c29SRuslan Bukin 
282574fe6c29SRuslan Bukin 		if (decoder->ip != ev->variant.async_branch.from)
282674fe6c29SRuslan Bukin 			break;
282774fe6c29SRuslan Bukin 
282874fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
282974fe6c29SRuslan Bukin 
283074fe6c29SRuslan Bukin 	case ptev_paging:
283174fe6c29SRuslan Bukin 		/* We apply the event immediately if we're not tracing. */
283274fe6c29SRuslan Bukin 		if (!decoder->enabled)
283374fe6c29SRuslan Bukin 			return pt_blk_status(decoder, pts_event_pending);
283474fe6c29SRuslan Bukin 
283574fe6c29SRuslan Bukin 		/* Synchronous paging events are normally indicated on the event
283674fe6c29SRuslan Bukin 		 * flow, unless they bind to the same instruction as a previous
283774fe6c29SRuslan Bukin 		 * event.
283874fe6c29SRuslan Bukin 		 *
283974fe6c29SRuslan Bukin 		 * We bind at most one paging event to an instruction, though.
284074fe6c29SRuslan Bukin 		 */
284174fe6c29SRuslan Bukin 		if (!decoder->process_insn || decoder->bound_paging)
284274fe6c29SRuslan Bukin 			break;
284374fe6c29SRuslan Bukin 
284474fe6c29SRuslan Bukin 		/* We're done if we're not binding to the currently postponed
284574fe6c29SRuslan Bukin 		 * instruction.  We will process the event on the normal event
284674fe6c29SRuslan Bukin 		 * flow in the next iteration.
284774fe6c29SRuslan Bukin 		 */
284874fe6c29SRuslan Bukin 		if (!pt_insn_binds_to_pip(&decoder->insn, &decoder->iext))
284974fe6c29SRuslan Bukin 			break;
285074fe6c29SRuslan Bukin 
285174fe6c29SRuslan Bukin 		/* We bound a paging event.  Make sure we do not bind further
285274fe6c29SRuslan Bukin 		 * paging events to this instruction.
285374fe6c29SRuslan Bukin 		 */
285474fe6c29SRuslan Bukin 		decoder->bound_paging = 1;
285574fe6c29SRuslan Bukin 
285674fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
285774fe6c29SRuslan Bukin 
285874fe6c29SRuslan Bukin 	case ptev_async_paging:
285974fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
286074fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
286174fe6c29SRuslan Bukin 		if (status < 0)
286274fe6c29SRuslan Bukin 			return status;
286374fe6c29SRuslan Bukin 
286474fe6c29SRuslan Bukin 		if (!ev->ip_suppressed &&
286574fe6c29SRuslan Bukin 		    decoder->ip != ev->variant.async_paging.ip)
286674fe6c29SRuslan Bukin 			break;
286774fe6c29SRuslan Bukin 
286874fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
286974fe6c29SRuslan Bukin 
287074fe6c29SRuslan Bukin 	case ptev_vmcs:
287174fe6c29SRuslan Bukin 		/* We apply the event immediately if we're not tracing. */
287274fe6c29SRuslan Bukin 		if (!decoder->enabled)
287374fe6c29SRuslan Bukin 			return pt_blk_status(decoder, pts_event_pending);
287474fe6c29SRuslan Bukin 
287574fe6c29SRuslan Bukin 		/* Synchronous vmcs events are normally indicated on the event
287674fe6c29SRuslan Bukin 		 * flow, unless they bind to the same instruction as a previous
287774fe6c29SRuslan Bukin 		 * event.
287874fe6c29SRuslan Bukin 		 *
287974fe6c29SRuslan Bukin 		 * We bind at most one vmcs event to an instruction, though.
288074fe6c29SRuslan Bukin 		 */
288174fe6c29SRuslan Bukin 		if (!decoder->process_insn || decoder->bound_vmcs)
288274fe6c29SRuslan Bukin 			break;
288374fe6c29SRuslan Bukin 
288474fe6c29SRuslan Bukin 		/* We're done if we're not binding to the currently postponed
288574fe6c29SRuslan Bukin 		 * instruction.  We will process the event on the normal event
288674fe6c29SRuslan Bukin 		 * flow in the next iteration.
288774fe6c29SRuslan Bukin 		 */
288874fe6c29SRuslan Bukin 		if (!pt_insn_binds_to_vmcs(&decoder->insn, &decoder->iext))
288974fe6c29SRuslan Bukin 			break;
289074fe6c29SRuslan Bukin 
289174fe6c29SRuslan Bukin 		/* We bound a vmcs event.  Make sure we do not bind further vmcs
289274fe6c29SRuslan Bukin 		 * events to this instruction.
289374fe6c29SRuslan Bukin 		 */
289474fe6c29SRuslan Bukin 		decoder->bound_vmcs = 1;
289574fe6c29SRuslan Bukin 
289674fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
289774fe6c29SRuslan Bukin 
289874fe6c29SRuslan Bukin 	case ptev_async_vmcs:
289974fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
290074fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
290174fe6c29SRuslan Bukin 		if (status < 0)
290274fe6c29SRuslan Bukin 			return status;
290374fe6c29SRuslan Bukin 
290474fe6c29SRuslan Bukin 		if (!ev->ip_suppressed &&
290574fe6c29SRuslan Bukin 		    decoder->ip != ev->variant.async_vmcs.ip)
290674fe6c29SRuslan Bukin 			break;
290774fe6c29SRuslan Bukin 
290874fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
290974fe6c29SRuslan Bukin 
291074fe6c29SRuslan Bukin 	case ptev_overflow:
291174fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
291274fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
291374fe6c29SRuslan Bukin 		if (status < 0)
291474fe6c29SRuslan Bukin 			return status;
291574fe6c29SRuslan Bukin 
291674fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
291774fe6c29SRuslan Bukin 
291874fe6c29SRuslan Bukin 	case ptev_exec_mode:
291974fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
292074fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
292174fe6c29SRuslan Bukin 		if (status < 0)
292274fe6c29SRuslan Bukin 			return status;
292374fe6c29SRuslan Bukin 
292474fe6c29SRuslan Bukin 		if (!ev->ip_suppressed &&
292574fe6c29SRuslan Bukin 		    decoder->ip != ev->variant.exec_mode.ip)
292674fe6c29SRuslan Bukin 			break;
292774fe6c29SRuslan Bukin 
292874fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
292974fe6c29SRuslan Bukin 
293074fe6c29SRuslan Bukin 	case ptev_tsx:
293174fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
293274fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
293374fe6c29SRuslan Bukin 		if (status < 0)
293474fe6c29SRuslan Bukin 			return status;
293574fe6c29SRuslan Bukin 
293674fe6c29SRuslan Bukin 		status = pt_blk_postpone_trailing_tsx(decoder, block, ev);
293774fe6c29SRuslan Bukin 		if (status != 0) {
293874fe6c29SRuslan Bukin 			if (status < 0)
293974fe6c29SRuslan Bukin 				return status;
294074fe6c29SRuslan Bukin 
294174fe6c29SRuslan Bukin 			break;
294274fe6c29SRuslan Bukin 		}
294374fe6c29SRuslan Bukin 
294474fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
294574fe6c29SRuslan Bukin 
294674fe6c29SRuslan Bukin 	case ptev_stop:
294774fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
294874fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
294974fe6c29SRuslan Bukin 		if (status < 0)
295074fe6c29SRuslan Bukin 			return status;
295174fe6c29SRuslan Bukin 
295274fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
295374fe6c29SRuslan Bukin 
295474fe6c29SRuslan Bukin 	case ptev_exstop:
295574fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
295674fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
295774fe6c29SRuslan Bukin 		if (status < 0)
295874fe6c29SRuslan Bukin 			return status;
295974fe6c29SRuslan Bukin 
296074fe6c29SRuslan Bukin 		if (!ev->ip_suppressed && decoder->enabled &&
296174fe6c29SRuslan Bukin 		    decoder->ip != ev->variant.exstop.ip)
296274fe6c29SRuslan Bukin 			break;
296374fe6c29SRuslan Bukin 
296474fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
296574fe6c29SRuslan Bukin 
296674fe6c29SRuslan Bukin 	case ptev_mwait:
296774fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
296874fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
296974fe6c29SRuslan Bukin 		if (status < 0)
297074fe6c29SRuslan Bukin 			return status;
297174fe6c29SRuslan Bukin 
297274fe6c29SRuslan Bukin 		if (!ev->ip_suppressed && decoder->enabled &&
297374fe6c29SRuslan Bukin 		    decoder->ip != ev->variant.mwait.ip)
297474fe6c29SRuslan Bukin 			break;
297574fe6c29SRuslan Bukin 
297674fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
297774fe6c29SRuslan Bukin 
297874fe6c29SRuslan Bukin 	case ptev_pwre:
297974fe6c29SRuslan Bukin 	case ptev_pwrx:
298074fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
298174fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
298274fe6c29SRuslan Bukin 		if (status < 0)
298374fe6c29SRuslan Bukin 			return status;
298474fe6c29SRuslan Bukin 
298574fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
298674fe6c29SRuslan Bukin 
298774fe6c29SRuslan Bukin 	case ptev_ptwrite:
298874fe6c29SRuslan Bukin 		/* We apply the event immediately if we're not tracing. */
298974fe6c29SRuslan Bukin 		if (!decoder->enabled)
299074fe6c29SRuslan Bukin 			return pt_blk_status(decoder, pts_event_pending);
299174fe6c29SRuslan Bukin 
299274fe6c29SRuslan Bukin 		/* Ptwrite events are normally indicated on the event flow,
299374fe6c29SRuslan Bukin 		 * unless they bind to the same instruction as a previous event.
299474fe6c29SRuslan Bukin 		 *
299574fe6c29SRuslan Bukin 		 * We bind at most one ptwrite event to an instruction, though.
299674fe6c29SRuslan Bukin 		 */
299774fe6c29SRuslan Bukin 		if (!decoder->process_insn || decoder->bound_ptwrite)
299874fe6c29SRuslan Bukin 			break;
299974fe6c29SRuslan Bukin 
300074fe6c29SRuslan Bukin 		/* We're done if we're not binding to the currently postponed
300174fe6c29SRuslan Bukin 		 * instruction.  We will process the event on the normal event
300274fe6c29SRuslan Bukin 		 * flow in the next iteration.
300374fe6c29SRuslan Bukin 		 */
300474fe6c29SRuslan Bukin 		if (!ev->ip_suppressed ||
300574fe6c29SRuslan Bukin 		    !pt_insn_is_ptwrite(&decoder->insn, &decoder->iext))
300674fe6c29SRuslan Bukin 			break;
300774fe6c29SRuslan Bukin 
300874fe6c29SRuslan Bukin 		/* We bound a ptwrite event.  Make sure we do not bind further
300974fe6c29SRuslan Bukin 		 * ptwrite events to this instruction.
301074fe6c29SRuslan Bukin 		 */
301174fe6c29SRuslan Bukin 		decoder->bound_ptwrite = 1;
301274fe6c29SRuslan Bukin 
301374fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
301474fe6c29SRuslan Bukin 
301574fe6c29SRuslan Bukin 	case ptev_tick:
301674fe6c29SRuslan Bukin 	case ptev_cbr:
301774fe6c29SRuslan Bukin 	case ptev_mnt:
301874fe6c29SRuslan Bukin 		/* This event does not bind to an instruction. */
301974fe6c29SRuslan Bukin 		status = pt_blk_proceed_postponed_insn(decoder);
302074fe6c29SRuslan Bukin 		if (status < 0)
302174fe6c29SRuslan Bukin 			return status;
302274fe6c29SRuslan Bukin 
302374fe6c29SRuslan Bukin 		return pt_blk_status(decoder, pts_event_pending);
302474fe6c29SRuslan Bukin 	}
302574fe6c29SRuslan Bukin 
302674fe6c29SRuslan Bukin 	/* No further events.  Proceed past any postponed instruction. */
302774fe6c29SRuslan Bukin 	status = pt_blk_proceed_postponed_insn(decoder);
302874fe6c29SRuslan Bukin 	if (status < 0)
302974fe6c29SRuslan Bukin 		return status;
303074fe6c29SRuslan Bukin 
303174fe6c29SRuslan Bukin 	return pt_blk_status(decoder, 0);
303274fe6c29SRuslan Bukin }
303374fe6c29SRuslan Bukin 
303474fe6c29SRuslan Bukin int pt_blk_next(struct pt_block_decoder *decoder, struct pt_block *ublock,
303574fe6c29SRuslan Bukin 		size_t size)
303674fe6c29SRuslan Bukin {
303774fe6c29SRuslan Bukin 	struct pt_block block, *pblock;
303874fe6c29SRuslan Bukin 	int errcode, status;
303974fe6c29SRuslan Bukin 
304074fe6c29SRuslan Bukin 	if (!decoder || !ublock)
304174fe6c29SRuslan Bukin 		return -pte_invalid;
304274fe6c29SRuslan Bukin 
304374fe6c29SRuslan Bukin 	pblock = size == sizeof(block) ? ublock : &block;
304474fe6c29SRuslan Bukin 
304574fe6c29SRuslan Bukin 	/* Zero-initialize the block in case of error returns. */
304674fe6c29SRuslan Bukin 	memset(pblock, 0, sizeof(*pblock));
304774fe6c29SRuslan Bukin 
304874fe6c29SRuslan Bukin 	/* Fill in a few things from the current decode state.
304974fe6c29SRuslan Bukin 	 *
305074fe6c29SRuslan Bukin 	 * This reflects the state of the last pt_blk_next() or pt_blk_start()
305174fe6c29SRuslan Bukin 	 * call.  Note that, unless we stop with tracing disabled, we proceed
305274fe6c29SRuslan Bukin 	 * already to the start IP of the next block.
305374fe6c29SRuslan Bukin 	 *
305474fe6c29SRuslan Bukin 	 * Some of the state may later be overwritten as we process events.
305574fe6c29SRuslan Bukin 	 */
305674fe6c29SRuslan Bukin 	pblock->ip = decoder->ip;
305774fe6c29SRuslan Bukin 	pblock->mode = decoder->mode;
305874fe6c29SRuslan Bukin 	if (decoder->speculative)
305974fe6c29SRuslan Bukin 		pblock->speculative = 1;
306074fe6c29SRuslan Bukin 
306174fe6c29SRuslan Bukin 	/* Proceed one block. */
306274fe6c29SRuslan Bukin 	status = pt_blk_proceed(decoder, pblock);
306374fe6c29SRuslan Bukin 
306474fe6c29SRuslan Bukin 	errcode = block_to_user(ublock, size, pblock);
306574fe6c29SRuslan Bukin 	if (errcode < 0)
306674fe6c29SRuslan Bukin 		return errcode;
306774fe6c29SRuslan Bukin 
306874fe6c29SRuslan Bukin 	return status;
306974fe6c29SRuslan Bukin }
307074fe6c29SRuslan Bukin 
307174fe6c29SRuslan Bukin /* Process an enabled event.
307274fe6c29SRuslan Bukin  *
307374fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
307474fe6c29SRuslan Bukin  */
307574fe6c29SRuslan Bukin static int pt_blk_process_enabled(struct pt_block_decoder *decoder,
307674fe6c29SRuslan Bukin 				  const struct pt_event *ev)
307774fe6c29SRuslan Bukin {
307874fe6c29SRuslan Bukin 	if (!decoder || !ev)
307974fe6c29SRuslan Bukin 		return -pte_internal;
308074fe6c29SRuslan Bukin 
308174fe6c29SRuslan Bukin 	/* This event can't be a status update. */
308274fe6c29SRuslan Bukin 	if (ev->status_update)
308374fe6c29SRuslan Bukin 		return -pte_bad_context;
308474fe6c29SRuslan Bukin 
308574fe6c29SRuslan Bukin 	/* We must have an IP in order to start decoding. */
308674fe6c29SRuslan Bukin 	if (ev->ip_suppressed)
308774fe6c29SRuslan Bukin 		return -pte_noip;
308874fe6c29SRuslan Bukin 
308974fe6c29SRuslan Bukin 	/* We must currently be disabled. */
309074fe6c29SRuslan Bukin 	if (decoder->enabled)
309174fe6c29SRuslan Bukin 		return -pte_bad_context;
309274fe6c29SRuslan Bukin 
309374fe6c29SRuslan Bukin 	decoder->ip = ev->variant.enabled.ip;
309474fe6c29SRuslan Bukin 	decoder->enabled = 1;
309574fe6c29SRuslan Bukin 	decoder->process_event = 0;
309674fe6c29SRuslan Bukin 
309774fe6c29SRuslan Bukin 	return 0;
309874fe6c29SRuslan Bukin }
309974fe6c29SRuslan Bukin 
310074fe6c29SRuslan Bukin /* Process a disabled event.
310174fe6c29SRuslan Bukin  *
310274fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
310374fe6c29SRuslan Bukin  */
310474fe6c29SRuslan Bukin static int pt_blk_process_disabled(struct pt_block_decoder *decoder,
310574fe6c29SRuslan Bukin 				   const struct pt_event *ev)
310674fe6c29SRuslan Bukin {
310774fe6c29SRuslan Bukin 	if (!decoder || !ev)
310874fe6c29SRuslan Bukin 		return -pte_internal;
310974fe6c29SRuslan Bukin 
311074fe6c29SRuslan Bukin 	/* This event can't be a status update. */
311174fe6c29SRuslan Bukin 	if (ev->status_update)
311274fe6c29SRuslan Bukin 		return -pte_bad_context;
311374fe6c29SRuslan Bukin 
311474fe6c29SRuslan Bukin 	/* We must currently be enabled. */
311574fe6c29SRuslan Bukin 	if (!decoder->enabled)
311674fe6c29SRuslan Bukin 		return -pte_bad_context;
311774fe6c29SRuslan Bukin 
311874fe6c29SRuslan Bukin 	/* We preserve @decoder->ip.  This is where we expect tracing to resume
311974fe6c29SRuslan Bukin 	 * and we'll indicate that on the subsequent enabled event if tracing
312074fe6c29SRuslan Bukin 	 * actually does resume from there.
312174fe6c29SRuslan Bukin 	 */
312274fe6c29SRuslan Bukin 	decoder->enabled = 0;
312374fe6c29SRuslan Bukin 	decoder->process_event = 0;
312474fe6c29SRuslan Bukin 
312574fe6c29SRuslan Bukin 	return 0;
312674fe6c29SRuslan Bukin }
312774fe6c29SRuslan Bukin 
312874fe6c29SRuslan Bukin /* Process an asynchronous branch event.
312974fe6c29SRuslan Bukin  *
313074fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
313174fe6c29SRuslan Bukin  */
313274fe6c29SRuslan Bukin static int pt_blk_process_async_branch(struct pt_block_decoder *decoder,
313374fe6c29SRuslan Bukin 				       const struct pt_event *ev)
313474fe6c29SRuslan Bukin {
313574fe6c29SRuslan Bukin 	if (!decoder || !ev)
313674fe6c29SRuslan Bukin 		return -pte_internal;
313774fe6c29SRuslan Bukin 
313874fe6c29SRuslan Bukin 	/* This event can't be a status update. */
313974fe6c29SRuslan Bukin 	if (ev->status_update)
314074fe6c29SRuslan Bukin 		return -pte_bad_context;
314174fe6c29SRuslan Bukin 
314274fe6c29SRuslan Bukin 	/* We must currently be enabled. */
314374fe6c29SRuslan Bukin 	if (!decoder->enabled)
314474fe6c29SRuslan Bukin 		return -pte_bad_context;
314574fe6c29SRuslan Bukin 
314674fe6c29SRuslan Bukin 	/* Jump to the branch destination.  We will continue from there in the
314774fe6c29SRuslan Bukin 	 * next iteration.
314874fe6c29SRuslan Bukin 	 */
314974fe6c29SRuslan Bukin 	decoder->ip = ev->variant.async_branch.to;
315074fe6c29SRuslan Bukin 	decoder->process_event = 0;
315174fe6c29SRuslan Bukin 
315274fe6c29SRuslan Bukin 	return 0;
315374fe6c29SRuslan Bukin }
315474fe6c29SRuslan Bukin 
315574fe6c29SRuslan Bukin /* Process a paging event.
315674fe6c29SRuslan Bukin  *
315774fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
315874fe6c29SRuslan Bukin  */
315974fe6c29SRuslan Bukin static int pt_blk_process_paging(struct pt_block_decoder *decoder,
316074fe6c29SRuslan Bukin 				 const struct pt_event *ev)
316174fe6c29SRuslan Bukin {
316274fe6c29SRuslan Bukin 	uint64_t cr3;
316374fe6c29SRuslan Bukin 	int errcode;
316474fe6c29SRuslan Bukin 
316574fe6c29SRuslan Bukin 	if (!decoder || !ev)
316674fe6c29SRuslan Bukin 		return -pte_internal;
316774fe6c29SRuslan Bukin 
316874fe6c29SRuslan Bukin 	cr3 = ev->variant.paging.cr3;
316974fe6c29SRuslan Bukin 	if (decoder->asid.cr3 != cr3) {
317074fe6c29SRuslan Bukin 		errcode = pt_msec_cache_invalidate(&decoder->scache);
317174fe6c29SRuslan Bukin 		if (errcode < 0)
317274fe6c29SRuslan Bukin 			return errcode;
317374fe6c29SRuslan Bukin 
317474fe6c29SRuslan Bukin 		decoder->asid.cr3 = cr3;
317574fe6c29SRuslan Bukin 	}
317674fe6c29SRuslan Bukin 
317774fe6c29SRuslan Bukin 	decoder->process_event = 0;
317874fe6c29SRuslan Bukin 
317974fe6c29SRuslan Bukin 	return 0;
318074fe6c29SRuslan Bukin }
318174fe6c29SRuslan Bukin 
318274fe6c29SRuslan Bukin /* Process a vmcs event.
318374fe6c29SRuslan Bukin  *
318474fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
318574fe6c29SRuslan Bukin  */
318674fe6c29SRuslan Bukin static int pt_blk_process_vmcs(struct pt_block_decoder *decoder,
318774fe6c29SRuslan Bukin 			       const struct pt_event *ev)
318874fe6c29SRuslan Bukin {
318974fe6c29SRuslan Bukin 	uint64_t vmcs;
319074fe6c29SRuslan Bukin 	int errcode;
319174fe6c29SRuslan Bukin 
319274fe6c29SRuslan Bukin 	if (!decoder || !ev)
319374fe6c29SRuslan Bukin 		return -pte_internal;
319474fe6c29SRuslan Bukin 
319574fe6c29SRuslan Bukin 	vmcs = ev->variant.vmcs.base;
319674fe6c29SRuslan Bukin 	if (decoder->asid.vmcs != vmcs) {
319774fe6c29SRuslan Bukin 		errcode = pt_msec_cache_invalidate(&decoder->scache);
319874fe6c29SRuslan Bukin 		if (errcode < 0)
319974fe6c29SRuslan Bukin 			return errcode;
320074fe6c29SRuslan Bukin 
320174fe6c29SRuslan Bukin 		decoder->asid.vmcs = vmcs;
320274fe6c29SRuslan Bukin 	}
320374fe6c29SRuslan Bukin 
320474fe6c29SRuslan Bukin 	decoder->process_event = 0;
320574fe6c29SRuslan Bukin 
320674fe6c29SRuslan Bukin 	return 0;
320774fe6c29SRuslan Bukin }
320874fe6c29SRuslan Bukin 
320974fe6c29SRuslan Bukin /* Process an overflow event.
321074fe6c29SRuslan Bukin  *
321174fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
321274fe6c29SRuslan Bukin  */
321374fe6c29SRuslan Bukin static int pt_blk_process_overflow(struct pt_block_decoder *decoder,
321474fe6c29SRuslan Bukin 				   const struct pt_event *ev)
321574fe6c29SRuslan Bukin {
321674fe6c29SRuslan Bukin 	if (!decoder || !ev)
321774fe6c29SRuslan Bukin 		return -pte_internal;
321874fe6c29SRuslan Bukin 
321974fe6c29SRuslan Bukin 	/* This event can't be a status update. */
322074fe6c29SRuslan Bukin 	if (ev->status_update)
322174fe6c29SRuslan Bukin 		return -pte_bad_context;
322274fe6c29SRuslan Bukin 
322374fe6c29SRuslan Bukin 	/* If the IP is suppressed, the overflow resolved while tracing was
322474fe6c29SRuslan Bukin 	 * disabled.  Otherwise it resolved while tracing was enabled.
322574fe6c29SRuslan Bukin 	 */
322674fe6c29SRuslan Bukin 	if (ev->ip_suppressed) {
322774fe6c29SRuslan Bukin 		/* Tracing is disabled.  It doesn't make sense to preserve the
322874fe6c29SRuslan Bukin 		 * previous IP.  This will just be misleading.  Even if tracing
322974fe6c29SRuslan Bukin 		 * had been disabled before, as well, we might have missed the
323074fe6c29SRuslan Bukin 		 * re-enable in the overflow.
323174fe6c29SRuslan Bukin 		 */
323274fe6c29SRuslan Bukin 		decoder->enabled = 0;
323374fe6c29SRuslan Bukin 		decoder->ip = 0ull;
323474fe6c29SRuslan Bukin 	} else {
323574fe6c29SRuslan Bukin 		/* Tracing is enabled and we're at the IP at which the overflow
323674fe6c29SRuslan Bukin 		 * resolved.
323774fe6c29SRuslan Bukin 		 */
323874fe6c29SRuslan Bukin 		decoder->enabled = 1;
323974fe6c29SRuslan Bukin 		decoder->ip = ev->variant.overflow.ip;
324074fe6c29SRuslan Bukin 	}
324174fe6c29SRuslan Bukin 
324274fe6c29SRuslan Bukin 	/* We don't know the TSX state.  Let's assume we execute normally.
324374fe6c29SRuslan Bukin 	 *
324474fe6c29SRuslan Bukin 	 * We also don't know the execution mode.  Let's keep what we have
324574fe6c29SRuslan Bukin 	 * in case we don't get an update before we have to decode the next
324674fe6c29SRuslan Bukin 	 * instruction.
324774fe6c29SRuslan Bukin 	 */
324874fe6c29SRuslan Bukin 	decoder->speculative = 0;
324974fe6c29SRuslan Bukin 	decoder->process_event = 0;
325074fe6c29SRuslan Bukin 
325174fe6c29SRuslan Bukin 	return 0;
325274fe6c29SRuslan Bukin }
325374fe6c29SRuslan Bukin 
325474fe6c29SRuslan Bukin /* Process an exec mode event.
325574fe6c29SRuslan Bukin  *
325674fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
325774fe6c29SRuslan Bukin  */
325874fe6c29SRuslan Bukin static int pt_blk_process_exec_mode(struct pt_block_decoder *decoder,
325974fe6c29SRuslan Bukin 				    const struct pt_event *ev)
326074fe6c29SRuslan Bukin {
326174fe6c29SRuslan Bukin 	enum pt_exec_mode mode;
326274fe6c29SRuslan Bukin 
326374fe6c29SRuslan Bukin 	if (!decoder || !ev)
326474fe6c29SRuslan Bukin 		return -pte_internal;
326574fe6c29SRuslan Bukin 
326674fe6c29SRuslan Bukin 	/* Use status update events to diagnose inconsistencies. */
326774fe6c29SRuslan Bukin 	mode = ev->variant.exec_mode.mode;
326874fe6c29SRuslan Bukin 	if (ev->status_update && decoder->enabled &&
326974fe6c29SRuslan Bukin 	    decoder->mode != ptem_unknown && decoder->mode != mode)
327074fe6c29SRuslan Bukin 		return -pte_bad_status_update;
327174fe6c29SRuslan Bukin 
327274fe6c29SRuslan Bukin 	decoder->mode = mode;
327374fe6c29SRuslan Bukin 	decoder->process_event = 0;
327474fe6c29SRuslan Bukin 
327574fe6c29SRuslan Bukin 	return 0;
327674fe6c29SRuslan Bukin }
327774fe6c29SRuslan Bukin 
327874fe6c29SRuslan Bukin /* Process a tsx event.
327974fe6c29SRuslan Bukin  *
328074fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
328174fe6c29SRuslan Bukin  */
328274fe6c29SRuslan Bukin static int pt_blk_process_tsx(struct pt_block_decoder *decoder,
328374fe6c29SRuslan Bukin 			      const struct pt_event *ev)
328474fe6c29SRuslan Bukin {
328574fe6c29SRuslan Bukin 	if (!decoder || !ev)
328674fe6c29SRuslan Bukin 		return -pte_internal;
328774fe6c29SRuslan Bukin 
328874fe6c29SRuslan Bukin 	decoder->speculative = ev->variant.tsx.speculative;
328974fe6c29SRuslan Bukin 	decoder->process_event = 0;
329074fe6c29SRuslan Bukin 
329174fe6c29SRuslan Bukin 	return 0;
329274fe6c29SRuslan Bukin }
329374fe6c29SRuslan Bukin 
329474fe6c29SRuslan Bukin /* Process a stop event.
329574fe6c29SRuslan Bukin  *
329674fe6c29SRuslan Bukin  * Returns zero on success, a negative error code otherwise.
329774fe6c29SRuslan Bukin  */
329874fe6c29SRuslan Bukin static int pt_blk_process_stop(struct pt_block_decoder *decoder,
329974fe6c29SRuslan Bukin 			       const struct pt_event *ev)
330074fe6c29SRuslan Bukin {
330174fe6c29SRuslan Bukin 	if (!decoder || !ev)
330274fe6c29SRuslan Bukin 		return -pte_internal;
330374fe6c29SRuslan Bukin 
330474fe6c29SRuslan Bukin 	/* This event can't be a status update. */
330574fe6c29SRuslan Bukin 	if (ev->status_update)
330674fe6c29SRuslan Bukin 		return -pte_bad_context;
330774fe6c29SRuslan Bukin 
330874fe6c29SRuslan Bukin 	/* Tracing is always disabled before it is stopped. */
330974fe6c29SRuslan Bukin 	if (decoder->enabled)
331074fe6c29SRuslan Bukin 		return -pte_bad_context;
331174fe6c29SRuslan Bukin 
331274fe6c29SRuslan Bukin 	decoder->process_event = 0;
331374fe6c29SRuslan Bukin 
331474fe6c29SRuslan Bukin 	return 0;
331574fe6c29SRuslan Bukin }
331674fe6c29SRuslan Bukin 
331774fe6c29SRuslan Bukin int pt_blk_event(struct pt_block_decoder *decoder, struct pt_event *uevent,
331874fe6c29SRuslan Bukin 		 size_t size)
331974fe6c29SRuslan Bukin {
332074fe6c29SRuslan Bukin 	struct pt_event *ev;
332174fe6c29SRuslan Bukin 	int status;
332274fe6c29SRuslan Bukin 
332374fe6c29SRuslan Bukin 	if (!decoder || !uevent)
332474fe6c29SRuslan Bukin 		return -pte_invalid;
332574fe6c29SRuslan Bukin 
332674fe6c29SRuslan Bukin 	/* We must currently process an event. */
332774fe6c29SRuslan Bukin 	if (!decoder->process_event)
332874fe6c29SRuslan Bukin 		return -pte_bad_query;
332974fe6c29SRuslan Bukin 
333074fe6c29SRuslan Bukin 	ev = &decoder->event;
333174fe6c29SRuslan Bukin 	switch (ev->type) {
333274fe6c29SRuslan Bukin 	case ptev_enabled:
333374fe6c29SRuslan Bukin 		/* Indicate that tracing resumes from the IP at which tracing
333474fe6c29SRuslan Bukin 		 * had been disabled before (with some special treatment for
333574fe6c29SRuslan Bukin 		 * calls).
333674fe6c29SRuslan Bukin 		 */
333774fe6c29SRuslan Bukin 		if (ev->variant.enabled.ip == decoder->ip)
333874fe6c29SRuslan Bukin 			ev->variant.enabled.resumed = 1;
333974fe6c29SRuslan Bukin 
334074fe6c29SRuslan Bukin 		status = pt_blk_process_enabled(decoder, ev);
334174fe6c29SRuslan Bukin 		if (status < 0)
334274fe6c29SRuslan Bukin 			return status;
334374fe6c29SRuslan Bukin 
334474fe6c29SRuslan Bukin 		break;
334574fe6c29SRuslan Bukin 
334674fe6c29SRuslan Bukin 	case ptev_async_disabled:
334774fe6c29SRuslan Bukin 		if (decoder->ip != ev->variant.async_disabled.at)
334874fe6c29SRuslan Bukin 			return -pte_bad_query;
334974fe6c29SRuslan Bukin 
335074fe6c29SRuslan Bukin 		fallthrough;
335174fe6c29SRuslan Bukin 	case ptev_disabled:
335274fe6c29SRuslan Bukin 
335374fe6c29SRuslan Bukin 		status = pt_blk_process_disabled(decoder, ev);
335474fe6c29SRuslan Bukin 		if (status < 0)
335574fe6c29SRuslan Bukin 			return status;
335674fe6c29SRuslan Bukin 
335774fe6c29SRuslan Bukin 		break;
335874fe6c29SRuslan Bukin 
335974fe6c29SRuslan Bukin 	case ptev_async_branch:
336074fe6c29SRuslan Bukin 		if (decoder->ip != ev->variant.async_branch.from)
336174fe6c29SRuslan Bukin 			return -pte_bad_query;
336274fe6c29SRuslan Bukin 
336374fe6c29SRuslan Bukin 		status = pt_blk_process_async_branch(decoder, ev);
336474fe6c29SRuslan Bukin 		if (status < 0)
336574fe6c29SRuslan Bukin 			return status;
336674fe6c29SRuslan Bukin 
336774fe6c29SRuslan Bukin 		break;
336874fe6c29SRuslan Bukin 
336974fe6c29SRuslan Bukin 	case ptev_async_paging:
337074fe6c29SRuslan Bukin 		if (!ev->ip_suppressed &&
337174fe6c29SRuslan Bukin 		    decoder->ip != ev->variant.async_paging.ip)
337274fe6c29SRuslan Bukin 			return -pte_bad_query;
337374fe6c29SRuslan Bukin 
337474fe6c29SRuslan Bukin 		fallthrough;
337574fe6c29SRuslan Bukin 	case ptev_paging:
337674fe6c29SRuslan Bukin 		status = pt_blk_process_paging(decoder, ev);
337774fe6c29SRuslan Bukin 		if (status < 0)
337874fe6c29SRuslan Bukin 			return status;
337974fe6c29SRuslan Bukin 
338074fe6c29SRuslan Bukin 		break;
338174fe6c29SRuslan Bukin 
338274fe6c29SRuslan Bukin 	case ptev_async_vmcs:
338374fe6c29SRuslan Bukin 		if (!ev->ip_suppressed &&
338474fe6c29SRuslan Bukin 		    decoder->ip != ev->variant.async_vmcs.ip)
338574fe6c29SRuslan Bukin 			return -pte_bad_query;
338674fe6c29SRuslan Bukin 
338774fe6c29SRuslan Bukin 		fallthrough;
338874fe6c29SRuslan Bukin 	case ptev_vmcs:
338974fe6c29SRuslan Bukin 		status = pt_blk_process_vmcs(decoder, ev);
339074fe6c29SRuslan Bukin 		if (status < 0)
339174fe6c29SRuslan Bukin 			return status;
339274fe6c29SRuslan Bukin 
339374fe6c29SRuslan Bukin 		break;
339474fe6c29SRuslan Bukin 
339574fe6c29SRuslan Bukin 	case ptev_overflow:
339674fe6c29SRuslan Bukin 		status = pt_blk_process_overflow(decoder, ev);
339774fe6c29SRuslan Bukin 		if (status < 0)
339874fe6c29SRuslan Bukin 			return status;
339974fe6c29SRuslan Bukin 
340074fe6c29SRuslan Bukin 		break;
340174fe6c29SRuslan Bukin 
340274fe6c29SRuslan Bukin 	case ptev_exec_mode:
340374fe6c29SRuslan Bukin 		if (!ev->ip_suppressed &&
340474fe6c29SRuslan Bukin 		    decoder->ip != ev->variant.exec_mode.ip)
340574fe6c29SRuslan Bukin 			return -pte_bad_query;
340674fe6c29SRuslan Bukin 
340774fe6c29SRuslan Bukin 		status = pt_blk_process_exec_mode(decoder, ev);
340874fe6c29SRuslan Bukin 		if (status < 0)
340974fe6c29SRuslan Bukin 			return status;
341074fe6c29SRuslan Bukin 
341174fe6c29SRuslan Bukin 		break;
341274fe6c29SRuslan Bukin 
341374fe6c29SRuslan Bukin 	case ptev_tsx:
341474fe6c29SRuslan Bukin 		if (!ev->ip_suppressed && decoder->ip != ev->variant.tsx.ip)
341574fe6c29SRuslan Bukin 			return -pte_bad_query;
341674fe6c29SRuslan Bukin 
341774fe6c29SRuslan Bukin 		status = pt_blk_process_tsx(decoder, ev);
341874fe6c29SRuslan Bukin 		if (status < 0)
341974fe6c29SRuslan Bukin 			return status;
342074fe6c29SRuslan Bukin 
342174fe6c29SRuslan Bukin 		break;
342274fe6c29SRuslan Bukin 
342374fe6c29SRuslan Bukin 	case ptev_stop:
342474fe6c29SRuslan Bukin 		status = pt_blk_process_stop(decoder, ev);
342574fe6c29SRuslan Bukin 		if (status < 0)
342674fe6c29SRuslan Bukin 			return status;
342774fe6c29SRuslan Bukin 
342874fe6c29SRuslan Bukin 		break;
342974fe6c29SRuslan Bukin 
343074fe6c29SRuslan Bukin 	case ptev_exstop:
343174fe6c29SRuslan Bukin 		if (!ev->ip_suppressed && decoder->enabled &&
343274fe6c29SRuslan Bukin 		    decoder->ip != ev->variant.exstop.ip)
343374fe6c29SRuslan Bukin 			return -pte_bad_query;
343474fe6c29SRuslan Bukin 
343574fe6c29SRuslan Bukin 		decoder->process_event = 0;
343674fe6c29SRuslan Bukin 		break;
343774fe6c29SRuslan Bukin 
343874fe6c29SRuslan Bukin 	case ptev_mwait:
343974fe6c29SRuslan Bukin 		if (!ev->ip_suppressed && decoder->enabled &&
344074fe6c29SRuslan Bukin 		    decoder->ip != ev->variant.mwait.ip)
344174fe6c29SRuslan Bukin 			return -pte_bad_query;
344274fe6c29SRuslan Bukin 
344374fe6c29SRuslan Bukin 		decoder->process_event = 0;
344474fe6c29SRuslan Bukin 		break;
344574fe6c29SRuslan Bukin 
344674fe6c29SRuslan Bukin 	case ptev_pwre:
344774fe6c29SRuslan Bukin 	case ptev_pwrx:
344874fe6c29SRuslan Bukin 	case ptev_ptwrite:
344974fe6c29SRuslan Bukin 	case ptev_tick:
345074fe6c29SRuslan Bukin 	case ptev_cbr:
345174fe6c29SRuslan Bukin 	case ptev_mnt:
345274fe6c29SRuslan Bukin 		decoder->process_event = 0;
345374fe6c29SRuslan Bukin 		break;
345474fe6c29SRuslan Bukin 	}
345574fe6c29SRuslan Bukin 
345674fe6c29SRuslan Bukin 	/* Copy the event to the user.  Make sure we're not writing beyond the
345774fe6c29SRuslan Bukin 	 * memory provided by the user.
345874fe6c29SRuslan Bukin 	 *
345974fe6c29SRuslan Bukin 	 * We might truncate details of an event but only for those events the
346074fe6c29SRuslan Bukin 	 * user can't know about, anyway.
346174fe6c29SRuslan Bukin 	 */
346274fe6c29SRuslan Bukin 	if (sizeof(*ev) < size)
346374fe6c29SRuslan Bukin 		size = sizeof(*ev);
346474fe6c29SRuslan Bukin 
346574fe6c29SRuslan Bukin 	memcpy(uevent, ev, size);
346674fe6c29SRuslan Bukin 
346774fe6c29SRuslan Bukin 	/* Indicate further events. */
346874fe6c29SRuslan Bukin 	return pt_blk_proceed_trailing_event(decoder, NULL);
346974fe6c29SRuslan Bukin }
3470