1622 lines
51 KiB
Plaintext
1622 lines
51 KiB
Plaintext
<!--
|
||
================================================================
|
||
doc/docbook/development/development.dbk
|
||
$Id: development.dbk,v 1.13 2003-11-02 10:23:59 cbothamy Exp $
|
||
|
||
This is the top level file for the Bochs Developers Manual.
|
||
================================================================
|
||
-->
|
||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
|
||
|
||
<!-- include definitions that are common to all bochs documentation -->
|
||
<!ENTITY % bochsdefs SYSTEM "../include/defs.sgm">
|
||
%bochsdefs;
|
||
|
||
]>
|
||
<book>
|
||
<bookinfo>
|
||
<title>Bochs Developers Guide</title>
|
||
<authorgroup>
|
||
<author><firstname>Kevin</firstname><surname>Lawton</surname></author>
|
||
<author><firstname>Bryce</firstname><surname>Denney</surname></author>
|
||
<author><firstname>Christophe</firstname><surname>Bothamy</surname></author>
|
||
<editor><firstname>Michael</firstname><surname>Calabrese</surname></editor>
|
||
</authorgroup>
|
||
</bookinfo>
|
||
|
||
<!-- *************************************************************** -->
|
||
<chapter id="resources"><title>Resources for developers</title>
|
||
<para>
|
||
The development guide describes resources that are intended for developers
|
||
in particular. Many Bochs resources are also covered in the User Guide,
|
||
including compile instructions, bochsrc options, how to find the mailing
|
||
lists, etc.
|
||
</para>
|
||
|
||
|
||
<section><title>Setting up CVS write access</title>
|
||
<para>
|
||
If you are an official SourceForge developer, then you can use CVS with write
|
||
access. The CVS contains the most recent copy of the source code, and with
|
||
write access you can upload any changes you make to the CVS server for others
|
||
to use. A few extra steps are required the first time you use CVS write
|
||
access.
|
||
</para>
|
||
|
||
<section><title>Install ssh and cvs</title>
|
||
<para>
|
||
First you need to install both cvs (Concurrent Version System) and ssh (Secure
|
||
Shell). These are already installed on many UNIX systems and also Cygwin
|
||
(win32 platform). If not, you can install binaries or compile cvs and ssh
|
||
yourself. The links below should help you get going.
|
||
</para>
|
||
<itemizedlist>
|
||
<listitem> <para> CVS software and instructions are available at <ulink url="http://www.cvshome.org">www.cvshome.org</ulink>. </para> </listitem>
|
||
<listitem> <para> A free version of secure shell called OpenSSH is at <ulink url="http://www.openssh.org">www.openssh.org</ulink>. </para> </listitem>
|
||
<listitem> <para> OpenSSH requires a library called OpenSSL from <ulink url="http://www.openssl.org">www.openssl.org</ulink>. Be sure to install OpenSSL before trying to compile OpenSSH. </para> </listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
<section><title>ssh to cvs.sf.net</title>
|
||
<para>
|
||
Next, you need to use secure shell to connect to cvs.sf.net. This step is a
|
||
little strange, because you can't actually log in and get a shell prompt. All
|
||
that will happen, when you get the username and password right, is that it
|
||
will create a home directory on that machine for you. That's it! If you try
|
||
it again, it will say "This is a restricted Shell Account. You cannot execute
|
||
anything here." At this point, you've succeeded and you never have to do
|
||
this step again, ever.
|
||
|
||
<screen>
|
||
ssh <replaceable>sfusername</replaceable>@cvs.sf.net
|
||
</screen>
|
||
</para>
|
||
|
||
<para>
|
||
Replace <replaceable>sfusername</replaceable> with your Source Forge username,
|
||
of course. The first time, you will probably get a message like
|
||
<screen>
|
||
The authenticity of host 'cvs.sf.net' can't be established.
|
||
Are you sure you want to continue?</screen>
|
||
|
||
Just type yes. When it asks for a password, be sure to type your source
|
||
forge password. If you have trouble logging in, be sure to use your SOURCE
|
||
FORGE username and password in the ssh line, which isn't necessarily the same
|
||
as your local username and password. Add the "-v" option to ssh to see more
|
||
information about what is failing. If you have ssh version 2, it is possible
|
||
that you might need to add "-1" to the ssh command to force it to use the
|
||
version 1 protocol. </para> </section>
|
||
|
||
<section><title>Set CVS_RSH environment variable to ssh</title>
|
||
<para>
|
||
Every time you connect to the Source Forge CVS server (including cvs update,
|
||
stat, commit, etc.), you must set the CVS_RSH environment variable to ssh. So
|
||
just take the time now to add one of these lines to your .bashrc/.cshrc, so
|
||
that the CVS_RSH setting will be there every time you log in.
|
||
</para>
|
||
|
||
<screen>
|
||
export CVS_RSH=ssh (bash syntax)
|
||
setenv CVS_RSH ssh (csh syntax)
|
||
</screen>
|
||
</section> <!--end of "Set environment variable"-->
|
||
|
||
<section><title>cvs checkout</title>
|
||
<para>
|
||
Finally, you should be able to do the checkout! If you already have a bochs
|
||
subdirectory directory, move it out of the way because the checkout will
|
||
overwrite it.
|
||
</para>
|
||
|
||
<screen>
|
||
export CVSROOT=":ext:<replaceable>sfusername</replaceable>@cvs.bochs.sourceforge.net:/cvsroot/bochs"
|
||
cvs -z3 checkout bochs
|
||
<replaceable>sfusername</replaceable>@cvs.sf.net's password: <replaceable><--type your password</replaceable>
|
||
</screen>
|
||
|
||
<para>
|
||
In the CVSROOT variable, replace <replaceable>sfusername</replaceable> with your SF username. There's
|
||
no need to add CVSROOT to your rc files because CVS will remember it
|
||
after the checkout. The -z3 (optional) just adds some compression to make
|
||
the checkout go faster. Once all the files have been downloaded, you will
|
||
have a bochs directory which is checked out with write access!
|
||
</para>
|
||
</section> <!-- end cvs checkout -->
|
||
|
||
</section> <!-- end setting up cvs write access -->
|
||
|
||
<section id="using-cvs-write-access"><title>Using CVS write access</title>
|
||
|
||
<section><title>Checking in files</title>
|
||
<para>
|
||
Once you have a bochs directory with cvs write access, you can compile the
|
||
files, edit them, test them, etc. See the documentation section, "Tracking
|
||
the source code with CVS" for more info on CVS, in the User Manual.
|
||
(FIXME: add cross reference) But what's new and different is that you can now
|
||
do cvs commits. When a file is all fixed and ready to share with the rest of
|
||
the world, you run a commit command to upload your version to the server.
|
||
First, it's good to do a cvs update to make sure nobody else has changed it
|
||
since you downloaded it last.
|
||
</para>
|
||
|
||
<screen>
|
||
$ cvs update file.cc
|
||
<replaceable>sfusername</replaceable>@cvs.sf.net's password: <replaceable><--type your password</replaceable>
|
||
$ cvs commit file.cc
|
||
<replaceable>sfusername</replaceable>@cvs.sf.net's password: <replaceable><--type your password</replaceable>
|
||
[editor opens. type log message, save, and exit.]
|
||
</screen>
|
||
|
||
<para>
|
||
When CVS starts an editor, The default is usually vi. If you want a different
|
||
editor, set the EDITOR environment variable to the name of your preferred
|
||
editor. When you're done, just save the file and quit the editor. Unless
|
||
there's some problem, you will see a message that says what the new revision
|
||
number for the file is, and then "done". If while you're editing the log
|
||
message, you decide that you don't want to commit after all, don't save the
|
||
file. Quit the editor, and when it asks where the log message went, tell it
|
||
to abort.
|
||
</para>
|
||
|
||
<para>
|
||
Here is an example of a successful checkin:
|
||
|
||
<screen>
|
||
$ cvs commit misc.txt
|
||
<replaceable>sfusername</replaceable>@cvs.sf.net's password: <replaceable><--type your password</replaceable>
|
||
[edit log msg]
|
||
Checking in misc.txt;
|
||
/cvsroot/bochs/bochs/doc/docbook/misc.txt,v <-- misc.txt
|
||
new revision: 1.6; previous revision: 1.5
|
||
done
|
||
</screen>
|
||
|
||
And here is an aborted one:
|
||
|
||
<screen>
|
||
$ cvs commit misc.txt
|
||
<replaceable>sfusername</replaceable>@cvs.sf.net's password: <replaceable><--type your password</replaceable>
|
||
[quit editor without saving]
|
||
Log message unchanged or not specified
|
||
a)bort, c)ontinue, e)dit, !)reuse this message unchanged for remaining dirs
|
||
Action: a
|
||
cvs [commit aborted]: aborted by user
|
||
</screen>
|
||
|
||
</para>
|
||
</section> <!--end of "Checking in Files" -->
|
||
|
||
</section> <!--end of "Using CVS write access" -->
|
||
|
||
<section id="trackers"><title>SourceForge bug, feature, and patch trackers</title>
|
||
<para>
|
||
&FIXME;
|
||
</para>
|
||
</section>
|
||
|
||
<section id="other"><title>Ideas for other sections</title>
|
||
<para>
|
||
<screen>
|
||
Ideas:
|
||
- how to browse code with cvsweb
|
||
- how to find an identifier, variable, or specific text in the code
|
||
- write access CVS (must be an official developer on SF)
|
||
- how to make patches with CVS
|
||
</screen>
|
||
</para>
|
||
</section>
|
||
|
||
</chapter>
|
||
|
||
<chapter id="about-the-code"><title>About the code</title>
|
||
|
||
<section><title>How to add keymapping in a GUI client</title>
|
||
<para>
|
||
Christophe Bothamy, wrote the keymapping code for Bochs, provided these
|
||
instructions to help developers to add keymapping to a GUI.
|
||
</para>
|
||
|
||
<screen>
|
||
Bochs creates a bx_keymap_c object named bx_keymap.
|
||
This object allows you to :
|
||
- load the configuration specified keymap file
|
||
- get the translated BX_KEY_* from your GUI key
|
||
|
||
You have to provide a translation function from string to your Bit32u key
|
||
constant. Casting will be necessary if your key constants are not Bit32u typed.
|
||
The function must be "static Bit32u (*)(const char *)" typed, and must return
|
||
BX_KEYMAP_UNKNOWN if it can not translate the parameter string.
|
||
|
||
What you have to do is :
|
||
- call once "void loadKeymap(Bit32u (*)(const char*))",
|
||
providing your translation function, to load the keymap
|
||
- call "Bit32u getBXKey(Bit32u)" that returns the BX_KEY_*
|
||
constant, for each key you want to map.
|
||
|
||
The file gui/x.cc implements this architecture, so you can refer to it
|
||
as an example.
|
||
</screen>
|
||
|
||
</section>
|
||
|
||
<section id="directory-structure"><title>Directory Structure</title>
|
||
<para>
|
||
&FIXME;
|
||
cpu directory does this, iodev does that, gui does that
|
||
</para>
|
||
</section>
|
||
|
||
<section id="configure-scripting"><title>Configure Scripting</title>
|
||
<para>
|
||
&FIXME;
|
||
configure script, makefiles, header files
|
||
</para>
|
||
</section>
|
||
|
||
<section id="logfunctions"><title>Log Functions</title>
|
||
<para>
|
||
&FIXME;
|
||
log functions: what is a panic, what is an error, etc.
|
||
</para>
|
||
</section>
|
||
|
||
<section id="emulator-objects"><title>Emulator Objects</title>
|
||
<para>
|
||
&FIXME;
|
||
objects that do all the work (cpu, mem)
|
||
</para>
|
||
</section>
|
||
|
||
<section id="timers"><title>timers</title>
|
||
<para>
|
||
&FIXME;
|
||
</para>
|
||
</section>
|
||
|
||
<section id="sb16-emulation-basics"> <!-- start of SB16 section-->
|
||
|
||
<title>Sound Blaster 16 Emulation</title>
|
||
<para>
|
||
Sound Blaster 16 (SB16) emulation for Bochs was written and donated by
|
||
Josef Drexler, who has a
|
||
<ulink url="http://publish.uwo.ca/~jdrexler/bochs/">web page</ulink> on the topic.
|
||
The entire set of his SB16 patches have been integrated into
|
||
Bochs, however, so you can find everything you need here.
|
||
</para>
|
||
|
||
<para>
|
||
SB16 Emulation has been tested with several soundcards and versions of Linux. Please give
|
||
Josef <ulink url="mailto:jdrexler@julian.uwo.ca">feedback</ulink> on
|
||
whether is does or doesn't work on your combination of software and hardware.
|
||
</para>
|
||
|
||
<section><title>How well does it work?</title>
|
||
<para>
|
||
Right now, MPU401 emulation is next to perfect. It supports UART
|
||
and SBMIDI mode, because the SB16's MPU401 ports can't do anything else as well.
|
||
</para>
|
||
|
||
<para>
|
||
The digital audio basically works, but the emulation is too slow for fluent
|
||
output unless the application doesn't do much in the background (or the
|
||
foreground, really). The sound tends to looping or crackle on slower
|
||
computer, but the emulation appears to be correct. Even a MOD
|
||
player works, although only for lower sampling speeds.
|
||
</para>
|
||
<para>
|
||
Also, the MIDI data running through the MPU401 ports can be written
|
||
into a SMF, that is the standard midi file. The wave output
|
||
can be written into a VOC file, which has a format defined by
|
||
Creative Labs. This file format can be converted to WAV by
|
||
sox for example.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>Output to a sound card</title>
|
||
|
||
<para>
|
||
Output is supported on Linux and Windows 95 at the moment.
|
||
On Linux, the output goes to any file or device. If you have a
|
||
wavetable synthesizer, midi can go to /dev/midi00, otherwise you may need
|
||
a midi interpreter. For example, the midid program from the
|
||
DosEmu project would work. Wave output should go to /dev/dsp.
|
||
These devices are assumed to be OSS devices, if they're not
|
||
some of the ioctl's might fail.
|
||
On Windows, midi and output goes to the midi mapper and the wave mapper,
|
||
respectively. A future version might have selectable output devices.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>Installation on Linux</title>
|
||
|
||
<para>
|
||
<emphasis>Prerequisites:</emphasis>
|
||
</para>
|
||
|
||
<para>
|
||
A wavetable synthesizer on /dev/midi00 and a working /dev/dsp if you want real time music and sound, otherwise output to midi and wave files is also possible.
|
||
Optionally, you can use a software midi interpreter, such as the midid program from the DosEmu project instead of /dev/midi00.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>Configuring bochs</title>
|
||
|
||
<para>
|
||
There are a few values in config.h that are relevant to the sound functions.
|
||
Edit config.h after running configure, but before compiling.
|
||
</para>
|
||
|
||
<para>
|
||
BX_USE_SB16_SMF should be 1 unless you intend to have several sound cards
|
||
running at the same time.
|
||
</para>
|
||
|
||
<para>
|
||
BX_USE_SOUND_VIRTUAL can be 0 or 1, and determines whether the output class
|
||
uses virtual functions or not. The former is more versatile and allows to
|
||
select the class at runtime (not supported at the moment), while the latter
|
||
is slightly faster.
|
||
</para>
|
||
|
||
<para>
|
||
BX_SOUND_OUTPUT_C is the name of the class used for output. The default is
|
||
to have no output functions, so you need to change this if you want any sound.
|
||
The following are supported at the moment:
|
||
</para>
|
||
|
||
<programlisting>
|
||
bx_sound_linux_c for output to /dev/dsp and /dev/midi00 on Linux
|
||
(and maybe other OSes that use the OSS driver)
|
||
bx_sound_windows_c for output to the midi and wave mapper of
|
||
Windows 3.1 and higher.
|
||
bx_sound_output_c for no output at all.
|
||
</programlisting>
|
||
|
||
<para>
|
||
Setup the SB16 emulation in your .bochsrc, according to instructions
|
||
in that file.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>Runtime configuration</title>
|
||
|
||
<para>
|
||
The source for the SB16CTRL program that is used to modify
|
||
the runtime behaviour of the SB16 emulator is included in
|
||
misc/sb16. You can compile it or download the
|
||
<ulink url="http://publish.uwo.ca/~jdrexler/bochs/">executable</ulink>.
|
||
</para>
|
||
|
||
<para>
|
||
See the section "Sound Blaster 16 Emulation" in the user documentation for
|
||
information about the commands of SB16CTRL.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>Features planned for the future</title>
|
||
<itemizedlist>
|
||
<listitem><para>Ports to more OS's, but I can't do this myself</para></listitem>
|
||
<listitem><para>Finishing the OPL3 FM emulation by translating the music to midi data</para></listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Description of the sound output classes</title>
|
||
|
||
<para>
|
||
This file is intended for programmers who would like to port the sound
|
||
output routines to their platform. It gives a short outline what services
|
||
have to be provided.
|
||
</para>
|
||
<para>
|
||
You should also have a look at the exisiting files, <emphasis>SOUNDLNX.CC</emphasis>
|
||
for Linux and <emphasis>SOUNDWIN.CC</emphasis> for Windows and their respective
|
||
header files to get an idea about how these things really work.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>Files</title>
|
||
|
||
<para>
|
||
The main include file is <emphasis>bochs.h</emphasis>. It has all definitions
|
||
for the system-independent functions that the SB16 emulation uses, which
|
||
are defined in <emphasis>sb16.h</emphasis>.
|
||
</para>
|
||
|
||
<para>
|
||
Additionally, every output driver will have an include file, which
|
||
should be included at the end of sb16.h to allow the emulator
|
||
to use that driver.
|
||
</para>
|
||
|
||
<para>
|
||
To actually make the emulator use any specific driver,
|
||
<emphasis>BX_SOUND_OUTPUT_C</emphasis> has to be set to the name of the respective
|
||
output class.
|
||
</para>
|
||
|
||
<para>
|
||
Note that if your class contains any system-specific statements,
|
||
include-files and so on, you should enclose both the include-file and
|
||
the CC-file in an <emphasis>#if defined</emphasis> (OS-define) construct.
|
||
Also don't forget to add your file to the object list in
|
||
iodev/Makefile and iodev/Makefile.in.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>Classes</title>
|
||
|
||
<para>
|
||
The following classes are involved with the SB16 emulation:
|
||
</para>
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
<emphasis>bx_sb16_c</emphasis> is the class containing the emulator itself, that
|
||
is the part acting on port accesses by the application, handling the
|
||
DMA transfers and so on. It also prepares the data for the output
|
||
classes.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>bx_sound_output_c</emphasis> is the base output class. It has all
|
||
the methods used by the emulator, but only as stubs and does not
|
||
actually produce any output. These methods are then called by
|
||
the emulator whenever output is necessary.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>bx_sound_OS_c</emphasis> is derived from
|
||
<emphasis>bx_sound_output_c</emphasis>. It contains the code to generate
|
||
output for the <emphasis>OS</emphasis> operating system.
|
||
It is necessary to override all
|
||
the methods defined in the base class, unless virtual functions
|
||
are used. Note that this should remain an option, so try to
|
||
override all methods, even if only as stubs. They should be
|
||
declared <emphasis>virtual</emphasis> if and only if <emphasis>BX_USE_SOUND_VIRTUAL</emphasis>
|
||
is defined, just as in the examples.
|
||
The constructor should call the inherited constructor
|
||
as usual, even though the current constructor does not do
|
||
anything yet.
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
|
||
<section><title>Methods</title>
|
||
<para>
|
||
The following are the methods that the output class has to override.
|
||
All but constructor and destructor have to return either
|
||
<emphasis>BX_SOUND_OUTPUT_OK</emphasis> <emphasis>(0)</emphasis> if the function was successful,
|
||
or <emphasis>BX_SOUND_OUTPUT_ERR</emphasis> <emphasis>(1)</emphasis> if not. If any of the initialization
|
||
functions fail, output to that device is disabled until the emulator is restarted.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>bx_sound_OS_c(bx_sb16_c*sb16)</title>
|
||
|
||
<para>
|
||
The emulator instantiates the class at the initialization of Bochs.
|
||
</para>
|
||
|
||
<para>
|
||
Description of the parameter:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
<emphasis>sb16</emphasis> is a pointer to the emulator class.
|
||
This pointer can then be used to access for example the <emphasis>writelog</emphasis> function to generate
|
||
sound-related log messages. Apart from that, no access to the emulator
|
||
should be necessary.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
The constructor should <emphasis>not</emphasis> allocate the output devices.
|
||
This shouldn't be done until the actual output occurs; in either
|
||
<emphasis>initmidioutput()</emphasis> or <emphasis>initwaveoutput()</emphasis>.
|
||
Otherwise it would be impossible to have two copies of Bochs running
|
||
concurrently (if anybody ever wants to do this).
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
<section><title>~bx_sound_OS_c()</title>
|
||
|
||
<para>
|
||
The instance is destroyed just before Bochs ends.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>int openmidioutput(char *device)</title>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
<emphasis>openmidioutput()</emphasis> is called when the first midi output starts.
|
||
It is only called if the midi output mode is 1 (midimode 1). It should
|
||
prepare the given MIDI hardware for receiving midi commands.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>openmidioutput()</emphasis> will always be called before <emphasis>openwaveoutput()</emphasis>,
|
||
and <emphasis>closemidioutput()</emphasis>will always be called before <emphasis>closewaveoutput()</emphasis>, but not in all cases will both functions be called.
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Description of the parameters:</title>
|
||
|
||
<itemizedlist>
|
||
|
||
<listitem><para>
|
||
<emphasis>device</emphasis> is a system-dependent variable.
|
||
It contains the value of the <emphasis>MIDI=device</emphasis> configuration option.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
Note that only one midi output device will be used at any one time.
|
||
<emphasis>device</emphasis>
|
||
may not have the same value throughout one session, but it will be closed
|
||
before it is changed.
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
<section><title>int midiready()</title>
|
||
|
||
<para>
|
||
<emphasis>midiready()</emphasis> is called whenever the applications asks if the
|
||
midi queue can accept more data.
|
||
</para>
|
||
|
||
<para>
|
||
Return values:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
<emphasis>BX_SOUND_OUTPUT_OK</emphasis> if the midi output device is ready.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>BX_SOUND_OUTPUT_ERR</emphasis> if it isn't ready.
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
<emphasis>Note: </emphasis><emphasis>midiready()</emphasis> will be called a few times
|
||
<emphasis>before</emphasis> the device is opened. If this is the case, it should
|
||
always report that it is ready, otherwise the application (not Bochs)
|
||
will hang.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>int sendmidicommand(int delta, int command, int length, Bit8u data[])</title>
|
||
|
||
<para>
|
||
<emphasis>sendmidicommand()</emphasis>is called whenever a complete midi command has
|
||
been written to the emulator. It should then send the given midi command to the midi hardware.
|
||
It will only be called after the midi output has been opened. Note that
|
||
if at all possible it should not wait for the completion of the command
|
||
and instead indicate that the device is not ready during the execution
|
||
of the command. This is to avoid delays in the program while it is
|
||
generating midi output.
|
||
</para>
|
||
|
||
<para>
|
||
Description of the parameters:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
<emphasis>delta</emphasis> is the number of delta ticks that
|
||
have passed since the last command has been issued. It is always zero for
|
||
the first command. There are 24 delta ticks per quarter, and 120 quarters
|
||
per minute, thus 48 delta ticks per second.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>command</emphasis> is the midi command byte (sometimes
|
||
called status byte), in the usual range of 0x80..0xff. For more information
|
||
please see the midi standard specification.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>length</emphasis> is the number of data bytes that
|
||
are contained in the data structure. This does <emphasis>not</emphasis> include the status
|
||
byte which is not replicated in the data array. It can only be greater
|
||
than 3 for SysEx messages (commands <emphasis>0xF0</emphasis> and <emphasis>0xF7</emphasis>)
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>data[]</emphasis> is the array of these data bytes,
|
||
in the order they have in the standard MIDI specification.
|
||
Note, it might be <emphasis>NULL</emphasis> if length==0.
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
|
||
<section><title>int closemidioutput()</title>
|
||
|
||
<para>
|
||
<emphasis>closemidioutput()</emphasis> is called before shutting down Bochs or
|
||
when the
|
||
emulator gets the <emphasis>stop_output</emphasis> command through the emulator port.
|
||
After this, no more output will be necessary until <emphasis>openmidioutput()</emphasis>
|
||
is called again, but <emphasis>midiready()</emphasis> might still be called. It should do the following:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
Wait for all remaining messages to be completed
|
||
</para></listitem>
|
||
<listitem><para>
|
||
Reset and close the midi output device
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
|
||
<section><title>int openwaveoutput(char *device)</title>
|
||
|
||
<para>
|
||
<emphasis>openwaveoutput()</emphasis> is called when the first wave output occurs,
|
||
and only if the selected wavemode is 1. It should do the following:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
Open the given device, and prepare it for wave output
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
<para>
|
||
<emphasis>or</emphasis>
|
||
</para>
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
Store the device name so that the device can be opened in <emphasis>startplayback()</emphasis>.
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
<emphasis>openmidioutput()</emphasis> will always be called before <emphasis>openwaveoutput()</emphasis>,
|
||
and <emphasis>closemidioutput()</emphasis>will always be called before <emphasis>closewaveoutput()</emphasis>, but not in all cases will both functions be called.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>openwaveoutput()</emphasis> will typically be called once, whereas
|
||
<emphasis>startplayback()</emphasis> is called for every new DMA transfer to the SB16 emulation. If feasible,
|
||
it could be useful to open and/or lock the output device in
|
||
<emphasis>startplayback()</emphasis> as opposed to <emphasis>openwaveoutput()</emphasis>
|
||
to ensure that it can be used by other applications while Bochs doesn't
|
||
need it.
|
||
</para>
|
||
|
||
<para>
|
||
However, many older applications don't use the auto-init DMA
|
||
mode, which means that they start a new DMA transfer for every single
|
||
block of output, which means usually for every 2048 bytes or so.
|
||
Unfortunately there is no way of knowing whether the application will
|
||
restart an expired DMA transfer soon, so that in these cases the
|
||
<emphasis>startwaveplayback</emphasis> function will be called very often, and it
|
||
isn't a good idea to have it reopen the device every time.
|
||
</para>
|
||
|
||
<para>The buffer when writing to the device should not be overly large.
|
||
Usually about four buffers of 4096 bytes produce best results. Smaller
|
||
buffers could mean too much overhead, while larger buffers contribute
|
||
to the fact that the actual output will always be late when the application
|
||
tries to synchronize it with for example graphics.
|
||
</para>
|
||
|
||
<para>The parameters are the following: </para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
<emphasis>device</emphasis> is the wave device selected by
|
||
the user. It is strictly system-dependent. The value is that of the
|
||
<emphasis>WAVE=device</emphasis>
|
||
configuration option.
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
Note that only one wave output device will be used at any one time.
|
||
<emphasis>device</emphasis> may not have the same value throughout one session, but it will be closed
|
||
before it is changed.
|
||
</para>
|
||
</section>
|
||
|
||
<section>
|
||
<title>int startwaveplayback(int frequency, int bits, int stereo, int format)</title>
|
||
|
||
<para>
|
||
This function is called whenever the application starts a new DMA transfer. It should do the following:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
Open the wave output device, unless <emphasis>openwaveoutput()</emphasis> did that
|
||
already
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
Prepare the device for data and set the device parameters to those given
|
||
in the function call
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
The parameters are the following:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
<emphasis>frequency</emphasis> is the desired frequency of the
|
||
output. Because of the capabities of the SB16, it can have any value between
|
||
5000 and 44,100.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>bits</emphasis> is either 8 or 16, denoting the resolution
|
||
of one sample.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>stereo</emphasis> is either 1 for stereo output, or 0 for mono output.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>format</emphasis> is a bit-coded value (see below).
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
<table>
|
||
<title>format bits</title>
|
||
<tgroup cols="2">
|
||
<thead>
|
||
<row>
|
||
<entry>Bit number</entry>
|
||
<entry>Meaning</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row> <entry> 0 (LSB) </entry><entry><para> 0: unsigned data </para><para>
|
||
1: signed data </para></entry> </row>
|
||
<row> <entry> 1..6 </entry><entry> Type of codec (see below) </entry> </row>
|
||
<row> <entry> 7 </entry><entry><para> 0: no reference byte </para><para>
|
||
1: with reference byte </para></entry> </row>
|
||
<row> <entry> 8..x </entry><entry> reserved (0) </entry> </row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
|
||
<table>
|
||
<title>codecs</title>
|
||
<tgroup cols="2">
|
||
<thead>
|
||
<row>
|
||
<entry>Value</entry>
|
||
<entry>Meaning</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row> <entry> 0 </entry><entry> PCM (raw data) </entry> </row>
|
||
<row> <entry> 1 </entry><entry> reserved </entry> </row>
|
||
<row> <entry> 2 </entry><entry> 2-bit ADPCM (Creative Labs format) </entry> </row>
|
||
<row> <entry> 3 </entry><entry> 2.4-bit (3-bit) ADPCM (Creative Labs format) </entry> </row>
|
||
<row> <entry> 4 </entry><entry> 4-bit ADPCM (Creative Labs format) </entry> </row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
</para>
|
||
<para>
|
||
Other codecs are not supported by the SB hardware. In fact, most applications will
|
||
translate their data into raw data, so that in most cases the codec will be zero.
|
||
</para>
|
||
<para>
|
||
The number of bytes per sample can be calculated from this as (bits / 8) * (stereo + 1).
|
||
</para>
|
||
</section>
|
||
|
||
|
||
<section>
|
||
<title>int waveready()</title>
|
||
|
||
<para>
|
||
This is called whenever the emulator has another output buffer ready
|
||
and would like to pass it to the output class. This happens every
|
||
<emphasis>BX_SOUND_OUTPUT_WAVEPACKETSIZE</emphasis> bytes, or whenever a DMA transfer
|
||
is done or aborted.
|
||
</para>
|
||
|
||
<para>
|
||
It should return whether the output device is ready for another buffer
|
||
of <emphasis>BX_SOUND_OUTPUT_WAVEPACKETSIZE</emphasis> bytes.
|
||
If <emphasis>BX_SOUND_OUTPUT_ERR</emphasis>
|
||
is returned, the emulator waits about 1/(frequency * bytes per sample) seconds
|
||
and then asks again. The DMA transfer is stalled during that time, but
|
||
the application keeps running, until the output device becomes ready.
|
||
</para>
|
||
|
||
<para>
|
||
As opposed to <emphasis>midiready(), waveready()</emphasis> will <emphasis>not</emphasis> be
|
||
called unless the device is open.
|
||
</para>
|
||
</section>
|
||
|
||
<section>
|
||
<title>int sendwavepacket(int length, Bit8u data[])</title>
|
||
|
||
<para>
|
||
This function is called whenever a data packet of at most <emphasis>BX_SB16_WAVEPACKETSIZE</emphasis>
|
||
is ready at the SB16 emulator. It should then do the following:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
Send this wave packet to the wave hardware
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
This function <emphasis>has</emphasis> to be synchronous, meaning that it <emphasis>has</emphasis>
|
||
to return immediately, and <emphasis>not</emphasis> wait until the output is done. Also,
|
||
this function might be called before the previous output is done. If your
|
||
hardware can't append the new output to the old one, you will have to implement
|
||
this yourself, or the output will be very chunky, with as much silence
|
||
between the blocks as the blocks take to play. This is not what you want.
|
||
Instead, <emphasis>waveready()</emphasis> should return <emphasis>BX_SOUND_OUTPUT_ERR</emphasis>
|
||
until the device accepts another block of data.
|
||
</para>
|
||
|
||
<para>
|
||
Parameters:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
<emphasis>length</emphasis> is the number of data bytes in
|
||
the data stream. It will never be larger than <emphasis>BX_SB16_WAVEPACKETSIZE</emphasis>.
|
||
</para></listitem>
|
||
|
||
<listitem><para>
|
||
<emphasis>data</emphasis> is the array of data bytes.
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
The order of bytes in the data stream is the same as that in the Wave file format:
|
||
|
||
<table>
|
||
<title>wave output types</title>
|
||
<tgroup cols="2">
|
||
<thead>
|
||
<row>
|
||
<entry>Output type</entry>
|
||
<entry>Sequence of data bytes</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row> <entry> 8 bit mono </entry><entry> Sample 1; Sample 2; Sample 3; etc. </entry> </row>
|
||
<row> <entry> 8 bit stereo </entry><entry> Sample 1, Channel 0; Sample 1, Channel 1; Sample 2, Channel 0; Sample 2, Channel 1; etc. </entry> </row>
|
||
<row> <entry> 16 bit mono </entry><entry> Sample 1, LSB; Sample 1, MSB; Sample 2, LSB; Sample 2, MSB; etc. </entry> </row>
|
||
<row> <entry> 16 bit stereo </entry><entry> Sample 1, LSB, Channel 0; Sample 1, MSB, Channel 0; Sample 1, LSB, Channel 1; Sample 1, MSB, Channel 1; etc. </entry> </row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
</para>
|
||
|
||
<para>
|
||
Typically 8 bit data will be unsigned with values from 0 to 255, and
|
||
16 bit data will be signed with values from -32768 to 32767, although the
|
||
SB16 is not limited to this. For further information on the codecs and
|
||
the use of reference bytes please refer to the Creative Labs Sound Blaster
|
||
Programmer's Manual, which can be downloaded from the Creative Labs web
|
||
site.
|
||
</para>
|
||
</section>
|
||
|
||
<section><title>int stopwaveplayback()</title>
|
||
|
||
<para>
|
||
This function is called at the end of a DMA transfer. It should do the following:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
Close the output device if it was opened by <emphasis>startwaveplayback()</emphasis>.
|
||
and it's not going to be opened soon. Which is almost impossible to tell.
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
</section>
|
||
|
||
<section><title>int closewaveoutput()</title>
|
||
|
||
<para>
|
||
This function is called just before Bochs exits. It should do the following:
|
||
</para>
|
||
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
Close the output device, if this hasn't been done by <emphasis>stopwaveplayback()</emphasis>.
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
Typically, <emphasis>stopwaveplayback()</emphasis> will be called several times, whenever
|
||
a DMA transfer is done, where <emphasis>closewaveoutput()</emphasis> will only be called
|
||
once. However, in the future it might be possible that <emphasis>openwaveoutput()</emphasis>
|
||
is called again, for example if the user chose to switch devices while
|
||
Bochs was running. This is not supported at the moment, but might be in
|
||
the future.
|
||
</para>
|
||
</section>
|
||
|
||
</section> <!-- end of SB16 section-->
|
||
|
||
<section id="harddisk-redologs"><title>Harddisk Images based on redologs</title>
|
||
<para>
|
||
This section describes how the three new disk images "undoable", "growing", and "volatile" are
|
||
implemented in Bochs 2.1 :
|
||
</para>
|
||
<itemizedlist>
|
||
<listitem><para>
|
||
undoable -> flat file, plus growing, commitable, rollbackable redolog file
|
||
</para></listitem>
|
||
<listitem><para>
|
||
growing -> growing files, all previously unwritten sectors go to the end of file
|
||
</para></listitem>
|
||
<listitem><para>
|
||
volatile -> flat file, plus hidden growing redolog
|
||
</para></listitem>
|
||
</itemizedlist>
|
||
|
||
<para>
|
||
</para>
|
||
|
||
<section>
|
||
<title>
|
||
Description
|
||
</title>
|
||
<para>
|
||
The idea behind volatile and undoable disk images
|
||
is to have a flat file, associated with one redolog file.
|
||
</para>
|
||
<para>
|
||
Reading a sector is done from the redolog file if it contains
|
||
the sector, or from the flat file otherwise.
|
||
</para>
|
||
<para>
|
||
Sectors written go to the redolog,
|
||
so flat files are opened in read only mode in this configuration.
|
||
</para>
|
||
<para>
|
||
The redolog is designed in a way so it starts as a small file
|
||
and grows with every new sectors written to it. Previously written
|
||
sectors are done in place. Redolog files can not shrink.
|
||
</para>
|
||
<para>
|
||
The redolog is a growing file that can be created on the fly.
|
||
</para>
|
||
<para>
|
||
Now, it turns out that if you only use a redolog without any
|
||
flat file, you get a "growing" disk image.
|
||
</para>
|
||
<para>
|
||
So "undoable", "volatile" and "growing" harddisk images classes
|
||
are implemented on top of a redolog class.
|
||
</para>
|
||
</section>
|
||
|
||
<section>
|
||
<title>
|
||
How redologs works ?
|
||
</title>
|
||
|
||
<para>
|
||
At the start of a redolog file, there is a header, so Bochs can check whether
|
||
a file is consistent.
|
||
This header could also be checked when we implement
|
||
automatic type and size detection.
|
||
</para>
|
||
<para>
|
||
The generic part of the header contains values like type of image, and
|
||
spec version number.
|
||
</para>
|
||
<para>
|
||
The header also has a specific part.
|
||
For redologs, the number
|
||
of entries of the catalog, the extent, bitmap and disk size are stored.
|
||
</para>
|
||
|
||
<para>
|
||
In a redolog, the disk image is divided in a number of equal size "extents".
|
||
Each extent is a collection of successive 512-bytes sectors of the disk image,
|
||
preceeded by a n*512bytes bitmap.
|
||
</para>
|
||
|
||
<para>
|
||
the n*512bytes bitmap defines the presence (data has been written to it)
|
||
of a specific sector in the extent, one bit for each sector.
|
||
Therefore with a 512bytes bitmap, each extent can hold up to 4k blocks
|
||
</para>
|
||
|
||
<para>
|
||
Typically the catalog can have 256k entries.
|
||
With a 256k entries catalog and 512bytes bitmaps, the redolog can hold up to 512GiB
|
||
</para>
|
||
|
||
<note>
|
||
<para>
|
||
All data is stored on images as little-endian values
|
||
</para>
|
||
</note>
|
||
<section>
|
||
<title>
|
||
Header
|
||
</title>
|
||
<para>
|
||
At the start of a redolog file, there is a header. This header is designed
|
||
to be reusable by other disk image types.
|
||
</para>
|
||
<para>
|
||
The header length is 512 bytes. It contains :
|
||
<table>
|
||
<title>Generic header description</title>
|
||
<tgroup cols="5">
|
||
<thead>
|
||
<row>
|
||
<entry>Start position in bytes</entry>
|
||
<entry>Length in bytes</entry>
|
||
<entry>Data type</entry>
|
||
<entry>Description</entry>
|
||
<entry>Possible values</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row> <entry> 0 </entry> <entry> 32 </entry> <entry> string </entry> <entry> magical value </entry> <entry> Bochs Virtual HD Image </entry> </row>
|
||
<row> <entry> 32 </entry> <entry> 16 </entry> <entry> string </entry> <entry> type of file </entry> <entry> Redolog </entry> </row>
|
||
<row> <entry> 48 </entry> <entry> 16 </entry> <entry> string </entry> <entry> subtype of file </entry> <entry> Undoable, Volatile, Growing </entry> </row>
|
||
<row> <entry> 64 </entry> <entry> 4 </entry> <entry> Bit32u </entry> <entry> version of used specification </entry> <entry> 0x00010000 </entry> </row>
|
||
<row> <entry> 68 </entry> <entry> 4 </entry> <entry> Bit32u </entry> <entry> header size </entry> <entry> 512 </entry> </row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
<table>
|
||
<title>Redolog specific header description</title>
|
||
<tgroup cols="5">
|
||
<thead>
|
||
<row>
|
||
<entry>Start position in bytes</entry>
|
||
<entry>Length in bytes</entry>
|
||
<entry>Data type</entry>
|
||
<entry>Description</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row> <entry> 72 </entry> <entry> 4 </entry> <entry> Bit32u </entry> <entry> number of entries in the catalog </entry> </row>
|
||
<row> <entry> 76 </entry> <entry> 4 </entry> <entry> Bit32u </entry> <entry> bitmap size in bytes </entry> </row>
|
||
<row> <entry> 80 </entry> <entry> 4 </entry> <entry> Bit32u </entry> <entry> extent size in bytes</entry> </row>
|
||
<row> <entry> 84 </entry> <entry> 8 </entry> <entry> Bit64u </entry> <entry> disk size in bytes </entry> </row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
</para>
|
||
</section>
|
||
<section>
|
||
<title>
|
||
Catalog
|
||
</title>
|
||
<para>
|
||
Immediately following the header, there is a catalog containing
|
||
the position number (in extents) where each extent is located in the file.
|
||
</para>
|
||
<para>
|
||
Each position is a Bit32u entity.
|
||
</para>
|
||
|
||
</section>
|
||
<section>
|
||
<title>
|
||
Extent
|
||
</title>
|
||
<para>
|
||
&FIXME;
|
||
</para>
|
||
</section>
|
||
</section>
|
||
|
||
<section>
|
||
<title>Parameters
|
||
</title>
|
||
<para>
|
||
The following tables shows what paremeters are used when creating redologs or creating <20>growing" images :
|
||
<table>
|
||
<title>
|
||
How number of entries in the catalog and number of blocks by extents are computed
|
||
</title>
|
||
<tgroup cols="5">
|
||
<thead>
|
||
<row>
|
||
<entry>Catalog entries</entry> <entry>Catalog size(KiB)</entry> <entry>Bitmap size (B)</entry> <entry>Extent size (KiB)</entry> <entry>Disk Max Size</entry>
|
||
</row>
|
||
</thead>
|
||
|
||
<tbody>
|
||
<row>
|
||
<entry>512</entry> <entry>2</entry> <entry>1</entry> <entry>4</entry> <entry>2MiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>512</entry> <entry>2</entry> <entry>2</entry> <entry>8</entry> <entry>4MiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>1k</entry> <entry>4</entry> <entry>2</entry> <entry>8</entry> <entry>8MiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>1k</entry> <entry>4</entry> <entry>4</entry> <entry>16</entry> <entry>16MiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>2k</entry> <entry>8</entry> <entry>4</entry> <entry>16</entry> <entry>32MiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>2k</entry> <entry>8</entry> <entry>8</entry> <entry>32</entry> <entry>64MiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>4k</entry> <entry>16</entry> <entry>8</entry> <entry>32</entry> <entry>128MiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>4k</entry> <entry>16</entry> <entry>16</entry> <entry>64</entry> <entry>256MiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>8k</entry> <entry>32</entry> <entry>16</entry> <entry>64</entry> <entry>512MiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>8k</entry> <entry>32</entry> <entry>32</entry> <entry>128</entry> <entry>1GiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>16k</entry> <entry>64</entry> <entry>32</entry> <entry>128</entry> <entry>2GiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>16k</entry> <entry>64</entry> <entry>64</entry> <entry>256</entry> <entry>4GiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>32k</entry> <entry>128</entry> <entry>64</entry> <entry>256</entry> <entry>8GiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>32k</entry> <entry>128</entry> <entry>128</entry> <entry>512</entry> <entry>16GiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>64k</entry> <entry>256</entry> <entry>128</entry> <entry>512</entry> <entry>32GiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>64k</entry> <entry>256</entry> <entry>256</entry> <entry>1024</entry> <entry>64GiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>128k</entry> <entry>512</entry> <entry>256</entry> <entry>1024</entry> <entry>128GiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>128k</entry> <entry>512</entry> <entry>512</entry> <entry>2048</entry> <entry>256GiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>256k</entry> <entry>1024</entry> <entry>512</entry> <entry>2048</entry> <entry>512GiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>256k</entry> <entry>1024</entry> <entry>1024</entry> <entry>4096</entry> <entry>1TiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>512k</entry> <entry>2048</entry> <entry>1024</entry> <entry>4096</entry> <entry>2TiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>512k</entry> <entry>2048</entry> <entry>2048</entry> <entry>8192</entry> <entry>4TiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>1024k</entry> <entry>4096</entry> <entry>2048</entry> <entry>8192</entry> <entry>8TiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>1024k</entry> <entry>4096</entry> <entry>4096</entry> <entry>16384</entry> <entry>16TiB</entry>
|
||
</row>
|
||
<row>
|
||
<entry>2048k</entry> <entry>8192</entry> <entry>4096</entry> <entry>16384</entry> <entry>32TiB</entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
</para>
|
||
|
||
</section>
|
||
|
||
<section>
|
||
<title>
|
||
Redolog class description
|
||
</title>
|
||
<para>
|
||
The class <emphasis>redolog_t();</emphasis> implements the necessary
|
||
methods to create, open, close, read and write data to a redolog.
|
||
Managment of header catalog and sector bitmaps is done internally
|
||
by the class.
|
||
</para>
|
||
<section>
|
||
<title>
|
||
Constants
|
||
</title>
|
||
<para>
|
||
<screen>
|
||
#define STANDARD_HEADER_MAGIC "Bochs Virtual HD Image"
|
||
#define STANDARD_HEADER_VERSION (0x00010000)
|
||
#define STANDARD_HEADER_SIZE (512)
|
||
</screen>
|
||
These constants are used in the generic part of the header.
|
||
</para>
|
||
|
||
<para>
|
||
<screen>
|
||
#define REDOLOG_TYPE "Redolog"
|
||
#define REDOLOG_SUBTYPE_UNDOABLE "Undoable"
|
||
#define REDOLOG_SUBTYPE_VOLATILE "Volatile"
|
||
#define REDOLOG_SUBTYPE_GROWING "Growing"
|
||
</screen>
|
||
These constants are used in the specific part of the header.
|
||
</para>
|
||
|
||
<para>
|
||
<screen>
|
||
#define REDOLOG_PAGE_NOT_ALLOCATED (0xffffffff)
|
||
</screen>
|
||
This constant is used in the catalog for an unwritten extent.
|
||
</para>
|
||
|
||
</section> <!-- Constants -->
|
||
|
||
<section> <title>Methods</title>
|
||
<para>
|
||
<emphasis>redolog_t();</emphasis> instanciates a new redolog.
|
||
</para>
|
||
<para>
|
||
<emphasis>int make_header (const char* type, Bit64u size);</emphasis> creates a header
|
||
structure in memory, and sets its <emphasis>type</emphasis> and parameters based on the
|
||
disk image <emphasis>size</emphasis>. Returns 0.
|
||
</para>
|
||
<para>
|
||
<emphasis>int create (const char* filename, const char* type, Bit64u size);</emphasis>
|
||
creates a new empty redolog file, with header and catalog, named <emphasis>filename</emphasis>
|
||
of type <emphasis>type</emphasis> for a <emphasis>size</emphasis> bytes image.
|
||
Returns 0 for OK or -1 if a problem occured.
|
||
</para>
|
||
<para>
|
||
<emphasis>int create (int filedes, const char* type, Bit64u size);</emphasis>
|
||
creates a new empty redolog file, with header and catalog, in a previously
|
||
opened file described by <emphasis>filedes</emphasis>, of type <emphasis>type</emphasis>
|
||
for a <emphasis>size</emphasis> bytes image.
|
||
Returns 0 for OK or -1 if a problem occured.
|
||
</para>
|
||
<para>
|
||
<emphasis>int open (const char* filename, const char* type, Bit64u size);</emphasis>
|
||
opens a redolog file named <emphasis>filename</emphasis>, and checks
|
||
for consistency of header values against a <emphasis>type</emphasis> and
|
||
<emphasis>size</emphasis>.
|
||
Returns 0 for OK or -1 if a problem occured.
|
||
</para>
|
||
<para>
|
||
<emphasis>void close ();</emphasis>
|
||
closes a redolog file.
|
||
</para>
|
||
<para>
|
||
<emphasis>off_t lseek (off_t offset, int whence);</emphasis>
|
||
seeks at logical data offset <emphasis>offset</emphasis> in a redolog.
|
||
<emphasis>offset</emphasis> must be a multiple of 512.
|
||
Only SEEK_SET is supported for <emphasis>whence</emphasis>.
|
||
Returns -1 if a problem occured, or the current logical offset in
|
||
the redolog.
|
||
</para>
|
||
<para>
|
||
<emphasis>ssize_t read (void* buf, size_t count);</emphasis>
|
||
reads <emphasis>count</emphasis> bytes of data of the redolog, from current logical offset,
|
||
and copies it into <emphasis>buf</emphasis>.
|
||
<emphasis>count</emphasis> must be 512.
|
||
Returns the number of bytes read, that can be 0 if the data
|
||
has not previously be written to the redolog.
|
||
</para>
|
||
<para>
|
||
<emphasis>ssize_t write (const void* buf, size_t count);</emphasis>
|
||
writes <emphasis>count</emphasis> bytes of data from <emphasis>buf</emphasis>
|
||
to the redolog, at current logical offset.
|
||
<emphasis>count</emphasis> must be 512.
|
||
Returns the number of bytes written.
|
||
</para>
|
||
|
||
</section>
|
||
|
||
</section> <!-- Redolog class description -->
|
||
|
||
<section>
|
||
<title>
|
||
Disk image classes description
|
||
</title>
|
||
<para>
|
||
"volatile" and "undoable" disk images are easily implemented
|
||
by instanciating a <emphasis>default_image_t</emphasis> object (flat image)
|
||
and a <emphasis>redolog_t</emphasis> object (redolog).
|
||
</para>
|
||
<para>
|
||
"growing" disk images only instanciates a <emphasis>redolog_t</emphasis> object.
|
||
</para>
|
||
<para>
|
||
Classe names are <emphasis>undoable_image_t</emphasis>, <emphasis>volatile_image_t</emphasis>
|
||
and <emphasis>growing_image_t</emphasis>.
|
||
</para>
|
||
<para>
|
||
When using these disk images, the underlying data structure and layout
|
||
is completely
|
||
hidden to the caller. Then, all offset and size values are "logical" values,
|
||
as if the disk was a flat file.
|
||
</para>
|
||
<section>
|
||
<title>
|
||
Constants
|
||
</title>
|
||
<para>
|
||
<screen>
|
||
#define UNDOABLE_REDOLOG_EXTENSION ".redolog"
|
||
#define UNDOABLE_REDOLOG_EXTENSION_LENGTH (strlen(UNDOABLE_REDOLOG_EXTENSION))
|
||
#define VOLATILE_REDOLOG_EXTENSION ".XXXXXX"
|
||
#define VOLATILE_REDOLOG_EXTENSION_LENGTH (strlen(VOLATILE_REDOLOG_EXTENSION))
|
||
</screen>
|
||
These constants are used when building redolog file names
|
||
</para>
|
||
</section>
|
||
|
||
<section>
|
||
<title>
|
||
undoable_image_t methods
|
||
</title>
|
||
<para>
|
||
<emphasis>
|
||
undoable_image_t(Bit64u size, const char* redolog_name);
|
||
</emphasis>
|
||
instanciates a new <emphasis>undoable_image_t</emphasis>
|
||
object. This disk image logical length is <emphasis>size</emphasis> bytes and
|
||
the redolog filename is <emphasis>redolog_name</emphasis>.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
int open (const char* pathname);
|
||
</emphasis>
|
||
opens the flat disk image <emphasis>pathname</emphasis>,
|
||
as an undoable disk image. The associated redolog will
|
||
be named <emphasis>pathname</emphasis> with a
|
||
<emphasis>UNDOABLE_REDOLOG_EXTENSION</emphasis>
|
||
suffix, unless set in the constructor.
|
||
Returns 0 for OK or -1 if a problem occured.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
void close ();
|
||
</emphasis>
|
||
closes the flat image and its redolog.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
off_t lseek (off_t offset, int whence);
|
||
</emphasis>
|
||
seeks at logical data position <emphasis>offset</emphasis> in
|
||
the undoable disk image.
|
||
Only SEEK_SET is supported for <emphasis>whence</emphasis>.
|
||
Returns -1 if a problem occured, or the current logical
|
||
offset in the undoable disk image.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
ssize_t read (void* buf, size_t count);
|
||
</emphasis>
|
||
reads <emphasis>count</emphasis> bytes of data
|
||
from the undoable disk image, from current logical offset,
|
||
and copies it into <emphasis>buf</emphasis>.
|
||
<emphasis>count</emphasis> must be 512.
|
||
Returns the number of bytes read.
|
||
Data will be read from the redolog if it has
|
||
been previously written or from the flat image
|
||
otherwise.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
ssize_t write (const void* buf, size_t count);
|
||
</emphasis>
|
||
writes <emphasis>count</emphasis> bytes of data from <emphasis>buf</emphasis>
|
||
to the undoable disk image, at current logical offset.
|
||
<emphasis>count</emphasis> must be 512.
|
||
Returns the number of bytes written.
|
||
Data will always be written to the redolog.
|
||
</para>
|
||
</section>
|
||
|
||
<section>
|
||
<title>
|
||
volatile_image_t methods
|
||
</title>
|
||
<para>
|
||
<emphasis>
|
||
volatile_image_t(Bit64u size, const char* redolog_name);
|
||
</emphasis>
|
||
instanciates a new <emphasis>volatile_image_t</emphasis>
|
||
object. This disk image logical length is <emphasis>size</emphasis> bytes and
|
||
the redolog filename is <emphasis>redolog_name</emphasis> plus a
|
||
random suffix.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
int open (const char* pathname);
|
||
</emphasis>
|
||
opens the flat disk image <emphasis>pathname</emphasis>,
|
||
as a volatile disk image. The associated redolog will
|
||
be named <emphasis>pathname</emphasis> with a
|
||
random suffix, unless set in the constructor.
|
||
Returns 0 for OK or -1 if a problem occured.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
void close ();
|
||
</emphasis>
|
||
closes the flat image and its redolog.
|
||
The redolog is deleted/lost after close is called.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
off_t lseek (off_t offset, int whence);
|
||
</emphasis>
|
||
seeks at logical data position <emphasis>offset</emphasis> in
|
||
the volatile disk image.
|
||
Only SEEK_SET is supported for <emphasis>whence</emphasis>.
|
||
Returns -1 if a problem occured, or the current logical offset in
|
||
the volatile disk image.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
ssize_t read (void* buf, size_t count);
|
||
</emphasis>
|
||
reads <emphasis>count</emphasis> bytes of data
|
||
from the volatile disk image, from current logical offset,
|
||
and copies it into <emphasis>buf</emphasis>.
|
||
<emphasis>count</emphasis> must be 512.
|
||
Returns the number of bytes read.
|
||
Data will be read from the redolog if it has
|
||
been previously written or from the flat image
|
||
otherwise.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
ssize_t write (const void* buf, size_t count);
|
||
</emphasis>
|
||
writes <emphasis>count</emphasis> bytes of data from <emphasis>buf</emphasis>
|
||
to the volatile disk image, at current logical offset.
|
||
<emphasis>count</emphasis> must be 512.
|
||
Returns the number of bytes written.
|
||
Data will always be written to the redolog.
|
||
</para>
|
||
</section>
|
||
|
||
<section>
|
||
<title>
|
||
growing_image_t methods
|
||
</title>
|
||
<para>
|
||
<emphasis>
|
||
growing_image_t(Bit64u size);
|
||
</emphasis>
|
||
instanciates a new <emphasis>growing_image_t</emphasis>
|
||
object. This disk image logical length is <emphasis>size</emphasis> bytes.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
int open (const char* pathname);
|
||
</emphasis>
|
||
opens the growing disk image <emphasis>pathname</emphasis>,
|
||
Returns 0 for OK or -1 if a problem occured.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
void close ();
|
||
</emphasis>
|
||
closes the growing disk image.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
off_t lseek (off_t offset, int whence);
|
||
</emphasis>
|
||
seeks at logical data position <emphasis>offset</emphasis> in
|
||
the growable disk image.
|
||
Only SEEK_SET is supported for <emphasis>whence</emphasis>.
|
||
Returns -1 if a problem occured, or the current logical offset in
|
||
the grwoing image.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
ssize_t read (void* buf, size_t count);
|
||
</emphasis>
|
||
reads <emphasis>count</emphasis> bytes of data
|
||
from the growing disk image, from current logical offset,
|
||
and copies it into <emphasis>buf</emphasis>.
|
||
<emphasis>count</emphasis> must be 512.
|
||
Returns the number of bytes read.
|
||
The buffer will be filled with null bytes if data
|
||
has not been previously written to the growing image.
|
||
</para>
|
||
|
||
<para>
|
||
<emphasis>
|
||
ssize_t write (const void* buf, size_t count);
|
||
</emphasis>
|
||
writes <emphasis>count</emphasis> bytes of data from <emphasis>buf</emphasis>
|
||
to the growing disk image, at current logical offset.
|
||
<emphasis>count</emphasis> must be 512.
|
||
Returns the number of bytes written.
|
||
</para>
|
||
</section>
|
||
|
||
</section>
|
||
|
||
</section>
|
||
|
||
</chapter>
|
||
|
||
<chapter id="debugger"><title>Debugger</title>
|
||
<section><title>compile with debugger support</title>
|
||
<para>
|
||
&FIXME;
|
||
</para>
|
||
</section>
|
||
<section id="debugger-get-started"><title>get started in debugger</title>
|
||
<para>
|
||
&FIXME;
|
||
</para>
|
||
</section>
|
||
<section id="debugger-commands"><title>command reference</title>
|
||
<para>
|
||
&FIXME;
|
||
</para>
|
||
</section>
|
||
<section id="debugger-techniques"><title>techniques</title>
|
||
<para>
|
||
&FIXME;
|
||
</para>
|
||
</section>
|
||
</chapter>
|
||
|
||
<chapter id="coding"><title>Coding</title>
|
||
<section><title>coding conventions</title>
|
||
<para>
|
||
&FIXME;
|
||
</para>
|
||
</section>
|
||
<section id="patches"><title>patches:</title>
|
||
<para>
|
||
&FIXME;
|
||
how to make, where to submit, what happens then?
|
||
</para>
|
||
</section>
|
||
|
||
<section id="cvs-release"><title>life cycle of a CVS release</title>
|
||
<para>
|
||
&FIXME;
|
||
</para>
|
||
</section>
|
||
|
||
</chapter>
|
||
</book>
|