Transcript lesson2

Using data conversions
How we can ‘peek’ at regions of
system memory, such as the
ROM-BIOS DATA AREA
Our programming tools
• Last time we got some in-class practice at
using our software development tools:
– The Linux assembler: as
– The Linux linker: ld
– The low-level copying utility: dd
– The UNIX visual text-editor: vi
• We applied these tools to the creation of a
‘boot-sector replacement’ (something we’ll
need to know about for writing a mini OS)
X86 ‘real-mode’ memory
ROM-BIOS
Expansion ROMs
Video BIOS
VRAM
Extended BIOS
Data Area
EBDA
1-MB
DRAM
BOOT_LOCN
CS:IP
Interrupt
Vector
Table
ROM-BIOS
DATA AREA
RBDA
IVT
Disk Storage
Numerical conversions
• While developing and debugging our own
miniature operating system, we will often
need to display some numerical values
• The ROM-BIOS does not provide ‘helper’
functions for directly displaying raw data
• But assembly language programmers
learn to code efficient algorithms which
perform frequently needed conversions
Binary-to-Decimal
• We can use a procedure that converts a value
found in register AX into its representation as a
string of decimal numerals, suitable for output to
the terminal screen or to a printing device
• It’s based on repeatedly dividing the AX value by
ten (the radix of our decimal-system) to generate
a stream of remainders, which are converted to
ascii-codes and then displayed in reverse order
Algorithm’s implementation
ax2dec: # converts value in AX to a string of decimal digits at DS:DI
pusha
# save contents of registers
mov
$10, %bx
# decimal-system base in BX
xor
%cx, %cx
# initialize CX as digit-counter
nxdiv: xor
%dx, %dx
# extend AX for next division
div
%bx
# divide (DX,AX) by the base
push
%dx
# save remainder on the stack
inc
%cx
# and update our digit-counter
or
%ax, %ax
# was the quotient nonzero?
jnz
nxdiv
# yes, then do another division
nxdgt: pop
%dx
# recover the newest remainder
add
$’0’, %dl
# convert number to a numeral
mov
%dl, (%di)
# store numeral in output-buffer
inc
%di
# advance output-buffer index
loop
nxdgt
# process all the remainders
popa
# restore contents of registers
ret
Left-versus-Right justification
• The foregoing assembly language routine
draws the string of decimal-digits using a
“left-justified” display-convention:
# left-justified
34567
963
2468
# right-justified
34567
963
2468
• But sometimes we prefer the appearance
of a “right-justified” display-convention
Our ‘memsize.s’ demo
• We’ve written a boot-sector replacement
program that reports the amount of realmode memory available (in kilobytes)
• It uses a ROM-BIOS function (int 0x12) to
obtain this memory-size in the AX register
• Then it uses repeated division by ten to
convert the AX value into a right-justified
string of decimal numerals for display
Can avoid ‘interrupt-0x12’
• It’s possible for a program to find out the
upper limit of real-mode memory without
using the ‘int $0x12’ ROM-BIOS function
• The memory-size is among the variables
stored in the ROM-BIOS data-area – so
we can fetch it directly if we know where
it’s located, namely at address 0x00413
• ROM-BIOS is only useful in Real Mode
Fetching value from 0x00413
.code16
# for execution in x86 ‘real-mode’
#
# Here’s real-mode code that returns the ‘memsize’ value in register AX
#
get_memory_size:
push
%ds
# preserve value in DS register
mov
$0x0040, %ax
# address ROM-BIOS DATA-AREA
mov
$%ax, %ds
# using the DS segment-register
mov
%ds:0x13, %ax # load the ‘memsize’ value into AX
pop
%ds
# recover the former DS value
ret
# return control to the caller
NOTE: The ‘int $0x12’ instruction can be stored in just two bytes: 0xCD, 0x12
(which is good to know if your program-code needs to fit within a small space)
Binary-to-Hexadecimal
• Our ability to see a computer’s binary-data
in an understandable format will be vital in
exploring hardware or debugging software
• The easiest scheme for doing it will be to
show binary values in hexadecimal format
• Let’s look at a straightforward algorithm to
convert any 16-bit number into a string of
(four) hexadecimal numeral-characters
Our ‘ax2hex’ procedure
• We create an array of the ascii-codes for
the sixteen hexadecimal digit-characters
hex:
.ascii
“0123456789ABCDEF”
• Our procedure expects the binary value to
be in register AX and the memory-address
for the hex-string is in registers DS:DI
• Our procedure will preserve the contents
of the CPU’s registers (no ‘side-effects’)
A 4-bit leftward-rotation
Hi-nybble
AX =
0 1 0 0 0 1 0 1 0 1 1 0 0 1 1 1
(Before rotation)
AX =
0 1 0 1 0 1 1 0 0 1 1 1 0 1 0 0
(After rotation)
Lo-nybble
A bitwise ‘AND’ opration
BL is copied from AL
Unknown bits in BH
BX =
Lo-nybble
? ? ? ? ? ? ? ? 0 1 1 1 0 1 0 0
(Before masking)
& & & & & & & & & & & & & & & &
$0xF =
0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1
(bitmask-value)
= = = = = = = = = = = = = = = =
BX =
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
(After masking)
Lo-nybble
Thus the lo-nybble (4-bits) gets ‘zero-extended’ to its equivalent 16-bit value
Array ‘lookup’ operation
hex:
‘0’ ‘1’ ‘2’ ‘3’ ‘4’ ‘5’ ‘6’ ‘7’ ‘8’ ‘9’ ‘A’ ‘B’ ‘C’ ‘D’ ‘E’ ‘F’
hex( %bx ) = ‘4’
mov hex( %bx ), %dl
BX = 0004
DL =
DS:DI = &buf
‘4’
mov %dl, %ds:( %di )
buf:
‘4’
So the number 4 in BX gets
converted to the numeral ‘4’
in the ‘buf’ array-cell at DS:DI
Algorithm implementation
ax2hex: # converts the word-value in AX to a hex-string at DS:DI
pusha
mov
$4, %cx
# save general registers
# setup digit-count
nxnyb:
hex:
rol
mov
and
mov
mov
inc
loop
popa
ret
$4, %ax
%al, %bl
$0xF, %bx
hex(%bx), %dl
%dl, (%di)
%di
nxnyb
# rotate hi-nybble into AL
# copy the nybble into BL
# isolate the nybble’s bits
# lookup nybble’s ascii-code
# store numeral into buffer
# advance the buffer index
# generate remaining digits
# restore saved registers
# return control to the caller
.ascii
“0123456789ABCDEF”
# array of hex numerals
Our ‘viewrbda.s’ demo
• We can use this binary-to-hex algorithm to
view the contents of regions in memory,
such as the ROM-BIOS DATA-AREA
• The RBDA includes a number of variables
whose values change with system activity
• For a dynamic view of this memory area,
we need to draw and redraw its contents
Direct-Drawing to VRAM
• Our demo-program will perform its display
by writing character-codes directly into the
text-mode video-display memory-region (it
starts at memory-address 0x000B8000)
• Each onscreen character is controlled by a
pair of adjacent bytes in the video memory
Byte at odd-numbered offset
Background
color
Foreground
color
Byte at even-numbered offset
ASCII
character-code
Drawing ‘A’ in top-left corner
• Here’s a fragment of assembly-language
code that draws an uppercase letter ‘A’ in
the top-left corner of the screen (using the
normal ‘white-on-black’ color-attributes):
mov
mov
xor
movb
movb
$0xB800, %ax
%ax, %es
%di, %di
$’A’, %es:0(%di)
$0x07, %es:1(%di)
# address VRAM segment
# using the ES register
# point ES:DI at top-left cell
# draw character-code to VRAM
# draw attribute-codes to VRAM
Organization of VRAM
• The first 80 byte-pairs within video memory (at
offsets 0, 2, 4, …, 158) control the top row (row
number 0) on the screen, in left-to-right order
• Then the next 80 byte-pairs (offsets 160, 162,
164, …, 318) control the next row of text on the
screen (i.e., row number 1)
• Altogether there are 25 rows of text, with 80
characters per row, when the display first gets
programmed at startup for ‘standard’ text-mode
‘Real-Mode’ Memory Map
Vendor’s Firmware
ROM-BIOS
64+ kbytes
No installed memory
Video-ROM
Video Display Memory
Top of RAM (= 0x000A0000)
Volatile Program Memory
0x00007E00
0x00007C00
0x00000500
0x00000400
0x00000000
VRAM
128 kbytes
Extended BIOS Data
1-MB
RAM
BOOT_LOCN 512 bytes
RBDA
IVT
256 bytes
1024 bytes
Several regions of interest
•
•
•
•
•
•
•
View ROM-BIOS code at 0xF0000
View Interrupt Vectors at 0x00000
View ROM-BIOS DATA at 0x00400
View Text-mode VRAM at 0xB8000
View Video ROM-BIOS at 0xC0000
View the BOOT_LOCN at 0x07C00
(Note: Linux may have ‘overwritten’ some
areas that ROM-BIOS startup-code set up)
In-class exercise #1
• Can you revise our ‘memsize.s’ program
so that it would get its word-value directly
from the ROM-BIOS DATA AREA, rather
than by using an ‘int $0x12’ instruction?
In-class exercise #2
• There is a ROM-BIOS service (int 0x11)
which returns a word-value in register AX
that is known as the ‘equipment_list’ flag
• It’s a collection of bit-fields, rather than a
single number, and gives us information
about some of the hardware attached to
the system (e.g., floppy drives, mouse)
• Can you display it in hexadecimal format?
The ‘Equipment-List’ flag
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
No of serial-ports (0..4)
Modem installed (1=yes, 0=no)
No of floppy drives (if bit 0 is set to 1)
00=one, 01=two, 10=three, 11= four
No of parallel-ports (0..3)
Initial video display mode
00 = EGA/VGA
01 = color 40x25
10 = color 80x25
11 = mono 80x25
Mouse port installed on system board (1=yes, 0=no)
Math coprocessor installed (1=yes, 0=no)
Bootable floppy-drive installed (1=yes, 0=no)
0