Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/boot2/boot.c

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

Archive Download this file

Revision: 1376