1/*	$NetBSD: machdep.c,v 1.33 2024/03/05 14:15:31 thorpej Exp $	*/
2
3/*-
4 * Copyright (c) 2001, 2004, 2005 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.33 2024/03/05 14:15:31 thorpej Exp $");
31
32#include "opt_ddb.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/proc.h>
38#include <sys/buf.h>
39#include <sys/reboot.h>
40#include <sys/mount.h>
41#include <sys/kcore.h>
42#include <sys/boot_flag.h>
43#include <sys/device.h>
44#include <sys/cpu.h>
45
46#include <uvm/uvm_extern.h>
47
48#include <machine/bootinfo.h>
49#include <machine/locore.h>
50#include <machine/sbdvar.h>	/* System board */
51#include <machine/wired_map.h>
52
53#include <mips/cache.h>
54
55#ifdef DDB
56#include <machine/db_machdep.h>
57#include <ddb/db_sym.h>
58#include <ddb/db_extern.h>
59#include <ddb/db_output.h>
60#include <sys/exec_elf.h>
61#endif
62
63#include <dev/cons.h>
64
65#include <ews4800mips/ews4800mips/cons_machdep.h>
66
67vsize_t kseg2iobufsize;		/* to reserve PTEs for KSEG2 I/O space */
68
69/* maps for VM objects */
70struct vm_map *phys_map;
71
72/* referenced by mips_machdep.c:cpu_dump() */
73int mem_cluster_cnt;
74phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX];
75
76void mach_init(int, char *[], struct bootinfo *);
77void option(int, char *[], struct bootinfo *);
78/* NMI */
79void nmi_exception(void);
80
81void
82mach_init(int argc, char *argv[], struct bootinfo *bi)
83{
84	extern char kernel_text[], edata[], end[];
85	void *v;
86	int i;
87
88	/* Clear BSS */
89	if (bi == NULL || bi->bi_size != sizeof(struct bootinfo)) {
90		/*
91		 * No bootinfo, so assume we are loaded by
92		 * the firmware directly and have to clear BSS here.
93		 */
94		memset(edata, 0, end - edata);
95	}
96
97	/* Setup early-console with BIOS ROM routines */
98	rom_cons_init();
99
100	/* Initialize machine dependent System-Board ops. */
101	sbd_init();
102
103	__asm volatile("move %0, $29" : "=r"(v));
104	printf("kernel_text=%p edata=%p end=%p sp=%p\n",
105	    kernel_text, edata, end, v);
106
107	option(argc, argv, bi);
108
109	uvm_md_init();
110
111	/* Fill mem_clusters and mem_cluster_cnt */
112	(*platform.mem_init)(kernel_text,
113	    (bi && bi->bi_nsym) ? (void *)bi->bi_esym : end);
114
115	/*
116	 * make sure that we don't call BIOS console from now
117	 * because wired mappings set up by BIOS will be discarded
118	 * in mips_vector_init().
119	 */
120	cn_tab = NULL;
121
122	mips_vector_init(NULL, false);
123
124	memcpy((void *)0x80000200, ews4800mips_nmi_vec, 32); /* NMI */
125	mips_dcache_wbinv_all();
126	mips_icache_sync_all();
127
128	/* setup cpu_info */
129	curcpu()->ci_cycles_per_hz = (curcpu()->ci_cpu_freq + hz / 2) / hz;
130	curcpu()->ci_divisor_delay =
131	    ((curcpu()->ci_cpu_freq + 500000) / 1000000);
132	if (mips_options.mips_cpu_flags & CPU_MIPS_DOUBLE_COUNT) {
133		curcpu()->ci_cycles_per_hz /= 2;
134		curcpu()->ci_divisor_delay /= 2;
135	}
136
137	/* Load memory to UVM */
138	for (i = 1; i < mem_cluster_cnt; i++) {
139		phys_ram_seg_t *p;
140		paddr_t start;
141		size_t size;
142		p = &mem_clusters[i];
143		start = p->start;
144		size = p->size;
145		uvm_page_physload(atop(start), atop(start + size),
146		    atop(start), atop(start + size), VM_FREELIST_DEFAULT);
147	}
148
149	cpu_setmodel("NEC %s", platform.name);
150
151	mips_init_msgbuf();
152
153	pmap_bootstrap();
154
155	mips_init_lwp0_uarea();
156}
157
158void
159option(int argc, char *argv[], struct bootinfo *bi)
160{
161	extern char __boot_kernel_name[];
162	bool boot_device_set;
163	char *p;
164	int i;
165
166	printf("argc=%d argv=%p syminfo=%p\n", argc, argv, bi);
167	printf("version=%d size=%d nsym=%d ssym=%p esym=%p\n",
168	    bi->bi_version, bi->bi_size, bi->bi_nsym, bi->bi_ssym, bi->bi_esym);
169
170	for (i = 0; i < argc; i++)
171		printf("[%d] %s\n", i, argv[i]);
172
173#ifdef DDB
174	/* Load symbol table */
175	if (bi->bi_nsym)
176		ksyms_addsyms_elf(bi->bi_esym - bi->bi_ssym,
177		    (void *)bi->bi_ssym, (void *)bi->bi_esym);
178#endif
179	/* Parse option */
180	boot_device_set = false;
181	for (i = 2; i < argc; i++) {
182		p = argv[i];
183		/* prompt for root device */
184		if (p[0] == '-' && p[1] == 'a')
185			boot_device_set = true;
186
187		/* root device option. ex) -b=net:netbsd, -b=sd0k:netbsd */
188		if (p[0] == '-' && p[1] == 'b') {
189			boot_device_set = true;
190			strcpy(__boot_kernel_name, p + 3);
191		}
192	}
193
194	if (!boot_device_set)
195		strcpy(__boot_kernel_name, argv[1]);
196
197	/* Memory address information from IPL */
198	sbd_memcluster_init(bi->bi_mainfo);
199}
200
201void
202mips_machdep_cache_config(void)
203{
204
205	/* Set L2-cache size */
206	if (platform.cache_config)
207		(*platform.cache_config)();
208}
209
210void
211cpu_startup(void)
212{
213	vaddr_t minaddr, maxaddr;
214	char pbuf[9];
215
216	printf("%s%s", copyright, version);
217	printf("%s %dMHz\n", cpu_getmodel(), platform.cpu_clock / 1000000);
218	format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
219	printf("total memory = %s\n", pbuf);
220
221	minaddr = 0;
222	/*
223	 * Allocate a submap for physio.
224	 */
225	phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
226	    VM_PHYS_SIZE, 0, false, NULL);
227
228	/*
229	 * (No need to allocate an mbuf cluster submap.  Mbuf clusters
230	 * are allocated via the pool allocator, and we use KSEG to
231	 * map those pages.)
232	 */
233	format_bytes(pbuf, sizeof(pbuf), ptoa(uvm_availmem(false)));
234	printf("avail memory = %s\n", pbuf);
235}
236
237void
238cpu_reboot(int howto, char *bootstr)
239{
240	static int waittime = -1;
241
242	/* Take a snapshot before clobbering any registers. */
243	savectx(curpcb);
244
245	if (cold) {
246		howto |= RB_HALT;
247		goto haltsys;
248	}
249
250	/* If "always halt" was specified as a boot flag, obey. */
251	if (boothowto & RB_HALT)
252		howto |= RB_HALT;
253
254	boothowto = howto;
255	if ((howto & RB_NOSYNC) == 0 && (waittime < 0)) {
256		waittime = 0;
257		vfs_shutdown();
258	}
259
260	splhigh();
261
262	if (howto & RB_DUMP)
263		dumpsys();
264
265 haltsys:
266	doshutdownhooks();
267
268	pmf_system_shutdown(boothowto);
269
270	if ((howto & RB_POWERDOWN) == RB_POWERDOWN) {
271		if (platform.poweroff) {
272			DELAY(1000000);
273			(*platform.poweroff)();
274		}
275	}
276
277	if (howto & RB_HALT) {
278		printf("System halted.  Hit any key to reboot.\n\n");
279		(void)cngetc();
280	}
281
282	printf("rebooting...\n");
283	DELAY(1000000);
284	if (platform.reboot)
285		(*platform.reboot)();
286
287	printf("reboot failed.\n");
288	for (;;)
289		;
290	/* NOTREACHED */
291}
292
293#ifdef DDB
294void
295__db_print_symbol(db_expr_t value)
296{
297	const char *name;
298	db_expr_t offset;
299
300	db_find_xtrn_sym_and_offset((db_addr_t)value, &name, &offset);
301
302	if (name != NULL && offset <= db_maxoff && offset != value)
303		db_print_loc_and_inst(value);
304	else
305		db_printf("\n");
306
307}
308#endif
309