1 /* map.c - Map file creation
3 * Copyright 1992-1998 Werner Almesberger
4 * Copyright 1999-2005 John Coffman
5 * Copyright 2009-2011 Joachim Wiedorn
8 * Licensed under the terms contained in the file 'COPYING'
9 * in the source directory.
24 #endif /* !__MSDOS__ */
28 typedef struct _map_entry {
30 struct _map_entry *next;
34 static MAP_ENTRY *map,*last;
35 static SECTOR_ADDR zero_addr;
37 #endif /* !__MSDOS__ */
39 void map_patch_first(char *name,char *str)
46 if (strlen(str) >= SECTOR_SIZE-2)
47 die("map_patch_first: String is too long");
48 if ((fd = open(name,O_RDWR)) < 0) die("open %s: %s",name,strerror(errno));
49 if (lseek(fd,(off_t)SECTOR_SIZE,SEEK_SET) < 0) die("lseek %s: %s",name,strerror(errno));
50 if (read(fd,(char *) &descrs,sizeof(descrs)) != sizeof(descrs))
51 die("read %s: %s",name,strerror(errno));
52 for (start = str; *start && *start == ' '; start++);
54 for (end = start; *end && *end != ' '; end++);
57 for (image = 0; image < MAX_IMAGES; image++)
59 if (!strcasecmp(descrs.d.descr[image].name,start)) break;
61 if (!strcmp(descrs.d.descr[image].name,start)) break;
63 if (image == MAX_IMAGES) die("No image \"%s\" is defined",start);
66 if (lseek(fd,(off_t)0,SEEK_SET) < 0) die("lseek %s: %s",name,strerror(errno));
67 magic = *str ? DC_MAGIC : 0;
68 if ((size = write(fd,(char *) &magic,2)) < 0)
69 die("write %s: %s",name,strerror(errno));
70 if (size != 2) die("map_patch_first: Bad write ?!?");
71 if ((size = write(fd,str,strlen(str)+1)) < 0)
72 die("write %s: %s",name,strerror(errno));
73 if (size != strlen(str)+1) die("map_patch_first: Bad write ?!?");
74 if (close(fd) < 0) die("close %s: %s",name,strerror(errno));
79 static GEOMETRY map_geo;
81 void map_create(char *name)
83 char buffer[SECTOR_SIZE];
86 if ((fd = creat(name,0600)) < 0) die("creat %s: %s",name,strerror(errno));
88 memset(buffer,0,SECTOR_SIZE);
89 *(unsigned short *) buffer = DC_MGOFF;
90 map_file = geo_open(&map_geo,name,O_RDWR);
91 bios_map = map_geo.device; /* set device code of map file */
94 if(fstat(map_file,&st)) die("map_create: cannot fstat map file");
96 printf("map_create: boot=%04X map=%04X\n",
97 boot_dev_nr, (int)st.st_dev);
98 if (boot_dev_nr != st.st_dev && extra != X_MBR_ONLY) {
99 die("map file must be on the boot RAID partition");
103 /* write default command line, descriptor table, zero sector */
105 for (i=0; i<MAX_DESCR_SECS+2; i++) {
106 if (write(map_file,buffer,SECTOR_SIZE) != SECTOR_SIZE)
107 die("write %s: %s",name,strerror(errno));
108 *(unsigned short *) buffer = 0;
110 if (!geo_comp_addr(&map_geo,SECTOR_SIZE*(MAX_DESCR_SECS+1),&zero_addr))
111 die("Hole found in map file (zero sector)");
115 void map_descrs(DESCR_SECTORS *descr, SECTOR_ADDR* addr, SECTOR_ADDR* dflcmd)
122 crc32(descr->sector, sizeof((*descr).l.sector), CRC_POLY1);
124 last = lseek(map_file, 0L, SEEK_END); /* save final position */
126 if (lseek(map_file, pos, SEEK_SET) < 0) pdie("lseek map file");
127 if (write(map_file,(char *) descr, SECTOR_SIZE*MAX_DESCR_SECS) != SECTOR_SIZE*MAX_DESCR_SECS)
128 pdie("write map file");
130 for (i=0; i<MAX_DESCR_SECS; i++) {
131 if (!geo_comp_addr(&map_geo,pos,addr))
132 die("Hole found in map file (descr. sector %d)", i);
137 if (!geo_comp_addr(&map_geo,0,dflcmd))
138 die("Hole found in map file (default command line)");
141 if (fstat(map_file,&st) < 0) pdie("fstat map file");
142 printf("Map file size: %d bytes.\n",(int) st.st_size);
144 if (last!=lseek(map_file, last, SEEK_SET)) pdie("lseek map file to end");
148 void map_close(BOOT_PARAMS_2 *param2, off_t here)
151 if (lseek(map_file, here, SEEK_SET) != here)
152 die("map_close: lseek");
153 if (write(map_file,(void*)param2,sizeof(BOOT_PARAMS_2))!=sizeof(BOOT_PARAMS_2))
154 die("map_close: write");
160 void map_register(SECTOR_ADDR *addr)
164 new = alloc_t(MAP_ENTRY);
167 if (last) last->next = new;
173 void map_add_sector(void *sector)
178 if ((here = lseek(map_file,0L,SEEK_CUR)) < 0) pdie("lseek map file");
179 if (write(map_file,sector,SECTOR_SIZE) != SECTOR_SIZE)
180 pdie("write map file");
181 if (!geo_comp_addr(&map_geo,here,&addr))
182 die("Hole found in map file (app. sector)");
187 void map_begin_section(void)
193 void map_add(GEOMETRY *geo,int from,int num_sect)
198 for (count = 0; count < num_sect; count++) {
199 if (geo_comp_addr(geo,SECTOR_SIZE*(count+from),&addr))
202 map_register(&zero_addr);
203 if (verbose > 3) printf("Covering hole at sector %d.\n",count);
209 void map_add_zero(void)
211 map_register(&zero_addr);
215 static void map_compact(int dont_compact)
217 MAP_ENTRY *walk,*next;
218 int count, removed, offset, adj, hinib, noffset, maxcount;
222 maxcount = lba32 ? 127 : 128; /* JRC: max LBA transfer is 127 sectors,
223 per the EDD spec, v1.1, not 128 (unfortunately) */
224 /* JRC: for testing the hinib save: */
226 maxcount = lba32 ? 3 : maxcount;
229 for (count = 0; walk && count < dont_compact; count++) walk = walk->next;
232 while (walk && walk->next) {
233 adj = ((walk->addr.device ^ walk->next->addr.device) & ~LBA32_NOCOUNT) == 0;
234 if (adj && (walk->addr.device & LBA32_FLAG)) {
235 if ((walk->addr.device & LBA32_NOCOUNT)==0) {
236 if ( (adj = (hinib==walk->next->addr.num_sect)) ) {
237 walk->next->addr.num_sect = 1;
238 walk->next->addr.device &= ~LBA32_NOCOUNT;
243 hinib = walk->addr.num_sect;
244 if ((walk->next->addr.device&LBA32_NOCOUNT) &&
245 (walk->next->addr.num_sect == hinib)) {
246 walk->next->addr.num_sect = 1;
247 walk->next->addr.device &= ~LBA32_NOCOUNT;
251 if (adj && walk->addr.device & (LINEAR_FLAG|LBA32_FLAG))
252 adj = ((walk->addr.head << 16) | (walk->addr.track << 8) |
253 walk->addr.sector)+walk->addr.num_sect == ((walk->next->addr.head
254 << 16) | (walk->next->addr.track << 8) | walk->next->addr.sector);
255 else adj = adj && walk->addr.track == walk->next->addr.track &&
256 walk->addr.head == walk->next->addr.head &&
257 walk->addr.sector+walk->addr.num_sect == walk->next->addr.sector;
258 noffset += SECTOR_SIZE;
259 adj = adj && (offset>>16 == noffset>>16) &&
260 (walk->addr.num_sect < maxcount);
266 walk->addr.num_sect++;
267 next = walk->next->next;
274 printf("Compaction removed %d BIOS call%s.\n",removed,removed == 1 ?
279 static void map_alloc_page(int offset,SECTOR_ADDR *addr)
283 if ((here = lseek(map_file,offset,SEEK_CUR)) < 0) pdie("lseek map file");
284 if (write(map_file,"",1) != 1) pdie("write map file");
285 if (fdatasync(map_file)) pdie("fdatasync map file");
286 if (!geo_comp_addr(&map_geo,here,addr))
287 die("Hole found in map file (alloc_page)");
288 if (lseek(map_file,-offset-1,SEEK_CUR) < 0) pdie("lseek map file");
292 int map_end_section(SECTOR_ADDR *addr,int dont_compact)
294 int first,offset,sectors;
295 char buffer[SECTOR_SIZE];
296 MAP_ENTRY *walk,*next;
300 memset(buffer,0,SECTOR_SIZE);
301 offset = sectors = 0;
302 if (compact) map_compact(dont_compact);
303 if (!map) die("Empty map section");
305 for (walk = map; walk; walk = next) {
308 if ((walk->addr.device&LBA32_FLAG) && (walk->addr.device&LBA32_NOCOUNT)) hinib = walk->addr.num_sect;
309 printf(" Mapped AL=0x%02x CX=0x%04x DX=0x%04x",walk->addr.num_sect,
310 (walk->addr.track << 8) | walk->addr.sector,(walk->addr.head << 8)
311 | walk->addr.device);
314 lba32 ? "LBA" : "linear",
315 (walk->addr.head << 16) | (walk->addr.track << 8) | walk->addr.sector | hinib<<24);
320 map_alloc_page(0,addr);
322 if (offset+sizeof(SECTOR_ADDR)*2 > SECTOR_SIZE) {
323 map_alloc_page(SECTOR_SIZE,(SECTOR_ADDR *) (buffer+offset));
324 if (write(map_file,buffer,SECTOR_SIZE) != SECTOR_SIZE)
325 pdie("write map file");
326 memset(buffer,0,SECTOR_SIZE);
329 memcpy(buffer+offset,&walk->addr,sizeof(SECTOR_ADDR));
330 offset += sizeof(SECTOR_ADDR);
331 sectors += (walk->addr.device&LBA32_FLAG) && (walk->addr.device&LBA32_NOCOUNT)
332 ? 1 : walk->addr.num_sect;
336 if (write(map_file,buffer,SECTOR_SIZE) != SECTOR_SIZE)
337 pdie("write map file");
342 static int sa6_from_sa(SECTOR_ADDR6 *sa6, SECTOR_ADDR *sa)
344 static unsigned char hinib = 0;
349 sa6->device = sa->device & DEV_MASK;
350 flags = sa6->flags = sa->device & ~DEV_MASK;
351 count = sa->num_sect;
353 if ((flags & (LBA32_FLAG|LINEAR_FLAG)) == 0) {
354 /* pure geometric addressing */
355 sector = *(unsigned int*)&(sa->sector);
358 if (flags & LBA32_FLAG) {
359 /* pure lba32 addressing */
360 if (flags & LBA32_NOCOUNT) {
365 } /* linear addressing */
368 sector = ((sector<<8 | sa->head)<<8 | sa->track)<<8 | sa->sector;
370 sa6->sector = sector;
379 int map_write(SECTOR_ADDR *list,int max_len,int terminate,int sa6)
381 int map_write(SECTOR_ADDR *list,int max_len,int terminate)
384 MAP_ENTRY *walk,*next;
387 SECTOR_ADDR6 sa6tem, *list6 = (void*)list;
388 unsigned int *list4 = (void*)list;
392 for (walk = map; walk; walk = next) {
394 if (--max_len < (terminate ? 1 : 0)) die("Map segment is too big.");
397 (void)sa6_from_sa(&sa6tem, &(walk->addr));
398 if (sa6==2) *list4++ = sa6tem.sector;
399 else *list6++ = sa6tem;
403 *list++ = walk->addr;
411 if (sa6==2) *list4 = 0;
412 else if (sa6) memset(list6, 0, sizeof(SECTOR_ADDR6));
415 memset(list,0,sizeof(SECTOR_ADDR));
422 off_t map_insert_file(GEOMETRY *geo, int skip, int sectors)
426 char buff[SECTOR_SIZE];
428 if (verbose>0) printf("Calling map_insert_file\n");
429 if (lseek(geo->fd, (off_t)skip*SECTOR_SIZE, SEEK_SET)<0)
430 pdie("map_insert_file: file seek");
431 here = lseek(map_file, 0, SEEK_CUR);
433 for (i=0; i<sectors; i++) {
434 count = read(geo->fd, buff, SECTOR_SIZE);
435 if (count<0) pdie("map_insert_file: file read");
436 if (count<SECTOR_SIZE) memset(buff+count, 0, SECTOR_SIZE-count);
437 count = write(map_file, buff, SECTOR_SIZE);
438 if (count<=0) pdie("map_insert_file: map write");
441 if ((here % SECTOR_SIZE) != 0) die("Map file positioning error");
442 map_add(&map_geo, here/SECTOR_SIZE, sectors);
447 off_t map_insert_data(unsigned char *data, int size)
450 int count, sectors = 0;
451 char buff[SECTOR_SIZE];
453 if (verbose>0) printf("Calling map_insert_data\n");
454 here = lseek(map_file, 0, SEEK_CUR);
457 if (size>SECTOR_SIZE) count=SECTOR_SIZE;
460 memcpy(buff, data, count);
465 if (count<SECTOR_SIZE) memset(buff+count, 0, SECTOR_SIZE-count);
467 count = write(map_file, buff, SECTOR_SIZE);
468 if (count<=0) pdie("map_insert_data: map write");
471 if ((here % SECTOR_SIZE) != 0) die("Map file positioning error");
472 map_add(&map_geo, here/SECTOR_SIZE, sectors);
477 #endif /* !__MSDOS__ */