1 /* $NetBSD: md.c,v 1.2 2014/08/03 16:09:39 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 if (get_ramsize() <= 32) 252 set_swap(pm->diskdev, pm->bsdlabel); 253 254 return 0; 255 } 256 257 /* 258 * hook called after upgrade() or install() has finished setting 259 * up the target disk but immediately before the user is given the 260 * ``disks are now set up'' message. 261 */ 262 int 263 md_post_newfs(void) 264 { 265 static const char *kernels[] = { 266 "vmlinux-nfsroot.gz", 267 "vmlinux.gz", 268 "vmlinux_RAQ.gz", 269 "vmlinux_raq-2800.gz" 270 }; 271 static const char *bootfile = "boot.gz"; 272 char bootdir[64]; 273 unsigned int i; 274 275 if (!nobootfs) { 276 msg_display(msg_string(MSG_copybootloader), pm->diskdev); 277 278 snprintf(bootdir, sizeof(bootdir), "%s/boot", 279 target_expand(PART_BOOT_EXT2FS_PI_MOUNT)); 280 run_program(0, "/bin/mkdir -p %s", bootdir); 281 run_program(0, "/bin/cp /usr/mdec/boot %s", bootdir); 282 run_program(0, "/bin/rm -f %s/%s", bootdir, bootfile); 283 run_program(0, "/usr/bin/gzip -9 %s/boot", bootdir); 284 for (i = 0; i < __arraycount(kernels); i++) 285 run_program(0, "/bin/ln -fs %s %s/%s", 286 bootfile, bootdir, kernels[i]); 287 } 288 289 return 0; 290 } 291 292 int 293 md_post_extract(void) 294 { 295 return 0; 296 } 297 298 void 299 md_cleanup_install(void) 300 { 301 #ifndef DEBUG 302 enable_rc_conf(); 303 #endif 304 } 305 306 int 307 md_pre_update(void) 308 { 309 struct mbr_partition *part; 310 mbr_info_t *ext; 311 int i; 312 313 if (get_ramsize() <= 32) 314 set_swap(pm->diskdev, NULL); 315 316 read_mbr(pm->diskdev, &mbr); 317 /* do a sanity check of the partition table */ 318 for (ext = &mbr; ext; ext = ext->extended) { 319 part = ext->mbr.mbr_parts; 320 for (i = 0; i < MBR_PART_COUNT; part++, i++) { 321 if (part->mbrp_type != MBR_PTYPE_LNXEXT2) 322 continue; 323 if (part->mbrp_size < (MIN_EXT2FS_BOOT / 512)) { 324 msg_display(MSG_boottoosmall); 325 msg_display_add(MSG_nobootpart, 0); 326 process_menu(MENU_yesno, NULL); 327 if (!yesno) 328 return 0; 329 nobootfs = 1; 330 } 331 } 332 } 333 if (md_check_partitions() == 0) 334 nobootfs = 1; 335 return 1; 336 } 337 338 /* Upgrade support */ 339 int 340 md_update(void) 341 { 342 md_post_newfs(); 343 return 1; 344 } 345 346 int 347 md_check_mbr(mbr_info_t *mbri) 348 { 349 mbr_info_t *ext; 350 struct mbr_partition *part; 351 int i; 352 353 for (ext = mbri; ext; ext = ext->extended) { 354 part = ext->mbr.mbr_parts; 355 for (i = 0; i < MBR_PART_COUNT; part++, i++) { 356 if (part->mbrp_type == MBR_PTYPE_LNXEXT2) { 357 pm->bootstart = part->mbrp_start; 358 pm->bootsize = part->mbrp_size; 359 break; 360 } 361 } 362 } 363 if (pm->bootsize < (MIN_EXT2FS_BOOT / 512)) { 364 msg_display(MSG_boottoosmall); 365 msg_display_add(MSG_reeditpart, 0); 366 process_menu(MENU_yesno, NULL); 367 if (!yesno) 368 return 0; 369 return 1; 370 } 371 if (pm->bootstart == 0 || pm->bootsize == 0) { 372 msg_display(MSG_nobootpart); 373 msg_display_add(MSG_reeditpart, 0); 374 process_menu(MENU_yesno, NULL); 375 if (!yesno) 376 return 0; 377 return 1; 378 } 379 return 2; 380 } 381 382 int 383 md_mbr_use_wholedisk(mbr_info_t *mbri) 384 { 385 struct mbr_sector *mbrs = &mbri->mbr; 386 mbr_info_t *ext; 387 struct mbr_partition *part; 388 389 part = &mbrs->mbr_parts[0]; 390 /* Set the partition information for full disk usage. */ 391 while ((ext = mbri->extended)) { 392 mbri->extended = ext->extended; 393 free(ext); 394 } 395 memset(part, 0, MBR_PART_COUNT * sizeof *part); 396 #ifdef BOOTSEL 397 memset(&mbri->mbrb, 0, sizeof mbri->mbrb); 398 #endif 399 part[0].mbrp_type = MBR_PTYPE_LNXEXT2; 400 part[0].mbrp_size = EXT2FS_BOOT_SIZE / 512; 401 part[0].mbrp_start = bsec; 402 part[0].mbrp_flag = MBR_PFLAG_ACTIVE; 403 404 part[1].mbrp_type = MBR_PTYPE_NETBSD; 405 part[1].mbrp_size = pm->dlsize - (bsec + EXT2FS_BOOT_SIZE / 512); 406 part[1].mbrp_start = bsec + EXT2FS_BOOT_SIZE / 512; 407 part[1].mbrp_flag = 0; 408 409 pm->ptstart = part[1].mbrp_start; 410 pm->ptsize = part[1].mbrp_size; 411 pm->bootstart = part[0].mbrp_start; 412 pm->bootsize = part[0].mbrp_size; 413 return 1; 414 } 415 416 int 417 md_pre_mount() 418 { 419 return 0; 420 } 421