]> git.saurik.com Git - apple/bootx.git/blame - bootx.tproj/sl.subproj/main.c
BootX-74.1.tar.gz
[apple/bootx.git] / bootx.tproj / sl.subproj / main.c
CommitLineData
04fee52e
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
8be739c0
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
04fee52e 11 *
8be739c0
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
04fee52e
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
8be739c0
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
04fee52e
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * main.c - Main functions for BootX.
24 *
8be739c0 25 * Copyright (c) 1998-2004 Apple Computer, Inc.
04fee52e
A
26 *
27 * DRI: Josh de Cesare
28 */
29
30
31#include <sl.h>
8be739c0 32#include "aes.h"
04fee52e
A
33
34static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr);
35static void Main(ClientInterfacePtr ciPtr);
36static long InitEverything(ClientInterfacePtr ciPtr);
8be739c0 37static long DecodeKernel(void *binary);
04fee52e
A
38static long SetUpBootArgs(void);
39static long CallKernel(void);
40static void FailToBoot(long num);
41static long InitMemoryMap(void);
42static long GetOFVersion(void);
43static long TestForKey(long key);
44static long GetBootPaths(void);
8be739c0 45static long ReadBootPlist(char *devSpec);
04fee52e
A
46
47const unsigned long StartTVector[2] = {(unsigned long)Start, 0};
48
49char gStackBaseAddr[0x8000];
50
51char *gVectorSaveAddr;
52long gImageLastKernelAddr = 0;
53long gImageFirstBootXAddr = kLoadAddr;
54long gKernelEntryPoint;
55long gDeviceTreeAddr;
56long gDeviceTreeSize;
57long gBootArgsAddr;
58long gBootArgsSize;
59long gSymbolTableAddr;
60long gSymbolTableSize;
61
62long gBootSourceNumber = -1;
63long gBootSourceNumberMax;
366defd1 64long gBootMode = kBootModeNormal;
04fee52e
A
65long gBootDeviceType;
66long gBootFileType;
b1faa321 67char gHaveKernelCache = 0;
04fee52e
A
68char gBootDevice[256];
69char gBootFile[256];
8be739c0 70TagPtr gBootDict = NULL;
b1faa321
A
71static char gBootKernelCacheFile[512];
72static char gExtensionsSpec[4096];
73static char gCacheNameAdler[64 + sizeof(gBootFile)];
74static char *gPlatformName = gCacheNameAdler;
04fee52e
A
75
76char gTempStr[4096];
77
78long *gDeviceTreeMMTmp = 0;
79
8be739c0 80long gOFVersion = 0;
04fee52e
A
81
82char *gKeyMap;
83
71019aa0
A
84long gRootAddrCells;
85long gRootSizeCells;
86
04fee52e
A
87CICell gChosenPH;
88CICell gOptionsPH;
89CICell gScreenPH;
90CICell gMemoryMapPH;
91CICell gStdOutPH;
92
93CICell gMMUIH;
94CICell gMemoryIH;
95CICell gStdOutIH;
96CICell gKeyboardIH;
97
71019aa0
A
98static char gOFVectorSave[kVectorSize];
99static unsigned long gOFMSRSave;
100static unsigned long gOFSPRG0Save;
101static unsigned long gOFSPRG1Save;
102static unsigned long gOFSPRG2Save;
103static unsigned long gOFSPRG3Save;
104
8be739c0
A
105//int gDebugCount = 0;
106
04fee52e
A
107// Private Functions
108
109static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr)
110{
111 long newSP;
112
113 // Move the Stack to a chunk of the BSS
114 newSP = (long)gStackBaseAddr + sizeof(gStackBaseAddr) - 0x100;
115 __asm__ volatile("mr r1, %0" : : "r" (newSP));
116
117 Main(ciPtr);
118}
119
120
8be739c0 121
04fee52e
A
122static void Main(ClientInterfacePtr ciPtr)
123{
124 long ret;
b1faa321 125 int trycache;
8be739c0
A
126 long flags, cachetime, kerneltime, exttime = 0;
127 void *binary = (void *)kLoadAddr;
04fee52e
A
128
129 ret = InitEverything(ciPtr);
130 if (ret != 0) Exit();
8be739c0
A
131
132
04fee52e
A
133 // Get or infer the boot paths.
134 ret = GetBootPaths();
135 if (ret != 0) FailToBoot(1);
136
8be739c0 137#if kFailToBoot
366defd1 138 DrawSplashScreen(0);
8be739c0 139#endif
04fee52e
A
140
141 while (ret == 0) {
b1faa321
A
142 trycache = (0 == (gBootMode & kBootModeSafe))
143 && (gBootKernelCacheFile[0] != 0);
144
145 if (trycache && (gBootFileType == kBlockDeviceType)) do {
146
147 // if we haven't found the kernel yet, don't use the cache
8be739c0 148 ret = GetFileInfo(NULL, gBootFile, &flags, &kerneltime);
b1faa321
A
149 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
150 trycache = 0;
151 break;
152 }
153 ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
154 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
8be739c0 155 || (cachetime < kerneltime)) {
b1faa321
A
156 trycache = 0;
157 break;
158 }
8be739c0 159 ret = GetFileInfo(gExtensionsSpec, "Extensions", &flags, &exttime);
b1faa321 160 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
8be739c0
A
161 && (cachetime < exttime)) {
162 trycache = 0;
163 break;
164 }
165 if (kerneltime > exttime)
166 exttime = kerneltime;
167 if (cachetime != (exttime + 1)) {
b1faa321
A
168 trycache = 0;
169 break;
170 }
171 } while (0);
172
173 if (trycache) {
174 ret = LoadFile(gBootKernelCacheFile);
175 if (ret != -1) {
8be739c0 176 ret = DecodeKernel(binary);
b1faa321
A
177 if (ret != -1) break;
178 }
179 }
8be739c0
A
180 ret = LoadThinFatFile(gBootFile, &binary);
181 if (ret != -1) ret = DecodeKernel(binary);
04fee52e
A
182 if (ret != -1) break;
183
184 ret = GetBootPaths();
185 if (ret != 0) FailToBoot(2);
186 }
187
366defd1 188 if (ret != 0) FailToBoot(3);
04fee52e 189
b1faa321
A
190 if (!gHaveKernelCache) {
191 ret = LoadDrivers(gExtensionsSpec);
192 if (ret != 0) FailToBoot(4);
193 }
366defd1 194
8be739c0 195#if kFailToBoot
366defd1 196 DrawSplashScreen(1);
8be739c0 197#endif
366defd1 198
04fee52e 199 ret = SetUpBootArgs();
366defd1 200 if (ret != 0) FailToBoot(5);
04fee52e
A
201
202 ret = CallKernel();
203
366defd1 204 FailToBoot(6);
04fee52e
A
205}
206
8be739c0
A
207static uint32_t UnescapeData(const uint8_t * src,
208 uint32_t srcLen,
209 uint8_t * dst,
210 uint32_t dstMaxLen)
211{
212 uint32_t cnt, cnt2, dstLen = 0;
213 uint8_t byte;
214
215 for (cnt = 0; cnt < srcLen;) {
216 byte = src[cnt++];
217 if (byte == 0xFF) {
218 byte = src[cnt++];
219 cnt2 = byte & 0x7F;
220 byte = (byte & 0x80) ? 0xFF : 0x00;
221 } else
222 cnt2 = 1;
223 while (cnt2--) {
224 if (dstLen >= dstMaxLen)
225 return (-1);
226 dst[dstLen++] = byte;
227 }
228 }
229 return (dstLen);
230}
04fee52e
A
231
232static long InitEverything(ClientInterfacePtr ciPtr)
233{
366defd1 234 long ret, mem_base, mem_base2, size;
04fee52e 235 CICell keyboardPH;
366defd1 236 char name[32], securityMode[33];
b1faa321
A
237 long length;
238 char *compatible;
04fee52e
A
239
240 // Init the OF Client Interface.
241 ret = InitCI(ciPtr);
242 if (ret != 0) return -1;
243
244 // Get the OF Version
245 gOFVersion = GetOFVersion();
246 if (gOFVersion == 0) return -1;
247
71019aa0
A
248 // Get the address and size cells for the root.
249 GetProp(Peer(0), "#address-cells", (char *)&gRootAddrCells, 4);
250 GetProp(Peer(0), "#size-cells", (char *)&gRootSizeCells, 4);
251 if ((gRootAddrCells > 2) || (gRootAddrCells > 2)) return -1;
252
04fee52e 253 // Init the SL Words package.
366defd1 254 ret = InitSLWords();
04fee52e
A
255 if (ret != 0) return -1;
256
257 // Get the phandle for /options
258 gOptionsPH = FindDevice("/options");
259 if (gOptionsPH == -1) return -1;
260
261 // Get the phandle for /chosen
262 gChosenPH = FindDevice("/chosen");
263 if (gChosenPH == -1) return -1;
264
265 // Init the Memory Map.
266 ret = InitMemoryMap();
267 if (ret != 0) return -1;
268
269 // Get IHandles for the MMU and Memory
270 size = GetProp(gChosenPH, "mmu", (char *)&gMMUIH, 4);
271 if (size != 4) {
272 printf("Failed to get the IH for the MMU.\n");
273 return -1;
274 }
275 size = GetProp(gChosenPH, "memory", (char *)&gMemoryIH, 4);
276 if (size != 4) {
277 printf("Failed to get the IH for the Memory.\n");
278 return -1;
279 }
280
b1faa321
A
281 // Get first element of root's compatible property.
282 ret = GetPackageProperty(Peer(0), "compatible", &compatible, &length);
283 if (ret != -1)
284 strcpy(gPlatformName, compatible);
285
04fee52e
A
286 // Get stdout's IH, so that the boot display can be found.
287 ret = GetProp(gChosenPH, "stdout", (char *)&gStdOutIH, 4);
288 if (ret == 4) gStdOutPH = InstanceToPackage(gStdOutIH);
289 else gStdOutPH = gStdOutIH = 0;
290
291 // Try to find the keyboard using chosen
292 ret = GetProp(gChosenPH, "stdin", (char *)&gKeyboardIH, 4);
293 if (ret != 4) gKeyboardIH = 0;
294 else {
295 keyboardPH = InstanceToPackage(gKeyboardIH);
296 ret = GetProp(keyboardPH, "name", name, 31);
297 if (ret != -1) {
298 name[ret] = '\0';
299 if (strcmp(name, "keyboard") && strcmp(name, "kbd")) gKeyboardIH = 0;
300 } else gKeyboardIH = 0;
301 }
302
303 // Try to the find the keyboard using open if chosen did not work.
304 if (gKeyboardIH == 0) gKeyboardIH = Open("keyboard");
305 if (gKeyboardIH == 0) gKeyboardIH = Open("kbd");
306
307 // Get the key map set up, and make it up to date.
308 gKeyMap = InitKeyMap(gKeyboardIH);
309 if (gKeyMap == NULL) return -1;
310 UpdateKeyMap();
311
366defd1
A
312 // Test for Secure Boot Mode.
313 size = GetProp(gOptionsPH, "security-mode", securityMode, 32);
314 if (size != -1) {
315 securityMode[size] = '\0';
316 if (strcmp(securityMode, "none")) gBootMode |= kBootModeSecure;
04fee52e 317 }
04fee52e
A
318
319#if kFailToBoot
320 // 'cmd-s' or 'cmd-v' is pressed set outputLevel to kOutputLevelFull
366defd1
A
321 if (((gBootMode & kBootModeSecure) == 0) && TestForKey(kCommandKey) &&
322 (TestForKey('s') || TestForKey('v'))) {
04fee52e 323 SetOutputLevel(kOutputLevelFull);
366defd1
A
324 } else {
325 SetOutputLevel(kOutputLevelOff);
326 }
04fee52e
A
327#else
328 SetOutputLevel(kOutputLevelFull);
329#endif
330
331 // printf now works.
332 printf("\n\nMac OS X Loader\n");
333
8be739c0
A
334 // Test for Safe Boot Mode; Shift and not Delete.
335 if (((gBootMode & kBootModeSecure) == 0)
336 && TestForKey(kShiftKey) && !TestForKey(kDeleteKey)) {
366defd1
A
337 gBootMode |= kBootModeSafe;
338 }
8be739c0
A
339
340 {
341 // Claim memory for the FS Cache.
342 if (Claim(kFSCacheAddr, kFSCacheSize, 0) == 0) {
343 printf("Claim for fs cache failed.\n");
04fee52e
A
344 return -1;
345 }
8be739c0
A
346
347 // Claim memory for malloc.
348 if (Claim(kMallocAddr, kMallocSize, 0) == 0) {
349 printf("Claim for malloc failed.\n");
04fee52e
A
350 return -1;
351 }
8be739c0 352 malloc_init((char *)kMallocAddr, kMallocSize);
04fee52e 353
8be739c0
A
354 // Claim memory for the Load Addr.
355 mem_base = Claim(kLoadAddr, kLoadSize, 0);
356 if (mem_base == 0) {
357 printf("Claim for Load Area failed.\n");
04fee52e
A
358 return -1;
359 }
360
8be739c0
A
361 // Claim the memory for the Image Addr
362 if (gOFVersion >= kOFVersion3x) {
363 mem_base = Claim(kImageAddr, kImageSize, 0);
364 if (mem_base == 0) {
365 printf("Claim for Image Area failed.\n");
366 return -1;
367 }
368 } else {
369 // Claim the 1:1 mapped chunks first.
370 mem_base = Claim(kImageAddr0, kImageSize0, 0);
371 mem_base2 = Claim(kImageAddr2, kImageSize2, 0);
372 if ((mem_base == 0) || (mem_base2 == 0)) {
373 printf("Claim for Image Area failed.\n");
374 return -1;
375 }
376
377 // Unmap the old xcoff stack.
378 CallMethod(2, 0, gMMUIH, "unmap", 0x00380000, 0x00080000);
379
380 // Grab the physical memory then the logical.
381 CallMethod(3, 1, gMemoryIH, "claim",
382 kImageAddr1Phys, kImageSize1, 0, &mem_base);
383 CallMethod(3, 1, gMMUIH, "claim",
384 kImageAddr1, kImageSize1, 0, &mem_base2);
385 if ((mem_base == 0) || (mem_base2 == 0)) {
386 printf("Claim for Image Area failed.\n");
387 return -1;
388 }
389
390 // Map them together.
391 CallMethod(4, 0, gMMUIH, "map",
392 kImageAddr1Phys, kImageAddr1, kImageSize1, 0);
393 }
394
395 bzero((char *)kImageAddr, kImageSize);
396
397 // Allocate some space for the Vector Save area.
398 gVectorSaveAddr = AllocateBootXMemory(kVectorSize);
399 if (gVectorSaveAddr == 0) {
400 printf("Allocation for the Vector Save Area failed.\n");
401 return -1;
402 }
403 // Find all the displays and set them up.
404 ret = InitDisplays(1);
405 if (ret != 0) {
406 printf("InitDisplays failed.\n");
407 return -1;
408 }
409 }
04fee52e
A
410
411 return 0;
412}
413
414
71019aa0
A
415long ThinFatBinary(void **binary, unsigned long *length)
416{
417 long ret;
418
419 ret = ThinFatBinaryMachO(binary, length);
420 if (ret == -1) ret = ThinFatBinaryElf(binary, length);
421
422 return ret;
423}
424
8be739c0 425static long DecodeKernel(void *binary)
04fee52e
A
426{
427 long ret;
8be739c0 428 compressed_kernel_header *kernel_header = (compressed_kernel_header *)binary;
b1faa321
A
429 u_int32_t size;
430
431 if (kernel_header->signature == 'comp') {
432 if (kernel_header->compress_type != 'lzss')
433 return -1;
434 if (kernel_header->platform_name[0] && strcmp(gPlatformName, kernel_header->platform_name))
435 return -1;
436 if (kernel_header->root_path[0] && strcmp(gBootFile, kernel_header->root_path))
437 return -1;
438
439 binary = AllocateBootXMemory(kernel_header->uncompressed_size);
440
441 size = decompress_lzss((u_int8_t *) binary, &kernel_header->data[0], kernel_header->compressed_size);
442 if (kernel_header->uncompressed_size != size) {
443 printf("size mismatch from lzss %x\n", size);
444 return -1;
445 }
446 if (kernel_header->adler32 !=
8be739c0 447 Adler32(binary, kernel_header->uncompressed_size)) {
b1faa321
A
448 printf("adler mismatch\n");
449 return -1;
450 }
451 }
04fee52e 452
71019aa0
A
453 ThinFatBinary(&binary, 0);
454
455 ret = DecodeMachO(binary);
456 if (ret == -1) ret = DecodeElf(binary);
04fee52e
A
457
458 return ret;
459}
460
461
462static long SetUpBootArgs(void)
463{
71019aa0
A
464 boot_args_ptr args;
465 CICell memoryPH;
466 long graphicsBoot = 1;
467 long ret, cnt, size, dash;
468 long sKey, vKey, keyPos;
8be739c0 469 char ofBootArgs[240], *ofArgs, tc, keyStr[8];
71019aa0
A
470 unsigned char mem_regs[kMaxDRAMBanks*16];
471 unsigned long mem_banks, bank_shift;
04fee52e
A
472
473 // Save file system cache statistics.
474 SetProp(gChosenPH, "BootXCacheHits", (char *)&gCacheHits, 4);
475 SetProp(gChosenPH, "BootXCacheMisses", (char *)&gCacheMisses, 4);
476 SetProp(gChosenPH, "BootXCacheEvicts", (char *)&gCacheEvicts, 4);
477
478 // Allocate some memory for the BootArgs.
479 gBootArgsSize = sizeof(boot_args);
480 gBootArgsAddr = AllocateKernelMemory(gBootArgsSize);
481
482 // Add the BootArgs to the memory-map.
483 AllocateMemoryRange("BootArgs", gBootArgsAddr, gBootArgsSize);
484
485 args = (boot_args_ptr)gBootArgsAddr;
486
487 args->Revision = kBootArgsRevision;
71019aa0 488 args->Version = kBootArgsVersion1;
04fee52e
A
489 args->machineType = 0;
490
366defd1 491 // Check the Keyboard for 'cmd-s' and 'cmd-v'
04fee52e 492 UpdateKeyMap();
366defd1 493 if ((gBootMode & kBootModeSecure) == 0) {
04fee52e
A
494 sKey = TestForKey(kCommandKey) && TestForKey('s');
495 vKey = TestForKey(kCommandKey) && TestForKey('v');
04fee52e 496 } else {
04fee52e
A
497 sKey = 0;
498 vKey = 0;
04fee52e 499 }
04fee52e
A
500
501 // if 'cmd-s' or 'cmd-v' was pressed do a text boot.
502 if (sKey || vKey) graphicsBoot = 0;
503
04fee52e
A
504 // Create the command line.
505 if (gOFVersion < kOFVersion3x) {
506 ofBootArgs[0] = ' ';
8be739c0 507 size = GetProp(gChosenPH, "machargs", ofBootArgs + 1, (sizeof(ofBootArgs) - 2));
04fee52e 508 if (size == -1) {
8be739c0 509 size = GetProp(gOptionsPH, "boot-command", ofBootArgs, (sizeof(ofBootArgs) - 1));
04fee52e
A
510 if (size == -1) ofBootArgs[0] = '\0';
511 else ofBootArgs[size] = '\0';
512 // Look for " bootr" but skip the number.
513 if (!strncmp(ofBootArgs + 1, " bootr", 6)) {
514 strcpy(ofBootArgs, ofBootArgs + 7);
515 } else ofBootArgs[0] = '\0';
516 SetProp(gChosenPH, "machargs", ofBootArgs, strlen(ofBootArgs) + 1);
517 } else ofBootArgs[size] = '\0';
518 // Force boot-command to start with 0 bootr.
519 sprintf(gTempStr, "0 bootr%s", ofBootArgs);
520 SetProp(gOptionsPH, "boot-command", gTempStr, strlen(gTempStr));
521 } else {
8be739c0 522 size = GetProp(gOptionsPH, "boot-args", ofBootArgs, (sizeof(ofBootArgs) - 1));
04fee52e
A
523 if (size == -1) ofBootArgs[0] = '\0';
524 else ofBootArgs[size] = '\0';
525 }
526
527 if (ofBootArgs[0] != '\0') {
528 // Look for special options and copy the rest.
529 dash = 0;
530 ofArgs = ofBootArgs;
531 while ((tc = *ofArgs) != '\0') {
532 tc = tolower(tc);
533
534 // Check for entering a dash arg.
535 if (tc == '-') {
536 dash = 1;
537 ofArgs++;
538 continue;
539 }
540
541 // Do special stuff if in a dash arg.
542 if (dash) {
366defd1 543 if (tc == 's') {
04fee52e
A
544 graphicsBoot = 0;
545 ofArgs++;
546 sKey = 0;
366defd1 547 } else if (tc == 'v') {
04fee52e
A
548 graphicsBoot = 0;
549 ofArgs++;
550 vKey = 0;
366defd1 551 } else {
04fee52e
A
552 // Check for exiting dash arg
553 if (isspace(tc)) dash = 0;
554
366defd1 555 // Copy any non 's' or 'v'
04fee52e
A
556 ofArgs++;
557 }
558 } else {
559 // Not a dash arg so just copy it.
560 ofArgs++;
366defd1 561 }
04fee52e
A
562 }
563 }
564
366defd1 565 // Add any pressed keys (s, v, shift) to the command line
04fee52e 566 keyPos = 0;
366defd1 567 if (sKey || vKey || (gBootMode & kBootModeSafe)) {
04fee52e
A
568 keyStr[keyPos++] = '-';
569
04fee52e
A
570 if (sKey) keyStr[keyPos++] = 's';
571 if (vKey) keyStr[keyPos++] = 'v';
366defd1 572 if (gBootMode & kBootModeSafe) keyStr[keyPos++] = 'x';
04fee52e
A
573
574 keyStr[keyPos++] = ' ';
575 }
576 keyStr[keyPos++] = '\0';
577
366defd1 578 sprintf(args->CommandLine, "%s%s", keyStr, ofBootArgs);
04fee52e 579
71019aa0
A
580 // If the address or size cells are larger than 1, use page numbers
581 // and signify Boot Args Version 2.
582 if ((gRootAddrCells == 1) && (gRootSizeCells == 1)) bank_shift = 0;
583 else {
584 bank_shift = 12;
585 args->Version = kBootArgsVersion2;
586 }
587
588 // Get the information about the memory banks
04fee52e
A
589 memoryPH = FindDevice("/memory");
590 if (memoryPH == -1) return -1;
71019aa0 591 size = GetProp(memoryPH, "reg", mem_regs, kMaxDRAMBanks * 16);
04fee52e 592 if (size == 0) return -1;
71019aa0
A
593 mem_banks = size / (4 * (gRootAddrCells + gRootSizeCells));
594 if (mem_banks > kMaxDRAMBanks) mem_banks = kMaxDRAMBanks;
595
596 // Convert the reg properties to 32 bit values
597 for (cnt = 0; cnt < mem_banks; cnt++) {
598 if (gRootAddrCells == 1) {
599 args->PhysicalDRAM[cnt].base =
600 *(unsigned long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells)) >> bank_shift;
601 } else {
602 args->PhysicalDRAM[cnt].base =
603 *(unsigned long long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells)) >> bank_shift;
604
605 }
606
607 if (gRootSizeCells == 1) {
608 args->PhysicalDRAM[cnt].size =
609 *(unsigned long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells) + 4 * gRootAddrCells) >> bank_shift;
610 } else {
611 args->PhysicalDRAM[cnt].size =
612 *(unsigned long long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells) + 4 * gRootAddrCells) >> bank_shift;
613
614 }
615 }
04fee52e 616
71019aa0
A
617 // Collapse the memory banks into contiguous chunks
618 for (cnt = 0; cnt < mem_banks - 1; cnt++) {
619 if ((args->PhysicalDRAM[cnt + 1].base != 0) &&
620 ((args->PhysicalDRAM[cnt].base + args->PhysicalDRAM[cnt].size) !=
621 args->PhysicalDRAM[cnt + 1].base)) continue;
622
623 args->PhysicalDRAM[cnt].size += args->PhysicalDRAM[cnt + 1].size;
624 bcopy(args->PhysicalDRAM + cnt + 2, args->PhysicalDRAM + cnt + 1, (mem_banks - cnt - 2) * sizeof(DRAMBank));
625 mem_banks--;
626 cnt--;
04fee52e 627 }
71019aa0 628 bzero(args->PhysicalDRAM + mem_banks, (kMaxDRAMBanks - mem_banks) * sizeof(DRAMBank));
04fee52e
A
629
630 // Get the video info
8be739c0 631 GetMainScreenPH(&args->Video, 1);
366defd1 632 args->Video.v_display = graphicsBoot;
04fee52e
A
633
634 // Add the DeviceTree to the memory-map.
635 // The actuall address and size must be filled in later.
636 AllocateMemoryRange("DeviceTree", 0, 0);
637
638 ret = FlattenDeviceTree();
639 if (ret != 0) return -1;
640
641 // Fill in the address and size of the device tree.
642 if (gDeviceTreeAddr) {
643 gDeviceTreeMMTmp[0] = gDeviceTreeAddr;
644 gDeviceTreeMMTmp[1] = gDeviceTreeSize;
645 }
646
647 args->deviceTreeP = (void *)gDeviceTreeAddr;
648 args->deviceTreeLength = gDeviceTreeSize;
649 args->topOfKernelData = AllocateKernelMemory(0);
650
651 return 0;
652}
653
654
655static long CallKernel(void)
656{
71019aa0 657 unsigned long msr, cnt;
04fee52e
A
658
659 Quiesce();
660
661 printf("\nCall Kernel!\n");
662
71019aa0
A
663 // Save SPRs for OF
664 __asm__ volatile("mfmsr %0" : "=r" (gOFMSRSave));
665 __asm__ volatile("mfsprg %0, 0" : "=r" (gOFSPRG0Save));
666 __asm__ volatile("mfsprg %0, 1" : "=r" (gOFSPRG1Save));
667 __asm__ volatile("mfsprg %0, 2" : "=r" (gOFSPRG2Save));
668 __asm__ volatile("mfsprg %0, 3" : "=r" (gOFSPRG3Save));
669
670 // Turn off translations
04fee52e 671 msr = 0x00001000;
71019aa0 672 __asm__ volatile("sync");
04fee52e
A
673 __asm__ volatile("mtmsr %0" : : "r" (msr));
674 __asm__ volatile("isync");
675
71019aa0
A
676 // Save the OF's Exceptions Vectors
677 bcopy(0x0, gOFVectorSave, kVectorSize);
678
679 // Move the Exception Vectors
04fee52e
A
680 bcopy(gVectorSaveAddr, 0x0, kVectorSize);
681 for (cnt = 0; cnt < kVectorSize; cnt += 0x20) {
682 __asm__ volatile("dcbf 0, %0" : : "r" (cnt));
683 __asm__ volatile("icbi 0, %0" : : "r" (cnt));
684 }
685
686 // Move the Image1 save area for OF 1.x / 2.x
687 if (gOFVersion < kOFVersion3x) {
688 bcopy((char *)kImageAddr1Phys, (char *)kImageAddr1, kImageSize1);
689 for (cnt = kImageAddr1; cnt < kImageSize1; cnt += 0x20) {
690 __asm__ volatile("dcbf 0, %0" : : "r" (cnt));
691 __asm__ volatile("icbi 0, %0" : : "r" (cnt));
692 }
693 }
694
695 // Make sure everything get sync'd up.
696 __asm__ volatile("isync");
697 __asm__ volatile("sync");
698 __asm__ volatile("eieio");
699
71019aa0 700 // Call the Kernel's entry point
04fee52e 701 (*(void (*)())gKernelEntryPoint)(gBootArgsAddr, kMacOSXSignature);
8be739c0 702
71019aa0
A
703 // Restore OF's Exception Vectors
704 bcopy(gOFVectorSave, 0x0, 0x3000);
705 for (cnt = 0; cnt < kVectorSize; cnt += 0x20) {
706 __asm__ volatile("dcbf 0, %0" : : "r" (cnt));
707 __asm__ volatile("icbi 0, %0" : : "r" (cnt));
708 }
709
710 // Restore SPRs for OF
711 __asm__ volatile("mtsprg 0, %0" : : "r" (gOFSPRG0Save));
712 __asm__ volatile("mtsprg 1, %0" : : "r" (gOFSPRG1Save));
713 __asm__ volatile("mtsprg 2, %0" : : "r" (gOFSPRG2Save));
714 __asm__ volatile("mtsprg 3, %0" : : "r" (gOFSPRG3Save));
715
716 // Restore translations
717 __asm__ volatile("sync");
718 __asm__ volatile("mtmsr %0" : : "r" (gOFMSRSave));
719 __asm__ volatile("isync");
720
04fee52e
A
721 return -1;
722}
723
724
725static void FailToBoot(long num)
726{
8be739c0
A
727 // useful for those holding down command-v ...
728 printf("FailToBoot: %d\n", num);
04fee52e 729#if kFailToBoot
366defd1 730 DrawFailedBootPicture();
04fee52e
A
731 while (1);
732 num = 0;
733#else
04fee52e
A
734 Enter(); // For debugging
735#endif
736}
737
738
739static long InitMemoryMap(void)
740{
741 long result;
742
366defd1
A
743 result = Interpret(0, 1,
744 " dev /chosen"
745 " new-device"
746 " \" memory-map\" device-name"
747 " active-package"
748 " device-end"
749 , &gMemoryMapPH);
04fee52e
A
750
751 return result;
752}
753
754
755static long GetOFVersion(void)
756{
757 CICell ph;
758 char versStr[256], *tmpStr;
759 long vers, size;
760
761 // Get the openprom package
762 ph = FindDevice("/openprom");
763 if (ph == -1) return 0;
764
765 // Get it's model property
766 size = GetProp(ph, "model", versStr, 255);
767 if (size == -1) return -1;
768 versStr[size] = '\0';
769
770 // Find the start of the number.
771 tmpStr = NULL;
772 if (!strncmp(versStr, "Open Firmware, ", 15)) {
773 tmpStr = versStr + 15;
774 } else if (!strncmp(versStr, "OpenFirmware ", 13)) {
775 tmpStr = versStr + 13;
8be739c0 776 } else return -1;
04fee52e
A
777
778 // Clasify by each instance as needed...
779 switch (*tmpStr) {
780 case '1' :
781 vers = kOFVersion1x;
782 break;
783
784 case '2' :
785 vers = kOFVersion2x;
786 break;
787
788 case '3' :
789 vers = kOFVersion3x;
790 break;
791
71019aa0
A
792 case '4' :
793 vers = kOFVersion4x;
794 break;
795
04fee52e
A
796 default :
797 vers = 0;
798 break;
799 }
800
801 return vers;
802}
803
804
805static long TestForKey(long key)
806{
807 long keyNum;
808 long bp;
809 char tc;
810
811 if (gOFVersion < kOFVersion3x) {
812 switch(key) {
813 case 'a' : keyNum = 7; break;
814 case 's' : keyNum = 6; break;
815 case 'v' : keyNum = 14; break;
816 case 'y' : keyNum = 23; break;
817 case kCommandKey : keyNum = 48; break;
818 case kOptKey : keyNum = 61; break;
819 case kShiftKey : keyNum = 63; break;
820 case kControlKey : keyNum = 49; break;
821 default : keyNum = -1; break;
822 }
823 } else {
824 switch(key) {
825 case 'a' : keyNum = 3; break;
826 case 's' : keyNum = 17; break;
827 case 'v' : keyNum = 30; break;
828 case 'y' : keyNum = 27; break;
829 case kCommandKey : keyNum = 228; break;
830 case kOptKey : keyNum = 229; break;
831 case kShiftKey : keyNum = 230; break;
832 case kControlKey : keyNum = 231; break;
8be739c0 833 case kDeleteKey : keyNum = 45; break;
04fee52e
A
834 default : keyNum = -1; break;
835 }
836
837 // Map the right modifier keys on to the left.
838 gKeyMap[28] |= gKeyMap[28] << 4;
839 }
840
841 if (keyNum == -1) return 0;
842
843 bp = keyNum & 7;
844 tc = gKeyMap[keyNum >> 3];
845
846 return (tc & (1 << bp)) != 0;
847}
848
849
850#define kBootpBootFileOffset (108)
851
852static long GetBootPaths(void)
853{
854 long ret, cnt, cnt2, cnt3, cnt4, size, partNum, bootplen, bsdplen;
b1faa321 855 unsigned long adler32;
8be739c0 856 char *filePath, *buffer, uuidStr[64];
04fee52e
A
857
858 if (gBootSourceNumber == -1) {
8be739c0
A
859 // Get the boot device and derive its type
860 // (try chosen "bootpath", then boot-device in the options)
04fee52e
A
861 size = GetProp(gChosenPH, "bootpath", gBootDevice, 255);
862 gBootDevice[size] = '\0';
863 if (gBootDevice[0] == '\0') {
864 size = GetProp(gOptionsPH, "boot-device", gBootDevice, 255);
865 gBootDevice[size] = '\0';
866 }
8be739c0
A
867// hardcode to my Apple_Boot before my Apple_RAID
868// debug: override boot device to boot from disk even if OF used TFTP
869//printf("old gBootDevice: %s\n", gBootDevice);
870//strcpy(gBootDevice, "fw/node@d0010100007a9d/sbp-2@c000/@0:12"); // SmartDisk
871//strcpy(gBootDevice, "fw/node@d04b491d060252/sbp-2@c000/@0:9"); // mconcatI
872//strcpy(gBootDevice, "fw/node@d04b491d060252/sbp-2@c000/@0:11"); // mconcatI
873//strcpy(gBootDevice, "fw/node@d04b491d075f57/sbp-2@c000/@0:2"); // mconcatII
874//strcpy(gBootDevice, "fw/node@d04b491d075f57/sbp-2@c000/@0:4"); // mconcatII
875//strcpy(gBootDevice, "fw/node@50770e0000676f/sbp-2@4000/@0:3"); // m120
876//strcpy(gBootDevice, "fw/node@50770e0000725b/sbp-2@4000/@0:3"); // m120
877
878
879 // Look for Boot.plist-based booter stuff (like RAID :)
880 ret = ReadBootPlist(gBootDevice);
881 if (ret == 0) {
882 // success -> gBootDevice = "AppleRAID/#:0,\\\\:tbxi"
883 (void)LookForRAID(gBootDict); // could take gBootDevice?
884 }
04fee52e 885
8be739c0
A
886
887 // note RAID itself is of "block" type like members
888 gBootDeviceType = GetDeviceType(gBootDevice);
889 if(gBootDeviceType == -1) {
890 printf("Could not find boot device %s\n", gBootDevice);
891 return -1;
892 }
893
894
895 // Get the boot file (e.g. mach_kernel)
04fee52e
A
896 size = GetProp(gChosenPH, "bootargs", gBootFile, 256);
897 gBootFile[size] = '\0';
898
899 if (gBootFile[0] != '\0') {
900 gBootFileType = GetDeviceType(gBootFile);
901 gBootSourceNumberMax = 0;
902 } else {
903 gBootSourceNumber = 0;
904 gBootFileType = gBootDeviceType;
905 if (gBootFileType == kNetworkDeviceType) gBootSourceNumberMax = 1;
366defd1
A
906 else {
907 if (gOFVersion < kOFVersion3x) {
908 gBootSourceNumberMax = 4;
909 } else {
910 gBootSourceNumberMax = 6;
911 }
912 }
04fee52e 913 }
8be739c0 914// gBootSourceNumberMax = 2; // helpful to prevent lots of probing
04fee52e
A
915
916 if (gBootFileType == kNetworkDeviceType) {
917 SetProp(Peer(0), "net-boot", NULL, 0);
918 }
919 }
920
921 if (gBootSourceNumber >= gBootSourceNumberMax) return -1;
922
923 if (gBootSourceNumberMax != 0) {
924 switch (gBootFileType) {
925 case kNetworkDeviceType :
926 // Find the end of the device spec.
927 cnt = 0;
928 while (gBootDevice[cnt] != ':') cnt++;
929
930 // Copy the device spec with the ':'.
931 strncpy(gBootFile, gBootDevice, cnt + 1);
932
933 // Check for bootp-responce or bsdp-responce.
934 bootplen = GetPropLen(gChosenPH, "bootp-response");
935 bsdplen = GetPropLen(gChosenPH, "bsdp-response");
936 if ((bootplen > 0) || (bsdplen > 0)) {
937 if (bootplen > 0) {
938 buffer = malloc(bootplen);
939 GetProp(gChosenPH, "bootp-response", buffer, bootplen);
940 } else {
941 buffer = malloc(bsdplen);
942 GetProp(gChosenPH, "bsdp-response", buffer, bsdplen);
943 }
944
945 // Flip the slash's to back slash's while looking for the last one.
946 cnt = cnt2 = kBootpBootFileOffset;
947 while (buffer[cnt] != '\0') {
948 if (buffer[cnt] == '/') {
949 buffer[cnt] = '\\';
950 cnt2 = cnt + 1;
951 }
952 cnt++;
953 }
954
955 // Add a comma at the front.
956 buffer[kBootpBootFileOffset - 1] = ',';
957
958 // Append the the root dir to the device spec.
959 strncat(gBootFile, buffer + kBootpBootFileOffset - 1,
960 cnt2 - kBootpBootFileOffset + 1);
961
962 free(buffer);
963 } else {
964 // Look for the start of the root dir path.
965 cnt3 = cnt;
966 while (gBootDevice[cnt3] != ',') cnt3++;
967
968 // Find the end of the path. Look for a comma or null.
969 cnt2 = cnt3 + 1;
970 while ((gBootDevice[cnt2] != '\0') && (gBootDevice[cnt2] != ',')) cnt2++;
971
972 // Find the last back slash or comma in the path
973 cnt4 = cnt2 - 1;
974 while ((gBootDevice[cnt4] != ',') && (gBootDevice[cnt4] != '\\')) cnt4--;
975
976 // Copy the IP addresses if needed.
977 if (gOFVersion < kOFVersion3x) {
978 strncat(gBootFile, gBootDevice + cnt + 1, cnt3 - cnt - 1);
979 }
980
981 // Add on the directory path
982 strncat(gBootFile, gBootDevice + cnt3, cnt4 - cnt3 + 1);
983 }
984
985 // Add on the kernel name
986 strcat(gBootFile, "mach.macosx");
987
988 // Add on postfix
989 strcat(gBootFile, gBootDevice + cnt2);
990 break;
991
992 case kBlockDeviceType :
993 // Find the first ':'.
994 cnt = 0;
995 while ((gBootDevice[cnt] != '\0') && (gBootDevice[cnt] != ':')) cnt++;
996 if (gBootDevice[cnt] == '\0') return -1;
997
998 // Find the comma after the ':'.
999 cnt2 = cnt + 1;
1000 while ((gBootDevice[cnt2] != '\0') && (gBootDevice[cnt] != ',')) cnt2++;
1001
1002 // Get just the partition number
1003 strncpy(gBootFile, gBootDevice + cnt + 1, cnt2 - cnt - 1);
1b564a0a
A
1004 partNum = strtol(gBootFile, 0, 10);
1005 if (partNum == 0) partNum = strtol(gBootFile, 0, 16);
04fee52e 1006
366defd1
A
1007 // Adjust the partition number.
1008 // Pass 0 & 1, no offset. Pass 2 & 3, offset 1, Pass 4 & 5, offset 2.
1009 partNum += gBootSourceNumber / 2;
04fee52e
A
1010
1011 // Construct the boot-file
1012 strncpy(gBootFile, gBootDevice, cnt + 1);
1013 sprintf(gBootFile + cnt + 1, "%d,%s\\mach_kernel",
1014 partNum, ((gBootSourceNumber & 1) ? "" : "\\"));
1b564a0a 1015
b1faa321 1016 // and the cache file name
1b564a0a 1017
b1faa321
A
1018 bzero(gCacheNameAdler + 64, sizeof(gBootFile));
1019 strcpy(gCacheNameAdler + 64, gBootFile);
8be739c0 1020 adler32 = Adler32(gCacheNameAdler, sizeof(gCacheNameAdler));
1b564a0a 1021
b1faa321
A
1022 strncpy(gBootKernelCacheFile, gBootDevice, cnt + 1);
1023 sprintf(gBootKernelCacheFile + cnt + 1,
1024 "%d,\\System\\Library\\Caches\\com.apple.kernelcaches\\kernelcache.%08lX", partNum, adler32);
04fee52e 1025 break;
1b564a0a 1026
04fee52e
A
1027 default:
1028 printf("Failed to infer Boot Device Type.\n");
1029 return -1;
1030 break;
1031 }
1032 }
1033
1034 // Figure out the root dir.
b1faa321 1035 ret = ConvertFileSpec(gBootFile, gExtensionsSpec, &filePath);
8be739c0
A
1036 if (ret == -1) {
1037 printf("Failed to determine root directory\n");
1038 return -1;
1039 }
04fee52e 1040
b1faa321 1041 strcat(gExtensionsSpec, ",");
04fee52e
A
1042
1043 // Add in any extra path to gRootDir.
1044 cnt = 0;
1045 while (filePath[cnt] != '\0') cnt++;
1046
1047 if (cnt != 0) {
1048 for (cnt2 = cnt - 1; cnt2 >= 0; cnt2--) {
1049 if (filePath[cnt2] == '\\') {
b1faa321 1050 strncat(gExtensionsSpec, filePath, cnt2 + 1);
04fee52e
A
1051 break;
1052 }
1053 }
1054 }
b1faa321
A
1055
1056 // Figure out the extensions dir.
1057 if (gBootFileType == kBlockDeviceType) {
1058 cnt = strlen(gExtensionsSpec);
1059 if ((cnt > 2) && (gExtensionsSpec[cnt-1] == '\\') && (gExtensionsSpec[cnt-2] == '\\'))
1060 cnt--;
1061 strcpy(gExtensionsSpec + cnt, "System\\Library\\");
1062 }
1063
8be739c0 1064 // technically could just do this once at the end
04fee52e 1065 SetProp(gChosenPH, "rootpath", gBootFile, strlen(gBootFile) + 1);
8be739c0
A
1066
1067 if (GetFSUUID(gBootFile, uuidStr) == 0) {
1068 printf("setting boot-uuid to: %s\n", uuidStr);
1069 SetProp(gChosenPH, "boot-uuid", uuidStr, strlen(uuidStr) + 1);
1070 }
04fee52e
A
1071
1072 gBootSourceNumber++;
1073
1074 return 0;
1075}
1076
8be739c0
A
1077#define BOOTPLIST_PATH "com.apple.Boot.plist"
1078
1079// ReadBootPlist could live elsewhere
1080static long ReadBootPlist(char *devSpec)
1081{
1082 char plistSpec[256];
1083 int len;
1084
1085 do {
1086 // construct the Boot.plist spec
1087 if (ConvertFileSpec(devSpec, plistSpec, NULL)) break;
1088 strncat(plistSpec, ",\\\\", 255-strlen(plistSpec));
1089 strncat(plistSpec, BOOTPLIST_PATH, 255-strlen(plistSpec));
1090
1091 // load the contents
1092 if ((len = LoadFile(plistSpec)) < 0) break;
1093 // we could try for the root as well as the blessed folder
1094 *((char*)kLoadAddr + len) = '\0'; // terminate for parser safety
1095
1096 if (ParseXML((char*)kLoadAddr, &gBootDict) < 0 || !gBootDict) {
1097 printf("couldn't parse %s\n", BOOTPLIST_PATH);
1098 break;
1099 }
1100
1101 return 0;
1102 } while(0);
1103
1104 return -1;
1105}
1106
04fee52e
A
1107// Public Functions
1108
1109long GetDeviceType(char *devSpec)
1110{
1111 CICell ph;
1112 long size;
1113 char deviceType[32];
1114
8be739c0
A
1115 if (isRAIDPath(devSpec))
1116 return kBlockDeviceType;
1117
04fee52e
A
1118 ph = FindDevice(devSpec);
1119 if (ph == -1) return -1;
1120
1121 size = GetProp(ph, "device_type", deviceType, 31);
1122 if (size != -1) deviceType[size] = '\0';
1123 else deviceType[0] = '\0';
1124
1125 if (strcmp(deviceType, "network") == 0) return kNetworkDeviceType;
1126 if (strcmp(deviceType, "block") == 0) return kBlockDeviceType;
1127
1128 return kUnknownDeviceType;
1129}
1130
1131
1132long ConvertFileSpec(char *fileSpec, char *devSpec, char **filePath)
1133{
1134 long cnt;
1135
1136 // Find the first ':' in the fileSpec.
1137 cnt = 0;
1138 while ((fileSpec[cnt] != '\0') && (fileSpec[cnt] != ':')) cnt++;
1139 if (fileSpec[cnt] == '\0') return -1;
1140
1141 // Find the next ',' in the fileSpec.
1142 while ((fileSpec[cnt] != '\0') && (fileSpec[cnt] != ',')) cnt++;
1143
1144 // Copy the string to devSpec.
1145 strncpy(devSpec, fileSpec, cnt);
1146 devSpec[cnt] = '\0';
1147
1148 // If there is a filePath start it after the ',', otherwise NULL.
1149 if (filePath != NULL) {
1150 if (fileSpec[cnt] != '\0') {
1151 *filePath = fileSpec + cnt + 1;
1152 } else {
1153 *filePath = NULL;
1154 }
1155 }
1156
1157 return 0;
1158}
1159
1160
1161long MatchThis(CICell phandle, char *string)
1162{
1163 long ret, length;
1164 char *name, *model, *compatible;
1165
1166 ret = GetPackageProperty(phandle, "name", &name, &length);
1167 if ((ret == -1) || (length == 0)) name = NULL;
1168
1169 ret = GetPackageProperty(phandle, "model", &model, &length);
1170 if ((ret == -1) || (length == 0)) model = NULL;
1171
1172 ret = GetPackageProperty(phandle, "compatible", &compatible, &length);
1173 if ((ret == -1) || (length == 0)) model = NULL;
1174
1175 if ((name != NULL) && strcmp(name, string) == 0) return 0;
1176 if ((model != NULL) && strcmp(model, string) == 0) return 0;
1177
1178 if (compatible != NULL) {
1179 while (*compatible != '\0') {
1180 if (strcmp(compatible, string) == 0) return 0;
1181
1182 compatible += strlen(compatible) + 1;
1183 }
1184 }
1185
1186 return -1;
1187}
1188
1189
1190void *AllocateBootXMemory(long size)
1191{
1192 long addr = gImageFirstBootXAddr - size;
1193
1194 if (addr < gImageLastKernelAddr) return 0;
1195
1196 gImageFirstBootXAddr = addr;
1197
1198 return (void *)addr;
1199}
1200
1201
1202long AllocateKernelMemory(long size)
1203{
1204 long addr = gImageLastKernelAddr;
1205
1206 gImageLastKernelAddr += (size + 0xFFF) & ~0xFFF;
1207
1208 if (gImageLastKernelAddr > gImageFirstBootXAddr)
1209 FailToBoot(-1);
1210
1211 return addr;
1212}
1213
1214
1215long AllocateMemoryRange(char *rangeName, long start, long length)
1216{
1217 long result, *buffer;
1218
1219 buffer = AllocateBootXMemory(2 * sizeof(long));
1220 if (buffer == 0) return -1;
1221
1222 buffer[0] = start;
1223 buffer[1] = length;
1224
1225 result = SetProp(gMemoryMapPH, rangeName, (char *)buffer, 2 * sizeof(long));
1226 if (result == -1) return -1;
1227
1228 return 0;
1229}
1230
8be739c0
A
1231#define BASE 65521L /* largest prime smaller than 65536 */
1232#define NMAX 5000
1233// NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
1234
1235#define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
1236#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
1237#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
1238#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
1239#define DO16(buf) DO8(buf,0); DO8(buf,8);
04fee52e 1240
8be739c0 1241unsigned long Adler32(unsigned char *buf, long len)
04fee52e 1242{
8be739c0
A
1243 unsigned long s1 = 1; // adler & 0xffff;
1244 unsigned long s2 = 0; // (adler >> 16) & 0xffff;
1245 int k;
04fee52e 1246
8be739c0
A
1247 while (len > 0) {
1248 k = len < NMAX ? len : NMAX;
1249 len -= k;
1250 while (k >= 16) {
1251 DO16(buf);
1252 buf += 16;
1253 k -= 16;
1254 }
1255 if (k != 0) do {
1256 s1 += *buf++;
1257 s2 += s1;
1258 } while (--k);
1259 s1 %= BASE;
1260 s2 %= BASE;
1261 }
1262 return (s2 << 16) | s1;
04fee52e 1263}