123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- /*
- * 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"
- #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);
- }
- void check_tmpexec(void)
- {
- void *addr;
- int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
- addr = mmap(NULL, UM_KERN_PAGE_SIZE,
- PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
- printf("Checking PROT_EXEC mmap in /tmp...");
- fflush(stdout);
- if(addr == MAP_FAILED){
- err = errno;
- perror("failed");
- if(err == EPERM)
- printf("/tmp must be not mounted noexec\n");
- exit(1);
- }
- printf("OK\n");
- munmap(addr, UM_KERN_PAGE_SIZE);
- os_close_file(fd);
- }
- static int have_devanon = 0;
- void check_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;
- }
- printk("OK\n");
- have_devanon = 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){
- perror("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, size;
- 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;
- }
- size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
- *new = ((struct iomem_region) { .next = iomem_regions,
- .driver = driver,
- .fd = fd,
- .size = 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);
- }
- #if 0
- /* Debugging facility for dumping stuff out to the host, avoiding the timing
- * problems that come with printf and breakpoints.
- * Enable in case of emergency.
- */
- int logging = 1;
- int logging_fd = -1;
- int logging_line = 0;
- char logging_buf[512];
- void log(char *fmt, ...)
- {
- va_list ap;
- struct timeval tv;
- struct openflags flags;
- if(logging == 0) return;
- if(logging_fd < 0){
- flags = of_create(of_trunc(of_rdwr(OPENFLAGS())));
- logging_fd = os_open_file("log", flags, 0644);
- }
- gettimeofday(&tv, NULL);
- sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec,
- tv.tv_usec);
- va_start(ap, fmt);
- vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap);
- va_end(ap);
- write(logging_fd, logging_buf, strlen(logging_buf));
- }
- #endif
- /*
- * 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:
- */
|