xref: /openbmc/qemu/target/i386/tcg/access.c (revision 2eefd4fcec4b8fe41ceee2a8f00cdec1fe81b75c)
124f68139SRichard Henderson /* SPDX-License-Identifier: GPL-2.0-or-later */
224f68139SRichard Henderson /* Access guest memory in blocks. */
324f68139SRichard Henderson 
424f68139SRichard Henderson #include "qemu/osdep.h"
524f68139SRichard Henderson #include "cpu.h"
624f68139SRichard Henderson #include "exec/cpu_ldst.h"
724f68139SRichard Henderson #include "exec/exec-all.h"
824f68139SRichard Henderson #include "access.h"
924f68139SRichard Henderson 
1024f68139SRichard Henderson 
access_prepare_mmu(X86Access * ret,CPUX86State * env,vaddr vaddr,unsigned size,MMUAccessType type,int mmu_idx,uintptr_t ra)1124f68139SRichard Henderson void access_prepare_mmu(X86Access *ret, CPUX86State *env,
1224f68139SRichard Henderson                         vaddr vaddr, unsigned size,
1324f68139SRichard Henderson                         MMUAccessType type, int mmu_idx, uintptr_t ra)
1424f68139SRichard Henderson {
1524f68139SRichard Henderson     int size1, size2;
1624f68139SRichard Henderson     void *haddr1, *haddr2;
1724f68139SRichard Henderson 
1824f68139SRichard Henderson     assert(size > 0 && size <= TARGET_PAGE_SIZE);
1924f68139SRichard Henderson 
2024f68139SRichard Henderson     size1 = MIN(size, -(vaddr | TARGET_PAGE_MASK)),
2124f68139SRichard Henderson     size2 = size - size1;
2224f68139SRichard Henderson 
2324f68139SRichard Henderson     memset(ret, 0, sizeof(*ret));
2424f68139SRichard Henderson     ret->vaddr = vaddr;
2524f68139SRichard Henderson     ret->size = size;
2624f68139SRichard Henderson     ret->size1 = size1;
2724f68139SRichard Henderson     ret->mmu_idx = mmu_idx;
2824f68139SRichard Henderson     ret->env = env;
2924f68139SRichard Henderson     ret->ra = ra;
3024f68139SRichard Henderson 
3124f68139SRichard Henderson     haddr1 = probe_access(env, vaddr, size1, type, mmu_idx, ra);
3224f68139SRichard Henderson     ret->haddr1 = haddr1;
3324f68139SRichard Henderson 
3424f68139SRichard Henderson     if (unlikely(size2)) {
3524f68139SRichard Henderson         haddr2 = probe_access(env, vaddr + size1, size2, type, mmu_idx, ra);
3624f68139SRichard Henderson         if (haddr2 == haddr1 + size1) {
3724f68139SRichard Henderson             ret->size1 = size;
3824f68139SRichard Henderson         } else {
3924f68139SRichard Henderson #ifdef CONFIG_USER_ONLY
4024f68139SRichard Henderson             g_assert_not_reached();
4124f68139SRichard Henderson #else
4224f68139SRichard Henderson             ret->haddr2 = haddr2;
4324f68139SRichard Henderson #endif
4424f68139SRichard Henderson         }
4524f68139SRichard Henderson     }
4624f68139SRichard Henderson }
4724f68139SRichard Henderson 
access_prepare(X86Access * ret,CPUX86State * env,vaddr vaddr,unsigned size,MMUAccessType type,uintptr_t ra)4824f68139SRichard Henderson void access_prepare(X86Access *ret, CPUX86State *env, vaddr vaddr,
4924f68139SRichard Henderson                     unsigned size, MMUAccessType type, uintptr_t ra)
5024f68139SRichard Henderson {
5124f68139SRichard Henderson     int mmu_idx = cpu_mmu_index(env_cpu(env), false);
5224f68139SRichard Henderson     access_prepare_mmu(ret, env, vaddr, size, type, mmu_idx, ra);
5324f68139SRichard Henderson }
5424f68139SRichard Henderson 
access_ptr(X86Access * ac,vaddr addr,unsigned len)5524f68139SRichard Henderson static void *access_ptr(X86Access *ac, vaddr addr, unsigned len)
5624f68139SRichard Henderson {
5724f68139SRichard Henderson     vaddr offset = addr - ac->vaddr;
5824f68139SRichard Henderson 
5924f68139SRichard Henderson     assert(addr >= ac->vaddr);
6024f68139SRichard Henderson 
61*cf584a90SAlex Bennée     /* No haddr means probe_access wants to force slow path */
62*cf584a90SAlex Bennée     if (!ac->haddr1) {
63*cf584a90SAlex Bennée         return NULL;
64*cf584a90SAlex Bennée     }
65*cf584a90SAlex Bennée 
6624f68139SRichard Henderson #ifdef CONFIG_USER_ONLY
6724f68139SRichard Henderson     assert(offset <= ac->size1 - len);
6824f68139SRichard Henderson     return ac->haddr1 + offset;
6924f68139SRichard Henderson #else
7024f68139SRichard Henderson     if (likely(offset <= ac->size1 - len)) {
7124f68139SRichard Henderson         return ac->haddr1 + offset;
7224f68139SRichard Henderson     }
7324f68139SRichard Henderson     assert(offset <= ac->size - len);
7424f68139SRichard Henderson     /*
7524f68139SRichard Henderson      * If the address is not naturally aligned, it might span both pages.
7624f68139SRichard Henderson      * Only return ac->haddr2 if the area is entirely within the second page,
7724f68139SRichard Henderson      * otherwise fall back to slow accesses.
7824f68139SRichard Henderson      */
7924f68139SRichard Henderson     if (likely(offset >= ac->size1)) {
8024f68139SRichard Henderson         return ac->haddr2 + (offset - ac->size1);
8124f68139SRichard Henderson     }
8224f68139SRichard Henderson     return NULL;
8324f68139SRichard Henderson #endif
8424f68139SRichard Henderson }
8524f68139SRichard Henderson 
access_ldb(X86Access * ac,vaddr addr)8624f68139SRichard Henderson uint8_t access_ldb(X86Access *ac, vaddr addr)
8724f68139SRichard Henderson {
8824f68139SRichard Henderson     void *p = access_ptr(ac, addr, sizeof(uint8_t));
8924f68139SRichard Henderson 
90*cf584a90SAlex Bennée     if (likely(p)) {
9124f68139SRichard Henderson         return ldub_p(p);
9224f68139SRichard Henderson     }
9324f68139SRichard Henderson     return cpu_ldub_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
9424f68139SRichard Henderson }
9524f68139SRichard Henderson 
access_ldw(X86Access * ac,vaddr addr)9624f68139SRichard Henderson uint16_t access_ldw(X86Access *ac, vaddr addr)
9724f68139SRichard Henderson {
9824f68139SRichard Henderson     void *p = access_ptr(ac, addr, sizeof(uint16_t));
9924f68139SRichard Henderson 
100*cf584a90SAlex Bennée     if (likely(p)) {
10124f68139SRichard Henderson         return lduw_le_p(p);
10224f68139SRichard Henderson     }
10324f68139SRichard Henderson     return cpu_lduw_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
10424f68139SRichard Henderson }
10524f68139SRichard Henderson 
access_ldl(X86Access * ac,vaddr addr)10624f68139SRichard Henderson uint32_t access_ldl(X86Access *ac, vaddr addr)
10724f68139SRichard Henderson {
10824f68139SRichard Henderson     void *p = access_ptr(ac, addr, sizeof(uint32_t));
10924f68139SRichard Henderson 
110*cf584a90SAlex Bennée     if (likely(p)) {
11124f68139SRichard Henderson         return ldl_le_p(p);
11224f68139SRichard Henderson     }
11324f68139SRichard Henderson     return cpu_ldl_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
11424f68139SRichard Henderson }
11524f68139SRichard Henderson 
access_ldq(X86Access * ac,vaddr addr)11624f68139SRichard Henderson uint64_t access_ldq(X86Access *ac, vaddr addr)
11724f68139SRichard Henderson {
11824f68139SRichard Henderson     void *p = access_ptr(ac, addr, sizeof(uint64_t));
11924f68139SRichard Henderson 
120*cf584a90SAlex Bennée     if (likely(p)) {
12124f68139SRichard Henderson         return ldq_le_p(p);
12224f68139SRichard Henderson     }
12324f68139SRichard Henderson     return cpu_ldq_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra);
12424f68139SRichard Henderson }
12524f68139SRichard Henderson 
access_stb(X86Access * ac,vaddr addr,uint8_t val)12624f68139SRichard Henderson void access_stb(X86Access *ac, vaddr addr, uint8_t val)
12724f68139SRichard Henderson {
12824f68139SRichard Henderson     void *p = access_ptr(ac, addr, sizeof(uint8_t));
12924f68139SRichard Henderson 
130*cf584a90SAlex Bennée     if (likely(p)) {
13124f68139SRichard Henderson         stb_p(p, val);
13224f68139SRichard Henderson     } else {
13324f68139SRichard Henderson         cpu_stb_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
13424f68139SRichard Henderson     }
13524f68139SRichard Henderson }
13624f68139SRichard Henderson 
access_stw(X86Access * ac,vaddr addr,uint16_t val)13724f68139SRichard Henderson void access_stw(X86Access *ac, vaddr addr, uint16_t val)
13824f68139SRichard Henderson {
13924f68139SRichard Henderson     void *p = access_ptr(ac, addr, sizeof(uint16_t));
14024f68139SRichard Henderson 
141*cf584a90SAlex Bennée     if (likely(p)) {
14224f68139SRichard Henderson         stw_le_p(p, val);
14324f68139SRichard Henderson     } else {
14424f68139SRichard Henderson         cpu_stw_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
14524f68139SRichard Henderson     }
14624f68139SRichard Henderson }
14724f68139SRichard Henderson 
access_stl(X86Access * ac,vaddr addr,uint32_t val)14824f68139SRichard Henderson void access_stl(X86Access *ac, vaddr addr, uint32_t val)
14924f68139SRichard Henderson {
15024f68139SRichard Henderson     void *p = access_ptr(ac, addr, sizeof(uint32_t));
15124f68139SRichard Henderson 
152*cf584a90SAlex Bennée     if (likely(p)) {
15324f68139SRichard Henderson         stl_le_p(p, val);
15424f68139SRichard Henderson     } else {
15524f68139SRichard Henderson         cpu_stl_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
15624f68139SRichard Henderson     }
15724f68139SRichard Henderson }
15824f68139SRichard Henderson 
access_stq(X86Access * ac,vaddr addr,uint64_t val)15924f68139SRichard Henderson void access_stq(X86Access *ac, vaddr addr, uint64_t val)
16024f68139SRichard Henderson {
16124f68139SRichard Henderson     void *p = access_ptr(ac, addr, sizeof(uint64_t));
16224f68139SRichard Henderson 
163*cf584a90SAlex Bennée     if (likely(p)) {
16424f68139SRichard Henderson         stq_le_p(p, val);
16524f68139SRichard Henderson     } else {
16624f68139SRichard Henderson         cpu_stq_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra);
16724f68139SRichard Henderson     }
16824f68139SRichard Henderson }
169