News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Printing a message without BIOS

Started by zak100, August 06, 2009, 10:13:48 AM

Previous topic - Next topic

zak100

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



japheth

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.



zak100

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.

dedndave

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

dedndave

#4
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

zak100

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.

dedndave

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

zak100

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.

zak100

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.

dedndave

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

MichaelW


.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
eschew obfuscation

FORTRANS

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.

msftone

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

msftone

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

dedndave

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