8f2edc6a13023ee0e7d16dddd1e0999dac97c2cd
[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(FILEINFORMATION));
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 /* Setup the RAMDISK device */
116 FsRegisterDevice("ramdisk(0)", &RamDiskVtbl);
117 }
118
119 BOOLEAN
120 NTAPI
121 RamDiskLoadVirtualFile(IN PCHAR FileName)
122 {
123 PFILE RamFile;
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 UiDrawProgressBarCenter(1, 100, MsgBuffer);
135
136 //
137 // Try opening the ramdisk file
138 //
139 RamFile = FsOpenFile(FileName);
140 if (!RamFile)
141 return FALSE;
142
143 //
144 // Get the file size
145 //
146 Status = ArcGetFileInformation(RamFile, &Information);
147 if (Status != ESUCCESS)
148 {
149 FsCloseFile(RamFile);
150 return FALSE;
151 }
152
153 //
154 // For now, limit RAM disks to 4GB
155 //
156 if (Information.EndingAddress.HighPart != 0)
157 {
158 UiMessageBox("RAM disk too big.");
159 FsCloseFile(RamFile);
160 return FALSE;
161 }
162 gRamDiskSize = Information.EndingAddress.LowPart;
163
164 //
165 // Allocate memory for it
166 //
167 ChunkSize = 8 * 1024 * 1024;
168 if (gRamDiskSize < ChunkSize)
169 Percent = PercentPerChunk = 0;
170 else
171 Percent = PercentPerChunk = 100 / (gRamDiskSize / ChunkSize);
172 gRamDiskBase = MmAllocateMemoryWithType(gRamDiskSize, LoaderXIPRom);
173 if (!gRamDiskBase)
174 {
175 UiMessageBox("Failed to allocate memory for RAM disk.");
176 FsCloseFile(RamFile);
177 return FALSE;
178 }
179
180 //
181 // Read it in chunks
182 //
183 for (TotalRead = 0; TotalRead < gRamDiskSize; TotalRead += ChunkSize)
184 {
185 //
186 // Check if we're at the last chunk
187 //
188 if ((gRamDiskSize - TotalRead) < ChunkSize)
189 {
190 //
191 // Only need the actual data required
192 //
193 ChunkSize = gRamDiskSize - TotalRead;
194 }
195
196 //
197 // Draw progress
198 //
199 UiDrawProgressBarCenter(Percent, 100, MsgBuffer);
200 Percent += PercentPerChunk;
201
202 //
203 // Copy the contents
204 //
205 Position.HighPart = 0;
206 Position.LowPart = TotalRead;
207 Status = ArcSeek(RamFile, &Position, SeekAbsolute);
208 if (Status == ESUCCESS)
209 {
210 Status = ArcRead(RamFile,
211 (PVOID)((ULONG_PTR)gRamDiskBase + TotalRead),
212 ChunkSize,
213 &Count);
214 }
215
216 //
217 // Check for success
218 //
219 if (Status != ESUCCESS || Count != ChunkSize)
220 {
221 MmFreeMemory(gRamDiskBase);
222 gRamDiskBase = NULL;
223 gRamDiskSize = 0;
224 FsCloseFile(RamFile);
225 UiMessageBox("Failed to read RAM disk.");
226 return FALSE;
227 }
228 }
229
230 FsCloseFile(RamFile);
231
232 // Register a new device for the ramdisk
233 FsRegisterDevice("ramdisk(0)", &RamDiskVtbl);
234
235 return TRUE;
236 }