1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/cpr.h> 31 #include <sys/pte.h> 32 #include <sys/promimpl.h> 33 #include <sys/prom_plat.h> 34 35 extern int cpr_ufs_close(int); 36 extern int cpr_ufs_open(char *, char *); 37 extern int cpr_ufs_read(int, char *, int); 38 extern int cpr_read(int, char *, size_t); 39 extern void prom_unmap(caddr_t, uint_t); 40 41 extern int cpr_debug; 42 static int cpr_show_props = 0; 43 44 45 /* 46 * Read the config file and pass back the file path, filesystem 47 * device path. 48 */ 49 int 50 cpr_read_cprinfo(int fd, char *file_path, char *fs_path) 51 { 52 struct cprconfig cf; 53 54 if (cpr_ufs_read(fd, (char *)&cf, sizeof (cf)) != sizeof (cf) || 55 cf.cf_magic != CPR_CONFIG_MAGIC) 56 return (-1); 57 58 (void) prom_strcpy(file_path, cf.cf_path); 59 (void) prom_strcpy(fs_path, cf.cf_dev_prom); 60 61 return (0); 62 } 63 64 65 /* 66 * Read the location of the state file from the root filesystem. 67 * Pass back to the caller the full device path of the filesystem 68 * and the filename relative to that fs. 69 */ 70 int 71 cpr_locate_statefile(char *file_path, char *fs_path) 72 { 73 int fd; 74 char *boot_path = prom_bootpath(); 75 int rc; 76 77 if ((fd = cpr_ufs_open(CPR_CONFIG, boot_path)) != -1) { 78 rc = cpr_read_cprinfo(fd, file_path, fs_path); 79 (void) cpr_ufs_close(fd); 80 } else 81 rc = -1; 82 83 return (rc); 84 } 85 86 87 /* 88 * Open the "defaults" file in the root fs and read the values of the 89 * properties saved during the checkpoint. Restore the values to nvram. 90 * 91 * Note: an invalid magic number in the "defaults" file means that the 92 * state file is bad or obsolete so our caller should not proceed with 93 * the resume. 94 */ 95 int 96 cpr_reset_properties(void) 97 { 98 char *str, *boot_path, *default_path; 99 int fd, len, rc, prop_errors; 100 cprop_t *prop, *tail; 101 cdef_t cdef; 102 pnode_t node; 103 104 str = "cpr_reset_properties"; 105 default_path = CPR_DEFAULT; 106 boot_path = prom_bootpath(); 107 108 if ((fd = cpr_ufs_open(default_path, boot_path)) == -1) { 109 prom_printf("%s: unable to open %s on %s\n", 110 str, default_path, boot_path); 111 return (-1); 112 } 113 114 rc = 0; 115 len = cpr_ufs_read(fd, (char *)&cdef, sizeof (cdef)); 116 if (len != sizeof (cdef)) { 117 prom_printf("%s: error reading %s\n", str, default_path); 118 rc = -1; 119 } else if (cdef.mini.magic != CPR_DEFAULT_MAGIC) { 120 prom_printf("%s: bad magic number in %s\n", str, default_path); 121 rc = -1; 122 } 123 124 (void) cpr_ufs_close(fd); 125 if (rc) 126 return (rc); 127 128 node = prom_optionsnode(); 129 if (node == OBP_NONODE || node == OBP_BADNODE) { 130 prom_printf("%s: cannot find \"options\" node\n", str); 131 return (-1); 132 } 133 134 /* 135 * reset nvram to the original property values 136 */ 137 if (cpr_show_props) 138 prom_printf("\n\ncpr_show_props:\n"); 139 for (prop_errors = 0, prop = cdef.props, tail = prop + CPR_MAXPROP; 140 prop < tail; prop++) { 141 if (cpr_show_props) { 142 prom_printf("mod=%c, name=\"%s\",\tvalue=\"%s\"\n", 143 prop->mod, prop->name, prop->value); 144 } 145 if (prop->mod != PROP_MOD) 146 continue; 147 148 len = prom_strlen(prop->value); 149 if (prom_setprop(node, prop->name, prop->value, len + 1) < 0 || 150 prom_getproplen(node, prop->name) != len) { 151 prom_printf("%s: error setting \"%s\" to \"%s\"\n", 152 str, prop->name, prop->value); 153 prop_errors++; 154 } 155 } 156 157 return (prop_errors ? -1 : 0); 158 } 159 160 161 /* 162 * Read and verify cpr dump descriptor 163 */ 164 int 165 cpr_read_cdump(int fd, cdd_t *cdp, ushort_t mach_type) 166 { 167 char *str; 168 int nread; 169 170 str = "\ncpr_read_cdump:"; 171 nread = cpr_read(fd, (caddr_t)cdp, sizeof (*cdp)); 172 if (nread != sizeof (*cdp)) { 173 prom_printf("%s Error reading cpr dump descriptor\n", str); 174 return (-1); 175 } 176 177 if (cdp->cdd_magic != CPR_DUMP_MAGIC) { 178 prom_printf("%s bad dump magic 0x%x, expected 0x%x\n", 179 str, cdp->cdd_magic, CPR_DUMP_MAGIC); 180 return (-1); 181 } 182 183 if (cdp->cdd_version != CPR_VERSION) { 184 prom_printf("%s bad cpr version %d, expected %d\n", 185 str, cdp->cdd_version, CPR_VERSION); 186 return (-1); 187 } 188 189 if (cdp->cdd_machine != mach_type) { 190 prom_printf("%s bad machine type 0x%x, expected 0x%x\n", 191 str, cdp->cdd_machine, mach_type); 192 return (-1); 193 } 194 195 if (cdp->cdd_bitmaprec <= 0) { 196 prom_printf("%s bad bitmap %d\n", str, cdp->cdd_bitmaprec); 197 return (-1); 198 } 199 200 if (cdp->cdd_dumppgsize <= 0) { 201 prom_printf("%s Bad pg tot %d\n", str, cdp->cdd_dumppgsize); 202 return (-1); 203 } 204 205 cpr_debug = cdp->cdd_debug; 206 207 return (0); 208 } 209 210 211 /* 212 * update cpr dump terminator 213 */ 214 void 215 cpr_update_terminator(ctrm_t *file_term, caddr_t mapva) 216 { 217 ctrm_t *mem_term; 218 219 /* 220 * Add the offset to reach the terminator in the kernel so that we 221 * can directly change the restored kernel image. 222 */ 223 mem_term = (ctrm_t *)(mapva + (file_term->va & MMU_PAGEOFFSET)); 224 225 mem_term->real_statef_size = file_term->real_statef_size; 226 mem_term->tm_shutdown = file_term->tm_shutdown; 227 mem_term->tm_cprboot_start.tv_sec = file_term->tm_cprboot_start.tv_sec; 228 mem_term->tm_cprboot_end.tv_sec = prom_gettime() / 1000; 229 } 230 231 232 /* 233 * simple bcopy for cprboot 234 */ 235 void 236 bcopy(const void *s, void *d, size_t count) 237 { 238 const char *src = s; 239 char *dst = d; 240 241 while (count--) 242 *dst++ = *src++; 243 } 244