1 /*
2  * Copyright (c) 2008 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #pragma once
9 
10 #include <stdint.h>
11 
12 // Low level macros for accessing memory mapped hardware registers
13 
14 // Each architecture has an ability to provide their own specific accessors, or use the default
15 #include <arch/reg.h>
16 
17 // Newer style accessors, generally preferred due to virtual machine virtualization.
18 //
19 // If the arch didn't override it, use the default
20 #if !ARCH_MMIO_READ_WRITE_OVERRIDE
21 #define _MMIO_READ_DEFAULT(ptr) *ptr
22 #define _MMIO_WRITE_DEFAULT(ptr, val) *ptr = val
23 
24 #define _ARCH_MMIO_READ8 _MMIO_READ_DEFAULT
25 #define _ARCH_MMIO_READ16 _MMIO_READ_DEFAULT
26 #define _ARCH_MMIO_READ32 _MMIO_READ_DEFAULT
27 #define _ARCH_MMIO_READ64 _MMIO_READ_DEFAULT
28 #define _ARCH_MMIO_WRITE8 _MMIO_WRITE_DEFAULT
29 #define _ARCH_MMIO_WRITE16 _MMIO_WRITE_DEFAULT
30 #define _ARCH_MMIO_WRITE32 _MMIO_WRITE_DEFAULT
31 #define _ARCH_MMIO_WRITE64 _MMIO_WRITE_DEFAULT
32 #endif
33 
mmio_read8(volatile uint8_t * ptr)34 static inline uint8_t mmio_read8(volatile uint8_t *ptr) {
35     return _ARCH_MMIO_READ8(ptr);
36 }
37 
mmio_read16(volatile uint16_t * ptr)38 static inline uint16_t mmio_read16(volatile uint16_t *ptr) {
39     return _ARCH_MMIO_READ16(ptr);
40 }
41 
mmio_read32(volatile uint32_t * ptr)42 static inline uint32_t mmio_read32(volatile uint32_t *ptr) {
43     return _ARCH_MMIO_READ32(ptr);
44 }
45 
46 #if _LP64
mmio_read64(volatile uint64_t * ptr)47 static inline uint64_t mmio_read64(volatile uint64_t *ptr) {
48     return _ARCH_MMIO_READ64(ptr);
49 }
50 #endif
51 
52 // For architectures that do not need stricter accessor instructions
mmio_write8(volatile uint8_t * ptr,uint8_t val)53 static inline void mmio_write8(volatile uint8_t *ptr, uint8_t val) {
54     _ARCH_MMIO_WRITE8(ptr, val);
55 }
56 
mmio_write16(volatile uint16_t * ptr,uint16_t val)57 static inline void mmio_write16(volatile uint16_t *ptr, uint16_t val) {
58     _ARCH_MMIO_WRITE16(ptr, val);
59 }
60 
mmio_write32(volatile uint32_t * ptr,uint32_t val)61 static inline void mmio_write32(volatile uint32_t *ptr, uint32_t val) {
62     _ARCH_MMIO_WRITE32(ptr, val);
63 }
64 
65 #if _LP64
mmio_write64(volatile uint64_t * ptr,uint64_t val)66 static inline void mmio_write64(volatile uint64_t *ptr, uint64_t val) {
67     _ARCH_MMIO_WRITE64(ptr, val);
68 }
69 #endif
70 
71 // TODO: define C++ accessors here
72 
73 // Older style accessors:
74 // NOTE: These are not generally VM safe, since some architectures require specific instruction
75 // forms to work properly in a trap-and-emulate situation.
76 #define REG64(addr) ((volatile uint64_t *)(uintptr_t)(addr))
77 #define REG32(addr) ((volatile uint32_t *)(uintptr_t)(addr))
78 #define REG16(addr) ((volatile uint16_t *)(uintptr_t)(addr))
79 #define REG8(addr) ((volatile uint8_t *)(uintptr_t)(addr))
80 
81 #define RMWREG64(addr, startbit, width, val) mmio_write64((volatile void *)(addr), (mmio_read64((volatile void *)(addr)) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)))
82 #define RMWREG32(addr, startbit, width, val) mmio_write32((volatile void *)(addr), (mmio_read32((volatile void *)(addr)) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)))
83 #define RMWREG16(addr, startbit, width, val) mmio_write16((volatile void *)(addr), (mmio_read16((volatile void *)(addr)) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)))
84 #define RMWREG8(addr, startbit, width, val) mmio_write8((volatile void *)(addr), (mmio_read8((volatile void *)(addr)) & ~(((1<<(width)) - 1) << (startbit))) | ((val) << (startbit)))
85 
86 // Linux-style accessors
87 #define readb(a) mmio_read8((volatile uint8_t *)(a))
88 #define readw(a) mmio_read16((volatile uint16_t *)(a))
89 #define readl(a) mmio_read32((volatile uint32_t *)(a))
90 #if _LP64
91 #define readq(a) mmio_read64((volatile uint64_t *)(a))
92 #endif
93 #define writeb(v, a) mmio_write8((volatile uint8_t *)(a), v)
94 #define writew(v, a) mmio_write16((volatile uint16_t *)(a), v)
95 #define writel(v, a) mmio_write32((volatile uint32_t *)(a), v)
96 #if _LP64
97 #define writeq(v, a) mmio_write64((volatile uint64_t *)(a), v)
98 #endif
99 
100 
101