--- /dev/null
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <i386/asm.h>
+#include <i386/proc_reg.h>
+
+#include <i386/postcode.h>
+#include <assym.s>
+
+/*
+This code is linked into the kernel but part of the "__HIB" section, which means
+its used by code running in the special context of restoring the kernel text and data
+from the hibernation image read by the booter. hibernate_kernel_entrypoint() and everything
+it calls or references (ie. hibernate_restore_phys_page())
+needs to be careful to only touch memory also in the "__HIB" section.
+*/
+
+/*
+ * GAS won't handle an intersegment jump with a relocatable offset.
+ */
+#define LJMP(segment,address) \
+ .byte 0xea ;\
+ .long address ;\
+ .word segment
+
+#define KVTOPHYS (-KERNELBASE)
+#define KVTOLINEAR LINEAR_KERNELBASE
+
+#define PA(addr) ((addr)+KVTOPHYS)
+#define VA(addr) ((addr)-KVTOPHYS)
+
+/* Location of temporary page tables */
+#define HPTD 0x80000
+
+#define KERNEL_MAP_SIZE ( 4 * 1024 * 1024)
+
+/*
+ * fillkpt
+ * eax = page frame address
+ * ebx = index into page table
+ * ecx = how many pages to map
+ * base = base address of page dir/table
+ * prot = protection bits
+ */
+#define fillkpt(base, prot) \
+ shll $2,%ebx ; \
+ addl base,%ebx ; \
+ orl $(PTE_V), %eax ; \
+ orl prot,%eax ; \
+1: movl %eax,(%ebx) ; \
+ addl $(PAGE_SIZE),%eax ; /* increment physical address */ \
+ addl $4,%ebx ; /* next pte */ \
+ loop 1b
+
+/*
+ * fillpse
+ * eax = physical page address
+ * ebx = index into page table
+ * ecx = how many pages to map
+ * base = base address of page dir/table
+ * prot = protection bits
+ */
+#define fillpse(base, prot) \
+ shll $2,%ebx ; \
+ addl base,%ebx ; \
+ orl $(PTE_V|PTE_PS), %eax ; \
+ orl prot,%eax ; \
+1: movl %eax,(%ebx) ; \
+ addl $(1 << PDESHIFT),%eax ; /* increment physical address 4Mb */ \
+ addl $4,%ebx ; /* next entry */ \
+ loop 1b
+
+/*
+ * fillkptphys(base, prot)
+ * eax = physical address
+ * ecx = how many pages to map
+ * base = base of page table
+ * prot = protection bits
+ */
+#define fillkptphys(base, prot) \
+ movl %eax, %ebx ; \
+ shrl $(PAGE_SHIFT), %ebx ; \
+ fillkpt(base, prot)
+
+/*
+ * Hibernation code restarts here. Steal some pages from 0x10000
+ * to 0x90000 for pages tables and directories etc to temporarily
+ * map the hibernation code (put at 0x100000 (phys) by the booter
+ * and linked to 0xC0100000 by the linker) to 0xC0100000 so it can
+ * execute. It's self-contained and won't make any references outside
+ * of itself.
+ *
+ * On the way down it has to save IdlePTD (and if PAE also IdlePDPT)
+ * and after it runs it has to restore those and load IdlePTD (or
+ * IdlePDPT if PAE) into %cr3 to re-establish the original mappings
+ */
+
+ .align ALIGN
+ .globl EXT(hibernate_machine_entrypoint)
+LEXT(hibernate_machine_entrypoint)
+ cli
+
+ mov %eax, %edi
+
+ POSTCODE(0x1)
+
+ /* Map physical memory from zero to 0xC0000000 */
+ xorl %eax, %eax
+ xorl %ebx, %ebx
+ movl $(KPTDI), %ecx
+ fillpse( $(HPTD), $(PTE_W) )
+
+ /* Map 0 again at 0xC0000000 */
+ xorl %eax, %eax
+ movl $(KPTDI), %ebx
+ movl $(KERNEL_MAP_SIZE >> PDESHIFT), %ecx
+ fillpse( $(HPTD), $(PTE_W) )
+
+ movl $(HPTD), %eax
+ movl %eax, %cr3
+
+ POSTCODE(0x3)
+
+ movl %cr4,%eax
+ orl $(CR4_PSE),%eax
+ movl %eax,%cr4 /* enable page size extensions */
+ movl %cr0, %eax
+ orl $(CR0_PG|CR0_WP|CR0_PE), %eax
+ movl %eax, %cr0 /* ready paging */
+
+ POSTCODE(0x4)
+
+ lgdt PA(EXT(gdtptr)) /* load GDT */
+ lidt PA(EXT(idtptr)) /* load IDT */
+
+ POSTCODE(0x5)
+
+ LJMP (KERNEL_CS,EXT(hstart)) /* paging on and go to correct vaddr */
+
+/* Hib restart code now running with correct addresses */
+LEXT(hstart)
+ POSTCODE(0x6)
+
+ mov $(KERNEL_DS),%ax /* set kernel data segment */
+ mov %ax,%ds
+ mov %ax,%es
+ mov %ax,%ss
+
+ mov $0,%ax /* fs must be zeroed; */
+ mov %ax,%fs /* some bootstrappers don`t do this */
+ mov %ax,%gs
+
+ lea EXT(gIOHibernateRestoreStackEnd),%esp /* switch to the bootup stack */
+
+ POSTCODE(0x7)
+
+ xorl %eax, %eax /* Video memory - N/A */
+ pushl %eax
+ mov %edi, %eax /* Pointer to hibernate header */
+ pushl %eax
+ call EXT(hibernate_kernel_entrypoint)
+ /* NOTREACHED */
+ hlt
+
+
+
+/*
+void
+hibernate_restore_phys_page(uint64_t src, uint64_t dst, uint32_t len, uint32_t procFlags);
+*/
+
+ .align 5
+ .globl EXT(hibernate_restore_phys_page)
+
+ /* XXX doesn't handle 64-bit addresses yet */
+ /* XXX can only deal with exactly one page */
+LEXT(hibernate_restore_phys_page)
+ pushl %edi
+ pushl %esi
+
+ movl 8+ 4(%esp),%esi /* source virtual address */
+ addl $0, %esi
+ jz 2f /* If source == 0, nothing to do */
+
+
+ movl 8+ 12(%esp),%edi /* destination physical address */
+ cmpl $(LINEAR_KERNELBASE), %edi
+ jl 1f /* no need to map, below 0xC0000000 */
+
+ movl %edi, %eax /* destination physical address */
+ /* Map physical address to virt. address 0xffc00000 (4GB - 4MB) */
+ andl $0xFFC00000, %eax
+ orl $(PTE_V | PTE_PS | PTE_W), %eax
+ movl %eax, (HPTD + (0x3FF * 4))
+ orl $0xFFC00000, %edi
+ invlpg (%edi)
+
+1:
+ movl 8+ 20(%esp),%edx /* number of bytes */
+ cld
+/* move longs*/
+ movl %edx,%ecx
+ sarl $2,%ecx
+ rep
+ movsl
+/* move bytes*/
+ movl %edx,%ecx
+ andl $3,%ecx
+ rep
+ movsb
+2:
+ popl %esi
+ popl %edi
+ ret