Hi,
I am trying to print a message without BIOS but this code is not working. Can anybody plz help me with this.
Zulfi.
.MODEL TINY
.data
msg db "We be bootin2'!",0
.CODE
;----------------------------------------------------------------------------------
ORG 0
;code branch
boot0: jmp short boot1
;----------------------------------------------------------------------------------
ORG 3
;OEM identifier
boot03 db 'BootDisk' ;always 8 characters
.STACK 2048; removes the stack warning
;----------------------------------------------------------------------------------
ORG 0Bh
boot0B dw 200h ;bytes per sector
boot0D db 1 ;sectors per cluster
boot0E dw 1 ;reserved sectors (the boot sector is reserved)
boot10 db 2 ;number of copies of the FAT
boot11 dw 0E0h ;root directory entries (224 for 1.4 mb)
boot13 dw 0B40h ;total disk sectors
boot15 db 0F0h ;media descriptor byte (F0 for 1.4 mb)
boot16 dw 9 ;sectors per FAT
boot18 dw 12h ;sectors per cylinder
boot1A dw 2 ;number of heads
boot1C dw 0 ;hidden sectors
;----------------------------------------------------------------------------------
boot1: cli ;disable maskable interrupts
xor di,di
mov ss,di
mov sp,7C00h ;SS:SP = 0000:7C00
XOR AX,AX ;Makes AX=0.
MOV ES,AX ;Make ES=0
mov DS,ax
sti
mov ax,0B800h ;notice that di is already 0
mov es,ax
cld
mov ax,1F41h
stosw
;----------------------------------call procedures
xor di,di
mov ds,di
mov ax,0B800h
mov es,ax
; should probably set up a sane stack here, too.
mov si,offset msg ; "our dear string"
mov ah,04h ; color
msgloop:
lodsb ;loads AL with a byte of data from mem location pointed by SI
or al,al
cld
jz boot2
stosw ; transfers the contents of AL to the mem location pointed by di
jmp msgloop
boot2: jmp boot2
;-------------------------------------procedure definitions
;----------------------------------------------------------------------------------
ORG 1FEh
;validation marker
dw 0AA55h
;----------------------------------------------------------------------------------
END boot0
Hi,
> mov si,offset msg ; "our dear string"
this line won't be translated as expected. since your boot loader is loaded at 7C00h, but you're telling the assembler - with the ORGs - that it's loaded at 0000h.
The solution is to either add 7C00h to all of your ORGs or to change the value of DS:
> mov ax,7C0h
> mov ds,ax
> mov si,offset msg
However, there's another error in your source:
> .data
> msg db "We be bootin2'!",0
Your string is in the DATA segment, which will be appended to the CODE segment. Since the length of the CODE segment is already 512, the string will be located beyond the first sector.
Hi,
I have removed the .data declaration and I have also changed the address of ds.
mov ax,7C0h
mov ds,ax
mov si,offset msg ; "our dear string"
but still its not working.
Zulfi.
well, when you use the "offset" directive to get the message address,
the assembler returns it's offset RELATIVE to the segment in which the label is defined
that creates a problem, as Japheth suggested
because the ORG directives we use are based on a 512-byte file (ORG 0 is the base offset)
when loaded in memory, however, the address of that ORG is 0000:7C00
to overcome this, many boot-loaders use a far jmp or retf to translate the CS segment to 07C0
after that, the label offsets in the assembler file match the offsets at run-time because the ORG 0 is now at 07C0:0000
another way is to adjust all label references by 7C00h
as for setting the stack to something sane, it is already done for you
0000:7C00 is a good place for the stack and the code i provided earlier sets it there
keep in mind, the bootloader's duty is to locate the boot-strap code on the disk and load it
typically, that boot-strap code measures available memory and sets the stack to some higher address
also, there is nothing wrong with using BIOS INT 10h functions to display characters
in fact, DOS boot-loaders used INT 10h because display adapters may have different buffer segments
the CGA (color graphics adapter) had the buffer based at segment B800
the MDA (monochrome display adapter) and HGC (hercules graphics card) had the buffer based at segment B000
that was done so a computer could have one of each type graphic card
BIOS knows which segment to use, so INT 10h always worked
but, if you want to do it without INT 10h.......
;bootable boot sector for a 1.4 mb floppy disk - by DednDave
;use windows or dos to format the floppy, then replace the boot sector
;----------------------------------------------------------------------------------
.MODEL TINY
.CODE
;----------------------------------------------------------------------------------
ORG 0
;code branch
boot0: jmp short boot1
;----------------------------------------------------------------------------------
ORG 3
;OEM identifier
boot03 db 'BootDisk' ;always 8 characters
;----------------------------------------------------------------------------------
ORG 0Bh
;BPB - BIOS Parameter Block
;later operating systems use an "extended BPB", which varies with the OS
;but BIOS only uses the original BPB
boot0B dw 200h ;bytes per sector
boot0D db 1 ;sectors per cluster
boot0E dw 1 ;reserved sectors (the boot sector is reserved)
boot10 db 2 ;number of copies of the FAT
boot11 dw 0E0h ;root directory entries (224 for 1.4 mb)
boot13 dw 0B40h ;total disk sectors
boot15 db 0F0h ;media descriptor byte (F0 for 1.4 mb)
boot16 dw 9 ;sectors per FAT
boot18 dw 12h ;sectors per cylinder
boot1A dw 2 ;number of heads
boot1C dw 0 ;hidden sectors
;----------------------------------------------------------------------------------
boot1: cli ;disable maskable interrupts
xor di,di
mov ss,di
mov sp,7C00h ;SS:SP = 0000:7C00
;normally, a boot floppy would copy the first 11 bytes of the BPB to 0000:0522
;some of the timing related values in that record are also set
;then, it would revector INT 1Eh to point to that BPB
;interrupts are left disabled until that task is complete
;any boot code that wants to continue and load a boot-strap loader should do this
;for our simple booter, we do not need to do that as the floppy is done being read
sti
;translate CS:IP to 07C0:xlat0 so the assembler offsets match the run-time offsets
;DI = 0
mov ax,7C0h
mov ds,ax
push ax
mov ax,xlat0
push ax
retf
;at this point, the registers are as follows:
;DI = 0000
;CS = DS = 07C0
;IP = xlat0 offset
;SS:SP = 0000:7C00
;display the message at B800:0000
xlat0: mov ax,0B800h ;notice that di is already 0
mov es,ax
mov si,offset msg
cld
mov ah,1Fh
mov cx,sizeof msg
disp0: lodsb
stosw
loop disp0
boot2: jmp boot2
;----------------------------------------------------------------------------------
;data area - notice the absence of a ".DATA" directive
msg db "We be bootin2'!"
;----------------------------------------------------------------------------------
ORG 1FEh
;validation marker
dw 0AA55h
;----------------------------------------------------------------------------------
END boot0
well, when you use the "offset" directive to get the message address,
the assembler returns it's offset RELATIVE to the segment in which the label is defined
that creates a problem, as Japheth suggested
because the ORG directives we use are based on a 512-byte file (ORG 0 is the base offset)
when loaded in memory, however, the address of that ORG is 0000:7C00
to overcome this, many boot-loaders use a far jmp or retf to translate the CS segment to 07C0
after that, the label offsets in the assembler file match the offsets at run-time because the ORG 0 is now at 07C0:0000
they do that so that a CS: segment override may be used to access data in the boot sector
the DS segment register typically points to the disk data buffer where the boot-straper is loaded
another way is to adjust all label references by 7C00h
as for setting the stack to something sane, it is already done for you
0000:7C00 is a good place for the stack and the code i provided earlier sets it there
keep in mind, the bootloader's duty is to locate the boot-strap code on the disk and load it
typically, that boot-strap code measures available memory and sets the stack to some higher address
also, there is nothing wrong with using BIOS INT 10h functions to display characters
in fact, DOS boot-loaders used INT 10h because display adapters may have different buffer segments
the CGA (color graphics adapter) had the buffer based at segment B800
the MDA (monochrome display adapter) and HGC (hercules graphics card) had the buffer based at segment B000
that was done so that a computer could have one of each type of display adapter
BIOS knows which segment to use, so INT 10h always worked
but, if you want to do it without INT 10h.......
;bootable boot sector for a 1.4 mb floppy disk - by DednDave
;use windows or dos to format the floppy, then replace the boot sector
;----------------------------------------------------------------------------------
.MODEL TINY
.CODE
;----------------------------------------------------------------------------------
ORG 0
;code branch
boot0: jmp short boot1
;----------------------------------------------------------------------------------
ORG 3
;OEM identifier
boot03 db 'BootDisk' ;always 8 characters
;----------------------------------------------------------------------------------
ORG 0Bh
;BPB - BIOS Parameter Block
;later operating systems use an "extended BPB", which varies with the OS
;but BIOS only uses the original BPB
boot0B dw 200h ;bytes per sector
boot0D db 1 ;sectors per cluster
boot0E dw 1 ;reserved sectors (the boot sector is reserved)
boot10 db 2 ;number of copies of the FAT
boot11 dw 0E0h ;root directory entries (224 for 1.4 mb)
boot13 dw 0B40h ;total disk sectors
boot15 db 0F0h ;media descriptor byte (F0 for 1.4 mb)
boot16 dw 9 ;sectors per FAT
boot18 dw 12h ;sectors per cylinder
boot1A dw 2 ;number of heads
boot1C dw 0 ;hidden sectors
;----------------------------------------------------------------------------------
boot1: cli ;disable maskable interrupts
xor di,di
mov ss,di
mov sp,7C00h ;SS:SP = 0000:7C00
;normally, a boot floppy would copy the first 11 bytes of the BPB to 0000:0522
;some of the timing related values in that record are also set
;then, it would revector INT 1Eh to point to that BPB
;interrupts are left disabled until that task is complete
;any boot code that wants to continue and load a boot-strap loader should do this
;for our simple booter, we do not need to do that as the floppy is done being read
sti
;translate CS:IP to 07C0:xlat0 so the assembler offsets match the run-time offsets
;DI = 0
mov ax,7C0h
mov ds,ax
push ax
mov ax,xlat0
push ax
retf
;at this point, the registers are as follows:
;DI = 0000
;CS = DS = 07C0
;IP = xlat0 offset
;SS:SP = 0000:7C00
;display the message at B800:0000
xlat0: mov ax,0B800h ;notice that di is already 0
mov es,ax
mov si,offset msg
cld
mov ah,1Fh
mov cx,sizeof msg
disp0: lodsb
stosw
loop disp0
boot2: jmp boot2
;----------------------------------------------------------------------------------
;data area - notice the absence of a ".DATA" directive
msg db "We be bootin2'!"
;----------------------------------------------------------------------------------
ORG 1FEh
;validation marker
dw 0AA55h
;----------------------------------------------------------------------------------
END boot0
in this case, translating the CS segment is really not neccessary, as we could just set DS to 07C0 and be done with it
i put the code in there to demonstrate how it was done for DOS boot-loaders, which needed the DS register for reading the disk
also, i used the sizeof directive to get the length of the message, rather than 0-terminating the message string
alternatively, we could use a 0-terminated string and do it this way:
xlat0: mov ax,0B800h ;notice that di is already 0
mov es,ax
mov si,offset msg
cld
mov ah,1Fh
disp0: lodsb
or al,al
jz boot2
stosw
jmp disp0
boot2: jmp boot2
;----------------------------------------------------------------------------------
;data area - notice the absence of a ".DATA" directive
msg db "We be bootin2'!",0
Hi,
I have not used this statement before
mov ax,xlat0
where xlat0 is a label. If you can provide some link for its details, I would really appreciate it. Whats the name of it?
Zulfi.
that just places the offset of the xlat0 branch label in ax
if it is a branch label (like a proc or a jmp addr), you do not need "offset"
if it is a data label, you do need "offset", otherwise it would get the value
the assembler knows you have no use for the code value located at xlat0, so it assumes you want the address
Quote mov ax,xlat0
push ax
retf
xlat0: mov ax,0B800h
mov es,ax
Kindly tell me the addressing mode of this instruction. What its called in the masm documentation?
Thanks for your attention and solution on this. I am working on it.
Zulfi.
Hi,
I have found that this program is running but its difficult to grasp the concepts with out reading the actual documentation. I dont know the name of addressing mode. Thanks for your code and efforts on this problem.
Zulfi.
well, i am not exactly sure what it's called either - lol
other than LODS and STOS are x86 "string instructions"
usually, when i see the term "addressing mode", it refers to the method the address is acquired
in that context, i would have to call it "indexed addressing" as it uses the SI (source index) and DI (destination index) registers
.model small
.stack
.data
var dw 0
.code
.startup
label0:
; for all three, ax is a register operand
mov ax, label0 ; label0 is an immediate operand
mov ax, var ; var is a direct memory operand
mov ax, [bx] ; [bx] is an indirect memory operand
.exit
end
Hi,
If you create a program listing and a cross reference of your
program you can see a bit of what happens.
Here are two lines of assembly language. A code label and
an instruction.
Start1: ; Number loop
PUSH CX
Here is a code label in the listing. Line 80, location 0016H.
80 0016 Start1: ; Number loop
81 0016 51 PUSH CX
Here is the symbol listing showing that it is a near label with a value
of 0016H in the CODE segment.
START1 . . . . . . . . . . . . . L NEAR 0016 CODE
Here is the symbol cross-reference, showing the label defined at
line 80 and used on line 120
START1 . . . . . . . . . . . . . 80# 120
Here is the listing of line 120 showing where the label is used.
120 004B E2 C9 LOOP Start1
If it was a MOV AX,Start1 you would see 16H as an immediate
value of 016H being loaded into AX. As it is, the LOOP is at 04BH
and wanting to jump to Start1, which is 016H. 04BH - 016H - 2
is equal to 0C9H.
It's a number game.
Steve N.
I used the sample you provided and have issues with output of CR and LFs from the strings.
the output simply shows the character and not actually respect a CR and LF codes on the strings I added:
Sample:
ErrorMsg DB 0DH, 0AH, 'ESC key touched', 0
I endedup re-writing a print function
Originally used the code sample here:
xlat0: mov ax,0B800h ;notice that di is already 0
mov es,ax
mov si,offset msg
cld
mov ah,1Fh
disp0: lodsb
or al,al
jz boot2
stosw
jmp disp0
The new function is ------------------------------
PrintMessage:
LODSB
OR AL,AL
JZ Return
MOV AH,0EH
MOV BX,0007H
INT 10h
JMP PrintMessage
good fix msftone
it has been years since i used bios to write to screen - lol
of course, the direct-buffer-write method is fastest
on old CGA cards, writing directly to the buffer caused terrible "flicker" or "flash"
this is because the memory was not synchronized
since EGA and VGA cards have come out, they have done a much better job of synchronizing video memory
in days of old, i used to detect if the card was a CGA, and had a little routine to sync writes
you could read one of the CRT registeres and find horizontal retrace
during a brief period that followed, you could write characters with no flicker
the faster the machine, the more characters you could write after each retrace - lol
For the EGA/VGA alphanumeric modes another method of eliminating flicker was to do your updates on a display page that was not visible, and then switch the visible page. This method did not depend on being able to complete the update in a single vertical frame, and it allowed you to work with up to 8 display pages, all stored in display memory.