1 /* -*-C++-*- $NetBSD: hpcmenu.cpp,v 1.17 2006/03/05 04:05:39 uwe Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2004 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 57 if (!_instance) 58 _instance = new HpcMenuInterface(); 59 return *_instance; 60 } 61 62 void 63 HpcMenuInterface::Destroy() 64 { 65 66 if (_instance) 67 delete _instance; 68 } 69 70 HpcMenuInterface::HpcMenuInterface() 71 { 72 73 if (!load()) 74 _set_default_pref(); 75 _pref._version = HPCBOOT_VERSION; 76 _pref._size = sizeof(HpcMenuPreferences); 77 78 _cons_parameter = 0; 79 memset(_cons_hook, 0, sizeof(struct cons_hook_args) * 4); 80 memset(&_boot_hook, 0, sizeof(struct boot_hook_args)); 81 } 82 83 void 84 HpcMenuInterface::print(TCHAR *buf) 85 { 86 87 if (_console) 88 _console->print(buf); 89 } 90 91 void 92 HpcMenuInterface::get_options() 93 { 94 95 _main->get(); 96 _option->get(); 97 } 98 99 TCHAR * 100 HpcMenuInterface::dir(int i) 101 { 102 int res = IDS_DIR_RES(i); 103 104 if (!IDS_DIR_RES_VALID(res)) 105 return 0; 106 107 if (_pref.dir_user && res == IDS_DIR_USER_DEFINED) { 108 return _pref.dir_user_path; 109 } 110 111 TCHAR *s = reinterpret_cast <TCHAR *> 112 (LoadString(_root->_app._instance, res, 0, 0)); 113 114 return s; 115 } 116 117 int 118 HpcMenuInterface::dir_default() 119 { 120 121 return _pref.dir_user ? IDS_DIR_SEQ(IDS_DIR_USER_DEFINED) : 0; 122 } 123 124 void 125 HpcMenuInterface::_set_default_pref() 126 { 127 128 _pref._magic = HPCBOOT_MAGIC; 129 _pref.dir = 0; 130 _pref.dir_user = FALSE; 131 _pref.kernel_user = FALSE; 132 _pref.platid_hi = 0; 133 _pref.platid_lo = 0; 134 _pref.rootfs = 0; 135 wsprintf(_pref.rootfs_file, TEXT("miniroot.fs")); 136 _pref.boot_serial = FALSE; 137 _pref.boot_verbose = FALSE; 138 _pref.boot_single_user = FALSE; 139 _pref.boot_ask_for_name = FALSE; 140 _pref.boot_debugger = FALSE; 141 wsprintf(_pref.boot_extra, TEXT("")); 142 _pref.auto_boot = 0; 143 _pref.reverse_video = FALSE; 144 _pref.pause_before_boot = TRUE; 145 _pref.safety_message = TRUE; 146 #ifdef MIPS 147 _pref.serial_speed = 9600; // historical reason. 148 #else 149 _pref.serial_speed = 19200; 150 #endif 151 } 152 153 // 154 // load and save current menu status. 155 // 156 BOOL 157 HpcMenuInterface::load() 158 { 159 TCHAR path[MAX_PATH]; 160 161 if (!_find_pref_dir(path)) 162 return FALSE; 163 164 TCHAR filename[MAX_PATH]; 165 wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path); 166 HANDLE file = CreateFile(filename, GENERIC_READ, 0, 0, OPEN_EXISTING, 167 FILE_ATTRIBUTE_NORMAL, 0); 168 if (file == INVALID_HANDLE_VALUE) 169 return FALSE; 170 171 DWORD cnt; 172 // read header. 173 if (!ReadFile(file, &_pref, 12, &cnt, 0)) 174 goto bad; 175 if (_pref._magic != HPCBOOT_MAGIC) 176 goto bad; 177 // read all. 178 SetFilePointer(file, 0, 0, FILE_BEGIN); 179 if (!ReadFile(file, &_pref, _pref._size, &cnt, 0)) 180 goto bad; 181 CloseHandle(file); 182 183 return TRUE; 184 bad: 185 CloseHandle(file); 186 return FALSE; 187 } 188 189 BOOL 190 HpcMenuInterface::save() 191 { 192 TCHAR path[MAX_PATH]; 193 194 if (_find_pref_dir(path)) { 195 TCHAR filename[MAX_PATH]; 196 wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path); 197 HANDLE file = CreateFile(filename, GENERIC_WRITE, 0, 0, 198 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 199 DWORD cnt; 200 WriteFile(file, &_pref, _pref._size, &cnt, 0); 201 CloseHandle(file); 202 return cnt == _pref._size; 203 } 204 205 return FALSE; 206 } 207 208 // arguments for kernel. 209 int 210 HpcMenuInterface::setup_kernel_args(vaddr_t v, paddr_t p, size_t sz) 211 { 212 int argc = 0; 213 kaddr_t *argv = reinterpret_cast <kaddr_t *>(v); 214 char *loc = reinterpret_cast <char *> 215 (v + sizeof(char **) * MAX_KERNEL_ARGS); 216 paddr_t locp = p + sizeof(char **) * MAX_KERNEL_ARGS; 217 size_t len; 218 TCHAR *w; 219 char *ptr; 220 221 #define SETOPT(c) \ 222 __BEGIN_MACRO \ 223 argv[argc++] = ptokv(locp); \ 224 *loc++ =(c); \ 225 *loc++ = '\0'; \ 226 locp += 2; \ 227 __END_MACRO 228 // 1st arg is kernel name. 229 // DPRINTF_SETUP(); //if you want to use debug print, enable this line. 230 231 w = _pref.kernel_user_file; 232 argv[argc++] = ptokv(locp); 233 len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0); 234 WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0); 235 loc[len] = '\0'; 236 loc += len + 1; 237 locp += len + 1; 238 239 if (_pref.boot_serial) // serial console 240 SETOPT('h'); 241 if (_pref.boot_verbose) // boot verbosely 242 SETOPT('v'); 243 if (_pref.boot_single_user) // boot to single user 244 SETOPT('s'); 245 if (_pref.boot_ask_for_name) // ask for file name to boot from 246 SETOPT('a'); 247 if (_pref.boot_debugger) // break into the kernel debugger 248 SETOPT('d'); 249 250 // boot from 251 switch(_pref.rootfs) { 252 case 0: // wd0 253 break; 254 case 1: // sd0 255 argv[argc++] = ptokv(locp); 256 strncpy(loc, "b=sd0", 6); 257 loc += 6; 258 locp += 6; 259 break; 260 case 2: // memory disk 261 w = _pref.rootfs_file; 262 argv[argc++] = ptokv(locp); 263 strncpy(loc, "m=", 2); 264 loc += 2; 265 len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0); 266 WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0); 267 loc[len] = '\0'; 268 loc += len + 1; 269 locp += 2 + len + 1; 270 break; 271 case 3: // nfs 272 argv[argc++] = ptokv(locp); 273 strncpy(loc, "b=nfs", 6); 274 loc += 6; 275 locp += 6; 276 break; 277 } 278 279 // Extra kernel options. (Option tab window) 280 w = _pref.boot_extra; 281 len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0); 282 283 if ((ptr = (char *)malloc(len)) == NULL) { 284 MessageBox(_root->_window, 285 L"Can't allocate memory for extra kernel options.", 286 TEXT("WARNING"), 287 MB_ICONWARNING | MB_OK); 288 UpdateWindow(_root->_window); 289 290 return argc; 291 } 292 WideCharToMultiByte(CP_ACP, 0, w, len, ptr, len, 0, 0); 293 ptr[len]='\0'; 294 295 while (*ptr == ' ' || *ptr == '\t') 296 ptr++; 297 while (*ptr != '\0') { 298 len = strcspn(ptr, " \t"); 299 if (len == 0) 300 len = strlen(ptr); 301 302 if (argc == MAX_KERNEL_ARGS || locp + len + 1 > p + sz) { 303 MessageBox(_root->_window, 304 L"Too many extra kernel options.", 305 TEXT("WARNING"), 306 MB_ICONWARNING | MB_OK); 307 UpdateWindow(_root->_window); 308 break; 309 } 310 argv[argc++] = ptokv(locp); 311 strncpy(loc, ptr, len); 312 loc[len] = '\0'; 313 loc += len + 1; 314 locp += len + 1; 315 316 ptr += len; 317 while (*ptr == ' ' || *ptr == '\t') 318 ptr++; 319 } 320 321 return argc; 322 } 323 324 // kernel bootinfo. 325 void 326 HpcMenuInterface::setup_bootinfo(struct bootinfo &bi) 327 { 328 FrameBufferInfo fb(_pref.platid_hi, _pref.platid_lo); 329 TIME_ZONE_INFORMATION tz; 330 DWORD tzid = GetTimeZoneInformation(&tz); 331 332 memset(&bi, 0, sizeof(struct bootinfo)); 333 bi.length = sizeof(struct bootinfo); 334 bi.reserved = 0; 335 bi.magic = BOOTINFO_MAGIC; 336 bi.fb_addr = fb.addr(); 337 bi.fb_type = fb.type(); 338 bi.fb_line_bytes = fb.linebytes(); 339 bi.fb_width = fb.width(); 340 bi.fb_height = fb.height(); 341 bi.platid_cpu = _pref.platid_hi; 342 bi.platid_machine = _pref.platid_lo; 343 bi.timezone = tz.Bias; 344 if (tzid == TIME_ZONE_ID_DAYLIGHT) 345 bi.timezone += tz.DaylightBias; 346 } 347 348 // Progress bar 349 void 350 HpcMenuInterface::progress(const char *msg) 351 { 352 353 _root->progress(msg); 354 } 355 356 void 357 HpcMenuInterface::unprogress() 358 { 359 360 _root->unprogress(); 361 } 362 363 // Boot kernel. 364 void 365 HpcMenuInterface::boot() 366 { 367 struct support_status *tab = _unsupported; 368 uint32_t cpu = _pref.platid_hi; 369 uint32_t machine = _pref.platid_lo; 370 371 if (_pref.safety_message) 372 for (; tab->cpu; tab++) { 373 if (tab->cpu == cpu && tab->machine == machine) { 374 MessageBox(_root->_window, 375 tab->cause ? tab->cause : 376 L"Not supported yet.", 377 TEXT("BOOT FAILED"), 378 MB_ICONERROR | MB_OK); 379 return; 380 } 381 } 382 383 if (_boot_hook.func) 384 _boot_hook.func(_boot_hook.arg); 385 } 386