2 * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <mach/mach_types.h>
31 #include <mach/vm_param.h>
32 #include <IOKit/IOHibernatePrivate.h>
33 #include <IOKit/IOLib.h>
34 #include <pexpert/boot.h>
35 #include <libkern/libkern.h>
37 #include <vm/WKdm_new.h>
38 #include "IOHibernateInternal.h"
40 #include <machine/pal_hibernate.h>
43 This code is linked into the kernel but part of the "__HIB" section, which means
44 its used by code running in the special context of restoring the kernel text and data
45 from the hibernation image read by the booter. hibernate_kernel_entrypoint() and everything
46 it calls or references needs to be careful to only touch memory also in the "__HIB" section.
49 uint32_t gIOHibernateState
;
51 uint32_t gIOHibernateDebugFlags
;
53 static IOHibernateImageHeader _hibernateHeader
;
54 IOHibernateImageHeader
* gIOHibernateCurrentHeader
= &_hibernateHeader
;
56 ppnum_t gIOHibernateHandoffPages
[64];
57 uint32_t gIOHibernateHandoffPageCount
= sizeof(gIOHibernateHandoffPages
)
58 / sizeof(gIOHibernateHandoffPages
[0]);
61 void hibprintf(const char *fmt
, ...);
63 #define hibprintf(x...)
68 #if defined(__i386__) || defined(__x86_64__)
69 extern void acpi_wake_prot_entry(void);
73 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
75 #if defined(__i386__) || defined(__x86_64__)
77 #define rdtsc(lo,hi) \
78 __asm__ volatile("lfence; rdtsc; lfence" : "=a" (lo), "=d" (hi))
80 static inline uint64_t rdtsc64(void)
84 return ((hi
) << 32) | (lo
);
89 static inline uint64_t rdtsc64(void)
94 #endif /* defined(__i386__) || defined(__x86_64__) */
96 #if defined(__i386__) || defined(__x86_64__)
100 #include <architecture/i386/pio.h>
102 /* standard port addresses */
104 COM1_PORT_ADDR
= 0x3f8,
105 COM2_PORT_ADDR
= 0x2f8
108 /* UART register offsets */
110 UART_RBR
= 0, /* receive buffer Register (R) */
111 UART_THR
= 0, /* transmit holding register (W) */
112 UART_DLL
= 0, /* DLAB = 1, divisor latch (LSB) */
113 UART_IER
= 1, /* interrupt enable register */
114 UART_DLM
= 1, /* DLAB = 1, divisor latch (MSB) */
115 UART_IIR
= 2, /* interrupt ident register (R) */
116 UART_FCR
= 2, /* fifo control register (W) */
117 UART_LCR
= 3, /* line control register */
118 UART_MCR
= 4, /* modem control register */
119 UART_LSR
= 5, /* line status register */
120 UART_MSR
= 6, /* modem status register */
121 UART_SCR
= 7 /* scratch register */
125 UART_LCR_8BITS
= 0x03,
132 UART_MCR_OUT1
= 0x04,
133 UART_MCR_OUT2
= 0x08,
145 static void uart_putc(char c
)
147 while (!(inb(COM1_PORT_ADDR
+ UART_LSR
) & UART_LSR_THRE
))
149 outb(COM1_PORT_ADDR
+ UART_THR
, c
);
152 static int debug_probe( void )
154 /* Verify that the Scratch Register is accessible */
155 outb(COM1_PORT_ADDR
+ UART_SCR
, 0x5a);
156 if (inb(COM1_PORT_ADDR
+ UART_SCR
) != 0x5a) return false;
157 outb(COM1_PORT_ADDR
+ UART_SCR
, 0xa5);
158 if (inb(COM1_PORT_ADDR
+ UART_SCR
) != 0xa5) return false;
163 static void uart_puthex(uint64_t num
)
169 for (bit
= 60; bit
>= 0; bit
-= 4)
171 c
= 0xf & (num
>> bit
);
174 else if (leading
&& bit
)
184 static void debug_code(uint32_t code
, uint64_t value
)
189 if (!(kIOHibernateDebugRestoreLogs
& gIOHibernateDebugFlags
))
192 for (bit
= 24; bit
>= 0; bit
-= 8)
194 c
= 0xFF & (code
>> bit
);
204 #endif /* defined(__i386__) || defined(__x86_64__) */
207 #define debug_probe() (false)
208 #define debug_code(c, v) {}
213 kIOHibernateRestoreCodeImageStart
= 'imgS',
214 kIOHibernateRestoreCodeImageEnd
= 'imgE',
215 kIOHibernateRestoreCodePageIndexStart
= 'pgiS',
216 kIOHibernateRestoreCodePageIndexEnd
= 'pgiE',
217 kIOHibernateRestoreCodeMapStart
= 'mapS',
218 kIOHibernateRestoreCodeMapEnd
= 'mapE',
219 kIOHibernateRestoreCodeWakeMapSize
= 'wkms',
220 kIOHibernateRestoreCodeConflictPage
= 'cfpg',
221 kIOHibernateRestoreCodeConflictSource
= 'cfsr',
222 kIOHibernateRestoreCodeNoMemory
= 'nomm',
223 kIOHibernateRestoreCodeTag
= 'tag ',
224 kIOHibernateRestoreCodeSignature
= 'sign',
225 kIOHibernateRestoreCodeMapVirt
= 'mapV',
226 kIOHibernateRestoreCodeHandoffPages
= 'hand',
227 kIOHibernateRestoreCodeHandoffCount
= 'hndc',
230 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
233 static void fatal(void)
235 #if defined(__i386__) || defined(__x86_64__)
242 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
245 hibernate_sum_page(uint8_t *buf
, uint32_t ppnum
)
247 return (((uint32_t *)buf
)[((PAGE_SIZE
>> 2) - 1) & ppnum
]);
250 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
252 static hibernate_bitmap_t
*
253 hibernate_page_bitmap(hibernate_page_list_t
* list
, uint32_t page
)
256 hibernate_bitmap_t
* bitmap
= &list
->bank_bitmap
[0];
258 for (bank
= 0; bank
< list
->bank_count
; bank
++)
260 if ((page
>= bitmap
->first_page
) && (page
<= bitmap
->last_page
))
262 bitmap
= (hibernate_bitmap_t
*) &bitmap
->bitmap
[bitmap
->bitmapwords
];
264 if (bank
== list
->bank_count
)
271 hibernate_page_bitmap_pin(hibernate_page_list_t
* list
, uint32_t * pPage
)
273 uint32_t bank
, page
= *pPage
;
274 hibernate_bitmap_t
* bitmap
= &list
->bank_bitmap
[0];
276 for (bank
= 0; bank
< list
->bank_count
; bank
++)
278 if (page
<= bitmap
->first_page
)
280 *pPage
= bitmap
->first_page
;
283 if (page
<= bitmap
->last_page
)
285 bitmap
= (hibernate_bitmap_t
*) &bitmap
->bitmap
[bitmap
->bitmapwords
];
287 if (bank
== list
->bank_count
)
294 hibernate_page_bitset(hibernate_page_list_t
* list
, boolean_t set
, uint32_t page
)
296 hibernate_bitmap_t
* bitmap
;
298 bitmap
= hibernate_page_bitmap(list
, page
);
301 page
-= bitmap
->first_page
;
303 bitmap
->bitmap
[page
>> 5] |= (0x80000000 >> (page
& 31));
304 //setbit(page - bitmap->first_page, (int *) &bitmap->bitmap[0]);
306 bitmap
->bitmap
[page
>> 5] &= ~(0x80000000 >> (page
& 31));
307 //clrbit(page - bitmap->first_page, (int *) &bitmap->bitmap[0]);
312 hibernate_page_bittst(hibernate_page_list_t
* list
, uint32_t page
)
314 boolean_t result
= TRUE
;
315 hibernate_bitmap_t
* bitmap
;
317 bitmap
= hibernate_page_bitmap(list
, page
);
320 page
-= bitmap
->first_page
;
321 result
= (0 != (bitmap
->bitmap
[page
>> 5] & (0x80000000 >> (page
& 31))));
326 // count bits clear or set (set == TRUE) starting at page.
328 hibernate_page_bitmap_count(hibernate_bitmap_t
* bitmap
, uint32_t set
, uint32_t page
)
330 uint32_t index
, bit
, bits
;
335 index
= (page
- bitmap
->first_page
) >> 5;
336 bit
= (page
- bitmap
->first_page
) & 31;
338 bits
= bitmap
->bitmap
[index
];
341 bits
= (bits
<< bit
);
343 count
+= __builtin_clz(bits
);
347 while (++index
< bitmap
->bitmapwords
)
349 bits
= bitmap
->bitmap
[index
];
354 count
+= __builtin_clz(bits
);
361 if ((page
+ count
) > (bitmap
->last_page
+ 1)) count
= (bitmap
->last_page
+ 1) - page
;
367 hibernate_page_list_grab(hibernate_page_list_t
* list
, uint32_t * pNextFree
)
369 uint32_t nextFree
= *pNextFree
;
370 uint32_t nextFreeInBank
;
371 hibernate_bitmap_t
* bitmap
;
373 nextFreeInBank
= nextFree
+ 1;
374 while ((bitmap
= hibernate_page_bitmap_pin(list
, &nextFreeInBank
)))
376 nextFreeInBank
+= hibernate_page_bitmap_count(bitmap
, FALSE
, nextFreeInBank
);
377 if (nextFreeInBank
<= bitmap
->last_page
)
379 *pNextFree
= nextFreeInBank
;
386 debug_code(kIOHibernateRestoreCodeNoMemory
, nextFree
);
395 store_one_page(uint32_t procFlags
, uint32_t * src
, uint32_t compressedSize
,
396 uint32_t * buffer
, uint32_t ppnum
)
398 uint64_t dst
= ptoa_64(ppnum
);
399 uint8_t scratch
[WKdm_SCRATCH_BUF_SIZE_INTERNAL
] __attribute__ ((aligned (16)));
401 if (compressedSize
!= PAGE_SIZE
)
403 dst
= pal_hib_map(DEST_COPY_AREA
, dst
);
404 if (compressedSize
!= 4) WKdm_decompress_new((WK_word
*) src
, (WK_word
*)(uintptr_t)dst
, (WK_word
*) &scratch
[0], compressedSize
);
411 d
= (uint32_t *)(uintptr_t)dst
;
412 if (!s
) bzero((void *) dst
, PAGE_SIZE
);
413 else for (i
= 0; i
< (PAGE_SIZE
/ sizeof(int32_t)); i
++) *d
++ = s
;
418 dst
= hibernate_restore_phys_page((uint64_t) (uintptr_t) src
, dst
, PAGE_SIZE
, procFlags
);
421 return hibernate_sum_page((uint8_t *)(uintptr_t)dst
, ppnum
);
425 hibernate_kernel_entrypoint(uint32_t p1
,
426 uint32_t p2
, uint32_t p3
, uint32_t p4
)
431 uint64_t imageReadPhys
;
432 uint64_t pageIndexPhys
;
433 uint32_t * pageIndexSource
;
434 hibernate_page_list_t
* map
;
439 uint32_t conflictCount
;
440 uint32_t compressedSize
;
441 uint32_t uncompressedPages
;
442 uint32_t copyPageListHeadPage
;
443 uint32_t pageListPage
;
444 uint32_t * copyPageList
;
446 uint32_t copyPageIndex
;
450 uint32_t lastImagePage
;
451 uint32_t lastMapPage
;
452 uint32_t lastPageIndexPage
;
453 uint32_t handoffPages
;
454 uint32_t handoffPageCount
;
457 timeStart
= rdtsc64();
459 static_assert(sizeof(IOHibernateImageHeader
) == 512);
461 headerPhys
= ptoa_64(p1
);
463 if ((kIOHibernateDebugRestoreLogs
& gIOHibernateDebugFlags
) && !debug_probe())
464 gIOHibernateDebugFlags
&= ~kIOHibernateDebugRestoreLogs
;
466 debug_code(kIOHibernateRestoreCodeImageStart
, headerPhys
);
468 memcpy(gIOHibernateCurrentHeader
,
469 (void *) pal_hib_map(IMAGE_AREA
, headerPhys
),
470 sizeof(IOHibernateImageHeader
));
472 debug_code(kIOHibernateRestoreCodeSignature
, gIOHibernateCurrentHeader
->signature
);
475 + (offsetof(IOHibernateImageHeader
, fileExtentMap
)
476 + gIOHibernateCurrentHeader
->fileExtentMapSize
477 + ptoa_32(gIOHibernateCurrentHeader
->restore1PageCount
)
478 + gIOHibernateCurrentHeader
->previewSize
);
480 map
= (hibernate_page_list_t
*) pal_hib_map(BITMAP_AREA
, mapPhys
);
482 lastImagePage
= atop_64(headerPhys
+ gIOHibernateCurrentHeader
->image1Size
);
483 lastMapPage
= atop_64(mapPhys
+ gIOHibernateCurrentHeader
->bitmapSize
);
485 handoffPages
= gIOHibernateCurrentHeader
->handoffPages
;
486 handoffPageCount
= gIOHibernateCurrentHeader
->handoffPageCount
;
488 debug_code(kIOHibernateRestoreCodeImageEnd
, ptoa_64(lastImagePage
));
489 debug_code(kIOHibernateRestoreCodeMapStart
, mapPhys
);
490 debug_code(kIOHibernateRestoreCodeMapEnd
, ptoa_64(lastMapPage
));
492 debug_code(kIOHibernateRestoreCodeMapVirt
, (uintptr_t) map
);
493 debug_code(kIOHibernateRestoreCodeHandoffPages
, ptoa_64(handoffPages
));
494 debug_code(kIOHibernateRestoreCodeHandoffCount
, handoffPageCount
);
496 // knock all the image pages to be used out of free map
497 for (ppnum
= atop_64(headerPhys
); ppnum
<= lastImagePage
; ppnum
++)
499 hibernate_page_bitset(map
, FALSE
, ppnum
);
501 // knock all the handoff pages to be used out of free map
502 for (ppnum
= handoffPages
; ppnum
< (handoffPages
+ handoffPageCount
); ppnum
++)
504 hibernate_page_bitset(map
, FALSE
, ppnum
);
508 hibernate_page_list_grab(map
, &nextFree
);
510 sum
= gIOHibernateCurrentHeader
->actualRestore1Sum
;
511 gIOHibernateCurrentHeader
->diag
[0] = atop_64(headerPhys
);
512 gIOHibernateCurrentHeader
->diag
[1] = sum
;
513 gIOHibernateCurrentHeader
->trampolineTime
= 0;
515 uncompressedPages
= 0;
517 copyPageListHeadPage
= 0;
519 copyPageIndex
= PAGE_SIZE
>> 2;
521 compressedSize
= PAGE_SIZE
;
526 if (gIOHibernateCurrentHeader
->previewSize
)
528 pageIndexPhys
= headerPhys
529 + (offsetof(IOHibernateImageHeader
, fileExtentMap
)
530 + gIOHibernateCurrentHeader
->fileExtentMapSize
531 + ptoa_32(gIOHibernateCurrentHeader
->restore1PageCount
));
532 imageReadPhys
= (pageIndexPhys
+ gIOHibernateCurrentHeader
->previewPageListSize
);
533 lastPageIndexPage
= atop_64(imageReadPhys
);
534 pageIndexSource
= (uint32_t *) pal_hib_map(IMAGE2_AREA
, pageIndexPhys
);
539 lastPageIndexPage
= 0;
540 imageReadPhys
= (mapPhys
+ gIOHibernateCurrentHeader
->bitmapSize
);
543 debug_code(kIOHibernateRestoreCodePageIndexStart
, pageIndexPhys
);
544 debug_code(kIOHibernateRestoreCodePageIndexEnd
, ptoa_64(lastPageIndexPage
));
552 count
= srcPhys
? 0 : handoffPageCount
;
555 if (count
> gIOHibernateHandoffPageCount
) count
= gIOHibernateHandoffPageCount
;
556 srcPhys
= ptoa_64(handoffPages
);
560 // copy pageIndexSource pages == preview image data
563 if (!pageIndexPhys
) break;
564 srcPhys
= imageReadPhys
;
566 ppnum
= pageIndexSource
[0];
567 count
= pageIndexSource
[1];
568 pageIndexSource
+= 2;
569 pageIndexPhys
+= 2 * sizeof(pageIndexSource
[0]);
570 imageReadPhys
= srcPhys
;
575 if (!srcPhys
) srcPhys
= (mapPhys
+ gIOHibernateCurrentHeader
->bitmapSize
);
576 src
= (uint32_t *) pal_hib_map(IMAGE_AREA
, srcPhys
);
579 srcPhys
+= 2 * sizeof(*src
);
580 imageReadPhys
= srcPhys
;
594 for (page
= 0; page
< count
; page
++, ppnum
++)
599 src
= (uint32_t *) pal_hib_map(IMAGE_AREA
, srcPhys
);
601 if (2 == stage
) ppnum
= gIOHibernateHandoffPages
[page
];
605 // debug_code(kIOHibernateRestoreCodeTag, (uintptr_t) tag);
606 srcPhys
+= sizeof(*src
);
607 compressedSize
= kIOHibernateTagLength
& tag
;
610 conflicts
= (ppnum
>= atop_64(mapPhys
)) && (ppnum
<= lastMapPage
);
612 conflicts
|= ((ppnum
>= atop_64(imageReadPhys
)) && (ppnum
<= lastImagePage
));
615 conflicts
|= ((ppnum
>= atop_64(srcPhys
)) && (ppnum
<= (handoffPages
+ handoffPageCount
- 1)));
618 conflicts
|= ((ppnum
>= atop_64(pageIndexPhys
)) && (ppnum
<= lastPageIndexPage
));
622 pageSum
= store_one_page(gIOHibernateCurrentHeader
->processorFlags
,
623 src
, compressedSize
, 0, ppnum
);
630 uint32_t bufferPage
= 0;
633 // debug_code(kIOHibernateRestoreCodeConflictPage, ppnum);
634 // debug_code(kIOHibernateRestoreCodeConflictSource, (uintptr_t) src);
638 // alloc new buffer page
639 bufferPage
= hibernate_page_list_grab(map
, &nextFree
);
640 dst
= (uint32_t *)pal_hib_map(DEST_COPY_AREA
, ptoa_64(bufferPage
));
641 memcpy(dst
, src
, compressedSize
);
643 if (copyPageIndex
> ((PAGE_SIZE
>> 2) - 3))
645 // alloc new copy list page
646 pageListPage
= hibernate_page_list_grab(map
, &nextFree
);
649 copyPageList
[1] = pageListPage
;
651 copyPageListHeadPage
= pageListPage
;
653 copyPageList
= (uint32_t *)pal_hib_map(SRC_COPY_AREA
,
654 ptoa_64(pageListPage
));
658 copyPageList
[copyPageIndex
++] = ppnum
;
659 copyPageList
[copyPageIndex
++] = bufferPage
;
660 copyPageList
[copyPageIndex
++] = (compressedSize
| (stage
<< 24));
661 copyPageList
[0] = copyPageIndex
;
663 srcPhys
+= ((compressedSize
+ 3) & ~3);
664 src
+= ((compressedSize
+ 3) >> 2);
668 /* src points to the last page restored, so we need to skip over that */
669 hibernateRestorePALState(src
);
671 // -- copy back conflicts
673 pageListPage
= copyPageListHeadPage
;
676 copyPageList
= (uint32_t *)pal_hib_map(COPY_PAGE_AREA
, ptoa_64(pageListPage
));
677 for (copyPageIndex
= 2; copyPageIndex
< copyPageList
[0]; copyPageIndex
+= 3)
679 ppnum
= copyPageList
[copyPageIndex
+ 0];
680 srcPhys
= ptoa_64(copyPageList
[copyPageIndex
+ 1]);
681 src
= (uint32_t *) pal_hib_map(SRC_COPY_AREA
, srcPhys
);
682 compressedSize
= copyPageList
[copyPageIndex
+ 2];
683 stage
= compressedSize
>> 24;
684 compressedSize
&= 0x1FFF;
685 pageSum
= store_one_page(gIOHibernateCurrentHeader
->processorFlags
,
686 src
, compressedSize
, 0, ppnum
);
691 pageListPage
= copyPageList
[1];
696 // -- image has been destroyed...
698 gIOHibernateCurrentHeader
->actualImage1Sum
= sum
;
699 gIOHibernateCurrentHeader
->actualUncompressedPages
= uncompressedPages
;
700 gIOHibernateCurrentHeader
->conflictCount
= conflictCount
;
701 gIOHibernateCurrentHeader
->nextFree
= nextFree
;
703 gIOHibernateState
= kIOHibernateStateWakingFromHibernate
;
705 gIOHibernateCurrentHeader
->trampolineTime
= (((rdtsc64() - timeStart
)) >> 8);
707 // debug_code('done', 0);
710 #if defined(__i386__) || defined(__x86_64__)
711 typedef void (*ResetProc
)(void);
713 proc
= HIB_ENTRYPOINT
;
726 /* standalone printf implementation */
728 * Copyright (c) 1986, 1988, 1991, 1993
729 * The Regents of the University of California. All rights reserved.
730 * (c) UNIX System Laboratories, Inc.
731 * All or some portions of this file are derived from material licensed
732 * to the University of California by American Telephone and Telegraph
733 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
734 * the permission of UNIX System Laboratories, Inc.
736 * Redistribution and use in source and binary forms, with or without
737 * modification, are permitted provided that the following conditions
739 * 1. Redistributions of source code must retain the above copyright
740 * notice, this list of conditions and the following disclaimer.
741 * 2. Redistributions in binary form must reproduce the above copyright
742 * notice, this list of conditions and the following disclaimer in the
743 * documentation and/or other materials provided with the distribution.
744 * 4. Neither the name of the University nor the names of its contributors
745 * may be used to endorse or promote products derived from this software
746 * without specific prior written permission.
748 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
749 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
750 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
751 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
752 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
753 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
754 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
755 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
756 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
757 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
760 * @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
763 typedef long ptrdiff_t;
764 char const hibhex2ascii_data
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
765 #define hibhex2ascii(hex) (hibhex2ascii_data[hex])
766 #define toupper(c) ((c) - 0x20 * (((c) >= 'a') && ((c) <= 'z')))
768 hibstrlen(const char *s
)
776 /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
777 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
780 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
781 * order; return an optional length and a pointer to the last character
782 * written in the buffer (i.e., the first character of the string).
783 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
786 ksprintn(char *nbuf
, uintmax_t num
, int base
, int *lenp
, int upper
)
790 /* Truncate so we don't call umoddi3, which isn't in __HIB */
791 #if !defined(__LP64__)
792 uint32_t num2
= (uint32_t) num
;
794 uintmax_t num2
= num
;
800 c
= hibhex2ascii(num2
% base
);
801 *++p
= upper
? toupper(c
) : c
;
802 } while (num2
/= base
);
804 *lenp
= (int)(p
- nbuf
);
809 * Scaled down version of printf(3).
811 * Two additional formats:
813 * The format %b is supported to decode error registers.
816 * printf("reg=%b\n", regval, "*");
818 * where is the output base expressed as a control character, e.g.
819 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
820 * the first of which gives the bit number to be inspected (origin 1), and
821 * the next characters (up to a control character, i.e. a character <= 32),
822 * give the name of the register. Thus:
824 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
826 * would produce output:
830 * XXX: %D -- Hexdump, takes pointer and separator string:
831 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
832 * ("%*D", len, ptr, " " -> XX XX XX XX ...
835 hibkvprintf(char const *fmt
, void (*func
)(int, void*), void *arg
, int radix
, va_list ap
)
837 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
840 const char *p
, *percent
, *q
;
844 int base
, lflag
, qflag
, tmp
, width
, ladjust
, sharpflag
, neg
, sign
, dot
;
845 int cflag
, hflag
, jflag
, tflag
, zflag
;
848 int stop
= 0, retval
= 0;
857 fmt
= "(fmt null)\n";
859 if (radix
< 2 || radix
> 36)
865 while ((ch
= (u_char
)*fmt
++) != '%' || stop
) {
871 qflag
= 0; lflag
= 0; ladjust
= 0; sharpflag
= 0; neg
= 0;
872 sign
= 0; dot
= 0; dwidth
= 0; upper
= 0;
873 cflag
= 0; hflag
= 0; jflag
= 0; tflag
= 0; zflag
= 0;
874 reswitch
: switch (ch
= (u_char
)*fmt
++) {
892 width
= va_arg(ap
, int);
898 dwidth
= va_arg(ap
, int);
906 case '1': case '2': case '3': case '4':
907 case '5': case '6': case '7': case '8': case '9':
908 for (n
= 0;; ++fmt
) {
909 n
= n
* 10 + ch
- '0';
911 if (ch
< '0' || ch
> '9')
920 num
= (u_int
)va_arg(ap
, int);
921 p
= va_arg(ap
, char *);
922 for (q
= ksprintn(nbuf
, num
, *p
++, NULL
, 0); *q
;)
930 if (num
& (1 << (n
- 1))) {
931 PCHAR(tmp
? ',' : '<');
932 for (; (n
= *p
) > ' '; ++p
)
936 for (; *p
> ' '; ++p
)
943 PCHAR(va_arg(ap
, int));
946 up
= va_arg(ap
, u_char
*);
947 p
= va_arg(ap
, char *);
951 PCHAR(hibhex2ascii(*up
>> 4));
952 PCHAR(hibhex2ascii(*up
& 0x0f));
983 *(va_arg(ap
, intmax_t *)) = retval
;
985 *(va_arg(ap
, quad_t
*)) = retval
;
987 *(va_arg(ap
, long *)) = retval
;
989 *(va_arg(ap
, size_t *)) = retval
;
991 *(va_arg(ap
, short *)) = retval
;
993 *(va_arg(ap
, char *)) = retval
;
995 *(va_arg(ap
, int *)) = retval
;
1002 sharpflag
= (width
== 0);
1004 num
= (uintptr_t)va_arg(ap
, void *);
1015 p
= va_arg(ap
, char *);
1019 n
= (typeof(n
))hibstrlen (p
);
1021 for (n
= 0; n
< dwidth
&& p
[n
]; n
++)
1026 if (!ladjust
&& width
> 0)
1031 if (ladjust
&& width
> 0)
1056 num
= va_arg(ap
, uintmax_t);
1058 num
= va_arg(ap
, u_quad_t
);
1060 num
= va_arg(ap
, ptrdiff_t);
1062 num
= va_arg(ap
, u_long
);
1064 num
= va_arg(ap
, size_t);
1066 num
= (u_short
)va_arg(ap
, int);
1068 num
= (u_char
)va_arg(ap
, int);
1070 num
= va_arg(ap
, u_int
);
1074 num
= va_arg(ap
, intmax_t);
1076 num
= va_arg(ap
, quad_t
);
1078 num
= va_arg(ap
, ptrdiff_t);
1080 num
= va_arg(ap
, long);
1082 num
= va_arg(ap
, ssize_t
);
1084 num
= (short)va_arg(ap
, int);
1086 num
= (char)va_arg(ap
, int);
1088 num
= va_arg(ap
, int);
1090 if (sign
&& (intmax_t)num
< 0) {
1092 num
= -(intmax_t)num
;
1094 p
= ksprintn(nbuf
, num
, base
, &tmp
, upper
);
1095 if (sharpflag
&& num
!= 0) {
1098 else if (base
== 16)
1104 if (!ladjust
&& padc
!= '0' && width
1105 && (width
-= tmp
) > 0)
1110 if (sharpflag
&& num
!= 0) {
1113 } else if (base
== 16) {
1118 if (!ladjust
&& width
&& (width
-= tmp
) > 0)
1125 if (ladjust
&& width
&& (width
-= tmp
) > 0)
1131 while (percent
< fmt
)
1134 * Since we ignore an formatting argument it is no
1135 * longer safe to obey the remaining formatting
1136 * arguments as the arguments will no longer match
1148 putchar(int c
, void *arg
)
1155 hibprintf(const char *fmt
, ...)
1157 /* http://www.pagetable.com/?p=298 */
1161 hibkvprintf(fmt
, putchar
, NULL
, 10, ap
);
1164 #endif /* CONFIG_DEBUG */