ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / um / kernel / mem_user.c
1 /*
2  * arch/um/kernel/mem_user.c
3  *
4  * BRIEF MODULE DESCRIPTION
5  * user side memory routines for supporting IO memory inside user mode linux
6  *
7  * Copyright (C) 2001 RidgeRun, Inc.
8  * Author: RidgeRun, Inc.
9  *         Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com
10  *
11  *  This program is free software; you can redistribute  it and/or modify it
12  *  under  the terms of  the GNU General  Public License as published by the
13  *  Free Software Foundation;  either version 2 of the  License, or (at your
14  *  option) any later version.
15  *
16  *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
17  *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
18  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
19  *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
20  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
22  *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23  *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
24  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  *  You should have received a copy of the  GNU General Public License along
28  *  with this program; if not, write  to the Free Software Foundation, Inc.,
29  *  675 Mass Ave, Cambridge, MA 02139, USA.
30  */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stddef.h>
35 #include <stdarg.h>
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <sys/mman.h>
43 #include "kern_util.h"
44 #include "user.h"
45 #include "user_util.h"
46 #include "mem_user.h"
47 #include "init.h"
48 #include "os.h"
49 #include "tempfile.h"
50
51 extern struct mem_region physmem_region;
52
53 #define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
54
55 int create_mem_file(unsigned long len)
56 {
57         int fd;
58         char zero;
59
60         fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
61         if (fchmod(fd, 0777) < 0){
62                 perror("fchmod");
63                 exit(1);
64         }
65         if(os_seek_file(fd, len) < 0){
66                 perror("lseek");
67                 exit(1);
68         }
69         zero = 0;
70         if(write(fd, &zero, 1) != 1){
71                 perror("write");
72                 exit(1);
73         }
74         if(fcntl(fd, F_SETFD, 1) != 0)
75                 perror("Setting FD_CLOEXEC failed");
76         return(fd);
77 }
78
79 int setup_region(struct mem_region *region, void *entry)
80 {
81         void *loc, *start;
82         char *driver;
83         int err, offset;
84
85         if(region->start != -1){
86                 err = reserve_vm(region->start, 
87                                  region->start + region->len, entry);
88                 if(err){
89                         printk("setup_region : failed to reserve "
90                                "0x%x - 0x%x for driver '%s'\n",
91                                region->start, 
92                                region->start + region->len,
93                                region->driver);
94                         return(-1);
95                 }
96         }
97         else region->start = get_vm(region->len);
98         if(region->start == 0){
99                 if(region->driver == NULL) driver = "physmem";
100                 else driver = region->driver;
101                 printk("setup_region : failed to find vm for "
102                        "driver '%s' (length %d)\n", driver, region->len);
103                 return(-1);
104         }
105         if(region->start == uml_physmem){
106                 start = (void *) uml_reserved;
107                 offset = uml_reserved - uml_physmem;
108         }
109         else {
110                 start = (void *) region->start;
111                 offset = 0;
112         }
113
114         loc = mmap(start, region->len - offset, PROT_READ | PROT_WRITE, 
115                    MAP_SHARED | MAP_FIXED, region->fd, offset);
116         if(loc != start){
117                 perror("Mapping memory");
118                 exit(1);
119         }
120         return(0);
121 }
122
123 static int __init parse_iomem(char *str, int *add)
124 {
125         struct stat buf;
126         char *file, *driver;
127         int fd;
128
129         driver = str;
130         file = strchr(str,',');
131         if(file == NULL){
132                 printk("parse_iomem : failed to parse iomem\n");
133                 return(1);
134         }
135         *file = '\0';
136         file++;
137         fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
138         if(fd < 0){
139                 printk("parse_iomem - Couldn't open io file, errno = %d\n", 
140                        errno);
141                 return(1);
142         }
143         if(fstat(fd, &buf) < 0) {
144                 printk("parse_iomem - cannot fstat file, errno = %d\n", errno);
145                 return(1);
146         }
147         add_iomem(driver, fd, buf.st_size);
148         return(0);
149 }
150
151 __uml_setup("iomem=", parse_iomem,
152 "iomem=<name>,<file>\n"
153 "    Configure <file> as an IO memory region named <name>.\n\n"
154 );
155
156 #ifdef notdef
157 int logging = 0;
158 int logging_fd = -1;
159
160 int logging_line = 0;
161 char logging_buf[256];
162
163 void log(char *fmt, ...)
164 {
165         va_list ap;
166         struct timeval tv;
167         struct openflags flags;
168
169         if(logging == 0) return;
170         if(logging_fd < 0){
171                 flags = of_create(of_trunc(of_rdrw(OPENFLAGS())));
172                 logging_fd = os_open_file("log", flags, 0644);
173         }
174         gettimeofday(&tv, NULL);
175         sprintf(logging_buf, "%d\t %u.%u  ", logging_line++, tv.tv_sec, 
176                 tv.tv_usec);
177         va_start(ap, fmt);
178         vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap);
179         va_end(ap);
180         write(logging_fd, logging_buf, strlen(logging_buf));
181 }
182 #endif
183
184 int map_memory(unsigned long virt, unsigned long phys, unsigned long len, 
185                int r, int w, int x)
186 {
187         struct mem_region *region = phys_region(phys);
188
189         return(os_map_memory((void *) virt, region->fd, phys_offset(phys), len,
190                              r, w, x));
191 }
192
193 int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
194                    int must_succeed)
195 {
196         if(os_protect_memory((void *) addr, len, r, w, x) < 0){
197                 if(must_succeed)
198                         panic("protect failed, errno = %d", errno);
199                 else return(-errno);
200         }
201         return(0);
202 }
203
204 unsigned long find_iomem(char *driver, unsigned long *len_out)
205 {
206         struct mem_region *region;
207         int i, n;
208
209         n = nregions();
210         for(i = 0; i < n; i++){
211                 region = regions[i];
212                 if(region == NULL) continue;
213                 if((region->driver != NULL) &&
214                    !strcmp(region->driver, driver)){
215                         *len_out = region->len;
216                         return(region->start);
217                 }
218         }
219         *len_out = 0;
220         return 0;
221 }
222
223 /*
224  * Overrides for Emacs so that we follow Linus's tabbing style.
225  * Emacs will notice this stuff at the end of the file and automatically
226  * adjust the settings for this buffer only.  This must remain at the end
227  * of the file.
228  * ---------------------------------------------------------------------------
229  * Local variables:
230  * c-file-style: "linux"
231  * End:
232  */