1 | /* $NetBSD: dkwedge_apple.c,v 1.2 2015/01/24 02:58:56 christos Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2012 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Christos Zoulas. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Apple support for disk wedges |
34 | */ |
35 | |
36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: dkwedge_apple.c,v 1.2 2015/01/24 02:58:56 christos Exp $" ); |
38 | |
39 | #include <sys/param.h> |
40 | #ifdef _KERNEL |
41 | #include <sys/systm.h> |
42 | #endif |
43 | #include <sys/proc.h> |
44 | #include <sys/errno.h> |
45 | #include <sys/disk.h> |
46 | #include <sys/vnode.h> |
47 | #include <sys/malloc.h> |
48 | #include <sys/bitops.h> |
49 | |
50 | #include <sys/bootblock.h> |
51 | |
52 | #define SWAP16(x) ap->x = be16toh(ap->x) |
53 | #define SWAP32(x) ap->x = be32toh(ap->x) |
54 | |
55 | #ifdef DKWEDGE_DEBUG |
56 | #define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__) |
57 | #else |
58 | #define DPRINTF(fmt, ...) |
59 | #endif |
60 | |
61 | static void |
62 | swap_apple_drvr_descriptor(struct apple_drvr_descriptor *ap) |
63 | { |
64 | SWAP32(descBlock); |
65 | SWAP16(descSize); |
66 | SWAP16(descType); |
67 | } |
68 | |
69 | static void |
70 | swap_apple_drvr_map(struct apple_drvr_map *ap) |
71 | { |
72 | uint16_t i; |
73 | |
74 | SWAP16(sbSig); |
75 | SWAP16(sbBlockSize); |
76 | SWAP32(sbBlkCount); |
77 | SWAP16(sbDevType); |
78 | SWAP16(sbDevID); |
79 | SWAP32(sbData); |
80 | SWAP16(sbDrvrCount); |
81 | |
82 | if (ap->sbDrvrCount >= APPLE_DRVR_MAP_MAX_DESCRIPTORS) |
83 | ap->sbDrvrCount = APPLE_DRVR_MAP_MAX_DESCRIPTORS; |
84 | |
85 | for (i = 0; i < ap->sbDrvrCount; i++) |
86 | swap_apple_drvr_descriptor(&ap->sb_dd[i]); |
87 | } |
88 | |
89 | static void |
90 | swap_apple_part_map_entry(struct apple_part_map_entry *ap) |
91 | { |
92 | SWAP16(pmSig); |
93 | SWAP16(pmSigPad); |
94 | SWAP32(pmMapBlkCnt); |
95 | SWAP32(pmPyPartStart); |
96 | SWAP32(pmPartBlkCnt); |
97 | SWAP32(pmLgDataStart); |
98 | SWAP32(pmDataCnt); |
99 | SWAP32(pmPartStatus); |
100 | SWAP32(pmLgBootStart); |
101 | SWAP32(pmBootSize); |
102 | SWAP32(pmBootLoad); |
103 | SWAP32(pmBootLoad2); |
104 | SWAP32(pmBootEntry); |
105 | SWAP32(pmBootEntry2); |
106 | SWAP32(pmBootCksum); |
107 | } |
108 | |
109 | static void |
110 | swap_apple_blockzeroblock(struct apple_blockzeroblock *ap) |
111 | { |
112 | SWAP32(bzbMagic); |
113 | SWAP16(bzbBadBlockInode); |
114 | SWAP16(bzbFlags); |
115 | SWAP16(bzbReserved); |
116 | SWAP32(bzbCreationTime); |
117 | SWAP32(bzbMountTime); |
118 | SWAP32(bzbUMountTime); |
119 | } |
120 | |
121 | #undef SWAP16 |
122 | #undef SWAP32 |
123 | |
124 | #define ASIZE 16384 |
125 | |
126 | #ifdef _KERNEL |
127 | #define DKW_MALLOC(SZ) malloc((SZ), M_DEVBUF, M_WAITOK) |
128 | #define DKW_FREE(PTR) free((PTR), M_DEVBUF) |
129 | #else |
130 | #define DKW_MALLOC(SZ) malloc((SZ)) |
131 | #define DKW_FREE(PTR) free((PTR)) |
132 | #endif |
133 | |
134 | static struct { |
135 | const char *name; |
136 | const char *type; |
137 | } map[] = { |
138 | { APPLE_PART_TYPE_UNIX, DKW_PTYPE_SYSV }, |
139 | { APPLE_PART_TYPE_MAC, DKW_PTYPE_APPLEHFS }, |
140 | }; |
141 | |
142 | |
143 | static int |
144 | dkwedge_discover_apple(struct disk *pdk, struct vnode *vp) |
145 | { |
146 | size_t i; |
147 | int error; |
148 | void *buf; |
149 | uint32_t blocksize, offset, rsize; |
150 | struct apple_drvr_map *am; |
151 | struct apple_part_map_entry *ae; |
152 | struct apple_blockzeroblock ab; |
153 | const char *ptype; |
154 | |
155 | buf = DKW_MALLOC(ASIZE); |
156 | if ((error = dkwedge_read(pdk, vp, 0, buf, ASIZE)) != 0) { |
157 | DPRINTF("%s: read @%u %d\n" , __func__, 0, error); |
158 | goto out; |
159 | } |
160 | |
161 | am = buf; |
162 | swap_apple_drvr_map(am); |
163 | |
164 | error = ESRCH; |
165 | |
166 | if (am->sbSig != APPLE_DRVR_MAP_MAGIC) { |
167 | DPRINTF("%s: drvr magic %x != %x\n" , __func__, am->sbSig, |
168 | APPLE_DRVR_MAP_MAGIC); |
169 | goto out; |
170 | } |
171 | |
172 | blocksize = am->sbBlockSize; |
173 | |
174 | rsize = 1 << (ilog2(MAX(sizeof(*ae), blocksize) - 1) + 1); |
175 | if (ASIZE < rsize) { |
176 | DPRINTF("%s: buffer too small %u < %u\n" , __func__, ASIZE, |
177 | rsize); |
178 | goto out; |
179 | } |
180 | |
181 | ae = buf; |
182 | for (offset = blocksize;; offset += rsize) { |
183 | DPRINTF("%s: offset %x rsize %x\n" , __func__, offset, rsize); |
184 | if ((error = dkwedge_read(pdk, vp, offset / DEV_BSIZE, buf, |
185 | rsize)) != 0) { |
186 | DPRINTF("%s: read @%u %d\n" , __func__, offset, |
187 | error); |
188 | goto out; |
189 | } |
190 | |
191 | swap_apple_part_map_entry(ae); |
192 | if (ae->pmSig != APPLE_PART_MAP_ENTRY_MAGIC) { |
193 | DPRINTF("%s: part magic %x != %x\n" , __func__, |
194 | ae->pmSig, APPLE_PART_MAP_ENTRY_MAGIC); |
195 | break; |
196 | } |
197 | |
198 | for (i = 0; i < __arraycount(map); i++) |
199 | if (strcasecmp(map[i].name, ae->pmPartType) == 0) |
200 | break; |
201 | |
202 | DPRINTF("%s: %s/%s PH=%u/%u LG=%u/%u\n" , __func__, |
203 | ae->pmPartName, ae->pmPartType, |
204 | ae->pmPyPartStart, ae->pmPartBlkCnt, |
205 | ae->pmLgDataStart, ae->pmDataCnt); |
206 | |
207 | if (i == __arraycount(map)) |
208 | continue; |
209 | |
210 | ptype = map[i].type; |
211 | memcpy(&ab, ae->pmBootArgs, sizeof(ab)); |
212 | swap_apple_blockzeroblock(&ab); |
213 | if (ab.bzbMagic == APPLE_BZB_MAGIC) { |
214 | if (ab.bzbType == APPLE_BZB_TYPESWAP) |
215 | ptype = DKW_PTYPE_SWAP; |
216 | } |
217 | |
218 | struct dkwedge_info dkw; |
219 | |
220 | strcpy(dkw.dkw_ptype, ptype); |
221 | strcpy(dkw.dkw_parent, pdk->dk_name); |
222 | dkw.dkw_offset = ae->pmPyPartStart; |
223 | dkw.dkw_size = ae->pmPartBlkCnt; |
224 | strlcpy(dkw.dkw_wname, ae->pmPartName, sizeof(dkw.dkw_wname)); |
225 | error = dkwedge_add(&dkw); |
226 | if (error == EEXIST) |
227 | aprint_error("%s: wedge named '%s' already " |
228 | "exists, manual intervention required\n" , |
229 | pdk->dk_name, dkw.dkw_wname); |
230 | else if (error) |
231 | aprint_error("%s: error %d adding partition " |
232 | "%s type %s\n" , pdk->dk_name, error, |
233 | ae->pmPartType, dkw.dkw_ptype); |
234 | } |
235 | |
236 | out: |
237 | DKW_FREE(buf); |
238 | DPRINTF("%s: return %d\n" , __func__, error); |
239 | return error; |
240 | } |
241 | |
242 | #ifdef _KERNEL |
243 | DKWEDGE_DISCOVERY_METHOD_DECL(APPLE, -5, dkwedge_discover_apple); |
244 | #endif |
245 | |