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