1 /* $NetBSD: ustarfs.c,v 1.9 2019/01/09 03:28:31 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 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 #include <lib/libsa/stand.h> 33 #include <lib/libkern/libkern.h> 34 35 #include <sys/param.h> 36 #include <machine/sbd.h> 37 #include <machine/sector.h> 38 39 #include "local.h" 40 #include "common.h" 41 42 static bool __ustarfs_file(int, char *, size_t *); 43 static bool __block_read(uint8_t *, int); 44 static bool __block_read_n(uint8_t *, int, int); 45 static void __change_volume(int); 46 static int __block2volume(int); 47 static int __volume_offset(int); 48 static int __next_block(int); 49 50 enum { USTAR_BLOCK_SIZE = 8192 };/* Check src/distrib/common/buildfloppies.sh */ 51 struct volume { 52 int max_block; 53 int current_volume; 54 } __volume; 55 56 bool 57 ustarfs_load(const char *file, void **addrp, size_t *sizep) 58 { 59 char fname[16]; 60 int block = 16; 61 size_t sz; 62 int maxblk; 63 64 if (DEVICE_CAPABILITY.active_device == NVSRAM_BOOTDEV_HARDDISK) 65 maxblk = 0x1fffffff; /* no limit */ 66 else if (DEVICE_CAPABILITY.active_device == NVSRAM_BOOTDEV_FLOPPYDISK) 67 /* 68 * Although phisical format isn't 2D, volume size is 69 * limited to size of 2D. 70 */ 71 maxblk = (77 + 76) * 13; 72 else { 73 printf("not supported device.\n"); 74 return false; 75 } 76 77 /* Truncate to ustar block boundary */ 78 __volume.max_block = (maxblk / (USTAR_BLOCK_SIZE >> DEV_BSHIFT)) * 79 (USTAR_BLOCK_SIZE >> DEV_BSHIFT); 80 __volume.current_volume = 0; 81 82 /* Find file */ 83 while (/*CONSTCOND*/1) { 84 if (!__ustarfs_file(block, fname, &sz)) 85 return false; 86 87 if (strcmp(file, fname) == 0) 88 break; 89 block += (ROUND_SECTOR(sz) >> DEV_BSHIFT) + 1; 90 } 91 block++; /* skip tar header */ 92 *sizep = sz; 93 94 /* Load file */ 95 sz = ROUND_SECTOR(sz); 96 if ((*addrp = alloc(sz)) == 0) { 97 printf("%s: can't allocate memory.\n", __func__); 98 return false; 99 } 100 101 if (!__block_read_n(*addrp, block, sz >> DEV_BSHIFT)) { 102 printf("%s: can't load file.\n", __func__); 103 dealloc(*addrp, sz); 104 return false; 105 } 106 107 return true; 108 } 109 110 bool 111 __ustarfs_file(int start_block, char *file, size_t *size) 112 { 113 uint8_t buf[512]; 114 115 if (!__block_read(buf, start_block)) { 116 printf("can't read tar header.\n"); 117 return false; 118 } 119 if (((*(uint32_t *)(buf + 256)) & 0xffffff) != 0x757374) { 120 printf("bad tar magic.\n"); 121 return false; 122 } 123 *size = strtoul((char *)buf + 124, 0, 0); 124 strncpy(file, (char *)buf, 16); 125 126 return true; 127 } 128 129 bool 130 __block_read_n(uint8_t *buf, int blk, int count) 131 { 132 int vol, cnt; 133 134 while (count > 0) { 135 vol = __block2volume(blk); 136 if (vol != __volume.current_volume) { 137 __change_volume(vol); 138 __volume.current_volume = vol; 139 } 140 141 cnt = __next_block(vol) - blk; 142 if (cnt > count) 143 cnt = count; 144 145 if (!sector_read_n(0, buf, __volume_offset(blk), cnt)) 146 return false; 147 count -= cnt; 148 blk += cnt; 149 buf += cnt * DEV_BSIZE; 150 } 151 152 return true; 153 } 154 155 bool 156 __block_read(uint8_t *buf, int blk) 157 { 158 int vol; 159 160 vol = __block2volume(blk); 161 162 if (vol != __volume.current_volume) { 163 __change_volume(vol); 164 __volume.current_volume = vol; 165 } 166 167 return sector_read(0, buf, __volume_offset(blk)); 168 } 169 170 void 171 __change_volume(int volume) 172 { 173 uint8_t buf[512]; 174 int i; 175 176 while (/*CONSTCOND*/1) { 177 printf("insert disk %d, and press return...", volume + 1); 178 while (getchar() != '\r') 179 ; 180 printf("\n"); 181 if (!sector_read(0, buf, 0)) 182 continue; 183 if (*(uint32_t *)buf != 0x55535441) { /* "USTAR" */ 184 printf("invalid magic.\n"); 185 continue; 186 } 187 if ((i = buf[8] - '0') != volume + 1) { 188 printf("invalid volume number. disk=%d requested=%d\n", 189 i, volume + 1); 190 continue; 191 } 192 return; 193 } 194 } 195 196 int 197 __block2volume(int blk) 198 { 199 200 if (blk < __volume.max_block) 201 return 0; 202 203 blk -= __volume.max_block; 204 205 return (blk / (__volume.max_block - 16)) + 1; 206 } 207 208 int 209 __volume_offset(int blk) 210 { 211 212 if (blk < __volume.max_block) 213 return blk; 214 215 blk -= __volume.max_block; 216 217 return blk % (__volume.max_block - 16) + 16; 218 } 219 220 int 221 __next_block(int vol) 222 { 223 224 return __volume.max_block + vol * (__volume.max_block - 16); 225 } 226