debugMinor
X86 Legacy boot loader error trapping
Viewed 0 times
loadererrorbootx86trappinglegacy
Problem
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.
Error codes are passed in EAX as a combination of two characters with attributes
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.
Parameters
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.
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.
Error codes are passed in EAX as a combination of two characters with attributes
mov eax, 0x07ce41cd
call Err
jz GoBackToThe 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 0Parameters
; 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.
Solution
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.
This is a misconception. The following
This calculation is overly complex and wastes a lot of bytes.
This is a better version:
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
In stead of preserving, which uses 4 bytes, you could simply write
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
In stead of preserving the dword
A small error here. On exit with Ignore the
My main concern here is why you want both the
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
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 workThis 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 pageThis calculation is overly complex and wastes a lot of bytes.
- Why zero the
CXregister and then assignCL? Usemov cx, 160
- Why zero the high byte of
DXwith an uglyand dx, 255when there's a perfectly goodmov dh, 0available?
- Why use a word multiplication
imul cxwhen 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 pagePrompting 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 $ - 6mov cx, ax ; Preserve attribute
...
mov ax, cx ; Retrieve previous attributeIn 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 32push eax
...
pop eaxIn 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
retI 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 GoBackToCode Snippets
xor dl, dl ; DX needs to be null for IMUL to workxor 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 pagemovzx 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; Write everything up and including opening bracket
lodsb
cmp al, 0xFF
je $ + 5
stosw
jmp $ - 6mov cx, ax ; Preserve attribute
...
mov ax, cx ; Retrieve previous attributeContext
StackExchange Code Review Q#145072, answer score: 4
Revisions (0)
No revisions yet.