/* $NetBSD: machdep.c,v 1.124 2024/03/05 14:15:29 thorpej Exp $ */ /*- * Copyright (c) 2006 Izumi Tsutsui. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 2000 Soren S. Jorvang. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.124 2024/03/05 14:15:29 thorpej Exp $"); #include "opt_ddb.h" #include "opt_kgdb.h" #include "opt_modular.h" #include "opt_execfmt.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KGDB #include #endif #include "ksyms.h" #if NKSYMS || defined(DDB) || defined(MODULAR) #include #include #include #endif /* Maps for VM objects. */ struct vm_map *phys_map = NULL; void *bootinfo = NULL; /* pointer to bootinfo structure */ char bootstring[512]; /* Boot command */ int netboot; /* Are we netbooting? */ char *nfsroot_bstr = NULL; char *root_bstr = NULL; int bootunit = -1; int bootpart = -1; #if 0 struct extent *cobalt_io_ex = NULL; struct extent *cobalt_mem_ex = NULL; struct mips_bus_space bonito_iot; struct mips_bus_space bonito_memt; struct mips_bus_dma_tag bonito_dmat; struct mips_pci_chipset bonito_pc; #endif int cpuspeed; u_int cobalt_id; static const char * const cobalt_model[] = { [COBALT_ID_QUBE2700] = "Cobalt Qube 2700", [COBALT_ID_RAQ] = "Cobalt RaQ", [COBALT_ID_QUBE2] = "Cobalt Qube 2", [COBALT_ID_RAQ2] = "Cobalt RaQ 2" }; #define COBALT_MODELS __arraycount(cobalt_model) phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; int mem_cluster_cnt; void mach_init(int32_t, u_int, int32_t); void decode_bootstring(void); static char *strtok_light(char *, const char); static u_int read_board_id(void); extern char *esym; struct mips_bus_space cobalt_bs; void mainbus_bus_mem_init(bus_space_tag_t, void *); /* * Do all the stuff that locore normally does before calling main(). */ void mach_init(int32_t memsize32, u_int bim, int32_t bip32) { intptr_t memsize = (int32_t)memsize32; char *kernend; char *bip = (char *)(intptr_t)(int32_t)bip32; u_long first, last; extern char edata[], end[]; const char *bi_msg; #if NKSYMS || defined(DDB) || defined(MODULAR) char *ssym = 0; struct btinfo_symtab *bi_syms; #endif struct btinfo_howto *bi_howto; /* * Clear the BSS segment (if needed). */ if (memcmp(((Elf_Ehdr *)end)->e_ident, ELFMAG, SELFMAG) == 0 && ((Elf_Ehdr *)end)->e_ident[EI_CLASS] == ELFCLASS) { esym = end; #if NKSYMS || defined(DDB) || defined(MODULAR) esym += ((Elf_Ehdr *)end)->e_entry; #endif kernend = (char *)mips_round_page(esym); /* * We don't have to clear BSS here * since our bootloader already does it. */ #if 0 memset(edata, 0, end - edata); #endif } else { kernend = (void *)mips_round_page(end); /* * No symbol table, so assume we are loaded by * the firmware directly with "bfd" command. * The firmware loader doesn't clear BSS of * a loaded kernel, so do it here. */ memset(edata, 0, kernend - edata); } /* * Copy exception-dispatch code down to exception vector. * Initialize locore-function vector. * Clear out the I and D caches. */ mips_vector_init(NULL, false); mainbus_bus_mem_init(&cobalt_bs, NULL); /* Check for valid bootinfo passed from bootstrap */ if (bim == BOOTINFO_MAGIC) { struct btinfo_magic *bi_magic; bootinfo = bip; bi_magic = lookup_bootinfo(BTINFO_MAGIC); if (bi_magic == NULL) { bi_msg = "missing bootinfo structure"; bim = (uintptr_t)bip; } else if (bi_magic->magic != BOOTINFO_MAGIC) { bi_msg = "invalid bootinfo structure"; bim = bi_magic->magic; } else bi_msg = NULL; } else { bi_msg = "invalid bootinfo (standalone boot?)"; } #if NKSYMS || defined(DDB) || defined(MODULAR) bi_syms = lookup_bootinfo(BTINFO_SYMTAB); /* Load symbol table if present */ if (bi_syms != NULL) { ssym = (void *)(intptr_t)bi_syms->ssym; esym = (void *)(intptr_t)bi_syms->esym; kernend = (void *)mips_round_page(esym); } #endif bi_howto = lookup_bootinfo(BTINFO_HOWTO); if (bi_howto != NULL) boothowto = bi_howto->bi_howto; cobalt_id = read_board_id(); if (cobalt_id >= COBALT_MODELS || cobalt_model[cobalt_id] == NULL) cpu_setmodel("Cobalt unknown model (board ID %u)", cobalt_id); else cpu_setmodel("%s", cobalt_model[cobalt_id]); switch (cobalt_id) { case COBALT_ID_QUBE2700: case COBALT_ID_RAQ: cpuspeed = 150; /* MHz */ break; case COBALT_ID_QUBE2: case COBALT_ID_RAQ2: cpuspeed = 250; /* MHz */ break; default: /* assume the fastest, so that delay(9) works */ cpuspeed = 250; break; } curcpu()->ci_cpu_freq = cpuspeed * 1000 * 1000; curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz; curcpu()->ci_divisor_delay = ((curcpu()->ci_cpu_freq + (1000000 / 2)) / 1000000); /* all models have Rm5200, which is CPU_MIPS_DOUBLE_COUNT */ curcpu()->ci_cycles_per_hz /= 2; curcpu()->ci_divisor_delay /= 2; physmem = btoc(memsize - MIPS_KSEG0_START); consinit(); KASSERT(&lwp0 == curlwp); if (bi_msg != NULL) printf("%s: magic=%#x bip=%p\n", bi_msg, bim, bip); uvm_md_init(); /* * The boot command is passed in the top 512 bytes, * so don't clobber that. */ mem_clusters[0].start = 0; mem_clusters[0].size = ctob(physmem) - 512; mem_cluster_cnt = 1; memcpy(bootstring, (char *)(memsize - 512), 512); memset((char *)(memsize - 512), 0, 512); bootstring[511] = '\0'; decode_bootstring(); #if NKSYMS || defined(DDB) || defined(MODULAR) /* init symbols if present */ if ((bi_syms != NULL) && (esym != NULL)) ksyms_addsyms_elf(esym - ssym, ssym, esym); #endif KASSERT(&lwp0 == curlwp); /* * Load the rest of the available pages into the VM system. */ first = round_page(MIPS_KSEG0_TO_PHYS(kernend)); last = mem_clusters[0].start + mem_clusters[0].size; uvm_page_physload(atop(first), atop(last), atop(first), atop(last), VM_FREELIST_DEFAULT); /* * Initialize error message buffer (at end of core). */ mips_init_msgbuf(); pmap_bootstrap(); /* * Allocate space for proc0's USPACE. */ mips_init_lwp0_uarea(); #ifdef DDB if (boothowto & RB_KDB) Debugger(); #endif #ifdef KGDB if (boothowto & RB_KDB) kgdb_connect(0); #endif } /* * Allocate memory for variable-sized tables, */ void cpu_startup(void) { cpu_startup_common(); } static int waittime = -1; void cpu_reboot(int howto, char *bootstr) { /* Take a snapshot before clobbering any registers. */ savectx(curpcb); if (cold) { howto |= RB_HALT; goto haltsys; } /* If "always halt" was specified as a boot flag, obey. */ if (boothowto & RB_HALT) howto |= RB_HALT; boothowto = howto; if ((howto & RB_NOSYNC) == 0 && (waittime < 0)) { waittime = 0; vfs_shutdown(); } splhigh(); if (howto & RB_DUMP) dumpsys(); haltsys: doshutdownhooks(); pmf_system_shutdown(boothowto); if (howto & RB_HALT) { printf("\n"); printf("The operating system has halted.\n"); printf("Please press any key to reboot.\n\n"); cnpollc(1); /* For proper keyboard command handling */ cngetc(); cnpollc(0); } printf("rebooting...\n\n"); delay(500000); *(volatile char *)MIPS_PHYS_TO_KSEG1(LED_ADDR) = LED_RESET; printf("WARNING: reboot failed!\n"); for (;;) ; } void decode_bootstring(void) { char *work; char *equ; int i; /* break apart bootstring on ' ' boundaries and iterate */ work = strtok_light(bootstring, ' '); while (work != NULL) { /* if starts with '-', we got options, walk its decode */ if (work[0] == '-') { i = 1; while (work[i] != ' ' && work[i] != '\0') { BOOT_FLAG(work[i], boothowto); i++; } } else /* if it has a '=' its an assignment, switch and set */ if ((equ = strchr(work, '=')) != NULL) { if (memcmp("nfsroot=", work, 8) == 0) { nfsroot_bstr = (equ + 1); } else if (memcmp("root=", work, 5) == 0) { root_bstr = (equ + 1); } } else /* else it a single value, switch and process */ if (memcmp("single", work, 5) == 0) { boothowto |= RB_SINGLE; } else if (memcmp("ro", work, 2) == 0) { /* this is also inserted by the firmware */ } /* grab next token */ work = strtok_light(NULL, ' '); } if (root_bstr != NULL) { /* this should be of the form "/dev/hda1" */ /* [abcd][1234] drive partition linux probe order */ if ((memcmp("/dev/hd", root_bstr, 7) == 0) && (strlen(root_bstr) == 9) ){ bootunit = root_bstr[7] - 'a'; bootpart = root_bstr[8] - '1'; } } if (nfsroot_bstr != NULL) netboot = 1; } static char * strtok_light(char *str, const char sep) { static char *proc; char *head; char *work; if (str != NULL) proc = str; if (proc == NULL) /* end of string return NULL */ return proc; head = proc; work = strchr(proc, sep); if (work == NULL) { /* we hit the end */ proc = work; } else { proc = (work + 1); *work = '\0'; } return head; } /* * Look up information in bootinfo of boot loader. */ void * lookup_bootinfo(unsigned int type) { struct btinfo_common *bt; char *help = bootinfo; /* Check for a bootinfo record first. */ if (help == NULL) { printf("##### help == NULL\n"); return NULL; } do { bt = (struct btinfo_common *)help; printf("Type %d @%p\n", bt->type, (void *)(intptr_t)bt); if (bt->type == type) return (void *)help; help += bt->next; } while (bt->next != 0 && (uintptr_t)help < (uintptr_t)bootinfo + BOOTINFO_SIZE); return NULL; } /* * Get board ID of cobalt models. * * The board ID info is stored at the PCI config register * on the PCI-ISA bridge part of the VIA VT82C586 chipset. * We can't use pci_conf_read(9) yet here, so read it directly. */ static u_int read_board_id(void) { volatile uint32_t *pcicfg_addr, *pcicfg_data; uint32_t reg; #define PCIB_PCI_BUS 0 #define PCIB_PCI_DEV 9 #define PCIB_PCI_FUNC 0 #define PCIB_BOARD_ID_REG 0x94 #define COBALT_BOARD_ID(reg) ((reg & 0x000000f0) >> 4) pcicfg_addr = (uint32_t *)MIPS_PHYS_TO_KSEG1(GT_BASE + GT_PCICFG_ADDR); pcicfg_data = (uint32_t *)MIPS_PHYS_TO_KSEG1(GT_BASE + GT_PCICFG_DATA); *pcicfg_addr = PCICFG_ENABLE | (PCIB_PCI_BUS << 16) | (PCIB_PCI_DEV << 11) | (PCIB_PCI_FUNC << 8) | PCIB_BOARD_ID_REG; reg = *pcicfg_data; *pcicfg_addr = 0; return COBALT_BOARD_ID(reg); }