xref: /titanic_52/usr/src/lib/libtnf/ref.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  *	Copyright (c) 1994, by Sun Microsytems, Inc.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma	ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #include "libtnf.h"
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate /*
31*7c478bd9Sstevel@tonic-gate  * Unoptimized versions, always dereference a cell through _GET_INT32()
32*7c478bd9Sstevel@tonic-gate  *
33*7c478bd9Sstevel@tonic-gate  */
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #define	LONG_SIGN_BIT	0x80000000
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate static tnf_ref32_t *vaddr_to_phys(TNF *, tnf_ref32_t *, tnf_ref32_t);
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate /*
40*7c478bd9Sstevel@tonic-gate  * Return target cell referred to via src_val from src_cell, after
41*7c478bd9Sstevel@tonic-gate  * checking that target is valid (block was not reused).  Return NULL
42*7c478bd9Sstevel@tonic-gate  * otherwise.
43*7c478bd9Sstevel@tonic-gate  *
44*7c478bd9Sstevel@tonic-gate  * NOTE: We must check if the destination is within the valid_bytes
45*7c478bd9Sstevel@tonic-gate  * range of its block, so as to correctly handle tnfxtract'ed files:
46*7c478bd9Sstevel@tonic-gate  * the block containing the target cell may have been copied out
47*7c478bd9Sstevel@tonic-gate  * before the block containing the source cell.
48*7c478bd9Sstevel@tonic-gate  */
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate static tnf_ref32_t *
51*7c478bd9Sstevel@tonic-gate vaddr_to_phys(TNF *tnf, tnf_ref32_t *src_cell, tnf_ref32_t src_val)
52*7c478bd9Sstevel@tonic-gate {
53*7c478bd9Sstevel@tonic-gate 	char		*base;
54*7c478bd9Sstevel@tonic-gate 	unsigned	shft, mask;
55*7c478bd9Sstevel@tonic-gate 	tnf_uint32_t	src_gen, dst_gen, exp_gen;
56*7c478bd9Sstevel@tonic-gate 	tnf_int32_t	gen_delta;
57*7c478bd9Sstevel@tonic-gate 	tnf_ref32_t	src_off, exp_off, dst_off, *dst_blk, *dst_cell;
58*7c478bd9Sstevel@tonic-gate 	tnf_uint32_t	bytes_valid;
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate 	base = tnf->file_start;
61*7c478bd9Sstevel@tonic-gate 	shft = tnf->generation_shift;
62*7c478bd9Sstevel@tonic-gate 	mask = tnf->address_mask;
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	/* Generation of source cell */
65*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer cast */
66*7c478bd9Sstevel@tonic-gate 	src_gen = _GET_BLOCK_GENERATION(tnf, _GET_BLOCK(tnf, src_cell));
67*7c478bd9Sstevel@tonic-gate 	/* Physical file offset of source cell */
68*7c478bd9Sstevel@tonic-gate 	src_off = (tnf_ref32_t)((char *)src_cell - base);
69*7c478bd9Sstevel@tonic-gate 	/* Expected (unadjusted) file offset of destination cell */
70*7c478bd9Sstevel@tonic-gate 	exp_off = src_off + src_val;
71*7c478bd9Sstevel@tonic-gate 	/* Generation delta */
72*7c478bd9Sstevel@tonic-gate 	gen_delta = (tnf_int32_t)((unsigned)exp_off >> shft);
73*7c478bd9Sstevel@tonic-gate 	if ((exp_off & LONG_SIGN_BIT) == LONG_SIGN_BIT) {
74*7c478bd9Sstevel@tonic-gate 		/* sign bit was a 1 - so restore sign */
75*7c478bd9Sstevel@tonic-gate 		gen_delta |= ((unsigned)mask << (32 - shft));
76*7c478bd9Sstevel@tonic-gate 	}
77*7c478bd9Sstevel@tonic-gate 	/* Expected destination generation */
78*7c478bd9Sstevel@tonic-gate 	exp_gen = src_gen + gen_delta;
79*7c478bd9Sstevel@tonic-gate 	/* Physical file offset of destination cell */
80*7c478bd9Sstevel@tonic-gate 	dst_off = (tnf_ref32_t)((unsigned)exp_off & mask);
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 	/* Destination cell */
83*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer cast */
84*7c478bd9Sstevel@tonic-gate 	dst_cell = (tnf_ref32_t *)(base + dst_off);
85*7c478bd9Sstevel@tonic-gate 	/* Destination block */
86*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer cast */
87*7c478bd9Sstevel@tonic-gate 	dst_blk = _GET_BLOCK(tnf, dst_cell);
88*7c478bd9Sstevel@tonic-gate 	/* Generation of destination cell */
89*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer cast */
90*7c478bd9Sstevel@tonic-gate 	dst_gen = _GET_BLOCK_GENERATION(tnf, dst_blk);
91*7c478bd9Sstevel@tonic-gate 	/* Bytes valid in destination block */
92*7c478bd9Sstevel@tonic-gate 	/* LINTED pointer cast */
93*7c478bd9Sstevel@tonic-gate 	bytes_valid = _GET_BLOCK_BYTES_VALID(tnf, dst_blk);
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate 	if ((src_gen == (tnf_uint32_t)TNF_TAG_GENERATION_NUM) ||
96*7c478bd9Sstevel@tonic-gate 	    (dst_gen == (tnf_uint32_t)TNF_TAG_GENERATION_NUM) ||
97*7c478bd9Sstevel@tonic-gate 	    ((dst_gen == exp_gen) &&
98*7c478bd9Sstevel@tonic-gate 		((char *)dst_cell - (char *)dst_blk) < bytes_valid))
99*7c478bd9Sstevel@tonic-gate 		return (dst_cell);
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 	return ((tnf_ref32_t *)NULL);
102*7c478bd9Sstevel@tonic-gate }
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate /*
105*7c478bd9Sstevel@tonic-gate  * Return the target referent of a cell, chasing forwarding references.
106*7c478bd9Sstevel@tonic-gate  * Return TNF_NULL if cell is a TNF_NULL forwarding reference.
107*7c478bd9Sstevel@tonic-gate  */
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate tnf_ref32_t *
110*7c478bd9Sstevel@tonic-gate _tnf_get_ref32(TNF *tnf, tnf_ref32_t *cell)
111*7c478bd9Sstevel@tonic-gate {
112*7c478bd9Sstevel@tonic-gate 	tnf_ref32_t 	ref32, reftemp;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	ref32 = _GET_INT32(tnf, cell);
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	if (TNF_REF32_IS_NULL(ref32))
117*7c478bd9Sstevel@tonic-gate 		return (TNF_NULL);
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	if (TNF_REF32_IS_RSVD(ref32)) {
120*7c478bd9Sstevel@tonic-gate 		_tnf_error(tnf, TNF_ERR_BADREFTYPE);
121*7c478bd9Sstevel@tonic-gate 		return (TNF_NULL);
122*7c478bd9Sstevel@tonic-gate 	}
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	if (TNF_REF32_IS_PAIR(ref32)) {
125*7c478bd9Sstevel@tonic-gate 		/* We chase the high (tag) half */
126*7c478bd9Sstevel@tonic-gate 		tnf_ref16_t	tag16;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 		tag16 = TNF_REF32_TAG16(ref32);
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 		if (TNF_TAG16_IS_ABS(tag16)) {
131*7c478bd9Sstevel@tonic-gate 			cell = (tnf_ref32_t *)
132*7c478bd9Sstevel@tonic-gate 				((char *)tnf->file_start
133*7c478bd9Sstevel@tonic-gate /* LINTED pointer cast may result in improper alignment */
134*7c478bd9Sstevel@tonic-gate 				+ TNF_TAG16_ABS16(tag16));
135*7c478bd9Sstevel@tonic-gate 			ref32 = _GET_INT32(tnf, cell);
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 		} else if (TNF_TAG16_IS_REL(tag16)) {
138*7c478bd9Sstevel@tonic-gate 			cell = vaddr_to_phys(tnf, cell,
139*7c478bd9Sstevel@tonic-gate 					(tnf_ref32_t) TNF_TAG16_REF16(tag16));
140*7c478bd9Sstevel@tonic-gate 			if (cell == TNF_NULL)
141*7c478bd9Sstevel@tonic-gate 				return (TNF_NULL);
142*7c478bd9Sstevel@tonic-gate 			ref32 = _GET_INT32(tnf, cell);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 		} else {
145*7c478bd9Sstevel@tonic-gate 			_tnf_error(tnf, TNF_ERR_BADREFTYPE);
146*7c478bd9Sstevel@tonic-gate 			return (TNF_NULL);
147*7c478bd9Sstevel@tonic-gate 		}
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate 	} else if (TNF_REF32_IS_PERMANENT(ref32)) {
150*7c478bd9Sstevel@tonic-gate 		/* permanent space pointer */
151*7c478bd9Sstevel@tonic-gate 		reftemp = TNF_REF32_VALUE(ref32);
152*7c478bd9Sstevel@tonic-gate 		reftemp = TNF_REF32_SIGN_EXTEND(reftemp);
153*7c478bd9Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
154*7c478bd9Sstevel@tonic-gate 		cell = (tnf_ref32_t *) ((char *)tnf->file_start + reftemp);
155*7c478bd9Sstevel@tonic-gate 		ref32 = _GET_INT32(tnf, cell);
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	} else {		/* full/tag reclaimable space reference */
158*7c478bd9Sstevel@tonic-gate 		cell = vaddr_to_phys(tnf, cell, TNF_REF32_VALUE(ref32));
159*7c478bd9Sstevel@tonic-gate 		if (cell == TNF_NULL)
160*7c478bd9Sstevel@tonic-gate 			return (TNF_NULL);
161*7c478bd9Sstevel@tonic-gate 		ref32 = _GET_INT32(tnf, cell);
162*7c478bd9Sstevel@tonic-gate 	}
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	/* chase intermediate forwarding references */
165*7c478bd9Sstevel@tonic-gate 	while (ref32 && TNF_REF32_IS_FWD(ref32)) {
166*7c478bd9Sstevel@tonic-gate 		if (TNF_REF32_IS_PERMANENT(ref32)) {
167*7c478bd9Sstevel@tonic-gate 			reftemp = TNF_REF32_VALUE(ref32);
168*7c478bd9Sstevel@tonic-gate 			reftemp = TNF_REF32_SIGN_EXTEND(reftemp);
169*7c478bd9Sstevel@tonic-gate 			cell = (tnf_ref32_t *) ((char *)tnf->file_start +
170*7c478bd9Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
171*7c478bd9Sstevel@tonic-gate 							reftemp);
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 		} else {
174*7c478bd9Sstevel@tonic-gate 			cell = vaddr_to_phys(tnf, cell, TNF_REF32_VALUE(ref32));
175*7c478bd9Sstevel@tonic-gate 			if (cell == TNF_NULL)
176*7c478bd9Sstevel@tonic-gate 				return (TNF_NULL);
177*7c478bd9Sstevel@tonic-gate 		}
178*7c478bd9Sstevel@tonic-gate 		ref32 = _GET_INT32(tnf, cell);
179*7c478bd9Sstevel@tonic-gate 	}
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	return (cell);
182*7c478bd9Sstevel@tonic-gate }
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate /*
185*7c478bd9Sstevel@tonic-gate  * Return the target referent of ref16 contained in cell.
186*7c478bd9Sstevel@tonic-gate  * Return TNF_NULL if cell doesn't have a ref16.
187*7c478bd9Sstevel@tonic-gate  */
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate tnf_ref32_t *
190*7c478bd9Sstevel@tonic-gate _tnf_get_ref16(TNF *tnf, tnf_ref32_t *cell)
191*7c478bd9Sstevel@tonic-gate {
192*7c478bd9Sstevel@tonic-gate 	tnf_ref32_t 	ref32, reftemp;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	ref32 = _GET_INT32(tnf, cell);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	if (TNF_REF32_IS_PAIR(ref32)) {
197*7c478bd9Sstevel@tonic-gate 		tnf_ref16_t	ref16;
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 		ref16 = TNF_REF32_REF16(ref32);
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 		if (TNF_REF16_VALUE(ref16) == TNF_NULL)
202*7c478bd9Sstevel@tonic-gate 			/* No ref16 was stored */
203*7c478bd9Sstevel@tonic-gate 			return (TNF_NULL);
204*7c478bd9Sstevel@tonic-gate 		else {
205*7c478bd9Sstevel@tonic-gate 			cell = vaddr_to_phys(tnf, cell,
206*7c478bd9Sstevel@tonic-gate 					(tnf_ref32_t) TNF_REF16_VALUE(ref16));
207*7c478bd9Sstevel@tonic-gate 			if (cell == TNF_NULL)
208*7c478bd9Sstevel@tonic-gate 				return (TNF_NULL);
209*7c478bd9Sstevel@tonic-gate 			ref32 = _GET_INT32(tnf, cell);
210*7c478bd9Sstevel@tonic-gate 		}
211*7c478bd9Sstevel@tonic-gate 	} else			/* not a pair pointer */
212*7c478bd9Sstevel@tonic-gate 		return (TNF_NULL);
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	/* chase intermediate forwarding references */
215*7c478bd9Sstevel@tonic-gate 	while (ref32 && TNF_REF32_IS_FWD(ref32)) {
216*7c478bd9Sstevel@tonic-gate 		if (TNF_REF32_IS_PERMANENT(ref32)) {
217*7c478bd9Sstevel@tonic-gate 			reftemp = TNF_REF32_VALUE(ref32);
218*7c478bd9Sstevel@tonic-gate 			reftemp = TNF_REF32_SIGN_EXTEND(reftemp);
219*7c478bd9Sstevel@tonic-gate 			cell = (tnf_ref32_t *) ((char *)tnf->file_start +
220*7c478bd9Sstevel@tonic-gate 		/* LINTED pointer cast may result in improper alignment */
221*7c478bd9Sstevel@tonic-gate 							reftemp);
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 		} else {
224*7c478bd9Sstevel@tonic-gate 			cell = vaddr_to_phys(tnf, cell, TNF_REF32_VALUE(ref32));
225*7c478bd9Sstevel@tonic-gate 			if (cell == TNF_NULL)
226*7c478bd9Sstevel@tonic-gate 				return (TNF_NULL);
227*7c478bd9Sstevel@tonic-gate 		}
228*7c478bd9Sstevel@tonic-gate 		ref32 = _GET_INT32(tnf, cell);
229*7c478bd9Sstevel@tonic-gate 	}
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	return (cell);
232*7c478bd9Sstevel@tonic-gate }
233