6
\$\begingroup\$

The boot loader that I'm designing is just simply going to setup (A) Stack, (B) Segment registers (C) Load remainder of track for specified device. Conventionally, this could have been up to 4 floppy and/or fixed disk devices, but now, it may be an FDC, but most likely USB or fixed disk. As my boot sector does have an 85 byte BPB, that leaves me with 422 bytes to work with. This code is fairly weighty (105 bytes), but in return of its 8160 possibilities, it can display all the detail I need.

INT 0x13 can return a possible 16 errors, so I came up with this color/character scheme that will provide me with all the details and not comprise to much space in boot sector. As an example, we want an error code to look like this.

Bochs session

Error codes are passed in EAX as a combination of two characters with attributes

        mov     eax, 0x07ce41cd
        call    Err
        jz      GoBackTo

The high order word is the center character and low order the outside two. Therefore 07 = Grey on Black, 0xCE is double line cross, 0x41 = Blue on Red and 0xCD = Double horizontal bars.

Prompting string can be constructed in any fashion required, but the only thing that must be is 0xFF where the error code will be inserted.

Prompt:    db    ' Error ['
           db  -1                      ; Position of error indicator
           db  '] (A)bort (R)etry (I)gnore'
           db  0

Parameters

;   ENTER:  EAX = Two combinations of attribute & character.

;   LEAVE:   AL = 'N' or 'R'
;                 EBX, ECX, EDX modified

;   FLAGS:   ZF = Retry otherwise NZ to Ignore.  

Procedure

  Err:  push    ds
        push    di
        push    si
        push    es

        push    cs
        pop     ds                  ; DS might be right

        push    eax
        mov     si, Prompt          ; DS:SI now points to prompt
        mov     ax, 0xb800
        mov     es, ax              ; Point to base of page 0

 ; Calcuate offset in page 0 where error prompting should begin.

        xor     bh, bh              ; BH = Page
        mov     ah, GetCurPos
        int     VIDEO
        xor     ax, ax
        mov     cx, ax
        mov     cl, 160             ; Chars & Attribue / line
        mov     al, dh
        and     dx, 255
        shl     dx, 1
        mov     di, dx
        xor     dl, dl              ; DX needs to be null for IMUL to work
        imul    cx                  ; Calculate offset
        add     di, ax              ; DI = offset in page 0

 ; Initial prompting including closing bracket will be in this attribute.

         mov    ah, 14              ; BIOS color for bright yellow
         mov    si, Prompt

 ; Write everything up and including opening bracket

         lodsb
         or      al, al
         js      $ + 5             
         stosw
         jmp     $ - 6

 ; Write 3 character error indicate

         mov    cx, ax              ; Preserve attribute        
         pop    eax
         stosd
         stosw

 ; Write closing bracket now

         mov    ax, cx              ; Retrieve previous attribute
         lodsb
         stosw

 ; Change attribute to bright white and display remainder of string
 ; terminated by NULL.

        mov    ah, 15               ; Attribute             
  .L0:  lodsb                       ; Read next character
        test   al, 255
        jz     .Done
        stosw                       ; Write char & attr to video memory.
        jmp    .L0

; Wait for response from operator and convert to uppercase

.Done:  xor     ax, ax
        int     KEYBOARD
        and     al, 0x5f            ; Converts to uppercase.

        cmp     al, 'A'
        jnz     $ + 4
        int     ReBoot

        cmp     al, 'R'
        jz      .Exit               ; Return with ZF set

        cmp     al, 'I'
        jnz     .Done
        inc     al                  ; Clears ZF

.Exit:  pop     es
        pop     si
        pop     di
        pop     ds
        ret

I haven't completely formulated how I want codes to look for disk errors, but essentially center character will reflect colors corresponding to code and outside will be blue for removable devices and bright blue for fixed assuming DL was either 00 or 0x80.

NOTE I do code a lot of hard conditionals and branches jmp $+?? to avoid a lot of unnecessary symbols in object files. Would be nice if NASM had something similar to MASM & FASM like @@:.

\$\endgroup\$
4
\$\begingroup\$

