OSDN Git Service

* fhandler.h (fhandler_dev_mem): Erase member `init_phase' and
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / fhandler_mem.cc
1 /* fhandler_mem.cc.  See fhandler.h for a description of the fhandler classes.
2
3    Copyright 1999, 2000 Cygnus Solutions.
4
5    This file is part of Cygwin.
6
7    This software is a copyrighted work licensed under the terms of the
8    Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9    details. */
10
11 #include "winsup.h"
12 #include <sys/termios.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <sys/mman.h>
17 #include <ntdef.h>
18
19 #include "autoload.h"
20 #include "cygheap.h"
21 #include "cygerrno.h"
22 #include "fhandler.h"
23 #include "path.h"
24
25 /*
26  * The following both data structures aren't defined anywhere in the Microsoft
27  * header files. Taken from the book "Windows NT/2000 Native API Reference"
28  * by Gary Nebbett.
29  */
30 typedef enum _SYSTEM_INFORMATION_CLASS {
31   SystemBasicInformation = 0
32   /* Dropped each other since not used here. */
33 } SYSTEM_INFORMATION_CLASS;
34
35 typedef struct _SYSTEM_BASIC_INFORMATION {
36   ULONG Unknown;
37   ULONG MaximumIncrement;
38   ULONG PhysicalPageSize;
39   ULONG NumberOfPhysicalPages;
40   ULONG LowestPhysicalPage;
41   ULONG HighestPhysicalPage;
42   ULONG AllocationGranularity;
43   ULONG LowestUserAddress;
44   ULONG HighestUserAddress;
45   ULONG ActiveProcessors;
46   ULONG NumberProcessors;
47 } SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;
48
49 extern "C" {
50 NTSTATUS NTAPI NtMapViewOfSection(HANDLE,HANDLE,PVOID*,ULONG,ULONG,
51                                   PLARGE_INTEGER,PULONG,SECTION_INHERIT,
52                                   ULONG,ULONG);
53 NTSTATUS NTAPI NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS,
54                                         PVOID,ULONG,PULONG);
55 NTSTATUS NTAPI NtOpenSection(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES);
56 NTSTATUS NTAPI NtUnmapViewOfSection(HANDLE,PVOID);
57 VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING,PCWSTR);
58 ULONG NTAPI RtlNtStatusToDosError(NTSTATUS);
59 }
60
61 /**********************************************************************/
62 /* fhandler_dev_mem */
63
64 fhandler_dev_mem::fhandler_dev_mem (const char *name, int nunit)
65 : fhandler_base (FH_MEM, name),
66   unit (nunit)
67 {
68   if (unit == 1) /* /dev/mem */
69     {
70       NTSTATUS ret;
71       SYSTEM_BASIC_INFORMATION sbi;
72       if ((ret = NtQuerySystemInformation (SystemBasicInformation, (PVOID) &sbi,
73                                            sizeof sbi, NULL)) != STATUS_SUCCESS)
74         {
75           __seterrno_from_win_error (RtlNtStatusToDosError (ret));
76           debug_printf("NtQuerySystemInformation: ret = %d, Dos(ret) = %d",
77                        ret, RtlNtStatusToDosError (ret));
78           mem_size = 0;
79         }
80       else
81         mem_size = sbi.PhysicalPageSize * sbi.NumberOfPhysicalPages;
82       debug_printf ("MemSize: %d MB", mem_size >>= 20);
83     }
84   else if (unit == 2) /* /dev/kmem - Not yet supported */
85     {
86       mem_size = 0;
87       debug_printf ("KMemSize: %d MB", mem_size >>= 20);
88     }
89   else if (unit == 4) /* /dev/port == First 64K of /dev/mem */
90     {
91       mem_size = 65536;
92       debug_printf ("PortSize: 64 KB");
93     }
94   else
95     {
96       mem_size = 0;
97       debug_printf ("Illegal minor number!!!");
98     }
99 }
100
101 fhandler_dev_mem::~fhandler_dev_mem (void)
102 {
103 }
104
105 int
106 fhandler_dev_mem::open (const char *, int flags, mode_t)
107 {
108   if (os_being_run != winNT)
109     {
110       set_errno (ENOENT);
111       debug_printf ("%s is accessible under NT/W2K only",
112                     unit == 1 ? "/dev/mem" :
113                     unit == 2 ? "/dev/kmem" :
114                                 "/dev/port" );
115       return 0;
116     }
117
118   /* Check for illegal flags. */
119   if (flags & (O_APPEND | O_TRUNC | O_EXCL))
120     {
121       set_errno (EINVAL);
122       return 0;
123     }
124
125   UNICODE_STRING memstr;
126   RtlInitUnicodeString (&memstr, L"\\device\\physicalmemory");
127
128   OBJECT_ATTRIBUTES attr;
129   InitializeObjectAttributes(&attr, &memstr, OBJ_CASE_INSENSITIVE, NULL, NULL);
130
131   ACCESS_MASK section_access;
132   if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY)
133     {
134       set_access (GENERIC_READ);
135       section_access = SECTION_MAP_READ;
136     }
137   else if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_WRONLY)
138     {
139       set_access (GENERIC_WRITE);
140       section_access = SECTION_MAP_READ | SECTION_MAP_WRITE;
141     }
142   else
143     {
144       set_access (GENERIC_READ | GENERIC_WRITE);
145       section_access = SECTION_MAP_READ | SECTION_MAP_WRITE;
146     }
147
148   HANDLE mem;
149   NTSTATUS ret = NtOpenSection (&mem, section_access, &attr);
150   if (!NT_SUCCESS(ret))
151     {
152       __seterrno_from_win_error (RtlNtStatusToDosError (ret));
153       set_io_handle (NULL);
154       return 0;
155     }
156
157   set_io_handle (mem);
158   return 1;
159 }
160
161 int
162 fhandler_dev_mem::write (const void *ptr, size_t ulen)
163 {
164   if (!ulen || pos >= mem_size)
165     return 0;
166
167   if (!(get_access () & GENERIC_WRITE))
168     {
169       set_errno (EINVAL);
170       return -1;
171     }
172
173   if (pos + ulen > mem_size)
174     ulen = mem_size - pos;
175
176   PHYSICAL_ADDRESS phys;
177   NTSTATUS ret;
178   void *viewmem = NULL;
179   DWORD len = ulen + getpagesize () - 1;
180
181   phys.QuadPart = (ULONGLONG) pos;
182   if ((ret = NtMapViewOfSection (get_handle (),
183                                  INVALID_HANDLE_VALUE,
184                                  &viewmem,
185                                  0L,
186                                  len,
187                                  &phys,
188                                  &len,
189                                  ViewShare,
190                                  0,
191                                  PAGE_READONLY)) != STATUS_SUCCESS)
192     {
193       __seterrno_from_win_error (RtlNtStatusToDosError (ret));
194       return -1;
195     }
196
197   memcpy ((char *) viewmem + (pos - phys.QuadPart), ptr, ulen);
198
199   if (!NT_SUCCESS(ret = NtUnmapViewOfSection (INVALID_HANDLE_VALUE, viewmem)))
200     {
201       __seterrno_from_win_error (RtlNtStatusToDosError (ret));
202       return -1;
203     }
204
205   pos += ulen;
206   return ulen;
207 }
208
209 int
210 fhandler_dev_mem::read (void *ptr, size_t ulen)
211 {
212   if (!ulen || pos >= mem_size)
213     return 0;
214
215   if (!(get_access () & GENERIC_READ))
216     {
217       set_errno (EINVAL);
218       return -1;
219     }
220
221   if (pos + ulen > mem_size)
222     ulen = mem_size - pos;
223
224   PHYSICAL_ADDRESS phys;
225   NTSTATUS ret;
226   void *viewmem = NULL;
227   DWORD len = ulen + getpagesize () - 1;
228
229   phys.QuadPart = (ULONGLONG) pos;
230   if ((ret = NtMapViewOfSection (get_handle (),
231                                  INVALID_HANDLE_VALUE,
232                                  &viewmem,
233                                  0L,
234                                  len,
235                                  &phys,
236                                  &len,
237                                  ViewShare,
238                                  0,
239                                  PAGE_READONLY)) != STATUS_SUCCESS)
240     {
241       __seterrno_from_win_error (RtlNtStatusToDosError (ret));
242       return -1;
243     }
244
245   memcpy (ptr, (char *) viewmem + (pos - phys.QuadPart), ulen);
246
247   if (!NT_SUCCESS(ret = NtUnmapViewOfSection (INVALID_HANDLE_VALUE, viewmem)))
248     {
249       __seterrno_from_win_error (RtlNtStatusToDosError (ret));
250       return -1;
251     }
252
253   pos += ulen;
254   return ulen;
255 }
256
257 int
258 fhandler_dev_mem::close (void)
259 {
260   return fhandler_base::close ();
261 }
262
263 off_t
264 fhandler_dev_mem::lseek (off_t offset, int whence)
265 {
266   switch (whence)
267     {
268     case SEEK_SET:
269       pos = offset;
270       break;
271     
272     case SEEK_CUR:
273       pos += offset;
274       break;
275
276     case SEEK_END:
277       pos = mem_size;
278       pos += offset;
279       break;
280     
281     default:
282       set_errno (EINVAL);
283       return (off_t) -1;
284     }
285
286   if (pos > mem_size)
287     {
288       set_errno (EINVAL);
289       return (off_t) -1;
290     }
291
292   return pos;
293 }
294
295 HANDLE
296 fhandler_dev_mem::mmap (caddr_t *addr, size_t len, DWORD access,
297                         int flags, off_t off)
298 {
299   if ((DWORD) off >= mem_size
300       || (DWORD) len >= mem_size
301       || (DWORD) off + len >= mem_size)
302     {
303       set_errno (EINVAL);
304       syscall_printf ("-1 = mmap(): illegal parameter, set EINVAL");
305       return INVALID_HANDLE_VALUE;
306     }
307
308   UNICODE_STRING memstr;
309   RtlInitUnicodeString (&memstr, L"\\device\\physicalmemory");
310
311   OBJECT_ATTRIBUTES attr;
312   InitializeObjectAttributes(&attr, &memstr, OBJ_CASE_INSENSITIVE, NULL, NULL);
313
314   ACCESS_MASK section_access;
315   ULONG protect;
316
317   if (access & FILE_MAP_COPY)
318     {
319       section_access = SECTION_MAP_READ | SECTION_MAP_WRITE;
320       protect = PAGE_WRITECOPY;
321     }
322   else if (access & FILE_MAP_WRITE)
323     {
324       section_access = SECTION_MAP_READ | SECTION_MAP_WRITE;
325       protect = PAGE_READWRITE;
326     }
327   else
328     {
329       section_access = SECTION_MAP_READ;
330       protect = PAGE_READONLY;
331     }
332
333   HANDLE h;
334   NTSTATUS ret = NtOpenSection (&h, section_access, &attr);
335   if (!NT_SUCCESS(ret))
336     {
337       __seterrno_from_win_error (RtlNtStatusToDosError (ret));
338       syscall_printf ("-1 = mmap(): NtOpenSection failed with %E");
339       return INVALID_HANDLE_VALUE;
340     }
341
342   PHYSICAL_ADDRESS phys;
343   void *base = *addr;
344   DWORD dlen = len;
345
346   phys.QuadPart = (ULONGLONG) off;
347
348   if ((ret = NtMapViewOfSection (h,
349                                  INVALID_HANDLE_VALUE,
350                                  &base,
351                                  0L,
352                                  dlen,
353                                  &phys,
354                                  &dlen,
355                                  ViewShare /*??*/,
356                                  0,
357                                  protect)) != STATUS_SUCCESS)
358     {
359       __seterrno_from_win_error (RtlNtStatusToDosError (ret));
360       syscall_printf ("-1 = mmap(): NtMapViewOfSection failed with %E");
361       return INVALID_HANDLE_VALUE;
362     }
363   if ((flags & MAP_FIXED) && base != addr)
364     {
365       set_errno (EINVAL);
366       syscall_printf ("-1 = mmap(): address shift with MAP_FIXED given");
367       NtUnmapViewOfSection (INVALID_HANDLE_VALUE, base);
368       return INVALID_HANDLE_VALUE;
369     }
370
371   *addr = (caddr_t) base;
372   return h;
373 }
374
375 int
376 fhandler_dev_mem::munmap (HANDLE h, caddr_t addr, size_t len)
377 {
378   NTSTATUS ret;
379   if (!NT_SUCCESS(ret = NtUnmapViewOfSection (INVALID_HANDLE_VALUE, addr)))
380     {
381       __seterrno_from_win_error (RtlNtStatusToDosError (ret));
382       return -1;
383     }
384   CloseHandle (h);
385   return 0;
386 }
387
388 int
389 fhandler_dev_mem::msync (HANDLE h, caddr_t addr, size_t len, int flags)
390 {
391   return 0;
392 }
393
394 int
395 fhandler_dev_mem::fstat (struct stat *buf)
396 {
397   if (!buf)
398     {
399       set_errno (EINVAL);
400       return -1;
401     }
402
403   memset (buf, 0, sizeof *buf);
404   buf->st_mode = S_IFCHR;
405   if (os_being_run != winNT)
406     buf->st_mode |= S_IRUSR | S_IWUSR |
407                     S_IRGRP | S_IWGRP |
408                     S_IROTH | S_IWOTH;
409   buf->st_nlink = 1;
410   buf->st_blksize = getpagesize ();
411   buf->st_dev = buf->st_rdev = get_device () << 8 | (unit & 0xff);
412
413   return 0;
414 }
415
416 int
417 fhandler_dev_mem::dup (fhandler_base *child)
418 {
419   int ret = fhandler_base::dup (child);
420
421   if (! ret)
422     {
423       fhandler_dev_mem *fhc = (fhandler_dev_mem *) child;
424
425       fhc->mem_size = mem_size;
426       fhc->pos = pos;
427     }
428   return ret;
429 }
430
431 void
432 fhandler_dev_mem::dump ()
433 {
434   paranoid_printf("here, fhandler_dev_mem");
435 }
436
437 extern "C" {
438
439 LoadDLLinitfunc (ntdll)
440 {
441   HANDLE h;
442   static NO_COPY LONG here = -1L;
443
444   while (InterlockedIncrement (&here))
445     {
446       InterlockedDecrement (&here);
447 small_printf ("Multiple tries to read ntdll.dll\n");
448       Sleep (0);
449     }
450
451   if (ntdll_handle)
452     /* nothing to do */;
453   else if ((h = LoadLibrary ("ntdll.dll")) != NULL)
454     ntdll_handle = h;
455   else if (!ntdll_handle)
456     api_fatal ("could not load ntdll.dll, %E");
457
458   InterlockedDecrement (&here);
459   return 0;
460 }
461
462 static void dummy_autoload (void) __attribute__ ((unused));
463 static void
464 dummy_autoload (void)
465 {
466 LoadDLLinit (ntdll)
467 LoadDLLfuncEx (NtMapViewOfSection, 40, ntdll, 1)
468 LoadDLLfuncEx (NtOpenSection, 12, ntdll, 1)
469 LoadDLLfuncEx (NtQuerySystemInformation, 16, ntdll, 1)
470 LoadDLLfuncEx (NtUnmapViewOfSection, 8, ntdll, 1)
471 LoadDLLfuncEx (RtlInitUnicodeString, 8, ntdll, 1)
472 LoadDLLfuncEx (RtlNtStatusToDosError, 4, ntdll, 1)
473 }
474 }