xref: /OK3568_Linux_fs/u-boot/common/spl/spl_ab.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <common.h>
7*4882a593Smuzhiyun #include <blk.h>
8*4882a593Smuzhiyun #include <spl_ab.h>
9*4882a593Smuzhiyun 
safe_memcmp(const void * s1,const void * s2,size_t n)10*4882a593Smuzhiyun int safe_memcmp(const void *s1, const void *s2, size_t n)
11*4882a593Smuzhiyun {
12*4882a593Smuzhiyun 	const unsigned char *us1 = s1;
13*4882a593Smuzhiyun 	const unsigned char *us2 = s2;
14*4882a593Smuzhiyun 	int result = 0;
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun 	if (0 == n)
17*4882a593Smuzhiyun 		return 0;
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 	/*
20*4882a593Smuzhiyun 	 * Code snippet without data-dependent branch due to Nate Lawson
21*4882a593Smuzhiyun 	 * (nate@root.org) of Root Labs.
22*4882a593Smuzhiyun 	 */
23*4882a593Smuzhiyun 	while (n--)
24*4882a593Smuzhiyun 		result |= *us1++ ^ *us2++;
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 	return result != 0;
27*4882a593Smuzhiyun }
28*4882a593Smuzhiyun 
htobe32(uint32_t in)29*4882a593Smuzhiyun static uint32_t htobe32(uint32_t in)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	union {
32*4882a593Smuzhiyun 		uint32_t word;
33*4882a593Smuzhiyun 		uint8_t bytes[4];
34*4882a593Smuzhiyun 	} ret;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	ret.bytes[0] = (in >> 24) & 0xff;
37*4882a593Smuzhiyun 	ret.bytes[1] = (in >> 16) & 0xff;
38*4882a593Smuzhiyun 	ret.bytes[2] = (in >> 8) & 0xff;
39*4882a593Smuzhiyun 	ret.bytes[3] = in & 0xff;
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	return ret.word;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
be32toh(uint32_t in)44*4882a593Smuzhiyun static uint32_t be32toh(uint32_t in)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	uint8_t *d = (uint8_t *)&in;
47*4882a593Smuzhiyun 	uint32_t ret;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	ret = ((uint32_t)d[0]) << 24;
50*4882a593Smuzhiyun 	ret |= ((uint32_t)d[1]) << 16;
51*4882a593Smuzhiyun 	ret |= ((uint32_t)d[2]) << 8;
52*4882a593Smuzhiyun 	ret |= ((uint32_t)d[3]);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	return ret;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun 
spl_ab_data_verify_and_byteswap(const AvbABData * src,AvbABData * dest)57*4882a593Smuzhiyun static bool spl_ab_data_verify_and_byteswap(const AvbABData *src,
58*4882a593Smuzhiyun 					    AvbABData *dest)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	/* Ensure magic is correct. */
61*4882a593Smuzhiyun 	if (safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
62*4882a593Smuzhiyun 		printf("Magic is incorrect.\n");
63*4882a593Smuzhiyun 		return false;
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	memcpy(dest, src, sizeof(AvbABData));
67*4882a593Smuzhiyun 	dest->crc32 = be32toh(dest->crc32);
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	/* Ensure we don't attempt to access any fields if the major version
70*4882a593Smuzhiyun 	 * is not supported.
71*4882a593Smuzhiyun 	 */
72*4882a593Smuzhiyun 	if (dest->version_major > AVB_AB_MAJOR_VERSION) {
73*4882a593Smuzhiyun 		printf("No support for given major version.\n");
74*4882a593Smuzhiyun 		return false;
75*4882a593Smuzhiyun 	}
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	/* Bail if CRC32 doesn't match. */
78*4882a593Smuzhiyun 	if (dest->crc32 !=
79*4882a593Smuzhiyun 		crc32(0, (const uint8_t *)dest,
80*4882a593Smuzhiyun 		      sizeof(AvbABData) - sizeof(uint32_t))) {
81*4882a593Smuzhiyun 		printf("CRC32 does not match.\n");
82*4882a593Smuzhiyun 		return false;
83*4882a593Smuzhiyun 	}
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	return true;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
spl_ab_data_update_crc_and_byteswap(const AvbABData * src,AvbABData * dest)88*4882a593Smuzhiyun static void spl_ab_data_update_crc_and_byteswap(const AvbABData *src,
89*4882a593Smuzhiyun 						AvbABData *dest)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	memcpy(dest, src, sizeof(AvbABData));
92*4882a593Smuzhiyun 	dest->crc32 = htobe32(crc32(0, (const uint8_t *)dest,
93*4882a593Smuzhiyun 			    sizeof(AvbABData) - sizeof(uint32_t)));
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
spl_ab_data_init(AvbABData * data)96*4882a593Smuzhiyun static void spl_ab_data_init(AvbABData *data)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	memset(data, '\0', sizeof(AvbABData));
99*4882a593Smuzhiyun 	memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
100*4882a593Smuzhiyun 	data->version_major = AVB_AB_MAJOR_VERSION;
101*4882a593Smuzhiyun 	data->version_minor = AVB_AB_MINOR_VERSION;
102*4882a593Smuzhiyun 	data->last_boot = 0;
103*4882a593Smuzhiyun 	data->slots[0].priority = AVB_AB_MAX_PRIORITY;
104*4882a593Smuzhiyun 	data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
105*4882a593Smuzhiyun 	data->slots[0].successful_boot = 0;
106*4882a593Smuzhiyun 	data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
107*4882a593Smuzhiyun 	data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
108*4882a593Smuzhiyun 	data->slots[1].successful_boot = 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
spl_read_ab_metadata(struct blk_desc * dev_desc,AvbABData * ab_data,char * partition)111*4882a593Smuzhiyun static int spl_read_ab_metadata(struct blk_desc *dev_desc, AvbABData *ab_data,
112*4882a593Smuzhiyun 				char *partition)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	disk_partition_t part_info;
115*4882a593Smuzhiyun 	char temp[512];
116*4882a593Smuzhiyun 	int ret;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (!dev_desc || !partition || !ab_data)
119*4882a593Smuzhiyun 		return -EFAULT;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	if (part_get_info_by_name(dev_desc, partition, &part_info) < 0)
122*4882a593Smuzhiyun 		return -ENOENT;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	ret = blk_dread(dev_desc, part_info.start + AB_METADATA_OFFSET, 1,
125*4882a593Smuzhiyun 			temp);
126*4882a593Smuzhiyun 	if (ret != 1)
127*4882a593Smuzhiyun 		return -ENODEV;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if (sizeof(AvbABData) > 512)
130*4882a593Smuzhiyun 		return -ENOMEM;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	memcpy(ab_data, temp, sizeof(AvbABData));
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	return 0;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
spl_write_ab_metadata(struct blk_desc * dev_desc,AvbABData * ab_data,char * partition)137*4882a593Smuzhiyun static int spl_write_ab_metadata(struct blk_desc *dev_desc, AvbABData *ab_data,
138*4882a593Smuzhiyun 				 char *partition)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	disk_partition_t part_info;
141*4882a593Smuzhiyun 	char temp[512];
142*4882a593Smuzhiyun 	int ret;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	if (!dev_desc || !partition || !ab_data)
145*4882a593Smuzhiyun 		return -EFAULT;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	if (sizeof(AvbABData) > 512)
148*4882a593Smuzhiyun 		return -ENOMEM;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	memcpy(temp, ab_data, sizeof(AvbABData));
151*4882a593Smuzhiyun 	if (part_get_info_by_name(dev_desc, partition, &part_info) < 0)
152*4882a593Smuzhiyun 		return -ENOENT;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	ret = blk_dwrite(dev_desc, part_info.start + AB_METADATA_OFFSET, 1,
155*4882a593Smuzhiyun 			 temp);
156*4882a593Smuzhiyun 	if (ret != 1)
157*4882a593Smuzhiyun 		return -ENODEV;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	return 0;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
spl_ab_data_write(struct blk_desc * dev_desc,AvbABData * ab_data,char * partition)162*4882a593Smuzhiyun static int spl_ab_data_write(struct blk_desc *dev_desc, AvbABData *ab_data,
163*4882a593Smuzhiyun 			     char *partition)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	AvbABData serialized;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	spl_ab_data_update_crc_and_byteswap(ab_data, &serialized);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return spl_write_ab_metadata(dev_desc, &serialized, partition);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
spl_ab_data_read(struct blk_desc * dev_desc,AvbABData * ab_data,char * partition)172*4882a593Smuzhiyun static int spl_ab_data_read(struct blk_desc *dev_desc, AvbABData *ab_data,
173*4882a593Smuzhiyun 			    char *partition)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	int ret;
176*4882a593Smuzhiyun 	AvbABData serialized;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	ret = spl_read_ab_metadata(dev_desc, &serialized, partition);
179*4882a593Smuzhiyun 	if (ret)
180*4882a593Smuzhiyun 		return ret;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	if (!spl_ab_data_verify_and_byteswap(&serialized, ab_data)) {
183*4882a593Smuzhiyun 		printf("Error validating A/B metadata from disk. "
184*4882a593Smuzhiyun 		       "Resetting and writing new A/B metadata to disk.\n");
185*4882a593Smuzhiyun 		spl_ab_data_init(ab_data);
186*4882a593Smuzhiyun 		spl_ab_data_write(dev_desc, ab_data, partition);
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
spl_slot_is_bootable(AvbABSlotData * slot)192*4882a593Smuzhiyun static bool spl_slot_is_bootable(AvbABSlotData *slot)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	return slot->priority > 0 &&
195*4882a593Smuzhiyun 		(slot->successful_boot || (slot->tries_remaining > 0));
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
spl_get_lastboot(AvbABData * ab_data)198*4882a593Smuzhiyun static int spl_get_lastboot(AvbABData *ab_data)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	return ab_data->last_boot;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
spl_get_current_slot(struct blk_desc * dev_desc,char * partition,char * slot)203*4882a593Smuzhiyun int spl_get_current_slot(struct blk_desc *dev_desc, char *partition, char *slot)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun 	static int last_slot_index = -1;
206*4882a593Smuzhiyun 	size_t slot_index_to_boot;
207*4882a593Smuzhiyun 	AvbABData ab_data;
208*4882a593Smuzhiyun 	int ret;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	ret = spl_ab_data_read(dev_desc, &ab_data, partition);
211*4882a593Smuzhiyun 	if (ret)
212*4882a593Smuzhiyun 		return ret;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	if (spl_slot_is_bootable(&ab_data.slots[0]) &&
215*4882a593Smuzhiyun 	    spl_slot_is_bootable(&ab_data.slots[1])) {
216*4882a593Smuzhiyun 		if (ab_data.slots[1].priority > ab_data.slots[0].priority)
217*4882a593Smuzhiyun 			slot_index_to_boot = 1;
218*4882a593Smuzhiyun 		else
219*4882a593Smuzhiyun 			slot_index_to_boot = 0;
220*4882a593Smuzhiyun 	} else if (spl_slot_is_bootable(&ab_data.slots[0])) {
221*4882a593Smuzhiyun 		slot_index_to_boot = 0;
222*4882a593Smuzhiyun 	} else if (spl_slot_is_bootable(&ab_data.slots[1])) {
223*4882a593Smuzhiyun 		slot_index_to_boot = 1;
224*4882a593Smuzhiyun 	} else {
225*4882a593Smuzhiyun 		printf("No bootable slots found, use lastboot.\n");
226*4882a593Smuzhiyun 		if (spl_get_lastboot(&ab_data) == 0) {
227*4882a593Smuzhiyun 			memcpy(slot, "_a", 2);
228*4882a593Smuzhiyun 			goto out;
229*4882a593Smuzhiyun 		} else if (spl_get_lastboot(&ab_data) == 1) {
230*4882a593Smuzhiyun 			memcpy(slot, "_b", 2);
231*4882a593Smuzhiyun 			goto out;
232*4882a593Smuzhiyun 		} else {
233*4882a593Smuzhiyun 			return -ENODEV;
234*4882a593Smuzhiyun 		}
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	if (slot_index_to_boot == 0)
238*4882a593Smuzhiyun 		memcpy(slot, "_a", 2);
239*4882a593Smuzhiyun 	else if (slot_index_to_boot == 1)
240*4882a593Smuzhiyun 		memcpy(slot, "_b", 2);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	if (last_slot_index != slot_index_to_boot) {
243*4882a593Smuzhiyun 		last_slot_index = slot_index_to_boot;
244*4882a593Smuzhiyun 		printf("SPL: A/B-slot: %s, successful: %d, tries-remain: %d\n",
245*4882a593Smuzhiyun 		       slot,
246*4882a593Smuzhiyun 		       ab_data.slots[slot_index_to_boot].successful_boot,
247*4882a593Smuzhiyun 		       ab_data.slots[slot_index_to_boot].tries_remaining);
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun out:
251*4882a593Smuzhiyun 	return 0;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun 
spl_ab_append_part_slot(struct blk_desc * dev_desc,const char * part_name,char * new_name)254*4882a593Smuzhiyun int spl_ab_append_part_slot(struct blk_desc *dev_desc,
255*4882a593Smuzhiyun 			    const char *part_name,
256*4882a593Smuzhiyun 			    char *new_name)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	char slot_suffix[3] = {0};
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	if (!strcmp(part_name, "misc")) {
261*4882a593Smuzhiyun 		strcat(new_name, part_name);
262*4882a593Smuzhiyun 		return 0;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	if (spl_get_current_slot(dev_desc, "misc", slot_suffix)) {
266*4882a593Smuzhiyun 		printf("No misc partition\n");
267*4882a593Smuzhiyun 		strcat(new_name, part_name);
268*4882a593Smuzhiyun 		return 0;
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	strcpy(new_name, part_name);
272*4882a593Smuzhiyun 	strcat(new_name, slot_suffix);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	return 0;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
spl_save_metadata_if_changed(struct blk_desc * dev_desc,AvbABData * ab_data,AvbABData * ab_data_orig)277*4882a593Smuzhiyun static int spl_save_metadata_if_changed(struct blk_desc *dev_desc,
278*4882a593Smuzhiyun 					AvbABData *ab_data,
279*4882a593Smuzhiyun 					AvbABData *ab_data_orig)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	if (safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)))
282*4882a593Smuzhiyun 		return spl_ab_data_write(dev_desc, ab_data, "misc");
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	return 0;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun /* If verify fail in a/b system, then decrease 1. */
spl_ab_decrease_tries(struct blk_desc * dev_desc)288*4882a593Smuzhiyun int spl_ab_decrease_tries(struct blk_desc *dev_desc)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun 	AvbABData ab_data, ab_data_orig;
291*4882a593Smuzhiyun 	size_t slot_index = 0;
292*4882a593Smuzhiyun 	char slot_suffix[3] = {0};
293*4882a593Smuzhiyun 	int ret = -1;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	ret = spl_get_current_slot(dev_desc, "misc", slot_suffix);
296*4882a593Smuzhiyun 	if (ret)
297*4882a593Smuzhiyun 		goto out;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (!strncmp(slot_suffix, "_a", 2))
300*4882a593Smuzhiyun 		slot_index = 0;
301*4882a593Smuzhiyun 	else if (!strncmp(slot_suffix, "_b", 2))
302*4882a593Smuzhiyun 		slot_index = 1;
303*4882a593Smuzhiyun 	else
304*4882a593Smuzhiyun 		slot_index = 0;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	ret = spl_ab_data_read(dev_desc, &ab_data, "misc");
307*4882a593Smuzhiyun 	if (ret)
308*4882a593Smuzhiyun 		goto out;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	memcpy(&ab_data_orig, &ab_data, sizeof(AvbABData));
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	/* ... and decrement tries remaining, if applicable. */
313*4882a593Smuzhiyun 	if (!ab_data.slots[slot_index].successful_boot &&
314*4882a593Smuzhiyun 	    ab_data.slots[slot_index].tries_remaining > 0)
315*4882a593Smuzhiyun 		ab_data.slots[slot_index].tries_remaining -= 1;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	ret = spl_save_metadata_if_changed(dev_desc, &ab_data, &ab_data_orig);
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun out:
320*4882a593Smuzhiyun 	return ret;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun /*
324*4882a593Smuzhiyun  * If boot A/B system fail, tries-remaining decrease 1
325*4882a593Smuzhiyun  * and do reset automatically if still bootable.
326*4882a593Smuzhiyun  */
spl_ab_decrease_reset(struct blk_desc * dev_desc)327*4882a593Smuzhiyun int spl_ab_decrease_reset(struct blk_desc *dev_desc)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun 	AvbABData ab_data;
330*4882a593Smuzhiyun 	int ret;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	ret = spl_ab_data_read(dev_desc, &ab_data, "misc");
333*4882a593Smuzhiyun 	if (ret)
334*4882a593Smuzhiyun 		return ret;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	/* If current device cannot boot, return and try other devices. */
337*4882a593Smuzhiyun 	if (!spl_slot_is_bootable(&ab_data.slots[0]) &&
338*4882a593Smuzhiyun 	    !spl_slot_is_bootable(&ab_data.slots[1])) {
339*4882a593Smuzhiyun 		printf("A/B: no bootable slot\n");
340*4882a593Smuzhiyun 		return -ENODEV;
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	/* If current device still can boot, decrease and do reset. */
344*4882a593Smuzhiyun 	ret = spl_ab_decrease_tries(dev_desc);
345*4882a593Smuzhiyun 	if (ret)
346*4882a593Smuzhiyun 		return ret;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	printf("A/B: slot boot fail, do reset\n");
349*4882a593Smuzhiyun 	do_reset(NULL, 0, 0, NULL);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	/*
352*4882a593Smuzhiyun 	 * Only do_reset() fail will arrive here, return a
353*4882a593Smuzhiyun 	 * negative number, then enter maskrom in the caller.
354*4882a593Smuzhiyun 	 */
355*4882a593Smuzhiyun 	return -EINVAL;
356*4882a593Smuzhiyun }
357