This code is fairly weighty (105 bytes)

Given all the things you want to do, and all the devices you want to interface from within this 512 bytes bootloader, you should take more steps to reduce the footprint of this error reporting routine.


xor     dl, dl              ; DX needs to be null for IMUL to work

This is a misconception. The following imul cx only depends on AX and CX for its operation. It will leave a result in DX:AX, but DX does not have to be initialized beforehand.

xor     ax, ax
mov     cx, ax
mov     cl, 160             ; Chars & Attribue / line
mov     al, dh
and     dx, 255
shl     dx, 1
mov     di, dx
xor     dl, dl              ; DX needs to be null for IMUL to work
imul    cx                  ; Calculate offset
add     di, ax              ; DI = offset in page

This calculation is overly complex and wastes a lot of bytes.

  • Why zero the CX register and then assign CL? Use mov cx, 160
  • Why zero the high byte of DX with an ugly and dx, 255 when there's a perfectly good mov dh, 0 available?
  • Why use a word multiplication imul cx when both numbers are mere bytes?

This is a better version:

movzx di, dl     ;DL is column
shl   di, 1
mov   al, 160
mul   dh         ;DH is row -> product in AX
add   di, ax     ;DI = offset in page

Prompting string can be constructed in any fashion required, but the only thing that must be is 0xFF where the error code will be inserted.

Because you used or al, al to test the exit condition, you denied yourself the chance to use ASCII's in the range [128,254] when constructing this prompting string. Just use the cmp al, 0xFF instruction, it's equally small.

; Write everything up and including opening bracket
lodsb
cmp     al, 0xFF
je      $ + 5             
stosw
jmp     $ - 6

mov    cx, ax              ; Preserve attribute        
...
mov    ax, cx              ; Retrieve previous attribute

In stead of preserving, which uses 4 bytes, you could simply write mov ah, 14 which uses only 2 bytes.


and     al, 0x5f            ; Converts to uppercase.

This way of UCasing is dangerous! You neglect bit 7 and thus p.e. the user could select abort by typing ALT-193 or ALT-225. Similarly for ignore and retry. Best write and al, 0xDF or even and al, -33. A third possibility is and al, not 32


push   eax
...
pop    eax

In stead of preserving the dword EAX, which uses 4 bytes, you could content yourself with just push ax and pop ax because the high word is never in danger of modification in your code. This saves another 2 bytes.


;   LEAVE:   AL = 'N' or 'R'
;                 EBX, ECX, EDX modified
;   FLAGS:   ZF = Retry otherwise NZ to Ignore.

A small error here. On exit with Ignore the AL register will hold an uppercase J.
My main concern here is why you want both the AL register and the ZeroFlag express essentially the same thing? If you would stick to only return result in the ZeroFlag then you could save extra bytes and at the same time get rid of the BX, CX, and DX registers being modified which is a good thing.

        push  ds
        push  es
        pusha
        ...
.Exit:  popa
        pop   es
        pop   ds
        ret

I haven't completely formulated how I want codes to look for disk errors, but essentially center character will reflect colors corresponding to code and outside will be blue for removable devices and bright blue for fixed assuming DL was either 00 or 0x80.

What you're saying here is that it is all about the colors that make it to the screen. Then why don't you put the ASCII's 0xCE for double line cross and 0xCD for double horizontal bars directly in the errortext? This will avoid using EAX as an argument (AX remains of course) and will save a lot of bytes on many occasions throughout the rest of the program.

mov     ax, 0x0741    ;Only colors conveyed
call    Err
jz      GoBackTo
\$\endgroup\$
  • 1
    \$\begingroup\$ "Best write and al, 0xDFh or even and al, -32" I tried to change these small errors through an edit but it got rejected! I suggested: "Best write and al, 0xDF or even and al, -33. A third possibility is and al, not 32" \$\endgroup\$ – Fifoernik Nov 18 '16 at 17:54
  • 1
    \$\begingroup\$ @Fifoernik You're right! -32 was a mistake. I copied everything you tried to edit. Thanks. \$\endgroup\$ – Sep Roland Nov 20 '16 at 14:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.