Carnegie Mellon
Computer Science Department |
|
|
|
|
|
|
|
|
|
|
15-410 Documentation For The Enthusiast
Simics Environment
Mouse Support
If the kernel being simulated is capable of handling PS/2
mouse events, you can request that Simics "capture" the
X Window System mouse by pointing into the Simics console
window, holding down the shift key, and right-clicking.
The same sequence will release the mouse from the window
for use by other parts of the window system.
Timing Details
Simics can force the simulation clock to run no faster than real time
passes on the machine running the simulation--though this is helpful
only when the simulated system can be simulated faster than real time.
One way to make this happen is for your application to use the
HLT instruction when it isn't doing useful work--HLT
can be simulated very quickly.
To limit the speed of the simulation clock, set the environment variable
SIMICS_REALTIME to a nonempty string (e.g., "yes") before
launching simics.
This is an experimental feature, new this
semester, so feedback would be appreciated if you make use of it.
Getting Up Close And Personal With Simics
There is a line between getting to know your debugger and diving in
and being consumed by your debugger. If you feel that you want to
cross this line, please see
this page.
Other Emulators
Please note that most other emulation programs are intended to emulate
correct programs, and so may not behave faithfully when running
development code.
Further, most other emulators are not geared towards faithfulness
of the simulation, trading accuracy for speed. In particular, they may make
use of a JIT compiler or rewriting scheme, which may divorce simulation state
and expectations thereof.
QEMU
Given a bootfd.img, simply run qemu -fda bootfd.img.
QEMU obtains better performance than single-instruction intepreters
such as Bochs or sub-instruction simulators such as Simics, but this
performance comes at the cost of reduced fidelity. QEMU frequently
runs correct code correctly, but it also frequently runs incorrect
code incorrectly.
In particular, the segment selector registers are not consulted
under all circumstances, allowing broken kernels to seem correct under many
tests. (As of March, 2007, this is a known defect in QEMU with some limited
acknowledgement that it should be fixed.)
In addition, because QEMU translates basic blocks as one unit,
most interrupts will appear to fire only at the end of a basic block.
In other words, Simics (like real hardware) can deliver an interrupt
between almost any pair of adjacent instructions, but for many pairs
of adjacent instructions QEMU will never deliver an interrupt between
them. This means that QEMU will run many tests much faster than
Simics, but the increased speed will not enable you to find
certain concurrency problems, because QEMU's operation will not allow
you to encounter them.
A second consequence of QEMU's code translation is that the value
of EFLAGS pushed onto the stack during the handling of some
interrupt or fault may not be correct--it may be the value that was
current a few instructions before the event was delivered. The value
will usually be wrong in "inconsequential" ways, such as the arithmetic
condition code flags being stale during a page fault, but you have been
warned.
QEMU has some debugging support built in, but please do be aware that
it is much more limited than that of Simics.
Overall, if you run your kernel for a long time in QEMU and it turns up a logic error such as a memory leak, the problem is probably real. But if you run your kernel under QEMU for a long time and it appears to have no concurrency bugs, you are probably tricking yourself. You have been warned!
Intel Hardware
Here are data sheets for the:
Keyboard Tricks
The Intel 8042, the keyboard controller chip either used, absorbed, or emulated
on modern systems, is quite a chip, and the PS/2 protocol is capable of
bidirectional communication with the keyboard. Internally, the back-channel is
used for acknowledgements, but of course it may also be used for more
interesting things.
For more detail (possibly more than you ever wanted), see
https://web.archive.org/web/20080210172603/computer-engineering.org/ps2keyboard/
or
http://www-ug.eecg.toronto.edu/msl/nios_devices/datasheets/PS2%20Keyboard%20Protocol.htm
.
Commanding The Keyboard
The keyboard is mostly an input device, but that'd be entirely too
simple to be the whole truth. Various interesting things are possible by
writing to KEYBOARD_PORT with outb. All commands begin with
a byte with the high bit turned on, and in general sending a command prefix
during a multi-byte command will abort the current command.
Note that for multibyte sequences, it is technically required that the host
program wait for Output Buffer Full (the LSB of the controller status
word, which may be read from port 0x64) bit to be clear before
transmitting another byte. Whether or not one can get away without this,
especially on Simics, is not clear.
Pinging The Keyboard Controller
Doing outb(KEYBOARD_PORT, 0xEE) will cause the keyboard (controller)
to echo back 0xEE as if it were a scan code.
Setting LED State
To set LED state, send 0xED and then a byte composed of OR-ing the
following masks, with other values being reserved (set to zero).
Mask | Effect |
0x01 | Turns on the Scroll-lock indicator |
0x02 | Turns on the Num-lock indicator |
0x04 | Turns on the Caps-lock indicator |
Enhanced Keyboard Handling Code
As mentioned in the project 1 handout, there is more capability stored in
process_scancode() than is strictly necessary to complete
the assignment. For people wishing to make use of the extended features,
there is some additional documentation here.
Multiple Keyboard Maps
The PS/2 scancode state machine we provide includes support for
three common layouts: the traditional "QWERTY" layout,
Dvorak,
and
Colemak.
To switch keyboard layouts, use
kl_set_layout()
as found in keylayout.h.
Note that your grader will assume your code begins
configured to use the QWERTY layout.
Internal State Tracking
The state machine currently tracks the following keyboard modifiers:
- Left and right shift keys. Shifting as usual is carried out.
- Left and right control keys. Full control sequence translation
to ASCII control codes is carried out.
- Left and right alt keys. This is tracked only as a modifier bit.
- CapsLock is interpreted as usual.
- NumLock (is tracked but only returned as a modifier bit,
no interpretation is done internally)
- The GUI modifers are currently untracked.
It is possible that the 410 Upper Code Page as defined thus far does not
include some of the keys you might desire. If that's so, please inform a TA
(the code was born of a partial implementation from the days of yore).
Raw Codes
Whenever possible, the "raw" character result is as close as possible to the
obvious interpretation. For most keys, it is the unshifted variant of the
ASCII representation; for extended keys it is the 410 Upper Code Page as you
might expect. For some keys, most notably enter, backspace, and escape, the
raw code is the ASCII control code to which the key maps.
Distinguishing Control Codes From Keys
Since the raw result is the key that actually produced the result, distinguishing,
for example, Ctrl+H from Backspace, can be achieved by noting that the former has
raw result 'h' and the latter has raw result 0x08.
Notes for Virtual Consoles
Since there is only a single state machine for the keyboard, CapsLock and
NumLock will follow the user around rather than be attributes of the virtual
console. Similarly, if the keystrokes used to switch consoles are independent
of modifier keys, then modifier state will reflect the keyboard's current state
(that is, if the switch codes are F{1,2,3} and the state of shift is ignored by
the VC switcher, then the shift state of the state machine will reflect the
state of the shift key on the keyboard regardless of console).
Example Transcripts
Here are some example transcripts using process_scancode which hopefully
will make concrete some of the discussion. We begin each with a keyboard with no
keys down and no locks on. Notice that we use a shorthand when describing the result
code bits; the labels used are C symbols if given the prefix of KH_RESULT_
Boring Key
Keystroke | Scancode | kh_type | Status Bits | Result Code Bits | Raw | Result |
'a' Make | 0x1E | 0x000D6161 | none | HASRAW | HASDATA | MAKE | 'a' | 'a' |
'a' Break | 0x9E | 0x000C6161 | none | HASRAW | HASDATA | 'a' | 'a' |
Shifted Key
Keystroke | Scancode | kh_type | Status Bits | Result Code Bits | Raw | Result |
Right Shift Make | 0x36 | 0x40098a00 | KH_RSHIFT_KEY | HASRAW | MAKE | KHE_RSHIFT | invalid |
'a' Make | 0x1E | 0x400D6141 | KH_RSHIFT_KEY | HASRAW | HASDATA | MAKE | 'a' | 'A' |
'a' Break | 0x9E | 0x400C6141 | KH_RSHIFT_KEY | HASRAW | HASDATA | 'a' | 'A' |
Right Shift Break | 0xB6 | 0x00088a00 | none | HASRAW | KHE_RSHIFT | invalid |
Arrow Key
Keystroke | Scancode | kh_type | Status Bits | Result Code Bits | Raw | Result |
Right Arrow Make | 0xE0 | 0x00000000 | none | none | invalid | invalid |
0x4D | 0x000D8484 | none | HASRAW | HASDATA | MAKE | KHE_ARROW_RIGHT | KHE_ARROW_RIGHT |
Right Arrow Break | 0xE0 | 0x00000000 | none | none | invalid | invalid |
0xCD | 0x000C8484 | none | HASRAW | HASDATA | KHE_ARROW_RIGHT | KHE_ARROW_RIGHT |
Ctrl-H vs. Backspace
Keystroke | Scancode | kh_type | Status Bits | Result Code Bits | Raw | Result |
Left Control Make | 0x1D | 0x20098700 | KH_LCONTROL_KEY | HASRAW | MAKE | KHE_LCTL | invalid |
'h' Make | 0x23 | 0x200D6808 | KH_LCONTROL_KEY | HASRAW | HASDATA | MAKE | 'h' | '\b' |
'h' Break | 0xA3 | 0x200C6808 | KH_LCONTROL_KEY | HASRAW | HASDATA | 'h' | '\b' |
Left Control Break | 0x9D | 0x00088700 | none | HASRAW | KHE_LCTL | invalid |
'\b' Make | 0x0E | 0x000D0808 | none | HASRAW | HASDATA | MAKE | '\b' | '\b' |
'\b' Break | 0x8E | 0x000C0808 | none | HASRAW | HASDATA | '\b' | '\b' |
Ctrl-Alt-Delete
Keystroke | Scancode | kh_type | Status Bits | Result Code Bits | Raw | Result |
Right Alt Make | 0xE0 | 0x00000000 | none | none | invalid | invalid |
0x38 | 0x04098600 | KH_RALT_KEY | HASRAW | MAKE | KHE_RALT | invalid |
Right Control Make | 0xE0 | 0x04000000 | KH_RALT_KEY | none | invalid | invalid |
0x1D | 0x14098800 | KH_RCONTROL_KEY | KH_RALT_KEY | HASRAW | MAKE |
KHE_RCTL | invalid |
Delete Make | 0xE0 | 0x14000000 | KH_RCONTROL_KEY | KH_RALT_KEY | none | invalid | invalid |
0x5E | 0x140D7F7F | KH_RCONTROL_KEY | KH_RALT_KEY | HASRAW | HASDATA | MAKE |
0x7F | 0x7F |
Delete Break | 0xE0 | 0x14000000 | KH_RCONTROL_KEY | KH_RALT_KEY | none | invalid | invalid |
0xDE | 0x140C7F7F | KH_RCONTROL_KEY | KH_RALT_KEY | HASRAW | HASDATA |
0x7F | 0x7F |
Right Alt Break | 0xE0 | 0x14000000 | KH_RCONTROL_KEY | KH_RALT_KEY | none |
invalid | invalid |
0xB8 | 0x10088600 | KH_RCONTROL_KEY | HASRAW | KHE_RALT | invalid |
Right Control Break | 0xE0 | 0x10000000 | KH_RCONTROL_KEY | none | invalid | invalid |
0x9D | 0x00088800 | none | HASRAW | KHE_RCTL | invalid |
Machine Initialization
What does a BIOS have to do in order to set up a machine
for execution of a kernel? Funny you should ask!
Intel has written a document specifying exactly that:
Minimal Intel Architecture Boot Loader.
|