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