1*bb00e811Sclaudio /* $OpenBSD: machdep.c,v 1.101 2023/10/24 13:20:10 claudio Exp $ */
22bf3c060Smiod
32bf3c060Smiod /*
46f377552Smiod * Copyright (c) 2009, 2010, 2014 Miodrag Vallat.
52bf3c060Smiod *
62bf3c060Smiod * Permission to use, copy, modify, and distribute this software for any
72bf3c060Smiod * purpose with or without fee is hereby granted, provided that the above
82bf3c060Smiod * copyright notice and this permission notice appear in all copies.
92bf3c060Smiod *
102bf3c060Smiod * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112bf3c060Smiod * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122bf3c060Smiod * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132bf3c060Smiod * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142bf3c060Smiod * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152bf3c060Smiod * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162bf3c060Smiod * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172bf3c060Smiod */
182bf3c060Smiod /*
192bf3c060Smiod * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
202bf3c060Smiod *
212bf3c060Smiod * Redistribution and use in source and binary forms, with or without
222bf3c060Smiod * modification, are permitted provided that the following conditions
232bf3c060Smiod * are met:
242bf3c060Smiod * 1. Redistributions of source code must retain the above copyright
252bf3c060Smiod * notice, this list of conditions and the following disclaimer.
262bf3c060Smiod * 2. Redistributions in binary form must reproduce the above copyright
272bf3c060Smiod * notice, this list of conditions and the following disclaimer in the
282bf3c060Smiod * documentation and/or other materials provided with the distribution.
292bf3c060Smiod *
302bf3c060Smiod * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
312bf3c060Smiod * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
322bf3c060Smiod * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
332bf3c060Smiod * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
342bf3c060Smiod * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
352bf3c060Smiod * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
362bf3c060Smiod * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
372bf3c060Smiod * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
382bf3c060Smiod * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
392bf3c060Smiod * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
402bf3c060Smiod * SUCH DAMAGE.
412bf3c060Smiod *
422bf3c060Smiod */
432bf3c060Smiod #include <sys/param.h>
442bf3c060Smiod #include <sys/systm.h>
452bf3c060Smiod #include <sys/kernel.h>
462bf3c060Smiod #include <sys/proc.h>
472bf3c060Smiod #include <sys/buf.h>
482bf3c060Smiod #include <sys/reboot.h>
492bf3c060Smiod #include <sys/conf.h>
502bf3c060Smiod #include <sys/msgbuf.h>
512bf3c060Smiod #include <sys/tty.h>
522bf3c060Smiod #include <sys/user.h>
532bf3c060Smiod #include <sys/exec.h>
542bf3c060Smiod #include <sys/sysctl.h>
552bf3c060Smiod #include <sys/mount.h>
562bf3c060Smiod #include <sys/syscallargs.h>
572bf3c060Smiod #include <sys/exec_elf.h>
582bf3c060Smiod #ifdef SYSVSHM
592bf3c060Smiod #include <sys/shm.h>
602bf3c060Smiod #endif
612bf3c060Smiod #ifdef SYSVSEM
622bf3c060Smiod #include <sys/sem.h>
632bf3c060Smiod #endif
642bf3c060Smiod
657d9ca166Sderaadt #include <net/if.h>
66a43a5a68Smpi
67a43a5a68Smpi #include <uvm/uvm_extern.h>
682bf3c060Smiod
692bf3c060Smiod #include <machine/db_machdep.h>
702bf3c060Smiod #include <ddb/db_interface.h>
712bf3c060Smiod
722bf3c060Smiod #include <machine/autoconf.h>
73737df64eSmiod #include <mips64/cache.h>
742bf3c060Smiod #include <machine/cpu.h>
757b6ae6a5Smiod #include <mips64/mips_cpu.h>
762bf3c060Smiod #include <machine/memconf.h>
772bf3c060Smiod #include <machine/pmon.h>
782bf3c060Smiod
793fc8f127Spirofti #ifdef HIBERNATE
803fc8f127Spirofti #include <machine/hibernate_var.h>
813fc8f127Spirofti #endif /* HIBERNATE */
823fc8f127Spirofti
832bf3c060Smiod #include <dev/cons.h>
842bf3c060Smiod
85f75298a7Smiod #include <dev/pci/pcireg.h>
86f75298a7Smiod #include <dev/pci/pcivar.h>
87f75298a7Smiod #include <dev/pci/pcidevs.h>
88f75298a7Smiod
892bf3c060Smiod /* The following is used externally (sysctl_hw) */
902bf3c060Smiod char machine[] = MACHINE; /* Machine "architecture" */
912bf3c060Smiod char cpu_model[30];
92b9984aa0Sotto char pmon_bootp[80];
932bf3c060Smiod
942bf3c060Smiod /*
956f377552Smiod * Even though the system is 64bit, 2E- and 2F-based hardware is constrained
9636fd90dcSjsg * to up to 2G of contiguous physical memory (direct 2GB DMA area). 2Gq- and
976f377552Smiod * 3A-based hardware only supports 32-bit DMA addresses, even though
986f377552Smiod * physical memory may exist beyond 4GB.
99b426ab7bSthib */
100b426ab7bSthib struct uvm_constraint_range dma_constraint = { 0x0, 0xffffffffUL };
101b426ab7bSthib struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
102b426ab7bSthib
1032bf3c060Smiod vm_map_t exec_map;
1042bf3c060Smiod vm_map_t phys_map;
1052bf3c060Smiod
106c72644a3Sderaadt /*
107c72644a3Sderaadt * safepri is a safe priority for sleep to set for a spin-wait
108c72644a3Sderaadt * during autoconfiguration or after a panic.
109c72644a3Sderaadt */
110c72644a3Sderaadt int safepri = 0;
111c72644a3Sderaadt
1122bf3c060Smiod caddr_t msgbufbase;
1132bf3c060Smiod
1142bf3c060Smiod int physmem; /* Max supported memory, changes to actual. */
1152bf3c060Smiod int ncpu = 1; /* At least one CPU in the system. */
1167d353fccSvisa int nnodes = 1; /* Number of NUMA nodes, only on 3A. */
1172bf3c060Smiod struct user *proc0paddr;
1182d357aedSnatano int lid_action = 1;
119e9721e48Stedu int pwr_action = 1;
1202bf3c060Smiod
12139de0dfdSvisa #ifdef MULTIPROCESSOR
12239de0dfdSvisa uint64_t cpu_spinup_a0;
12339de0dfdSvisa uint64_t cpu_spinup_sp;
12439de0dfdSvisa uint32_t ipi_mask;
12539de0dfdSvisa #endif
12639de0dfdSvisa
12751b07be5Smiod const struct platform *sys_platform;
128c301e791Smiod struct cpu_hwinfo bootcpu_hwinfo;
12977e35563Svisa void *loongson_videobios;
1303485d230Svisa uint loongson_cpumask = 1;
131d57a735dSmiod uint loongson_ver;
1322bf3c060Smiod
1332bf3c060Smiod /* Pointers to the start and end of the symbol table. */
1342bf3c060Smiod caddr_t ssym;
1352bf3c060Smiod caddr_t esym;
1362bf3c060Smiod caddr_t ekern;
1372bf3c060Smiod
1382bf3c060Smiod struct phys_mem_desc mem_layout[MAXMEMSEGS];
1395acbfd54Svisa paddr_t loongson_memlo_alias;
1402bf3c060Smiod
14103052511Smiod pcitag_t (*pci_make_tag_early)(int, int, int);
14203052511Smiod pcireg_t (*pci_conf_read_early)(pcitag_t, int);
14303052511Smiod bus_space_tag_t early_mem_t;
14403052511Smiod bus_space_tag_t early_io_t;
14503052511Smiod
1462bf3c060Smiod static u_long atoi(const char *, uint);
1472bf3c060Smiod static void dobootopts(int);
1482bf3c060Smiod
1492bf3c060Smiod void dumpsys(void);
1502bf3c060Smiod void dumpconf(void);
151b9984aa0Sotto extern void parsepmonbp(void);
1526f377552Smiod const struct platform *loongson_identify(const char *, int);
1536f377552Smiod vaddr_t mips_init(uint64_t, uint64_t, uint64_t, uint64_t, char *);
1542bf3c060Smiod
1557d353fccSvisa extern void htb_early_setup(void);
1567d353fccSvisa
1572bf3c060Smiod extern void loongson2e_setup(u_long, u_long);
1582bf3c060Smiod extern void loongson2f_setup(u_long, u_long);
1596f377552Smiod extern void loongson3a_setup(u_long, u_long);
1602bf3c060Smiod
1612bf3c060Smiod cons_decl(pmon);
1622bf3c060Smiod
1632bf3c060Smiod struct consdev pmoncons = {
1642bf3c060Smiod NULL,
1652bf3c060Smiod NULL,
1662bf3c060Smiod pmoncngetc,
1672bf3c060Smiod pmoncnputc,
1682bf3c060Smiod nullcnpollc,
1692bf3c060Smiod NULL,
1702bf3c060Smiod makedev(0, 0),
1712bf3c060Smiod CN_DEAD
1722bf3c060Smiod };
1732bf3c060Smiod
1742bf3c060Smiod /*
175e1844cd9Smiod * List of supported system types, from the ``Version'' environment
176e1844cd9Smiod * variable.
177e1844cd9Smiod */
178e1844cd9Smiod
179e1844cd9Smiod struct bonito_flavour {
180e1844cd9Smiod const char *prefix;
18151b07be5Smiod const struct platform *platform;
182e1844cd9Smiod };
183e1844cd9Smiod
184f75298a7Smiod extern const struct platform ebenton_platform;
18551b07be5Smiod extern const struct platform fuloong_platform;
18651b07be5Smiod extern const struct platform gdium_platform;
187d57a735dSmiod extern const struct platform generic2e_platform;
188c2d35888Smiod extern const struct platform lynloong_platform;
1897d353fccSvisa extern const struct platform rs780e_platform;
19051b07be5Smiod extern const struct platform yeeloong_platform;
19151b07be5Smiod
192e1844cd9Smiod const struct bonito_flavour bonito_flavours[] = {
1936f377552Smiod #ifdef CPU_LOONGSON2
194f75298a7Smiod /* eBenton EBT700 netbook */
195f75298a7Smiod { "EBT700", &ebenton_platform }, /* prefix added by user */
19651b07be5Smiod /* Lemote Fuloong 2F mini-PC */
197f75298a7Smiod { "LM6002", &fuloong_platform }, /* dual Ethernet,
198f75298a7Smiod prefix added by user */
199cd66aef1Smiod { "LM6003", &fuloong_platform },
20051b07be5Smiod { "LM6004", &fuloong_platform },
201e1844cd9Smiod /* EMTEC Gdium Liberty 1000 */
20251b07be5Smiod { "Gdium", &gdium_platform },
20351b07be5Smiod /* Lemote Yeeloong 8.9" netbook */
20451b07be5Smiod { "LM8089", &yeeloong_platform },
20551b07be5Smiod /* supposedly Lemote Yeeloong 10.1" netbook, but those found so far
20651b07be5Smiod report themselves as LM8089 */
20751b07be5Smiod { "LM8101", &yeeloong_platform },
208c2d35888Smiod /* Lemote Lynloong all-in-one computer */
209c2d35888Smiod { "LM9001", &lynloong_platform },
210b07de51bSvisa { "LM9002", &lynloong_platform },
211b07de51bSvisa { "LM9003", &lynloong_platform },
212b07de51bSvisa /* Lemote Lynloong all-in-one computer, Xueloong edition */
213b07de51bSvisa { "LM9013", &lynloong_platform },
2146f377552Smiod #endif
2156f377552Smiod #ifdef CPU_LOONGSON3
2166f377552Smiod /* Laptops */
2177d353fccSvisa { "A1004", &rs780e_platform }, /* 3A */
2187d353fccSvisa { "A1201", &rs780e_platform }, /* 2Gq */
2196f377552Smiod /* Lemote Xinghuo 6100 (mini-ITX PC) */
2207d353fccSvisa { "A1101", &rs780e_platform }, /* 3A */
2216f377552Smiod /* All-in-one PC */
2227d353fccSvisa { "A1205", &rs780e_platform }, /* 2Gq */
2236f377552Smiod #endif
224e1844cd9Smiod { NULL }
225e1844cd9Smiod };
226e1844cd9Smiod
227e1844cd9Smiod /*
228f75298a7Smiod * Try to figure out what particular machine we run on, depending on the
229f75298a7Smiod * scarce PMON version information and whatever else we can figure.
230f75298a7Smiod */
231f75298a7Smiod const struct platform *
loongson_identify(const char * version,int envtype)2326f377552Smiod loongson_identify(const char *version, int envtype)
233f75298a7Smiod {
234f75298a7Smiod const struct bonito_flavour *f;
235f75298a7Smiod
2366f377552Smiod switch (envtype) {
2375acbfd54Svisa #ifdef CPU_LOONGSON3
2386f377552Smiod case PMON_ENVTYPE_EFI:
2397d353fccSvisa if (loongson_ver == 0x3a || loongson_ver == 0x3b) {
2407d353fccSvisa pcitag_t tag;
2417d353fccSvisa pcireg_t id;
2427d353fccSvisa
2437d353fccSvisa htb_early_setup();
2447d353fccSvisa
2457d353fccSvisa /* Determine platform by host bridge. */
2467d353fccSvisa tag = pci_make_tag_early(0, 0, 0);
2477d353fccSvisa id = pci_conf_read_early(tag, PCI_ID_REG);
2487d353fccSvisa switch (id) {
2497d353fccSvisa case PCI_ID_CODE(PCI_VENDOR_AMD,
2507d353fccSvisa PCI_PRODUCT_AMD_RS780_HB):
2517d353fccSvisa return &rs780e_platform;
2527d353fccSvisa }
2537d353fccSvisa }
2547d353fccSvisa pmon_printf("Unable to figure out model!\n");
2557d353fccSvisa return NULL;
2565acbfd54Svisa #endif
2576f377552Smiod
2586f377552Smiod default:
2596f377552Smiod case PMON_ENVTYPE_ENVP:
260f75298a7Smiod if (version == NULL) {
2615acbfd54Svisa #ifdef CPU_LOONGSON2
262f75298a7Smiod /*
2636f377552Smiod * If there is no `Version' variable, we expect to be
2646f377552Smiod * running on a 2E system, use the generic code and
2656f377552Smiod * hope for the best.
266f75298a7Smiod */
2675acbfd54Svisa if (loongson_ver == 0x2e)
268f75298a7Smiod return &generic2e_platform;
2695acbfd54Svisa #endif
270f75298a7Smiod pmon_printf("Unable to figure out model!\n");
271f75298a7Smiod return NULL;
272f75298a7Smiod }
273f75298a7Smiod
274f75298a7Smiod for (f = bonito_flavours; f->prefix != NULL; f++)
275f75298a7Smiod if (strncmp(version, f->prefix, strlen(f->prefix)) == 0)
276f75298a7Smiod return f->platform;
277f75298a7Smiod
2785acbfd54Svisa #ifdef CPU_LOONGSON2
279f75298a7Smiod /*
280f75298a7Smiod * Early Lemote designs shipped without a model prefix.
281f75298a7Smiod *
2826f377552Smiod * We can reasonably expect these to be close enough to either
2836f377552Smiod * the first generation Fuloong 2F design (LM6002), or the 7
2846f377552Smiod * inch first netbook model; we can tell them apart by looking
2856f377552Smiod * at which video chip they embed.
286f75298a7Smiod *
287f75298a7Smiod * Note that this is only worth doing if the version string is
2886f377552Smiod * 1.2.something (1.3 onwards are expected to have a model
2896f377552Smiod * prefix, and there are currently no reports of 1.1 and
290f75298a7Smiod * below being 2F systems).
291f75298a7Smiod *
292f75298a7Smiod * LM6002 users are encouraged to add the system model prefix to
293f75298a7Smiod * the `Version' variable.
294f75298a7Smiod */
295f75298a7Smiod if (strncmp(version, "1.2.", 4) == 0) {
296f75298a7Smiod const struct platform *p = NULL;
297f75298a7Smiod pcitag_t tag;
298f75298a7Smiod pcireg_t id, class;
299f75298a7Smiod int dev;
300f75298a7Smiod
3016f377552Smiod pmon_printf("No model prefix "
3026f377552Smiod "in version string \"%s\".\n", version);
303f75298a7Smiod
3046f377552Smiod if (loongson_ver == 0x2f)
305f75298a7Smiod for (dev = 0; dev < 32; dev++) {
306f75298a7Smiod tag = pci_make_tag_early(0, dev, 0);
3076f377552Smiod id = pci_conf_read_early(tag,
3086f377552Smiod PCI_ID_REG);
3096f377552Smiod if (id == 0 || PCI_VENDOR(id) ==
3106f377552Smiod PCI_VENDOR_INVALID)
311f75298a7Smiod continue;
312f75298a7Smiod
3136f377552Smiod /*
3146f377552Smiod * No need to check for
3156f377552Smiod * DEVICE_IS_VGA_PCI here, since we
3166f377552Smiod * expect a linear framebuffer.
3176f377552Smiod */
3186f377552Smiod class = pci_conf_read_early(tag,
3196f377552Smiod PCI_CLASS_REG);
3206f377552Smiod if (PCI_CLASS(class) !=
3216f377552Smiod PCI_CLASS_DISPLAY ||
3226f377552Smiod (PCI_SUBCLASS(class) !=
3236f377552Smiod PCI_SUBCLASS_DISPLAY_VGA &&
3246f377552Smiod PCI_SUBCLASS(class) !=
3256f377552Smiod PCI_SUBCLASS_DISPLAY_MISC))
326f75298a7Smiod continue;
327f75298a7Smiod
328f75298a7Smiod switch (id) {
329f75298a7Smiod case PCI_ID_CODE(PCI_VENDOR_SIS,
330f75298a7Smiod PCI_PRODUCT_SIS_315PRO_VGA):
331f75298a7Smiod p = &fuloong_platform;
332f75298a7Smiod break;
333f75298a7Smiod case PCI_ID_CODE(PCI_VENDOR_SMI,
334f75298a7Smiod PCI_PRODUCT_SMI_SM712):
335f75298a7Smiod p = &ebenton_platform;
336f75298a7Smiod break;
337f75298a7Smiod }
3386f377552Smiod }
339f75298a7Smiod
340f75298a7Smiod if (p != NULL) {
3416f377552Smiod pmon_printf("Attempting to match as "
3426f377552Smiod "%s %s\n", p->vendor, p->product);
343f75298a7Smiod return p;
344f75298a7Smiod }
345f75298a7Smiod }
3465acbfd54Svisa #endif
347f75298a7Smiod }
348f75298a7Smiod
349f75298a7Smiod pmon_printf("This kernel doesn't support model \"%s\"." "\n", version);
350f75298a7Smiod return NULL;
351f75298a7Smiod }
352f75298a7Smiod
3535acbfd54Svisa /*
3545acbfd54Svisa * Figure out machine parameters using the 'EFI-like' interface.
3555acbfd54Svisa */
3565acbfd54Svisa int
loongson_efi_setup(void)3575acbfd54Svisa loongson_efi_setup(void)
3585acbfd54Svisa {
359afa841fbSvisa struct pmon_env_mem_entry entry;
3603485d230Svisa const struct pmon_env_cpu *cpuenv;
3615acbfd54Svisa const struct pmon_env_mem *mem;
3625acbfd54Svisa paddr_t fp, lp;
3633485d230Svisa uint32_t i, ncpus, seg = 0;
3645acbfd54Svisa
3653485d230Svisa cpuenv = pmon_get_env_cpu();
3663485d230Svisa bootcpu_hwinfo.clock = cpuenv->speed;
3673485d230Svisa
3683485d230Svisa /*
3693485d230Svisa * Get available CPUs.
3703485d230Svisa */
3713485d230Svisa
3723485d230Svisa ncpus = cpuenv->ncpus;
3733485d230Svisa if (ncpus > LOONGSON_MAXCPUS)
3743485d230Svisa ncpus = LOONGSON_MAXCPUS;
3753485d230Svisa
3763485d230Svisa loongson_cpumask = (1u << ncpus) - 1;
3773485d230Svisa loongson_cpumask &= ~(uint)cpuenv->reserved_cores;
3783485d230Svisa
3793485d230Svisa ncpusfound = 0;
3803485d230Svisa for (i = 0; i < ncpus; i++) {
3813485d230Svisa if (ISSET(loongson_cpumask, 1u << i))
3823485d230Svisa ncpusfound++;
3833485d230Svisa }
3843485d230Svisa
3853485d230Svisa /*
3863485d230Svisa * Get free memory segments.
3873485d230Svisa */
3885acbfd54Svisa
3895acbfd54Svisa mem = pmon_get_env_mem();
3905acbfd54Svisa physmem = 0;
3915acbfd54Svisa for (i = 0; i < mem->nentries && seg < MAXMEMSEGS; i++) {
392afa841fbSvisa memcpy(&entry, &mem->mem_map[i], sizeof(entry));
393afa841fbSvisa if (entry.node != 0 ||
394afa841fbSvisa (entry.type != PMON_MEM_SYSTEM_LOW &&
395afa841fbSvisa entry.type != PMON_MEM_SYSTEM_HIGH))
3965acbfd54Svisa continue;
397afa841fbSvisa fp = atop(entry.address);
39832192ce3Svisa lp = atop(entry.address + ((uint64_t)entry.size << 20));
3995acbfd54Svisa if (lp > atop(pfn_to_pad(PG_FRAME)) + 1)
4005acbfd54Svisa lp = atop(pfn_to_pad(PG_FRAME)) + 1;
4015acbfd54Svisa if (fp >= lp)
4025acbfd54Svisa continue;
4035acbfd54Svisa physmem += lp - fp;
4045acbfd54Svisa mem_layout[seg].mem_first_page = fp;
4055acbfd54Svisa mem_layout[seg].mem_last_page = lp;
4065acbfd54Svisa seg++;
4075acbfd54Svisa }
4085acbfd54Svisa
4095acbfd54Svisa return 0;
4105acbfd54Svisa }
4115acbfd54Svisa
4125acbfd54Svisa /*
4135acbfd54Svisa * Figure out machine parameters using the PMON interface.
4145acbfd54Svisa */
4155acbfd54Svisa int
loongson_envp_setup(void)4165acbfd54Svisa loongson_envp_setup(void)
4175acbfd54Svisa {
4185acbfd54Svisa const char *envvar;
4195acbfd54Svisa u_long cpuspeed, memlo, memhi;
4205acbfd54Svisa
4215acbfd54Svisa /*
4225acbfd54Svisa * Figure out processor clock speed.
4235acbfd54Svisa * Hopefully the processor speed, in Hertz, will not overflow
4245acbfd54Svisa * uint32_t...
4255acbfd54Svisa */
4265acbfd54Svisa
4275acbfd54Svisa cpuspeed = 0;
4285acbfd54Svisa envvar = pmon_getenv("cpuclock");
4295acbfd54Svisa if (envvar != NULL)
4305acbfd54Svisa cpuspeed = atoi(envvar, 10); /* speed in Hz */
4315acbfd54Svisa if (cpuspeed < 100 * 1000000)
4325acbfd54Svisa cpuspeed = 797000000; /* Reasonable default */
4335acbfd54Svisa bootcpu_hwinfo.clock = cpuspeed;
4345acbfd54Svisa
4355acbfd54Svisa /*
4363485d230Svisa * Guess the available CPUs.
4373485d230Svisa */
4383485d230Svisa
4393485d230Svisa switch (loongson_ver) {
4403485d230Svisa #ifdef CPU_LOONGSON3
4413485d230Svisa case 0x3a:
4423485d230Svisa loongson_cpumask = 0x0f;
4433485d230Svisa ncpusfound = 4;
4443485d230Svisa break;
4453485d230Svisa case 0x3b:
4463485d230Svisa loongson_cpumask = 0xff;
4473485d230Svisa ncpusfound = 8;
4483485d230Svisa break;
4493485d230Svisa #endif
4503485d230Svisa }
4513485d230Svisa
4523485d230Svisa /*
4535acbfd54Svisa * Figure out memory information.
4545acbfd54Svisa * PMON reports it in two chunks, the memory under the 256MB
4555acbfd54Svisa * CKSEG limit, and memory above that limit. We need to do the
4565acbfd54Svisa * math ourselves.
4575acbfd54Svisa */
4585acbfd54Svisa
4595acbfd54Svisa envvar = pmon_getenv("memsize");
4605acbfd54Svisa if (envvar == NULL) {
4615acbfd54Svisa pmon_printf("Could not get memory information"
4625acbfd54Svisa " from the firmware\n");
4635acbfd54Svisa return -1;
4645acbfd54Svisa }
4655acbfd54Svisa memlo = atoi(envvar, 10); /* size in MB */
4665acbfd54Svisa if (memlo < 0 || memlo > 256) {
4675acbfd54Svisa pmon_printf("Incorrect low memory size `%s'\n", envvar);
4685acbfd54Svisa return -1;
4695acbfd54Svisa }
4705acbfd54Svisa
4715acbfd54Svisa /* 3A PMON only reports up to 240MB as low memory */
4725acbfd54Svisa if (memlo >= 240) {
4735acbfd54Svisa envvar = pmon_getenv("highmemsize");
4745acbfd54Svisa if (envvar == NULL)
4755acbfd54Svisa memhi = 0;
4765acbfd54Svisa else
4775acbfd54Svisa memhi = atoi(envvar, 10); /* size in MB */
4785acbfd54Svisa if (memhi < 0 || memhi > (64 * 1024) - 256) {
4795acbfd54Svisa pmon_printf("Incorrect high memory size `%s'\n",
4805acbfd54Svisa envvar);
4815acbfd54Svisa /* better expose the problem than limit to 256MB */
4825acbfd54Svisa return -1;
4835acbfd54Svisa }
4845acbfd54Svisa } else
4855acbfd54Svisa memhi = 0;
4865acbfd54Svisa
4875acbfd54Svisa switch (loongson_ver) {
4885acbfd54Svisa default:
4895acbfd54Svisa #ifdef CPU_LOONGSON2
4905acbfd54Svisa case 0x2e:
4915acbfd54Svisa loongson2e_setup(memlo, memhi);
4925acbfd54Svisa break;
4935acbfd54Svisa case 0x2f:
4945acbfd54Svisa loongson2f_setup(memlo, memhi);
4955acbfd54Svisa break;
4965acbfd54Svisa #endif
4975acbfd54Svisa #ifdef CPU_LOONGSON3
4985acbfd54Svisa case 0x3a:
4995acbfd54Svisa loongson3a_setup(memlo, memhi);
5005acbfd54Svisa break;
5015acbfd54Svisa #endif
5025acbfd54Svisa }
5035acbfd54Svisa
5045acbfd54Svisa return 0;
5055acbfd54Svisa }
506f75298a7Smiod
507f75298a7Smiod /*
5082bf3c060Smiod * Do all the stuff that locore normally does before calling main().
5092bf3c060Smiod * Reset mapping and set up mapping to hardware and init "wired" reg.
5102bf3c060Smiod */
5112bf3c060Smiod
5122bf3c060Smiod vaddr_t
mips_init(uint64_t argc,uint64_t argv,uint64_t envp,uint64_t cv,char * boot_esym)5136f377552Smiod mips_init(uint64_t argc, uint64_t argv, uint64_t envp, uint64_t cv,
514e923757cSmiod char *boot_esym)
5152bf3c060Smiod {
5166f377552Smiod uint32_t prid;
5172bf3c060Smiod vaddr_t xtlb_handler;
5182bf3c060Smiod const char *envvar;
5192bf3c060Smiod int i;
5202bf3c060Smiod
5212bf3c060Smiod extern char start[], edata[], end[];
5222bf3c060Smiod extern char exception[], e_exception[];
5232bf3c060Smiod extern void xtlb_miss;
5242bf3c060Smiod
52539de0dfdSvisa #ifdef MULTIPROCESSOR
52639de0dfdSvisa /*
52739de0dfdSvisa * Set curcpu address on primary processor.
52839de0dfdSvisa */
52939de0dfdSvisa setcurcpu(&cpu_info_primary);
53039de0dfdSvisa #endif
53139de0dfdSvisa
5322bf3c060Smiod /*
5336cfc9e23Smiod * Make sure we can access the extended address space.
5346cfc9e23Smiod * This is not necessary on real hardware, but some emulators
5356cfc9e23Smiod * are not aware of this.
5366cfc9e23Smiod */
5376cfc9e23Smiod setsr(getsr() | SR_KX | SR_UX);
5386cfc9e23Smiod
5396cfc9e23Smiod /*
5402bf3c060Smiod * Clear the compiled BSS segment in OpenBSD code.
5412bf3c060Smiod * PMON is supposed to have done this, though.
5422bf3c060Smiod */
5432bf3c060Smiod
5442bf3c060Smiod bzero(edata, end - edata);
5452bf3c060Smiod
5462bf3c060Smiod /*
5472bf3c060Smiod * Set up early console output.
5482bf3c060Smiod */
5492bf3c060Smiod
5506f377552Smiod prid = cp0_get_prid();
5516f377552Smiod pmon_init((int32_t)argc, (int32_t)argv, (int32_t)envp, (int32_t)cv,
5526f377552Smiod prid);
5532bf3c060Smiod cn_tab = &pmoncons;
5542bf3c060Smiod
5552bf3c060Smiod /*
556e923757cSmiod * Reserve space for the symbol table, if it exists.
5572bf3c060Smiod */
5582bf3c060Smiod
559e923757cSmiod /* Attempt to locate ELF header and symbol table after kernel. */
560e923757cSmiod if (end[0] == ELFMAG0 && end[1] == ELFMAG1 &&
561e923757cSmiod end[2] == ELFMAG2 && end[3] == ELFMAG3) {
562e923757cSmiod /* ELF header exists directly after kernel. */
563e923757cSmiod ssym = end;
564e923757cSmiod esym = boot_esym;
565e923757cSmiod ekern = esym;
566e923757cSmiod } else {
5672bf3c060Smiod ssym = (char *)(vaddr_t)*(int32_t *)end;
5682bf3c060Smiod if (((long)ssym - (long)end) >= 0 &&
5692bf3c060Smiod ((long)ssym - (long)end) <= 0x1000 &&
5702bf3c060Smiod ssym[0] == ELFMAG0 && ssym[1] == ELFMAG1 &&
5712bf3c060Smiod ssym[2] == ELFMAG2 && ssym[3] == ELFMAG3) {
5722bf3c060Smiod /* Pointers exist directly after kernel. */
5732bf3c060Smiod esym = (char *)(vaddr_t)*((int32_t *)end + 1);
5742bf3c060Smiod ekern = esym;
5752bf3c060Smiod } else {
5762bf3c060Smiod /* Pointers aren't setup either... */
577e923757cSmiod ssym = NULL;
578e923757cSmiod esym = NULL;
5792bf3c060Smiod ekern = end;
5802bf3c060Smiod }
581e923757cSmiod }
5822bf3c060Smiod
5832bf3c060Smiod /*
5846f377552Smiod * While the kernel supports other processor types than Loongson,
5856f377552Smiod * we are currently not expecting to run on a system with a
5866f377552Smiod * different processor. Just to be on the safe side, refuse to
5875acbfd54Svisa * run on non-Loongson processors for now.
5886f377552Smiod */
5896f377552Smiod
5906f377552Smiod switch ((prid >> 8) & 0xff) {
5916f377552Smiod case MIPS_LOONGSON2:
5926f377552Smiod switch (prid & 0xff) {
5936f377552Smiod #ifdef CPU_LOONGSON2
5946f377552Smiod #ifdef CPU_LOONGSON2C
5956f377552Smiod case 0x00:
5966f377552Smiod loongson_ver = 0x2c;
5976f377552Smiod break;
5986f377552Smiod #endif
5996f377552Smiod case 0x02:
6006f377552Smiod loongson_ver = 0x2e;
6016f377552Smiod break;
6026f377552Smiod case 0x03:
6036f377552Smiod loongson_ver = 0x2f;
6046f377552Smiod break;
6056f377552Smiod #endif
6066f377552Smiod #ifdef CPU_LOONGSON3
6076f377552Smiod case 0x05:
60800cbda18Svisa case 0x08:
6096f377552Smiod loongson_ver = 0x3a;
6106f377552Smiod break;
6116f377552Smiod #endif
6126f377552Smiod default:
6136f377552Smiod break;
6146f377552Smiod }
6156f377552Smiod }
6166f377552Smiod if (loongson_ver == 0) {
6176f377552Smiod pmon_printf("This kernel doesn't support processor type 0x%x"
6186f377552Smiod ", version %d.%d.\n",
6196f377552Smiod (prid >> 8) & 0xff, (prid >> 4) & 0x0f, prid & 0x0f);
6206f377552Smiod goto unsupported;
6216f377552Smiod }
6226f377552Smiod
6236f377552Smiod /*
6242bf3c060Smiod * Try and figure out what kind of hardware we are.
6252bf3c060Smiod */
6262bf3c060Smiod
6276f377552Smiod switch (pmon_getenvtype()) {
6286f377552Smiod default:
6296f377552Smiod pmon_printf("Unable to figure out "
6306f377552Smiod "firmware environment information!\n");
6316f377552Smiod goto unsupported;
6326f377552Smiod
6336f377552Smiod case PMON_ENVTYPE_EFI:
6346f377552Smiod break;
6356f377552Smiod
6366f377552Smiod case PMON_ENVTYPE_ENVP:
6372bf3c060Smiod envvar = pmon_getenv("systype");
6382bf3c060Smiod if (envvar == NULL) {
6392bf3c060Smiod pmon_printf("Unable to figure out system type!\n");
6402bf3c060Smiod goto unsupported;
6412bf3c060Smiod }
6422bf3c060Smiod if (strcmp(envvar, "Bonito") != 0) {
6432bf3c060Smiod pmon_printf("This kernel doesn't support system type \"%s\".\n",
6442bf3c060Smiod envvar);
6452bf3c060Smiod goto unsupported;
6462bf3c060Smiod }
6472bf3c060Smiod }
6482bf3c060Smiod
6492bf3c060Smiod /*
6502bf3c060Smiod * Try to figure out what particular machine we run on, depending
6512bf3c060Smiod * on the PMON version information.
6522bf3c060Smiod */
6532bf3c060Smiod
6546f377552Smiod if ((sys_platform = loongson_identify(pmon_getenv("Version"),
6556f377552Smiod pmon_getenvtype())) == NULL)
6562bf3c060Smiod goto unsupported;
6572bf3c060Smiod
65851b07be5Smiod hw_vendor = sys_platform->vendor;
65951b07be5Smiod hw_prod = sys_platform->product;
6602bf3c060Smiod pmon_printf("Found %s %s, setting up.\n", hw_vendor, hw_prod);
6612bf3c060Smiod
6622bf3c060Smiod snprintf(cpu_model, sizeof cpu_model, "Loongson %X", loongson_ver);
6632bf3c060Smiod
6642bf3c060Smiod /*
6652bf3c060Smiod * Look at arguments passed to us and compute boothowto.
6662bf3c060Smiod */
6672bf3c060Smiod
6682bf3c060Smiod boothowto = RB_AUTOBOOT;
6692bf3c060Smiod dobootopts(argc);
6702bf3c060Smiod
6715acbfd54Svisa switch (pmon_getenvtype()) {
6725acbfd54Svisa case PMON_ENVTYPE_EFI:
6735acbfd54Svisa if (loongson_efi_setup() != 0)
6742bf3c060Smiod goto unsupported;
6755acbfd54Svisa break;
6762bf3c060Smiod
6775acbfd54Svisa case PMON_ENVTYPE_ENVP:
6785acbfd54Svisa if (loongson_envp_setup() != 0)
6792bf3c060Smiod goto unsupported;
6802bf3c060Smiod break;
6812bf3c060Smiod }
6822bf3c060Smiod
6838a850467Smiod if (sys_platform->setup != NULL)
6848a850467Smiod (*(sys_platform->setup))();
6858a850467Smiod
6862bf3c060Smiod /*
6878a850467Smiod * PMON functions should no longer be used from now on.
6882bf3c060Smiod */
6892bf3c060Smiod
6902bf3c060Smiod /*
6912bf3c060Smiod * Set pagesize to enable use of page macros and functions.
6922bf3c060Smiod * Commit available memory to UVM system.
6932bf3c060Smiod */
6942bf3c060Smiod
6952bf3c060Smiod uvmexp.pagesize = PAGE_SIZE;
6962bf3c060Smiod uvm_setpagesize();
6972bf3c060Smiod
6982bf3c060Smiod for (i = 0; i < MAXMEMSEGS && mem_layout[i].mem_last_page != 0; i++) {
6992bf3c060Smiod uint64_t fp, lp;
7002bf3c060Smiod uint64_t firstkernpage, lastkernpage;
7012bf3c060Smiod paddr_t firstkernpa, lastkernpa;
7022bf3c060Smiod
7032bf3c060Smiod /* kernel is linked in CKSEG0 */
7049b065564Smiod firstkernpa = CKSEG0_TO_PHYS((vaddr_t)start);
7059b065564Smiod lastkernpa = CKSEG0_TO_PHYS((vaddr_t)ekern);
7062bf3c060Smiod
7075acbfd54Svisa firstkernpage = atop(trunc_page(firstkernpa));
7083fc8f127Spirofti #ifdef HIBERNATE
7093fc8f127Spirofti firstkernpage -= HIBERNATE_RESERVED_PAGES;
7103fc8f127Spirofti #endif
7115acbfd54Svisa lastkernpage = atop(round_page(lastkernpa));
7125acbfd54Svisa
7135acbfd54Svisa if (loongson_memlo_alias != 0) {
7145acbfd54Svisa firstkernpage += atop(loongson_memlo_alias);
7155acbfd54Svisa lastkernpage += atop(loongson_memlo_alias);
7165acbfd54Svisa }
7172bf3c060Smiod
7182bf3c060Smiod fp = mem_layout[i].mem_first_page;
7192bf3c060Smiod lp = mem_layout[i].mem_last_page;
7202bf3c060Smiod
7212bf3c060Smiod /* Account for kernel and kernel symbol table. */
7222bf3c060Smiod if (fp >= firstkernpage && lp < lastkernpage)
7232bf3c060Smiod continue; /* In kernel. */
7242bf3c060Smiod
7252bf3c060Smiod if (lp < firstkernpage || fp > lastkernpage) {
7262ce3b4a8Soga uvm_page_physload(fp, lp, fp, lp, 0);
7272bf3c060Smiod continue; /* Outside kernel. */
7282bf3c060Smiod }
7292bf3c060Smiod
7302bf3c060Smiod if (fp >= firstkernpage)
7312bf3c060Smiod fp = lastkernpage;
7322bf3c060Smiod else if (lp < lastkernpage)
7332bf3c060Smiod lp = firstkernpage;
7342bf3c060Smiod else { /* Need to split! */
7352bf3c060Smiod uint64_t xp = firstkernpage;
7362ce3b4a8Soga uvm_page_physload(fp, xp, fp, xp, 0);
7372bf3c060Smiod fp = lastkernpage;
7382bf3c060Smiod }
7392bf3c060Smiod if (lp > fp) {
7402ce3b4a8Soga uvm_page_physload(fp, lp, fp, lp, 0);
7412bf3c060Smiod }
7422bf3c060Smiod }
7432bf3c060Smiod
744c301e791Smiod bootcpu_hwinfo.c0prid = prid;
745c301e791Smiod bootcpu_hwinfo.type = (prid >> 8) & 0xff;
7462bf3c060Smiod /* FPU reports itself as type 5, version 0.1... */
747c301e791Smiod bootcpu_hwinfo.c1prid = bootcpu_hwinfo.c0prid;
7482bf3c060Smiod
7492bf3c060Smiod /*
7506f377552Smiod * Configure cache and tlb.
7512bf3c060Smiod */
7522bf3c060Smiod
7536f377552Smiod switch (loongson_ver) {
7546f377552Smiod default:
7556f377552Smiod #ifdef CPU_LOONGSON2
7566f377552Smiod #ifdef CPU_LOONGSON2C
7576f377552Smiod case 0x2c:
7586f377552Smiod #endif
7596f377552Smiod case 0x2e:
7606f377552Smiod case 0x2f:
7616f377552Smiod bootcpu_hwinfo.tlbsize = 64;
762c1805af1Smiod Loongson2_ConfigCache(curcpu());
763f894e8c8Smiod Loongson2_SyncCache(curcpu());
7646f377552Smiod break;
7656f377552Smiod #endif
7666f377552Smiod #ifdef CPU_LOONGSON3
7676f377552Smiod case 0x3a:
7686f377552Smiod bootcpu_hwinfo.tlbsize =
76954efcfedSvisa 1 + ((cp0_get_config_1() & CONFIG1_MMUSize1) >>
77054efcfedSvisa CONFIG1_MMUSize1_SHIFT);
7716f377552Smiod Loongson3_ConfigCache(curcpu());
7726f377552Smiod Loongson3_SyncCache(curcpu());
7736f377552Smiod break;
7746f377552Smiod #endif
7756f377552Smiod }
7762bf3c060Smiod
777caeb30e1Smiod tlb_init(bootcpu_hwinfo.tlbsize);
7782bf3c060Smiod
7792bf3c060Smiod /*
7802bf3c060Smiod * Get a console, very early but after initial mapping setup.
7812bf3c060Smiod */
7822bf3c060Smiod
7832bf3c060Smiod consinit();
7842bf3c060Smiod printf("Initial setup done, switching console.\n");
7852bf3c060Smiod
7862bf3c060Smiod /*
78713142ff7Smiod * Init message buffer. This is similar to pmap_steal_memory(), but
78813142ff7Smiod * without zeroing the area, to keep the message buffer from the
78913142ff7Smiod * previous kernel run intact, if any.
7902bf3c060Smiod */
79113142ff7Smiod for (i = 0; i < vm_nphysseg; i++) {
79213142ff7Smiod struct vm_physseg *vps = &vm_physmem[i];
79313142ff7Smiod uint npg = atop(round_page(MSGBUFSIZE));
79413142ff7Smiod int j;
7952bf3c060Smiod
79613142ff7Smiod if (vps->avail_start != vps->start ||
79713142ff7Smiod vps->avail_start >= vps->avail_end) {
79813142ff7Smiod continue;
79913142ff7Smiod }
80013142ff7Smiod
80113142ff7Smiod if ((vps->avail_end - vps->avail_start) < npg)
80213142ff7Smiod continue;
80313142ff7Smiod
80413142ff7Smiod msgbufbase = (caddr_t)PHYS_TO_XKPHYS(ptoa(vps->avail_start),
80513142ff7Smiod CCA_CACHED);
80613142ff7Smiod vps->avail_start += npg;
80713142ff7Smiod vps->start += npg;
80813142ff7Smiod
80913142ff7Smiod if (vps->avail_start == vps->end) {
81013142ff7Smiod /* don't bother panicing if nphysseg becomes zero, */
81113142ff7Smiod /* the next pmap_steal_memory() call will. */
81213142ff7Smiod vm_nphysseg--;
81313142ff7Smiod for (j = i; j < vm_nphysseg; j++)
81413142ff7Smiod vm_physmem[j] = vm_physmem[j + 1];
81513142ff7Smiod }
81613142ff7Smiod
81713142ff7Smiod break;
81813142ff7Smiod }
81913142ff7Smiod if (msgbufbase == NULL)
82013142ff7Smiod panic("not enough contiguous memory for message buffer");
8212bf3c060Smiod initmsgbuf(msgbufbase, MSGBUFSIZE);
8222bf3c060Smiod
8232bf3c060Smiod /*
8242bf3c060Smiod * Allocate U page(s) for proc[0], pm_tlbpid 1.
8252bf3c060Smiod */
8262bf3c060Smiod
8272bf3c060Smiod proc0.p_addr = proc0paddr = curcpu()->ci_curprocpaddr =
8282bf3c060Smiod (struct user *)pmap_steal_memory(USPACE, NULL, NULL);
829b43ebd13Smpi proc0.p_md.md_regs = (struct trapframe *)&proc0paddr->u_pcb.pcb_regs;
830caeb30e1Smiod tlb_set_pid(MIN_USER_ASID);
8312bf3c060Smiod
8322bf3c060Smiod /*
8332bf3c060Smiod * Bootstrap VM system.
8342bf3c060Smiod */
8352bf3c060Smiod
8362bf3c060Smiod pmap_bootstrap();
8372bf3c060Smiod
8382bf3c060Smiod /*
8392bf3c060Smiod * Copy down exception vector code.
8402bf3c060Smiod */
8412bf3c060Smiod
8422bf3c060Smiod bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - exception);
8432bf3c060Smiod bcopy(exception, (char *)GEN_EXC_VEC, e_exception - exception);
8442bf3c060Smiod
8452bf3c060Smiod /*
8462bf3c060Smiod * Build proper TLB refill handler trampolines.
847c5cb0eb4Svisa *
848c5cb0eb4Svisa * On Loongson 2F, the XTLB refill exception actually uses
849c5cb0eb4Svisa * the TLB refill vector.
8502bf3c060Smiod */
8512bf3c060Smiod
8522bf3c060Smiod xtlb_handler = (vaddr_t)&xtlb_miss;
8532bf3c060Smiod build_trampoline(TLB_MISS_EXC_VEC, xtlb_handler);
854c5cb0eb4Svisa build_trampoline(XTLB_MISS_EXC_VEC, xtlb_handler);
8552bf3c060Smiod
8562bf3c060Smiod /*
8572bf3c060Smiod * Turn off bootstrap exception vectors.
8582bf3c060Smiod * (this is done by PMON already, but it doesn't hurt to be safe)
8592bf3c060Smiod */
8602bf3c060Smiod
8612bf3c060Smiod setsr(getsr() & ~SR_BOOT_EXC_VEC);
8622bf3c060Smiod proc0.p_md.md_regs->sr = getsr();
8632bf3c060Smiod
8642bf3c060Smiod #ifdef DDB
8652bf3c060Smiod db_machine_init();
8662bf3c060Smiod if (boothowto & RB_KDB)
867e97088d6Smpi db_enter();
8682bf3c060Smiod #endif
8692bf3c060Smiod
8702bf3c060Smiod /*
8712bf3c060Smiod * Return the new kernel stack pointer.
8722bf3c060Smiod */
8732bf3c060Smiod
8742bf3c060Smiod return ((vaddr_t)proc0paddr + USPACE - 64);
8752bf3c060Smiod
8762bf3c060Smiod unsupported:
8772bf3c060Smiod pmon_printf("Halting system.\nPress enter to return to PMON\n");
8782bf3c060Smiod cngetc();
8792bf3c060Smiod return 0; /* causes us to return to pmon */
8802bf3c060Smiod }
8812bf3c060Smiod
8822bf3c060Smiod /*
8832bf3c060Smiod * Decode boot options.
8842bf3c060Smiod */
8852bf3c060Smiod static void
dobootopts(int argc)8862bf3c060Smiod dobootopts(int argc)
8872bf3c060Smiod {
8882bf3c060Smiod const char *arg;
8892bf3c060Smiod const char *cp;
8902bf3c060Smiod int ignore = 1;
8912bf3c060Smiod int i;
8922bf3c060Smiod
8932bf3c060Smiod /*
8942bf3c060Smiod * Parse the boot command line.
8952bf3c060Smiod *
8962bf3c060Smiod * It should be of the form `boot [flags] filename [args]', so we
8972bf3c060Smiod * need to ignore flags to the boot command.
8982bf3c060Smiod * To achieve this, we ignore argc[0], which is the `boot' command
8992bf3c060Smiod * itself, and ignore arguments starting with dashes until the
9002bf3c060Smiod * boot file has been found.
9012bf3c060Smiod */
9022bf3c060Smiod
903ac91c5e9Smiod if (argc != 0) {
904ac91c5e9Smiod arg = pmon_getarg(0);
905ac91c5e9Smiod if (arg == NULL)
906ac91c5e9Smiod return;
907ac91c5e9Smiod /* if `go', not `boot', then no path and command options */
908ac91c5e9Smiod if (*arg == 'g')
909ac91c5e9Smiod ignore = 0;
910ac91c5e9Smiod }
9112bf3c060Smiod for (i = 1; i < argc; i++) {
9122bf3c060Smiod arg = pmon_getarg(i);
9132bf3c060Smiod if (arg == NULL)
9142bf3c060Smiod continue;
9152bf3c060Smiod
916ac91c5e9Smiod /* device path */
917af751efbSvisa if (*arg == '/' || strncmp(arg, "bootduid=", 9) == 0 ||
918af751efbSvisa strncmp(arg, "tftp://", 7) == 0) {
919b9984aa0Sotto if (*pmon_bootp == '\0') {
920b9984aa0Sotto strlcpy(pmon_bootp, arg, sizeof pmon_bootp);
921b9984aa0Sotto parsepmonbp();
922b9984aa0Sotto }
923ac91c5e9Smiod ignore = 0; /* further options are for the kernel */
9242bf3c060Smiod continue;
9252bf3c060Smiod }
9262bf3c060Smiod
927ac91c5e9Smiod /* not an option, or not a kernel option */
928ac91c5e9Smiod if (*arg != '-' || ignore)
9292bf3c060Smiod continue;
9302bf3c060Smiod
9312bf3c060Smiod for (cp = arg + 1; *cp != '\0'; cp++)
9322bf3c060Smiod switch (*cp) {
9332bf3c060Smiod case '-':
9342bf3c060Smiod break;
9352bf3c060Smiod case 'a':
9362bf3c060Smiod boothowto |= RB_ASKNAME;
9372bf3c060Smiod break;
9382bf3c060Smiod case 'c':
9392bf3c060Smiod boothowto |= RB_CONFIG;
9402bf3c060Smiod break;
9412bf3c060Smiod case 'd':
9422bf3c060Smiod boothowto |= RB_KDB;
9432bf3c060Smiod break;
9442bf3c060Smiod case 's':
9452bf3c060Smiod boothowto |= RB_SINGLE;
9462bf3c060Smiod break;
9474b422019Smiod case 'g':
9484b422019Smiod boothowto |= RB_GOODRANDOM;
9494b422019Smiod break;
9502bf3c060Smiod default:
9512bf3c060Smiod pmon_printf("unrecognized option `%c'", *cp);
9522bf3c060Smiod break;
9532bf3c060Smiod }
9542bf3c060Smiod }
9552bf3c060Smiod
9562bf3c060Smiod /*
9572bf3c060Smiod * Consider parsing the `karg' environment variable here too?
9582bf3c060Smiod */
9592bf3c060Smiod }
9602bf3c060Smiod
9612bf3c060Smiod
9622bf3c060Smiod /*
9632bf3c060Smiod * Console initialization: called early on from main, before vm init or startup.
9642bf3c060Smiod * Do enough configuration to choose and initialize a console.
9652bf3c060Smiod */
9662bf3c060Smiod void
consinit()9672bf3c060Smiod consinit()
9682bf3c060Smiod {
9692bf3c060Smiod static int console_ok = 0;
9702bf3c060Smiod
9712bf3c060Smiod if (console_ok == 0) {
9726f377552Smiod cn_tab = NULL;
9732bf3c060Smiod cninit();
9742bf3c060Smiod console_ok = 1;
9752bf3c060Smiod }
9762bf3c060Smiod }
9772bf3c060Smiod
9782bf3c060Smiod /*
9792bf3c060Smiod * cpu_startup: allocate memory for variable-sized tables, initialize CPU, and
9802bf3c060Smiod * do auto-configuration.
9812bf3c060Smiod */
9822bf3c060Smiod void
cpu_startup()9832bf3c060Smiod cpu_startup()
9842bf3c060Smiod {
9852bf3c060Smiod vaddr_t minaddr, maxaddr;
9862bf3c060Smiod
9872bf3c060Smiod /*
9882bf3c060Smiod * Good {morning,afternoon,evening,night}.
9892bf3c060Smiod */
990c268af84Svisa printf("%s", version);
991b7eb4a84Sjsing printf("real mem = %lu (%luMB)\n", ptoa((psize_t)physmem),
992901254b4Sjasper ptoa((psize_t)physmem)/1024/1024);
9932bf3c060Smiod
9942bf3c060Smiod /*
9952bf3c060Smiod * Allocate a submap for exec arguments. This map effectively
9962bf3c060Smiod * limits the number of processes exec'ing at any time.
9972bf3c060Smiod */
9982bf3c060Smiod minaddr = vm_map_min(kernel_map);
9992bf3c060Smiod exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
10002bf3c060Smiod 16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
10012bf3c060Smiod /* Allocate a submap for physio. */
10022bf3c060Smiod phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
10032bf3c060Smiod VM_PHYS_SIZE, 0, FALSE, NULL);
10042bf3c060Smiod
1005b7eb4a84Sjsing printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
10062bf3c060Smiod ptoa(uvmexp.free)/1024/1024);
10072bf3c060Smiod
10082bf3c060Smiod /*
10092bf3c060Smiod * Set up buffers, so they can be used to read disk labels.
10102bf3c060Smiod */
10112bf3c060Smiod bufinit();
10122bf3c060Smiod
10132bf3c060Smiod /*
10142bf3c060Smiod * Configure the system.
10152bf3c060Smiod */
10162bf3c060Smiod if (boothowto & RB_CONFIG) {
10172bf3c060Smiod #ifdef BOOT_CONFIG
10182bf3c060Smiod user_config();
10192bf3c060Smiod #else
10202bf3c060Smiod printf("kernel does not support -c; continuing..\n");
10212bf3c060Smiod #endif
10222bf3c060Smiod }
10232bf3c060Smiod }
10242bf3c060Smiod
1025e5680b7fSgnezdo const struct sysctl_bounded_args cpuctl_vars[] = {
1026e5680b7fSgnezdo { CPU_LIDACTION, &lid_action, 0, 2 },
1027e5680b7fSgnezdo };
1028e5680b7fSgnezdo
10292bf3c060Smiod /*
10302bf3c060Smiod * Machine dependent system variables.
10312bf3c060Smiod */
10322bf3c060Smiod int
cpu_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)1033e262726eSfcambus cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
1034e262726eSfcambus size_t newlen, struct proc *p)
10352bf3c060Smiod {
1036e5680b7fSgnezdo return (sysctl_bounded_arr(cpuctl_vars, nitems(cpuctl_vars),
1037e5680b7fSgnezdo name, namelen, oldp, oldlenp, newp, newlen));
10382bf3c060Smiod }
10392bf3c060Smiod
10402bf3c060Smiod int waittime = -1;
10412bf3c060Smiod
1042ff261808Suebayasi __dead void
boot(int howto)10432bf3c060Smiod boot(int howto)
10442bf3c060Smiod {
104536ffd15aStedu void (*__reset)(void) = (void (*)(void))RESET_EXC_VEC;
104636ffd15aStedu
10473c291078Stedu if ((howto & RB_RESET) != 0)
10483c291078Stedu goto doreset;
10493c291078Stedu
10502bf3c060Smiod if (curproc)
10512bf3c060Smiod savectx(curproc->p_addr, 0);
10522bf3c060Smiod
10532bf3c060Smiod if (cold) {
10542bf3c060Smiod if ((howto & RB_USERREQ) == 0)
10552bf3c060Smiod howto |= RB_HALT;
10562bf3c060Smiod goto haltsys;
10572bf3c060Smiod }
10582bf3c060Smiod
10592bf3c060Smiod boothowto = howto;
10602bf3c060Smiod if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
10612bf3c060Smiod waittime = 0;
10627efda1a1Sderaadt vfs_shutdown(curproc);
10632bf3c060Smiod
10642bf3c060Smiod if ((howto & RB_TIMEBAD) == 0) {
10652bf3c060Smiod resettodr();
10662bf3c060Smiod } else {
10672bf3c060Smiod printf("WARNING: not updating battery clock\n");
10682bf3c060Smiod }
10692bf3c060Smiod }
10707d9ca166Sderaadt if_downall();
10712bf3c060Smiod
10722bf3c060Smiod uvm_shutdown();
10739f43f03fSuebayasi splhigh();
107480ce5a38Smpi cold = 1;
10752bf3c060Smiod
1076b33b2f20Suebayasi if ((howto & RB_DUMP) != 0)
10772bf3c060Smiod dumpsys();
10782bf3c060Smiod
10792bf3c060Smiod haltsys:
1080c16e7cd6Spirofti pci_dopm = 0;
108196f419e1Skettenis config_suspend_all(DVACT_POWERDOWN);
10822bf3c060Smiod
1083b33b2f20Suebayasi if ((howto & RB_HALT) != 0) {
1084b33b2f20Suebayasi if ((howto & RB_POWERDOWN) != 0) {
108551b07be5Smiod if (sys_platform->powerdown != NULL) {
10862bf3c060Smiod printf("System Power Down.\n");
108751b07be5Smiod (*(sys_platform->powerdown))();
108851b07be5Smiod } else {
108951b07be5Smiod printf("System Power Down not supported,"
109051b07be5Smiod " halting system.\n");
1091e1844cd9Smiod }
10922bf3c060Smiod } else
10932bf3c060Smiod printf("System Halt.\n");
10942bf3c060Smiod } else {
10953c291078Stedu doreset:
10962bf3c060Smiod printf("System restart.\n");
10978a850467Smiod if (sys_platform->reset != NULL)
10988a850467Smiod (*(sys_platform->reset))();
10998a850467Smiod (void)disableintr();
11008a850467Smiod tlb_set_wired(0);
11018a850467Smiod tlb_flush(bootcpu_hwinfo.tlbsize);
11022bf3c060Smiod __reset();
11032bf3c060Smiod }
11042bf3c060Smiod
1105de5ed823Stom for (;;)
1106de5ed823Stom continue;
11072bf3c060Smiod /* NOTREACHED */
11082bf3c060Smiod }
11092bf3c060Smiod
11102bf3c060Smiod u_long dumpmag = 0x8fca0101; /* Magic number for savecore. */
11112bf3c060Smiod int dumpsize = 0; /* Also for savecore. */
11122bf3c060Smiod long dumplo = 0;
11132bf3c060Smiod
11142bf3c060Smiod void
dumpconf(void)11152bf3c060Smiod dumpconf(void)
11162bf3c060Smiod {
11172bf3c060Smiod int nblks;
11182bf3c060Smiod
11192bf3c060Smiod if (dumpdev == NODEV ||
11202bf3c060Smiod (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
11212bf3c060Smiod return;
11222bf3c060Smiod if (nblks <= ctod(1))
11232bf3c060Smiod return;
11242bf3c060Smiod
11252bf3c060Smiod dumpsize = ptoa(physmem);
11262bf3c060Smiod if (dumpsize > atop(round_page(dbtob(nblks - dumplo))))
11272bf3c060Smiod dumpsize = atop(round_page(dbtob(nblks - dumplo)));
11282bf3c060Smiod else if (dumplo == 0)
11292bf3c060Smiod dumplo = nblks - btodb(ptoa(physmem));
11302bf3c060Smiod
11312bf3c060Smiod /*
11322bf3c060Smiod * Don't dump on the first page in case the dump device includes a
11332bf3c060Smiod * disk label.
11342bf3c060Smiod */
11352bf3c060Smiod if (dumplo < btodb(PAGE_SIZE))
11362bf3c060Smiod dumplo = btodb(PAGE_SIZE);
11372bf3c060Smiod }
11382bf3c060Smiod
11392bf3c060Smiod void
dumpsys()11402bf3c060Smiod dumpsys()
11412bf3c060Smiod {
11422bf3c060Smiod /* XXX TBD */
11432bf3c060Smiod }
11442bf3c060Smiod
11452bf3c060Smiod /*
11462bf3c060Smiod * Convert an ASCII string into an integer.
11472bf3c060Smiod */
11482bf3c060Smiod static u_long
atoi(const char * s,uint b)11492bf3c060Smiod atoi(const char *s, uint b)
11502bf3c060Smiod {
11512bf3c060Smiod int c;
11522bf3c060Smiod uint base = b, d;
11532bf3c060Smiod int neg = 0;
11542bf3c060Smiod u_long val = 0;
11552bf3c060Smiod
11562bf3c060Smiod if (s == NULL || *s == '\0')
11572bf3c060Smiod return 0;
11582bf3c060Smiod
11592bf3c060Smiod /* Skip spaces if any. */
11602bf3c060Smiod do {
11612bf3c060Smiod c = *s++;
11622bf3c060Smiod } while (c == ' ' || c == '\t');
11632bf3c060Smiod
11642bf3c060Smiod /* Parse sign, allow more than one (compat). */
11652bf3c060Smiod while (c == '-') {
11662bf3c060Smiod neg = !neg;
11672bf3c060Smiod c = *s++;
11682bf3c060Smiod }
11692bf3c060Smiod
11702bf3c060Smiod /* Parse base specification, if any. */
11712bf3c060Smiod if (base == 0 && c == '0') {
11722bf3c060Smiod c = *s++;
11732bf3c060Smiod switch (c) {
11742bf3c060Smiod case 'X':
11752bf3c060Smiod case 'x':
11762bf3c060Smiod base = 16;
11772bf3c060Smiod c = *s++;
11782bf3c060Smiod break;
11792bf3c060Smiod case 'B':
11802bf3c060Smiod case 'b':
11812bf3c060Smiod base = 2;
11822bf3c060Smiod c = *s++;
11832bf3c060Smiod break;
11842bf3c060Smiod default:
11852bf3c060Smiod base = 8;
11862bf3c060Smiod break;
11872bf3c060Smiod }
11882bf3c060Smiod }
11892bf3c060Smiod
11902bf3c060Smiod /* Parse number proper. */
11912bf3c060Smiod for (;;) {
11922bf3c060Smiod if (c >= '0' && c <= '9')
11932bf3c060Smiod d = c - '0';
11942bf3c060Smiod else if (c >= 'a' && c <= 'z')
11952bf3c060Smiod d = c - 'a' + 10;
11962bf3c060Smiod else if (c >= 'A' && c <= 'Z')
11972bf3c060Smiod d = c - 'A' + 10;
11982bf3c060Smiod else
11992bf3c060Smiod break;
12002bf3c060Smiod if (d >= base)
12012bf3c060Smiod break;
12022bf3c060Smiod val *= base;
12032bf3c060Smiod val += d;
12042bf3c060Smiod c = *s++;
12052bf3c060Smiod }
12062bf3c060Smiod
12072bf3c060Smiod return neg ? -val : val;
12082bf3c060Smiod }
12092bf3c060Smiod
12102bf3c060Smiod /*
12112bf3c060Smiod * Early console through pmon routines.
12122bf3c060Smiod */
12132bf3c060Smiod
12142bf3c060Smiod int
pmoncngetc(dev_t dev)12152bf3c060Smiod pmoncngetc(dev_t dev)
12162bf3c060Smiod {
12172bf3c060Smiod /*
12182bf3c060Smiod * PMON does not give us a getc routine. So try to get a whole line
12192bf3c060Smiod * and return it char by char, trying not to lose the \n. Kind
12202bf3c060Smiod * of ugly but should work.
1221e1844cd9Smiod *
1222e1844cd9Smiod * Note that one could theoretically use pmon_read(STDIN, &c, 1)
1223e1844cd9Smiod * but the value of STDIN within PMON is not a constant and there
1224e1844cd9Smiod * does not seem to be a way of letting us know which value to use.
12252bf3c060Smiod */
12262bf3c060Smiod static char buf[1 + PMON_MAXLN];
12272bf3c060Smiod static char *bufpos = buf;
12282bf3c060Smiod int c;
12292bf3c060Smiod
12302bf3c060Smiod if (*bufpos == '\0') {
12312bf3c060Smiod bufpos = buf;
12322bf3c060Smiod if (pmon_gets(buf) == NULL) {
12332bf3c060Smiod /* either an empty line or EOF. assume the former */
12342bf3c060Smiod return (int)'\n';
12352bf3c060Smiod } else {
12362bf3c060Smiod /* put back the \n sign */
12372bf3c060Smiod buf[strlen(buf)] = '\n';
12382bf3c060Smiod }
12392bf3c060Smiod }
12402bf3c060Smiod
12412bf3c060Smiod c = (int)*bufpos++;
12422bf3c060Smiod if (bufpos - buf > PMON_MAXLN) {
12432bf3c060Smiod bufpos = buf;
12442bf3c060Smiod *bufpos = '\0';
12452bf3c060Smiod }
12462bf3c060Smiod
12472bf3c060Smiod return c;
12482bf3c060Smiod }
12492bf3c060Smiod
12502bf3c060Smiod void
pmoncnputc(dev_t dev,int c)12512bf3c060Smiod pmoncnputc(dev_t dev, int c)
12522bf3c060Smiod {
12532bf3c060Smiod if (c == '\n')
12542bf3c060Smiod pmon_printf("\n");
12552bf3c060Smiod else
12562bf3c060Smiod pmon_printf("%c", c);
12572bf3c060Smiod }
125839de0dfdSvisa
1259cae6d111Svisa void
intr_barrier(void * cookie)1260cae6d111Svisa intr_barrier(void *cookie)
1261cae6d111Svisa {
1262cae6d111Svisa sched_barrier(NULL);
1263cae6d111Svisa }
1264cae6d111Svisa
126539de0dfdSvisa #ifdef MULTIPROCESSOR
126639de0dfdSvisa
126739de0dfdSvisa void
hw_cpu_hatch(struct cpu_info * ci)126839de0dfdSvisa hw_cpu_hatch(struct cpu_info *ci)
126939de0dfdSvisa {
127039de0dfdSvisa /*
127139de0dfdSvisa * Set curcpu address on this processor.
127239de0dfdSvisa */
127339de0dfdSvisa setcurcpu(ci);
127439de0dfdSvisa
127539de0dfdSvisa /*
127639de0dfdSvisa * Make sure we can access the extended address space.
127739de0dfdSvisa */
127839de0dfdSvisa setsr(getsr() | SR_KX | SR_UX);
127939de0dfdSvisa
1280f4728271Svisa tlb_init(ci->ci_hw.tlbsize);
1281f4728271Svisa tlb_set_pid(0);
1282f4728271Svisa
128339de0dfdSvisa /*
128439de0dfdSvisa * Turn off bootstrap exception vectors.
128539de0dfdSvisa */
128639de0dfdSvisa setsr(getsr() & ~SR_BOOT_EXC_VEC);
128739de0dfdSvisa
128839de0dfdSvisa /*
128939de0dfdSvisa * Clear out the I and D caches.
129039de0dfdSvisa */
129139de0dfdSvisa switch (loongson_ver) {
129239de0dfdSvisa #ifdef CPU_LOONGSON3
129339de0dfdSvisa case 0x3a:
129439de0dfdSvisa case 0x3b:
129539de0dfdSvisa Loongson3_ConfigCache(ci);
129639de0dfdSvisa Loongson3_SyncCache(ci);
129739de0dfdSvisa break;
129839de0dfdSvisa #endif
129939de0dfdSvisa default:
13004123b6a7Sderaadt panic("%s: unhandled Loongson version %x", __func__,
130139de0dfdSvisa loongson_ver);
130239de0dfdSvisa }
130339de0dfdSvisa
130439de0dfdSvisa (*md_startclock)(ci);
130539de0dfdSvisa
130639de0dfdSvisa mips64_ipi_init();
130739de0dfdSvisa
13085c29d161Svisa ci->ci_flags |= CPUF_RUNNING;
13095c29d161Svisa membar_sync();
13105c29d161Svisa
131139de0dfdSvisa ncpus++;
131239de0dfdSvisa
131339de0dfdSvisa spl0();
131439de0dfdSvisa (void)updateimask(0);
131539de0dfdSvisa
1316*bb00e811Sclaudio sched_toidle();
131739de0dfdSvisa }
131839de0dfdSvisa
131939de0dfdSvisa void
hw_cpu_boot_secondary(struct cpu_info * ci)132039de0dfdSvisa hw_cpu_boot_secondary(struct cpu_info *ci)
132139de0dfdSvisa {
132239de0dfdSvisa sys_platform->boot_secondary_cpu(ci);
132339de0dfdSvisa }
132439de0dfdSvisa
132539de0dfdSvisa int
hw_ipi_intr_establish(int (* func)(void *),u_long cpuid)132639de0dfdSvisa hw_ipi_intr_establish(int (*func)(void *), u_long cpuid)
132739de0dfdSvisa {
132839de0dfdSvisa if (sys_platform->ipi_establish != NULL)
132939de0dfdSvisa return sys_platform->ipi_establish(func, cpuid);
133039de0dfdSvisa else
133139de0dfdSvisa return 0;
133239de0dfdSvisa }
133339de0dfdSvisa
133439de0dfdSvisa void
hw_ipi_intr_set(u_long cpuid)133539de0dfdSvisa hw_ipi_intr_set(u_long cpuid)
133639de0dfdSvisa {
133739de0dfdSvisa sys_platform->ipi_set(cpuid);
133839de0dfdSvisa }
133939de0dfdSvisa
134039de0dfdSvisa void
hw_ipi_intr_clear(u_long cpuid)134139de0dfdSvisa hw_ipi_intr_clear(u_long cpuid)
134239de0dfdSvisa {
134339de0dfdSvisa if (sys_platform->ipi_clear != NULL)
134439de0dfdSvisa sys_platform->ipi_clear(cpuid);
134539de0dfdSvisa }
134639de0dfdSvisa
134739de0dfdSvisa #endif /* MULTIPROCESSOR */
1348