From: Ian Rogers <ian.rogers@manchester.ac.uk>
To: User-mode-linux-devel@lists.sourceforge.net
Subject: Re: [uml-devel] Using SKAS, any examples?
Date: Thu, 05 May 2005 18:03:53 +0100 [thread overview]
Message-ID: <427A51F9.2060208@manchester.ac.uk> (raw)
In-Reply-To: <20050504132701.GA3755@ccure.user-mode-linux.org>
[-- Attachment #1: Type: text/plain, Size: 501 bytes --]
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
[-- Attachment #2: skas_test.c --]
[-- Type: text/x-csrc, Size: 10147 bytes --]
/*
* 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 (jdike@karaya.com)
*
* 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);
}
next prev parent reply other threads:[~2005-05-05 17:02 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-05-04 9:28 [uml-devel] Using SKAS, any examples? Ian Rogers
2005-05-04 13:27 ` Jeff Dike
2005-05-04 14:49 ` Ian Rogers
2005-05-04 19:03 ` Blaisorblade
2005-05-05 17:03 ` Ian Rogers [this message]
2005-05-07 3:11 ` Jeff Dike
2005-05-07 20:31 ` Ian Rogers
2005-05-08 17:02 ` Blaisorblade
2005-05-08 18:09 ` Ian Rogers
2005-05-09 15:08 ` Blaisorblade
2005-05-09 18:09 ` Ian Rogers
2005-05-07 15:28 ` Blaisorblade
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=427A51F9.2060208@manchester.ac.uk \
--to=ian.rogers@manchester.ac.uk \
--cc=User-mode-linux-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox