174fe6c29SRuslan Bukin /*
2*85f87cf4SRuslan Bukin * Copyright (c) 2013-2019, Intel Corporation
374fe6c29SRuslan Bukin *
474fe6c29SRuslan Bukin * Redistribution and use in source and binary forms, with or without
574fe6c29SRuslan Bukin * modification, are permitted provided that the following conditions are met:
674fe6c29SRuslan Bukin *
774fe6c29SRuslan Bukin * * Redistributions of source code must retain the above copyright notice,
874fe6c29SRuslan Bukin * this list of conditions and the following disclaimer.
974fe6c29SRuslan Bukin * * Redistributions in binary form must reproduce the above copyright notice,
1074fe6c29SRuslan Bukin * this list of conditions and the following disclaimer in the documentation
1174fe6c29SRuslan Bukin * and/or other materials provided with the distribution.
1274fe6c29SRuslan Bukin * * Neither the name of Intel Corporation nor the names of its contributors
1374fe6c29SRuslan Bukin * may be used to endorse or promote products derived from this software
1474fe6c29SRuslan Bukin * without specific prior written permission.
1574fe6c29SRuslan Bukin *
1674fe6c29SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1774fe6c29SRuslan Bukin * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1874fe6c29SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1974fe6c29SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2074fe6c29SRuslan Bukin * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2174fe6c29SRuslan Bukin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2274fe6c29SRuslan Bukin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2374fe6c29SRuslan Bukin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2474fe6c29SRuslan Bukin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2574fe6c29SRuslan Bukin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2674fe6c29SRuslan Bukin * POSSIBILITY OF SUCH DAMAGE.
2774fe6c29SRuslan Bukin */
2874fe6c29SRuslan Bukin
2974fe6c29SRuslan Bukin #include "pt_section.h"
3074fe6c29SRuslan Bukin #include "pt_block_cache.h"
3174fe6c29SRuslan Bukin #include "pt_image_section_cache.h"
3274fe6c29SRuslan Bukin
3374fe6c29SRuslan Bukin #include "intel-pt.h"
3474fe6c29SRuslan Bukin
3574fe6c29SRuslan Bukin #include <stdlib.h>
3674fe6c29SRuslan Bukin #include <stdio.h>
3774fe6c29SRuslan Bukin #include <string.h>
3874fe6c29SRuslan Bukin
3974fe6c29SRuslan Bukin
pt_mk_section(struct pt_section ** psection,const char * filename,uint64_t offset,uint64_t size)40*85f87cf4SRuslan Bukin int pt_mk_section(struct pt_section **psection, const char *filename,
41*85f87cf4SRuslan Bukin uint64_t offset, uint64_t size)
4274fe6c29SRuslan Bukin {
4374fe6c29SRuslan Bukin struct pt_section *section;
4474fe6c29SRuslan Bukin uint64_t fsize;
45*85f87cf4SRuslan Bukin size_t flen;
4674fe6c29SRuslan Bukin void *status;
47*85f87cf4SRuslan Bukin char *fname;
4874fe6c29SRuslan Bukin int errcode;
4974fe6c29SRuslan Bukin
50*85f87cf4SRuslan Bukin if (!psection)
51*85f87cf4SRuslan Bukin return -pte_internal;
52*85f87cf4SRuslan Bukin
53*85f87cf4SRuslan Bukin flen = strnlen(filename, FILENAME_MAX);
54*85f87cf4SRuslan Bukin if (FILENAME_MAX <= flen)
55*85f87cf4SRuslan Bukin return -pte_invalid;
56*85f87cf4SRuslan Bukin
57*85f87cf4SRuslan Bukin flen += 1;
58*85f87cf4SRuslan Bukin
59*85f87cf4SRuslan Bukin fname = malloc(flen);
60*85f87cf4SRuslan Bukin if (!fname)
61*85f87cf4SRuslan Bukin return -pte_nomem;
62*85f87cf4SRuslan Bukin
63*85f87cf4SRuslan Bukin memcpy(fname, filename, flen);
64*85f87cf4SRuslan Bukin
65*85f87cf4SRuslan Bukin errcode = pt_section_mk_status(&status, &fsize, fname);
6674fe6c29SRuslan Bukin if (errcode < 0)
67*85f87cf4SRuslan Bukin goto out_fname;
6874fe6c29SRuslan Bukin
6974fe6c29SRuslan Bukin /* Fail if the requested @offset lies beyond the end of @file. */
70*85f87cf4SRuslan Bukin if (fsize <= offset) {
71*85f87cf4SRuslan Bukin errcode = -pte_invalid;
7274fe6c29SRuslan Bukin goto out_status;
73*85f87cf4SRuslan Bukin }
7474fe6c29SRuslan Bukin
7574fe6c29SRuslan Bukin /* Truncate @size so the entire range lies within @file. */
7674fe6c29SRuslan Bukin fsize -= offset;
7774fe6c29SRuslan Bukin if (fsize < size)
7874fe6c29SRuslan Bukin size = fsize;
7974fe6c29SRuslan Bukin
8074fe6c29SRuslan Bukin section = malloc(sizeof(*section));
81*85f87cf4SRuslan Bukin if (!section) {
82*85f87cf4SRuslan Bukin errcode = -pte_nomem;
8374fe6c29SRuslan Bukin goto out_status;
84*85f87cf4SRuslan Bukin }
8574fe6c29SRuslan Bukin
8674fe6c29SRuslan Bukin memset(section, 0, sizeof(*section));
8774fe6c29SRuslan Bukin
88*85f87cf4SRuslan Bukin section->filename = fname;
8974fe6c29SRuslan Bukin section->status = status;
9074fe6c29SRuslan Bukin section->offset = offset;
9174fe6c29SRuslan Bukin section->size = size;
9274fe6c29SRuslan Bukin section->ucount = 1;
9374fe6c29SRuslan Bukin
9474fe6c29SRuslan Bukin #if defined(FEATURE_THREADS)
9574fe6c29SRuslan Bukin
9674fe6c29SRuslan Bukin errcode = mtx_init(§ion->lock, mtx_plain);
9774fe6c29SRuslan Bukin if (errcode != thrd_success) {
9874fe6c29SRuslan Bukin free(section);
99*85f87cf4SRuslan Bukin
100*85f87cf4SRuslan Bukin errcode = -pte_bad_lock;
10174fe6c29SRuslan Bukin goto out_status;
10274fe6c29SRuslan Bukin }
10374fe6c29SRuslan Bukin
10474fe6c29SRuslan Bukin errcode = mtx_init(§ion->alock, mtx_plain);
10574fe6c29SRuslan Bukin if (errcode != thrd_success) {
10674fe6c29SRuslan Bukin mtx_destroy(§ion->lock);
10774fe6c29SRuslan Bukin free(section);
108*85f87cf4SRuslan Bukin
109*85f87cf4SRuslan Bukin errcode = -pte_bad_lock;
11074fe6c29SRuslan Bukin goto out_status;
11174fe6c29SRuslan Bukin }
11274fe6c29SRuslan Bukin
11374fe6c29SRuslan Bukin #endif /* defined(FEATURE_THREADS) */
11474fe6c29SRuslan Bukin
115*85f87cf4SRuslan Bukin *psection = section;
116*85f87cf4SRuslan Bukin return 0;
11774fe6c29SRuslan Bukin
11874fe6c29SRuslan Bukin out_status:
11974fe6c29SRuslan Bukin free(status);
120*85f87cf4SRuslan Bukin
121*85f87cf4SRuslan Bukin out_fname:
122*85f87cf4SRuslan Bukin free(fname);
123*85f87cf4SRuslan Bukin return errcode;
12474fe6c29SRuslan Bukin }
12574fe6c29SRuslan Bukin
pt_section_lock(struct pt_section * section)12674fe6c29SRuslan Bukin int pt_section_lock(struct pt_section *section)
12774fe6c29SRuslan Bukin {
12874fe6c29SRuslan Bukin if (!section)
12974fe6c29SRuslan Bukin return -pte_internal;
13074fe6c29SRuslan Bukin
13174fe6c29SRuslan Bukin #if defined(FEATURE_THREADS)
13274fe6c29SRuslan Bukin {
13374fe6c29SRuslan Bukin int errcode;
13474fe6c29SRuslan Bukin
13574fe6c29SRuslan Bukin errcode = mtx_lock(§ion->lock);
13674fe6c29SRuslan Bukin if (errcode != thrd_success)
13774fe6c29SRuslan Bukin return -pte_bad_lock;
13874fe6c29SRuslan Bukin }
13974fe6c29SRuslan Bukin #endif /* defined(FEATURE_THREADS) */
14074fe6c29SRuslan Bukin
14174fe6c29SRuslan Bukin return 0;
14274fe6c29SRuslan Bukin }
14374fe6c29SRuslan Bukin
pt_section_unlock(struct pt_section * section)14474fe6c29SRuslan Bukin int pt_section_unlock(struct pt_section *section)
14574fe6c29SRuslan Bukin {
14674fe6c29SRuslan Bukin if (!section)
14774fe6c29SRuslan Bukin return -pte_internal;
14874fe6c29SRuslan Bukin
14974fe6c29SRuslan Bukin #if defined(FEATURE_THREADS)
15074fe6c29SRuslan Bukin {
15174fe6c29SRuslan Bukin int errcode;
15274fe6c29SRuslan Bukin
15374fe6c29SRuslan Bukin errcode = mtx_unlock(§ion->lock);
15474fe6c29SRuslan Bukin if (errcode != thrd_success)
15574fe6c29SRuslan Bukin return -pte_bad_lock;
15674fe6c29SRuslan Bukin }
15774fe6c29SRuslan Bukin #endif /* defined(FEATURE_THREADS) */
15874fe6c29SRuslan Bukin
15974fe6c29SRuslan Bukin return 0;
16074fe6c29SRuslan Bukin }
16174fe6c29SRuslan Bukin
pt_section_free(struct pt_section * section)16274fe6c29SRuslan Bukin static void pt_section_free(struct pt_section *section)
16374fe6c29SRuslan Bukin {
16474fe6c29SRuslan Bukin if (!section)
16574fe6c29SRuslan Bukin return;
16674fe6c29SRuslan Bukin
16774fe6c29SRuslan Bukin #if defined(FEATURE_THREADS)
16874fe6c29SRuslan Bukin
16974fe6c29SRuslan Bukin mtx_destroy(§ion->alock);
17074fe6c29SRuslan Bukin mtx_destroy(§ion->lock);
17174fe6c29SRuslan Bukin
17274fe6c29SRuslan Bukin #endif /* defined(FEATURE_THREADS) */
17374fe6c29SRuslan Bukin
17474fe6c29SRuslan Bukin free(section->filename);
17574fe6c29SRuslan Bukin free(section->status);
17674fe6c29SRuslan Bukin free(section);
17774fe6c29SRuslan Bukin }
17874fe6c29SRuslan Bukin
pt_section_get(struct pt_section * section)17974fe6c29SRuslan Bukin int pt_section_get(struct pt_section *section)
18074fe6c29SRuslan Bukin {
18174fe6c29SRuslan Bukin uint16_t ucount;
18274fe6c29SRuslan Bukin int errcode;
18374fe6c29SRuslan Bukin
18474fe6c29SRuslan Bukin if (!section)
18574fe6c29SRuslan Bukin return -pte_internal;
18674fe6c29SRuslan Bukin
18774fe6c29SRuslan Bukin errcode = pt_section_lock(section);
18874fe6c29SRuslan Bukin if (errcode < 0)
18974fe6c29SRuslan Bukin return errcode;
19074fe6c29SRuslan Bukin
19174fe6c29SRuslan Bukin ucount = section->ucount + 1;
19274fe6c29SRuslan Bukin if (!ucount) {
19374fe6c29SRuslan Bukin (void) pt_section_unlock(section);
19474fe6c29SRuslan Bukin return -pte_overflow;
19574fe6c29SRuslan Bukin }
19674fe6c29SRuslan Bukin
19774fe6c29SRuslan Bukin section->ucount = ucount;
19874fe6c29SRuslan Bukin
19974fe6c29SRuslan Bukin return pt_section_unlock(section);
20074fe6c29SRuslan Bukin }
20174fe6c29SRuslan Bukin
pt_section_put(struct pt_section * section)20274fe6c29SRuslan Bukin int pt_section_put(struct pt_section *section)
20374fe6c29SRuslan Bukin {
20474fe6c29SRuslan Bukin uint16_t ucount, mcount;
20574fe6c29SRuslan Bukin int errcode;
20674fe6c29SRuslan Bukin
20774fe6c29SRuslan Bukin if (!section)
20874fe6c29SRuslan Bukin return -pte_internal;
20974fe6c29SRuslan Bukin
21074fe6c29SRuslan Bukin errcode = pt_section_lock(section);
21174fe6c29SRuslan Bukin if (errcode < 0)
21274fe6c29SRuslan Bukin return errcode;
21374fe6c29SRuslan Bukin
21474fe6c29SRuslan Bukin mcount = section->mcount;
21574fe6c29SRuslan Bukin ucount = section->ucount;
21674fe6c29SRuslan Bukin if (ucount > 1) {
21774fe6c29SRuslan Bukin section->ucount = ucount - 1;
21874fe6c29SRuslan Bukin return pt_section_unlock(section);
21974fe6c29SRuslan Bukin }
22074fe6c29SRuslan Bukin
22174fe6c29SRuslan Bukin errcode = pt_section_unlock(section);
22274fe6c29SRuslan Bukin if (errcode < 0)
22374fe6c29SRuslan Bukin return errcode;
22474fe6c29SRuslan Bukin
22574fe6c29SRuslan Bukin if (!ucount || mcount)
22674fe6c29SRuslan Bukin return -pte_internal;
22774fe6c29SRuslan Bukin
22874fe6c29SRuslan Bukin pt_section_free(section);
22974fe6c29SRuslan Bukin return 0;
23074fe6c29SRuslan Bukin }
23174fe6c29SRuslan Bukin
pt_section_lock_attach(struct pt_section * section)23274fe6c29SRuslan Bukin static int pt_section_lock_attach(struct pt_section *section)
23374fe6c29SRuslan Bukin {
23474fe6c29SRuslan Bukin if (!section)
23574fe6c29SRuslan Bukin return -pte_internal;
23674fe6c29SRuslan Bukin
23774fe6c29SRuslan Bukin #if defined(FEATURE_THREADS)
23874fe6c29SRuslan Bukin {
23974fe6c29SRuslan Bukin int errcode;
24074fe6c29SRuslan Bukin
24174fe6c29SRuslan Bukin errcode = mtx_lock(§ion->alock);
24274fe6c29SRuslan Bukin if (errcode != thrd_success)
24374fe6c29SRuslan Bukin return -pte_bad_lock;
24474fe6c29SRuslan Bukin }
24574fe6c29SRuslan Bukin #endif /* defined(FEATURE_THREADS) */
24674fe6c29SRuslan Bukin
24774fe6c29SRuslan Bukin return 0;
24874fe6c29SRuslan Bukin }
24974fe6c29SRuslan Bukin
pt_section_unlock_attach(struct pt_section * section)25074fe6c29SRuslan Bukin static int pt_section_unlock_attach(struct pt_section *section)
25174fe6c29SRuslan Bukin {
25274fe6c29SRuslan Bukin if (!section)
25374fe6c29SRuslan Bukin return -pte_internal;
25474fe6c29SRuslan Bukin
25574fe6c29SRuslan Bukin #if defined(FEATURE_THREADS)
25674fe6c29SRuslan Bukin {
25774fe6c29SRuslan Bukin int errcode;
25874fe6c29SRuslan Bukin
25974fe6c29SRuslan Bukin errcode = mtx_unlock(§ion->alock);
26074fe6c29SRuslan Bukin if (errcode != thrd_success)
26174fe6c29SRuslan Bukin return -pte_bad_lock;
26274fe6c29SRuslan Bukin }
26374fe6c29SRuslan Bukin #endif /* defined(FEATURE_THREADS) */
26474fe6c29SRuslan Bukin
26574fe6c29SRuslan Bukin return 0;
26674fe6c29SRuslan Bukin }
26774fe6c29SRuslan Bukin
pt_section_attach(struct pt_section * section,struct pt_image_section_cache * iscache)26874fe6c29SRuslan Bukin int pt_section_attach(struct pt_section *section,
26974fe6c29SRuslan Bukin struct pt_image_section_cache *iscache)
27074fe6c29SRuslan Bukin {
27174fe6c29SRuslan Bukin uint16_t acount, ucount;
27274fe6c29SRuslan Bukin int errcode;
27374fe6c29SRuslan Bukin
27474fe6c29SRuslan Bukin if (!section || !iscache)
27574fe6c29SRuslan Bukin return -pte_internal;
27674fe6c29SRuslan Bukin
27774fe6c29SRuslan Bukin errcode = pt_section_lock_attach(section);
27874fe6c29SRuslan Bukin if (errcode < 0)
27974fe6c29SRuslan Bukin return errcode;
28074fe6c29SRuslan Bukin
28174fe6c29SRuslan Bukin ucount = section->ucount;
28274fe6c29SRuslan Bukin acount = section->acount;
28374fe6c29SRuslan Bukin if (!acount) {
28474fe6c29SRuslan Bukin if (section->iscache || !ucount)
28574fe6c29SRuslan Bukin goto out_unlock;
28674fe6c29SRuslan Bukin
28774fe6c29SRuslan Bukin section->iscache = iscache;
28874fe6c29SRuslan Bukin section->acount = 1;
28974fe6c29SRuslan Bukin
29074fe6c29SRuslan Bukin return pt_section_unlock_attach(section);
29174fe6c29SRuslan Bukin }
29274fe6c29SRuslan Bukin
29374fe6c29SRuslan Bukin acount += 1;
29474fe6c29SRuslan Bukin if (!acount) {
29574fe6c29SRuslan Bukin (void) pt_section_unlock_attach(section);
29674fe6c29SRuslan Bukin return -pte_overflow;
29774fe6c29SRuslan Bukin }
29874fe6c29SRuslan Bukin
29974fe6c29SRuslan Bukin if (ucount < acount)
30074fe6c29SRuslan Bukin goto out_unlock;
30174fe6c29SRuslan Bukin
30274fe6c29SRuslan Bukin if (section->iscache != iscache)
30374fe6c29SRuslan Bukin goto out_unlock;
30474fe6c29SRuslan Bukin
30574fe6c29SRuslan Bukin section->acount = acount;
30674fe6c29SRuslan Bukin
30774fe6c29SRuslan Bukin return pt_section_unlock_attach(section);
30874fe6c29SRuslan Bukin
30974fe6c29SRuslan Bukin out_unlock:
31074fe6c29SRuslan Bukin (void) pt_section_unlock_attach(section);
31174fe6c29SRuslan Bukin return -pte_internal;
31274fe6c29SRuslan Bukin }
31374fe6c29SRuslan Bukin
pt_section_detach(struct pt_section * section,struct pt_image_section_cache * iscache)31474fe6c29SRuslan Bukin int pt_section_detach(struct pt_section *section,
31574fe6c29SRuslan Bukin struct pt_image_section_cache *iscache)
31674fe6c29SRuslan Bukin {
31774fe6c29SRuslan Bukin uint16_t acount, ucount;
31874fe6c29SRuslan Bukin int errcode;
31974fe6c29SRuslan Bukin
32074fe6c29SRuslan Bukin if (!section || !iscache)
32174fe6c29SRuslan Bukin return -pte_internal;
32274fe6c29SRuslan Bukin
32374fe6c29SRuslan Bukin errcode = pt_section_lock_attach(section);
32474fe6c29SRuslan Bukin if (errcode < 0)
32574fe6c29SRuslan Bukin return errcode;
32674fe6c29SRuslan Bukin
32774fe6c29SRuslan Bukin if (section->iscache != iscache)
32874fe6c29SRuslan Bukin goto out_unlock;
32974fe6c29SRuslan Bukin
33074fe6c29SRuslan Bukin acount = section->acount;
33174fe6c29SRuslan Bukin if (!acount)
33274fe6c29SRuslan Bukin goto out_unlock;
33374fe6c29SRuslan Bukin
33474fe6c29SRuslan Bukin acount -= 1;
33574fe6c29SRuslan Bukin ucount = section->ucount;
33674fe6c29SRuslan Bukin if (ucount < acount)
33774fe6c29SRuslan Bukin goto out_unlock;
33874fe6c29SRuslan Bukin
33974fe6c29SRuslan Bukin section->acount = acount;
34074fe6c29SRuslan Bukin if (!acount)
34174fe6c29SRuslan Bukin section->iscache = NULL;
34274fe6c29SRuslan Bukin
34374fe6c29SRuslan Bukin return pt_section_unlock_attach(section);
34474fe6c29SRuslan Bukin
34574fe6c29SRuslan Bukin out_unlock:
34674fe6c29SRuslan Bukin (void) pt_section_unlock_attach(section);
34774fe6c29SRuslan Bukin return -pte_internal;
34874fe6c29SRuslan Bukin }
34974fe6c29SRuslan Bukin
pt_section_filename(const struct pt_section * section)35074fe6c29SRuslan Bukin const char *pt_section_filename(const struct pt_section *section)
35174fe6c29SRuslan Bukin {
35274fe6c29SRuslan Bukin if (!section)
35374fe6c29SRuslan Bukin return NULL;
35474fe6c29SRuslan Bukin
35574fe6c29SRuslan Bukin return section->filename;
35674fe6c29SRuslan Bukin }
35774fe6c29SRuslan Bukin
pt_section_size(const struct pt_section * section)35874fe6c29SRuslan Bukin uint64_t pt_section_size(const struct pt_section *section)
35974fe6c29SRuslan Bukin {
36074fe6c29SRuslan Bukin if (!section)
36174fe6c29SRuslan Bukin return 0ull;
36274fe6c29SRuslan Bukin
36374fe6c29SRuslan Bukin return section->size;
36474fe6c29SRuslan Bukin }
36574fe6c29SRuslan Bukin
pt_section_bcache_memsize(const struct pt_section * section,uint64_t * psize)36674fe6c29SRuslan Bukin static int pt_section_bcache_memsize(const struct pt_section *section,
36774fe6c29SRuslan Bukin uint64_t *psize)
36874fe6c29SRuslan Bukin {
36974fe6c29SRuslan Bukin struct pt_block_cache *bcache;
37074fe6c29SRuslan Bukin
37174fe6c29SRuslan Bukin if (!section || !psize)
37274fe6c29SRuslan Bukin return -pte_internal;
37374fe6c29SRuslan Bukin
37474fe6c29SRuslan Bukin bcache = section->bcache;
37574fe6c29SRuslan Bukin if (!bcache) {
37674fe6c29SRuslan Bukin *psize = 0ull;
37774fe6c29SRuslan Bukin return 0;
37874fe6c29SRuslan Bukin }
37974fe6c29SRuslan Bukin
38074fe6c29SRuslan Bukin *psize = sizeof(*bcache) +
38174fe6c29SRuslan Bukin (bcache->nentries * sizeof(struct pt_bcache_entry));
38274fe6c29SRuslan Bukin
38374fe6c29SRuslan Bukin return 0;
38474fe6c29SRuslan Bukin }
38574fe6c29SRuslan Bukin
pt_section_memsize_locked(const struct pt_section * section,uint64_t * psize)38674fe6c29SRuslan Bukin static int pt_section_memsize_locked(const struct pt_section *section,
38774fe6c29SRuslan Bukin uint64_t *psize)
38874fe6c29SRuslan Bukin {
38974fe6c29SRuslan Bukin uint64_t msize, bcsize;
39074fe6c29SRuslan Bukin int (*memsize)(const struct pt_section *section, uint64_t *size);
39174fe6c29SRuslan Bukin int errcode;
39274fe6c29SRuslan Bukin
39374fe6c29SRuslan Bukin if (!section || !psize)
39474fe6c29SRuslan Bukin return -pte_internal;
39574fe6c29SRuslan Bukin
39674fe6c29SRuslan Bukin memsize = section->memsize;
39774fe6c29SRuslan Bukin if (!memsize) {
39874fe6c29SRuslan Bukin if (section->mcount)
39974fe6c29SRuslan Bukin return -pte_internal;
40074fe6c29SRuslan Bukin
40174fe6c29SRuslan Bukin *psize = 0ull;
40274fe6c29SRuslan Bukin return 0;
40374fe6c29SRuslan Bukin }
40474fe6c29SRuslan Bukin
40574fe6c29SRuslan Bukin errcode = memsize(section, &msize);
40674fe6c29SRuslan Bukin if (errcode < 0)
40774fe6c29SRuslan Bukin return errcode;
40874fe6c29SRuslan Bukin
40974fe6c29SRuslan Bukin errcode = pt_section_bcache_memsize(section, &bcsize);
41074fe6c29SRuslan Bukin if (errcode < 0)
41174fe6c29SRuslan Bukin return errcode;
41274fe6c29SRuslan Bukin
41374fe6c29SRuslan Bukin *psize = msize + bcsize;
41474fe6c29SRuslan Bukin
41574fe6c29SRuslan Bukin return 0;
41674fe6c29SRuslan Bukin }
41774fe6c29SRuslan Bukin
pt_section_memsize(struct pt_section * section,uint64_t * size)41874fe6c29SRuslan Bukin int pt_section_memsize(struct pt_section *section, uint64_t *size)
41974fe6c29SRuslan Bukin {
42074fe6c29SRuslan Bukin int errcode, status;
42174fe6c29SRuslan Bukin
42274fe6c29SRuslan Bukin errcode = pt_section_lock(section);
42374fe6c29SRuslan Bukin if (errcode < 0)
42474fe6c29SRuslan Bukin return errcode;
42574fe6c29SRuslan Bukin
42674fe6c29SRuslan Bukin status = pt_section_memsize_locked(section, size);
42774fe6c29SRuslan Bukin
42874fe6c29SRuslan Bukin errcode = pt_section_unlock(section);
42974fe6c29SRuslan Bukin if (errcode < 0)
43074fe6c29SRuslan Bukin return errcode;
43174fe6c29SRuslan Bukin
43274fe6c29SRuslan Bukin return status;
43374fe6c29SRuslan Bukin }
43474fe6c29SRuslan Bukin
pt_section_offset(const struct pt_section * section)43574fe6c29SRuslan Bukin uint64_t pt_section_offset(const struct pt_section *section)
43674fe6c29SRuslan Bukin {
43774fe6c29SRuslan Bukin if (!section)
43874fe6c29SRuslan Bukin return 0ull;
43974fe6c29SRuslan Bukin
44074fe6c29SRuslan Bukin return section->offset;
44174fe6c29SRuslan Bukin }
44274fe6c29SRuslan Bukin
pt_section_alloc_bcache(struct pt_section * section)44374fe6c29SRuslan Bukin int pt_section_alloc_bcache(struct pt_section *section)
44474fe6c29SRuslan Bukin {
44574fe6c29SRuslan Bukin struct pt_image_section_cache *iscache;
44674fe6c29SRuslan Bukin struct pt_block_cache *bcache;
44774fe6c29SRuslan Bukin uint64_t ssize, memsize;
44874fe6c29SRuslan Bukin uint32_t csize;
44974fe6c29SRuslan Bukin int errcode;
45074fe6c29SRuslan Bukin
45174fe6c29SRuslan Bukin if (!section)
45274fe6c29SRuslan Bukin return -pte_internal;
45374fe6c29SRuslan Bukin
45474fe6c29SRuslan Bukin if (!section->mcount)
45574fe6c29SRuslan Bukin return -pte_internal;
45674fe6c29SRuslan Bukin
45774fe6c29SRuslan Bukin ssize = pt_section_size(section);
45874fe6c29SRuslan Bukin csize = (uint32_t) ssize;
45974fe6c29SRuslan Bukin
46074fe6c29SRuslan Bukin if (csize != ssize)
46174fe6c29SRuslan Bukin return -pte_not_supported;
46274fe6c29SRuslan Bukin
46374fe6c29SRuslan Bukin memsize = 0ull;
46474fe6c29SRuslan Bukin
46574fe6c29SRuslan Bukin /* We need to take both the attach and the section lock in order to pair
46674fe6c29SRuslan Bukin * the block cache allocation and the resize notification.
46774fe6c29SRuslan Bukin *
46874fe6c29SRuslan Bukin * This allows map notifications in between but they only change the
46974fe6c29SRuslan Bukin * order of sections in the cache.
47074fe6c29SRuslan Bukin *
47174fe6c29SRuslan Bukin * The attach lock needs to be taken first.
47274fe6c29SRuslan Bukin */
47374fe6c29SRuslan Bukin errcode = pt_section_lock_attach(section);
47474fe6c29SRuslan Bukin if (errcode < 0)
47574fe6c29SRuslan Bukin return errcode;
47674fe6c29SRuslan Bukin
47774fe6c29SRuslan Bukin errcode = pt_section_lock(section);
47874fe6c29SRuslan Bukin if (errcode < 0)
47974fe6c29SRuslan Bukin goto out_alock;
48074fe6c29SRuslan Bukin
48174fe6c29SRuslan Bukin bcache = pt_section_bcache(section);
48274fe6c29SRuslan Bukin if (bcache) {
48374fe6c29SRuslan Bukin errcode = 0;
48474fe6c29SRuslan Bukin goto out_lock;
48574fe6c29SRuslan Bukin }
48674fe6c29SRuslan Bukin
48774fe6c29SRuslan Bukin bcache = pt_bcache_alloc(csize);
48874fe6c29SRuslan Bukin if (!bcache) {
48974fe6c29SRuslan Bukin errcode = -pte_nomem;
49074fe6c29SRuslan Bukin goto out_lock;
49174fe6c29SRuslan Bukin }
49274fe6c29SRuslan Bukin
49374fe6c29SRuslan Bukin /* Install the block cache. It will become visible and may be used
49474fe6c29SRuslan Bukin * immediately.
49574fe6c29SRuslan Bukin *
49674fe6c29SRuslan Bukin * If we fail later on, we leave the block cache and report the error to
49774fe6c29SRuslan Bukin * the allocating decoder thread.
49874fe6c29SRuslan Bukin */
49974fe6c29SRuslan Bukin section->bcache = bcache;
50074fe6c29SRuslan Bukin
50174fe6c29SRuslan Bukin errcode = pt_section_memsize_locked(section, &memsize);
50274fe6c29SRuslan Bukin if (errcode < 0)
50374fe6c29SRuslan Bukin goto out_lock;
50474fe6c29SRuslan Bukin
50574fe6c29SRuslan Bukin errcode = pt_section_unlock(section);
50674fe6c29SRuslan Bukin if (errcode < 0)
50774fe6c29SRuslan Bukin goto out_alock;
50874fe6c29SRuslan Bukin
50974fe6c29SRuslan Bukin if (memsize) {
51074fe6c29SRuslan Bukin iscache = section->iscache;
51174fe6c29SRuslan Bukin if (iscache) {
51274fe6c29SRuslan Bukin errcode = pt_iscache_notify_resize(iscache, section,
51374fe6c29SRuslan Bukin memsize);
51474fe6c29SRuslan Bukin if (errcode < 0)
51574fe6c29SRuslan Bukin goto out_alock;
51674fe6c29SRuslan Bukin }
51774fe6c29SRuslan Bukin }
51874fe6c29SRuslan Bukin
51974fe6c29SRuslan Bukin return pt_section_unlock_attach(section);
52074fe6c29SRuslan Bukin
52174fe6c29SRuslan Bukin
52274fe6c29SRuslan Bukin out_lock:
52374fe6c29SRuslan Bukin (void) pt_section_unlock(section);
52474fe6c29SRuslan Bukin
52574fe6c29SRuslan Bukin out_alock:
52674fe6c29SRuslan Bukin (void) pt_section_unlock_attach(section);
52774fe6c29SRuslan Bukin return errcode;
52874fe6c29SRuslan Bukin }
52974fe6c29SRuslan Bukin
pt_section_on_map_lock(struct pt_section * section)53074fe6c29SRuslan Bukin int pt_section_on_map_lock(struct pt_section *section)
53174fe6c29SRuslan Bukin {
53274fe6c29SRuslan Bukin struct pt_image_section_cache *iscache;
53374fe6c29SRuslan Bukin int errcode, status;
53474fe6c29SRuslan Bukin
53574fe6c29SRuslan Bukin if (!section)
53674fe6c29SRuslan Bukin return -pte_internal;
53774fe6c29SRuslan Bukin
53874fe6c29SRuslan Bukin errcode = pt_section_lock_attach(section);
53974fe6c29SRuslan Bukin if (errcode < 0)
54074fe6c29SRuslan Bukin return errcode;
54174fe6c29SRuslan Bukin
54274fe6c29SRuslan Bukin iscache = section->iscache;
54374fe6c29SRuslan Bukin if (!iscache)
54474fe6c29SRuslan Bukin return pt_section_unlock_attach(section);
54574fe6c29SRuslan Bukin
54674fe6c29SRuslan Bukin /* There is a potential deadlock when @section was unmapped again and
54774fe6c29SRuslan Bukin * @iscache tries to map it. This would cause this function to be
54874fe6c29SRuslan Bukin * re-entered while we're still holding the attach lock.
54974fe6c29SRuslan Bukin *
55074fe6c29SRuslan Bukin * This scenario is very unlikely, though, since our caller does not yet
55174fe6c29SRuslan Bukin * know whether pt_section_map() succeeded.
55274fe6c29SRuslan Bukin */
55374fe6c29SRuslan Bukin status = pt_iscache_notify_map(iscache, section);
55474fe6c29SRuslan Bukin
55574fe6c29SRuslan Bukin errcode = pt_section_unlock_attach(section);
55674fe6c29SRuslan Bukin if (errcode < 0)
55774fe6c29SRuslan Bukin return errcode;
55874fe6c29SRuslan Bukin
55974fe6c29SRuslan Bukin return status;
56074fe6c29SRuslan Bukin }
56174fe6c29SRuslan Bukin
pt_section_map_share(struct pt_section * section)56274fe6c29SRuslan Bukin int pt_section_map_share(struct pt_section *section)
56374fe6c29SRuslan Bukin {
56474fe6c29SRuslan Bukin uint16_t mcount;
56574fe6c29SRuslan Bukin int errcode;
56674fe6c29SRuslan Bukin
56774fe6c29SRuslan Bukin if (!section)
56874fe6c29SRuslan Bukin return -pte_internal;
56974fe6c29SRuslan Bukin
57074fe6c29SRuslan Bukin errcode = pt_section_lock(section);
57174fe6c29SRuslan Bukin if (errcode < 0)
57274fe6c29SRuslan Bukin return errcode;
57374fe6c29SRuslan Bukin
57474fe6c29SRuslan Bukin mcount = section->mcount;
57574fe6c29SRuslan Bukin if (!mcount) {
57674fe6c29SRuslan Bukin (void) pt_section_unlock(section);
57774fe6c29SRuslan Bukin return -pte_internal;
57874fe6c29SRuslan Bukin }
57974fe6c29SRuslan Bukin
58074fe6c29SRuslan Bukin mcount += 1;
58174fe6c29SRuslan Bukin if (!mcount) {
58274fe6c29SRuslan Bukin (void) pt_section_unlock(section);
58374fe6c29SRuslan Bukin return -pte_overflow;
58474fe6c29SRuslan Bukin }
58574fe6c29SRuslan Bukin
58674fe6c29SRuslan Bukin section->mcount = mcount;
58774fe6c29SRuslan Bukin
58874fe6c29SRuslan Bukin return pt_section_unlock(section);
58974fe6c29SRuslan Bukin }
59074fe6c29SRuslan Bukin
pt_section_unmap(struct pt_section * section)59174fe6c29SRuslan Bukin int pt_section_unmap(struct pt_section *section)
59274fe6c29SRuslan Bukin {
59374fe6c29SRuslan Bukin uint16_t mcount;
59474fe6c29SRuslan Bukin int errcode, status;
59574fe6c29SRuslan Bukin
59674fe6c29SRuslan Bukin if (!section)
59774fe6c29SRuslan Bukin return -pte_internal;
59874fe6c29SRuslan Bukin
59974fe6c29SRuslan Bukin errcode = pt_section_lock(section);
60074fe6c29SRuslan Bukin if (errcode < 0)
60174fe6c29SRuslan Bukin return errcode;
60274fe6c29SRuslan Bukin
60374fe6c29SRuslan Bukin mcount = section->mcount;
60474fe6c29SRuslan Bukin
60574fe6c29SRuslan Bukin errcode = -pte_nomap;
60674fe6c29SRuslan Bukin if (!mcount)
60774fe6c29SRuslan Bukin goto out_unlock;
60874fe6c29SRuslan Bukin
60974fe6c29SRuslan Bukin section->mcount = mcount -= 1;
61074fe6c29SRuslan Bukin if (mcount)
61174fe6c29SRuslan Bukin return pt_section_unlock(section);
61274fe6c29SRuslan Bukin
61374fe6c29SRuslan Bukin errcode = -pte_internal;
61474fe6c29SRuslan Bukin if (!section->unmap)
61574fe6c29SRuslan Bukin goto out_unlock;
61674fe6c29SRuslan Bukin
61774fe6c29SRuslan Bukin status = section->unmap(section);
61874fe6c29SRuslan Bukin
61974fe6c29SRuslan Bukin pt_bcache_free(section->bcache);
62074fe6c29SRuslan Bukin section->bcache = NULL;
62174fe6c29SRuslan Bukin
62274fe6c29SRuslan Bukin errcode = pt_section_unlock(section);
62374fe6c29SRuslan Bukin if (errcode < 0)
62474fe6c29SRuslan Bukin return errcode;
62574fe6c29SRuslan Bukin
62674fe6c29SRuslan Bukin return status;
62774fe6c29SRuslan Bukin
62874fe6c29SRuslan Bukin out_unlock:
62974fe6c29SRuslan Bukin (void) pt_section_unlock(section);
63074fe6c29SRuslan Bukin return errcode;
63174fe6c29SRuslan Bukin }
63274fe6c29SRuslan Bukin
pt_section_read(const struct pt_section * section,uint8_t * buffer,uint16_t size,uint64_t offset)63374fe6c29SRuslan Bukin int pt_section_read(const struct pt_section *section, uint8_t *buffer,
63474fe6c29SRuslan Bukin uint16_t size, uint64_t offset)
63574fe6c29SRuslan Bukin {
63674fe6c29SRuslan Bukin uint64_t limit, space;
63774fe6c29SRuslan Bukin
63874fe6c29SRuslan Bukin if (!section)
63974fe6c29SRuslan Bukin return -pte_internal;
64074fe6c29SRuslan Bukin
64174fe6c29SRuslan Bukin if (!section->read)
64274fe6c29SRuslan Bukin return -pte_nomap;
64374fe6c29SRuslan Bukin
64474fe6c29SRuslan Bukin limit = section->size;
64574fe6c29SRuslan Bukin if (limit <= offset)
64674fe6c29SRuslan Bukin return -pte_nomap;
64774fe6c29SRuslan Bukin
64874fe6c29SRuslan Bukin /* Truncate if we try to read past the end of the section. */
64974fe6c29SRuslan Bukin space = limit - offset;
65074fe6c29SRuslan Bukin if (space < size)
65174fe6c29SRuslan Bukin size = (uint16_t) space;
65274fe6c29SRuslan Bukin
65374fe6c29SRuslan Bukin return section->read(section, buffer, size, offset);
65474fe6c29SRuslan Bukin }
655