- make sysreg work again under Windows

svn path=/trunk/; revision=27759
This commit is contained in:
Johannes Anderwald 2007-07-20 18:55:03 +00:00
parent a67d29ae20
commit 5b1cf1f67f
6 changed files with 253 additions and 196 deletions

View file

@ -59,12 +59,15 @@ namespace Sysreg_
if (ws_pos != string::npos && ws_pos > 0 && ws_pos < s_buffer.size()) if (ws_pos != string::npos && ws_pos > 0 && ws_pos < s_buffer.size())
{ {
string name = s_buffer.substr (0, ws_pos); string name = s_buffer.substr (0, ws_pos);
string value = s_buffer.substr (ws_pos + 1); string value = s_buffer.substr (ws_pos + 1, s_buffer.size() - ws_pos - 2);
/*
if (value[value.length () -1] == 0xA) if (value[value.length () -1] == 0xA)
{ {
// remove newline char // remove newline char
value[value.length ()-1] = _T('\0'); value[value.length ()-1] = _T('\0');
} }
*/
// cerr << "name: "<< name << "value: "<< value << "|" << endl;
m_Map[name] = value; m_Map[name] = value;
ret = true; ret = true;
} }
@ -88,6 +91,31 @@ namespace Sysreg_
ConfValue = it->second; ConfValue = it->second;
return true; return true;
} }
//----------------------------------------------------------------------------------------
bool ConfigParser::getDoubleValue(string ConfVariable, double & ConfValue)
{
ConfigMap::iterator it = m_Map.find (ConfVariable);
if (it == m_Map.end ())
{
cerr << "ConfigParser::getValue failed to find " << ConfVariable << endl;
return false;
}
ConfValue = _tcstod(it->second.c_str(), NULL);
return true;
}
//-----------------------------------------------------------------------------------------
bool ConfigParser::getIntValue(string ConfVariable, long int & ConfValue)
{
ConfigMap::iterator it = m_Map.find (ConfVariable);
if (it == m_Map.end ())
{
cerr << "ConfigParser::getValue failed to find " << ConfVariable << endl;
return false;
}
ConfValue = _tcstol(it->second.c_str(), NULL, 10);
return true;
}
} // end of namespace Sysreg_ } // end of namespace Sysreg_

View file

@ -77,6 +77,9 @@ namespace Sysreg_
bool getStringValue(string & ConfVariable, string & ConfValue); bool getStringValue(string & ConfVariable, string & ConfValue);
bool getDoubleValue(string ConfVariable, double & value);
bool getIntValue(string ConfVariable, long int & value);
protected: protected:
ConfigMap m_Map; ConfigMap m_Map;

View file

