xref: /netbsd-src/sys/arch/hpc/stand/hpcboot/hpcmenu.cpp (revision 569b7f924fd547a1a14b66aa1fdab30e6ee501c2)
1*569b7f92Snonaka /* -*-C++-*-	$NetBSD: hpcmenu.cpp,v 1.19 2010/04/06 16:20:27 nonaka Exp $	*/
29173eae7Such 
39173eae7Such /*-
4b5f1c496Such  * Copyright (c) 2001, 2004 The NetBSD Foundation, Inc.
59173eae7Such  * All rights reserved.
69173eae7Such  *
79173eae7Such  * This code is derived from software contributed to The NetBSD Foundation
89173eae7Such  * by UCHIYAMA Yasushi.
99173eae7Such  *
109173eae7Such  * Redistribution and use in source and binary forms, with or without
119173eae7Such  * modification, are permitted provided that the following conditions
129173eae7Such  * are met:
139173eae7Such  * 1. Redistributions of source code must retain the above copyright
149173eae7Such  *    notice, this list of conditions and the following disclaimer.
159173eae7Such  * 2. Redistributions in binary form must reproduce the above copyright
169173eae7Such  *    notice, this list of conditions and the following disclaimer in the
179173eae7Such  *    documentation and/or other materials provided with the distribution.
189173eae7Such  *
199173eae7Such  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
209173eae7Such  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
219173eae7Such  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
229173eae7Such  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
239173eae7Such  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
249173eae7Such  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259173eae7Such  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
269173eae7Such  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279173eae7Such  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
289173eae7Such  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
299173eae7Such  * POSSIBILITY OF SUCH DAMAGE.
309173eae7Such  */
319173eae7Such 
329173eae7Such #include <hpcmenu.h>
339173eae7Such #include <hpcboot.h>
349173eae7Such #include <res/resource.h>
359173eae7Such #include <menu/window.h>
369173eae7Such #include <menu/tabwindow.h>
379173eae7Such #include <menu/rootwindow.h>
38bd926f64Such #include <menu/menu.h>
399173eae7Such #include <machine/bootinfo.h>
409173eae7Such #include <framebuffer.h>
419173eae7Such #include <console.h>
42d1f348c0Such #include <string.h>
439173eae7Such 
449173eae7Such HpcMenuInterface *HpcMenuInterface::_instance = 0;
459173eae7Such 
469173eae7Such HpcMenuInterface &
Instance()47a7876b44Such HpcMenuInterface::Instance()
489173eae7Such {
4932b30275Such 
509173eae7Such 	if (!_instance)
519173eae7Such 		_instance = new HpcMenuInterface();
529173eae7Such 	return *_instance;
539173eae7Such }
549173eae7Such 
559173eae7Such void
Destroy()56a7876b44Such HpcMenuInterface::Destroy()
579173eae7Such {
5832b30275Such 
599173eae7Such 	if (_instance)
609173eae7Such 		delete _instance;
619173eae7Such }
629173eae7Such 
HpcMenuInterface()63bd926f64Such HpcMenuInterface::HpcMenuInterface()
64bd926f64Such {
6532b30275Such 
66bd926f64Such 	if (!load())
67bd926f64Such 		_set_default_pref();
68bd926f64Such 	_pref._version	= HPCBOOT_VERSION;
69bd926f64Such 	_pref._size	= sizeof(HpcMenuPreferences);
70bd926f64Such 
71bd926f64Such 	_cons_parameter = 0;
72bd926f64Such 	memset(_cons_hook, 0, sizeof(struct cons_hook_args) * 4);
73bd926f64Such 	memset(&_boot_hook, 0, sizeof(struct boot_hook_args));
74bd926f64Such }
75bd926f64Such 
769173eae7Such void
print(TCHAR * buf)779173eae7Such HpcMenuInterface::print(TCHAR *buf)
789173eae7Such {
7932b30275Such 
809173eae7Such 	if (_console)
819173eae7Such 		_console->print(buf);
829173eae7Such }
839173eae7Such 
849173eae7Such void
get_options()85a7876b44Such HpcMenuInterface::get_options()
869173eae7Such {
8732b30275Such 
889173eae7Such 	_main->get();
899173eae7Such 	_option->get();
909173eae7Such }
919173eae7Such 
929173eae7Such TCHAR *
dir(int i)939173eae7Such HpcMenuInterface::dir(int i)
949173eae7Such {
959173eae7Such 	int res = IDS_DIR_RES(i);
9632b30275Such 
979173eae7Such 	if (!IDS_DIR_RES_VALID(res))
989173eae7Such 		return 0;
999173eae7Such 
1009173eae7Such 	if (_pref.dir_user && res == IDS_DIR_USER_DEFINED) {
1019173eae7Such 		return _pref.dir_user_path;
1029173eae7Such 	}
1039173eae7Such 
1049173eae7Such 	TCHAR *s = reinterpret_cast <TCHAR *>
1059173eae7Such 	    (LoadString(_root->_app._instance, res, 0, 0));
1069173eae7Such 
1079173eae7Such 	return s;
1089173eae7Such }
1099173eae7Such 
1109173eae7Such int
dir_default()111a7876b44Such HpcMenuInterface::dir_default()
1129173eae7Such {
11332b30275Such 
1149173eae7Such 	return _pref.dir_user ? IDS_DIR_SEQ(IDS_DIR_USER_DEFINED) : 0;
1159173eae7Such }
1169173eae7Such 
117bd926f64Such void
_set_default_pref()118bd926f64Such HpcMenuInterface::_set_default_pref()
119bd926f64Such {
12032b30275Such 
121bd926f64Such 	_pref._magic		= HPCBOOT_MAGIC;
122bd926f64Such 	_pref.dir		= 0;
123bd926f64Such 	_pref.dir_user		= FALSE;
124bd926f64Such 	_pref.kernel_user	= FALSE;
125bd926f64Such 	_pref.platid_hi		= 0;
126bd926f64Such 	_pref.platid_lo		= 0;
127bd926f64Such 	_pref.rootfs		= 0;
128bd926f64Such 	wsprintf(_pref.rootfs_file, TEXT("miniroot.fs"));
129bd926f64Such 	_pref.boot_serial	= FALSE;
130bd926f64Such 	_pref.boot_verbose	= FALSE;
131bd926f64Such 	_pref.boot_single_user	= FALSE;
132bd926f64Such 	_pref.boot_ask_for_name	= FALSE;
133c7a624dcSenami 	_pref.boot_debugger	= FALSE;
134d1f348c0Such 	wsprintf(_pref.boot_extra, TEXT(""));
135bd926f64Such 	_pref.auto_boot		= 0;
136bd926f64Such 	_pref.reverse_video	= FALSE;
137bd926f64Such 	_pref.pause_before_boot	= TRUE;
138bd926f64Such 	_pref.safety_message	= TRUE;
139bd926f64Such #ifdef MIPS
140bd926f64Such 	_pref.serial_speed	= 9600; // historical reason.
141bd926f64Such #else
142bd926f64Such 	_pref.serial_speed	= 19200;
143bd926f64Such #endif
144bd926f64Such }
145bd926f64Such 
146bd926f64Such //
147bd926f64Such // load and save current menu status.
148bd926f64Such //
1499173eae7Such BOOL
load()150a7876b44Such HpcMenuInterface::load()
1519173eae7Such {
1529173eae7Such 	TCHAR path[MAX_PATH];
1539173eae7Such 
1549173eae7Such 	if (!_find_pref_dir(path))
1559173eae7Such 		return FALSE;
1569173eae7Such 
1579173eae7Such 	TCHAR filename[MAX_PATH];
1589173eae7Such 	wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path);
1599173eae7Such 	HANDLE file = CreateFile(filename, GENERIC_READ, 0, 0, OPEN_EXISTING,
1609173eae7Such 	    FILE_ATTRIBUTE_NORMAL, 0);
1619173eae7Such 	if (file == INVALID_HANDLE_VALUE)
1629173eae7Such 		return FALSE;
1639173eae7Such 
1649173eae7Such 	DWORD cnt;
1659173eae7Such 	// read header.
1669173eae7Such 	if (!ReadFile(file, &_pref, 12, &cnt, 0))
1679173eae7Such 		goto bad;
1689173eae7Such 	if (_pref._magic != HPCBOOT_MAGIC)
1699173eae7Such 		goto bad;
1709173eae7Such 	// read all.
1719173eae7Such 	SetFilePointer(file, 0, 0, FILE_BEGIN);
1729173eae7Such 	if (!ReadFile(file, &_pref, _pref._size, &cnt, 0))
1739173eae7Such 		goto bad;
1749173eae7Such 	CloseHandle(file);
1759173eae7Such 
1769173eae7Such 	return TRUE;
1779173eae7Such  bad:
1789173eae7Such 	CloseHandle(file);
1799173eae7Such 	return FALSE;
1809173eae7Such }
1819173eae7Such 
1829173eae7Such BOOL
save()183a7876b44Such HpcMenuInterface::save()
1849173eae7Such {
1859173eae7Such 	TCHAR path[MAX_PATH];
1869173eae7Such 
1879173eae7Such 	if (_find_pref_dir(path)) {
1889173eae7Such 		TCHAR filename[MAX_PATH];
1899173eae7Such 		wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path);
1909173eae7Such 		HANDLE file = CreateFile(filename, GENERIC_WRITE, 0, 0,
191fae3e8e7Such 		    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
1929173eae7Such 		DWORD cnt;
1939173eae7Such 		WriteFile(file, &_pref, _pref._size, &cnt, 0);
1949173eae7Such 		CloseHandle(file);
1959173eae7Such 		return cnt == _pref._size;
1969173eae7Such 	}
1979173eae7Such 
1989173eae7Such 	return FALSE;
1999173eae7Such }
2009173eae7Such 
2019173eae7Such // arguments for kernel.
2029173eae7Such int
setup_kernel_args(vaddr_t v,paddr_t p,size_t sz)203d1f348c0Such HpcMenuInterface::setup_kernel_args(vaddr_t v, paddr_t p, size_t sz)
2049173eae7Such {
2059173eae7Such 	int argc = 0;
2069173eae7Such 	kaddr_t *argv = reinterpret_cast <kaddr_t *>(v);
2079173eae7Such 	char *loc = reinterpret_cast <char *>
2089173eae7Such 	    (v + sizeof(char **) * MAX_KERNEL_ARGS);
2099173eae7Such 	paddr_t locp = p + sizeof(char **) * MAX_KERNEL_ARGS;
2109173eae7Such 	size_t len;
2119173eae7Such 	TCHAR *w;
212d1f348c0Such 	char *ptr;
2139173eae7Such 
2149173eae7Such #define	SETOPT(c)							\
2159173eae7Such __BEGIN_MACRO								\
2169173eae7Such 	argv[argc++] = ptokv(locp);					\
2179173eae7Such 	*loc++ =(c);							\
2189173eae7Such 	*loc++ = '\0';							\
2199173eae7Such 	locp += 2;							\
2209173eae7Such __END_MACRO
2219173eae7Such 	// 1st arg is kernel name.
222d1f348c0Such //	DPRINTF_SETUP();  //if you want to use debug print, enable this line.
2239173eae7Such 
2249173eae7Such 	w = _pref.kernel_user_file;
2259173eae7Such 	argv[argc++] = ptokv(locp);
2269173eae7Such 	len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0);
2279173eae7Such 	WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0);
2289173eae7Such 	loc[len] = '\0';
2299173eae7Such 	loc += len + 1;
2309173eae7Such 	locp += len + 1;
2319173eae7Such 
2329173eae7Such 	if (_pref.boot_serial)		// serial console
2339173eae7Such 		SETOPT('h');
2349173eae7Such 	if (_pref.boot_verbose)		// boot verbosely
2359173eae7Such 		SETOPT('v');
2369173eae7Such 	if (_pref.boot_single_user)	// boot to single user
2379173eae7Such 		SETOPT('s');
2389173eae7Such 	if (_pref.boot_ask_for_name)	// ask for file name to boot from
2399173eae7Such 		SETOPT('a');
240c7a624dcSenami 	if (_pref.boot_debugger)	// break into the kernel debugger
241c7a624dcSenami 		SETOPT('d');
2429173eae7Such 
2439173eae7Such 	// boot from
2449173eae7Such 	switch(_pref.rootfs) {
2459173eae7Such 	case 0:	// wd0
2469173eae7Such 		break;
2479173eae7Such 	case 1:	// sd0
248df98929eSuch 		argv[argc++] = ptokv(locp);
249df98929eSuch 		strncpy(loc, "b=sd0", 6);
250df98929eSuch 		loc += 6;
251df98929eSuch 		locp += 6;
2529173eae7Such 		break;
2539173eae7Such 	case 2:	// memory disk
2549173eae7Such 		w = _pref.rootfs_file;
2559173eae7Such 		argv[argc++] = ptokv(locp);
2569173eae7Such 		strncpy(loc, "m=", 2);
2579173eae7Such 		loc += 2;
2589173eae7Such 		len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0);
2599173eae7Such 		WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0);
2609173eae7Such 		loc[len] = '\0';
2619173eae7Such 		loc += len + 1;
2629173eae7Such 		locp += 2 + len + 1;
2639173eae7Such 		break;
2649173eae7Such 	case 3:	// nfs
2659173eae7Such 		argv[argc++] = ptokv(locp);
2669173eae7Such 		strncpy(loc, "b=nfs", 6);
2679173eae7Such 		loc += 6;
2689173eae7Such 		locp += 6;
2699173eae7Such 		break;
270*569b7f92Snonaka 	case 4:	// dk0
271*569b7f92Snonaka 		argv[argc++] = ptokv(locp);
272*569b7f92Snonaka 		strncpy(loc, "b=dk0", 6);
273*569b7f92Snonaka 		loc += 6;
274*569b7f92Snonaka 		locp += 6;
275*569b7f92Snonaka 		break;
276*569b7f92Snonaka 	case 5:	// ld0
277*569b7f92Snonaka 		argv[argc++] = ptokv(locp);
278*569b7f92Snonaka 		strncpy(loc, "b=ld0", 6);
279*569b7f92Snonaka 		loc += 6;
280*569b7f92Snonaka 		locp += 6;
281*569b7f92Snonaka 		break;
2829173eae7Such 	}
2839173eae7Such 
284d1f348c0Such 	// Extra kernel options. (Option tab window)
285d1f348c0Such 	w = _pref.boot_extra;
286d1f348c0Such 	len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0);
287d1f348c0Such 
288d1f348c0Such 	if ((ptr = (char *)malloc(len)) == NULL) {
289d1f348c0Such 		MessageBox(_root->_window,
290545bd4c3Suwe 		    L"Can't allocate memory for extra kernel options.",
291545bd4c3Suwe 		    TEXT("WARNING"),
292545bd4c3Suwe 		    MB_ICONWARNING | MB_OK);
2938c941b84Suwe 		UpdateWindow(_root->_window);
294d1f348c0Such 
295d1f348c0Such 		return argc;
296d1f348c0Such 	}
297d1f348c0Such 	WideCharToMultiByte(CP_ACP, 0, w, len, ptr, len, 0, 0);
298d1f348c0Such 	ptr[len]='\0';
299d1f348c0Such 
300d1f348c0Such 	while (*ptr == ' ' || *ptr == '\t')
301d1f348c0Such 		ptr++;
302d1f348c0Such 	while (*ptr != '\0') {
303d1f348c0Such 		len = strcspn(ptr, " \t");
304d1f348c0Such 		if (len == 0)
305d1f348c0Such 			len = strlen(ptr);
306d1f348c0Such 
307d1f348c0Such 		if (argc == MAX_KERNEL_ARGS || locp + len + 1 > p + sz) {
308d1f348c0Such 			MessageBox(_root->_window,
309d1f348c0Such 			    L"Too many extra kernel options.",
310545bd4c3Suwe 			    TEXT("WARNING"),
311545bd4c3Suwe 			    MB_ICONWARNING | MB_OK);
3128c941b84Suwe 			UpdateWindow(_root->_window);
313d1f348c0Such 			break;
314d1f348c0Such 		}
315d1f348c0Such 		argv[argc++] = ptokv(locp);
316d1f348c0Such 		strncpy(loc, ptr, len);
317d1f348c0Such 		loc[len] = '\0';
318d1f348c0Such 		loc += len + 1;
319d1f348c0Such 		locp += len + 1;
320d1f348c0Such 
321d1f348c0Such 		ptr += len;
322d1f348c0Such 		while (*ptr == ' ' || *ptr == '\t')
323d1f348c0Such 			ptr++;
324d1f348c0Such 	}
325d1f348c0Such 
3269173eae7Such 	return argc;
3279173eae7Such }
3289173eae7Such 
3299173eae7Such // kernel bootinfo.
3309173eae7Such void
setup_bootinfo(struct bootinfo & bi)3319173eae7Such HpcMenuInterface::setup_bootinfo(struct bootinfo &bi)
3329173eae7Such {
3339173eae7Such 	FrameBufferInfo fb(_pref.platid_hi, _pref.platid_lo);
3349173eae7Such 	TIME_ZONE_INFORMATION tz;
3352ddba961Suwe 	DWORD tzid = GetTimeZoneInformation(&tz);
3369173eae7Such 
3379173eae7Such 	memset(&bi, 0, sizeof(struct bootinfo));
3389173eae7Such 	bi.length		= sizeof(struct bootinfo);
3399173eae7Such 	bi.reserved		= 0;
3409173eae7Such 	bi.magic		= BOOTINFO_MAGIC;
3419173eae7Such 	bi.fb_addr		= fb.addr();
3429173eae7Such 	bi.fb_type		= fb.type();
3439173eae7Such 	bi.fb_line_bytes	= fb.linebytes();
3449173eae7Such 	bi.fb_width		= fb.width();
3459173eae7Such 	bi.fb_height		= fb.height();
3469173eae7Such 	bi.platid_cpu		= _pref.platid_hi;
3479173eae7Such 	bi.platid_machine	= _pref.platid_lo;
3489173eae7Such 	bi.timezone		= tz.Bias;
3492ddba961Suwe 	if (tzid == TIME_ZONE_ID_DAYLIGHT)
3502ddba961Suwe 		bi.timezone    += tz.DaylightBias;
3519173eae7Such }
3529173eae7Such 
3539173eae7Such // Progress bar
3549173eae7Such void
progress(const char * msg)355b5f1c496Such HpcMenuInterface::progress(const char *msg)
3569173eae7Such {
35732b30275Such 
358b5f1c496Such 	_root->progress(msg);
359f94c4399Suwe }
360f94c4399Suwe 
361f94c4399Suwe void
unprogress()362f94c4399Suwe HpcMenuInterface::unprogress()
363f94c4399Suwe {
36432b30275Such 
365f94c4399Suwe 	_root->unprogress();
3669173eae7Such }
367a7876b44Such 
368bd926f64Such // Boot kernel.
369a7876b44Such void
boot()370a7876b44Such HpcMenuInterface::boot()
371a7876b44Such {
372a7876b44Such 	struct support_status *tab = _unsupported;
37324c8a902Suwe 	uint32_t cpu = _pref.platid_hi;
37424c8a902Suwe 	uint32_t machine = _pref.platid_lo;
375a7876b44Such 
376a7876b44Such 	if (_pref.safety_message)
377a7876b44Such 		for (; tab->cpu; tab++) {
378a7876b44Such 			if (tab->cpu == cpu && tab->machine == machine) {
379a7876b44Such 				MessageBox(_root->_window,
380a7876b44Such 				    tab->cause ? tab->cause :
381545bd4c3Suwe 				    L"Not supported yet.",
382545bd4c3Suwe 				    TEXT("BOOT FAILED"),
383545bd4c3Suwe 				    MB_ICONERROR | MB_OK);
384a7876b44Such 				return;
385a7876b44Such 			}
386a7876b44Such 		}
387a7876b44Such 
388a7876b44Such 	if (_boot_hook.func)
389bd926f64Such 		_boot_hook.func(_boot_hook.arg);
390a7876b44Such }
391