1 1.23 andvar /* $NetBSD: md.c,v 1.23 2025/02/24 21:32:26 andvar Exp $ */ 2 1.1 dholland 3 1.1 dholland /* 4 1.1 dholland * Copyright 1997 Piermont Information Systems Inc. 5 1.1 dholland * All rights reserved. 6 1.1 dholland * 7 1.1 dholland * Based on code written by Philip A. Nelson for Piermont Information 8 1.1 dholland * Systems Inc. 9 1.1 dholland * 10 1.1 dholland * Redistribution and use in source and binary forms, with or without 11 1.1 dholland * modification, are permitted provided that the following conditions 12 1.1 dholland * are met: 13 1.1 dholland * 1. Redistributions of source code must retain the above copyright 14 1.1 dholland * notice, this list of conditions and the following disclaimer. 15 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 dholland * notice, this list of conditions and the following disclaimer in the 17 1.1 dholland * documentation and/or other materials provided with the distribution. 18 1.1 dholland * 3. The name of Piermont Information Systems Inc. may not be used to endorse 19 1.1 dholland * or promote products derived from this software without specific prior 20 1.1 dholland * written permission. 21 1.1 dholland * 22 1.1 dholland * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS'' 23 1.1 dholland * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE 26 1.1 dholland * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 1.1 dholland * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 1.1 dholland * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 1.1 dholland * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 1.1 dholland * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 1.1 dholland * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 1.1 dholland * THE POSSIBILITY OF SUCH DAMAGE. 33 1.1 dholland */ 34 1.1 dholland 35 1.1 dholland /* md.c -- shark machine specific routines */ 36 1.1 dholland 37 1.1 dholland #include <stdio.h> 38 1.1 dholland #include <curses.h> 39 1.1 dholland #include <unistd.h> 40 1.1 dholland #include <fcntl.h> 41 1.1 dholland #include <util.h> 42 1.1 dholland #include <sys/types.h> 43 1.1 dholland #include <sys/ioctl.h> 44 1.1 dholland #include <sys/param.h> 45 1.12 martin #include <sys/sysctl.h> 46 1.1 dholland 47 1.1 dholland #include "defs.h" 48 1.1 dholland #include "md.h" 49 1.1 dholland #include "msg_defs.h" 50 1.1 dholland #include "menu_defs.h" 51 1.1 dholland 52 1.10 martin int boardtype = BOARD_TYPE_NORMAL; 53 1.1 dholland 54 1.12 martin #define SBSA_MODEL_STR "netbsd,generic-acpi" 55 1.12 martin #define RPI_MODEL_STR "raspberrypi," 56 1.12 martin 57 1.1 dholland void 58 1.10 martin md_init(void) 59 1.1 dholland { 60 1.12 martin static const int mib[2] = {CTL_HW, HW_MODEL}; 61 1.12 martin size_t len; 62 1.12 martin char *cpu_model; 63 1.12 martin 64 1.12 martin sysctl(mib, 2, NULL, &len, NULL, 0); 65 1.12 martin cpu_model = malloc(len); 66 1.12 martin sysctl(mib, 2, cpu_model, &len, NULL, 0); 67 1.12 martin 68 1.12 martin if (strstr(cpu_model, RPI_MODEL_STR) != NULL) 69 1.12 martin /* this is some kind of Raspberry Pi */ 70 1.12 martin boardtype = BOARD_TYPE_RPI; 71 1.12 martin else if (strstr(cpu_model, SBSA_MODEL_STR) != NULL) 72 1.12 martin /* some SBSA compatible machine */ 73 1.12 martin boardtype = BOARD_TYPE_ACPI; 74 1.12 martin else 75 1.12 martin /* unknown, assume u-boot + dtb */ 76 1.12 martin boardtype = BOARD_TYPE_NORMAL; 77 1.1 dholland 78 1.12 martin free(cpu_model); 79 1.1 dholland } 80 1.1 dholland 81 1.1 dholland void 82 1.1 dholland md_init_set_status(int flags) 83 1.1 dholland { 84 1.13 martin 85 1.13 martin /* 86 1.16 jmcneill * we will extract kernel variants piecewise manually 87 1.16 jmcneill * later, just fetch the kernel set, do not unpack it. 88 1.13 martin */ 89 1.20 jmcneill set_kernel_set(SET_KERNEL_1); 90 1.13 martin set_noextract_set(SET_KERNEL_1); 91 1.1 dholland } 92 1.1 dholland 93 1.6 martin bool 94 1.6 martin md_get_info(struct install_partition_desc *install) 95 1.1 dholland { 96 1.17 martin int res; 97 1.1 dholland 98 1.7 martin if (pm->no_mbr || pm->no_part) 99 1.7 martin return true; 100 1.7 martin 101 1.17 martin again: 102 1.7 martin if (pm->parts == NULL) { 103 1.7 martin 104 1.7 martin const struct disk_partitioning_scheme *ps = 105 1.7 martin select_part_scheme(pm, NULL, true, NULL); 106 1.7 martin 107 1.7 martin if (!ps) 108 1.9 martin return false; 109 1.7 martin 110 1.7 martin struct disk_partitions *parts = 111 1.7 martin (*ps->create_new_for_disk)(pm->diskdev, 112 1.14 martin 0, pm->dlsize, true, NULL); 113 1.7 martin if (!parts) 114 1.7 martin return false; 115 1.7 martin 116 1.7 martin pm->parts = parts; 117 1.7 martin if (ps->size_limit > 0 && pm->dlsize > ps->size_limit) 118 1.7 martin pm->dlsize = ps->size_limit; 119 1.7 martin } 120 1.7 martin 121 1.18 martin /* 122 1.18 martin * If the selected scheme does not need two-stage partitioning 123 1.18 martin * (like GPT), do not bother to edit the outer partitions. 124 1.18 martin */ 125 1.18 martin if (pm->parts->pscheme->secondary_partitions == NULL || 126 1.18 martin pm->parts->pscheme->secondary_scheme == NULL) 127 1.18 martin return true; 128 1.17 martin 129 1.17 martin res = edit_outer_parts(pm->parts); 130 1.17 martin if (res == 0) 131 1.17 martin return false; 132 1.17 martin else if (res == 1) 133 1.17 martin return true; 134 1.17 martin 135 1.17 martin pm->parts->pscheme->destroy_part_scheme(pm->parts); 136 1.17 martin pm->parts = NULL; 137 1.17 martin goto again; 138 1.1 dholland } 139 1.1 dholland 140 1.1 dholland /* 141 1.1 dholland * md back-end code for menu-driven BSD disklabel editor. 142 1.1 dholland */ 143 1.17 martin int 144 1.6 martin md_make_bsd_partitions(struct install_partition_desc *install) 145 1.1 dholland { 146 1.6 martin return make_bsd_partitions(install); 147 1.1 dholland } 148 1.1 dholland 149 1.1 dholland /* 150 1.1 dholland * any additional partition validation 151 1.1 dholland */ 152 1.6 martin bool 153 1.6 martin md_check_partitions(struct install_partition_desc *install) 154 1.1 dholland { 155 1.6 martin size_t i; 156 1.1 dholland 157 1.13 martin for (i = 0; i < install->num; i++) 158 1.13 martin if (install->infos[i].fs_type == FS_MSDOS) 159 1.13 martin return true; 160 1.13 martin 161 1.13 martin msg_display(MSG_nomsdospart); 162 1.13 martin process_menu(MENU_ok, NULL); 163 1.1 dholland 164 1.6 martin return false; 165 1.1 dholland } 166 1.1 dholland 167 1.1 dholland /* 168 1.1 dholland * hook called before writing new disklabel. 169 1.1 dholland */ 170 1.6 martin bool 171 1.6 martin md_pre_disklabel(struct install_partition_desc *install, 172 1.6 martin struct disk_partitions *parts) 173 1.1 dholland { 174 1.1 dholland 175 1.18 martin /* 176 1.18 martin * RAW_PART is 2 on evbarm and bad things happen if we 177 1.18 martin * write the MBR first and then the disklabel - so postpone 178 1.23 andvar * the MBR to md_post_disklabel(), unlike other architectures. 179 1.18 martin */ 180 1.18 martin return true; 181 1.18 martin } 182 1.18 martin 183 1.18 martin /* 184 1.18 martin * hook called after writing disklabel to new target disk. 185 1.18 martin */ 186 1.18 martin bool 187 1.18 martin md_post_disklabel(struct install_partition_desc *install, 188 1.18 martin struct disk_partitions *parts) 189 1.18 martin { 190 1.6 martin if (parts->parent == NULL) 191 1.6 martin return true; /* no outer partitions */ 192 1.6 martin 193 1.6 martin parts = parts->parent; 194 1.6 martin 195 1.6 martin msg_display_subst(MSG_dofdisk, 3, parts->disk, 196 1.6 martin msg_string(parts->pscheme->name), 197 1.6 martin msg_string(parts->pscheme->short_name)); 198 1.1 dholland 199 1.6 martin /* write edited "MBR" onto disk. */ 200 1.6 martin if (!parts->pscheme->write_to_disk(parts)) { 201 1.1 dholland msg_display(MSG_wmbrfail); 202 1.1 dholland process_menu(MENU_ok, NULL); 203 1.6 martin return false; 204 1.1 dholland } 205 1.6 martin return true; 206 1.1 dholland } 207 1.1 dholland 208 1.1 dholland /* 209 1.1 dholland * hook called after upgrade() or install() has finished setting 210 1.1 dholland * up the target disk but immediately before the user is given the 211 1.1 dholland * ``disks are now set up'' message. 212 1.1 dholland */ 213 1.1 dholland int 214 1.6 martin md_post_newfs(struct install_partition_desc *install) 215 1.1 dholland { 216 1.1 dholland return 0; 217 1.1 dholland } 218 1.1 dholland 219 1.1 dholland int 220 1.13 martin evbarm_extract_finalize(int update) 221 1.1 dholland { 222 1.13 martin distinfo *dist; 223 1.1 dholland char kernelbin[100]; 224 1.13 martin int (*saved_fetch_fn)(const char *); 225 1.13 martin #ifdef _LP64 226 1.13 martin #define EFIBOOT "/usr/mdec/bootaa64.efi" 227 1.13 martin #else 228 1.13 martin #define EFIBOOT "/usr/mdec/bootarm.efi" 229 1.13 martin #endif 230 1.13 martin 231 1.13 martin dist = get_set_distinfo(SET_KERNEL_1); 232 1.13 martin if (dist == NULL) 233 1.13 martin return 0; 234 1.13 martin 235 1.13 martin saved_fetch_fn = fetch_fn; 236 1.13 martin extract_file_to(dist, false, "/", "./netbsd", false); 237 1.13 martin fetch_fn = NULL; 238 1.13 martin make_target_dir("/boot/EFI/boot"); 239 1.13 martin if (target_file_exists_p(EFIBOOT)) 240 1.13 martin cp_within_target(EFIBOOT, "/boot/EFI/boot", 0); 241 1.1 dholland 242 1.13 martin if (boardtype == BOARD_TYPE_ACPI) { 243 1.13 martin fetch_fn = saved_fetch_fn; 244 1.1 dholland return 0; 245 1.13 martin } 246 1.13 martin if (boardtype == BOARD_TYPE_NORMAL) { 247 1.13 martin extract_file_to(dist, false, "/boot", "./netbsd.ub", false); 248 1.13 martin fetch_fn = saved_fetch_fn; 249 1.13 martin return 0; 250 1.13 martin } 251 1.1 dholland if (boardtype == BOARD_TYPE_RPI) { 252 1.13 martin extract_file_to(dist, false, "/boot", "./netbsd.img", false); 253 1.13 martin fetch_fn = saved_fetch_fn; 254 1.5 skrll snprintf(kernelbin, 100, "%s/netbsd.img", targetroot_mnt); 255 1.1 dholland if (file_exists_p(kernelbin)) { 256 1.1 dholland run_program(RUN_DISPLAY, 257 1.1 dholland "/bin/cp %s /targetroot/boot/kernel.img", kernelbin); 258 1.1 dholland } else { 259 1.1 dholland msg_display(MSG_rpikernelmissing); 260 1.1 dholland process_menu(MENU_ok, NULL); 261 1.1 dholland return 1; 262 1.1 dholland } 263 1.1 dholland } 264 1.13 martin fetch_fn = saved_fetch_fn; 265 1.13 martin return 0; 266 1.13 martin } 267 1.13 martin 268 1.13 martin int 269 1.22 martin md_post_extract(struct install_partition_desc *install, bool upgrade) 270 1.13 martin { 271 1.13 martin 272 1.1 dholland return 0; 273 1.1 dholland } 274 1.1 dholland 275 1.1 dholland void 276 1.6 martin md_cleanup_install(struct install_partition_desc *install) 277 1.1 dholland { 278 1.1 dholland #ifndef DEBUG 279 1.1 dholland enable_rc_conf(); 280 1.1 dholland add_rc_conf("sshd=YES\n"); 281 1.1 dholland add_rc_conf("dhcpcd=YES\n"); 282 1.1 dholland #endif 283 1.1 dholland } 284 1.1 dholland 285 1.1 dholland int 286 1.6 martin md_pre_update(struct install_partition_desc *install) 287 1.1 dholland { 288 1.1 dholland return 1; 289 1.1 dholland } 290 1.1 dholland 291 1.1 dholland /* Upgrade support */ 292 1.1 dholland int 293 1.6 martin md_update(struct install_partition_desc *install) 294 1.1 dholland { 295 1.6 martin md_post_newfs(install); 296 1.1 dholland return 1; 297 1.1 dholland } 298 1.1 dholland 299 1.1 dholland int 300 1.8 martin md_pre_mount(struct install_partition_desc *install, size_t ndx) 301 1.1 dholland { 302 1.1 dholland return 0; 303 1.1 dholland } 304 1.1 dholland 305 1.1 dholland int 306 1.6 martin md_check_mbr(struct disk_partitions *parts, mbr_info_t *mbri, bool quiet) 307 1.1 dholland { 308 1.1 dholland mbr_info_t *ext; 309 1.1 dholland struct mbr_partition *part; 310 1.1 dholland int i, hasboot=0; 311 1.1 dholland 312 1.13 martin for (ext = mbri; ext; ext = ext->extended) { 313 1.13 martin part = ext->mbr.mbr_parts; 314 1.13 martin for (i=0, hasboot=0; i < MBR_PART_COUNT; part++, i++) { 315 1.13 martin if (part->mbrp_type != MBR_PTYPE_FAT16L && 316 1.13 martin part->mbrp_type != MBR_PTYPE_FAT32L) 317 1.13 martin continue; 318 1.13 martin hasboot = 1; 319 1.13 martin break; 320 1.1 dholland } 321 1.1 dholland } 322 1.13 martin if (!hasboot) { 323 1.13 martin if (quiet) 324 1.13 martin return 2; 325 1.13 martin msg_display(MSG_nomsdospart); 326 1.13 martin return ask_reedit(parts); 327 1.13 martin } 328 1.13 martin 329 1.1 dholland return 2; 330 1.1 dholland } 331 1.1 dholland 332 1.6 martin bool 333 1.6 martin md_parts_use_wholedisk(struct disk_partitions *parts) 334 1.1 dholland { 335 1.13 martin struct disk_part_info boot_part = { 336 1.21 martin .size = boardtype == BOARD_TYPE_NORMAL ? 337 1.19 martin PART_BOOT_LARGE/parts->bytes_per_sector : 338 1.19 martin PART_BOOT/parts->bytes_per_sector, 339 1.21 martin .fs_type = PART_BOOT_TYPE, 340 1.21 martin .fs_sub_type = boardtype == BOARD_TYPE_NORMAL ? 341 1.21 martin MBR_PTYPE_FAT32L : MBR_PTYPE_FAT16L, 342 1.13 martin }; 343 1.1 dholland 344 1.13 martin return parts_use_wholedisk(parts, 1, &boot_part); 345 1.6 martin } 346 1.6 martin 347 1.6 martin /* returns false if no write-back of parts is required */ 348 1.6 martin bool 349 1.6 martin md_mbr_update_check(struct disk_partitions *parts, mbr_info_t *mbri) 350 1.6 martin { 351 1.6 martin return false; 352 1.6 martin } 353 1.6 martin 354 1.6 martin #ifdef HAVE_GPT 355 1.6 martin /* 356 1.6 martin * New GPT partitions have been written, update bootloader or remember 357 1.23 andvar * data until needed in md_post_newfs 358 1.6 martin */ 359 1.6 martin bool 360 1.6 martin md_gpt_post_write(struct disk_partitions *parts, part_id root_id, 361 1.6 martin bool root_is_new, part_id efi_id, bool efi_is_new) 362 1.6 martin { 363 1.6 martin return true; 364 1.1 dholland } 365 1.6 martin #endif 366 1.13 martin 367 1.13 martin void 368 1.13 martin evbarm_part_defaults(struct pm_devs *my_pm, struct part_usage_info *infos, 369 1.13 martin size_t num_usage_infos) 370 1.13 martin { 371 1.13 martin size_t i; 372 1.13 martin 373 1.13 martin for (i = 0; i < num_usage_infos; i++) { 374 1.13 martin if (infos[i].fs_type == PART_BOOT_TYPE && 375 1.15 martin infos[i].mount[0] != 0 && 376 1.13 martin strcmp(infos[i].mount, PART_BOOT_MOUNT) == 0) { 377 1.21 martin infos[i].size = boardtype == BOARD_TYPE_NORMAL ? 378 1.21 martin PART_BOOT_LARGE/my_pm->parts->bytes_per_sector : 379 1.21 martin PART_BOOT/my_pm->parts->bytes_per_sector; 380 1.21 martin infos[i].fs_version = boardtype == BOARD_TYPE_NORMAL ? 381 1.21 martin MBR_PTYPE_FAT32L : MBR_PTYPE_FAT16L; 382 1.13 martin return; 383 1.13 martin } 384 1.13 martin } 385 1.13 martin } 386 1.13 martin 387