//----------------------------------------------------------------- // viewrbda.s // // This boot-sector program will generate a dynamic real-time // display of values residing in the PC's ROM-BIOS DATA-AREA. // A user can hit the -key to terminate this display. // // to assemble: $ as viewrbda.s -o viewrbda.o // and to link: $ ld viewrbda.o -T ldscript -o viewrbda.b // and install: $ dd if=viewrbda.b of=/dev/sda4 // // NOTE: This program begins executing with CS:IP = 0000:7C00 // // programmer: ALLAN CRUSE // written on: 28 AUG 2006 // revised on: 01 SEP 2008 //----------------------------------------------------------------- .code16 # for 'real-mode execution # manifest constants .equ seg_bios, 0x0040 # segment-address for RBDA .equ seg_code, 0x07C0 # segment-address for code .equ seg_vram, 0xB800 # segment-address for vram .section .text #------------------------------------------------------------------ start: ljmp $seg_code, $main # to renormalize CS and IP #------------------------------------------------------------------ msg: .ascii "ROM-BIOS DATA-AREA" # string to explain info len: .short . - msg # count of message bytes buf: .ascii "0x00400:" # buffer for hex strings hex: .ascii "0123456789ABCDEF" # hexadecimal digit-list #------------------------------------------------------------------ main: # initialize registers and memory for efficient looping call setup_segment_regs call erase_video_screen call draw_template_info again: # continuously redraw the dynamic portions of our display call check_for_exit_key call draw_rom_bios_data jnz again # freeze the display in case the -key was pressed freeze: jmp freeze #------------------------------------------------------------------ setup_segment_regs: mov $seg_code, %ax # address program data mov %ax, %ds # with DS register mov $seg_vram, %ax # address video memory mov %ax, %es # with ES register mov $seg_bios, %ax # address ROM-BIOS data mov %ax, %fs # with FS register ret #------------------------------------------------------------------ #------------------------------------------------------------------ erase_video_screen: # # This procedure uses the x86's 'store-string' instruction to fill # up the active page of video-memory with blank-space ascii-codes. # xor %di, %di # point ES:DI to page zero mov $' ', %al # ascii-code for a 'space' mov att, %ah # 'normal' textmode colors mov $2000, %cx # number of screen's cells cld # use 'forward' processing rep stosw # fill the 80-by-25 screen ret #------------------------------------------------------------------ src: .short msg # offset for text string dst: .short (3*80 + 31)*2 # offset for screen cell att: .byte 0x07 # colors: white-on-black #------------------------------------------------------------------ draw_text_string: # # This 'helper' function gets parameters from our global variables # pusha # preserve registers mov src, %si # point DS:SI to source mov dst, %di # point ES:DI to dest'n mov len, %cx # string length into CX mov att, %ah # text attributes in AH nxpel: lodsb # fetch next character stosw # store char and color loop nxpel # again for other pels popa # recover registers ret #------------------------------------------------------------------ draw_template_info: # # This procedure calls a 'helper' function to draw a title-string, # relying on already initialized program variables; then it reuses # that 'helper' function to draw a succession of sidebar strings. # call draw_text_string # write title onto screen # loop to draw the sidebar strings movw $buf, src # offset of source-text movw $8, len # length of source-text movw $(5*80 + 16)*2, dst # offset to topmost row xor %bx, %bx # initialize row-counter nxbar: mov hex(%bx), %dl # lookup ascii numeral mov %dl, buf+5 # to use in row's string call draw_text_string # draw the sidebar text addw $80*2, dst # advance to row beneath inc %bx # increment row-counter cmp $16, %bx # has count reached 16? jb nxbar # no, draw next sidebar ret #------------------------------------------------------------------ #------------------------------------------------------------------ draw_rom_bios_data: # # This procedure loops through the array of 128 memory-words that # reside in the ROM-BIOS DATA-AREA: it converts each one into its # representation as a string of hexadecimal digits, it calculates # the screen-location where that string should be drawn, and then # it calls our 'helper' function to write the digit-string there. # pushf # preserve FLAGS values movw $4, len # setup buffer's length xor %bx, %bx # initialize item-index nxdat: call format_next_item # convert binary to hex call calc_item_offset # compute screen offset call draw_text_string # draw string on screen inc %bx # increment item-index cmp $128, %bx # has index reached 128? jb nxdat # no, draw another value popf # recover FLAGS values ret #------------------------------------------------------------------ format_next_item: # # This procedure fetches the next word-value from the ROM-BIOS # DATA-AREA, and converts it into a 4-digit hexadecimal string # in our 'buf' storage-area. The array-index of the data-word # is found in register BX; all of the registers are preserved. # pusha # preserve registers # compute the word-offset by doubling the array-index add %bx, %bx # BX-value is doubled # fetch the array-word using a segment-override prefix mov %fs:(%bx), %ax # word-item is fetched # loop uses four nybble-rotations to lookup hex digits xor %di, %di # initialize buf index mov $4, %cx # generate four digits nxnyb: rol $4, %ax # high-nybble into AL mov %ax, %bx # copy result into BX and $0x0F, %bx # isolate nybble bits mov hex(%bx), %dl # lookup hex numeral mov %dl, buf(%di) # put numeral in buf inc %di # advance buf index loop nxnyb # again for next digit popa # restore registers ret #------------------------------------------------------------------ calc_item_offset: # # This procedure computes the screen-position where the next word # from the ROM-BIOS DATA-AREA should be drawn, based on the value # found in register BX, and assigns it to our 'dst' variable. # # CELL-LOCATION ALGORITHM # index = word-number (from BX) # row = ( index / 8 ) + 5; # col = ( index % 8 )*5 + 25 ; # dst = ( row * 80 + col )*2; # pusha # preserve registers mov %bx, %ax # copy dividend to AX xor %dx, %dx # and extend dividend mov $8, %cx # setup divisor in CX div %cx # perform a division add $5, %ax # plus 5 for row-number imul $5, %dx # remainder times five add $25, %dx # add 25 for col-number imul $80, %ax, %di # DI = row * 80 add %dx, %di # + col add %di, %di # then DI is doubled mov %di, dst # result is screen-posn popa # restore registers ret #------------------------------------------------------------------ check_for_exit_key: # # This procedure invokes a ROM-BIOS keyboard-service which 'peeks' # into the keyboard input-queue to see whether or not it is empty, # as indicated by the ZF-bit in the FLAGS register. In case ZF=1, # it returns immediately; otherwise, it calls a ROM-BIOS keyboard- # service which removes an entry from the keyboard input-queue and # checks to see if that entry indicates that was pressed. # # RETURNS: ZF=1 if -key was pressed # ZF=0 otherwise # # see if data is waiting in the keyboard input-queue mov $0x01, %ah # keyboard-queue 'peek' int $0x16 # invoke BIOS service # if so, pull it out and into AX; otherwise leave AX clear mov $0, %ax # put zero in accumulator jz check # queue empty? do compare int $0x16 # else remove queue-item check: # now compare value in AL with ascii-code for -key cmp $0x1B, %al # was -key pressed? ret # return ZF-bit setting #------------------------------------------------------------------ .org 510 # offset of boot-signature .byte 0x55, 0xAA # value for boot-signature #------------------------------------------------------------------ .end # nothing more to assemble