NASM - The Netwide Assembler
NASM Forum => Other Discussion => Topic started by: TightCoderEx on January 07, 2013, 12:23:19 AM
-
In my effort to roll my own BIOS and OS :-\ well at least the intention is there, I've come across a problem. Certain information is missing from the sites I visit, so what I'm doing is writing an informative phase to my boot loader. Initial prompt is as follows;
Loading BONES OS
Stack Pointer 0000:03E2
Not surprisingly BIOS stack is just below BPB (Bios Parameter Block) 0x400 to 0x501. This is the code that does this.
[bits 16]
BOOT_BASE equ 0x7c00
org BOOT_BASE ; Bootstrap base
; ============================================================================================
start mov ax, ss
mov bx, sp
cli
xor ax, ax
mov ss, ax
mov ds, ax
mov es, ax
mov sp, BOOT_BASE
sti
push bx
push ax
mov si, SignOn
call ShowS
pop ax
push si
mov di, Stack
call I2A_16
pop si
pop ax
push si
add di, 5
call I2A_16
mov si, Disp
call ShowS
; Wait for operator input before carrying on
.Again xor ax, ax
inc al
int 0x16
jz .Again
int 0x19
; --------------------------------------------------------------------------------------------
; Display NULL termianted string teletype mode
; ENTRY: SI = Pointer to string
; LEAVE: SI = Pointer to next string if applicable. If stings are positioned properly
; in data area, this could be called successively without modifying SI.
; ____________________________________________________________________________________________
ShowS mov ah, 14
.Next lodsb ; Get character from string
or al, al
jz .Done
int 0x10 ; Display character
jmp .Next
.Done ret ; BX = Pointer to next possible string
; ============================================================================================
; Converts unsigned integer to NULL terminated ASCII string
; ENTRY: AX = 16 bit value to be converted
; DX = Pointer to destination buffer (must be at least 5 bytes in length)
; LEAVE: AX = Pointer to first character of conversion
; DX = Unchanged and points to ASCII string padded with blanks.
; --------------------------------------------------------------------------------------------
I2A_16 push di ; Preserve base pointer
add di, 3 ; Bump to end of display area
push dx
mov dx, ax
; It might be a better idea to check flag before changing, but in this case I'm
; going to assume all routines change to auto increment before completing.
std ; Auto decrement
; Cycle until DX is null, but should it be zero at least one '0' will be written.
.Next mov al, dl ; Get next byte
and al, 15 ; Strip high nibble
or al, '0' ; Make ASCII
cmp al, 58 ; and determine if greater than '9'
jb $ + 4 ; Branch if between '0' & '9'
add al, 7 ; Makes character 'A' - 'F'
stosb ; Write ASCII character to buffer
shr dx, 4 ; Shift next nibble into AL
jnz .Next ; and continue if not zero
cld ; Set default direction
pop dx ; Restore original contents
mov ax, di ; Copy pointer
inc ax ; and bump so there are no leading spaces
pop di ; Pointer with leading spaces
ret
; <> - <> - <> - <> - <> - <> - <> - <> - < > - <> - <> - <> - <> - <> - <> - <> - <> - <>- <>
SignOn db 'Loading BONES OS', 13, 10, 13, 10, 0
Disp db 'Stack Pointer '
Stack db '0000:0000', 13, 10, 0
times 510 - ($ - $$) db 90H
dw 0xAA55
My alternate version, which should have worked, because it does on my DOS box invoked from command prompt, DEBUG and SYMDEB, but didn't when booting. Code in part;
mov si, SignOn
call ShowS
pop ax
push si
mov di, Stack
call I2A_16
pop si
pop ax
push si
add di, 5
call I2A_16
pop si
call ShowS
As you can see, identical except SI is derived from stack. Hoping somebody has an idea before I have to code a trace mechanism in to follow what's happening >:(
-
start mov ax, ss
mov bx, sp
cli
xor ax, ax
I don't doubt that ss was 0 before you put it there, but we don't really know this... If you're looking for some "standard" values for what BIOS hands us in any register but dl (boot drive), I don't think there is any... I'm not sure I understand what the issue is, TightCoderEx. Feeling slow today...
Best,
Frank
-
ES @ start is zero & SS is 0x3E2, so that is resolved no problem.
ShowS is designed to take SI as a pointer and when done SI points to the next location after the terminator being NULL. So at the first invocation of ShowS SI = 7C65 and when it's done 7C7A.
112 7C65 4C6F6164696E672042- SignOn db 'Loading BONES OS', 13, 10, 13, 10, 0
113 7C6E 4F4E4553204F530D0A-
114 7C77 0D0A00
115 7C7A 537461636B20506F69- Disp db 'Stack Pointer '
116 7C83 6E74657220
117 7C88 303030303A30303030- Stack db '0000:0000', 13, 10, 0
118 7C91 0D0A00
At lines 20 & 21 I save ES:SP and at lines 26 & 27 exchange ES with pointer to Disp = 7C7A. That value being zero is converted correctly and then @ 31 - 33 in essence 7C7A is exchanged with 03E2 and then converted so my display in previous posting is 0000:03E2. by the time we get to 37, contents of stack should be 7C7A, but it's not. The string @ SignOn is displayed again, so somehow the contents of stack got changed to 7C65.
20 7C11 53 push bx
21 7C12 50 push ax
22
23 7C13 BE[6500] mov si, SignOn
24 7C16 E81F00 call ShowS
25
26 7C19 58 pop ax
27 7C1A 56 push si
28 7C1B BF[8800] mov di, Stack
29 7C1E E82300 call I2A_16
30
31 7C21 5E pop si
32 7C22 58 pop ax
33 7C23 56 push si
34 7C24 83C705 add di, 5
35 7C27 E81A00 call I2A_16
36
37 7C2A 5E pop si
38 7C2B E80A00 call ShowS
The question is, how did the contents of the stack get changed to 7C65 when application was tested in DEBUG & SYSDEB it worked just fine. Also when @ line 37 I directly address Disp mov si, Disp it also works fine.
As usual and has been the case for quite some time, work arounds are in order. My guess would be the BIOS encounters some sort of interrupt and trashes SP. Just thought somebody might have some quick insight. It is working, just not the way I wanted
Thanks for the heads up Frank, as one never knows if the question is stated clearly, if not made aware.
-
37 7C2A 5E pop si
This version works for me, indentical to your first version. Tested as a real floppy disk boot sector on a pentium mmx laptop. The output is:
Loading BONES OS
Stack Pointer 0000:0100
(I think you know your code overwrites the segment value with zero.)
(It should be SS:SP 0030:0100h for this machine.)
(I had to try your code, because I couldn't see the problem - there isn't one. You must've made some other inadvertant error.)
hth,
Steve
-
Stack Pointer 0000:03E2
Recommended reading: x86 Memory Map @ OSDev.org (http://wiki.osdev.org/Memory_Map_%28x86%29#.22Low.22_memory_.28.3C_1_MiB.29)
TL;DR: Stay above 0000:0500 in Real Mode.
Hoping somebody has an idea before I have to code a trace mechanism in to follow what's happening >:(
Use Bochs (http://wiki.osdev.org/Bochs).
-
Thanks for the input, but as it turns out in order to satisfy my curiosity, I did concoct a snippet in the boot loader to give me the information I was looking for. There are two versions I tried this out on, being AMI v02.58 and Phoenix Truecore (Lenovo 3000 J Series)
My trials showed bottom of stack for AMI set to 7C00H & Truecore 400H. As you pointed out Keith, probably a better idea to stay above BDA, but if Phoenix isn't to worried about it, maybe I'll be ok. As you can see, I'm only going 24 bytes deeper. I believe IVT (http://www.bioscentral.com/misc/interrupts.htm) only comes as high as 77H ( 1DCH ), so I'm probably not interfering with anything.
00 60 pushaw
01 0FA8 push gs
03 0FA0 push fs
05 16 push ss
06 06 push es
07 1E push ds
08 0E push cs
09 8CD3 mov bx,ss
0B 89E1 mov cx,sp
0D EAAC00C007 jmp word 0x7c0:0xac
Now I set the stack pointer to a place I know it will be safe, but use BIOS data again to determine bottom. On AMI, my pointer winds up @ 9300:C000 = 9FC00 and 91C0:C000 on Truecore. Not sure why real BIOS's need so much room, but emulators like EMU8086 & Bochs don't.
AC FA cli
AD B84000 mov ax,0x40
B0 8ED8 mov ds,ax
B2 A11300 mov ax,[0x13]
B5 BC3000 mov sp,0x30
B8 29E0 sub ax,sp
BA C1E006 shl ax,0x6
BD C1E40A shl sp,0xa
C0 8ED0 mov ss,ax
C2 8CC8 mov ax,cs
C4 8ED8 mov ds,ax
C6 8EC0 mov es,ax
C8 31C0 xor ax,ax
CA 8EE8 mov gs,ax
CC 8EE0 mov fs,axAX: C8D
CX: 4
DX: 80 80 GS: F000 F000
BX: FFFF FS: 2DC2 E3CF
SP: 7E02 3E2 SS:
BP: 7C00 ES: F000
SI: 80 DS: 9FC0 40
DI: 6B30 CS:
CE FB sti
After all is said and done, these are the results I get for Phoenix (left column) & AMI (right column).
Blanks denote zero.
AX: C8D
CX: 4
DX: 80 80 GS: F000 F000
BX: FFFF FS: 2DC2 E3CF
SP: 7E02 3E2 SS:
BP: 7C00 ES: F000
SI: 80 DS: 9FC0 40
DI: 6B30 CS:
Anyone interested in running the code will see these values on the screen, but without labels, as sectors 2 - 66 are video images as to take the overhead away from code.