xref: /openbmc/qemu/target/xtensa/op_helper.c (revision d044b7c3)
1 /*
2  * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the Open Source and Linux Lab nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "qemu/osdep.h"
29 #include "qemu/main-loop.h"
30 #include "cpu.h"
31 #include "exec/helper-proto.h"
32 #include "qemu/host-utils.h"
33 #include "exec/exec-all.h"
34 #include "exec/cpu_ldst.h"
35 #include "qemu/timer.h"
36 
37 #ifndef CONFIG_USER_ONLY
38 
39 void HELPER(update_ccount)(CPUXtensaState *env)
40 {
41     XtensaCPU *cpu = XTENSA_CPU(env_cpu(env));
42     uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
43 
44     env->ccount_time = now;
45     env->sregs[CCOUNT] = env->ccount_base +
46         (uint32_t)clock_ns_to_ticks(cpu->clock, now - env->time_base);
47 }
48 
49 void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v)
50 {
51     int i;
52 
53     HELPER(update_ccount)(env);
54     env->ccount_base += v - env->sregs[CCOUNT];
55     for (i = 0; i < env->config->nccompare; ++i) {
56         HELPER(update_ccompare)(env, i);
57     }
58 }
59 
60 void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i)
61 {
62     XtensaCPU *cpu = XTENSA_CPU(env_cpu(env));
63     uint64_t dcc;
64 
65     qatomic_and(&env->sregs[INTSET],
66                ~(1u << env->config->timerint[i]));
67     HELPER(update_ccount)(env);
68     dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1;
69     timer_mod(env->ccompare[i].timer,
70               env->ccount_time + clock_ticks_to_ns(cpu->clock, dcc));
71     env->yield_needed = 1;
72 }
73 
74 /*!
75  * Check vaddr accessibility/cache attributes and raise an exception if
76  * specified by the ATOMCTL SR.
77  *
78  * Note: local memory exclusion is not implemented
79  */
80 void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr)
81 {
82     uint32_t paddr, page_size, access;
83     uint32_t atomctl = env->sregs[ATOMCTL];
84     int rc = xtensa_get_physical_addr(env, true, vaddr, 1,
85             xtensa_get_cring(env), &paddr, &page_size, &access);
86 
87     /*
88      * s32c1i never causes LOAD_PROHIBITED_CAUSE exceptions,
89      * see opcode description in the ISA
90      */
91     if (rc == 0 &&
92             (access & (PAGE_READ | PAGE_WRITE)) != (PAGE_READ | PAGE_WRITE)) {
93         rc = STORE_PROHIBITED_CAUSE;
94     }
95 
96     if (rc) {
97         HELPER(exception_cause_vaddr)(env, pc, rc, vaddr);
98     }
99 
100     /*
101      * When data cache is not configured use ATOMCTL bypass field.
102      * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL)
103      * under the Conditional Store Option.
104      */
105     if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
106         access = PAGE_CACHE_BYPASS;
107     }
108 
109     switch (access & PAGE_CACHE_MASK) {
110     case PAGE_CACHE_WB:
111         atomctl >>= 2;
112         /* fall through */
113     case PAGE_CACHE_WT:
114         atomctl >>= 2;
115         /* fall through */
116     case PAGE_CACHE_BYPASS:
117         if ((atomctl & 0x3) == 0) {
118             HELPER(exception_cause_vaddr)(env, pc,
119                     LOAD_STORE_ERROR_CAUSE, vaddr);
120         }
121         break;
122 
123     case PAGE_CACHE_ISOLATE:
124         HELPER(exception_cause_vaddr)(env, pc,
125                 LOAD_STORE_ERROR_CAUSE, vaddr);
126         break;
127 
128     default:
129         break;
130     }
131 }
132 
133 void HELPER(check_exclusive)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr,
134                              uint32_t is_write)
135 {
136     uint32_t paddr, page_size, access;
137     uint32_t atomctl = env->sregs[ATOMCTL];
138     int rc = xtensa_get_physical_addr(env, true, vaddr, is_write,
139                                       xtensa_get_cring(env), &paddr,
140                                       &page_size, &access);
141 
142     if (rc) {
143         HELPER(exception_cause_vaddr)(env, pc, rc, vaddr);
144     }
145 
146     /* When data cache is not configured use ATOMCTL bypass field. */
147     if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
148         access = PAGE_CACHE_BYPASS;
149     }
150 
151     switch (access & PAGE_CACHE_MASK) {
152     case PAGE_CACHE_WB:
153         atomctl >>= 2;
154         /* fall through */
155     case PAGE_CACHE_WT:
156         atomctl >>= 2;
157         /* fall through */
158     case PAGE_CACHE_BYPASS:
159         if ((atomctl & 0x3) == 0) {
160             HELPER(exception_cause_vaddr)(env, pc,
161                                           EXCLUSIVE_ERROR_CAUSE, vaddr);
162         }
163         break;
164 
165     case PAGE_CACHE_ISOLATE:
166         HELPER(exception_cause_vaddr)(env, pc,
167                 LOAD_STORE_ERROR_CAUSE, vaddr);
168         break;
169 
170     default:
171         break;
172     }
173 }
174 
175 void HELPER(wsr_memctl)(CPUXtensaState *env, uint32_t v)
176 {
177     if (xtensa_option_enabled(env->config, XTENSA_OPTION_ICACHE)) {
178         if (extract32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN) >
179             env->config->icache_ways) {
180             deposit32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN,
181                       env->config->icache_ways);
182         }
183     }
184     if (xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
185         if (extract32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN) >
186             env->config->dcache_ways) {
187             deposit32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN,
188                       env->config->dcache_ways);
189         }
190         if (extract32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN) >
191             env->config->dcache_ways) {
192             deposit32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN,
193                       env->config->dcache_ways);
194         }
195     }
196     env->sregs[MEMCTL] = v & env->config->memctl_mask;
197 }
198 
199 #endif
200 
201 uint32_t HELPER(rer)(CPUXtensaState *env, uint32_t addr)
202 {
203 #ifndef CONFIG_USER_ONLY
204     return address_space_ldl(env->address_space_er, addr,
205                              MEMTXATTRS_UNSPECIFIED, NULL);
206 #else
207     return 0;
208 #endif
209 }
210 
211 void HELPER(wer)(CPUXtensaState *env, uint32_t data, uint32_t addr)
212 {
213 #ifndef CONFIG_USER_ONLY
214     address_space_stl(env->address_space_er, addr, data,
215                       MEMTXATTRS_UNSPECIFIED, NULL);
216 #endif
217 }
218