blob: f110eb55c4286b236b27e419869b651a4726414d [file] [log] [blame]
/*
* arch/um/kernel/mem_user.c
*
* BRIEF MODULE DESCRIPTION
* user side memory routines for supporting IO memory inside user mode linux
*
* Copyright (C) 2001 RidgeRun, Inc.
* Author: RidgeRun, Inc.
* Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include "kern_util.h"
#include "user.h"
#include "user_util.h"
#include "mem_user.h"
#include "init.h"
#include "os.h"
#include "tempfile.h"
#include "kern_constants.h"
extern struct mem_region physmem_region;
#define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
static int create_tmp_file(unsigned long len)
{
int fd, err;
char zero;
fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
if(fd < 0) {
os_print_error(fd, "make_tempfile");
exit(1);
}
err = os_mode_fd(fd, 0777);
if(err < 0){
os_print_error(err, "os_mode_fd");
exit(1);
}
err = os_seek_file(fd, len);
if(err < 0){
os_print_error(err, "os_seek_file");
exit(1);
}
zero = 0;
err = os_write_file(fd, &zero, 1);
if(err != 1){
os_print_error(err, "os_write_file");
exit(1);
}
return(fd);
}
static int have_devanon(void)
{
int fd;
printk("Checking for /dev/anon on the host...");
fd = open("/dev/anon", O_RDWR);
if(fd < 0){
printk("Not available (open failed with errno %d)\n", errno);
return(0);
}
printk("OK\n");
return(1);
}
static int create_anon_file(unsigned long len)
{
void *addr;
int fd;
fd = open("/dev/anon", O_RDWR);
if(fd < 0) {
os_print_error(fd, "opening /dev/anon");
exit(1);
}
addr = mmap(NULL, len, PROT_READ | PROT_WRITE , MAP_PRIVATE, fd, 0);
if(addr == MAP_FAILED){
os_print_error((int) addr, "mapping physmem file");
exit(1);
}
munmap(addr, len);
return(fd);
}
int create_mem_file(unsigned long len)
{
int err, fd;
if(have_devanon())
fd = create_anon_file(len);
else fd = create_tmp_file(len);
err = os_set_exec_close(fd, 1);
if(err < 0)
os_print_error(err, "exec_close");
return(fd);
}
struct iomem_region *iomem_regions = NULL;
int iomem_size = 0;
static int __init parse_iomem(char *str, int *add)
{
struct iomem_region *new;
struct uml_stat buf;
char *file, *driver;
int fd, err;
driver = str;
file = strchr(str,',');
if(file == NULL){
printf("parse_iomem : failed to parse iomem\n");
goto out;
}
*file = '\0';
file++;
fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
if(fd < 0){
os_print_error(fd, "parse_iomem - Couldn't open io file");
goto out;
}
err = os_stat_fd(fd, &buf);
if(err < 0){
os_print_error(err, "parse_iomem - cannot stat_fd file");
goto out_close;
}
new = malloc(sizeof(*new));
if(new == NULL){
perror("Couldn't allocate iomem_region struct");
goto out_close;
}
*new = ((struct iomem_region) { .next = iomem_regions,
.driver = driver,
.fd = fd,
.size = buf.ust_size,
.phys = 0,
.virt = 0 });
iomem_regions = new;
iomem_size += new->size + UM_KERN_PAGE_SIZE;
return(0);
out_close:
os_close_file(fd);
out:
return(1);
}
__uml_setup("iomem=", parse_iomem,
"iomem=<name>,<file>\n"
" Configure <file> as an IO memory region named <name>.\n\n"
);
int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
int must_succeed)
{
int err;
err = os_protect_memory((void *) addr, len, r, w, x);
if(err < 0){
if(must_succeed)
panic("protect failed, err = %d", -err);
else return(err);
}
return(0);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-file-style: "linux"
* End:
*/