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 : █ 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