250 likes | 492 Vues
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
E N D
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 DRAM EBDA 1-MB CS:IP BOOT_LOCN ROM-BIOS DATA AREA Interrupt Vector Table RBDA Disk Storage IVT
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: • But sometimes we prefer the appearance of a “right-justified” display-convention # left-justified # right-justified 34567 34567 963 963 2468 2468
Our ‘memsize.s’ demo • We’ve written a boot-sector replacement program that reports the amount of real-mode 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 • 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’) hex: .ascii “0123456789ABCDEF”
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 Lo-nybble BX = ? ? ? ? ? ? ? ? 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 = ‘4’ DS:DI = &buf 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 # save general registers mov $4, %cx # setup digit-count nxnyb: rol $4, %ax # rotate hi-nybble into AL mov %al, %bl # copy the nybble into BL and $0xF, %bx # isolate the nybble’s bits mov hex(%bx), %dl # lookup nybble’s ascii-code mov %dl, (%di) # store numeral into buffer inc %di # advance the buffer index loop nxnyb # generate remaining digits popa # restore saved registers ret # return control to the caller hex: .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 Byte at even-numbered offset Background color Foreground color 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 $0xB800, %ax # address VRAM segment mov %ax, %es # using the ES register xor %di, %di # point ES:DI at top-left cell movb $’A’, %es:0(%di) # draw character-code to VRAM movb $0x07, %es:1(%di) # 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 ROM-BIOS Vendor’s Firmware 64+ kbytes No installed memory Video-ROM Video Display Memory VRAM 128 kbytes Top of RAM (= 0x000A0000) Extended BIOS Data 1-MB Volatile Program Memory RAM 0x00007E00 BOOT_LOCN 512 bytes 0x00007C00 0x00000500 256 bytes RBDA 0x00000400 IVT 1024 bytes 0x00000000
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 0 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 Initial video display mode 00 = EGA/VGA 01 = color 40x25 10 = color 80x25 11 = mono 80x25 No of parallel-ports (0..3) 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)