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);
}

Reply via email to