lesson18

advertisement
Using x86 “protected mode” on
our anchor-cluster’s machines
A look at some terminal emulation
features utilized in the “consoleredirection” mechanism
Our remote-access scheme
sixteen
Core 2 Duo systems
...
‘anchor08’
‘anchor07’
‘telnet’
application
student
workstation
‘anchor06’
‘anchor05’
‘pyramid’
‘anchor04’
CS file-server
KVM cable
‘anchor03’
rackmount
PC system
‘anchor02’
null-modem
serial cables
ethernet cables
‘anchor01’
A programming hurdle
• When you try to test a ‘boot-time’ program
on one of our ‘anchor’ machines, you will
encounter a problem when your program
enters protected-mode: you can no longer
see the current screen-output, nor control
your program using keyboard-input, since
the normal ‘console redirection’ capability
(which ‘telnet’ relies on) has been disabled
The console’s output
• At boot-time the ‘anchor’ machines use a
‘real-mode’ interrupt-handler in the BIOS
to continually transfer information (via the
null-modem serial-cable) from the display
memory of the local machine to the ‘telnet’
program running on the ‘pyramid’ server
• From there it gets sent over the Ethernet
network to a student’s computer screen
The console’s input
• When a student types a keystroke, it gets
sent via the network to the ‘telnet’ program
running on ‘pyramid’, whereupon it then is
forwarded to the ‘anchor’ machine via the
null-modem serial-cable connection
• This scheme allows us to do our work on
the anchor-machines remotely – from our
classroom or CS Labs, or even from home
The IVT’s role
• But this scheme relies on BIOS code that
handle’s UART interrupts in ‘real-mode’
• When a program enters ‘protected-mode’,
it has to switch from its Table of Interrupt
Vectors (used in real-mode) to a different
table for dispatching of interrupts to ISRs
• At that point we lose all the functionality
that BIOS’s interrupt-handlers provided!
Our reimplementation
• Just as we’ve seen how to regain some of
the functionality provided by the real-mode
BIOS code, by writing our own protectedmode interrupt-handlers for the keyboard
and the timer, we can restore the basic
‘console redirection’ capability by writing
our own interrupt-handler for the UART
when the CPU is in its ‘protected-mode’
Some details
• We need to write “trivial” interrupt-handlers
for a few peripherals besides the UART:
– For the timer (so we can see something that’s
changing on the display screen)
– For the keyboard (so we can control when to
quit watching our display)
– For any ‘spurious’ interrupts that the 8259 PIC
delivers to the CPU (so we won’t “crash” due
to unwanted General Protection Exceptions)
Idea for UART’s RX-interrupts
• When our UART receives a new scancode
sent by the ‘telnet’ program on ‘pyramid’
we need it to be treated as if it were from
the anchor-machine’s keyboard – but the
anchor’s keyboard is out-of-our-reach
• So we issue a command to the keyboardcontroller to write that scancode into its
Output Buffer register (command 0xD2)
Idea for UART’s TX-interrupts
• When the UART issues its THRE-interrupt
(Transmitter Holding Register Empty), we
want to output a new byte of information
from the anchor-machine’s video memory
• The video memory consists of alternating
ascii-codes and attribute-codes, requiring
distinct treatments for proper display on
the remote terminal (or Desktop window)
Clearing the screen
• Here is an ANSI command-sequence that
clears the terminal’s display-screen:
char cmd[] = “\033[2J”;
int
len = strlen( cmd );
write( 1, cmd, len );
Reposition the cursor
• Here is an ANSI command-sequence that
moves the cursor to row 12, column 40:
char cmd[] = “\033[12;40H”;
int
len = strlen( cmd );
write( 1, cmd, len );
Format of ‘attribute’ bytes
VGA text-color attributes byte
7
BLINK
6
BG
red
5
BG
green
4
BG
blue
background color
3
FG
intense
2
FG
red
1
FG
green
foreground color
0
FG
blue
ANSI color-codes
0 = black
1 = red
2 = green
3 = brown
4 = blue
5 = magenta
6 = cyan
7 = gray
Color-translation table
IBM VGA
DEC ANSI
-------------------------------------------------------------------------------000 = black
000 = black
001 = blue
100 = blue
010 = green
010 = green
011 = cyan
110 = cyan
100 = red
001 = red
101 = magenta
101 = magenta
110 = brown
011 = brown
111 = gray
111 = gray
--------------------------------------------------------------------------------
Setting text attributes
• Here is an ANSI command-sequence that
sets foreground and background colors:
char cmd[] = “\033[32;44m”;
int
len = strlen( cmd );
write( 1, cmd, len );
Cursor visibility commands
• Here are ANSI command-sequences that
will ‘hide’ or ‘show’ the terminal’s cursor:
char hide[] = “\033[?25l”;
// lowercase L
char show[] = “\033[?25h”; // lowercase H
‘console output’ algorithm
unsigned char
color_table[ 8 ] = { 0, 4, 2, 6, 1, 5, 3, 7 };
typedef struct { unsigned char ascii, color; } PEL;
PEL
*vram = (PEL *)0x000B8000;
PEL
prev = { 0, 0 };
for (int row = 0; row < 24; row++)
{
printf( “\033[?25l” );
// make the cursor invisible
printf( “\033[%d;%dH”, row+1, 1 );
// cursor to row’s beginning
for (int col = 0; col < 80; col++)
{
PEL
curr = vram[ row*80 + col ];
if ( curr.color != prev.color )
{
int
fg = color_table[ (curr.color >> 0)&7 ];
int
bg = color_table[ (curr.color >> 4)&7 ];
printf( “\033[%d;%dm”, fg + 30, bg + 40 );
}
printf( “%c”, curr.ascii );
prev = curr;
}
printf( “\033[?25h” );
// make the cursor visible
fflush( stdout );
// insure all data written
}
Programming interface
The PC uses eight consecutive I/O-ports to access the UART’s registers
0x03F8
RxD/TxD
0x03F9
0x03FA
0x03FB
0x03FC
0x03FD
IER
IIR/FCR
LCR
MCR
LSR
interrupt
enable
register
receive buffer register and
transmitter holding register
(also Divisor Latch register)
line
status
register
line
control
register
modem
control
register
interrupt identification register
and FIFO control register
0x03FE
0x03FF
MSR
SCR
modem
status
register
scratchpad
register
Modem Control Register
7
6
0
0
5
0
4
3
2
1
0
LOOP
BACK
OUT2
OUT1
RTS
DTR
Legend:
DTR = Data Terminal Ready (1=yes, 0=no)
RTS = Request To Send (1=yes, 0=no)
OUT1 = not used (except in loopback mode)
OUT2 = enables the UART to issue interrupts
LOOPBACK-mode (1=enabled, 0=disabled)
Modem Status Register
7
6
DCD
RI
5
DSR
4
3
2
1
0
CTS
delta
DCD
delta
RI
delta
DSR
delta
CTS
set if the corresponding bit
has changed since the last
time this register was read
Legend:
[---- loopback-mode ----]
CTS = Clear To Send (1=yes, 0=no)
[bit 0 in Modem Control]
DSR = Data Set Ready (1=yes, 0=no)
[bit 1 in Modem Control]
RI = Ring Indicator (1=yes,0=no)
[bit 2 in Modem Control]
DCD = Data Carrier Detected (1=yes,0=no) [bit 3 in Modem Control]
Line Status Register
7
6
Error in Transmitter
idle
Rx FIFO
5
THR
empty
4
3
Break
interrupt
Framing
error
2
Parity
error
1
0
Overrun
error
Received
Data
Ready
These status-bits indicate errors in the received data
This status-bit
indicates that the
data-transmission
has been completed
This status-bit indicates that
the Transmitter Holding Register
is ready to accept a new data byte
This status-bit indicates that a new byte of data has arrived
(or, in FIFO-mode, that the receiver-FIFO has reached its threshold)
Line Control Register
7
6
Divisor
Latch
access
set
break
5
stick
parity
4
3
2
even
parity
select
parity
enable
number
of stop
bits
1
0
word length
selection
00 = 5 bits
01 = 6 bits
10 = 7 bits
11 = 8 bits
0 = normal
1 = ‘break’
0 = not accessible
1 = assessible
0 = 1 stop bit
1 = 2 stop bits
0 = no parity bits
1 = one parity bit
1 = even parity
0 = ‘odd’ parity
Interrupt Enable Register
7
0
6
0
5
0
4
3
0
Modem
Status
change
2
Rx Line
Status
change
1
0
THR
is
empty
Received
data is
available
If enabled (by setting the bit to 1),
the UART will generate an interrupt:
(bit 3) whenever modem status changes
(bit 2) whenever a receive-error is detected
(bit 1) whenever the transmit-buffer is empty
(bit 0) whenever the receive-buffer is nonempty
Also, in FIFO mode, a ‘timeout’ interrupt will be generated if neither
FIFO has been ‘serviced’ for at least four character-clock times
FIFO Control Register
7
6
RCVR FIFO
trigger-level
00 = 1 byte
01 = 4 bytes
10 = 8 bytes
11 = 14 bytes
5
reserved
4
reserved
3
DMA
Mode
select
2
XMIT
FIFO
reset
1
0
RCVR
FIFO
reset
FIFO
enable
NOTE: DMA is unsupported
for the UART on our systems
Writing 1 empties the FIFO, writing 0 has no effect
Writing 0 will disable the UART’s FIFO-mode, writing 1 will enable FIFO-mode
Interrupt Identification Register
7
6
5
0
00 = FIFO-mode has not been enabled
11 = FIFO-mode is currently enabled
4
3
2
1
0
‘highest priority’
UART interrupt
still pending
highest
011 = receiver line-status
010 = received data ready
110 = character timeout
001 = Tx Holding Reg empty
000 = modem-status change
lowest
1 = No UART interrupts are pending
0 = At least one UART interrupt is pending
0
Response to UART interrupts
• In order of highest-to-lowest priority:
– 0x06:
– 0x04:
– 0x0C:
– 0x02:
– 0x00:
Receive errors (input Line Status)
Received data (input Rx-Data)
FIFO Timeout (input/output Data)
THRE (output Tx-Data, or input IIR)
Modem state (input Modem Status)
How to transmit a byte
Read the Line Status Register
NO
Transmit Holding Register
is Empty?
YES
Write byte to the Transmitter Data Register
DONE
How to receive a byte
Read the Line Status Register
NO
Received Data
is Ready?
YES
Read byte from the Receiver Data Register
DONE
Demo-program
• We wrote a boot-time program (it’s called
‘xmitvram.s’) that we can run on one of
our anchor-cluster machines
• It shows how a protected-mode interrupthandler for the serial UART interrupts can
send ANSI terminal-control strings (along
with ASCII character-codes) to the ‘telnet’
terminal emulator application on ‘pyramid’
In-class exercise
• Modify this simple C++ program so that it
will print its “Hello” message in colors and
be located in the center of the screen:
#include <stdio.h>
int main( void )
{
printf( “Hello, world! \n” );
}
Download