[FREELDR] Diverse enhancements.
[reactos.git] / boot / freeldr / freeldr / disk / ramdisk.c
1 /*
2 * PROJECT: ReactOS Boot Loader
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: boot/freeldr/freeldr/disk/ramdisk.c
5 * PURPOSE: Implements routines to support booting from a RAM Disk
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Hervé Poussineau
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <freeldr.h>
13
14 #include <debug.h>
15
16 /* GLOBALS ********************************************************************/
17
18 PVOID gRamDiskBase;
19 ULONG gRamDiskSize;
20 ULONG gRamDiskOffset;
21
22 /* FUNCTIONS ******************************************************************/
23
24 static ARC_STATUS RamDiskClose(ULONG FileId)
25 {
26 //
27 // Nothing to do
28 //
29 return ESUCCESS;
30 }
31
32 static ARC_STATUS RamDiskGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
33 {
34 //
35 // Give current seek offset and ram disk size to caller
36 //
37 RtlZeroMemory(Information, sizeof(*Information));
38 Information->EndingAddress.LowPart = gRamDiskSize;
39 Information->CurrentAddress.LowPart = gRamDiskOffset;
40
41 return ESUCCESS;
42 }
43
44 static ARC_STATUS RamDiskOpen(CHAR* Path, OPENMODE OpenMode, ULONG* FileId)
45 {
46 //
47 // Always return success, as contents are already in memory
48 //
49 return ESUCCESS;
50 }
51
52 static ARC_STATUS RamDiskRead(ULONG FileId, VOID* Buffer, ULONG N, ULONG* Count)
53 {
54 PVOID StartAddress;
55
56 //
57 // Get actual pointer
58 //
59 StartAddress = (PVOID)((ULONG_PTR)gRamDiskBase + gRamDiskOffset);
60
61 //
62 // Don't allow reads past our image
63 //
64 if (gRamDiskOffset + N > gRamDiskSize)
65 {
66 *Count = 0;
67 return EIO;
68 }
69
70 //
71 // Do the read
72 //
73 RtlCopyMemory(Buffer, StartAddress, N);
74 *Count = N;
75
76 return ESUCCESS;
77 }
78
79 static ARC_STATUS RamDiskSeek(ULONG FileId, LARGE_INTEGER* Position, SEEKMODE SeekMode)
80 {
81 //
82 // Only accept absolute mode now
83 //
84 if (SeekMode != SeekAbsolute)
85 return EINVAL;
86
87 //
88 // Check if we're in the ramdisk
89 //
90 if (Position->HighPart != 0)
91 return EINVAL;
92 if (Position->LowPart >= gRamDiskSize)
93 return EINVAL;
94
95 //
96 // OK, remember seek position
97 //
98 gRamDiskOffset = Position->LowPart;
99
100 return ESUCCESS;
101 }
102
103 static const DEVVTBL RamDiskVtbl = {
104 RamDiskClose,
105 RamDiskGetFileInformation,
106 RamDiskOpen,
107 RamDiskRead,
108 RamDiskSeek,
109 };
110
111 VOID
112 NTAPI
113 RamDiskInitialize(VOID)
114 {
115 /* Register the RAMDISK device */
116 FsRegisterDevice("ramdisk(0)", &RamDiskVtbl);
117 }
118
119 BOOLEAN
120 NTAPI
121 RamDiskLoadVirtualFile(IN PCHAR FileName)
122 {
123 ULONG RamFileId;
124 ULONG TotalRead, ChunkSize, Count;
125 PCHAR MsgBuffer = "Loading RamDisk...";
126 ULONG PercentPerChunk, Percent;
127 FILEINFORMATION Information;
128 LARGE_INTEGER Position;
129 ARC_STATUS Status;
130
131 //
132 // Display progress
133 //
134 UiDrawBackdrop();
135 UiDrawProgressBarCenter(1, 100, MsgBuffer);
136
137 //
138 // Try opening the ramdisk file
139 //
140 RamFileId = FsOpenFile(FileName);
141 if (!RamFileId)
142 return FALSE;
143
144 //
145 // Get the file size
146 //
147 Status = ArcGetFileInformation(RamFileId, &Information);
148 if (Status != ESUCCESS)
149 {
150 ArcClose(RamFileId);
151 return FALSE;
152 }
153
154 //
155 // For now, limit RAM disks to 4GB
156 //
157 if (Information.EndingAddress.HighPart != 0)
158 {
159 UiMessageBox("RAM disk too big.");
160 ArcClose(RamFileId);
161 return FALSE;
162 }
163 gRamDiskSize = Information.EndingAddress.LowPart;
164
165 //
166 // Allocate memory for it
167 //
168 ChunkSize = 8 * 1024 * 1024;
169 if (gRamDiskSize < ChunkSize)
170 Percent = PercentPerChunk = 0;
171 else
172 Percent = PercentPerChunk = 100 / (gRamDiskSize / ChunkSize);
173 gRamDiskBase = MmAllocateMemoryWithType(gRamDiskSize, LoaderXIPRom);
174 if (!gRamDiskBase)
175 {
176 UiMessageBox("Failed to allocate memory for RAM disk.");
177 ArcClose(RamFileId);
178 return FALSE;
179 }
180
181 //
182 // Read it in chunks
183 //
184 for (TotalRead = 0; TotalRead < gRamDiskSize; TotalRead += ChunkSize)
185 {
186 //
187 // Check if we're at the last chunk
188 //
189 if ((gRamDiskSize - TotalRead) < ChunkSize)
190 {
191 //
192 // Only need the actual data required
193 //
194 ChunkSize = gRamDiskSize - TotalRead;
195 }
196
197 //
198 // Draw progress
199 //
200 UiDrawProgressBarCenter(Percent, 100, MsgBuffer);
201 Percent += PercentPerChunk;
202
203 //
204 // Copy the contents
205 //
206 Position.HighPart = 0;
207 Position.LowPart = TotalRead;
208 Status = ArcSeek(RamFileId, &Position, SeekAbsolute);
209 if (Status == ESUCCESS)
210 {
211 Status = ArcRead(RamFileId,
212 (PVOID)((ULONG_PTR)gRamDiskBase + TotalRead),
213 ChunkSize,
214 &Count);
215 }
216
217 //
218 // Check for success
219 //
220 if (Status != ESUCCESS || Count != ChunkSize)
221 {
222 MmFreeMemory(gRamDiskBase);
223 gRamDiskBase = NULL;
224 gRamDiskSize = 0;
225 ArcClose(RamFileId);
226 UiMessageBox("Failed to read RAM disk.");
227 return FALSE;
228 }
229 }
230
231 ArcClose(RamFileId);
232
233 /* Setup the RAMDISK device */
234 RamDiskInitialize();
235
236 return TRUE;
237 }