# Binary values in hexidecimal notation written directly to video memory

In X86 Legacy boot loader prologue the first seven instructions preserve the state of the 8 general purpose and 6 segment registers. This is where they are displayed, right justified without leading zeros. Most often you'll see this kind of thing formulated as an ASCII string, then displayed with printf or maybe if INT 80 or SYSCALL under Linux.

The addresses are absolute and for those that may be interested in executing the code, you can PM me and I'll send the current version that can be assembled with NASM. Then breakpoints can be set and in my case I use BOCH's.

Here is the result; SI is already pointing to the beginning of this string

'AXCXDXBXSPBPSIDIESDSCSSSFSGS'

 700  83C61B            add     si, 27     Point to last character
703  FD                std                Do things in reverse
704  6800B8            push    VIDEO_SEG
707  07                pop     es
708  BF9C09            mov     di, 0x99c  Row 15 Column 30 (zero indexed)
70B  B90E00            mov     cx, 14     Values to be displayed
70E  B407              mov     ah, 0x7    in low intensity white


At this point SP is pointing to the values preserved in proglogue.

that is why this instruction without the corresponding push works. After all, is said and done, SS:SP will be pointing to the far pointer back into the BIOS.

 710  5A                pop     dx      Retrieve registers value


Retain pointer to end of hex value (DI) and in case we change attribute which is in AH, preserve it too.

 711  57                push    di
712  50                push    ax            AH = White
713  09D2              or      dx, dx        Is value zero
715  7502              jnz     719
717  FEC4              inc     ah            AH = Grey
719  E8BFFF            call    6db


Now registers mnemonic can be displayed in bright yellow

 71C  B40E              mov     ah, 14        Attribute bright yellow
71E  AC                lodsb
71F  AB                stosw
720  AC                lodsb
721  AB                stosw

722  58                pop     ax            AH = White again
723  5F                pop     di
724  81EFA000          sub     di, 160       Bump pointer up one line
728  FEC9              dec     cl
72A  740A              jz      736           Bail if done ZF=1


As soon as CL = 8, that means all the segment registers have been displayed and we can move over to the next column

 72C  80F908            cmp     cl, 8
72F  75DF              jnz     710
731  BF200A            mov     di,0xa20      DI = 5DC
734  EBDA              jmp     710


One thing I had considered here is adding 444H to DI instead, which in effect does exactly the same and then the left column would stay relative if the word at 709H was changed.

Finally, restore DF

 736  FC                cld


This is where DX will be right justified without leading spaces

 6DB  51                push    cx
6DC  B105              mov     cl, 0x5

Converts low nibble in AL to corresponding 0-1 or A-F
6DE  88D0              mov     al, dl
6E0  240F              and     al, 0xf
6E2  3C0A              cmp     al, 0xa
6E4  7202              jc      6e8
6EA  AB                stosw
6EB  FEC9              dec     cl

Asserting DX here assures only one zero will be displayed for zero
values in DX
6ED  C1EA04            shr     dx, 4
6F0  75EC              jnz     6de
6F2  D1E1              shl     cx, 1
6F4  29CF              sub     di, cx
6F6  B82D0F            mov     ax, 0xf2d
6F9  66AB              stosd                  Write bright white hyphen
6FB  59                pop     cx
6FC  C3                ret

• Retrive, hypen, charcter - If these comments are actually in your code, you might want to fix the spelling, otherwise future maintainers will laugh at you... – David Wohlferd Jun 28 '17 at 22:43
• Actually, sources have no comments at all. I'm experimenting with a different sort of regime through pages done with LibreOffice Impress. That being said, there's still no excuse for errors as there is spellcheck wich I usually use. – Shift_Left Jun 28 '17 at 23:39
• Wich - I see what you did there... I'm not sure what you are doing with LibreOffice, but code (especially assembler, but any code) without comments sounds like a support nightmare. – David Wohlferd Jun 29 '17 at 0:08
• @DavidWohlferd Wich reminds me to get a new keyboard, this one can't spell very well. Once I get into the kernel part of my code, I'll probably change things up quite a bit, as it's very likely GRUB will replace this, then maintainability will be much more important. The way binaries are written to fixed, flexible and removable media at the point is monumentally unorthodox. – Shift_Left Jun 29 '17 at 3:05

This is a very nice routine that totally succeeds in using a direction flag set to 1. I've seen others fail at this.

## Some observations:

731  BF200A            mov     di,0xa20      DI = 5DC


It's not clear what you mean with "DI = 5DC"

One thing I had considered here is adding 444H to DI instead, which in effect does exactly the same and then the left column would stay relative if the word at 709H was changed.

I would definitely choose adding 444h to DI in such a specially crafted routine. Relative addressing is so much more flexible to work with.

6F6  B82D0F            mov     ax, 0xf2d
6F9  66AB              stosd                  Write bright white hyphen


This is the only place where your code conceivably could fail. You store the dword from EAX without making sure the high word has any meaningful content. If the high word is empty you're in the clear, if not the screen will get disrupted.
Since modern BIOSes do use 32-bit registers, you can't be sure...

The shortest way to 'correct' this is:

mov     ax, 0x0F2D
stosw
dec     di
dec     di

• Yes, the comment at 731H could have been clearer, but at that point, the routine had just finished displaying contents of ES register and the value in DX = 5DC before mov instruction. So 5DC + 444H = A20H. – Shift_Left Jul 2 '17 at 21:24
• Right. It's one of those things then that one can only understand through recalculating. – Sep Roland Jul 2 '17 at 21:28
• At 6F9 EAX = 00000F2D. It should be 07200F2D, but zero to video works just as well and the premise to the instruction was to decrement DI byte 4, ...but... not a very good habit to get into cause this sort of thing is very innocuous on the surface, and monumentally hard to trace when there is a problem. Case in point, I just tried to trace back and couldn't find the place where high order bits of EAX were zeroed. Not a very good commentary, just having finished the app a couple of days ago. – Shift_Left Jul 2 '17 at 21:34