xref: /openbsd/sys/arch/loongson/loongson/machdep.c (revision bb00e811)
1 /*	$OpenBSD: machdep.c,v 1.101 2023/10/24 13:20:10 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2009, 2010, 2014 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 /*
19  * Copyright (c) 2003-2004 Opsycon AB  (www.opsycon.se / www.opsycon.com)
20  *
21  * Redistribution and use in source and binary forms, with or without
22  * modification, are permitted provided that the following conditions
23  * are met:
24  * 1. Redistributions of source code must retain the above copyright
25  *    notice, this list of conditions and the following disclaimer.
26  * 2. Redistributions in binary form must reproduce the above copyright
27  *    notice, this list of conditions and the following disclaimer in the
28  *    documentation and/or other materials provided with the distribution.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
31  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
34  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  */
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/proc.h>
47 #include <sys/buf.h>
48 #include <sys/reboot.h>
49 #include <sys/conf.h>
50 #include <sys/msgbuf.h>
51 #include <sys/tty.h>
52 #include <sys/user.h>
53 #include <sys/exec.h>
54 #include <sys/sysctl.h>
55 #include <sys/mount.h>
56 #include <sys/syscallargs.h>
57 #include <sys/exec_elf.h>
58 #ifdef SYSVSHM
59 #include <sys/shm.h>
60 #endif
61 #ifdef SYSVSEM
62 #include <sys/sem.h>
63 #endif
64 
65 #include <net/if.h>
66 
67 #include <uvm/uvm_extern.h>
68 
69 #include <machine/db_machdep.h>
70 #include <ddb/db_interface.h>
71 
72 #include <machine/autoconf.h>
73 #include <mips64/cache.h>
74 #include <machine/cpu.h>
75 #include <mips64/mips_cpu.h>
76 #include <machine/memconf.h>
77 #include <machine/pmon.h>
78 
79 #ifdef HIBERNATE
80 #include <machine/hibernate_var.h>
81 #endif /* HIBERNATE */
82 
83 #include <dev/cons.h>
84 
85 #include <dev/pci/pcireg.h>
86 #include <dev/pci/pcivar.h>
87 #include <dev/pci/pcidevs.h>
88 
89 /* The following is used externally (sysctl_hw) */
90 char	machine[] = MACHINE;		/* Machine "architecture" */
91 char	cpu_model[30];
92 char	pmon_bootp[80];
93 
94 /*
95  * Even though the system is 64bit, 2E- and 2F-based hardware is constrained
96  * to up to 2G of contiguous physical memory (direct 2GB DMA area). 2Gq- and
97  * 3A-based hardware only supports 32-bit DMA addresses, even though
98  * physical memory may exist beyond 4GB.
99  */
100 struct uvm_constraint_range  dma_constraint = { 0x0, 0xffffffffUL };
101 struct uvm_constraint_range *uvm_md_constraints[] = { NULL };
102 
103 vm_map_t exec_map;
104 vm_map_t phys_map;
105 
106 /*
107  * safepri is a safe priority for sleep to set for a spin-wait
108  * during autoconfiguration or after a panic.
109  */
110 int   safepri = 0;
111 
112 caddr_t	msgbufbase;
113 
114 int	physmem;		/* Max supported memory, changes to actual. */
115 int	ncpu = 1;		/* At least one CPU in the system. */
116 int	nnodes = 1;		/* Number of NUMA nodes, only on 3A. */
117 struct	user *proc0paddr;
118 int	lid_action = 1;
119 int	pwr_action = 1;
120 
121 #ifdef MULTIPROCESSOR
122 uint64_t cpu_spinup_a0;
123 uint64_t cpu_spinup_sp;
124 uint32_t ipi_mask;
125 #endif
126 
127 const struct platform *sys_platform;
128 struct cpu_hwinfo bootcpu_hwinfo;
129 void *loongson_videobios;
130 uint loongson_cpumask = 1;
131 uint loongson_ver;
132 
133 /* Pointers to the start and end of the symbol table. */
134 caddr_t	ssym;
135 caddr_t	esym;
136 caddr_t	ekern;
137 
138 struct phys_mem_desc mem_layout[MAXMEMSEGS];
139 paddr_t	loongson_memlo_alias;
140 
141 pcitag_t (*pci_make_tag_early)(int, int, int);
142 pcireg_t (*pci_conf_read_early)(pcitag_t, int);
143 bus_space_tag_t early_mem_t;
144 bus_space_tag_t early_io_t;
145 
146 static u_long atoi(const char *, uint);
147 static void dobootopts(int);
148 
149 void	dumpsys(void);
150 void	dumpconf(void);
151 extern	void parsepmonbp(void);
152 const struct platform *loongson_identify(const char *, int);
153 vaddr_t	mips_init(uint64_t, uint64_t, uint64_t, uint64_t, char *);
154 
155 extern	void htb_early_setup(void);
156 
157 extern	void loongson2e_setup(u_long, u_long);
158 extern	void loongson2f_setup(u_long, u_long);
159 extern	void loongson3a_setup(u_long, u_long);
160 
161 cons_decl(pmon);
162 
163 struct consdev pmoncons = {
164 	NULL,
165 	NULL,
166 	pmoncngetc,
167 	pmoncnputc,
168 	nullcnpollc,
169 	NULL,
170 	makedev(0, 0),
171 	CN_DEAD
172 };
173 
174 /*
175  * List of supported system types, from the ``Version'' environment
176  * variable.
177  */
178 
179 struct bonito_flavour {
180 	const char *prefix;
181 	const struct platform *platform;
182 };
183 
184 extern const struct platform ebenton_platform;
185 extern const struct platform fuloong_platform;
186 extern const struct platform gdium_platform;
187 extern const struct platform generic2e_platform;
188 extern const struct platform lynloong_platform;
189 extern const struct platform rs780e_platform;
190 extern const struct platform yeeloong_platform;
191 
192 const struct bonito_flavour bonito_flavours[] = {
193 #ifdef CPU_LOONGSON2
194 	/* eBenton EBT700 netbook */
195 	{ "EBT700",	&ebenton_platform },	/* prefix added by user */
196 	/* Lemote Fuloong 2F mini-PC */
197 	{ "LM6002",	&fuloong_platform },	/* dual Ethernet,
198 						   prefix added by user */
199 	{ "LM6003",	&fuloong_platform },
200 	{ "LM6004",	&fuloong_platform },
201 	/* EMTEC Gdium Liberty 1000 */
202 	{ "Gdium",	&gdium_platform },
203 	/* Lemote Yeeloong 8.9" netbook */
204 	{ "LM8089",	&yeeloong_platform },
205 	/* supposedly Lemote Yeeloong 10.1" netbook, but those found so far
206 	   report themselves as LM8089 */
207 	{ "LM8101",	&yeeloong_platform },
208 	/* Lemote Lynloong all-in-one computer */
209 	{ "LM9001",	&lynloong_platform },
210 	{ "LM9002",	&lynloong_platform },
211 	{ "LM9003",	&lynloong_platform },
212 	/* Lemote Lynloong all-in-one computer, Xueloong edition */
213 	{ "LM9013",	&lynloong_platform },
214 #endif
215 #ifdef CPU_LOONGSON3
216 	/* Laptops */
217 	{ "A1004",	&rs780e_platform },	/* 3A */
218 	{ "A1201",	&rs780e_platform },	/* 2Gq */
219 	/* Lemote Xinghuo 6100 (mini-ITX PC) */
220 	{ "A1101",	&rs780e_platform },	/* 3A */
221 	/* All-in-one PC */
222 	{ "A1205",	&rs780e_platform },	/* 2Gq */
223 #endif
224 	{ NULL }
225 };
226 
227 /*
228  * Try to figure out what particular machine we run on, depending on the
229  * scarce PMON version information and whatever else we can figure.
230  */
231 const struct platform *
loongson_identify(const char * version,int envtype)232 loongson_identify(const char *version, int envtype)
233 {
234 	const struct bonito_flavour *f;
235 
236 	switch (envtype) {
237 #ifdef CPU_LOONGSON3
238 	case PMON_ENVTYPE_EFI:
239 		if (loongson_ver == 0x3a || loongson_ver == 0x3b) {
240 			pcitag_t tag;
241 			pcireg_t id;
242 
243 			htb_early_setup();
244 
245 			/* Determine platform by host bridge. */
246 			tag = pci_make_tag_early(0, 0, 0);
247 			id = pci_conf_read_early(tag, PCI_ID_REG);
248 			switch (id) {
249 			case PCI_ID_CODE(PCI_VENDOR_AMD,
250 			    PCI_PRODUCT_AMD_RS780_HB):
251 				return &rs780e_platform;
252 			}
253 		}
254 		pmon_printf("Unable to figure out model!\n");
255 		return NULL;
256 #endif
257 
258 	default:
259 	case PMON_ENVTYPE_ENVP:
260 		if (version == NULL) {
261 #ifdef CPU_LOONGSON2
262 			/*
263 		 	 * If there is no `Version' variable, we expect to be
264 			 * running on a 2E system, use the generic code and
265 			 * hope for the best.
266 		 	 */
267 			if (loongson_ver == 0x2e)
268 				return &generic2e_platform;
269 #endif
270 			pmon_printf("Unable to figure out model!\n");
271 			return NULL;
272 		}
273 
274 		for (f = bonito_flavours; f->prefix != NULL; f++)
275 			if (strncmp(version, f->prefix, strlen(f->prefix)) == 0)
276 				return f->platform;
277 
278 #ifdef CPU_LOONGSON2
279 		/*
280 	 	 * Early Lemote designs shipped without a model prefix.
281 	 	 *
282 	 	 * We can reasonably expect these to be close enough to either
283 		 * the first generation Fuloong 2F design (LM6002), or the 7
284 		 * inch first netbook model; we can tell them apart by looking
285 		 * at which video chip they embed.
286 	 	 *
287 	 	 * Note that this is only worth doing if the version string is
288 	 	 * 1.2.something (1.3 onwards are expected to have a model
289 		 * prefix, and there are currently no reports of 1.1 and
290 	 	 * below being 2F systems).
291 	 	 *
292 	 	 * LM6002 users are encouraged to add the system model prefix to
293 	 	 * the `Version' variable.
294 	 	 */
295 		if (strncmp(version, "1.2.", 4) == 0) {
296 			const struct platform *p = NULL;
297 			pcitag_t tag;
298 			pcireg_t id, class;
299 			int dev;
300 
301 			pmon_printf("No model prefix "
302 			    "in version string \"%s\".\n", version);
303 
304 			if (loongson_ver == 0x2f)
305 				for (dev = 0; dev < 32; dev++) {
306 					tag = pci_make_tag_early(0, dev, 0);
307 					id = pci_conf_read_early(tag,
308 					    PCI_ID_REG);
309 					if (id == 0 || PCI_VENDOR(id) ==
310 					    PCI_VENDOR_INVALID)
311 						continue;
312 
313 					/*
314 					 * No need to check for
315 					 * DEVICE_IS_VGA_PCI here, since we
316 					 * expect a linear framebuffer.
317 					 */
318 					class = pci_conf_read_early(tag,
319 					    PCI_CLASS_REG);
320 					if (PCI_CLASS(class) !=
321 					    PCI_CLASS_DISPLAY ||
322 					    (PCI_SUBCLASS(class) !=
323 					     PCI_SUBCLASS_DISPLAY_VGA &&
324 					     PCI_SUBCLASS(class) !=
325 					     PCI_SUBCLASS_DISPLAY_MISC))
326 						continue;
327 
328 					switch (id) {
329 					case PCI_ID_CODE(PCI_VENDOR_SIS,
330 				    	    PCI_PRODUCT_SIS_315PRO_VGA):
331 						p = &fuloong_platform;
332 						break;
333 					case PCI_ID_CODE(PCI_VENDOR_SMI,
334 			    		    PCI_PRODUCT_SMI_SM712):
335 						p = &ebenton_platform;
336 						break;
337 					}
338 				}
339 
340 			if (p != NULL) {
341 				pmon_printf("Attempting to match as "
342 				    "%s %s\n", p->vendor, p->product);
343 				return p;
344 			}
345 		}
346 #endif
347 	}
348 
349 	pmon_printf("This kernel doesn't support model \"%s\"." "\n", version);
350 	return NULL;
351 }
352 
353 /*
354  * Figure out machine parameters using the 'EFI-like' interface.
355  */
356 int
loongson_efi_setup(void)357 loongson_efi_setup(void)
358 {
359 	struct pmon_env_mem_entry entry;
360 	const struct pmon_env_cpu *cpuenv;
361 	const struct pmon_env_mem *mem;
362 	paddr_t fp, lp;
363 	uint32_t i, ncpus, seg = 0;
364 
365 	cpuenv = pmon_get_env_cpu();
366 	bootcpu_hwinfo.clock = cpuenv->speed;
367 
368 	/*
369 	 * Get available CPUs.
370 	 */
371 
372 	ncpus = cpuenv->ncpus;
373 	if (ncpus > LOONGSON_MAXCPUS)
374 		ncpus = LOONGSON_MAXCPUS;
375 
376 	loongson_cpumask = (1u << ncpus) - 1;
377 	loongson_cpumask &= ~(uint)cpuenv->reserved_cores;
378 
379 	ncpusfound = 0;
380 	for (i = 0; i < ncpus; i++) {
381 		if (ISSET(loongson_cpumask, 1u << i))
382 			ncpusfound++;
383 	}
384 
385 	/*
386 	 * Get free memory segments.
387 	 */
388 
389 	mem = pmon_get_env_mem();
390 	physmem = 0;
391 	for (i = 0; i < mem->nentries && seg < MAXMEMSEGS; i++) {
392 		memcpy(&entry, &mem->mem_map[i], sizeof(entry));
393 		if (entry.node != 0 ||
394 		    (entry.type != PMON_MEM_SYSTEM_LOW &&
395 		     entry.type != PMON_MEM_SYSTEM_HIGH))
396 			continue;
397 		fp = atop(entry.address);
398 		lp = atop(entry.address + ((uint64_t)entry.size << 20));
399 		if (lp > atop(pfn_to_pad(PG_FRAME)) + 1)
400 			lp = atop(pfn_to_pad(PG_FRAME)) + 1;
401 		if (fp >= lp)
402 			continue;
403 		physmem += lp - fp;
404 		mem_layout[seg].mem_first_page = fp;
405 		mem_layout[seg].mem_last_page = lp;
406 		seg++;
407 	}
408 
409 	return 0;
410 }
411 
412 /*
413  * Figure out machine parameters using the PMON interface.
414  */
415 int
loongson_envp_setup(void)416 loongson_envp_setup(void)
417 {
418 	const char *envvar;
419 	u_long cpuspeed, memlo, memhi;
420 
421 	/*
422 	 * Figure out processor clock speed.
423 	 * Hopefully the processor speed, in Hertz, will not overflow
424 	 * uint32_t...
425 	 */
426 
427 	cpuspeed = 0;
428 	envvar = pmon_getenv("cpuclock");
429 	if (envvar != NULL)
430 		cpuspeed = atoi(envvar, 10);	/* speed in Hz */
431 	if (cpuspeed < 100 * 1000000)
432 		cpuspeed = 797000000;  /* Reasonable default */
433 	bootcpu_hwinfo.clock = cpuspeed;
434 
435 	/*
436 	 * Guess the available CPUs.
437 	 */
438 
439 	switch (loongson_ver) {
440 #ifdef CPU_LOONGSON3
441 	case 0x3a:
442 		loongson_cpumask = 0x0f;
443 		ncpusfound = 4;
444 		break;
445 	case 0x3b:
446 		loongson_cpumask = 0xff;
447 		ncpusfound = 8;
448 		break;
449 #endif
450 	}
451 
452 	/*
453 	 * Figure out memory information.
454 	 * PMON reports it in two chunks, the memory under the 256MB
455 	 * CKSEG limit, and memory above that limit.  We need to do the
456 	 * math ourselves.
457 	 */
458 
459 	envvar = pmon_getenv("memsize");
460 	if (envvar == NULL) {
461 		pmon_printf("Could not get memory information"
462 		    " from the firmware\n");
463 		return -1;
464 	}
465 	memlo = atoi(envvar, 10);	/* size in MB */
466 	if (memlo < 0 || memlo > 256) {
467 		pmon_printf("Incorrect low memory size `%s'\n", envvar);
468 		return -1;
469 	}
470 
471 	/* 3A PMON only reports up to 240MB as low memory */
472 	if (memlo >= 240) {
473 		envvar = pmon_getenv("highmemsize");
474 		if (envvar == NULL)
475 			memhi = 0;
476 		else
477 			memhi = atoi(envvar, 10);	/* size in MB */
478 		if (memhi < 0 || memhi > (64 * 1024) - 256) {
479 			pmon_printf("Incorrect high memory size `%s'\n",
480 			    envvar);
481 			/* better expose the problem than limit to 256MB */
482 			return -1;
483 		}
484 	} else
485 		memhi = 0;
486 
487 	switch (loongson_ver) {
488 	default:
489 #ifdef CPU_LOONGSON2
490 	case 0x2e:
491 		loongson2e_setup(memlo, memhi);
492 		break;
493 	case 0x2f:
494 		loongson2f_setup(memlo, memhi);
495 		break;
496 #endif
497 #ifdef CPU_LOONGSON3
498 	case 0x3a:
499 		loongson3a_setup(memlo, memhi);
500 		break;
501 #endif
502 	}
503 
504 	return 0;
505 }
506 
507 /*
508  * Do all the stuff that locore normally does before calling main().
509  * Reset mapping and set up mapping to hardware and init "wired" reg.
510  */
511 
512 vaddr_t
mips_init(uint64_t argc,uint64_t argv,uint64_t envp,uint64_t cv,char * boot_esym)513 mips_init(uint64_t argc, uint64_t argv, uint64_t envp, uint64_t cv,
514     char *boot_esym)
515 {
516 	uint32_t prid;
517 	vaddr_t xtlb_handler;
518 	const char *envvar;
519 	int i;
520 
521 	extern char start[], edata[], end[];
522 	extern char exception[], e_exception[];
523 	extern void xtlb_miss;
524 
525 #ifdef MULTIPROCESSOR
526 	/*
527 	 * Set curcpu address on primary processor.
528 	 */
529 	setcurcpu(&cpu_info_primary);
530 #endif
531 
532 	/*
533 	 * Make sure we can access the extended address space.
534 	 * This is not necessary on real hardware, but some emulators
535 	 * are not aware of this.
536 	 */
537 	setsr(getsr() | SR_KX | SR_UX);
538 
539 	/*
540 	 * Clear the compiled BSS segment in OpenBSD code.
541 	 * PMON is supposed to have done this, though.
542 	 */
543 
544 	bzero(edata, end - edata);
545 
546 	/*
547 	 * Set up early console output.
548 	 */
549 
550 	prid = cp0_get_prid();
551 	pmon_init((int32_t)argc, (int32_t)argv, (int32_t)envp, (int32_t)cv,
552 	    prid);
553 	cn_tab = &pmoncons;
554 
555 	/*
556 	 * Reserve space for the symbol table, if it exists.
557 	 */
558 
559 	/* Attempt to locate ELF header and symbol table after kernel. */
560 	if (end[0] == ELFMAG0 && end[1] == ELFMAG1 &&
561 	    end[2] == ELFMAG2 && end[3] == ELFMAG3) {
562 		/* ELF header exists directly after kernel. */
563 		ssym = end;
564 		esym = boot_esym;
565 		ekern = esym;
566 	} else {
567 		ssym = (char *)(vaddr_t)*(int32_t *)end;
568 		if (((long)ssym - (long)end) >= 0 &&
569 		    ((long)ssym - (long)end) <= 0x1000 &&
570 		    ssym[0] == ELFMAG0 && ssym[1] == ELFMAG1 &&
571 		    ssym[2] == ELFMAG2 && ssym[3] == ELFMAG3) {
572 			/* Pointers exist directly after kernel. */
573 			esym = (char *)(vaddr_t)*((int32_t *)end + 1);
574 			ekern = esym;
575 		} else {
576 			/* Pointers aren't setup either... */
577 			ssym = NULL;
578 			esym = NULL;
579 			ekern = end;
580 		}
581 	}
582 
583 	/*
584 	 * While the kernel supports other processor types than Loongson,
585 	 * we are currently not expecting to run on a system with a
586 	 * different processor.  Just to be on the safe side, refuse to
587 	 * run on non-Loongson processors for now.
588 	 */
589 
590 	switch ((prid >> 8) & 0xff) {
591 	case MIPS_LOONGSON2:
592 		switch (prid & 0xff) {
593 #ifdef CPU_LOONGSON2
594 #ifdef CPU_LOONGSON2C
595 		case 0x00:
596 			loongson_ver = 0x2c;
597 			break;
598 #endif
599 		case 0x02:
600 			loongson_ver = 0x2e;
601 			break;
602 		case 0x03:
603 			loongson_ver = 0x2f;
604 			break;
605 #endif
606 #ifdef CPU_LOONGSON3
607 		case 0x05:
608 		case 0x08:
609 			loongson_ver = 0x3a;
610 			break;
611 #endif
612 		default:
613 			break;
614 		}
615 	}
616 	if (loongson_ver == 0) {
617 		pmon_printf("This kernel doesn't support processor type 0x%x"
618 		    ", version %d.%d.\n",
619 		    (prid >> 8) & 0xff, (prid >> 4) & 0x0f, prid & 0x0f);
620 		goto unsupported;
621 	}
622 
623 	/*
624 	 * Try and figure out what kind of hardware we are.
625 	 */
626 
627 	switch (pmon_getenvtype()) {
628 	default:
629 		pmon_printf("Unable to figure out "
630 		    "firmware environment information!\n");
631 		goto unsupported;
632 
633 	case PMON_ENVTYPE_EFI:
634 		break;
635 
636 	case PMON_ENVTYPE_ENVP:
637 		envvar = pmon_getenv("systype");
638 		if (envvar == NULL) {
639 			pmon_printf("Unable to figure out system type!\n");
640 			goto unsupported;
641 		}
642 		if (strcmp(envvar, "Bonito") != 0) {
643 			pmon_printf("This kernel doesn't support system type \"%s\".\n",
644 		    	envvar);
645 			goto unsupported;
646 		}
647 	}
648 
649 	/*
650 	 * Try to figure out what particular machine we run on, depending
651 	 * on the PMON version information.
652 	 */
653 
654 	if ((sys_platform = loongson_identify(pmon_getenv("Version"),
655 	    pmon_getenvtype())) == NULL)
656 		goto unsupported;
657 
658 	hw_vendor = sys_platform->vendor;
659 	hw_prod = sys_platform->product;
660 	pmon_printf("Found %s %s, setting up.\n", hw_vendor, hw_prod);
661 
662 	snprintf(cpu_model, sizeof cpu_model, "Loongson %X", loongson_ver);
663 
664 	/*
665 	 * Look at arguments passed to us and compute boothowto.
666 	 */
667 
668 	boothowto = RB_AUTOBOOT;
669 	dobootopts(argc);
670 
671 	switch (pmon_getenvtype()) {
672 	case PMON_ENVTYPE_EFI:
673 		if (loongson_efi_setup() != 0)
674 			goto unsupported;
675 		break;
676 
677 	case PMON_ENVTYPE_ENVP:
678 		if (loongson_envp_setup() != 0)
679 			goto unsupported;
680 		break;
681 	}
682 
683 	if (sys_platform->setup != NULL)
684 		(*(sys_platform->setup))();
685 
686 	/*
687 	 * PMON functions should no longer be used from now on.
688 	 */
689 
690 	/*
691 	 * Set pagesize to enable use of page macros and functions.
692 	 * Commit available memory to UVM system.
693 	 */
694 
695 	uvmexp.pagesize = PAGE_SIZE;
696 	uvm_setpagesize();
697 
698 	for (i = 0; i < MAXMEMSEGS && mem_layout[i].mem_last_page != 0; i++) {
699 		uint64_t fp, lp;
700 		uint64_t firstkernpage, lastkernpage;
701 		paddr_t firstkernpa, lastkernpa;
702 
703 		/* kernel is linked in CKSEG0 */
704 		firstkernpa = CKSEG0_TO_PHYS((vaddr_t)start);
705 		lastkernpa = CKSEG0_TO_PHYS((vaddr_t)ekern);
706 
707 		firstkernpage = atop(trunc_page(firstkernpa));
708 #ifdef HIBERNATE
709 		firstkernpage -= HIBERNATE_RESERVED_PAGES;
710 #endif
711 		lastkernpage = atop(round_page(lastkernpa));
712 
713 		if (loongson_memlo_alias != 0) {
714 			firstkernpage += atop(loongson_memlo_alias);
715 			lastkernpage += atop(loongson_memlo_alias);
716 		}
717 
718 		fp = mem_layout[i].mem_first_page;
719 		lp = mem_layout[i].mem_last_page;
720 
721 		/* Account for kernel and kernel symbol table. */
722 		if (fp >= firstkernpage && lp < lastkernpage)
723 			continue;	/* In kernel. */
724 
725 		if (lp < firstkernpage || fp > lastkernpage) {
726 			uvm_page_physload(fp, lp, fp, lp, 0);
727 			continue;	/* Outside kernel. */
728 		}
729 
730 		if (fp >= firstkernpage)
731 			fp = lastkernpage;
732 		else if (lp < lastkernpage)
733 			lp = firstkernpage;
734 		else { /* Need to split! */
735 			uint64_t xp = firstkernpage;
736 			uvm_page_physload(fp, xp, fp, xp, 0);
737 			fp = lastkernpage;
738 		}
739 		if (lp > fp) {
740 			uvm_page_physload(fp, lp, fp, lp, 0);
741 		}
742 	}
743 
744 	bootcpu_hwinfo.c0prid = prid;
745 	bootcpu_hwinfo.type = (prid >> 8) & 0xff;
746 	/* FPU reports itself as type 5, version 0.1... */
747 	bootcpu_hwinfo.c1prid = bootcpu_hwinfo.c0prid;
748 
749 	/*
750 	 * Configure cache and tlb.
751 	 */
752 
753 	switch (loongson_ver) {
754 	default:
755 #ifdef CPU_LOONGSON2
756 #ifdef CPU_LOONGSON2C
757 	case 0x2c:
758 #endif
759 	case 0x2e:
760 	case 0x2f:
761 		bootcpu_hwinfo.tlbsize = 64;
762 		Loongson2_ConfigCache(curcpu());
763 		Loongson2_SyncCache(curcpu());
764 		break;
765 #endif
766 #ifdef CPU_LOONGSON3
767 	case 0x3a:
768 		bootcpu_hwinfo.tlbsize =
769 		    1 + ((cp0_get_config_1() & CONFIG1_MMUSize1) >>
770 		    CONFIG1_MMUSize1_SHIFT);
771 		Loongson3_ConfigCache(curcpu());
772 		Loongson3_SyncCache(curcpu());
773 		break;
774 #endif
775 	}
776 
777 	tlb_init(bootcpu_hwinfo.tlbsize);
778 
779 	/*
780 	 * Get a console, very early but after initial mapping setup.
781 	 */
782 
783 	consinit();
784 	printf("Initial setup done, switching console.\n");
785 
786 	/*
787 	 * Init message buffer. This is similar to pmap_steal_memory(), but
788 	 * without zeroing the area, to keep the message buffer from the
789 	 * previous kernel run intact, if any.
790 	 */
791 	for (i = 0; i < vm_nphysseg; i++) {
792 		struct vm_physseg *vps = &vm_physmem[i];
793 		uint npg = atop(round_page(MSGBUFSIZE));
794 		int j;
795 
796 		if (vps->avail_start != vps->start ||
797 		    vps->avail_start >= vps->avail_end) {
798 			continue;
799 		}
800 
801 		if ((vps->avail_end - vps->avail_start) < npg)
802 			continue;
803 
804 		msgbufbase = (caddr_t)PHYS_TO_XKPHYS(ptoa(vps->avail_start),
805 		    CCA_CACHED);
806 		vps->avail_start += npg;
807 		vps->start += npg;
808 
809 		if (vps->avail_start == vps->end) {
810 			/* don't bother panicing if nphysseg becomes zero, */
811 			/* the next pmap_steal_memory() call will. */
812 			vm_nphysseg--;
813 			for (j = i; j < vm_nphysseg; j++)
814 				vm_physmem[j] = vm_physmem[j + 1];
815 		}
816 
817 		break;
818 	}
819 	if (msgbufbase == NULL)
820 		panic("not enough contiguous memory for message buffer");
821 	initmsgbuf(msgbufbase, MSGBUFSIZE);
822 
823 	/*
824 	 * Allocate U page(s) for proc[0], pm_tlbpid 1.
825 	 */
826 
827 	proc0.p_addr = proc0paddr = curcpu()->ci_curprocpaddr =
828 	    (struct user *)pmap_steal_memory(USPACE, NULL, NULL);
829 	proc0.p_md.md_regs = (struct trapframe *)&proc0paddr->u_pcb.pcb_regs;
830 	tlb_set_pid(MIN_USER_ASID);
831 
832 	/*
833 	 * Bootstrap VM system.
834 	 */
835 
836 	pmap_bootstrap();
837 
838 	/*
839 	 * Copy down exception vector code.
840 	 */
841 
842 	bcopy(exception, (char *)CACHE_ERR_EXC_VEC, e_exception - exception);
843 	bcopy(exception, (char *)GEN_EXC_VEC, e_exception - exception);
844 
845 	/*
846 	 * Build proper TLB refill handler trampolines.
847 	 *
848 	 * On Loongson 2F, the XTLB refill exception actually uses
849 	 * the TLB refill vector.
850 	 */
851 
852 	xtlb_handler = (vaddr_t)&xtlb_miss;
853 	build_trampoline(TLB_MISS_EXC_VEC, xtlb_handler);
854 	build_trampoline(XTLB_MISS_EXC_VEC, xtlb_handler);
855 
856 	/*
857 	 * Turn off bootstrap exception vectors.
858 	 * (this is done by PMON already, but it doesn't hurt to be safe)
859 	 */
860 
861 	setsr(getsr() & ~SR_BOOT_EXC_VEC);
862 	proc0.p_md.md_regs->sr = getsr();
863 
864 #ifdef DDB
865 	db_machine_init();
866 	if (boothowto & RB_KDB)
867 		db_enter();
868 #endif
869 
870 	/*
871 	 * Return the new kernel stack pointer.
872 	 */
873 
874 	return ((vaddr_t)proc0paddr + USPACE - 64);
875 
876 unsupported:
877 	pmon_printf("Halting system.\nPress enter to return to PMON\n");
878 	cngetc();
879 	return 0;	/* causes us to return to pmon */
880 }
881 
882 /*
883  * Decode boot options.
884  */
885 static void
dobootopts(int argc)886 dobootopts(int argc)
887 {
888 	const char *arg;
889 	const char *cp;
890 	int ignore = 1;
891 	int i;
892 
893 	/*
894 	 * Parse the boot command line.
895 	 *
896 	 * It should be of the form `boot [flags] filename [args]', so we
897 	 * need to ignore flags to the boot command.
898 	 * To achieve this, we ignore argc[0], which is the `boot' command
899 	 * itself, and ignore arguments starting with dashes until the
900 	 * boot file has been found.
901 	 */
902 
903 	if (argc != 0) {
904 		arg = pmon_getarg(0);
905 		if (arg == NULL)
906 			return;
907 		/* if `go', not `boot', then no path and command options */
908 		if (*arg == 'g')
909 			ignore = 0;
910 	}
911 	for (i = 1; i < argc; i++) {
912 		arg = pmon_getarg(i);
913 		if (arg == NULL)
914 			continue;
915 
916 		/* device path */
917 		if (*arg == '/' || strncmp(arg, "bootduid=", 9) == 0 ||
918 		    strncmp(arg, "tftp://", 7) == 0) {
919 			if (*pmon_bootp == '\0') {
920 				strlcpy(pmon_bootp, arg, sizeof pmon_bootp);
921 				parsepmonbp();
922 			}
923 			ignore = 0;	/* further options are for the kernel */
924 			continue;
925 		}
926 
927 		/* not an option, or not a kernel option */
928 		if (*arg != '-' || ignore)
929 			continue;
930 
931 		for (cp = arg + 1; *cp != '\0'; cp++)
932 			switch (*cp) {
933 			case '-':
934 				break;
935 			case 'a':
936 				boothowto |= RB_ASKNAME;
937 				break;
938 			case 'c':
939 				boothowto |= RB_CONFIG;
940 				break;
941 			case 'd':
942 				boothowto |= RB_KDB;
943 				break;
944 			case 's':
945 				boothowto |= RB_SINGLE;
946 				break;
947 			case 'g':
948 				boothowto |= RB_GOODRANDOM;
949 				break;
950 			default:
951 				pmon_printf("unrecognized option `%c'", *cp);
952 				break;
953 			}
954 	}
955 
956 	/*
957 	 * Consider parsing the `karg' environment variable here too?
958 	 */
959 }
960 
961 
962 /*
963  * Console initialization: called early on from main, before vm init or startup.
964  * Do enough configuration to choose and initialize a console.
965  */
966 void
consinit()967 consinit()
968 {
969 	static int console_ok = 0;
970 
971 	if (console_ok == 0) {
972 		cn_tab = NULL;
973 		cninit();
974 		console_ok = 1;
975 	}
976 }
977 
978 /*
979  * cpu_startup: allocate memory for variable-sized tables, initialize CPU, and
980  * do auto-configuration.
981  */
982 void
cpu_startup()983 cpu_startup()
984 {
985 	vaddr_t minaddr, maxaddr;
986 
987 	/*
988 	 * Good {morning,afternoon,evening,night}.
989 	 */
990 	printf("%s", version);
991 	printf("real mem = %lu (%luMB)\n", ptoa((psize_t)physmem),
992 	    ptoa((psize_t)physmem)/1024/1024);
993 
994 	/*
995 	 * Allocate a submap for exec arguments. This map effectively
996 	 * limits the number of processes exec'ing at any time.
997 	 */
998 	minaddr = vm_map_min(kernel_map);
999 	exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
1000 	    16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
1001 	/* Allocate a submap for physio. */
1002 	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
1003 	    VM_PHYS_SIZE, 0, FALSE, NULL);
1004 
1005 	printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free),
1006 	    ptoa(uvmexp.free)/1024/1024);
1007 
1008 	/*
1009 	 * Set up buffers, so they can be used to read disk labels.
1010 	 */
1011 	bufinit();
1012 
1013 	/*
1014 	 * Configure the system.
1015 	 */
1016 	if (boothowto & RB_CONFIG) {
1017 #ifdef BOOT_CONFIG
1018 		user_config();
1019 #else
1020 		printf("kernel does not support -c; continuing..\n");
1021 #endif
1022 	}
1023 }
1024 
1025 const struct sysctl_bounded_args cpuctl_vars[] = {
1026 	{ CPU_LIDACTION, &lid_action, 0, 2 },
1027 };
1028 
1029 /*
1030  * Machine dependent system variables.
1031  */
1032 int
cpu_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen,struct proc * p)1033 cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
1034     size_t newlen, struct proc *p)
1035 {
1036 	return (sysctl_bounded_arr(cpuctl_vars, nitems(cpuctl_vars),
1037 	    name, namelen, oldp, oldlenp, newp, newlen));
1038 }
1039 
1040 int	waittime = -1;
1041 
1042 __dead void
boot(int howto)1043 boot(int howto)
1044 {
1045 	void (*__reset)(void) = (void (*)(void))RESET_EXC_VEC;
1046 
1047 	if ((howto & RB_RESET) != 0)
1048 		goto doreset;
1049 
1050 	if (curproc)
1051 		savectx(curproc->p_addr, 0);
1052 
1053 	if (cold) {
1054 		if ((howto & RB_USERREQ) == 0)
1055 			howto |= RB_HALT;
1056 		goto haltsys;
1057 	}
1058 
1059 	boothowto = howto;
1060 	if ((howto & RB_NOSYNC) == 0 && waittime < 0) {
1061 		waittime = 0;
1062 		vfs_shutdown(curproc);
1063 
1064 		if ((howto & RB_TIMEBAD) == 0) {
1065 			resettodr();
1066 		} else {
1067 			printf("WARNING: not updating battery clock\n");
1068 		}
1069 	}
1070 	if_downall();
1071 
1072 	uvm_shutdown();
1073 	splhigh();
1074 	cold = 1;
1075 
1076 	if ((howto & RB_DUMP) != 0)
1077 		dumpsys();
1078 
1079 haltsys:
1080 	pci_dopm = 0;
1081 	config_suspend_all(DVACT_POWERDOWN);
1082 
1083 	if ((howto & RB_HALT) != 0) {
1084 		if ((howto & RB_POWERDOWN) != 0) {
1085 			if (sys_platform->powerdown != NULL) {
1086 				printf("System Power Down.\n");
1087 				(*(sys_platform->powerdown))();
1088 			} else {
1089 				printf("System Power Down not supported,"
1090 				    " halting system.\n");
1091 			}
1092 		} else
1093 			printf("System Halt.\n");
1094 	} else {
1095 doreset:
1096 		printf("System restart.\n");
1097 		if (sys_platform->reset != NULL)
1098 			(*(sys_platform->reset))();
1099 		(void)disableintr();
1100 		tlb_set_wired(0);
1101 		tlb_flush(bootcpu_hwinfo.tlbsize);
1102 		__reset();
1103 	}
1104 
1105 	for (;;)
1106 		continue;
1107 	/* NOTREACHED */
1108 }
1109 
1110 u_long	dumpmag = 0x8fca0101;	/* Magic number for savecore. */
1111 int	dumpsize = 0;			/* Also for savecore. */
1112 long	dumplo = 0;
1113 
1114 void
dumpconf(void)1115 dumpconf(void)
1116 {
1117 	int nblks;
1118 
1119 	if (dumpdev == NODEV ||
1120 	    (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0)
1121 		return;
1122 	if (nblks <= ctod(1))
1123 		return;
1124 
1125 	dumpsize = ptoa(physmem);
1126 	if (dumpsize > atop(round_page(dbtob(nblks - dumplo))))
1127 		dumpsize = atop(round_page(dbtob(nblks - dumplo)));
1128 	else if (dumplo == 0)
1129 		dumplo = nblks - btodb(ptoa(physmem));
1130 
1131 	/*
1132 	 * Don't dump on the first page in case the dump device includes a
1133 	 * disk label.
1134 	 */
1135 	if (dumplo < btodb(PAGE_SIZE))
1136 		dumplo = btodb(PAGE_SIZE);
1137 }
1138 
1139 void
dumpsys()1140 dumpsys()
1141 {
1142 	/* XXX TBD */
1143 }
1144 
1145 /*
1146  * Convert an ASCII string into an integer.
1147  */
1148 static u_long
atoi(const char * s,uint b)1149 atoi(const char *s, uint b)
1150 {
1151 	int c;
1152 	uint base = b, d;
1153 	int neg = 0;
1154 	u_long val = 0;
1155 
1156 	if (s == NULL || *s == '\0')
1157 		return 0;
1158 
1159 	/* Skip spaces if any. */
1160 	do {
1161 		c = *s++;
1162 	} while (c == ' ' || c == '\t');
1163 
1164 	/* Parse sign, allow more than one (compat). */
1165 	while (c == '-') {
1166 		neg = !neg;
1167 		c = *s++;
1168 	}
1169 
1170 	/* Parse base specification, if any. */
1171 	if (base == 0 && c == '0') {
1172 		c = *s++;
1173 		switch (c) {
1174 		case 'X':
1175 		case 'x':
1176 			base = 16;
1177 			c = *s++;
1178 			break;
1179 		case 'B':
1180 		case 'b':
1181 			base = 2;
1182 			c = *s++;
1183 			break;
1184 		default:
1185 			base = 8;
1186 			break;
1187 		}
1188 	}
1189 
1190 	/* Parse number proper. */
1191 	for (;;) {
1192 		if (c >= '0' && c <= '9')
1193 			d = c - '0';
1194 		else if (c >= 'a' && c <= 'z')
1195 			d = c - 'a' + 10;
1196 		else if (c >= 'A' && c <= 'Z')
1197 			d = c - 'A' + 10;
1198 		else
1199 			break;
1200 		if (d >= base)
1201 			break;
1202 		val *= base;
1203 		val += d;
1204 		c = *s++;
1205 	}
1206 
1207 	return neg ? -val : val;
1208 }
1209 
1210 /*
1211  * Early console through pmon routines.
1212  */
1213 
1214 int
pmoncngetc(dev_t dev)1215 pmoncngetc(dev_t dev)
1216 {
1217 	/*
1218 	 * PMON does not give us a getc routine.  So try to get a whole line
1219 	 * and return it char by char, trying not to lose the \n.  Kind
1220 	 * of ugly but should work.
1221 	 *
1222 	 * Note that one could theoretically use pmon_read(STDIN, &c, 1)
1223 	 * but the value of STDIN within PMON is not a constant and there
1224 	 * does not seem to be a way of letting us know which value to use.
1225 	 */
1226 	static char buf[1 + PMON_MAXLN];
1227 	static char *bufpos = buf;
1228 	int c;
1229 
1230 	if (*bufpos == '\0') {
1231 		bufpos = buf;
1232 		if (pmon_gets(buf) == NULL) {
1233 			/* either an empty line or EOF. assume the former */
1234 			return (int)'\n';
1235 		} else {
1236 			/* put back the \n sign */
1237 			buf[strlen(buf)] = '\n';
1238 		}
1239 	}
1240 
1241 	c = (int)*bufpos++;
1242 	if (bufpos - buf > PMON_MAXLN) {
1243 		bufpos = buf;
1244 		*bufpos = '\0';
1245 	}
1246 
1247 	return c;
1248 }
1249 
1250 void
pmoncnputc(dev_t dev,int c)1251 pmoncnputc(dev_t dev, int c)
1252 {
1253 	if (c == '\n')
1254 		pmon_printf("\n");
1255 	else
1256 		pmon_printf("%c", c);
1257 }
1258 
1259 void
intr_barrier(void * cookie)1260 intr_barrier(void *cookie)
1261 {
1262 	sched_barrier(NULL);
1263 }
1264 
1265 #ifdef MULTIPROCESSOR
1266 
1267 void
hw_cpu_hatch(struct cpu_info * ci)1268 hw_cpu_hatch(struct cpu_info *ci)
1269 {
1270 	/*
1271 	 * Set curcpu address on this processor.
1272 	 */
1273 	setcurcpu(ci);
1274 
1275 	/*
1276 	 * Make sure we can access the extended address space.
1277 	 */
1278 	setsr(getsr() | SR_KX | SR_UX);
1279 
1280 	tlb_init(ci->ci_hw.tlbsize);
1281 	tlb_set_pid(0);
1282 
1283 	/*
1284 	 * Turn off bootstrap exception vectors.
1285 	 */
1286 	setsr(getsr() & ~SR_BOOT_EXC_VEC);
1287 
1288 	/*
1289 	 * Clear out the I and D caches.
1290 	 */
1291 	switch (loongson_ver) {
1292 #ifdef CPU_LOONGSON3
1293 	case 0x3a:
1294 	case 0x3b:
1295 		Loongson3_ConfigCache(ci);
1296 		Loongson3_SyncCache(ci);
1297 		break;
1298 #endif
1299 	default:
1300 		panic("%s: unhandled Loongson version %x", __func__,
1301 		    loongson_ver);
1302 	}
1303 
1304 	(*md_startclock)(ci);
1305 
1306 	mips64_ipi_init();
1307 
1308 	ci->ci_flags |= CPUF_RUNNING;
1309 	membar_sync();
1310 
1311 	ncpus++;
1312 
1313 	spl0();
1314 	(void)updateimask(0);
1315 
1316 	sched_toidle();
1317 }
1318 
1319 void
hw_cpu_boot_secondary(struct cpu_info * ci)1320 hw_cpu_boot_secondary(struct cpu_info *ci)
1321 {
1322 	sys_platform->boot_secondary_cpu(ci);
1323 }
1324 
1325 int
hw_ipi_intr_establish(int (* func)(void *),u_long cpuid)1326 hw_ipi_intr_establish(int (*func)(void *), u_long cpuid)
1327 {
1328 	if (sys_platform->ipi_establish != NULL)
1329 		return sys_platform->ipi_establish(func, cpuid);
1330 	else
1331 		return 0;
1332 }
1333 
1334 void
hw_ipi_intr_set(u_long cpuid)1335 hw_ipi_intr_set(u_long cpuid)
1336 {
1337 	sys_platform->ipi_set(cpuid);
1338 }
1339 
1340 void
hw_ipi_intr_clear(u_long cpuid)1341 hw_ipi_intr_clear(u_long cpuid)
1342 {
1343 	if (sys_platform->ipi_clear != NULL)
1344 		sys_platform->ipi_clear(cpuid);
1345 }
1346 
1347 #endif /* MULTIPROCESSOR */
1348