Home | History | Annotate | Line # | Download | only in hpcboot
hpcmenu.cpp revision 1.8.8.2
      1 /* -*-C++-*-	$NetBSD: hpcmenu.cpp,v 1.8.8.2 2002/04/01 07:40:14 nathanw Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by UCHIYAMA Yasushi.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <hpcmenu.h>
     40 #include <hpcboot.h>
     41 #include <res/resource.h>
     42 #include <menu/window.h>
     43 #include <menu/tabwindow.h>
     44 #include <menu/rootwindow.h>
     45 #include <menu/menu.h>
     46 #include <machine/bootinfo.h>
     47 #include <framebuffer.h>
     48 #include <console.h>
     49 #include <string.h>
     50 
     51 HpcMenuInterface *HpcMenuInterface::_instance = 0;
     52 
     53 HpcMenuInterface &
     54 HpcMenuInterface::Instance()
     55 {
     56 	if (!_instance)
     57 		_instance = new HpcMenuInterface();
     58 	return *_instance;
     59 }
     60 
     61 void
     62 HpcMenuInterface::Destroy()
     63 {
     64 	if (_instance)
     65 		delete _instance;
     66 }
     67 
     68 HpcMenuInterface::HpcMenuInterface()
     69 {
     70 	if (!load())
     71 		_set_default_pref();
     72 	_pref._version	= HPCBOOT_VERSION;
     73 	_pref._size	= sizeof(HpcMenuPreferences);
     74 
     75 	_cons_parameter = 0;
     76 	memset(_cons_hook, 0, sizeof(struct cons_hook_args) * 4);
     77 	memset(&_boot_hook, 0, sizeof(struct boot_hook_args));
     78 }
     79 
     80 void
     81 HpcMenuInterface::print(TCHAR *buf)
     82 {
     83 	if (_console)
     84 		_console->print(buf);
     85 }
     86 
     87 void
     88 HpcMenuInterface::get_options()
     89 {
     90 	_main->get();
     91 	_option->get();
     92 }
     93 
     94 TCHAR *
     95 HpcMenuInterface::dir(int i)
     96 {
     97 	int res = IDS_DIR_RES(i);
     98 	if (!IDS_DIR_RES_VALID(res))
     99 		return 0;
    100 
    101 	if (_pref.dir_user && res == IDS_DIR_USER_DEFINED) {
    102 		return _pref.dir_user_path;
    103 	}
    104 
    105 	TCHAR *s = reinterpret_cast <TCHAR *>
    106 	    (LoadString(_root->_app._instance, res, 0, 0));
    107 
    108 	return s;
    109 }
    110 
    111 int
    112 HpcMenuInterface::dir_default()
    113 {
    114 	return _pref.dir_user ? IDS_DIR_SEQ(IDS_DIR_USER_DEFINED) : 0;
    115 }
    116 
    117 void
    118 HpcMenuInterface::_set_default_pref()
    119 {
    120 	_pref._magic		= HPCBOOT_MAGIC;
    121 	_pref.dir		= 0;
    122 	_pref.dir_user		= FALSE;
    123 	_pref.kernel_user	= FALSE;
    124 	_pref.platid_hi		= 0;
    125 	_pref.platid_lo		= 0;
    126 	_pref.rootfs		= 0;
    127 	wsprintf(_pref.rootfs_file, TEXT("miniroot.fs"));
    128 	_pref.boot_serial	= FALSE;
    129 	_pref.boot_verbose	= FALSE;
    130 	_pref.boot_single_user	= FALSE;
    131 	_pref.boot_ask_for_name	= FALSE;
    132 	_pref.boot_debugger	= FALSE;
    133 	wsprintf(_pref.boot_extra, TEXT(""));
    134 	_pref.auto_boot		= 0;
    135 	_pref.reverse_video	= FALSE;
    136 	_pref.pause_before_boot	= TRUE;
    137 	_pref.safety_message	= TRUE;
    138 #ifdef MIPS
    139 	_pref.serial_speed	= 9600; // historical reason.
    140 #else
    141 	_pref.serial_speed	= 19200;
    142 #endif
    143 }
    144 
    145 //
    146 // load and save current menu status.
    147 //
    148 BOOL
    149 HpcMenuInterface::load()
    150 {
    151 	TCHAR path[MAX_PATH];
    152 
    153 	if (!_find_pref_dir(path))
    154 		return FALSE;
    155 
    156 	TCHAR filename[MAX_PATH];
    157 	wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path);
    158 	HANDLE file = CreateFile(filename, GENERIC_READ, 0, 0, OPEN_EXISTING,
    159 	    FILE_ATTRIBUTE_NORMAL, 0);
    160 	if (file == INVALID_HANDLE_VALUE)
    161 		return FALSE;
    162 
    163 	DWORD cnt;
    164 	// read header.
    165 	if (!ReadFile(file, &_pref, 12, &cnt, 0))
    166 		goto bad;
    167 	if (_pref._magic != HPCBOOT_MAGIC)
    168 		goto bad;
    169 	// read all.
    170 	SetFilePointer(file, 0, 0, FILE_BEGIN);
    171 	if (!ReadFile(file, &_pref, _pref._size, &cnt, 0))
    172 		goto bad;
    173 	CloseHandle(file);
    174 
    175 	return TRUE;
    176  bad:
    177 	CloseHandle(file);
    178 	return FALSE;
    179 }
    180 
    181 BOOL
    182 HpcMenuInterface::save()
    183 {
    184 	TCHAR path[MAX_PATH];
    185 
    186 	if (_find_pref_dir(path)) {
    187 		TCHAR filename[MAX_PATH];
    188 		wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path);
    189 		HANDLE file = CreateFile(filename, GENERIC_WRITE, 0, 0,
    190 		    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    191 		DWORD cnt;
    192 		WriteFile(file, &_pref, _pref._size, &cnt, 0);
    193 		CloseHandle(file);
    194 		return cnt == _pref._size;
    195 	}
    196 
    197 	return FALSE;
    198 }
    199 
    200 // arguments for kernel.
    201 int
    202 HpcMenuInterface::setup_kernel_args(vaddr_t v, paddr_t p, size_t sz)
    203 {
    204 	int argc = 0;
    205 	kaddr_t *argv = reinterpret_cast <kaddr_t *>(v);
    206 	char *loc = reinterpret_cast <char *>
    207 	    (v + sizeof(char **) * MAX_KERNEL_ARGS);
    208 	paddr_t locp = p + sizeof(char **) * MAX_KERNEL_ARGS;
    209 	size_t len;
    210 	TCHAR *w;
    211 	char *ptr;
    212 
    213 #define SETOPT(c)							\
    214 __BEGIN_MACRO								\
    215 	argv[argc++] = ptokv(locp);					\
    216 	*loc++ =(c);							\
    217 	*loc++ = '\0';							\
    218 	locp += 2;							\
    219 __END_MACRO
    220 	// 1st arg is kernel name.
    221 //	DPRINTF_SETUP();  //if you want to use debug print, enable this line.
    222 
    223 	w = _pref.kernel_user_file;
    224 	argv[argc++] = ptokv(locp);
    225 	len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0);
    226 	WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0);
    227 	loc[len] = '\0';
    228 	loc += len + 1;
    229 	locp += len + 1;
    230 
    231 	if (_pref.boot_serial)		// serial console
    232 		SETOPT('h');
    233 	if (_pref.boot_verbose)		// boot verbosely
    234 		SETOPT('v');
    235 	if (_pref.boot_single_user)	// boot to single user
    236 		SETOPT('s');
    237 	if (_pref.boot_ask_for_name)	// ask for file name to boot from
    238 		SETOPT('a');
    239 	if (_pref.boot_debugger)	// break into the kernel debugger
    240 		SETOPT('d');
    241 
    242 	// boot from
    243 	switch(_pref.rootfs) {
    244 	case 0:	// wd0
    245 		break;
    246 	case 1:	// sd0
    247 		argv[argc++] = ptokv(locp);
    248 		strncpy(loc, "b=sd0", 6);
    249 		loc += 6;
    250 		locp += 6;
    251 		break;
    252 	case 2:	// memory disk
    253 		w = _pref.rootfs_file;
    254 		argv[argc++] = ptokv(locp);
    255 		strncpy(loc, "m=", 2);
    256 		loc += 2;
    257 		len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0);
    258 		WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0);
    259 		loc[len] = '\0';
    260 		loc += len + 1;
    261 		locp += 2 + len + 1;
    262 		break;
    263 	case 3:	// nfs
    264 		argv[argc++] = ptokv(locp);
    265 		strncpy(loc, "b=nfs", 6);
    266 		loc += 6;
    267 		locp += 6;
    268 		break;
    269 	}
    270 
    271 	// Extra kernel options. (Option tab window)
    272 	w = _pref.boot_extra;
    273 	len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0);
    274 
    275 	if ((ptr = (char *)malloc(len)) == NULL) {
    276 		MessageBox(_root->_window,
    277 		    L"Couldn't allocate memory for extra kernel options.",
    278 		    TEXT("WARNING"), 0);
    279 
    280 		return argc;
    281 	}
    282 	WideCharToMultiByte(CP_ACP, 0, w, len, ptr, len, 0, 0);
    283 	ptr[len]='\0';
    284 
    285 	while (*ptr == ' ' || *ptr == '\t')
    286 		ptr++;
    287 	while (*ptr != '\0') {
    288 		len = strcspn(ptr, " \t");
    289 		if (len == 0)
    290 			len = strlen(ptr);
    291 
    292 		if (argc == MAX_KERNEL_ARGS || locp + len + 1 > p + sz) {
    293 			MessageBox(_root->_window,
    294 			    L"Too many extra kernel options.",
    295 			    TEXT("WARNING"), 0);
    296 			break;
    297 		}
    298 		argv[argc++] = ptokv(locp);
    299 		strncpy(loc, ptr, len);
    300 		loc[len] = '\0';
    301 		loc += len + 1;
    302 		locp += len + 1;
    303 
    304 		ptr += len;
    305 		while (*ptr == ' ' || *ptr == '\t')
    306 			ptr++;
    307 	}
    308 
    309 	return argc;
    310 }
    311 
    312 // kernel bootinfo.
    313 void
    314 HpcMenuInterface::setup_bootinfo(struct bootinfo &bi)
    315 {
    316 	FrameBufferInfo fb(_pref.platid_hi, _pref.platid_lo);
    317 	TIME_ZONE_INFORMATION tz;
    318 	GetTimeZoneInformation(&tz);
    319 
    320 	memset(&bi, 0, sizeof(struct bootinfo));
    321 	bi.length		= sizeof(struct bootinfo);
    322 	bi.reserved		= 0;
    323 	bi.magic		= BOOTINFO_MAGIC;
    324 	bi.fb_addr		= fb.addr();
    325 	bi.fb_type		= fb.type();
    326 	bi.fb_line_bytes	= fb.linebytes();
    327 	bi.fb_width		= fb.width();
    328 	bi.fb_height		= fb.height();
    329 	bi.platid_cpu		= _pref.platid_hi;
    330 	bi.platid_machine	= _pref.platid_lo;
    331 	bi.timezone		= tz.Bias;
    332 }
    333 
    334 // Progress bar
    335 void
    336 HpcMenuInterface::progress()
    337 {
    338 	SendMessage(_root->_progress_bar->_window, PBM_STEPIT, 0, 0);
    339 }
    340 
    341 // Boot kernel.
    342 void
    343 HpcMenuInterface::boot()
    344 {
    345 	struct support_status *tab = _unsupported;
    346 	u_int32_t cpu = _pref.platid_hi;
    347 	u_int32_t machine = _pref.platid_lo;
    348 
    349 	if (_pref.safety_message)
    350 		for (; tab->cpu; tab++) {
    351 			if (tab->cpu == cpu && tab->machine == machine) {
    352 				MessageBox(_root->_window,
    353 				    tab->cause ? tab->cause :
    354 				    L"not supported yet.",
    355 				    TEXT("BOOT FAILED"), 0);
    356 				return;
    357 			}
    358 		}
    359 
    360 	if (_boot_hook.func)
    361 		_boot_hook.func(_boot_hook.arg);
    362 }
    363