1 /* ----------------------------------------------------------------------- *
3 * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
16 * (Over)write a data item in the auxilliary data vector. To
17 * delete an item, set its length to zero.
19 * Return 0 on success, -1 on error, and set errno.
27 unsigned char syslinux_adv
[2*ADV_SIZE
];
29 #define ADV_MAGIC1 0x5a2d2fa5 /* Head signature */
30 #define ADV_MAGIC2 0xa3041767 /* Total checksum */
31 #define ADV_MAGIC3 0xdd28bf64 /* Tail signature */
33 static void cleanup_adv(unsigned char *advbuf
)
38 /* Make sure both copies agree, and update the checksum */
39 set_32(advbuf
, ADV_MAGIC1
);
42 for (i
= 8; i
< ADV_SIZE
-4; i
+= 4)
43 csum
-= get_32(advbuf
+i
);
45 set_32(advbuf
+4, csum
);
46 set_32(advbuf
+ADV_SIZE
-4, ADV_MAGIC3
);
48 memcpy(advbuf
+ADV_SIZE
, advbuf
, ADV_SIZE
);
51 int syslinux_setadv(int tag
, size_t size
, const void *data
)
55 uint8_t advtmp
[ADV_SIZE
];
57 if ((unsigned)tag
-1 > 254) {
59 return -1; /* Impossible tag value */
63 errno
= ENOSPC
; /* Max 255 bytes for a data item */
69 memcpy(p
, syslinux_adv
+2*4, left
); /* Make working copy */
79 /* Found our tag. Delete it. */
82 /* Entire remainder is our tag */
85 memmove(p
, p
+plen
, left
-plen
);
89 break; /* Corrupt tag (overrun) - overwrite it */
96 /* Now (p, left) reflects the position to write in and how much space
97 we have for our data. */
101 errno
= ENOSPC
; /* Not enough space for data */
107 memcpy(p
, data
, size
);
114 /* If we got here, everything went OK, commit the write */
115 memcpy(syslinux_adv
+2*4, advtmp
, ADV_LEN
);
116 cleanup_adv(syslinux_adv
);
121 void syslinux_reset_adv(unsigned char *advbuf
)
123 /* Create an all-zero ADV */
124 memset(advbuf
+2*4, 0, ADV_LEN
);
128 static int adv_consistent(const unsigned char *p
)
133 if (get_32(p
) != ADV_MAGIC1
|| get_32(p
+ADV_SIZE
-4) != ADV_MAGIC3
)
137 for (i
= 4; i
< ADV_SIZE
-4; i
+= 4)
140 return csum
== ADV_MAGIC2
;
144 * Verify that an in-memory ADV is consistent, making the copies consistent.
145 * If neither copy is OK, return -1 and call syslinux_reset_adv().
147 int syslinux_validate_adv(unsigned char *advbuf
)
149 if (adv_consistent(advbuf
+0*ADV_SIZE
)) {
150 memcpy(advbuf
+ADV_SIZE
, advbuf
, ADV_SIZE
);
152 } else if (adv_consistent(advbuf
+1*ADV_SIZE
)) {
153 memcpy(advbuf
, advbuf
+ADV_SIZE
, ADV_SIZE
);
156 syslinux_reset_adv(advbuf
);