Hi,
I've attached the test/example I'm working on to create and manipulate address spaces uses skas - as I want to allow an emulator to. There are a few missing functions (that can be pretty much cloned from mem_user.c) and I've not worked out how to calculate the descriptor value yet. Please could you have a look and suggest how to create the descriptor value and why when I look in /proc/<pid>/maps I can't see the asid_mmap that's being done as part of the test.
Many thanks,
Ian Rogers
/* * Program to create a dummy address space and play with it (much as * an emulator would) using the skas linux kernel module * * This code copies and is based upon code: * Copyright (C) 2002 Jeff Dike ([EMAIL PROTECTED]) * * Copyright (C) 2005 Ian Rogers, The University of Manchester * (http://www.cs.manchester.ac.uk/apt/projects/jamaica/) * * Licensed under the GPL */ #include <unistd.h> #include <stdio.h> #include <errno.h> #include <fcntl.h> #include <signal.h> #include <linux/unistd.h> #include <sched.h> #include <sys/mman.h> #include <sys/wait.h> #include <sys/ptrace.h>
/** * Taken from arch/um/kernel/skas/include/proc_mm.h */ #define MM_MMAP 54 #define MM_MUNMAP 55 #define MM_MPROTECT 56 #define MM_COPY_SEGMENTS 57 struct mm_mmap { unsigned long addr; unsigned long len; unsigned long prot; unsigned long flags; unsigned long fd; unsigned long offset; }; struct mm_munmap { unsigned long addr; unsigned long len; }; struct mm_mprotect { unsigned long addr; unsigned long len; unsigned int prot; }; struct proc_mm_op { int op; union { struct mm_mmap mmap; struct mm_munmap munmap; struct mm_mprotect mprotect; int copy_segments; } u; }; /** * Generate verbose output */ #define VERBOSE 1 /** * Maximum number of creatable address spaces */ #define MAX_ADDRESS_SPACES 1 /** * Maximum number of maps within the address space */ #define MAX_MAPS 128 /** * The size of blocks in the physical memory backing store */ #define BACKING_STORE_CHUNK_SIZE 4096 /** * The size of blocks in the physical memory backing store */ #define ADDRESS_SPACE_SIZE (BACKING_STORE_CHUNK_SIZE * MAX_MAPS) /** * The size of blocks in the physical memory backing store */ #define BACKING_STORE_SIZE (ADDRESS_SPACE_SIZE * MAX_ADDRESS_SPACES) /** * Information held about an address space */ struct AS_info { /** * The file descriptor of the physical memory backing store file. * Currently I don't know why you'd want this but I'm replicating * Jeff Dike's structures. */ int fd; /** * Per memory map information */ struct _map_info_t { /** * The virtual address this map information corresponds to */ void *virtual_address; /** * The offset within the physical memory backing store file */ unsigned long long offset; } map_info[MAX_MAPS]; /** * The process identifier created for this address space */ int pid; /** * An i386 descriptor value that can be used to access the address * space */ int descriptor; }; /** * Information on created address spaces */ struct AS_info AddressSpaces[MAX_ADDRESS_SPACES]; /** * The next available address space */ int nextFreeAddressSpace = 0; /** * Handle for /proc/mm - there's a handle for this for every context in UML */ int mm_fd; /** * Handle for physical memory backing store */ int physmem_fd; /** * Initialize */ void initialize() { // get a handle to /proc/mm mm_fd = open("/proc/mm", O_WRONLY); if(mm_fd == -1){ perror("Failed to open /proc/mm"); exit(1); } if(VERBOSE) fprintf(stderr, "Opened /proc/mm\n"); // make physical memory backing store // - try to use /dev/anon as it won't leave unmapped pages in memory physmem_fd = open("/dev/anon", O_RDWR); if (physmem_fd > 0) { // check we can map to a /dev/anon type file void *addr = mmap(NULL, BACKING_STORE_SIZE, PROT_READ | PROT_WRITE , MAP_PRIVATE, physmem_fd, 0); if(addr == MAP_FAILED){ perror("Error during mapping physmem file on /dev/anon"); exit(1); } munmap(addr, BACKING_STORE_SIZE); if(VERBOSE) fprintf(stderr, "Created backing store file on /dev/anon\n"); } else { // create a regular file for the backing store const char *physmem_filename = "/tmp/address_space_backing_store_XXXXXX"; char temp_filename[1024]; strcpy(temp_filename, physmem_filename); physmem_fd = mkstemp(temp_filename); if(physmem_fd < 0){ perror("Error during creation of a backing store file"); exit(1); } if(unlink(temp_filename) < 0) { perror("Error during unlinking of backing store file"); exit(1); } if(VERBOSE) fprintf(stderr, "Created backing store file %s\n", temp_filename); } // Set close on exit int err = fcntl(physmem_fd, F_SETFD, FD_CLOEXEC); if(err < 0) { perror("Error during setting close on exit"); exit(1); } } /** * Create an address space or die * @return the address space identifier (ASID) for this address space */ static int address_space_tramp(void *arg) { kill(getpid(), SIGSTOP); return(0); } int create_address_space() { // the address space we're working on int ASID = nextFreeAddressSpace; // pointers to a stack and a fake stack pointer void *stack, *sp; // temporaries int i, n, status; // setup file descriptor AddressSpaces[ASID].fd = physmem_fd; // nullify maps and set offsets within backing store file for(i=0; i<MAX_MAPS; i++) { AddressSpaces[ASID].map_info[i].virtual_address = ((void*)-1); AddressSpaces[ASID].map_info[i].offset = (ASID * ADDRESS_SPACE_SIZE) + (i * BACKING_STORE_CHUNK_SIZE); } // Create address space using clone stack = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if(stack == MAP_FAILED) { perror("Failed to create dummy user space stack"); exit(1); } sp = (void*)(((unsigned long) stack) + 4096 - sizeof(void *)); AddressSpaces[ASID].pid = clone(address_space_tramp, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, NULL); if(AddressSpaces[ASID].pid < 0) { perror("Failed to create address space: clone failed"); exit(1); } do { do { n = waitpid(AddressSpaces[ASID].pid, &status, WUNTRACED); } while ((n < 0) && errno == EINTR); if(n < 0) { perror("Failed to create address space: wait failed"); exit(1); } } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){ fprintf(stderr,"Failed to create address space: expected SIGSTOP, got status = %d",status); exit(1); } if(munmap(stack, 4096) < 0) { perror("Failed to create address space: munmap failed"); exit(1); } // set up descriptor - TODO!!! AddressSpaces[ASID].descriptor = -1; // move along and return nextFreeAddressSpace++; if(VERBOSE) fprintf(stderr, "Created address space %d\n", ASID); return ASID; } /** * Perform an mmap in the specified ASID or die * @param ASID the address space identifier * @param virt the address in the ASID to allocate * @param len the size of memory to allocate * @param r read permission * @param w write permission * @param x execute permission */ void asid_mmap(int ASID, void *virt, unsigned long len, int r, int w, int x) { // Data structure to write to the skas linux kernel module struct proc_mm_op operation; // The protection mask int prot; // The map within the address space we're going to use int map = -1; // temporary int i; // Check this will fit into the physical memory backing store if(len > BACKING_STORE_CHUNK_SIZE) { // Number of map structures required for this mapping int num_maps = (len + BACKING_STORE_CHUNK_SIZE - 1) / BACKING_STORE_CHUNK_SIZE; for(i=0; i < num_maps; i++) { asid_mmap(ASID, virt + (i * BACKING_STORE_CHUNK_SIZE), BACKING_STORE_CHUNK_SIZE, r, w ,x); } } else { // Find a map to use for (i=0; i < MAX_MAPS; i++) { if(AddressSpaces[ASID].map_info[i].virtual_address == virt) { map = i; break; } } if (map == -1) { for (i=0; i < MAX_MAPS; i++) { if(AddressSpaces[ASID].map_info[i].virtual_address == ((void*)-1)) { map = i; break; } } if (map == -1) { fprintf(stderr, "Failed to find a free map to use in address space %d\n", ASID); exit(1); } } // Calculate the protection properly prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | (x ? PROT_EXEC : 0); // Generate map to be written operation = ((struct proc_mm_op) { .op = MM_MMAP, .u = { .mmap = { .addr = (unsigned long)virt, .len = len, .prot = prot, .flags = MAP_SHARED | MAP_FIXED, // physical memory backing store .fd = AddressSpaces[ASID].fd, // offset within the backing store .offset = AddressSpaces[ASID].map_info[map].offset } } } ); int n = write(mm_fd, &operation, sizeof(operation)); if(n != sizeof(operation)) { perror("asid_mmap failed"); exit(1); } if(VERBOSE) fprintf(stderr, "Created page at %p in address space %d\n", virt, ASID); } } /** * Perform an munmap in the specified ASID or die * @param ASID the address space identifier * @param addr the address to deallocate * @param len the size of memory to deallocate */ void asid_munmap(int ASID, unsigned addr, unsigned long len) { // TODO!!! } /** * Perform an mprotect in the specified ASID or die * @param ASID the address space identifier * @param addr the address to modify the permissions * @param len the size of memory to modify * @param r read permission * @param w write permission * @param x execute permission */ void asid_mprotect(int ASID, unsigned addr, unsigned long len, int r, int w, int x) { // TODO!!! } /** * Peek a value in an address space * @param ASID the address space to peek * @param virt the virtual address to look at * @return the value peeked */ int asid_peek(int ASID, void *virt) { int res; asm volatile ("pushw %w2\n\t" "popw %%fs\n\t" "movl %%fs:(%1), %0\n\t" : "=r" (res) : "r" (virt), "r" (AddressSpaces[ASID].descriptor)); return res; } /** * Poke a value into an address space * @param ASID the address space to peek * @param virt the virtual address to look at * @param value the value poked */ void asid_poke(int ASID, void *virt, int value) { asm volatile ("pushw %w2\n\t" "popw %%fs\n\t" "movl %0, %%fs:(%1)\n\t" : : "r" (value), "r" (virt), "r" (AddressSpaces[ASID].descriptor)); } /** * main */ int main(int argc, char **argv) { initialize(); int ASID = create_address_space(); asid_mmap(ASID,((void*)4096),4096,1,1,1); sleep(30); }