Carnegie Mellon
SCS logo
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.


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!

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 or .

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
Right Arrow Break 0xE0 0x00000000 none none invalid invalid
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'
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
Delete Make 0xE0 0x14000000 KH_RCONTROL_KEY | KH_RALT_KEY none invalid invalid
Delete Break 0xE0 0x14000000 KH_RCONTROL_KEY | KH_RALT_KEY none invalid invalid
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.

[Last modified Thursday September 08, 2022]