]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/hibernate_i386.c
d8f14ea469e4b80f2358c7cabfd4cca5169c6de3
[apple/xnu.git] / osfmk / i386 / hibernate_i386.c
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23 #include <kern/machine.h>
24 #include <kern/misc_protos.h>
25 #include <kern/thread.h>
26 #include <kern/processor.h>
27 #include <kern/kalloc.h>
28 #include <mach/machine.h>
29 #include <mach/processor_info.h>
30 #include <mach/mach_types.h>
31 #include <i386/pmap.h>
32 #include <kern/cpu_data.h>
33 #include <IOKit/IOPlatformExpert.h>
34
35 #include <pexpert/i386/efi.h>
36
37 #include <IOKit/IOHibernatePrivate.h>
38 #include <vm/vm_page.h>
39 #include "i386_lowmem.h"
40
41 #define MAX_BANKS 32
42
43 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
44
45 hibernate_page_list_t *
46 hibernate_page_list_allocate(void)
47 {
48 ppnum_t base, num;
49 vm_size_t size;
50 uint32_t bank, num_banks;
51 uint32_t pages, page_count;
52 hibernate_page_list_t * list;
53 hibernate_bitmap_t * bitmap;
54
55 EfiMemoryRange * mptr;
56 uint32_t mcount, msize, i;
57 hibernate_bitmap_t dram_ranges[MAX_BANKS];
58 boot_args * args = (boot_args *) PE_state.bootArgs;
59
60 mptr = args->MemoryMap;
61 if (args->MemoryMapDescriptorSize == 0)
62 panic("Invalid memory map descriptor size");
63 msize = args->MemoryMapDescriptorSize;
64 mcount = args->MemoryMapSize / msize;
65
66 num_banks = 0;
67 for (i = 0; i < mcount; i++, mptr = (EfiMemoryRange *)(((vm_offset_t)mptr) + msize))
68 {
69 base = (ppnum_t) (mptr->PhysicalStart >> I386_PGSHIFT);
70 num = (ppnum_t) mptr->NumberOfPages;
71 if (!num)
72 continue;
73
74 switch (mptr->Type)
75 {
76 // any kind of dram
77 case kEfiLoaderCode:
78 case kEfiLoaderData:
79 case kEfiBootServicesCode:
80 case kEfiBootServicesData:
81 case kEfiConventionalMemory:
82 case kEfiACPIReclaimMemory:
83 case kEfiACPIMemoryNVS:
84 case kEfiPalCode:
85
86 if (!num_banks || (base != (1 + dram_ranges[num_banks - 1].last_page)))
87 {
88 num_banks++;
89 if (num_banks >= MAX_BANKS)
90 break;
91 dram_ranges[num_banks - 1].first_page = base;
92 }
93 dram_ranges[num_banks - 1].last_page = base + num - 1;
94 break;
95
96 // runtime services will be restarted, so no save
97 case kEfiRuntimeServicesCode:
98 case kEfiRuntimeServicesData:
99 // non dram
100 case kEfiReservedMemoryType:
101 case kEfiUnusableMemory:
102 case kEfiMemoryMappedIO:
103 case kEfiMemoryMappedIOPortSpace:
104 default:
105 break;
106 }
107 }
108
109 if (num_banks >= MAX_BANKS)
110 return (NULL);
111
112 // size the hibernation bitmap
113
114 size = sizeof(hibernate_page_list_t);
115 page_count = 0;
116 for (bank = 0; bank < num_banks; bank++) {
117 pages = dram_ranges[bank].last_page + 1 - dram_ranges[bank].first_page;
118 page_count += pages;
119 size += sizeof(hibernate_bitmap_t) + ((pages + 31) >> 5) * sizeof(uint32_t);
120 }
121
122 list = (hibernate_page_list_t *)kalloc(size);
123 if (!list)
124 return (list);
125
126 list->list_size = size;
127 list->page_count = page_count;
128 list->bank_count = num_banks;
129
130 // convert to hibernation bitmap.
131
132 bitmap = &list->bank_bitmap[0];
133 for (bank = 0; bank < num_banks; bank++)
134 {
135 bitmap->first_page = dram_ranges[bank].first_page;
136 bitmap->last_page = dram_ranges[bank].last_page;
137 bitmap->bitmapwords = (bitmap->last_page + 1
138 - bitmap->first_page + 31) >> 5;
139 kprintf("hib bank[%d]: 0x%x000 end 0x%xfff\n", bank,
140 bitmap->first_page,
141 bitmap->last_page);
142 bitmap = (hibernate_bitmap_t *) &bitmap->bitmap[bitmap->bitmapwords];
143 }
144
145 return (list);
146 }
147
148 // mark pages not to be saved, but available for scratch usage during restore
149
150 void
151 hibernate_page_list_setall_machine( __unused hibernate_page_list_t * page_list,
152 __unused hibernate_page_list_t * page_list_wired,
153 __unused uint32_t * pagesOut)
154 {
155 }
156
157 // mark pages not to be saved and not for scratch usage during restore
158 void
159 hibernate_page_list_set_volatile( hibernate_page_list_t * page_list,
160 hibernate_page_list_t * page_list_wired,
161 uint32_t * pagesOut)
162 {
163 boot_args * args = (boot_args *) PE_state.bootArgs;
164
165 hibernate_set_page_state(page_list, page_list_wired,
166 I386_HIB_PAGETABLE, I386_HIB_PAGETABLE_COUNT,
167 kIOHibernatePageStateFree);
168 *pagesOut -= I386_HIB_PAGETABLE_COUNT;
169
170 if (args->efiRuntimeServicesPageStart)
171 {
172 hibernate_set_page_state(page_list, page_list_wired,
173 args->efiRuntimeServicesPageStart, args->efiRuntimeServicesPageCount,
174 kIOHibernatePageStateFree);
175 *pagesOut -= args->efiRuntimeServicesPageCount;
176 }
177 }
178
179 kern_return_t
180 hibernate_processor_setup(IOHibernateImageHeader * header)
181 {
182 boot_args * args = (boot_args *) PE_state.bootArgs;
183
184 cpu_datap(0)->cpu_hibernate = 1;
185 header->processorFlags = 0;
186
187 header->runtimePages = args->efiRuntimeServicesPageStart;
188 header->runtimePageCount = args->efiRuntimeServicesPageCount;
189
190 return (KERN_SUCCESS);
191 }
192
193 void
194 hibernate_vm_lock(void)
195 {
196 if (current_cpu_datap()->cpu_hibernate)
197 {
198 vm_page_lock_queues();
199 mutex_lock(&vm_page_queue_free_lock);
200 }
201 }
202
203 void
204 hibernate_vm_unlock(void)
205 {
206 if (current_cpu_datap()->cpu_hibernate)
207 {
208 mutex_unlock(&vm_page_queue_free_lock);
209 vm_page_unlock_queues();
210 }
211 }