1 /* -*-C++-*- $NetBSD: hpcmenu.cpp,v 1.9 2002/03/25 17:23:19 uch 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