^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) ================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) Application Data Integrity (ADI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) ================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) SPARC M7 processor adds the Application Data Integrity (ADI) feature.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) ADI allows a task to set version tags on any subset of its address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) space. Once ADI is enabled and version tags are set for ranges of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) address space of a task, the processor will compare the tag in pointers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) to memory in these ranges to the version set by the application
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) previously. Access to memory is granted only if the tag in given pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) matches the tag set by the application. In case of mismatch, processor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) raises an exception.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) Following steps must be taken by a task to enable ADI fully:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) 1. Set the user mode PSTATE.mcde bit. This acts as master switch for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) the task's entire address space to enable/disable ADI for the task.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) 2. Set TTE.mcd bit on any TLB entries that correspond to the range of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) addresses ADI is being enabled on. MMU checks the version tag only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) on the pages that have TTE.mcd bit set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) 3. Set the version tag for virtual addresses using stxa instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) and one of the MCD specific ASIs. Each stxa instruction sets the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) given tag for one ADI block size number of bytes. This step must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) be repeated for entire page to set tags for entire page.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) ADI block size for the platform is provided by the hypervisor to kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) in machine description tables. Hypervisor also provides the number of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) top bits in the virtual address that specify the version tag. Once
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) version tag has been set for a memory location, the tag is stored in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) physical memory and the same tag must be present in the ADI version tag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) bits of the virtual address being presented to the MMU. For example on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) SPARC M7 processor, MMU uses bits 63-60 for version tags and ADI block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) size is same as cacheline size which is 64 bytes. A task that sets ADI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) version to, say 10, on a range of memory, must access that memory using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) virtual addresses that contain 0xa in bits 63-60.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) ADI is enabled on a set of pages using mprotect() with PROT_ADI flag.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) When ADI is enabled on a set of pages by a task for the first time,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) kernel sets the PSTATE.mcde bit fot the task. Version tags for memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) addresses are set with an stxa instruction on the addresses using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) ASI_MCD_PRIMARY or ASI_MCD_ST_BLKINIT_PRIMARY. ADI block size is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) provided by the hypervisor to the kernel. Kernel returns the value of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) ADI block size to userspace using auxiliary vector along with other ADI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) info. Following auxiliary vectors are provided by the kernel:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) ============ ===========================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) AT_ADI_BLKSZ ADI block size. This is the granularity and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) alignment, in bytes, of ADI versioning.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) AT_ADI_NBITS Number of ADI version bits in the VA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) ============ ===========================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) IMPORTANT NOTES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) ===============
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) - Version tag values of 0x0 and 0xf are reserved. These values match any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) tag in virtual address and never generate a mismatch exception.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) - Version tags are set on virtual addresses from userspace even though
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) tags are stored in physical memory. Tags are set on a physical page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) after it has been allocated to a task and a pte has been created for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) - When a task frees a memory page it had set version tags on, the page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) goes back to free page pool. When this page is re-allocated to a task,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) kernel clears the page using block initialization ASI which clears the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) version tags as well for the page. If a page allocated to a task is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) freed and allocated back to the same task, old version tags set by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) task on that page will no longer be present.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) - ADI tag mismatches are not detected for non-faulting loads.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) - Kernel does not set any tags for user pages and it is entirely a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) task's responsibility to set any version tags. Kernel does ensure the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) version tags are preserved if a page is swapped out to the disk and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) swapped back in. It also preserves that version tags if a page is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) migrated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) - ADI works for any size pages. A userspace task need not be aware of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) page size when using ADI. It can simply select a virtual address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) range, enable ADI on the range using mprotect() and set version tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) for the entire range. mprotect() ensures range is aligned to page size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) and is a multiple of page size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) - ADI tags can only be set on writable memory. For example, ADI tags can
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) not be set on read-only mappings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) ADI related traps
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) =================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) With ADI enabled, following new traps may occur:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) Disrupting memory corruption
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) ----------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) When a store accesses a memory localtion that has TTE.mcd=1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) the task is running with ADI enabled (PSTATE.mcde=1), and the ADI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) tag in the address used (bits 63:60) does not match the tag set on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) the corresponding cacheline, a memory corruption trap occurs. By
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) default, it is a disrupting trap and is sent to the hypervisor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) first. Hypervisor creates a sun4v error report and sends a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) resumable error (TT=0x7e) trap to the kernel. The kernel sends
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) a SIGSEGV to the task that resulted in this trap with the following
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) info::
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) siginfo.si_signo = SIGSEGV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) siginfo.errno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) siginfo.si_code = SEGV_ADIDERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) siginfo.si_addr = addr; /* PC where first mismatch occurred */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) siginfo.si_trapno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) Precise memory corruption
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) -------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) When a store accesses a memory location that has TTE.mcd=1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) the task is running with ADI enabled (PSTATE.mcde=1), and the ADI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) tag in the address used (bits 63:60) does not match the tag set on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) the corresponding cacheline, a memory corruption trap occurs. If
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) MCD precise exception is enabled (MCDPERR=1), a precise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) exception is sent to the kernel with TT=0x1a. The kernel sends
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) a SIGSEGV to the task that resulted in this trap with the following
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) info::
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) siginfo.si_signo = SIGSEGV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) siginfo.errno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) siginfo.si_code = SEGV_ADIPERR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) siginfo.si_addr = addr; /* address that caused trap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) siginfo.si_trapno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) NOTE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ADI tag mismatch on a load always results in precise trap.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) MCD disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) When a task has not enabled ADI and attempts to set ADI version
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) on a memory address, processor sends an MCD disabled trap. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) trap is handled by hypervisor first and the hypervisor vectors this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) trap through to the kernel as Data Access Exception trap with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) fault type set to 0xa (invalid ASI). When this occurs, the kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) sends the task SIGSEGV signal with following info::
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) siginfo.si_signo = SIGSEGV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) siginfo.errno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) siginfo.si_code = SEGV_ACCADI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) siginfo.si_addr = addr; /* address that caused trap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) siginfo.si_trapno = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) Sample program to use ADI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) -------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) Following sample program is meant to illustrate how to use the ADI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) functionality::
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #include <elf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #include <sys/ipc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) #include <sys/shm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) #include <sys/mman.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) #include <asm/asi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) #ifndef AT_ADI_BLKSZ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) #define AT_ADI_BLKSZ 48
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) #ifndef AT_ADI_NBITS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) #define AT_ADI_NBITS 49
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) #ifndef PROT_ADI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) #define PROT_ADI 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) #define BUFFER_SIZE 32*1024*1024UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) main(int argc, char* argv[], char* envp[])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) unsigned long i, mcde, adi_blksz, adi_nbits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) char *shmaddr, *tmp_addr, *end, *veraddr, *clraddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) int shmid, version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) Elf64_auxv_t *auxv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) adi_blksz = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) while(*envp++ != NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) for (auxv = (Elf64_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) switch (auxv->a_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) case AT_ADI_BLKSZ:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) adi_blksz = auxv->a_un.a_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case AT_ADI_NBITS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) adi_nbits = auxv->a_un.a_val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (adi_blksz == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) fprintf(stderr, "Oops! ADI is not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) exit(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) printf("ADI capabilities:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) printf("\tBlock size = %ld\n", adi_blksz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) printf("\tNumber of bits = %ld\n", adi_nbits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if ((shmid = shmget(2, BUFFER_SIZE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) IPC_CREAT | SHM_R | SHM_W)) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) perror("shmget failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) exit(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) shmaddr = shmat(shmid, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (shmaddr == (char *)-1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) perror("shm attach failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) shmctl(shmid, IPC_RMID, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) exit(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (mprotect(shmaddr, BUFFER_SIZE, PROT_READ|PROT_WRITE|PROT_ADI)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) perror("mprotect failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) /* Set the ADI version tag on the shm segment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) version = 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) tmp_addr = shmaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) end = shmaddr + BUFFER_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) while (tmp_addr < end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) "stxa %1, [%0]0x90\n\t"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) : "r" (tmp_addr), "r" (version));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) tmp_addr += adi_blksz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) asm volatile("membar #Sync\n\t");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /* Create a versioned address from the normal address by placing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * version tag in the upper adi_nbits bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) tmp_addr = (void *) ((unsigned long)shmaddr << adi_nbits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) tmp_addr = (void *) ((unsigned long)tmp_addr >> adi_nbits);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) veraddr = (void *) (((unsigned long)version << (64-adi_nbits))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) | (unsigned long)tmp_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) printf("Starting the writes:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) for (i = 0; i < BUFFER_SIZE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) veraddr[i] = (char)(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (!(i % (1024 * 1024)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) printf(".");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) printf("Verifying data...");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) fflush(stdout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) for (i = 0; i < BUFFER_SIZE; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (veraddr[i] != (char)i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) printf("\nIndex %lu mismatched\n", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) printf("Done.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /* Disable ADI and clean up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (mprotect(shmaddr, BUFFER_SIZE, PROT_READ|PROT_WRITE)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) perror("mprotect failed");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) goto err_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (shmdt((const void *)shmaddr) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) perror("Detach failure");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) shmctl(shmid, IPC_RMID, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) exit(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) err_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (shmdt((const void *)shmaddr) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) perror("Detach failure");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) shmctl(shmid, IPC_RMID, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) exit(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }