Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > alt.os.development > #9391 > unrolled thread

Re: How to use BIOS int 13h ah=48h ?

Started byRod Pemberton <NoHaveNotOne@bcczxcfre.cmm>
First post2016-04-03 17:36 -0400
Last post2016-04-06 00:10 -0400
Articles 13 — 6 participants

Back to article view | Back to alt.os.development

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: How to use BIOS int 13h ah=48h ? Rod Pemberton <NoHaveNotOne@bcczxcfre.cmm> - 2016-04-03 17:36 -0400
    Re: How to use BIOS int 13h ah=48h ? bilsch <king621@comcast.net> - 2016-04-05 05:34 -0700
      Re: How to use BIOS int 13h ah=48h ? "Benjamin David Lunt" <zfysz@fysnet.net> - 2016-04-05 12:53 -0700
        THANKS FOR INFO & SUGGESTIONS bilsch <king621@comcast.net> - 2016-04-09 14:09 -0700
          Re: THANKS FOR INFO & SUGGESTIONS "Mike Gonta" <mikegonta@gmail.com> - 2016-04-09 18:42 -0400
            Re: THANKS FOR INFO & SUGGESTIONS Rod Pemberton <NoHaveNotOne@bcczxcfre.cmm> - 2016-04-10 04:02 -0400
              Re: THANKS FOR INFO & SUGGESTIONS "Alexei A. Frounze" <alexfrunews@gmail.com> - 2016-04-10 01:31 -0700
          Re: THANKS FOR INFO & SUGGESTIONS "Benjamin David Lunt" <zfysz@fysnet.net> - 2016-04-09 21:28 -0700
            Re: THANKS FOR INFO & SUGGESTIONS bilsch <king621@comcast.net> - 2016-04-13 17:30 -0700
              Re: THANKS FOR INFO & SUGGESTIONS Rod Pemberton <NoHaveNotOne@bcczxcfre.cmm> - 2016-04-13 22:09 -0400
          Re: THANKS FOR INFO & SUGGESTIONS "wolfgang kern" <nowhere@never.at> - 2016-04-10 11:02 +0200
            Re: THANKS FOR INFO & SUGGESTIONS "wolfgang kern" <nowhere@never.at> - 2016-04-10 13:31 +0200
      Re: How to use BIOS int 13h ah=48h ? Rod Pemberton <NoHaveNotOne@bcczxcfre.cmm> - 2016-04-06 00:10 -0400

#9391 — Re: How to use BIOS int 13h ah=48h ?

FromRod Pemberton <NoHaveNotOne@bcczxcfre.cmm>
Date2016-04-03 17:36 -0400
SubjectRe: How to use BIOS int 13h ah=48h ?
Message-ID<20160403173650.55074eb8@_>
On Sun, 3 Apr 2016 03:52:01 -0700
bilsch <king621@comcast.net> wrote:

> I've been trying to use int 13h to get the number of
> sectors on the hard drive.

FYI, not many people have posted here (alt.comp.bios)
over the past 5 years or so, Bill.

I saw your post on comp.lang.asm.x86.  Why didn't you
look at Int 13H, AH=41h, BX=55AAh, as I suggested?  ...

comp.lang.asm.x86 was a good place to post.  alt.lang.asm
and even comp.os.msdos.programmer would've been good places
to post.  alt.os.development is probably the best place.
I've added AOD for replies.

>  From Ralph Brown List:
> <code>
> AH = 48h
> DL = drive (80h-FFh)
> DS:SI -> buffer for drive parameters
> 
> Return:
> CF clear if successful
> AH = 00h
> DS:SI buffer filled
> CF set on error
> AH = error code
> 
> Buffer for drive parameters:
> 
> Offset  Size    Description
> 00h    WORD    (call) size of buffer
> (001Ah for v1.x, 001Eh for v2.x, 42h for v3.0)
> (ret) size of returned data
> 02h    WORD    information flags (see #00274)
> 04h    DWORD   number of physical cylinders on drive
> 08h    DWORD   number of physical heads on drive
> 0Ch    DWORD   number of physical sectors per track
> 10h    QWORD   total number of sectors on drive
> 18h    WORD    bytes per sector
> 
> It seems to me, the following code would be the
> correct way to call int 13h ah=48h:

First, are you doing this in a boot loader at 7C00h,
or attempting to call from DOS .com or .exe,
or calling this from an emulator, or calling
this while using Linux or Windows, or using v86 mode?

If in a boot loader at 7C00h, you can call it.
If in DOS as a .com or .exe, DOS may be redirecting
the BIOS IVT interrupt to it's own routines.  If
using DOS, you should use DOS routines, not BIOS.
If in an emulator, there could be a bug.
If under another OS like Linux or Windows,
you should not expect to be able to call it.
If you're using v86 mode, you may have problems
with the PM OS or monitor controlling the v86 mode.

> sxbuf times 0x42 db 0  ;bufr for BIOS to fill

Is this buffer actually before your code?  Do you
jump to the 'mov' instruction below?  I.e., you're
not executing the empty buffer are you? ...

>     mov si,sxbuf		

What segment value is in DS?  It may be wise to make
sure it is below 512KB.  Early machines had only 512KB,
while later ones have 640KB.  Between 640KB and 1MB+64KB-16,
you have BIOS ROMs, video cards, etc.  Above 1MB, shouldn't
be possible, unless you're using "unreal" mode.  However,
the BIOS can't use a DS with a limit allowing access above
1MB+64KB-16.  I.e., your DS must be a 16-bit RM segment value
below 1MB, actually need to be below 640KB or 512KB, and you
must not be using the "unreal" mode to call the BIOS.

>     mov word [si], 0x42
>     mov ah,0x48
>     mov dl,0x80		;bit 7 = hard drive
>     int 0x13		

The buffer value is not necessarily 0x42.  It might be
some other value.  You should call Int 13h, AH=41h, BX=55AAh
to get the version number in register AH.  The AH byte needs
to be zero-extended to word AX and stored at DS:SI.

You also need to check the supported function bitmap
returned in register CX from Int 13h, AH=41h, BX=55AAh
to determine if the 48h call is even supported.  Also,
it might be supported, but just not for your device.

Yes, I see that you're attempting to use the most recent
values for modern machines which should in theory work.
However, each BIOS is different.  It's better to implement
it fully to get things working.  Then, find out why the
abbreviated version doesn't work.

> And the following would be the correct way to read the sectors info:
> 
>     mov di,0x10 		;offset into sxbuf
> getbuf:
>     mov ax,[sxbuf+di] 	

Location +0x10 is a QWORD or 8 bytes.

AH and AL are 1 byte (available in all modes)
AX is two bytes (available in 16-bit mode)  WORD
EAX is four bytes (available in 32-bit mode)  DWORD
RAX is eight bytes (available int 64-bit mode)  QWORD

>     inc di

DI is not scaled by the size of AX like a C variable.

I.e., 'inc di' increments DI by one (1).  So, you're
loading two bytes into AX, but moving DI by only one
byte at a time ...  You probably want another 'inc'
instruction here.

>     cmp di,4

With two 'inc' instructions, you'd need ,8 here.

>     je done
>     jmp getbuf
> <code>

While you are loading AX with values, I don't see code
to save or use AX within the loop.  IIRC, you called
a print loop in your CLAX post.

> but it doesn't work. The call returns:
> CF=1 (failed)
> ah=01 (invalid parameter)
> ax = 0000, 0000, 0000, 0000

I would assume that this is because the 0x42h in DS:SI
buffer is not the correct value, or that DS:SI is not
accessable by the BIOS, or that hard drive 80h is not
actually present.

Perhaps, you're attempting to access a floppy or USB
device or CD-ROM/DVD-ROM?

A floppy device can't be on 80h or higher. A USB device
can only be 80h if it was the boot device and is being
emulated by BIOS as a hard disk.  IIRC, a CD-ROM or
DVD-ROM can never be 80h, it must be secondary, e.g., 81h.

Also, note that some BIOS calls need you to explicitly
set CF via STC before being called.  Another option would
be that AH or other register is being corrupted somehow,
e.g., use of a debugger or emulator.

> I've tried variations, but none work.  I've tried it on five
> relatively new (last 5 years) computers - never works.
> 
> How do you do it?

I haven't, but some on alt.os.development have recently.
There was a short competition, IIRC, which used Int 13h
BIOS disk routines.  I added AOD to the reply newsgroups.


Other questions:

What value does Int 13h, AH=41h, BX=55AAh
return in in register CX?

This word value has a bitmap which indicates
which "IBM/MS INT 13 Extensions" are supported
by the BIOS.  Bit 1, 2, and 3 are listed as
extended, removable, and enhanced, respectively.
48h is listed for all three.  48h description
is as an extension, so, I'd suspect bit 1 to
be set.


What value does Int 13h, AH=41h, BX=55AAh
return in in register AH?

This byte value should be filled in to the first
word of the DS:SI buffer for Int 13h, AH=48h.


Int 13h, AH=48h, indicates that some BIOSes
need word at DS:[SI+2] set to 0000h.  So, you
should set both the version number word and
clear the next word in 'sxbuf'.


Is your DS:SI buffer placed below 1MB, preferably
below 640K or 512K?  Can you confirm the DS:SI
segment:offset?


Are you initializing the USB controllers?  If so,
you'll lose access to a USB boot device that is
being emulated by the BIOS as a hard disk.


If RBIL is not providing enough information,
you can search for the Phoenix Enhanced Disk
Drive Specifications.  There are a few versions.


Rod Pemberton

[toc] | [next] | [standalone]


#9403

Frombilsch <king621@comcast.net>
Date2016-04-05 05:34 -0700
Message-ID<ne0b78$m2g$1@dont-email.me>
In reply to#9391
On 04/03/2016 02:36 PM, Rod Pemberton wrote:

>
> First, are you doing this in a boot loader at 7C00h,
> or attempting to call from DOS .com or .exe,
> or calling this from an emulator, or calling
> this while using Linux or Windows, or using v86 mode?

Rod, thanks for your comments.

First, good news: I revised the program (see listing below), and for the 
first time ah=0x48 returns CF=0 (success) and ah=0. But the number of 
sectors doesn't work out right. It says EAB025420000FFFF. Backwards 
EAB02542 is 24520BAE is 609356718 decimal, times 512 is 311,990,639,616 
bytes. But that doesn't take little endian into account.  GPARTED says 
320,071,700,616 bytes.

To answer your questions: The program (code & data) fills one sector. I 
use org 7c00. I write it to the boot sector of a partition with boot 
flag set, or I write it to the boot sector of a partition and chain load 
it using GRUB - depending on which computer I use.

It has one 'section': text.  The segment registers: when I do set them, 
I use the following, which makes no difference in the output:
    mov ax, 0  ; set up segments
    mov ds, ax
    mov es, ax
    mov ss, ax     ; setup stack
    mov sp, 0x7C00 ; stack grows downwards from 0x7C00

> The buffer value is not necessarily 0x42.  It might be
> some other value.  You should call Int 13h, AH=41h, BX=55AAh
> to get the version number in register AH.  The AH byte needs
> to be zero-extended to word AX and stored at DS:SI.
>
> You also need to check the supported function bitmap
> returned in register CX from Int 13h, AH=41h, BX=55AAh
> to determine if the 48h call is even supported.  Also,
> it might be supported, but just not for your device.

I revised my code (listed below): it now reports version and bitmap.  On 
this PC it reports version 3.0 and bitmap says bits 0 and 2 set (ah=0x48 
is supported).

>
> Yes, I see that you're attempting to use the most recent
> values for modern machines which should in theory work.
> However, each BIOS is different.  It's better to implement
> it fully to get things working.  Then, find out why the
> abbreviated version doesn't work.
>
>> And the following would be the correct way to read the sectors info:
>>
>>      mov di,0x10 		;offset into sxbuf
>> getbuf:
>>      mov ax,[sxbuf+di] 	
>
> Location +0x10 is a QWORD or 8 bytes.
>
> AH and AL are 1 byte (available in all modes)
> AX is two bytes (available in 16-bit mode)  WORD
> EAX is four bytes (available in 32-bit mode)  DWORD
> RAX is eight bytes (available int 64-bit mode)  QWORD
>
>>      inc di
>
> DI is not scaled by the size of AX like a C variable.
>
> I.e., 'inc di' increments DI by one (1).  So, you're
> loading two bytes into AX, but moving DI by only one
> byte at a time ...  You probably want another 'inc'
> instruction here.
>
>>      cmp di,4
>
> With two 'inc' instructions, you'd need ,8 here.
>
>>      je done
>>      jmp getbuf
>> <code>
>
> While you are loading AX with values, I don't see code
> to save or use AX within the loop.  IIRC, you called
> a print loop in your CLAX post.



Please see revised code below, all these points are addressed.


>
>> but it doesn't work. The call returns:
>> CF=1 (failed)
>> ah=01 (invalid parameter)
>> ax = 0000, 0000, 0000, 0000
>
> I would assume that this is because the 0x42h in DS:SI
> buffer is not the correct value, or that DS:SI is not
> accessable by the BIOS, or that hard drive 80h is not
> actually present.
>
> Perhaps, you're attempting to access a floppy or USB
> device or CD-ROM/DVD-ROM?
>
> A floppy device can't be on 80h or higher. A USB device
> can only be 80h if it was the boot device and is being
> emulated by BIOS as a hard disk.  IIRC, a CD-ROM or
> DVD-ROM can never be 80h, it must be secondary, e.g., 81h.
>
> Also, note that some BIOS calls need you to explicitly
> set CF via STC before being called.  Another option would
> be that AH or other register is being corrupted somehow,
> e.g., use of a debugger or emulator.
>
>> I've tried variations, but none work.  I've tried it on five
>> relatively new (last 5 years) computers - never works.
>>
>> How do you do it?
>
> I haven't, but some on alt.os.development have recently.
> There was a short competition, IIRC, which used Int 13h
> BIOS disk routines.  I added AOD to the reply newsgroups.
>
>
> Other questions:
>
> What value does Int 13h, AH=41h, BX=55AAh
> return in in register CX?
>
> This word value has a bitmap which indicates
> which "IBM/MS INT 13 Extensions" are supported
> by the BIOS.  Bit 1, 2, and 3 are listed as
> extended, removable, and enhanced, respectively.
> 48h is listed for all three.  48h description
> is as an extension, so, I'd suspect bit 1 to
> be set.
>
>
> What value does Int 13h, AH=41h, BX=55AAh
> return in in register AH?
>
> This byte value should be filled in to the first
> word of the DS:SI buffer for Int 13h, AH=48h.
>
>
> Int 13h, AH=48h, indicates that some BIOSes
> need word at DS:[SI+2] set to 0000h.  So, you
> should set both the version number word and
> clear the next word in 'sxbuf'.
>
>
> Is your DS:SI buffer placed below 1MB, preferably
> below 640K or 512K?  Can you confirm the DS:SI
> segment:offset?
>
>
> Are you initializing the USB controllers?  If so,
> you'll lose access to a USB boot device that is
> being emulated by the BIOS as a hard disk.
>
>
> If RBIL is not providing enough information,
> you can search for the Phoenix Enhanced Disk
> Drive Specifications.  There are a few versions.
>
>
> Rod Pemberton
>
<code>
;kern1.asm	nasm -f bin kern1.asm -o kern1.bin

;reads an 8 byte buffer containing number of sectors info; buffer begins 
at ds:si + 0x10

org 0x7c00
bits 16
SECTION .text

    mov ax, 0  ; set up segments
    mov ds, ax
    mov es, ax
    mov ss, ax     ; setup stack
    mov sp, 0x7C00 ; stack grows downwards from 0x7C00

    mov si,msg41
    call print_string
    mov bx,0x55aa
    mov dl, 0x80
    mov ah,0x41
    int 0x13
    push cx
    push ax
    cmp ah,0x10		;ver 1.x
    mov word[bsiz],0x1a
    cmp ah,0x20		;ver 2.0
    mov word[bsiz],0x1e
    cmp ah,0x21		;ver 2.1
    mov word[bsiz],0x1e
    cmp ah,0x30		;ver 3.0
    mov word[bsiz],0x42

    mov si,ahmsg41	;'ah41 = '
    call print_string
    mov bx,i2xt
    xor cx,cx		;cx counts to 1
    pop ax
lup1:			;here ax is data from ah=0x41
    rol ax,4		;put hi hex digit on right
    push ax		;rol'd version
    and al,0x0f		;digit in al, is index into i2xt
    xlat			;table result in al, bx already points i2xt
    mov ah,0xe			
    int 0x10		;write
    pop ax
    cmp cx,1
    je api		;cx=1 then done w/ah
    inc cx
    jmp lup1
api:
    mov si,apimsg	;'api = '
    call print_string
    pop cx
    mov al,cl
    xlat			;table result in al, bx already points i2xt
    mov ah,0xe			
    int 0x10		;write

    mov si, msg48	;display BIOS call
    call print_string
    clc			;clear CF
    mov si,sxbuf		;bufr for BIOS to fill
    mov di,word[bsiz]
    mov [sxbuf],di 	;bufr size for BIOS call
    mov ah,0x48
    mov dl,0x80		;bit 7 = hd
    int 0x13		
    push ax

    jc cf1
    mov si, cfzro
    call print_string
    jmp ah48
cf1:
    mov si, cfone
    call print_string
ah48:
    mov si,ahmsg48 	;'ah='
    call print_string
    xor cx,cx		;cx counts to 1
    pop ax
lup2:			;here ax is data from ah=0x48
    rol ax,4		;put hi hex digit on right
    push ax		;rol'd version
    and al,0x0f		;digit in al, is index into i2xt
    xlat			;table result in al, bx already points i2xt
    mov ah,0xe			
    int 0x10		;write
    pop ax
    cmp cx,1
    je dsxinfo		;cx=1 then done w/ah
    inc cx
    jmp lup2

dsxinfo:
    mov si, sxmsg	;'hex # sectors = '
    call print_string
    xor cx,cx
    xor dx,dx
    xor di,di
    add di,0x10		;offset into sxbuf
get4hex:
    add di,dx
    add di,dx		;di=2*dx, dx counts words, di counts bytes
    mov ax,[sxbuf+di] 	
outdig:
    rol ax,4		;put hi hex digit on right
    push ax		;save rol'd ax
    and al,0x0f		;digit in al, is index into i2xt
    xlat			;table result in al
    mov ah,0xe			
    int 0x10		;write
    pop ax		;rol'd version of ax
    inc cx
    cmp cx,4		;cx is inner loop counter
    jne outdig		;4 digit loop - 1 nibble/loop

    xor cx,cx
    inc dx		;dx counts words
    cmp dx,4		;4 word loop - 1 word/loop
    je nend
    jmp get4hex		;get next 4 hex digits
nend:
    mov si, tstamp	;date & time (manual)
    call print_string	
    jmp $		;jmp here infinite loop

msg41 db 0xd,0xa,'int 13h, ah=41h', 0xd, 0xa, 0
msg48 db 0xd,0xa,'int 13h, ah=48h', 0xd, 0xa, 0
bsiz  dw 0
sxbuf times 0x42 db 0  ;bufr for BIOS to fill
ahmsg41  db 'ah = ', 0
apimsg   db '   api = ', 0
cfzro    db 'CF=0. success.', 0xd, 0xa, 0
cfone    db 'CF=1. failed.', 0xd, 0xa, 0
ahmsg48    db 'ah>0 is error code. ah = ', 0
sxmsg	 db  0xd, 0xa ,'L-endian sectors = ', 0
tstamp	 db  0xd, 0xa ,'date: 4/05/16  1:00 am', 0
i2xt	 db  '0123456789ABCDEF'

  ; ===============================================================
  ; 			calls start here
  ; ===============================================================

print_string:
    push ax		;preserve ax
.lup:
    lodsb        	; grab a byte from si
    or al, al  		; logical or al by itself
    jz .done   		; if the result is zero, get out
    mov ah, 0xe
    int 0x10     	; otherwise, print out the character!
    jmp .lup
  .done:
    pop ax		;preserve ax
    ret

    times 510-($-$$) db 0
    dw 0xAA55
<code>

[toc] | [prev] | [next] | [standalone]


#9406

From"Benjamin David Lunt" <zfysz@fysnet.net>
Date2016-04-05 12:53 -0700
Message-ID<ne1541$17fa$1@gioia.aioe.org>
In reply to#9403
"bilsch" <king621@comcast.net> wrote in message 
news:ne0b78$m2g$1@dont-email.me...
> On 04/03/2016 02:36 PM, Rod Pemberton wrote:

Hi bilsch, Hi guys,

I just have a few comments on your code, if you don't mind.

> <code>
> ;kern1.asm nasm -f bin kern1.asm -o kern1.bin
>
> ;reads an 8 byte buffer containing number of sectors info; buffer begins 
> at ds:si + 0x10
>
> org 0x7c00
> bits 16
> SECTION .text
>
>    mov ax, 0  ; set up segments

; in boot sectors, space is sometimes an issue.  Every byte
; counts, so I would change the above to
;    xor  ax,ax     ; saves a byte

>    mov ds, ax
>    mov es, ax
>    mov ss, ax     ; setup stack
>    mov sp, 0x7C00 ; stack grows downwards from 0x7C00
>
>    mov si,msg41
>    call print_string
>    mov bx,0x55aa
>    mov dl, 0x80
>    mov ah,0x41
>    int 0x13

; on return:
;  carry set if error
;    jc  short to_some_error_handler
;  carry clear if successful
;    cmp bx,0xAA55
;    jne short to_some_error_handler

>    push cx
>    push ax
>    cmp ah,0x10 ;ver 1.x
>    mov word[bsiz],0x1a
>    cmp ah,0x20 ;ver 2.0
>    mov word[bsiz],0x1e
>    cmp ah,0x21 ;ver 2.1
>    mov word[bsiz],0x1e
>    cmp ah,0x30 ;ver 3.0
>    mov word[bsiz],0x42

; the above code will *always* put a value of 0x42 in the
;  [bsiz] address.  You need some 'jcc' in there somewhere.

>    mov si,ahmsg41 ;'ah41 = '
>    call print_string

>    mov bx,i2xt
>    xor cx,cx ;cx counts to 1
>    pop ax
> lup1: ;here ax is data from ah=0x41
>    rol ax,4 ;put hi hex digit on right
>    push ax ;rol'd version
>    and al,0x0f ;digit in al, is index into i2xt
>    xlat ;table result in al, bx already points i2xt
>    mov ah,0xe int 0x10 ;write
>    pop ax
>    cmp cx,1
>    je api ;cx=1 then done w/ah
>    inc cx
>    jmp lup1

; I noticed that you use this print code a few times
;  within your listing here.  Can you call a routine
;  to do this?  Rather than listing it numerous times,
;  which takes up space, you can just call a function
;  to do it.  Also, I would change it a bit.
;
; first comment:
;  Setting CX to 0, then comparing it with a non-zero
;  value adds code, specifically an extra 'cmp' and 'jcc'
;  instruction.  Slower and larger.
;
;       mov  cx,2
;  @@:
;       ; do something here
;
;       dec  cx
;       jnz  short @b
; or change the above to just the 'loop' instruction
;       loop @b
;
; Saves time and space.

; the code above now becomes
;    mov  bx,i2xt
;    mov  cx,2      ; printing 2 nibbles
;    pop  ax
; lup1:             ; here ax is data from ah=0x41
;    rol  ax,4      ; put hi hex digit on right
;    push ax        ; rol'd version
;    and  al,0x0f   ; digit in al, is index into i2xt
;    xlat           ; table result in al, bx already points i2xt
;    mov  ah,0xe
;    int  0x10      ; write
;    pop  ax
;    loop lup1
;
; (It is easier on the eyes if you align the colums of code
;  and comments.  i.e.: which is easier to read, your code
;  above, or my code here?)
;
; Second comment:
;  printing hex digits is something everyone has done so
;  there is a lot of code around.  A few years ago, more than
;  I would like to admit, a regular in c.l.a.x passed away.
;  However, he left us with a very nice hex printing routine.
;    http://www.fysnet.net/prthex.htm#crayne
;  It uses 32-bit registers and prints to a string, but you
;  should be able to modify it to use 16-bit registers and
;  directly to the screen.
;
> api:
>    mov si,apimsg ;'api = '
>    call print_string
>    pop cx
>    mov al,cl

;  As you probably know, the push instruction does push
;  the register, it pushes the contents of the register.
;  Therefore, you don't have to use the same register
;  when you pop the value.  You can easily use a different
;  register.  Changing the above to
;    pop  ax
;  removes the 'mov' instruction.  Save space and time!

>    xlat ;table result in al, bx already points i2xt
>    mov ah,0xe int 0x10 ;write
>
>    mov si, msg48 ;display BIOS call
>    call print_string
>    clc ;clear CF
>    mov si,sxbuf ;bufr for BIOS to fill
>    mov di,word[bsiz]
>    mov [sxbuf],di ;bufr size for BIOS call
>    mov ah,0x48
>    mov dl,0x80 ;bit 7 = hd
>    int 0x13 push ax
>
>    jc cf1
>    mov si, cfzro
>    call print_string
>    jmp ah48
> cf1:
>    mov si, cfone
>    call print_string
> ah48:
>    mov si,ahmsg48 ;'ah='
>    call print_string
>    xor cx,cx ;cx counts to 1
>    pop ax
> lup2: ;here ax is data from ah=0x48
>    rol ax,4 ;put hi hex digit on right
>    push ax ;rol'd version
>    and al,0x0f ;digit in al, is index into i2xt
>    xlat ;table result in al, bx already points i2xt
>    mov ah,0xe int 0x10 ;write
>    pop ax
>    cmp cx,1
>    je dsxinfo ;cx=1 then done w/ah
>    inc cx
>    jmp lup2
>
> dsxinfo:
>    mov si, sxmsg ;'hex # sectors = '
>    call print_string
>    xor cx,cx
>    xor dx,dx
>    xor di,di
>    add di,0x10 ;offset into sxbuf

;    mov  di,0x10
;   (but I'm sure you are not worried about it at the
;    moment.  You just want the value printed)

> get4hex:
>    add di,dx
>    add di,dx ;di=2*dx, dx counts words, di counts bytes
>    mov ax,[sxbuf+di] outdig:
>    rol ax,4 ;put hi hex digit on right
>    push ax ;save rol'd ax
>    and al,0x0f ;digit in al, is index into i2xt
>    xlat ;table result in al
>    mov ah,0xe int 0x10 ;write
>    pop ax ;rol'd version of ax
>    inc cx
>    cmp cx,4 ;cx is inner loop counter
>    jne outdig ;4 digit loop - 1 nibble/loop
>    xor cx,cx
>    inc dx ;dx counts words
>    cmp dx,4 ;4 word loop - 1 word/loop
>    je nend
>    jmp get4hex ;get next 4 hex digits


; I would change the above to use SI and 'lodsb'
;    mov  cx,8     ; 8 bytes
;    lea  si,[sxbuf+0x10]
; @@:
;    lodsb
;    call hexdb    ; Crayne's print nibble
;    loop @b

Please note that your code all prints the hex digits
backwards.  Which through your comments, I think you
realize this. :-)

Anyway, just a few comments.

I know it is C code instead of assembly, but I have
source code at
 http://www.fysnet.net/syscore_help.htm
that will show you how to get all of the information from
the drive, including total sector count.

Hope this helps,
Ben

[toc] | [prev] | [next] | [standalone]


#9416 — THANKS FOR INFO & SUGGESTIONS

Frombilsch <king621@comcast.net>
Date2016-04-09 14:09 -0700
SubjectTHANKS FOR INFO & SUGGESTIONS
Message-ID<nebqrl$8it$1@dont-email.me>
In reply to#9406
On 04/05/2016 12:53 PM, Benjamin David Lunt wrote:
> "bilsch" <king621@comcast.net> wrote in message
> news:ne0b78$m2g$1@dont-email.me...
>> On 04/03/2016 02:36 PM, Rod Pemberton wrote:
>
> Hi bilsch, Hi guys,
>
> I just have a few comments on your code, if you don't mind.
>
>> <code>
>> ;kern1.asm nasm -f bin kern1.asm -o kern1.bin
>>
>> ;reads an 8 byte buffer containing number of sectors info; buffer begins
>> at ds:si + 0x10
>>
>> org 0x7c00
>> bits 16
>> SECTION .text
>>
>>     mov ax, 0  ; set up segments
>
> ; in boot sectors, space is sometimes an issue.  Every byte
> ; counts, so I would change the above to
> ;    xor  ax,ax     ; saves a byte
>
>>     mov ds, ax
>>     mov es, ax
>>     mov ss, ax     ; setup stack
>>     mov sp, 0x7C00 ; stack grows downwards from 0x7C00
>>
>>     mov si,msg41
>>     call print_string
>>     mov bx,0x55aa
>>     mov dl, 0x80
>>     mov ah,0x41
>>     int 0x13
>
> ; on return:
> ;  carry set if error
> ;    jc  short to_some_error_handler
> ;  carry clear if successful
> ;    cmp bx,0xAA55
> ;    jne short to_some_error_handler
>
>>     push cx
>>     push ax
>>     cmp ah,0x10 ;ver 1.x
>>     mov word[bsiz],0x1a
>>     cmp ah,0x20 ;ver 2.0
>>     mov word[bsiz],0x1e
>>     cmp ah,0x21 ;ver 2.1
>>     mov word[bsiz],0x1e
>>     cmp ah,0x30 ;ver 3.0
>>     mov word[bsiz],0x42
>
> ; the above code will *always* put a value of 0x42 in the
> ;  [bsiz] address.  You need some 'jcc' in there somewhere.
>
>>     mov si,ahmsg41 ;'ah41 = '
>>     call print_string
>
>>     mov bx,i2xt
>>     xor cx,cx ;cx counts to 1
>>     pop ax
>> lup1: ;here ax is data from ah=0x41
>>     rol ax,4 ;put hi hex digit on right
>>     push ax ;rol'd version
>>     and al,0x0f ;digit in al, is index into i2xt
>>     xlat ;table result in al, bx already points i2xt
>>     mov ah,0xe int 0x10 ;write
>>     pop ax
>>     cmp cx,1
>>     je api ;cx=1 then done w/ah
>>     inc cx
>>     jmp lup1
>
> ; I noticed that you use this print code a few times
> ;  within your listing here.  Can you call a routine
> ;  to do this?  Rather than listing it numerous times,
> ;  which takes up space, you can just call a function
> ;  to do it.  Also, I would change it a bit.
> ;
> ; first comment:
> ;  Setting CX to 0, then comparing it with a non-zero
> ;  value adds code, specifically an extra 'cmp' and 'jcc'
> ;  instruction.  Slower and larger.
> ;
> ;       mov  cx,2
> ;  @@:
> ;       ; do something here
> ;
> ;       dec  cx
> ;       jnz  short @b
> ; or change the above to just the 'loop' instruction
> ;       loop @b
> ;
> ; Saves time and space.
>
> ; the code above now becomes
> ;    mov  bx,i2xt
> ;    mov  cx,2      ; printing 2 nibbles
> ;    pop  ax
> ; lup1:             ; here ax is data from ah=0x41
> ;    rol  ax,4      ; put hi hex digit on right
> ;    push ax        ; rol'd version
> ;    and  al,0x0f   ; digit in al, is index into i2xt
> ;    xlat           ; table result in al, bx already points i2xt
> ;    mov  ah,0xe
> ;    int  0x10      ; write
> ;    pop  ax
> ;    loop lup1
> ;
> ; (It is easier on the eyes if you align the colums of code
> ;  and comments.  i.e.: which is easier to read, your code
> ;  above, or my code here?)
> ;
> ; Second comment:
> ;  printing hex digits is something everyone has done so
> ;  there is a lot of code around.  A few years ago, more than
> ;  I would like to admit, a regular in c.l.a.x passed away.
> ;  However, he left us with a very nice hex printing routine.
> ;    http://www.fysnet.net/prthex.htm#crayne
> ;  It uses 32-bit registers and prints to a string, but you
> ;  should be able to modify it to use 16-bit registers and
> ;  directly to the screen.
> ;
>> api:
>>     mov si,apimsg ;'api = '
>>     call print_string
>>     pop cx
>>     mov al,cl
>
> ;  As you probably know, the push instruction does push
> ;  the register, it pushes the contents of the register.
> ;  Therefore, you don't have to use the same register
> ;  when you pop the value.  You can easily use a different
> ;  register.  Changing the above to
> ;    pop  ax
> ;  removes the 'mov' instruction.  Save space and time!
>
>>     xlat ;table result in al, bx already points i2xt
>>     mov ah,0xe int 0x10 ;write
>>
>>     mov si, msg48 ;display BIOS call
>>     call print_string
>>     clc ;clear CF
>>     mov si,sxbuf ;bufr for BIOS to fill
>>     mov di,word[bsiz]
>>     mov [sxbuf],di ;bufr size for BIOS call
>>     mov ah,0x48
>>     mov dl,0x80 ;bit 7 = hd
>>     int 0x13 push ax
>>
>>     jc cf1
>>     mov si, cfzro
>>     call print_string
>>     jmp ah48
>> cf1:
>>     mov si, cfone
>>     call print_string
>> ah48:
>>     mov si,ahmsg48 ;'ah='
>>     call print_string
>>     xor cx,cx ;cx counts to 1
>>     pop ax
>> lup2: ;here ax is data from ah=0x48
>>     rol ax,4 ;put hi hex digit on right
>>     push ax ;rol'd version
>>     and al,0x0f ;digit in al, is index into i2xt
>>     xlat ;table result in al, bx already points i2xt
>>     mov ah,0xe int 0x10 ;write
>>     pop ax
>>     cmp cx,1
>>     je dsxinfo ;cx=1 then done w/ah
>>     inc cx
>>     jmp lup2
>>
>> dsxinfo:
>>     mov si, sxmsg ;'hex # sectors = '
>>     call print_string
>>     xor cx,cx
>>     xor dx,dx
>>     xor di,di
>>     add di,0x10 ;offset into sxbuf
>
> ;    mov  di,0x10
> ;   (but I'm sure you are not worried about it at the
> ;    moment.  You just want the value printed)
>
>> get4hex:
>>     add di,dx
>>     add di,dx ;di=2*dx, dx counts words, di counts bytes
>>     mov ax,[sxbuf+di] outdig:
>>     rol ax,4 ;put hi hex digit on right
>>     push ax ;save rol'd ax
>>     and al,0x0f ;digit in al, is index into i2xt
>>     xlat ;table result in al
>>     mov ah,0xe int 0x10 ;write
>>     pop ax ;rol'd version of ax
>>     inc cx
>>     cmp cx,4 ;cx is inner loop counter
>>     jne outdig ;4 digit loop - 1 nibble/loop
>>     xor cx,cx
>>     inc dx ;dx counts words
>>     cmp dx,4 ;4 word loop - 1 word/loop
>>     je nend
>>     jmp get4hex ;get next 4 hex digits
>
>
> ; I would change the above to use SI and 'lodsb'
> ;    mov  cx,8     ; 8 bytes
> ;    lea  si,[sxbuf+0x10]
> ; @@:
> ;    lodsb
> ;    call hexdb    ; Crayne's print nibble
> ;    loop @b
>
> Please note that your code all prints the hex digits
> backwards.  Which through your comments, I think you
> realize this. :-)
>
> Anyway, just a few comments.
>
> I know it is C code instead of assembly, but I have
> source code at
>   http://www.fysnet.net/syscore_help.htm
> that will show you how to get all of the information from
> the drive, including total sector count.
>
> Hope this helps,
> Ben
>
>
OK, I've got it how I want it.  Your suggestions about saving space were 
good, as I ran out of room at one point. Code is more efficient and 
compact now.  The program is listed below if anybody is interested. 
Thanks.   Bill S.

<code>
org 0x7c00
bits 16
SECTION .text

    xor ax,ax      ; set up segments
    mov ds, ax
    mov es, ax
    mov ss, ax     ; setup stack
    mov sp, 0x7c00 ; stack grows downwards from 0x7c00

    mov si,msg41
    call print_string
    mov bx,0x55aa
    mov dl,0x80
    mov ah,0x41
    int 0x13
    push cx
    cmp ah,0x10        ;ver 1.x
    jne ver20
    mov word[bsiz],0x1a
ver20:
    cmp ah,0x20        ;ver 2.0
    jne ver21
    mov word[bsiz],0x1e
ver21:
    cmp ah,0x21        ;ver 2.1
    jne ver30
    mov word[bsiz],0x1e
ver30:
    cmp ah,0x30        ;ver 3.0
    jne ckbsiz
    mov word[bsiz],0x42
ckbsiz:
    cmp word[bsiz],0
    jne ah41
    mov si,noext        ;no int 13h ext
    call print_string
    jmp nend        ;w/o bsiz we're going nowhere
ah41:
    mov si,ahmsg41    ;ah =
    call print_string
    mov bx,i2xt
    mov cx,2        ;cx = # of digits to translate
    call b2xa
api:
    mov si,apimsg    ;'api = '
    call print_string
    pop ax        ;this is pushed cx
    xlat            ;table result in al, bx already points i2xt
    mov ah,0xe
    int 0x10        ;write
