19eaa78aff826cc0fb589fbaf8f8f9c67e21a4c5
[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 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS ********************************************************************/
17
18 PVOID gRamDiskBase;
19 ULONG gRamDiskSize;
20 ULONG gRamDiskOffset;
21
22 /* FUNCTIONS ******************************************************************/
23
24 static LONG RamDiskClose(ULONG FileId)
25 {
26 //
27 // Nothing to do
28 //
29 return ESUCCESS;
30 }
31
32 static LONG RamDiskGetFileInformation(ULONG FileId, FILEINFORMATION* Information)
33 {
34 //
35 // Give current seek offset and ram disk size to caller
36 //
37 RtlZeroMemory(Information, sizeof(FILEINFORMATION));
38 Information->EndingAddress.LowPart = gRamDiskSize;
39 Information->CurrentAddress.LowPart = gRamDiskOffset;
40
41 return ESUCCESS;
42 }
43
44 static LONG 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 LONG 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 LONG 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 /* Setup the RAMDISK device */
116 FsRegisterDevice("ramdisk(0)", &RamDiskVtbl);
117 }
118
119 VOID
120 NTAPI
121 RamDiskLoadVirtualFile(IN PCHAR FileName)
122 {
123 ULONG RamFile;
124 ULONG TotalRead, ChunkSize, Count;
125 PCHAR MsgBuffer = "Loading ramdisk...";
126 ULONG PercentPerChunk, Percent;
127 FILEINFORMATION Information;
128 LARGE_INTEGER Position;
129 LONG ret;
130
131 //
132 // Display progress
133 //
134 UiDrawProgressBarCenter(1, 100, MsgBuffer);
135
136 //
137 // Try opening the ramdisk file
138 //
139 ret = ArcOpen(FileName, OpenReadOnly, &RamFile);
140 if (ret == ESUCCESS)
141 {
142 //
143 // Get the file size
144 //
145 ret = ArcGetFileInformation(RamFile, &Information);
146 if (ret != ESUCCESS)
147 {
148 ArcClose(RamFile);
149 return;
150 }
151
152 //
153 // For now, limit RAM disks to 4GB
154 //
155 if (Information.EndingAddress.HighPart != 0)
156 {
157 UiMessageBox("RAM disk too big\n");
158 ArcClose(RamFile);
159 return;
160 }
161 gRamDiskSize = Information.EndingAddress.LowPart;
162
163 //
164 // Allocate memory for it
165 //
166 ChunkSize = 8 * 1024 * 1024;
167 if (gRamDiskSize < ChunkSize)
168 Percent = PercentPerChunk = 0;
169 else
170 Percent = PercentPerChunk = 100 / (gRamDiskSize / ChunkSize);
171 gRamDiskBase = MmAllocateMemoryWithType(gRamDiskSize, LoaderXIPRom);
172 if (!gRamDiskBase)
173 {
174 UiMessageBox("Failed to allocate memory for RAM disk\n");
175 ArcClose(RamFile);
176 return;
177 }
178
179 //
180 // Read it in chunks
181 //
182 for (TotalRead = 0; TotalRead < gRamDiskSize; TotalRead += ChunkSize)
183 {
184 //
185 // Check if we're at the last chunk
186 //
187 if ((gRamDiskSize - TotalRead) < ChunkSize)
188 {
189 //
190 // Only need the actual data required
191 //
192 ChunkSize = gRamDiskSize - TotalRead;
193 }
194
195 //
196 // Draw progress
197 //
198 UiDrawProgressBarCenter(Percent, 100, MsgBuffer);
199 Percent += PercentPerChunk;
200
201 //
202 // Copy the contents
203 //
204 Position.HighPart = 0;
205 Position.LowPart = TotalRead;
206 ret = ArcSeek(RamFile, &Position, SeekAbsolute);
207 if (ret == ESUCCESS)
208 {
209 ret = ArcRead(RamFile,
210 (PVOID)((ULONG_PTR)gRamDiskBase + TotalRead),
211 ChunkSize,
212 &Count);
213 }
214
215 //
216 // Check for success
217 //
218 if (ret != ESUCCESS || Count != ChunkSize)
219 {
220 MmFreeMemory(gRamDiskBase);
221 gRamDiskBase = NULL;
222 gRamDiskSize = 0;
223 ArcClose(RamFile);
224 UiMessageBox("Failed to read ramdisk\n");
225 return;
226 }
227 }
228
229 ArcClose(RamFile);
230
231 // Register a new device for the ramdisk
232 FsRegisterDevice("ramdisk(0)", &RamDiskVtbl);
233 }
234 }