729ab4432bb05f44d56332dfe9e6dc9778e07d37
[tpg/acess2.git] / Kernel / vfs / mmap.c
1 /*
2  * Acess2 VFS
3  * - Open, Close and ChDir
4  */
5 #define DEBUG   0
6 #include <acess.h>
7 #include <vfs.h>
8 #include <vfs_ext.h>
9 #include <vfs_int.h>
10
11 #define MMAP_PAGES_PER_BLOCK    16
12
13 // === STRUCTURES ===
14 typedef struct sVFS_MMapPageBlock       tVFS_MMapPageBlock;
15 struct sVFS_MMapPageBlock
16 {
17         tVFS_MMapPageBlock      *Next;
18         Uint64  BaseOffset;     // Must be a multiple of MMAP_PAGES_PER_BLOCK*PAGE_SIZE
19         tPAddr  PhysAddrs[MMAP_PAGES_PER_BLOCK];
20 };
21
22 // === CODE ===
23 void *VFS_MMap(void *DestHint, size_t Length, int Protection, int Flags, int FD, Uint64 Offset)
24 {
25         tVFS_Handle     *h;
26         tVAddr  mapping_dest, mapping_base;
27          int    npages, pagenum;
28         tVFS_MMapPageBlock      *pb, *prev;
29
30         ENTER("pDestHint iLength xProtection xFlags xFD XOffset", DestHint, Length, Protection, Flags, FD, Offset);
31
32         npages = ((Offset & (PAGE_SIZE-1)) + Length + (PAGE_SIZE - 1)) / PAGE_SIZE;
33         pagenum = Offset / PAGE_SIZE;
34
35         mapping_base = (tVAddr)DestHint;
36         mapping_dest = mapping_base & ~(PAGE_SIZE-1);
37
38         // TODO: Locate space for the allocation
39
40         // Handle anonymous mappings
41         if( Flags & MMAP_MAP_ANONYMOUS )
42         {
43                 size_t  ofs = 0;
44                 for( ; npages --; mapping_dest += PAGE_SIZE, ofs += PAGE_SIZE )
45                 {
46                         if( MM_GetPhysAddr(mapping_dest) ) {
47                                 // TODO: Set flags to COW if needed (well, if shared)
48                                 MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
49                                 memset( (void*)(mapping_base + ofs), 0, PAGE_SIZE - (mapping_base & (PAGE_SIZE-1)));
50                         }
51                         else {
52                                 // TODO: Map a COW zero page instead
53                                 if( !MM_Allocate(mapping_dest) ) {
54                                         // TODO: Error
55                                         Log_Warning("VFS", "VFS_MMap: Anon alloc to %p failed", mapping_dest);
56                                 }
57                                 memset((void*)mapping_dest, 0, PAGE_SIZE);
58                                 LOG("Anon map to %p", mapping_dest);
59                         }
60                 }
61                 LEAVE_RET('p', (void*)mapping_base);
62         }
63
64         h = VFS_GetHandle(FD);
65         if( !h || !h->Node )    LEAVE_RET('n', NULL);
66
67         LOG("h = %p", h);
68         
69         Mutex_Acquire( &h->Node->Lock );
70
71         // Search for existing mapping for each page
72         // - Sorted list of 16 page blocks
73         for(
74                 pb = h->Node->MMapInfo, prev = NULL;
75                 pb && pb->BaseOffset + MMAP_PAGES_PER_BLOCK < pagenum;
76                 prev = pb, pb = pb->Next
77                 );
78
79         LOG("pb = %p, pb->BaseOffset = %X", pb, pb ? pb->BaseOffset : 0);
80
81         // - Allocate a block if needed
82         if( !pb || pb->BaseOffset > pagenum )
83         {
84                 void    *old_pb = pb;
85                 pb = malloc( sizeof(tVFS_MMapPageBlock) );
86                 if(!pb) {
87                         Mutex_Release( &h->Node->Lock );
88                         LEAVE_RET('n', NULL);
89                 }
90                 pb->Next = old_pb;
91                 pb->BaseOffset = pagenum - pagenum % MMAP_PAGES_PER_BLOCK;
92                 memset(pb->PhysAddrs, 0, sizeof(pb->PhysAddrs));
93                 if(prev)
94                         prev->Next = pb;
95                 else
96                         h->Node->MMapInfo = pb;
97         }
98
99         // - Map (and allocate) pages
100         while( npages -- )
101         {
102                 if( MM_GetPhysAddr(mapping_dest) == 0 )
103                 {
104                         if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
105                         {
106                                 if( h->Node->MMap )
107                                         h->Node->MMap(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
108                                 else
109                                 {
110                                          int    read_len;
111                                         // Allocate pages and read data
112                                         if( MM_Allocate(mapping_dest) == 0 ) {
113                                                 // TODO: Unwrap
114                                                 Mutex_Release( &h->Node->Lock );
115                                                 LEAVE('n');
116                                                 return NULL;
117                                         }
118                                         // TODO: Clip read length
119                                         read_len = h->Node->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
120 //                                      if( read_len != PAGE_SIZE ) {
121 //                                              memset( (void*)(mapping_dest+read_len), 0, PAGE_SIZE-read_len );
122 //                                      }
123                                 }
124                                 pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( mapping_dest );
125                                 MM_SetPageNode( pb->PhysAddrs[pagenum - pb->BaseOffset], h->Node );
126                                 MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] );
127                                 LOG("Read and map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest,
128                                         pb->PhysAddrs[pagenum - pb->BaseOffset]);
129                         }
130                         else
131                         {
132                                 MM_Map( mapping_dest, pb->PhysAddrs[pagenum - pb->BaseOffset] );
133                                 MM_RefPhys( pb->PhysAddrs[pagenum - pb->BaseOffset] );
134                                 LOG("Cached map %X to %p (%P)", pagenum*PAGE_SIZE, mapping_dest,
135                                         pb->PhysAddrs[pagenum - pb->BaseOffset]);
136                         }
137                         h->Node->ReferenceCount ++;
138                 
139                         // Set flags
140                         if( !(Protection & MMAP_PROT_WRITE) ) {
141                                 MM_SetFlags(mapping_dest, MM_PFLAG_RO, MM_PFLAG_RO);
142                         }
143                         else {
144                                 MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO);
145                         }
146                         
147                         if( Protection & MMAP_PROT_EXEC ) {
148                                 MM_SetFlags(mapping_dest, MM_PFLAG_EXEC, MM_PFLAG_EXEC);
149                         }
150                         else {
151                                 MM_SetFlags(mapping_dest, 0, MM_PFLAG_EXEC);
152                         }
153                 }
154                 else
155                 {
156                         LOG("Flag update on %p", mapping_dest);
157                         if( (MM_GetFlags(mapping_dest) & MM_PFLAG_RO) && (Protection & MMAP_PROT_WRITE) )
158                         {
159                                 MM_SetFlags(mapping_dest, 0, MM_PFLAG_RO);
160                         }
161                 }
162                 if( Flags & MMAP_MAP_PRIVATE )
163                         MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
164                 pagenum ++;
165                 mapping_dest += PAGE_SIZE;
166
167                 // Roll on to next block if needed
168                 if(pagenum - pb->BaseOffset == MMAP_PAGES_PER_BLOCK)
169                 {
170                         if( pb->Next && pb->Next->BaseOffset == pagenum )
171                                 pb = pb->Next;
172                         else
173                         {
174                                 tVFS_MMapPageBlock      *oldpb = pb;
175                                 pb = malloc( sizeof(tVFS_MMapPageBlock) );
176                                 pb->Next = oldpb->Next;
177                                 pb->BaseOffset = pagenum;
178                                 memset(pb->PhysAddrs, 0, sizeof(pb->PhysAddrs));
179                                 oldpb->Next = pb;
180                         }
181                         pagenum = 0;
182                 }
183         }
184         
185         Mutex_Release( &h->Node->Lock );
186
187         LEAVE('p', mapping_base);
188         return (void*)mapping_base;
189 }
190
191 int VFS_MUnmap(void *Addr, size_t Length)
192 {
193         return 0;
194 }

UCC git Repository :: git.ucc.asn.au