ah48:
    mov si, msg48    ;display BIOS call
    call print_string
    clc            ;clear CF
    mov si,sxbuf        ;bufr for BIOS to fill
    mov di,word[bsiz]
    mov [sxbuf],di     ;bufr size for BIOS call
    mov ah,0x48
    mov dl,0x80        ;bit 7 = hd
    int 0x13

    jc cf1
    mov si, cfzro
    call print_string
    jmp ah48m
cf1:
    mov si, cfone
    call print_string
ah48m:
    mov si,ahmsg48     ;'ah='
    call print_string
    mov cx,2        ;cx = # of digits to translate
    call b2xa
dsxinfo:
    mov si, sxmsg    ;'hex # sectors = '
    call print_string
    mov di,0x16        ;start w/bytes 0x16 & 0x17
get4digit:
    mov cx,4        ;cx counts 4 nibbles/word
    mov ax,[sxbuf+di]
outdigit:
    rol ax,4        ;put hi hex digit on right
    push ax        ;save rol'd ax
    and al,0x0f        ;digit in al, is index into i2xt
    xlat            ;table result in al
    mov ah,0xe
    int 0x10        ;write
    pop ax        ;rol'd version of ax
    dec cx
    jnz outdigit        ;4 digit loop - 1 nibble/loop
    dec di
    dec di
    cmp di,0xe        ;end w/bytes 0x10 & 0x11
    jnz get4digit    ;get next 4 hex digits
nend:
    mov si, tstamp    ;date & time (manual)
    call print_string
    jmp $        ;jmp here infinite loop

msg41      db 0xd,0xa,'int 13h, ah=41h', 0xd, 0xa, 0
msg48      db 0xd,0xa,'int 13h, ah=48h', 0xd, 0xa, 0
ahmsg41  db 'ah = ', 0
noext     db '   no int 13h ext', 0
apimsg   db '   api = ', 0
cfzro    db 'CF=0=success.', 0xd, 0xa, 0
cfone    db 'CF=1=failed.', 0xd, 0xa, 0
ahmsg48  db 'ah>0 is an error code. ah = ', 0
sxmsg     db  0xd, 0xa ,'# of sectors = ', 0
tstamp     db  0xd, 0xa ,'4/08/16  7:00 am', 0
i2xt     db '0123456789ABCDEF'
bsiz       dw 0
sxbuf times 0x42 db 0  ;bufr for BIOS to fill
  ; ===============================================================
  ;             calls start here
  ; ===============================================================

print_string:
    push ax        ;preserve ax
.lup:
    lodsb            ; grab a byte from si
    or al, al          ; logical or al by itself
    jz .done           ; if the result is zero, get out
    mov ah, 0xe
    int 0x10         ; otherwise, print out the character!
    jmp .lup
  .done:
    pop ax        ;preserve ax
    ret

b2xa:            ;ax has data, cx has # nibs to translate
    rol ax,4        ;put hi hex digit on right
    push ax        ;rol'd version
    and al,0x0f        ;digit in al, is index into i2xt
    xlat            ;table result in al, bx already points i2xt
    mov ah,0xe
    int 0x10        ;write
    pop ax
    dec cx
    jnz b2xa
    ret

    times 510-($-$$) db 0
    dw 0xAA55
</code>

[toc] | [prev] | [next] | [standalone]


#9417 — Re: THANKS FOR INFO & SUGGESTIONS

From"Mike Gonta" <mikegonta@gmail.com>
Date2016-04-09 18:42 -0400
SubjectRe: THANKS FOR INFO & SUGGESTIONS
Message-ID<nec0hn$75a$1@gioia.aioe.org>
In reply to#9416
"bilsch" wrote:
> OK, I've got it how I want it.  Your suggestions about
> saving space were good, as I ran out of room at one point.
> Code is more efficient and compact now.  The program is
> listed below if anybody is interested.
>    ....
>    mov bx,0x55aa
>    mov dl,0x80
>    ....

Best practice is not to assume the drive ID. At this point
in the code the BIOS has the boot drive ID in DL (which
should be used (and saved for later use as well).

>    ....
> print_string:
>    push ax        ;preserve ax
> .lup:
>    lodsb            ; grab a byte from si
>    or al, al          ; logical or al by itself
>    jz .done           ; if the result is zero, get out
>    mov ah, 0xe
>    int 0x10         ; otherwise, print out the character!
>    jmp .lup
>  .done:
>    pop ax        ;preserve ax
>    ret
>    ....

BIOS INT 0x10, AH=0x0E expects a BH="video page" (typically
this is BH=0, simply use the first "video page").
Oh, and you spelled loop wrong - the correct spelling should
be "lupe".


Mike Gonta
look and see - many look but few see

http://mikegonta.com
http://tawk.to/mikegonta

[toc] | [prev] | [next] | [standalone]


#9420 — Re: THANKS FOR INFO & SUGGESTIONS

FromRod Pemberton <NoHaveNotOne@bcczxcfre.cmm>
Date2016-04-10 04:02 -0400
SubjectRe: THANKS FOR INFO & SUGGESTIONS
Message-ID<20160410040225.725af127@_>
In reply to#9417
On Sat, 9 Apr 2016 18:42:51 -0400
"Mike Gonta" <mikegonta@gmail.com> wrote:

> > .lup:
>
> Oh, and you spelled loop wrong - the correct
> spelling should be "lupe".

Huh?


Rod Pemberton

[toc] | [prev] | [next] | [standalone]


#9421 — Re: THANKS FOR INFO & SUGGESTIONS

From"Alexei A. Frounze" <alexfrunews@gmail.com>
Date2016-04-10 01:31 -0700
SubjectRe: THANKS FOR INFO & SUGGESTIONS
Message-ID<67bcfb85-b8df-46e2-a5ee-0d7b4046ed50@googlegroups.com>
In reply to#9420
On Sunday, April 10, 2016 at 1:01:47 AM UTC-7, Rod Pemberton wrote:
> On Sat, 9 Apr 2016 18:42:51 -0400
> "Mike Gonta" <...@gmail.com> wrote:
> 
> > > .lup:
> >
> > Oh, and you spelled loop wrong - the correct
> > spelling should be "lupe".
> 
> Huh?

Italian for female wolves. With some imagination it could
become Guadalupe or lupus. Just kiddin'.

Alex

[toc] | [prev] | [next] | [standalone]


#9419 — Re: THANKS FOR INFO & SUGGESTIONS

From"Benjamin David Lunt" <zfysz@fysnet.net>
Date2016-04-09 21:28 -0700
SubjectRe: THANKS FOR INFO & SUGGESTIONS
Message-ID<neckpi$1f0k$1@gioia.aioe.org>
In reply to#9416
"bilsch" <king621@comcast.net> wrote in message 
news:nebqrl$8it$1@dont-email.me...

> OK, I've got it how I want it.  Your suggestions about saving space were 
> good, as I ran out of room at one point. Code is more efficient and 
> compact now.  The program is listed below if anybody is interested. 
> Thanks.   Bill S.

Glad to help.  I'll make a few more suggestions.

> <code>
> org 0x7c00
> bits 16
> SECTION .text
>
>    xor ax,ax      ; set up segments
>    mov ds, ax
>    mov es, ax
>    mov ss, ax     ; setup stack
>    mov sp, 0x7c00 ; stack grows downwards from 0x7c00
>
>    mov si,msg41
>    call print_string
>    mov bx,0x55aa
>    mov dl,0x80

; As Mike noted, DL is passed to your code.
     mov  [saved_dl],dl
; and comment out the line you used above,
;  being sure not to modify DL beforehand.

>    mov ah,0x41
>    int 0x13
>    push cx

>    cmp ah,0x10        ;ver 1.x
>    jne ver20
>    mov word[bsiz],0x1a
> ver20:
>    cmp ah,0x20        ;ver 2.0
>    jne ver21
>    mov word[bsiz],0x1e
> ver21:
>    cmp ah,0x21        ;ver 2.1
>    jne ver30
>    mov word[bsiz],0x1e
> ver30:
>    cmp ah,0x30        ;ver 3.0
>    jne ckbsiz
>    mov word[bsiz],0x42
> ckbsiz:
>    cmp word[bsiz],0
>    jne ah41
>    mov si,noext        ;no int 13h ext
>    call print_string
>    jmp nend        ;w/o bsiz we're going nowhere
> ah41:

Depending on how you look at it, the above
code is missing some 'jmp's or in the case
I show below, has way too many :-)

First, in the code above, even after you put the
correct value into [bsiz], you still cmp ah for
each additional check.  No problem, except that
it is slower code and larger code.  How about
something like this:

    mov word[bsiz],0x1a
    cmp ah,0x10        ;ver 1.x
    je  ah41
    mov word[bsiz],0x1e
    cmp ah,0x20        ;ver 2.0
    je  ah41
 ;   mov word[bsiz],0x1e
    cmp ah,0x21        ;ver 2.1
    je  ah41
    mov word[bsiz],0x42
    cmp ah,0x30        ;ver 3.0
    je  ah41
    mov si,noext        ;no int 13h ext
    call print_string
    jmp nend        ;w/o bsiz we're going nowhere
 ah41:

Less code, fewer jumps.

>    mov si,ahmsg41    ;ah =
>    call print_string
>    mov bx,i2xt
>    mov cx,2        ;cx = # of digits to translate
>    call b2xa
> api:
>    mov si,apimsg    ;'api = '
>    call print_string
>    pop ax        ;this is pushed cx
>    xlat            ;table result in al, bx already points i2xt
>    mov ah,0xe
>    int 0x10        ;write

Also as Mike said, bh should be zero before the
interrupt call above.

> ah48:
>    mov si, msg48    ;display BIOS call
>    call print_string
>    clc            ;clear CF
>    mov si,sxbuf        ;bufr for BIOS to fill
>    mov di,word[bsiz]
>    mov [sxbuf],di     ;bufr size for BIOS call
>    mov ah,0x48
>    mov dl,0x80        ;bit 7 = hd
>    int 0x13


>    jc cf1
>    mov si, cfzro
>    call print_string
>    jmp ah48m
> cf1:
>    mov si, cfone
>    call print_string
> ah48m:

Again, the 'mov' instruction does not modify the
flags register, so you can do a mov before the
carry check:

    mov si, cfone
    jc cf1
    mov si, cfzro
 cf1:
    call print_string
; less code, fewer jumps


>    mov si,ahmsg48     ;'ah='
>    call print_string
>    mov cx,2        ;cx = # of digits to translate
>    call b2xa
> dsxinfo:
>    mov si, sxmsg    ;'hex # sectors = '
>    call print_string
>    mov di,0x16        ;start w/bytes 0x16 & 0x17
> get4digit:
>    mov cx,4        ;cx counts 4 nibbles/word
>    mov ax,[sxbuf+di]
> outdigit:
>    rol ax,4        ;put hi hex digit on right
>    push ax        ;save rol'd ax
>    and al,0x0f        ;digit in al, is index into i2xt
>    xlat            ;table result in al
>    mov ah,0xe
     xor bh,bh
>    int 0x10        ;write
>    pop ax        ;rol'd version of ax
>    dec cx
>    jnz outdigit        ;4 digit loop - 1 nibble/loop
>    dec di
>    dec di
>    cmp di,0xe        ;end w/bytes 0x10 & 0x11
>    jnz get4digit    ;get next 4 hex digits
> nend:
>    mov si, tstamp    ;date & time (manual)
>    call print_string
>    jmp $        ;jmp here infinite loop
>
> msg41      db 0xd,0xa,'int 13h, ah=41h', 0xd, 0xa, 0
> msg48      db 0xd,0xa,'int 13h, ah=48h', 0xd, 0xa, 0
> ahmsg41  db 'ah = ', 0
> noext     db '   no int 13h ext', 0
> apimsg   db '   api = ', 0
> cfzro    db 'CF=0=success.', 0xd, 0xa, 0
> cfone    db 'CF=1=failed.', 0xd, 0xa, 0
> ahmsg48  db 'ah>0 is an error code. ah = ', 0
> sxmsg     db  0xd, 0xa ,'# of sectors = ', 0
> tstamp     db  0xd, 0xa ,'4/08/16  7:00 am', 0
> i2xt     db '0123456789ABCDEF'
> bsiz       dw 0
> sxbuf times 0x42 db 0  ;bufr for BIOS to fill
>  ; ===============================================================
>  ;             calls start here
>  ; ===============================================================
>
> print_string:
>    push ax        ;preserve ax
> .lup:
>    lodsb            ; grab a byte from si
>    or al, al          ; logical or al by itself
>    jz .done           ; if the result is zero, get out
>    mov ah, 0xe
>    int 0x10         ; otherwise, print out the character!
>    jmp .lup
>  .done:
>    pop ax        ;preserve ax
>    ret
>
> b2xa:            ;ax has data, cx has # nibs to translate
>    rol ax,4        ;put hi hex digit on right
>    push ax        ;rol'd version
>    and al,0x0f        ;digit in al, is index into i2xt
>    xlat            ;table result in al, bx already points i2xt
>    mov ah,0xe
>    int 0x10        ;write
>    pop ax
>    dec cx
>    jnz b2xa
>    ret
>
>    times 510-($-$$) db 0
>    dw 0xAA55
> </code>

I didn't go through it with as much detail, but it does
look better.  Good job.  Isn't learning fun :-)

Ben

[toc] | [prev] | [next] | [standalone]


#9433 — Re: THANKS FOR INFO & SUGGESTIONS

Frombilsch <king621@comcast.net>
Date2016-04-13 17:30 -0700
SubjectRe: THANKS FOR INFO & SUGGESTIONS
Message-ID<nemo4f$j4c$1@dont-email.me>
In reply to#9419
>>     mov si,msg41
>>     call print_string
>>     mov bx,0x55aa
>>     mov dl,0x80
>
> ; As Mike noted, DL is passed to your code.
>       mov  [saved_dl],dl
> ; and comment out the line you used above,
> ;  being sure not to modify DL beforehand.


I don't understand this comment.  Ralph Brown shows dl is a value that 
you must provide when calling int13 ah=41 bx=55aa. dl can't contain the 
drive number BEFORE I call int13.  Also RBIL doesn't show dl as a 
returned value.

[toc] | [prev] | [next] | [standalone]


#9434 — Re: THANKS FOR INFO & SUGGESTIONS

FromRod Pemberton <NoHaveNotOne@bcczxcfre.cmm>
Date2016-04-13 22:09 -0400
SubjectRe: THANKS FOR INFO & SUGGESTIONS
Message-ID<20160413220915.344a543a@_>
In reply to#9433
On Wed, 13 Apr 2016 17:30:12 -0700
bilsch <king621@comcast.net> wrote:

> >>     mov si,msg41
> >>     call print_string
> >>     mov bx,0x55aa
> >>     mov dl,0x80  
> >
> > ; As Mike noted, DL is passed to your code.
> >       mov  [saved_dl],dl
> > ; and comment out the line you used above,
> > ;  being sure not to modify DL beforehand.  
> 
> 
> I don't understand this comment.  Ralph Brown shows dl is a value
> that you must provide when calling int13 ah=41 bx=55aa. dl can't
> contain the drive number BEFORE I call int13.  Also RBIL doesn't show
> dl as a returned value.

7C00 start up code is called from Int 19h
with some entry values set in registers.
RBIL documents some of them.

7C00 entry values
http://www.delorie.com/djgpp/doc/rbinter/it/53/6.html

INT 19
http://www.delorie.com/djgpp/doc/rbinter/id/79/22.html

INT 18
http://www.delorie.com/djgpp/doc/rbinter/id/50/22.html

Additional values were added per later BIOS and drive
specifications and are not documented by RBIL.  Later
specifications also changed boot order to include
INT 18h.  None of that is in RBIL.

I don't recall where those are at the moment, perhaps
Phoenix EDD specifications or maybe IDE or maybe BIOS
Boot specification or maybe PCI specifications.  I can
look up my old posts or this info if you need it.

Ben or someone else might recall.


Rod Pemberton

[toc] | [prev] | [next] | [standalone]


#9422 — Re: THANKS FOR INFO & SUGGESTIONS

From"wolfgang kern" <nowhere@never.at>
Date2016-04-10 11:02 +0200
SubjectRe: THANKS FOR INFO & SUGGESTIONS
Message-ID<ned4qn$6ov$1@gioia.aioe.org>
In reply to#9416
bilsch posted:

[about]

seems you are on the right track yet, well done so far.

Ben already showed you possible shorter code solutions,
and here is what I'd do to save some more bytes:

I commented out ~175 bytes and added ~ 75.
Hope that I didn't make too many typos here ;)

__
wolfgang 

> <code>
> org 0x7c00
> bits 16
> SECTION .text
> 
>    xor ax,ax      ; set up segments
>    mov ds, ax
>    mov es, ax
>    mov ss, ax     ; setup stack
>    mov sp, 0x7c00 ; stack grows downwards from 0x7c00
> 
>    mov si,msg41
>    call print_string
>    mov bx,0x55aa
>    mov dl,0x80
>    mov ah,0x41
>    int 0x13

*    jc errr              ;could be not supported  
*    mov bx,0x7e00        ;points to your buffer now

>    push cx
>    cmp ah,0x10          ;ver 1.x
*    mov al,0x1a
*    je ah41

;> jne ver20
;> mov word[bsiz],0x1a
;> ver20:

>    cmp ah,0x20          ;ver 2.0
* ver21:
*    mov al,0x1e   
*    je ah41

;> jne ver21
;> mov word[bsiz],0x1e
;> ver21:

>    cmp ah,0x21          ;ver 2.1
*    je ver21 

;>    jne ver30
;>    mov word[bsiz],0x1e
;> ver30:

>    cmp ah,0x30          ;ver 3.0
*    mov al,0x42 
*    je ah41       

;>    jne ckbsiz
;>    mov word[bsiz],0x42
;> ckbsiz:
;>    cmp word[bsiz],0
;>    jne ah41

errr:
>    mov si,noext         ;no int 13h ext
>    call print_string
>    jmp nend             ;w/o bsiz we're going nowhere

> ah41:

*    mov word[bsiz],al
>    mov si,ahmsg41       ;ah =
>    call print_string

;> mov bx,i2xt
;> mov cx,2               ;cx = # of digits to translate
;> call b2xa

*    call hex2ah           ;AH 2 hex digits

Yeah, nibble based hex-print routines are fine.  
But the XLAT method isn't short nor fast, I use eax/ebx 
(you can use it too also within 16-bit code) to hold up 
to 8 nibbles for hex dwords display, but see below.

> api:
>    mov si,apimsg      ;'api = '
>    call print_string
>    pop ax             ;this is pushed cx

good, it works even it assumes that the pushed CL < 0x10 !

;>    xlat              ;table result in al, bx already points i2xt
;>    mov ah,0xe
;>    int 0x10          ;write

*     call hex1al       ;use only low nibble of AL

> ah48:
>    mov si, msg48      ;display BIOS call
>    call print_string
>    clc                ;clear CF

;>    mov si,sxbuf       ;bufr for BIOS to fill
>    mov di,word[bsiz]
;>    mov [sxbuf],di     ;bufr size for BIOS call
*    mov [bx],di 

>    mov ah,0x48
>    mov dl,0x80        ;bit 7 = hd
>    int 0x13

*    mov si, cfone
>    jc cf1
>    mov si, cfzro
* cf1:
>    call print_string

;>    jmp ah48m
;>cf1:
;> mov si, cfone
;> call print_string
;>ah48m:

>    mov si,ahmsg48     ;'ah='
>    call print_string
;>    mov cx,2          ;cx = # of digits to translate
;>    call b2xa

*    call hex2ah        ;AH

> dsxinfo:
>    mov si, sxmsg      ;'hex # sectors = '
>    call print_string
>    mov di,0x16        ;start w/bytes 0x16 & 0x17
> get4digit:

;>    mov cx,4           ;cx counts 4 nibbles/word
;>    mov ax,[sxbuf+di]

*   mov ax,[bx+di]
*   call hex4ax          ;four nibbles

;> outdigit:
;>    rol ax,4           ;put hi hex digit on right
;>    push ax            ;save rol'd ax
;>    and al,0x0f        ;digit in al, is index into i2xt
;>    xlat               ;table result in al
;>    mov ah,0xe
;>    int 0x10           ;write
;>    pop ax             ;rol'd version of ax
;>    dec cx
;>    jnz outdigit       ;4 digit loop - 1 nibble/loop

>    dec di
>    dec di
>    cmp di,0xe         ;end w/bytes 0x10 & 0x11
>    jnz get4digit      ;get next 4 hex digits

Have you got a reason to show it topdown ?  :)

> nend:
>    mov si, tstamp    ;date & time (manual)
>    call print_string
>    jmp $        ;jmp here infinite loop
 
> msg41      db 0xd,0xa,'int 13h, ah=41h', 0xd, 0xa, 0
> msg48      db 0xd,0xa,'int 13h, ah=48h', 0xd, 0xa, 0
> ahmsg41  db 'ah = ', 0
> noext     db '   no int 13h ext', 0
> apimsg   db '   api = ', 0
> cfzro    db 'CF=0=success.', 0xd, 0xa, 0
> cfone    db 'CF=1=failed.', 0xd, 0xa, 0
> ahmsg48  db 'ah>0 is an error code. ah = ', 0
> sxmsg     db  0xd, 0xa ,'# of sectors = ', 0
> tstamp     db  0xd, 0xa ,'4/08/16  7:00 am', 0

;> i2xt     db '0123456789ABCDEF'
> bsiz       dw 0
;> sxbuf times 0x42 db 0  ;bufr for BIOS to fill

I'd assign this buffer outside see: mov bx,0x7e00 above

>  ; ===============================================================
>  ;             calls start here
>  ; ===============================================================
> 
> print_string:
>    push ax          ;preserve ax
> .lup:
>    lodsb            ; grab a byte from si
>    or al, al        ; logical or al by itself
>    jz .done         ; if the result is zero, get out
>    mov ah, 0xe
>    int 0x10         ; otherwise, print out the character!
>    jmp .lup
>  .done:
>    pop ax           ;preserve ax
>    ret
 
;> b2xa:              ;ax has data, cx has # nibs to translate
;>    rol ax,4        ;put hi hex digit on right
;>    push ax         ;rol'd version
;>    and al,0x0f        ;digit in al, is index into i2xt
;>    xlat            ;table result in al, bx already points i2xt
;>    mov ah,0xe
;>    int 0x10        ;write
;>    pop ax
;>    dec cx
;>    jnz b2xa
;>    ret

hex4ax:               ;4 nibbles from ax
  push ax
  call hex2ah
  pop ax
  shl ax,8
hex2ah:               ;2 digits of AH
  mov al,ah
  shr al,4            ;high part first
  call hex1al
  mov al,ah 
hex1al:               ;a single nibble from AL
  push ax
  and al,0x0f
  cmp al,0x0a
  jc hex1
  add al,0x07
hex1:
  add al,0x30          
  mov ah 0x0e
  mov bh,0 
  int 0x10
  pop ax
  ret

;-------
my own routine:  
it always uses ebx and need to be preceded by MOVZX ebx,ah 
for AH only, but it terminates 'automated' w/o size info.

hexout:             
  mov eax,ebx
  ror eax,4        ;start with MSD
  and al,0x0f
  cmp al,0x0a
  jc itsnum        ;skip next instruction 
  add al,0x07      ;if > 9 then 'A..F' 
itsnum:
  add al,0x30      ;make it ASCII
  call charout     ;I don't use the BIOS here 
  shl ebx,4      
  jnz hexout       ;until nothing else to print
 ret  
;--------

> 
>    times 510-($-$$) db 0
>    dw 0xAA55
> </code> 

[toc] | [prev] | [next] | [standalone]


#9423 — Re: THANKS FOR INFO & SUGGESTIONS

From"wolfgang kern" <nowhere@never.at>
Date2016-04-10 13:31 +0200
SubjectRe: THANKS FOR INFO & SUGGESTIONS
Message-ID<neddj0$kp4$1@gioia.aioe.org>
In reply to#9422
I wrote:

and forgot to restore BX to 0x7e00 after the BIOS call !

> hex4ax:               ;4 nibbles from ax
>  push ax
>  call hex2ah
>  pop ax
>  shl ax,8
> hex2ah:               ;2 digits of AH
>  mov al,ah
>  shr al,4            ;high part first
>  call hex1al
>  mov al,ah 
> hex1al:               ;a single nibble from AL
>  push ax
>  and al,0x0f
>  cmp al,0x0a
>  jc hex1
>  add al,0x07
> hex1:
>  add al,0x30          
>  mov ah 0x0e
>  mov bh,0 
>  int 0x10
*  mov bx,0x7e00        ;restore buf-ptr
>  pop ax
>  ret

__
wolfgang 

[toc] | [prev] | [next] | [standalone]


#9412

FromRod Pemberton <NoHaveNotOne@bcczxcfre.cmm>
Date2016-04-06 00:10 -0400
Message-ID<20160406001011.196bfc80@_>
In reply to#9403
On Tue, 5 Apr 2016 05:34:50 -0700
bilsch <king621@comcast.net> wrote:

> First, good news: I revised the program (see listing below), and for
> the first time ah=0x48 returns CF=0 (success) and ah=0.

Congratulations!

Did you find out the issue with the earlier code? ...

> But the number of sectors doesn't work out right.
> It says EAB025420000FFFF.

Ben made a comment on your print routines being backwards.

I'm assuming that this value is word correct, but
the QWORD word order is reversed, because things seem
to work out below ...

Technically, then, assuming EAB025420000FFFF is word
correct but the QWORD word order is reversed, then the
byte order is B0 EA 42 25 00 00 FF FF.  So, the QWORD
value is FFFF00002542EAB0.

> Backwards EAB02542 is 24520BAE is 609356718 decimal,
> times 512 is 311,990,639,616 bytes. But that doesn't
> take little endian into account.  GPARTED says
> 320,071,700,616 bytes.

"24520BAE" is "incorrectly" reversed from EAB02542.

24520BAE is EAB02542 reversed by nybbles (4-bits).
4225B0EA is EAB02542 reversed by bytes (8-bits).
2542EAB0 is EAB02542 reversed by words (16-bits).

I think you want the last value since your code gets AX.

2542EAB0 is 625142448 in decimal which times 512 gives
320,072,933,376.  That is only slightly more than the
320,071,700,616 which GPARTED reported.

Some programs use 1000 instead of 1024 for a KB (kilobyte).
This is especially true for programs which report disk
capacity since manufacturers do that.  It would seem that
GPARTED is using 500 here instead of 512.  I.e., the
value 311,990,639,616 from GPARTED divided by 625,142,448
(2542EAB0 in hex) gives 499 ...

I'll let you track down the off-by-one discrepancy between
499 and 500, which should be around 7.5GB to 8GB on a 300GB
to 320GB drive.  If using GPARTED, i.e., Linux etc., maybe
check 'fdisk -l' for the reported device capacity.

> [snip]
>
>     mov bx,i2xt
>     xor cx,cx		;cx counts to 1
>     pop ax
> lup1:			;here ax is data from ah=0x41
>     rol ax,4		;put hi hex digit on right
>     push ax		;rol'd version
>     and al,0x0f		;digit in al, is index into i2xt
>     xlat			;table result in al, bx already
> points i2xt mov ah,0xe			
>     int 0x10		;write
>     pop ax
>     cmp cx,1
>     je api		;cx=1 then done w/ah
>     inc cx
>     jmp lup1

You rolled your own hex routine.  That's a good start.
Is it your first?  There is usually a virtual round
of applause for your first one on x86!  (clap! clap!)

There are many other ways to do hex for x86, including
some which are faster (larger) and some that are much
shorter.  E.g., some simply add a value to a nybble,
IIRC 0x30, then compare and add seven for the upper
hex digits 'A' to 'F'.  This eliminates the need for
the 'xlat' table.  It might be a few bytes shorter.
IIRC, some routines use one of the BCD instructions
(AAA, AAD, AAM, AAS, DAA, DAS) to unpack nybbles.
It might be the AAA instruction ...


Rod Pemberton

[toc] | [prev] | [standalone]


Back to top | Article view | alt.os.development


csiph-web