905c40941fac456146d81c62d78a8464cd09470d
[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 RamDiskInitialize(VOID)
113 {
114 /* Register the RAMDISK device */
115 FsRegisterDevice("ramdisk(0)", &RamDiskVtbl);
116 }
117
118 ARC_STATUS
119 RamDiskLoadVirtualFile(
120 IN PCSTR FileName,
121 IN PCSTR DefaultPath OPTIONAL)
122 {
123 ARC_STATUS Status;
124 ULONG RamFileId;
125 ULONG TotalRead, ChunkSize, Count;
126 PCHAR MsgBuffer = "Loading RamDisk...";
127 ULONG PercentPerChunk, Percent;
128 FILEINFORMATION Information;
129 LARGE_INTEGER Position;
130
131 /* Display progress */
132 UiDrawBackdrop();
133 UiDrawProgressBarCenter(1, 100, MsgBuffer);
134
135 /* Try opening the ramdisk file */
136 Status = FsOpenFile(FileName, DefaultPath, OpenReadOnly, &RamFileId);
137 if (Status != ESUCCESS)
138 return Status;
139
140 /* Get the file size */
141 Status = ArcGetFileInformation(RamFileId, &Information);
142 if (Status != ESUCCESS)
143 {
144 ArcClose(RamFileId);
145 return Status;
146 }
147
148 /* For now, limit RAM disks to 4GB */
149 if (Information.EndingAddress.HighPart != 0)
150 {
151 UiMessageBox("RAM disk too big.");
152 ArcClose(RamFileId);
153 return ENOMEM;
154 }
155 gRamDiskSize = Information.EndingAddress.LowPart;
156
157 /* Allocate memory for it */
158 ChunkSize = 8 * 1024 * 1024;
159 if (gRamDiskSize < ChunkSize)
160 Percent = PercentPerChunk = 0;
161 else
162 Percent = PercentPerChunk = 100 / (gRamDiskSize / ChunkSize);
163 gRamDiskBase = MmAllocateMemoryWithType(gRamDiskSize, LoaderXIPRom);
164 if (!gRamDiskBase)
165 {
166 UiMessageBox("Failed to allocate memory for RAM disk.");
167 ArcClose(RamFileId);
168 return ENOMEM;
169 }
170
171 /*
172 * Read it in chunks
173 */
174 for (TotalRead = 0; TotalRead < gRamDiskSize; TotalRead += ChunkSize)
175 {
176 /* Check if we're at the last chunk */
177 if ((gRamDiskSize - TotalRead) < ChunkSize)
178 {
179 /* Only need the actual data required */
180 ChunkSize = gRamDiskSize - TotalRead;
181 }
182
183 /* Draw progress */
184 UiDrawProgressBarCenter(Percent, 100, MsgBuffer);
185 Percent += PercentPerChunk;
186
187 /* Copy the contents */
188 Position.HighPart = 0;
189 Position.LowPart = TotalRead;
190 Status = ArcSeek(RamFileId, &Position, SeekAbsolute);
191 if (Status == ESUCCESS)
192 {
193 Status = ArcRead(RamFileId,
194 (PVOID)((ULONG_PTR)gRamDiskBase + TotalRead),
195 ChunkSize,
196 &Count);
197 }
198
199 /* Check for success */
200 if ((Status != ESUCCESS) || (Count != ChunkSize))
201 {
202 MmFreeMemory(gRamDiskBase);
203 gRamDiskBase = NULL;
204 gRamDiskSize = 0;
205 ArcClose(RamFileId);
206 UiMessageBox("Failed to read RAM disk.");
207 return ((Status != ESUCCESS) ? Status : EIO);
208 }
209 }
210
211 ArcClose(RamFileId);
212
213 /* Setup the RAMDISK device */
214 RamDiskInitialize();
215
216 return ESUCCESS;
217 }