1 /* $NetBSD: md.c,v 1.4 2015/05/10 10:14:02 martin Exp $ */ 2 3 /* 4 * Copyright 1997 Piermont Information Systems Inc. 5 * All rights reserved. 6 * 7 * Based on code written by Philip A. Nelson for Piermont Information 8 * Systems Inc. 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 * 3. The name of Piermont Information Systems Inc. may not be used to endorse 19 * or promote products derived from this software without specific prior 20 * written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* md.c -- cobalt machine specific routines */ 36 37 #include <sys/param.h> 38 #include <sys/sysctl.h> 39 #include <stdio.h> 40 #include <util.h> 41 #include <machine/cpu.h> 42 43 #include "defs.h" 44 #include "md.h" 45 #include "msg_defs.h" 46 #include "menu_defs.h" 47 48 /* 49 * Firmware reognizes only Linux Ext2 REV 0, so we have to have 50 * a Linux Ext2 fs to store our native bootloader. 51 */ 52 static int nobootfs = 0; 53 static int bootpart_ext2fs = PART_BOOT_EXT2FS; 54 55 void 56 md_init(void) 57 { 58 } 59 60 void 61 md_init_set_status(int flags) 62 { 63 (void)flags; 64 } 65 66 int 67 md_get_info(void) 68 { 69 return set_bios_geom_with_mbr_guess(); 70 } 71 72 /* 73 * md back-end code for menu-driven BSD disklabel editor. 74 */ 75 int 76 md_make_bsd_partitions(void) 77 { 78 int i; 79 int part; 80 int maxpart = getmaxpartitions(); 81 int partstart; 82 int part_raw, part_bsd; 83 int ptend; 84 int no_swap = 0; 85 partinfo *p; 86 87 /* 88 * Initialize global variables that track space used on this disk. 89 * Standard 4.4BSD 8-partition labels always cover whole disk. 90 */ 91 if (pm->ptsize == 0) 92 pm->ptsize = pm->dlsize - pm->ptstart; 93 if (pm->dlsize == 0) 94 pm->dlsize = pm->ptstart + pm->ptsize; 95 96 partstart = pm->ptstart; 97 ptend = pm->ptstart + pm->ptsize; 98 99 /* Ask for layout type -- standard or special */ 100 msg_display(MSG_layout, 101 pm->ptsize / (MEG / pm->sectorsize), 102 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE, 103 DEFROOTSIZE + DEFSWAPSIZE + DEFUSRSIZE + XNEEDMB); 104 105 process_menu(MENU_layout, NULL); 106 107 /* Set so we use the 'real' geometry for rounding, input in MB */ 108 pm->current_cylsize = pm->dlcylsize; 109 set_sizemultname_meg(); 110 111 /* Build standard partitions */ 112 memset(&pm->bsdlabel, 0, sizeof pm->bsdlabel); 113 114 /* Set initial partition types to unused */ 115 for (part = 0 ; part < maxpart ; ++part) 116 pm->bsdlabel[part].pi_fstype = FS_UNUSED; 117 118 /* Whole disk partition */ 119 part_raw = getrawpartition(); 120 if (part_raw == -1) 121 part_raw = PART_C; /* for sanity... */ 122 pm->bsdlabel[part_raw].pi_offset = 0; 123 pm->bsdlabel[part_raw].pi_size = pm->dlsize; 124 125 if (part_raw == PART_D) { 126 /* Probably a system that expects an i386 style mbr */ 127 part_bsd = PART_C; 128 pm->bsdlabel[PART_C].pi_offset = pm->ptstart; 129 pm->bsdlabel[PART_C].pi_size = pm->ptsize; 130 } else { 131 part_bsd = part_raw; 132 } 133 134 if (pm->bootsize != 0) { 135 pm->bsdlabel[PART_BOOT_EXT2FS].pi_fstype = FS_EX2FS; 136 pm->bsdlabel[PART_BOOT_EXT2FS].pi_size = pm->bootsize; 137 pm->bsdlabel[PART_BOOT_EXT2FS].pi_offset = pm->bootstart; 138 pm->bsdlabel[PART_BOOT_EXT2FS].pi_flags |= 139 PART_BOOT_EXT2FS_PI_FLAGS; 140 strlcpy(pm->bsdlabel[PART_BOOT_EXT2FS].pi_mount, 141 PART_BOOT_EXT2FS_PI_MOUNT, 142 sizeof pm->bsdlabel[PART_BOOT_EXT2FS].pi_mount); 143 } 144 145 #ifdef PART_REST 146 pm->bsdlabel[PART_REST].pi_offset = 0; 147 pm->bsdlabel[PART_REST].pi_size = pm->ptstart; 148 #endif 149 150 /* 151 * Save any partitions that are outside the area we are 152 * going to use. 153 * In particular this saves details of the other MBR 154 * partitions on a multiboot i386 system. 155 */ 156 for (i = maxpart; i--;) { 157 if (pm->bsdlabel[i].pi_size != 0) 158 /* Don't overwrite special partitions */ 159 continue; 160 p = &pm->oldlabel[i]; 161 if (p->pi_fstype == FS_UNUSED || p->pi_size == 0) 162 continue; 163 if (layoutkind == LY_USEEXIST) { 164 if (PI_ISBSDFS(p)) 165 p->pi_flags |= PIF_MOUNT; 166 } else { 167 if (p->pi_offset < pm->ptstart + pm->ptsize && 168 p->pi_offset + p->pi_size > pm->ptstart) 169 /* Not outside area we are allocating */ 170 continue; 171 if (p->pi_fstype == FS_SWAP) 172 no_swap = 1; 173 } 174 pm->bsdlabel[i] = pm->oldlabel[i]; 175 } 176 177 if (layoutkind == LY_USEEXIST) { 178 /* XXX Check we have a sensible layout */ 179 ; 180 } else 181 get_ptn_sizes(partstart, ptend - partstart, no_swap); 182 183 /* 184 * OK, we have a partition table. Give the user the chance to 185 * edit it and verify it's OK, or abort altogether. 186 */ 187 edit_check: 188 if (edit_and_check_label(pm->bsdlabel, maxpart, part_raw, part_bsd) == 0) { 189 msg_display(MSG_abort); 190 return 0; 191 } 192 if (md_check_partitions() == 0) 193 goto edit_check; 194 195 /* Disk name */ 196 msg_prompt(MSG_packname, pm->bsddiskname, pm->bsddiskname, sizeof pm->bsddiskname); 197 198 /* save label to disk for MI code to update. */ 199 (void)savenewlabel(pm->bsdlabel, maxpart); 200 201 /* Everything looks OK. */ 202 return 1; 203 } 204 205 /* 206 * any additional partition validation 207 */ 208 int 209 md_check_partitions(void) 210 { 211 int part; 212 213 /* we need to find a boot partition, otherwise we can't write our 214 * bootloader. We make the assumption that the user hasn't done 215 * something stupid, like move it away from the MBR partition. 216 */ 217 for (part = PART_A; part < MAXPARTITIONS; part++) 218 if (pm->bsdlabel[part].pi_fstype == FS_EX2FS) { 219 bootpart_ext2fs = part; 220 return 1; 221 } 222 223 msg_display(MSG_nobootpartdisklabel); 224 process_menu(MENU_ok, NULL); 225 return 0; 226 } 227 228 /* 229 * hook called before writing new disklabel. 230 */ 231 int 232 md_pre_disklabel(void) 233 { 234 msg_display(MSG_dofdisk); 235 236 /* write edited MBR onto disk. */ 237 if (write_mbr(pm->diskdev, &mbr, 1) != 0) { 238 msg_display(MSG_wmbrfail); 239 process_menu(MENU_ok, NULL); 240 return 1; 241 } 242 return 0; 243 } 244 245 /* 246 * hook called after writing disklabel to new target disk. 247 */ 248 int 249 md_post_disklabel(void) 250 { 251 return 0; 252 } 253 254 /* 255 * hook called after upgrade() or install() has finished setting 256 * up the target disk but immediately before the user is given the 257 * ``disks are now set up'' message. 258 */ 259 int 260 md_post_newfs(void) 261 { 262 static const char *kernels[] = { 263 "vmlinux-nfsroot.gz", 264 "vmlinux.gz", 265 "vmlinux_RAQ.gz", 266 "vmlinux_raq-2800.gz" 267 }; 268 static const char *bootfile = "boot.gz"; 269 char bootdir[64]; 270 unsigned int i; 271 272 if (!nobootfs) { 273 msg_display(msg_string(MSG_copybootloader), pm->diskdev); 274 275 snprintf(bootdir, sizeof(bootdir), "%s/boot", 276 target_expand(PART_BOOT_EXT2FS_PI_MOUNT)); 277 run_program(0, "/bin/mkdir -p %s", bootdir); 278 run_program(0, "/bin/cp /usr/mdec/boot %s", bootdir); 279 run_program(0, "/bin/rm -f %s/%s", bootdir, bootfile); 280 run_program(0, "/usr/bin/gzip -9 %s/boot", bootdir); 281 for (i = 0; i < __arraycount(kernels); i++) 282 run_program(0, "/bin/ln -fs %s %s/%s", 283 bootfile, bootdir, kernels[i]); 284 } 285 286 return 0; 287 } 288 289 int 290 md_post_extract(void) 291 { 292 return 0; 293 } 294 295 void 296 md_cleanup_install(void) 297 { 298 #ifndef DEBUG 299 enable_rc_conf(); 300 #endif 301 } 302 303 int 304 md_pre_update(void) 305 { 306 struct mbr_partition *part; 307 mbr_info_t *ext; 308 int i; 309 310 read_mbr(pm->diskdev, &mbr); 311 /* do a sanity check of the partition table */ 312 for (ext = &mbr; ext; ext = ext->extended) { 313 part = ext->mbr.mbr_parts; 314 for (i = 0; i < MBR_PART_COUNT; part++, i++) { 315 if (part->mbrp_type != MBR_PTYPE_LNXEXT2) 316 continue; 317 if (part->mbrp_size < (MIN_EXT2FS_BOOT / 512)) { 318 msg_display(MSG_boottoosmall); 319 msg_display_add(MSG_nobootpart, 0); 320 if (!ask_yesno(NULL)) 321 return 0; 322 nobootfs = 1; 323 } 324 } 325 } 326 if (md_check_partitions() == 0) 327 nobootfs = 1; 328 return 1; 329 } 330 331 /* Upgrade support */ 332 int 333 md_update(void) 334 { 335 md_post_newfs(); 336 return 1; 337 } 338 339 int 340 md_check_mbr(mbr_info_t *mbri) 341 { 342 mbr_info_t *ext; 343 struct mbr_partition *part; 344 int i; 345 346 for (ext = mbri; ext; ext = ext->extended) { 347 part = ext->mbr.mbr_parts; 348 for (i = 0; i < MBR_PART_COUNT; part++, i++) { 349 if (part->mbrp_type == MBR_PTYPE_LNXEXT2) { 350 pm->bootstart = part->mbrp_start; 351 pm->bootsize = part->mbrp_size; 352 break; 353 } 354 } 355 } 356 if (pm->bootsize < (MIN_EXT2FS_BOOT / 512)) { 357 msg_display(MSG_boottoosmall); 358 msg_display_add(MSG_reeditpart, 0); 359 if (!ask_yesno(NULL)) 360 return 0; 361 return 1; 362 } 363 if (pm->bootstart == 0 || pm->bootsize == 0) { 364 msg_display(MSG_nobootpart); 365 msg_display_add(MSG_reeditpart, 0); 366 if (!ask_yesno(NULL)) 367 return 0; 368 return 1; 369 } 370 return 2; 371 } 372 373 int 374 md_mbr_use_wholedisk(mbr_info_t *mbri) 375 { 376 struct mbr_sector *mbrs = &mbri->mbr; 377 mbr_info_t *ext; 378 struct mbr_partition *part; 379 380 part = &mbrs->mbr_parts[0]; 381 /* Set the partition information for full disk usage. */ 382 while ((ext = mbri->extended)) { 383 mbri->extended = ext->extended; 384 free(ext); 385 } 386 memset(part, 0, MBR_PART_COUNT * sizeof *part); 387 #ifdef BOOTSEL 388 memset(&mbri->mbrb, 0, sizeof mbri->mbrb); 389 #endif 390 part[0].mbrp_type = MBR_PTYPE_LNXEXT2; 391 part[0].mbrp_size = EXT2FS_BOOT_SIZE / 512; 392 part[0].mbrp_start = bsec; 393 part[0].mbrp_flag = MBR_PFLAG_ACTIVE; 394 395 part[1].mbrp_type = MBR_PTYPE_NETBSD; 396 part[1].mbrp_size = pm->dlsize - (bsec + EXT2FS_BOOT_SIZE / 512); 397 part[1].mbrp_start = bsec + EXT2FS_BOOT_SIZE / 512; 398 part[1].mbrp_flag = 0; 399 400 pm->ptstart = part[1].mbrp_start; 401 pm->ptsize = part[1].mbrp_size; 402 pm->bootstart = part[0].mbrp_start; 403 pm->bootsize = part[0].mbrp_size; 404 return 1; 405 } 406 407 int 408 md_pre_mount() 409 { 410 return 0; 411 } 412