diff options
Diffstat (limited to 'Documentation/sparc/adi.txt')
| -rw-r--r-- | Documentation/sparc/adi.txt | 278 |
1 files changed, 0 insertions, 278 deletions
diff --git a/Documentation/sparc/adi.txt b/Documentation/sparc/adi.txt deleted file mode 100644 index e1aed155fb89..000000000000 --- a/Documentation/sparc/adi.txt +++ /dev/null @@ -1,278 +0,0 @@ -Application Data Integrity (ADI) -================================ - -SPARC M7 processor adds the Application Data Integrity (ADI) feature. -ADI allows a task to set version tags on any subset of its address -space. Once ADI is enabled and version tags are set for ranges of -address space of a task, the processor will compare the tag in pointers -to memory in these ranges to the version set by the application -previously. Access to memory is granted only if the tag in given pointer -matches the tag set by the application. In case of mismatch, processor -raises an exception. - -Following steps must be taken by a task to enable ADI fully: - -1. Set the user mode PSTATE.mcde bit. This acts as master switch for - the task's entire address space to enable/disable ADI for the task. - -2. Set TTE.mcd bit on any TLB entries that correspond to the range of - addresses ADI is being enabled on. MMU checks the version tag only - on the pages that have TTE.mcd bit set. - -3. Set the version tag for virtual addresses using stxa instruction - and one of the MCD specific ASIs. Each stxa instruction sets the - given tag for one ADI block size number of bytes. This step must - be repeated for entire page to set tags for entire page. - -ADI block size for the platform is provided by the hypervisor to kernel -in machine description tables. Hypervisor also provides the number of -top bits in the virtual address that specify the version tag. Once -version tag has been set for a memory location, the tag is stored in the -physical memory and the same tag must be present in the ADI version tag -bits of the virtual address being presented to the MMU. For example on -SPARC M7 processor, MMU uses bits 63-60 for version tags and ADI block -size is same as cacheline size which is 64 bytes. A task that sets ADI -version to, say 10, on a range of memory, must access that memory using -virtual addresses that contain 0xa in bits 63-60. - -ADI is enabled on a set of pages using mprotect() with PROT_ADI flag. -When ADI is enabled on a set of pages by a task for the first time, -kernel sets the PSTATE.mcde bit fot the task. Version tags for memory -addresses are set with an stxa instruction on the addresses using -ASI_MCD_PRIMARY or ASI_MCD_ST_BLKINIT_PRIMARY. ADI block size is -provided by the hypervisor to the kernel. Kernel returns the value of -ADI block size to userspace using auxiliary vector along with other ADI -info. Following auxiliary vectors are provided by the kernel: - - AT_ADI_BLKSZ ADI block size. This is the granularity and - alignment, in bytes, of ADI versioning. - AT_ADI_NBITS Number of ADI version bits in the VA - - -IMPORTANT NOTES: - -- Version tag values of 0x0 and 0xf are reserved. These values match any - tag in virtual address and never generate a mismatch exception. - -- Version tags are set on virtual addresses from userspace even though - tags are stored in physical memory. Tags are set on a physical page - after it has been allocated to a task and a pte has been created for - it. - -- When a task frees a memory page it had set version tags on, the page - goes back to free page pool. When this page is re-allocated to a task, - kernel clears the page using block initialization ASI which clears the - version tags as well for the page. If a page allocated to a task is - freed and allocated back to the same task, old version tags set by the - task on that page will no longer be present. - -- ADI tag mismatches are not detected for non-faulting loads. - -- Kernel does not set any tags for user pages and it is entirely a - task's responsibility to set any version tags. Kernel does ensure the - version tags are preserved if a page is swapped out to the disk and - swapped back in. It also preserves that version tags if a page is - migrated. - -- ADI works for any size pages. A userspace task need not be aware of - page size when using ADI. It can simply select a virtual address - range, enable ADI on the range using mprotect() and set version tags - for the entire range. mprotect() ensures range is aligned to page size - and is a multiple of page size. - -- ADI tags can only be set on writable memory. For example, ADI tags can - not be set on read-only mappings. - - - -ADI related traps ------------------ - -With ADI enabled, following new traps may occur: - -Disrupting memory corruption - - When a store accesses a memory localtion that has TTE.mcd=1, - the task is running with ADI enabled (PSTATE.mcde=1), and the ADI - tag in the address used (bits 63:60) does not match the tag set on - the corresponding cacheline, a memory corruption trap occurs. By - default, it is a disrupting trap and is sent to the hypervisor - first. Hypervisor creates a sun4v error report and sends a - resumable error (TT=0x7e) trap to the kernel. The kernel sends - a SIGSEGV to the task that resulted in this trap with the following - info: - - siginfo.si_signo = SIGSEGV; - siginfo.errno = 0; - siginfo.si_code = SEGV_ADIDERR; - siginfo.si_addr = addr; /* PC where first mismatch occurred */ - siginfo.si_trapno = 0; - - -Precise memory corruption - - When a store accesses a memory location that has TTE.mcd=1, - the task is running with ADI enabled (PSTATE.mcde=1), and the ADI - tag in the address used (bits 63:60) does not match the tag set on - the corresponding cacheline, a memory corruption trap occurs. If - MCD precise exception is enabled (MCDPERR=1), a precise - exception is sent to the kernel with TT=0x1a. The kernel sends - a SIGSEGV to the task that resulted in this trap with the following - info: - - siginfo.si_signo = SIGSEGV; - siginfo.errno = 0; - siginfo.si_code = SEGV_ADIPERR; - siginfo.si_addr = addr; /* address that caused trap */ - siginfo.si_trapno = 0; - - NOTE: ADI tag mismatch on a load always results in precise trap. - - -MCD disabled - - When a task has not enabled ADI and attempts to set ADI version - on a memory address, processor sends an MCD disabled trap. This - trap is handled by hypervisor first and the hypervisor vectors this - trap through to the kernel as Data Access Exception trap with - fault type set to 0xa (invalid ASI). When this occurs, the kernel - sends the task SIGSEGV signal with following info: - - siginfo.si_signo = SIGSEGV; - siginfo.errno = 0; - siginfo.si_code = SEGV_ACCADI; - siginfo.si_addr = addr; /* address that caused trap */ - siginfo.si_trapno = 0; - - -Sample program to use ADI -------------------------- - -Following sample program is meant to illustrate how to use the ADI -functionality. - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <elf.h> -#include <sys/ipc.h> -#include <sys/shm.h> -#include <sys/mman.h> -#include <asm/asi.h> - -#ifndef AT_ADI_BLKSZ -#define AT_ADI_BLKSZ 48 -#endif -#ifndef AT_ADI_NBITS -#define AT_ADI_NBITS 49 -#endif - -#ifndef PROT_ADI -#define PROT_ADI 0x10 -#endif - -#define BUFFER_SIZE 32*1024*1024UL - -main(int argc, char* argv[], char* envp[]) -{ - unsigned long i, mcde, adi_blksz, adi_nbits; - char *shmaddr, *tmp_addr, *end, *veraddr, *clraddr; - int shmid, version; - Elf64_auxv_t *auxv; - - adi_blksz = 0; - - while(*envp++ != NULL); - for (auxv = (Elf64_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) { - switch (auxv->a_type) { - case AT_ADI_BLKSZ: - adi_blksz = auxv->a_un.a_val; - break; - case AT_ADI_NBITS: - adi_nbits = auxv->a_un.a_val; - break; - } - } - if (adi_blksz == 0) { - fprintf(stderr, "Oops! ADI is not supported\n"); - exit(1); - } - - printf("ADI capabilities:\n"); - printf("\tBlock size = %ld\n", adi_blksz); - printf("\tNumber of bits = %ld\n", adi_nbits); - - if ((shmid = shmget(2, BUFFER_SIZE, - IPC_CREAT | SHM_R | SHM_W)) < 0) { - perror("shmget failed"); - exit(1); - } - - shmaddr = shmat(shmid, NULL, 0); - if (shmaddr == (char *)-1) { - perror("shm attach failed"); - shmctl(shmid, IPC_RMID, NULL); - exit(1); - } - - if (mprotect(shmaddr, BUFFER_SIZE, PROT_READ|PROT_WRITE|PROT_ADI)) { - perror("mprotect failed"); - goto err_out; - } - - /* Set the ADI version tag on the shm segment - */ - version = 10; - tmp_addr = shmaddr; - end = shmaddr + BUFFER_SIZE; - while (tmp_addr < end) { - asm volatile( - "stxa %1, [%0]0x90\n\t" - : - : "r" (tmp_addr), "r" (version)); - tmp_addr += adi_blksz; - } - asm volatile("membar #Sync\n\t"); - - /* Create a versioned address from the normal address by placing - * version tag in the upper adi_nbits bits - */ - tmp_addr = (void *) ((unsigned long)shmaddr << adi_nbits); - tmp_addr = (void *) ((unsigned long)tmp_addr >> adi_nbits); - veraddr = (void *) (((unsigned long)version << (64-adi_nbits)) - | (unsigned long)tmp_addr); - - printf("Starting the writes:\n"); - for (i = 0; i < BUFFER_SIZE; i++) { - veraddr[i] = (char)(i); - if (!(i % (1024 * 1024))) - printf("."); - } - printf("\n"); - - printf("Verifying data..."); - fflush(stdout); - for (i = 0; i < BUFFER_SIZE; i++) - if (veraddr[i] != (char)i) - printf("\nIndex %lu mismatched\n", i); - printf("Done.\n"); - - /* Disable ADI and clean up - */ - if (mprotect(shmaddr, BUFFER_SIZE, PROT_READ|PROT_WRITE)) { - perror("mprotect failed"); - goto err_out; - } - - if (shmdt((const void *)shmaddr) != 0) - perror("Detach failure"); - shmctl(shmid, IPC_RMID, NULL); - - exit(0); - -err_out: - if (shmdt((const void *)shmaddr) != 0) - perror("Detach failure"); - shmctl(shmid, IPC_RMID, NULL); - exit(1); -} |