@ -41,7 +41,7 @@ namespace System_
return false; return false;
} }
h_Pipe = CreateFile(PipeCmd.c_str(), h_Pipe = CreateFile("\\\\.\\pipe\\qemu", //PipeCmd.c_str(),
GENERIC_WRITE | GENERIC_READ, GENERIC_WRITE | GENERIC_READ,
0, 0,
NULL, NULL,
@ -51,7 +51,7 @@ namespace System_
NULL); NULL);
if(INVALID_HANDLE_VALUE == h_Pipe) { if(INVALID_HANDLE_VALUE == h_Pipe) {
cerr << "NamedPipeReader::openPipe> failed to open pipe " << PipeCmd << GetLastError() << endl; cerr << "NamedPipeReader::openPipe> failed to open pipe " << PipeCmd << " Error:" << GetLastError() << endl;
h_Pipe = NULLVAL; h_Pipe = NULLVAL;
return false; return false;
} }
@ -70,7 +70,7 @@ namespace System_
bool NamedPipeReader::closeSource() bool NamedPipeReader::closeSource()
{ {
if (!h_Pipe) if (h_Pipe == INVALID_HANDLE_VALUE)
{ {
cerr << "NamedPipeReader::closePipe> pipe is not open" << endl; cerr << "NamedPipeReader::closePipe> pipe is not open" << endl;
return false; return false;

View file

@ -25,6 +25,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <signal.h>
namespace Sysreg_ namespace Sysreg_
@ -43,20 +44,23 @@ namespace Sysreg_
using std::ofstream; using std::ofstream;
#endif #endif
string RosBootTest::VARIABLE_NAME = _T("ROSBOOT_CMD"); string RosBootTest::ROS_EMU_TYPE= _T("ROS_EMU_TYPE");
string RosBootTest::CLASS_NAME = _T("rosboot"); string RosBootTest::EMU_TYPE_QEMU = _T("qemu");
string RosBootTest::DEBUG_PORT = _T("ROSBOOT_DEBUG_PORT"); string RosBootTest::EMU_TYPE_VMWARE = _T("vmware");
string RosBootTest::DEBUG_FILE = _T("ROSBOOT_DEBUG_FILE"); string RosBootTest::ROS_EMU_PATH = _T("ROS_EMU_PATH");
string RosBootTest::TIME_OUT = _T("ROSBOOT_TIME_OUT"); string RosBootTest::ROS_HDD_IMAGE= _T("ROS_HDD_IMAGE");
string RosBootTest::PID_FILE= _T("ROSBOOT_PID_FILE"); string RosBootTest::ROS_CD_IMAGE = _T("ROS_CD_IMAGE");
string RosBootTest::DELAY_READ = _T("ROSBOOT_DELAY_READ"); string RosBootTest::ROS_MAX_TIME = _T("ROS_MAX_TIME");
string RosBootTest::CHECK_POINT = _T("ROSBOOT_CHECK_POINT"); string RosBootTest::ROS_LOG_FILE = _T("ROS_LOG_FILE");
string RosBootTest::SYSREG_CHECKPOINT = _T("SYSREG_CHECKPOINT:"); string RosBootTest::ROS_SYM_DIR = _T("ROS_SYM_DIR");
string RosBootTest::CRITICAL_APP = _T("ROSBOOT_CRITICAL_APP"); string RosBootTest::ROS_DELAY_READ = _T("ROS_DELAY_READ");
string RosBootTest::TERMINATE_EMULATOR = _T("ROSBOOT_TERMINATE_EMULATOR"); string RosBootTest::ROS_SYSREG_CHECKPOINT = _T("SYSREG_CHECKPOINT:");
string RosBootTest::ROS_CRITICAL_IMAGE = _T("ROS_CRITICAL_IMAGE");
string RosBootTest::ROS_EMU_KILL = _T("ROS_EMU_KILL");
string RosBootTest::ROS_EMU_MEM = _T("ROS_EMU_MEM");
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
RosBootTest::RosBootTest() : m_Timeout(60.0), m_Delayread(0) RosBootTest::RosBootTest() : m_MaxTime(0.0), m_DelayRead(0)
{ {
} }
@ -81,196 +85,183 @@ namespace Sysreg_
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
void RosBootTest::delayRead() void RosBootTest::delayRead()
{ {
if (m_Delayread) if (m_DelayRead)
{ {
/// ///
/// delay reading until emulator is ready /// delay reading until emulator is ready
/// ///
OsSupport::sleep(m_Delayread * CLOCKS_PER_SEC ); OsSupport::sleep(m_DelayRead);
} }
} }
//----------------------------------------------------------------------------------------
bool RosBootTest::configureQemu()
{
string qemupath;
string::size_type pos;
//--------------------------------------------------------------------------------------- bool bootfromcd = false;
bool RosBootTest::configurePipe()
if (m_CDImage != _T("") )
{ {
if (!_tcscmp(m_DebugPort.c_str(), _T("qemupipe"))) bootfromcd = true;
{ }
string::size_type pipe_pos = m_BootCmd.find(_T("-serial pipe:"));
if (pipe_pos != string::npos)
{
pipe_pos += 12;
string::size_type pipe_pos_end = m_BootCmd.find (_T(" "), pipe_pos);
if (pipe_pos != string::npos && pipe_pos_end != string::npos)
{
m_Pipe = _T("\\\\.\\pipe\\") + m_BootCmd.substr (pipe_pos, pipe_pos_end - pipe_pos);
#ifdef __LINUX__ #ifdef __LINUX__
m_DataSource = new PipeReader(); pos = m_EmuPath.find_last_of(_T("/"));
#else #else
m_DataSource = new NamedPipeReader(); pos = m_EmuPath.find_last_of(_T("\\"));
#endif #endif
return true; if (pos == string::npos)
}
}
}
else if (!_tcscmp(m_DebugPort.c_str(), _T("vmwarepipe")))
{ {
cerr << "VmWare debug pipe is currently fixed to \\\\.\\pipe\\vmwaredebug" << endl; cerr << "Error: ROS_EMU_PATH is invalid!!!" << endl;
m_Pipe = _T("\\\\.\\pipe\\vmwaredebug");
#ifdef __LINUX__
m_DataSource = new PipeReader();
#else
m_DataSource = new NamedPipeReader();
#endif
return true;
}
//
// FIXME
// support other emulators
return false; return false;
} }
qemupath = m_EmuPath.substr(0, pos);
if (m_HDDImage == _T(""))
{
if(!bootfromcd)
{
cerr << "Error: ROS_CD_IMAGE and ROS_HDD_IMAGE is not set!!!" << endl;
return false;
}
string qemuimgdir = qemupath;
#ifdef __LINUX___
qemuimgdir += _T("qemu-img");
#else
qemuimgdir += _T("qemu-img.exe");
#endif
///
/// FIXME
/// call qemu-img to create the tool
///
cerr << "Creating HDD Image ..." << endl;
}
if (m_MaxMem == "")
{
// default to 64M
m_MaxMem = "64";
}
if (bootfromcd)
{
m_BootCmd = m_EmuPath + _T(" -serial pipe:qemu -L ") + qemupath + _T(" -m ") + m_MaxMem + _T(" -hda ") + m_HDDImage + _T(" -boot d -cdrom ") + m_CDImage;
}
else
{
m_BootCmd = m_EmuPath + _T(" -L ") + qemupath + _T(" -m ") + m_MaxMem + _T(" -boot c -serial pipe:sysreg");
}
if (m_KillEmulator == _T("yes"))
{
#ifdef __LINUX__
m_BootCmd += _T(" -pidfile pid.txt");
#endif
}
else
{
m_BootCmd += _T(" -no-reboot ");
}
cerr << "Opening Data Source:" << m_BootCmd << endl;
#ifdef __LINUX__
m_DataSource = new PipeReader();
m_Src = m_BootCmd;
#else
m_DataSource = new NamedPipeReader();
m_Src = _T("\\\\.\\pipe\\qemu");
if (!executeBootCmd())
{
cerr << "Error: failed to launch emulator with: " << m_BootCmd << endl;
return false;
}
#endif
return true;
}
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
bool RosBootTest::configureFile() bool RosBootTest::configureVmWare()
{ {
if (!_tcscmp(m_DebugPort.c_str(), _T("qemufile"))) cerr << "VmWare is currently not yet supported" << endl;
{
string::size_type file_pos = m_BootCmd.find(_T("-serial file:"));
if (file_pos != string::npos)
{
file_pos += 12;
string::size_type file_pos_end = m_BootCmd.find (_T(" "), file_pos);
if (file_pos != string::npos && file_pos_end != string::npos)
{
m_File = m_BootCmd.substr (file_pos, file_pos_end - file_pos);
m_DataSource = new FileReader();
return true;
}
cerr << "Error: missing space at end of option" << endl;
}
}
else if (!_tcscmp(m_DebugPort.c_str(), _T("vmwarefile")))
{
cerr << "VmWare debug file is currently fixed to debug.log" << endl;
m_File = "debug.log";
m_DataSource = new FileReader();
return true;
}
//
// FIXME
// support other emulators
return false; return false;
} }
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
bool RosBootTest::readConfigurationValues(ConfigParser &conf_parser) bool RosBootTest::readConfigurationValues(ConfigParser &conf_parser)
{ {
/// if (!conf_parser.getStringValue(RosBootTest::ROS_EMU_TYPE, m_EmuType))
/// read required configuration arguments
///
if (!conf_parser.getStringValue (RosBootTest::DEBUG_PORT, m_DebugPort))
{ {
cerr << "Error: ROSBOOT_DEBUG_TYPE is not set in configuration file" << endl; cerr << "Error: ROS_EMU_TYPE is not set" << endl;
return false;
}
if (!conf_parser.getStringValue(RosBootTest::VARIABLE_NAME, m_BootCmd))
{
cerr << "Error: ROSBOOT_CMD is not set in configuration file" << endl;
return false; return false;
} }
string timeout; if (!conf_parser.getStringValue(RosBootTest::ROS_EMU_PATH, m_EmuPath))
if (conf_parser.getStringValue(RosBootTest::TIME_OUT, timeout))
{ {
TCHAR * stop; cerr << "Error: ROS_EMU_PATH is not set" << endl;
m_Timeout = _tcstod(timeout.c_str (), &stop); return false;
if (isnan(m_Timeout) || m_Timeout == 0.0)
{
cerr << "Warning: overriding timeout with default of 60 sec" << endl;
m_Timeout = 60.0;
}
} }
string delayread; conf_parser.getStringValue (RosBootTest::ROS_HDD_IMAGE, m_HDDImage);
if (conf_parser.getStringValue(RosBootTest::DELAY_READ, delayread)) conf_parser.getStringValue (RosBootTest::ROS_CD_IMAGE, m_CDImage);
{ conf_parser.getDoubleValue (RosBootTest::ROS_MAX_TIME, m_MaxTime);
TCHAR * stop; conf_parser.getStringValue (RosBootTest::ROS_LOG_FILE, m_DebugFile);
m_Delayread = _tcstoul(delayread.c_str (), &stop, 10); conf_parser.getStringValue (RosBootTest::ROS_SYM_DIR, m_SymDir);
if (m_Delayread > 60 || m_Delayread < 0) conf_parser.getIntValue (RosBootTest::ROS_DELAY_READ, m_DelayRead);
{ conf_parser.getStringValue (RosBootTest::ROS_SYSREG_CHECKPOINT, m_Checkpoint);
cerr << "Warning: disabling delay read" << endl; conf_parser.getStringValue (RosBootTest::ROS_CRITICAL_IMAGE, m_CriticalImage);
m_Delayread = 0; conf_parser.getStringValue (RosBootTest::ROS_EMU_KILL, m_KillEmulator);
} conf_parser.getStringValue (RosBootTest::ROS_EMU_MEM, m_MaxMem);
}
///
/// read optional arguments
///
conf_parser.getStringValue (RosBootTest::CHECK_POINT, m_Checkpoint);
conf_parser.getStringValue (RosBootTest::CRITICAL_APP, m_CriticalApp);
conf_parser.getStringValue (RosBootTest::DEBUG_FILE, m_DebugFile);
conf_parser.getStringValue (RosBootTest::TERMINATE_EMULATOR, m_KillEmulator);
return true; return true;
} }
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
bool RosBootTest::execute(ConfigParser &conf_parser) bool RosBootTest::execute(ConfigParser &conf_parser)
{ {
if (!readConfigurationValues(conf_parser)) if (!readConfigurationValues(conf_parser))
{ {
return false; return false;
} }
string src; if (m_EmuType == EMU_TYPE_QEMU)
{
if (!configureQemu())
{
cerr << "Error: failed to configure qemu" << endl;
return false;
}
}
else if (m_EmuType == EMU_TYPE_VMWARE)
{
if (!configureVmWare())
{
cerr << "Error: failed to configure vmware" << endl;
return false;
}
}
else
{
///
/// unsupported emulator
if (m_DebugPort.find(_T("pipe")) != string::npos) cerr << "Error: ROS_EMU_TYPE value is not supported:" << m_EmuType << "=" << EMU_TYPE_QEMU << endl;
{
if (!configurePipe())
{
cerr << "Error: failed to configure pipe" << endl;
return false; return false;
} }
#ifndef __LINUX__ OsSupport::sleep(500);
if (!executeBootCmd())
if (!m_DataSource->openSource(m_Src))
{ {
cerr << "Error: failed to launch emulator" << endl; cerr << "Error: failed to open data source with " << m_Src << endl;
return false;
}
#endif
src = m_Pipe;
}
else if (m_DebugPort.find(_T("file")) != string::npos)
{
if (!configureFile())
{
cerr << "Error: failed to configure pipe" << endl;
return false;
}
if (!executeBootCmd())
{
cerr << "Error: failed to launch emulator" << endl;
return false; return false;
} }
src = m_File; OsSupport::sleep(3000);
}
if (!m_DataSource->openSource(src))
{
cerr << "Error: failed to open data source with " << src << endl;
return false;
}
bool ret = analyzeDebugData(); bool ret = analyzeDebugData();
@ -314,10 +305,10 @@ namespace Sysreg_
cout << line << endl; cout << line << endl;
if (line.find (RosBootTest::SYSREG_CHECKPOINT) != string::npos) if (line.find (RosBootTest::ROS_SYSREG_CHECKPOINT) != string::npos)
{ {
line.erase (0, line.find (RosBootTest::SYSREG_CHECKPOINT) + line.erase (0, line.find (RosBootTest::ROS_SYSREG_CHECKPOINT) +
RosBootTest::SYSREG_CHECKPOINT.length ()); RosBootTest::ROS_SYSREG_CHECKPOINT.length ());
if (!_tcsncmp(line.c_str (), m_Checkpoint.c_str (), m_Checkpoint.length ())) if (!_tcsncmp(line.c_str (), m_Checkpoint.c_str (), m_Checkpoint.length ()))
{ {
state = DebugStateCPReached; state = DebugStateCPReached;
@ -357,7 +348,7 @@ namespace Sysreg_
} }
else if (line.find (_T("Unhandled exception")) != string::npos) else if (line.find (_T("Unhandled exception")) != string::npos)
{ {
if (m_CriticalApp == _T("IGNORE")) if (m_CriticalImage == _T("IGNORE"))
{ {
/// ///
/// ignoring all user-mode exceptions /// ignoring all user-mode exceptions
@ -403,7 +394,7 @@ namespace Sysreg_
} }
string appname = modulename.substr (pos + 1, modulename.length () - pos); string appname = modulename.substr (pos + 1, modulename.length () - pos);
if (m_CriticalApp.find (appname) == string::npos && m_CriticalApp.length () > 1) if (m_CriticalImage.find (appname) == string::npos && m_CriticalImage.length () > 1)
{ {
/// the application is not in the list of /// the application is not in the list of
/// critical apps. Therefore we ignore the user-mode /// critical apps. Therefore we ignore the user-mode
@ -453,6 +444,11 @@ namespace Sysreg_
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
bool RosBootTest::isTimeout(double max_timeout) bool RosBootTest::isTimeout(double max_timeout)
{ {
if (max_timeout == 0)
{
// no timeout specified
return false;
}
static time_t start = 0; static time_t start = 0;
if (!start) if (!start)
@ -493,7 +489,7 @@ namespace Sysreg_
write_log = file.is_open (); write_log = file.is_open ();
while(1) while(1)
{ {
if (isTimeout(m_Timeout)) if (isTimeout(m_MaxTime))
{ {
break; break;
} }

View file

@ -11,6 +11,8 @@
*/ */
#include "data_source.h" #include "data_source.h"
#include "conf_parser.h" #include "conf_parser.h"
#include "os_support.h"
#include "user_types.h"
#include <vector> #include <vector>
#include <unistd.h> #include <unistd.h>
@ -19,6 +21,8 @@ namespace Sysreg_
{ {
using std::vector; using std::vector;
using System_::DataSource; using System_::DataSource;
using System_::OsSupport;
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
/// ///
@ -30,17 +34,22 @@ namespace Sysreg_
class RosBootTest class RosBootTest
{ {
public: public:
static string VARIABLE_NAME;
static string CLASS_NAME; static string ROS_EMU_TYPE;
static string DEBUG_PORT; static string EMU_TYPE_QEMU;
static string DEBUG_FILE; static string EMU_TYPE_VMWARE;
static string TIME_OUT; static string ROS_EMU_PATH;
static string PID_FILE; static string ROS_HDD_IMAGE;
static string CHECK_POINT; static string ROS_CD_IMAGE;
static string SYSREG_CHECKPOINT; static string ROS_MAX_TIME;
static string DELAY_READ; static string ROS_LOG_FILE;
static string CRITICAL_APP; static string ROS_SYM_DIR;
static string TERMINATE_EMULATOR; static string ROS_DELAY_READ;
static string ROS_SYSREG_CHECKPOINT;
static string ROS_CRITICAL_IMAGE;
static string ROS_EMU_KILL;
static string ROS_EMU_MEM;
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
/// ///
@ -81,7 +90,8 @@ namespace Sysreg_
bool configureFile(); bool configureFile();
bool analyzeDebugData(); bool analyzeDebugData();
bool readConfigurationValues(ConfigParser & conf_parser); bool readConfigurationValues(ConfigParser & conf_parser);
bool configureQemu();
bool configureVmWare();
//--------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------
/// ///
@ -122,20 +132,24 @@ typedef enum DebugState
protected: protected:
double m_Timeout; string m_EmuType;
string m_Checkpoint; string m_EmuPath;
string m_CriticalApp; string m_HDDImage;
string m_CDImage;
double m_MaxTime;
string m_DebugFile; string m_DebugFile;
string m_BootCmd; string m_SymDir;
string m_DebugPort; long int m_DelayRead;
string m_Pipe; string m_Checkpoint;
string m_File; string m_CriticalImage;
string m_KillEmulator; string m_KillEmulator;
string m_MaxMem;
string m_BootCmd;
string m_Src;
DataSource * m_DataSource; DataSource * m_DataSource;
vector <string> m_Checkpoints; OsSupport::ProcessID m_Pid;
unsigned long m_Delayread; std::vector<string> m_Checkpoints;
long m_Pid;
long m_DelayRead;
}; // end of class RosBootTest }; // end of class RosBootTest

View file

@ -14,13 +14,13 @@ ROS_EMU_TYPE=qemu
ROS_EMU_PATH=E:\reactos\qemu\qemu.exe ROS_EMU_PATH=E:\reactos\qemu\qemu.exe
; ROS_HD_IMAGE ; ROS_HDD_IMAGE
; ;
; The hdd image to use for running the emulator. If this variable is not ; The hdd image to use for running the emulator. If this variable is not
; set, SysReg will create a HDD with name "ros.img" using the qemu-img tool. It will search ; set, SysReg will create a HDD with name "ros.img" using the qemu-img tool. It will search
; this tool in the directory of emulator and abort if the tool cannot be found ; this tool in the directory of emulator and abort if the tool cannot be found
ROS_HD_IMAGE=E:\reactos\qemu\RosVMDK.img ROS_HDD_IMAGE=E:\reactos\qemu\ReactOS.hd
; ROS_CD_IMAGE ; ROS_CD_IMAGE
; ;
@ -29,7 +29,7 @@ ROS_HD_IMAGE=E:\reactos\qemu\RosVMDK.img
; from harddisk. ; from harddisk.
; ;
ROS_CD_IMAGE=E:\reactos\qemu\Reactos-RegTest.iso ROS_CD_IMAGE=E:\reactos\qemu\Reactos.iso
;------------------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------------------
; Additional Options ; Additional Options
@ -62,7 +62,7 @@ ROS_CD_IMAGE=E:\reactos\qemu\Reactos-RegTest.iso
; ;
; Note: set this value if you have problems with timeouts or cutoff debugging data ; Note: set this value if you have problems with timeouts or cutoff debugging data
; ;
; ROS_DELAY_READ=4 ROS_DELAY_READ=4000
; ROS_CHECK_POINT ; ROS_CHECK_POINT
; ;
@ -77,3 +77,19 @@ ROS_CD_IMAGE=E:\reactos\qemu\Reactos-RegTest.iso
; that the test has failed and quit debugging immediately ; that the test has failed and quit debugging immediately
; ;
;ROS_CRITICAL_IMAGE=setup.exe userinit.exe smss.exe winlogon.exe csrss.exe explorer.exe ;ROS_CRITICAL_IMAGE=setup.exe userinit.exe smss.exe winlogon.exe csrss.exe explorer.exe
; ROS_EMU_KILL
;
; Set this variable to true if you want SysReg to kill the emulator process when it has decided to exit.
;
; Note: Qemu>=0.9.0 has the option to shutdown on reboot (-no--reboot)
;
; ROS_EMU_KILL=yes
; ROS_EMU_MEM
;
; Controls how much memory the emulator use for ReactOS
;
; ROS_EMU_MEM=64