/* -*-C++-*- $NetBSD: hpcmenu.cpp,v 1.19 2010/04/06 16:20:27 nonaka Exp $ */ /*- * Copyright (c) 2001, 2004 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by UCHIYAMA Yasushi. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include HpcMenuInterface *HpcMenuInterface::_instance = 0; HpcMenuInterface & HpcMenuInterface::Instance() { if (!_instance) _instance = new HpcMenuInterface(); return *_instance; } void HpcMenuInterface::Destroy() { if (_instance) delete _instance; } HpcMenuInterface::HpcMenuInterface() { if (!load()) _set_default_pref(); _pref._version = HPCBOOT_VERSION; _pref._size = sizeof(HpcMenuPreferences); _cons_parameter = 0; memset(_cons_hook, 0, sizeof(struct cons_hook_args) * 4); memset(&_boot_hook, 0, sizeof(struct boot_hook_args)); } void HpcMenuInterface::print(TCHAR *buf) { if (_console) _console->print(buf); } void HpcMenuInterface::get_options() { _main->get(); _option->get(); } TCHAR * HpcMenuInterface::dir(int i) { int res = IDS_DIR_RES(i); if (!IDS_DIR_RES_VALID(res)) return 0; if (_pref.dir_user && res == IDS_DIR_USER_DEFINED) { return _pref.dir_user_path; } TCHAR *s = reinterpret_cast (LoadString(_root->_app._instance, res, 0, 0)); return s; } int HpcMenuInterface::dir_default() { return _pref.dir_user ? IDS_DIR_SEQ(IDS_DIR_USER_DEFINED) : 0; } void HpcMenuInterface::_set_default_pref() { _pref._magic = HPCBOOT_MAGIC; _pref.dir = 0; _pref.dir_user = FALSE; _pref.kernel_user = FALSE; _pref.platid_hi = 0; _pref.platid_lo = 0; _pref.rootfs = 0; wsprintf(_pref.rootfs_file, TEXT("miniroot.fs")); _pref.boot_serial = FALSE; _pref.boot_verbose = FALSE; _pref.boot_single_user = FALSE; _pref.boot_ask_for_name = FALSE; _pref.boot_debugger = FALSE; wsprintf(_pref.boot_extra, TEXT("")); _pref.auto_boot = 0; _pref.reverse_video = FALSE; _pref.pause_before_boot = TRUE; _pref.safety_message = TRUE; #ifdef MIPS _pref.serial_speed = 9600; // historical reason. #else _pref.serial_speed = 19200; #endif } // // load and save current menu status. // BOOL HpcMenuInterface::load() { TCHAR path[MAX_PATH]; if (!_find_pref_dir(path)) return FALSE; TCHAR filename[MAX_PATH]; wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path); HANDLE file = CreateFile(filename, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (file == INVALID_HANDLE_VALUE) return FALSE; DWORD cnt; // read header. if (!ReadFile(file, &_pref, 12, &cnt, 0)) goto bad; if (_pref._magic != HPCBOOT_MAGIC) goto bad; // read all. SetFilePointer(file, 0, 0, FILE_BEGIN); if (!ReadFile(file, &_pref, _pref._size, &cnt, 0)) goto bad; CloseHandle(file); return TRUE; bad: CloseHandle(file); return FALSE; } BOOL HpcMenuInterface::save() { TCHAR path[MAX_PATH]; if (_find_pref_dir(path)) { TCHAR filename[MAX_PATH]; wsprintf(filename, TEXT("\\%s\\hpcboot.cnf"), path); HANDLE file = CreateFile(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); DWORD cnt; WriteFile(file, &_pref, _pref._size, &cnt, 0); CloseHandle(file); return cnt == _pref._size; } return FALSE; } // arguments for kernel. int HpcMenuInterface::setup_kernel_args(vaddr_t v, paddr_t p, size_t sz) { int argc = 0; kaddr_t *argv = reinterpret_cast (v); char *loc = reinterpret_cast (v + sizeof(char **) * MAX_KERNEL_ARGS); paddr_t locp = p + sizeof(char **) * MAX_KERNEL_ARGS; size_t len; TCHAR *w; char *ptr; #define SETOPT(c) \ __BEGIN_MACRO \ argv[argc++] = ptokv(locp); \ *loc++ =(c); \ *loc++ = '\0'; \ locp += 2; \ __END_MACRO // 1st arg is kernel name. // DPRINTF_SETUP(); //if you want to use debug print, enable this line. w = _pref.kernel_user_file; argv[argc++] = ptokv(locp); len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0); WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0); loc[len] = '\0'; loc += len + 1; locp += len + 1; if (_pref.boot_serial) // serial console SETOPT('h'); if (_pref.boot_verbose) // boot verbosely SETOPT('v'); if (_pref.boot_single_user) // boot to single user SETOPT('s'); if (_pref.boot_ask_for_name) // ask for file name to boot from SETOPT('a'); if (_pref.boot_debugger) // break into the kernel debugger SETOPT('d'); // boot from switch(_pref.rootfs) { case 0: // wd0 break; case 1: // sd0 argv[argc++] = ptokv(locp); strncpy(loc, "b=sd0", 6); loc += 6; locp += 6; break; case 2: // memory disk w = _pref.rootfs_file; argv[argc++] = ptokv(locp); strncpy(loc, "m=", 2); loc += 2; len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0); WideCharToMultiByte(CP_ACP, 0, w, len, loc, len, 0, 0); loc[len] = '\0'; loc += len + 1; locp += 2 + len + 1; break; case 3: // nfs argv[argc++] = ptokv(locp); strncpy(loc, "b=nfs", 6); loc += 6; locp += 6; break; case 4: // dk0 argv[argc++] = ptokv(locp); strncpy(loc, "b=dk0", 6); loc += 6; locp += 6; break; case 5: // ld0 argv[argc++] = ptokv(locp); strncpy(loc, "b=ld0", 6); loc += 6; locp += 6; break; } // Extra kernel options. (Option tab window) w = _pref.boot_extra; len = WideCharToMultiByte(CP_ACP, 0, w, wcslen(w), 0, 0, 0, 0); if ((ptr = (char *)malloc(len)) == NULL) { MessageBox(_root->_window, L"Can't allocate memory for extra kernel options.", TEXT("WARNING"), MB_ICONWARNING | MB_OK); UpdateWindow(_root->_window); return argc; } WideCharToMultiByte(CP_ACP, 0, w, len, ptr, len, 0, 0); ptr[len]='\0'; while (*ptr == ' ' || *ptr == '\t') ptr++; while (*ptr != '\0') { len = strcspn(ptr, " \t"); if (len == 0) len = strlen(ptr); if (argc == MAX_KERNEL_ARGS || locp + len + 1 > p + sz) { MessageBox(_root->_window, L"Too many extra kernel options.", TEXT("WARNING"), MB_ICONWARNING | MB_OK); UpdateWindow(_root->_window); break; } argv[argc++] = ptokv(locp); strncpy(loc, ptr, len); loc[len] = '\0'; loc += len + 1; locp += len + 1; ptr += len; while (*ptr == ' ' || *ptr == '\t') ptr++; } return argc; } // kernel bootinfo. void HpcMenuInterface::setup_bootinfo(struct bootinfo &bi) { FrameBufferInfo fb(_pref.platid_hi, _pref.platid_lo); TIME_ZONE_INFORMATION tz; DWORD tzid = GetTimeZoneInformation(&tz); memset(&bi, 0, sizeof(struct bootinfo)); bi.length = sizeof(struct bootinfo); bi.reserved = 0; bi.magic = BOOTINFO_MAGIC; bi.fb_addr = fb.addr(); bi.fb_type = fb.type(); bi.fb_line_bytes = fb.linebytes(); bi.fb_width = fb.width(); bi.fb_height = fb.height(); bi.platid_cpu = _pref.platid_hi; bi.platid_machine = _pref.platid_lo; bi.timezone = tz.Bias; if (tzid == TIME_ZONE_ID_DAYLIGHT) bi.timezone += tz.DaylightBias; } // Progress bar void HpcMenuInterface::progress(const char *msg) { _root->progress(msg); } void HpcMenuInterface::unprogress() { _root->unprogress(); } // Boot kernel. void HpcMenuInterface::boot() { struct support_status *tab = _unsupported; uint32_t cpu = _pref.platid_hi; uint32_t machine = _pref.platid_lo; if (_pref.safety_message) for (; tab->cpu; tab++) { if (tab->cpu == cpu && tab->machine == machine) { MessageBox(_root->_window, tab->cause ? tab->cause : L"Not supported yet.", TEXT("BOOT FAILED"), MB_ICONERROR | MB_OK); return; } } if (_boot_hook.func) _boot_hook.func(_boot_hook.arg); }