Chameleon

Chameleon Svn Source Tree

Root/tags/2.0/i386/boot2/boot.c

Source at commit 1808 created 12 years 3 months ago.
By blackosx, Revise layout of package installer 'Welcome' file so it looks cleaner. Change the copyright notice to begin from 2009 as seen in the Chameleon 2.0 r431 installer. Should this date be set earlier?
1/*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License").You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25/*
26 * Mach Operating System
27 * Copyright (c) 1990 Carnegie-Mellon University
28 * Copyright (c) 1989 Carnegie-Mellon University
29 * All rights reserved. The CMU software License Agreement specifies
30 * the terms and conditions for use and redistribution.
31 */
32
33/*
34 *INTEL CORPORATION PROPRIETARY INFORMATION
35 *
36 *This software is supplied under the terms of a licenseagreement or
37 *nondisclosure agreement with Intel Corporation and may not be copied
38 *nor disclosed except in accordance with the terms of that agreement.
39 *
40 *Copyright 1988, 1989 by Intel Corporation
41 */
42
43/*
44 * Copyright 1993 NeXT Computer, Inc.
45 * All rights reserved.
46 */
47
48/*
49 * Completely reworked by Sam Streeper (sam_s@NeXT.com)
50 * Reworked again by Curtis Galloway (galloway@NeXT.com)
51 */
52
53#include "boot.h"
54#include "bootstruct.h"
55#include "fake_efi.h"
56#include "sl.h"
57#include "libsa.h"
58#include "ramdisk.h"
59#include "gui.h"
60#include "platform.h"
61#include "modules.h"
62
63/*
64 * How long to wait (in seconds) to load the
65 * kernel after displaying the "boot:" prompt.
66 */
67#define kBootErrorTimeout 5
68
69boolgOverrideKernel, gEnableCDROMRescan, gScanSingleDrive, useGUI;
70static boolgUnloadPXEOnExit = false;
71
72static chargCacheNameAdler[64 + 256];
73char*gPlatformName = gCacheNameAdler;
74
75chargRootDevice[512];
76chargMKextName[512];
77chargMacOSVersion[8];
78static chargBootKernelCacheFile[512];
79intbvCount = 0, gDeviceCount = 0;
80//intmenucount = 0;
81longgBootMode; /* defaults to 0 == kBootModeNormal */
82BVRefbvr, menuBVR, bvChain;
83
84static boolcheckOSVersion(const char * version);
85static boolgetOSVersion();
86static unsigned longAdler32(unsigned char *buffer, long length);
87//static voidselectBiosDevice(void);
88
89
90//==========================================================================
91// Zero the BSS.
92
93static void zeroBSS(void)
94{
95extern char _DATA__bss__begin, _DATA__bss__end;
96extern char _DATA__common__begin, _DATA__common__end;
97
98bzero(&_DATA__bss__begin, (&_DATA__bss__end - &_DATA__bss__begin));
99bzero(&_DATA__common__begin, (&_DATA__common__end - &_DATA__common__begin));
100}
101
102//==========================================================================
103// Malloc error function
104
105static void malloc_error(char *addr, size_t size, const char *file, int line)
106{
107stop("\nMemory allocation error! Addr: 0x%x, Size: 0x%x, File: %s, Line: %d\n",
108 (unsigned)addr, (unsigned)size, file, line);
109}
110
111//==========================================================================
112//Initializes the runtime. Right now this means zeroing the BSS and initializing malloc.
113//
114void initialize_runtime(void)
115{
116zeroBSS();
117malloc_init(0, 0, 0, malloc_error);
118}
119
120//==========================================================================
121// execKernel - Load the kernel image (mach-o) and jump to its entry point.
122
123static int ExecKernel(void *binary)
124{
125intret;
126entry_tkernelEntry;
127
128bootArgs->kaddr = bootArgs->ksize = 0;
129execute_hook("ExecKernel", (void*)binary, NULL, NULL, NULL);
130
131ret = DecodeKernel(binary,
132 &kernelEntry,
133 (char **) &bootArgs->kaddr,
134 (int *)&bootArgs->ksize );
135
136if ( ret != 0 )
137return ret;
138
139// Reserve space for boot args
140reserveKernBootStruct();
141
142// Notify modules that the kernel has been decoded
143execute_hook("DecodedKernel", (void*)binary, NULL, NULL, NULL);
144
145setupFakeEfi();
146
147// Load boot drivers from the specifed root path.
148//if (!gHaveKernelCache)
149LoadDrivers("/");
150
151execute_hook("DriversLoaded", (void*)binary, NULL, NULL, NULL);
152
153clearActivityIndicator();
154
155if (gErrors) {
156printf("Errors encountered while starting up the computer.\n");
157printf("Pausing %d seconds...\n", kBootErrorTimeout);
158sleep(kBootErrorTimeout);
159}
160
161md0Ramdisk();
162
163verbose("Starting Darwin %s\n",( archCpuType == CPU_TYPE_I386 ) ? "x86" : "x86_64");
164
165// Cleanup the PXE base code.
166
167if ( (gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit ) {
168if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess )
169{
170printf("nbpUnloadBaseCode error %d\n", (int) ret);
171sleep(2);
172}
173}
174
175bool dummyVal;
176if (getBoolForKey(kWaitForKeypressKey, &dummyVal, &bootInfo->chameleonConfig) && dummyVal) {
177printf("(Wait) ");
178pause();
179}
180
181usb_loop();
182
183// Notify modules that the kernel is about to be started
184if (checkOSVersion("10.7"))
185{
186execute_hook("Kernel Start", (void*)kernelEntry, (void*)bootArgs, NULL, NULL);
187}
188else
189{
190execute_hook("Kernel Start", (void*)kernelEntry, (void*)bootArgsPreLion, NULL, NULL);
191}
192
193// If we were in text mode, switch to graphics mode.
194// This will draw the boot graphics unless we are in
195// verbose mode.
196if (gVerboseMode)
197setVideoMode( GRAPHICS_MODE, 0 );
198else
199drawBootGraphics();
200
201setupBooterLog();
202
203finalizeBootStruct();
204
205// Jump to kernel's entry point. There's no going back now.
206if (checkOSVersion("10.7")) {
207
208// Masking out so that Lion doesn't doublefault
209outb(0x21, 0xff);/* Maskout all interrupts Pic1 */
210outb(0xa1, 0xff);/* Maskout all interrupts Pic2 */
211
212startprog( kernelEntry, bootArgs );
213}
214else {
215startprog( kernelEntry, bootArgsPreLion );
216}
217
218// Not reached
219return 0;
220}
221
222//==========================================================================
223// This is the entrypoint from real-mode which functions exactly as it did
224// before. Multiboot does its own runtime initialization, does some of its
225// own things, and then calls common_boot.
226void boot(int biosdev)
227{
228initialize_runtime();
229// Enable A20 gate before accessing memory above 1Mb.
230enableA20();
231common_boot(biosdev);
232}
233
234//==========================================================================
235// The 'main' function for the booter. Called by boot0 when booting
236// from a block device, or by the network booter.
237//
238// arguments:
239// biosdev - Value passed from boot1/NBP to specify the device
240// that the booter was loaded from.
241//
242// If biosdev is kBIOSDevNetwork, then this function will return if
243// booting was unsuccessful. This allows the PXE firmware to try the
244// next boot device on its list.
245void common_boot(int biosdev)
246{
247bool quiet;
248bool firstRun = true;
249bool instantMenu;
250bool rescanPrompt;
251char *bootFile;
252intstatus;
253unsigned intallowBVFlags = kBVFlagSystemVolume | kBVFlagForeignBoot;
254unsigned intdenyBVFlags = kBVFlagEFISystem;
255unsigned longadler32;
256
257// Set reminder to unload the PXE base code. Neglect to unload
258// the base code will result in a hang or kernel panic.
259gUnloadPXEOnExit = true;
260
261// Record the device that the booter was loaded from.
262gBIOSDev = biosdev & kBIOSDevMask;
263
264// Initialize boot info structure.
265initKernBootStruct();
266
267initBooterLog();
268
269// Setup VGA text mode.
270// Not sure if it is safe to call setVideoMode() before the
271// config table has been loaded. Call video_mode() instead.
272#if DEBUG
273printf("before video_mode\n");
274#endif
275video_mode( 2 ); // 80x25 mono text mode.
276#if DEBUG
277printf("after video_mode\n");
278#endif
279
280// Scan and record the system's hardware information.
281scan_platform();
282
283// First get info for boot volume.
284scanBootVolumes(gBIOSDev, 0);
285bvChain = getBVChainForBIOSDev(gBIOSDev);
286setBootGlobals(bvChain);
287
288// Load boot.plist config file
289status = loadChameleonConfig(&bootInfo->chameleonConfig);
290
291if (getBoolForKey(kQuietBootKey, &quiet, &bootInfo->chameleonConfig) && quiet) {
292gBootMode |= kBootModeQuiet;
293}
294
295// Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config
296if (getBoolForKey(kInstantMenuKey, &instantMenu, &bootInfo->chameleonConfig) && instantMenu) {
297firstRun = false;
298}
299
300// Loading preboot ramdisk if exists.
301loadPrebootRAMDisk();
302
303// Disable rescan option by default
304gEnableCDROMRescan = false;
305
306// Enable it with Rescan=y in system config
307if (getBoolForKey(kRescanKey, &gEnableCDROMRescan, &bootInfo->chameleonConfig)
308&& gEnableCDROMRescan) {
309gEnableCDROMRescan = true;
310}
311
312// Ask the user for Rescan option by setting "Rescan Prompt"=y in system config.
313rescanPrompt = false;
314if (getBoolForKey(kRescanPromptKey, &rescanPrompt , &bootInfo->chameleonConfig)
315&& rescanPrompt && biosDevIsCDROM(gBIOSDev))
316{
317gEnableCDROMRescan = promptForRescanOption();
318}
319
320// Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.
321if (getBoolForKey(kScanSingleDriveKey, &gScanSingleDrive, &bootInfo->chameleonConfig)
322&& gScanSingleDrive) {
323gScanSingleDrive = true;
324}
325
326// Create a list of partitions on device(s).
327if (gScanSingleDrive) {
328scanBootVolumes(gBIOSDev, &bvCount);
329} else {
330scanDisks(gBIOSDev, &bvCount);
331}
332
333// Create a separated bvr chain using the specified filters.
334bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
335
336gBootVolume = selectBootVolume(bvChain);
337
338// Intialize module system
339init_module_system();
340
341#if DEBUG
342printf(" Default: %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n",
343 gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);
344printf(" bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n",
345 gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);
346getchar();
347#endif
348
349useGUI = true;
350// Override useGUI default
351getBoolForKey(kGUIKey, &useGUI, &bootInfo->chameleonConfig);
352if (useGUI && initGUI())
353{
354// initGUI() returned with an error, disabling GUI.
355useGUI = false;
356}
357
358setBootGlobals(bvChain);
359
360// Parse args, load and start kernel.
361while (1)
362{
363booltryresume, tryresumedefault, forceresume;
364boolusecache = false;//true;
365const char*val;
366intlen, trycache, ret = -1;
367longflags, cachetime, kerneltime, exttime, sleeptime, time;
368void*binary = (void *)kLoadAddr;
369
370// additional variable for testing alternate kernel image locations on boot helper partitions.
371charbootFileSpec[512];
372
373// Initialize globals.
374sysConfigValid = false;
375gErrors = false;
376
377status = getBootOptions(firstRun);
378firstRun = false;
379if (status == -1) continue;
380
381status = processBootOptions();
382// Status == 1 means to chainboot
383if ( status ==1 ) break;
384// Status == -1 means that the config file couldn't be loaded or that gBootVolume is NULL
385if ( status == -1 )
386{
387// gBootVolume == NULL usually means the user hit escape.
388if (gBootVolume == NULL)
389{
390freeFilteredBVChain(bvChain);
391
392if (gEnableCDROMRescan)
393rescanBIOSDevice(gBIOSDev);
394
395bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
396setBootGlobals(bvChain);
397setupDeviceList(&bootInfo->themeConfig);
398}
399continue;
400}
401
402// Other status (e.g. 0) means that we should proceed with boot.
403
404// Turn off any GUI elements
405if ( bootArgs->Video.v_display == GRAPHICS_MODE )
406{
407gui.devicelist.draw = false;
408gui.bootprompt.draw = false;
409gui.menu.draw = false;
410gui.infobox.draw = false;
411gui.logo.draw = false;
412drawBackground();
413updateVRAM();
414}
415
416// Find out which version mac os we're booting.
417getOSVersion();
418
419if (platformCPUFeature(CPU_FEATURE_EM64T)) {
420archCpuType = CPU_TYPE_X86_64;
421} else {
422archCpuType = CPU_TYPE_I386;
423}
424
425if (getValueForKey(karch, &val, &len, &bootInfo->chameleonConfig)) {
426if (strncmp(val, "i386", 4) == 0) {
427archCpuType = CPU_TYPE_I386;
428}
429}
430
431if (getValueForKey(kKernelArchKey, &val, &len, &bootInfo->chameleonConfig)) {
432if (strncmp(val, "i386", 4) == 0) {
433archCpuType = CPU_TYPE_I386;
434}
435}
436
437// Notify modules that we are attempting to boot
438execute_hook("PreBoot", NULL, NULL, NULL, NULL);
439
440if (!getBoolForKey (kWake, &tryresume, &bootInfo->chameleonConfig)) {
441tryresume = true;
442tryresumedefault = true;
443} else {
444tryresumedefault = false;
445}
446
447if (!getBoolForKey (kForceWake, &forceresume, &bootInfo->chameleonConfig)) {
448forceresume = false;
449}
450
451if (forceresume) {
452tryresume = true;
453tryresumedefault = false;
454}
455
456while (tryresume) {
457const char *tmp;
458BVRef bvr;
459if (!getValueForKey(kWakeImage, &val, &len, &bootInfo->chameleonConfig))
460val = "/private/var/vm/sleepimage";
461
462// Do this first to be sure that root volume is mounted
463ret = GetFileInfo(0, val, &flags, &sleeptime);
464
465if ((bvr = getBootVolumeRef(val, &tmp)) == NULL)
466break;
467
468// Can't check if it was hibernation Wake=y is required
469if (bvr->modTime == 0 && tryresumedefault)
470break;
471
472if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
473break;
474
475if (!forceresume && ((sleeptime+3)<bvr->modTime)) {
476#if DEBUG
477printf ("Hibernate image is too old by %d seconds. Use ForceWake=y to override\n",
478bvr->modTime-sleeptime);
479#endif
480break;
481}
482
483HibernateBoot((char *)val);
484break;
485}
486
487getBoolForKey(kUseKernelCache, &usecache, &bootInfo->chameleonConfig);
488if (usecache) {
489if (getValueForKey(kKernelCacheKey, &val, &len, &bootInfo->bootConfig)) {
490if (val[0] == '\\')
491{
492len--;
493val++;
494}
495strlcpy(gBootKernelCacheFile, val, len + 1);
496}
497else {
498//Lion
499if (checkOSVersion("10.7")) {
500sprintf(gBootKernelCacheFile, "%skernelcache", kDefaultCachePathSnow);
501}
502// Snow Leopard
503else if (checkOSVersion("10.6")) {
504sprintf(gBootKernelCacheFile, "kernelcache_%s", (archCpuType == CPU_TYPE_I386)
505? "i386" : "x86_64");
506int lnam = sizeof(gBootKernelCacheFile) + 9; //with adler32
507
508char* name;
509long prev_time = 0;
510
511struct dirstuff* cacheDir = opendir(kDefaultCachePathSnow);
512
513while(readdir(cacheDir, (const char**)&name, &flags, &time) >= 0)
514{
515if (((flags & kFileTypeMask) != kFileTypeDirectory) && time > prev_time
516&& strstr(name, gBootKernelCacheFile) && (name[lnam] != '.'))
517{
518sprintf(gBootKernelCacheFile, "%s%s", kDefaultCachePathSnow, name);
519prev_time = time;
520}
521}
522}
523else {
524// Reset cache name.
525bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64);
526
527sprintf(gCacheNameAdler + 64, "%s,%s", gRootDevice, bootInfo->bootFile);
528
529adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler));
530
531sprintf(gBootKernelCacheFile, "%s.%08lX", kDefaultCachePathLeo, adler32);
532}
533}
534}
535
536// Check for cache file.
537trycache = (usecache &&
538((gBootMode & kBootModeSafe) == 0) &&
539!gOverrideKernel &&
540(gBootFileType == kBlockDeviceType) &&
541(gMKextName[0] == '\0') &&
542(gBootKernelCacheFile[0] != '\0'));
543
544verbose("Loading Darwin %s\n", gMacOSVersion);
545
546if (trycache) do {
547ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
548if (ret != 0) kerneltime = 0;
549else if ((flags & kFileTypeMask) != kFileTypeFlat) {
550trycache = 0;
551break;
552}
553
554ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
555if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
556|| (cachetime < kerneltime)) {
557trycache = 0;
558break;
559}
560
561ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
562if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
563&& (cachetime < exttime)) {
564trycache = 0;
565break;
566}
567
568if (ret == 0 && kerneltime > exttime) {
569exttime = kerneltime;
570}
571
572if (ret == 0 && cachetime != (exttime + 1)) {
573trycache = 0;
574break;
575}
576} while (0);
577
578do {
579if (trycache) {
580bootFile = gBootKernelCacheFile;
581
582verbose("Loading kernel cache %s\n", bootFile);
583
584if (checkOSVersion("10.7")) {
585ret = LoadThinFatFile(bootFile, &binary);
586}
587else {
588ret = LoadFile(bootFile);
589binary = (void *)kLoadAddr;
590}
591
592if (ret >= 0)
593break;
594
595verbose("Kernel cache did not load %s\n ", bootFile);
596}
597
598if (checkOSVersion("10.7")) {
599bootFile = gBootKernelCacheFile;
600}
601else {
602sprintf(bootFile, "\%s", bootInfo->bootFile);
603}
604
605// Try to load kernel image from alternate locations on boot helper partitions.
606sprintf(bootFileSpec, "com.apple.boot.P%s", bootFile);
607ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
608if (ret == -1)
609{
610sprintf(bootFileSpec, "com.apple.boot.R%s", bootFile);
611ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
612if (ret == -1)
613{
614sprintf(bootFileSpec, "com.apple.boot.S%s", bootFile);
615ret = GetFileInfo(NULL, bootFileSpec, &flags, &time);
616if (ret == -1)
617{
618// No alternate location found, using the original kernel image path.
619strcpy(bootFileSpec, bootInfo->bootFile);
620}
621}
622}
623
624if (checkOSVersion("10.7"))
625{
626//Lion, dont load kernel if haz cache
627if (!trycache)
628{
629verbose("Loading kernel %s\n", bootFileSpec);
630ret = LoadThinFatFile(bootFileSpec, &binary);
631if (ret <= 0 && archCpuType == CPU_TYPE_X86_64)
632{
633archCpuType = CPU_TYPE_I386;
634ret = LoadThinFatFile(bootFileSpec, &binary);
635}
636}
637else ret = 1;
638}
639else
640{
641//Snow Leopard or older
642verbose("Loading kernel %s\n", bootFileSpec);
643ret = LoadThinFatFile(bootFileSpec, &binary);
644if (ret <= 0 && archCpuType == CPU_TYPE_X86_64)
645{
646archCpuType = CPU_TYPE_I386;
647ret = LoadThinFatFile(bootFileSpec, &binary);
648}
649}
650} while (0);
651
652clearActivityIndicator();
653
654#if DEBUG
655printf("Pausing...");
656sleep(8);
657#endif
658
659if (ret <= 0) {
660printf("Can't find %s\n", bootFile);
661
662sleep(1);
663
664if (gBootFileType == kNetworkDeviceType) {
665// Return control back to PXE. Don't unload PXE base code.
666gUnloadPXEOnExit = false;
667break;
668}
669} else {
670/* Won't return if successful. */
671ret = ExecKernel(binary);
672}
673}
674
675// chainboot
676if (status == 1) {
677// if we are already in graphics-mode,
678if (getVideoMode() == GRAPHICS_MODE) {
679setVideoMode(VGA_TEXT_MODE, 0); // switch back to text mode.
680}
681}
682
683if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) {
684nbpUnloadBaseCode();
685}
686}
687
688/*!
689Selects a new BIOS device, taking care to update the global state appropriately.
690 */
691/*
692static void selectBiosDevice(void)
693{
694struct DiskBVMap *oldMap = diskResetBootVolumes(gBIOSDev);
695CacheReset();
696diskFreeMap(oldMap);
697oldMap = NULL;
698
699int dev = selectAlternateBootDevice(gBIOSDev);
700
701BVRef bvchain = scanBootVolumes(dev, 0);
702BVRef bootVol = selectBootVolume(bvchain);
703gBootVolume = bootVol;
704setRootVolume(bootVol);
705gBIOSDev = dev;
706}
707*/
708
709bool checkOSVersion(const char * version)
710{
711return ((gMacOSVersion[0] == version[0]) && (gMacOSVersion[1] == version[1])
712&& (gMacOSVersion[2] == version[2]) && (gMacOSVersion[3] == version[3]));
713}
714
715bool getOSVersion()
716{
717boolvalid = false;
718const char*val;
719intlen;
720config_file_tsystemVersion;
721
722if (!loadConfigFile("System/Library/CoreServices/SystemVersion.plist", &systemVersion))
723{
724valid = true;
725}
726else if (!loadConfigFile("System/Library/CoreServices/ServerVersion.plist", &systemVersion))
727{
728valid = true;
729}
730
731if (valid)
732{
733if(getValueForKey(kProductVersion, &val, &len, &systemVersion))
734{
735// getValueForKey uses const char for val
736// so copy it and trim
737*gMacOSVersion = '\0';
738strncat(gMacOSVersion, val, MIN(len, 4));
739}
740else
741valid = false;
742}
743
744return valid;
745}
746
747#define BASE 65521L /* largest prime smaller than 65536 */
748#define NMAX 5000
749// NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
750
751#define DO1(buf, i){s1 += buf[i]; s2 += s1;}
752#define DO2(buf, i)DO1(buf, i); DO1(buf, i + 1);
753#define DO4(buf, i)DO2(buf, i); DO2(buf, i + 2);
754#define DO8(buf, i)DO4(buf, i); DO4(buf, i + 4);
755#define DO16(buf)DO8(buf, 0); DO8(buf, 8);
756
757unsigned long Adler32(unsigned char *buf, long len)
758{
759unsigned long s1 = 1; // adler & 0xffff;
760unsigned long s2 = 0; // (adler >> 16) & 0xffff;
761unsigned long result;
762int k;
763
764while (len > 0) {
765k = len < NMAX ? len : NMAX;
766len -= k;
767while (k >= 16) {
768DO16(buf);
769buf += 16;
770k -= 16;
771}
772if (k != 0) do {
773s1 += *buf++;
774s2 += s1;
775} while (--k);
776s1 %= BASE;
777s2 %= BASE;
778}
779result = (s2 << 16) | s1;
780return OSSwapHostToBigInt32(result);
781}
782

Archive Download this file

Revision: 1808