1/*
2 * Power ISA decode for misc instructions
3 *
4 * Copyright (c) 2024, IBM Corporation.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21 * Memory Barrier Instructions
22 */
23
24static bool trans_SYNC(DisasContext *ctx, arg_X_sync *a)
25{
26    TCGBar bar = TCG_MO_ALL;
27    uint32_t l = a->l;
28
29    /*
30     * BookE uses the msync mnemonic. This means hwsync, except in the
31     * 440, where it an execution serialisation point that requires all
32     * previous storage accesses to have been performed to memory (which
33     * doesn't matter for TCG).
34     */
35    if (!(ctx->insns_flags & PPC_MEM_SYNC)) {
36        if (ctx->insns_flags & PPC_BOOKE) {
37            /* msync replaces sync on 440, interpreted as nop */
38            /* XXX: this also catches e200 */
39            return true;
40        }
41
42        return false;
43    }
44
45    if ((l == 1) && (ctx->insns_flags2 & PPC2_MEM_LWSYNC)) {
46        bar = TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST;
47    }
48
49    /*
50     * We may need to check for a pending TLB flush.
51     *
52     * We do this on ptesync (l == 2) on ppc64 and any sync on ppc32.
53     *
54     * Additionally, this can only happen in kernel mode however so
55     * check MSR_PR as well.
56     */
57    if (((l == 2) || !(ctx->insns_flags & PPC_64B)) && !ctx->pr) {
58        gen_check_tlb_flush(ctx, true);
59    }
60
61    tcg_gen_mb(bar | TCG_BAR_SC);
62
63    return true;
64}
65
66static bool trans_EIEIO(DisasContext *ctx, arg_EIEIO *a)
67{
68    TCGBar bar = TCG_MO_ALL;
69
70    /*
71     * BookE uses the mbar instruction instead of eieio, which is basically
72     * full hwsync memory barrier, but is not execution synchronising. For
73     * the purpose of TCG the distinction is not relevant.
74     */
75    if (!(ctx->insns_flags & PPC_MEM_EIEIO)) {
76        if ((ctx->insns_flags & PPC_BOOKE) ||
77            (ctx->insns_flags2 & PPC2_BOOKE206)) {
78            return true;
79        }
80        return false;
81    }
82
83    /*
84     * eieio has complex semanitcs. It provides memory ordering between
85     * operations in the set:
86     * - loads from CI memory.
87     * - stores to CI memory.
88     * - stores to WT memory.
89     *
90     * It separately also orders memory for operations in the set:
91     * - stores to cacheble memory.
92     *
93     * It also serializes instructions:
94     * - dcbt and dcbst.
95     *
96     * It separately serializes:
97     * - tlbie and tlbsync.
98     *
99     * And separately serializes:
100     * - slbieg, slbiag, and slbsync.
101     *
102     * The end result is that CI memory ordering requires TCG_MO_ALL
103     * and it is not possible to special-case more relaxed ordering for
104     * cacheable accesses. TCG_BAR_SC is required to provide this
105     * serialization.
106     */
107
108    /*
109     * POWER9 has a eieio instruction variant using bit 6 as a hint to
110     * tell the CPU it is a store-forwarding barrier.
111     */
112    if (ctx->opcode & 0x2000000) {
113        /*
114         * ISA says that "Reserved fields in instructions are ignored
115         * by the processor". So ignore the bit 6 on non-POWER9 CPU but
116         * as this is not an instruction software should be using,
117         * complain to the user.
118         */
119        if (!(ctx->insns_flags2 & PPC2_ISA300)) {
120            qemu_log_mask(LOG_GUEST_ERROR, "invalid eieio using bit 6 at @"
121                          TARGET_FMT_lx "\n", ctx->cia);
122        } else {
123            bar = TCG_MO_ST_LD;
124        }
125    }
126
127    tcg_gen_mb(bar | TCG_BAR_SC);
128
129    return true;
130}
131