Hi,
I have got a code related to memory map. I have not understood everything of this code. But thing which hindering me is that its using 32 bit registers. Should I have to switch to protected mode?
; use the INT 0x15, eax= 0xE820 BIOS function to get a memory map
; inputs: es:di -> destination buffer for 24 byte entries
; outputs: bp = entry count, trashes all registers except esi
do_e820:
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx, 0x0534D4150 ; Place "SMAP" into edx
mov eax, 0xe820
mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes
int 0x15
jc short .failed ; carry set on first call means "unsupported function"
mov edx, 0x0534D4150 ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short .failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short .failed
jmp short .jmpin
.e820lp:
mov eax, 0xe820 ; eax, ecx get trashed on every int 0x15 call
mov [es:di + 20], dword 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes again
int 0x15
jc short .e820f ; carry set means "end of list already reached"
mov edx, 0x0534D4150 ; repair potentially trashed register
.jmpin:
jcxz .skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short .notext
test byte [es:di + 20], 1 ; if so: is the "ignore this data" bit clear?
je short .skipent
.notext:
mov ecx, [es:di + 8] ; get lower dword of memory region length
test ecx, ecx ; is the qword == 0?
jne short .goodent
mov ecx, [es:di + 12] ; get upper dword of memory region length
jecxz .skipent ; if length qword is 0, skip entry
.goodent:
inc bp ; got a good entry: ++count, move to next storage spot
add di, 24
.skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
jne short .e820lp
.e820f:
mov [mmap_ent], bp ; store the entry count
ret ; test opcode cleared carry flag
.failed:
stc ; "function unsupported" error exit
ret
Zulfi.
no - in fact, i don't think it will work in protected mode
from what i understand, to use 32-bit registers in real mode, all you should need is....
.386
(or higher) after the model directive
Remember that when running anything this low-level within a DOS Box under Windows NT, always take the output with a grain of salt. I'm fairly certain NTVDM doesn't support this particular INT 15 call, so ensure you run this in 'real' real mode
-r
Hi,
As Dave says you can use 32 bit instructions in real mode.
You have to make sure that the assembler knows to be in 16-bit
mode or the default instruction mode will be incorrect. I Think
Dave and MichaelW have posted posted code that shows how
to do this.
When you are in protected mode interrupts work differently
than when in real mode. If that has not been set up correctly,
it will not work. Also BIOS code is 16-bit and a lot of examples
of setting up protected mode also set up the 32-bit execution
mode.
Regards,
Steve N.
i think he is reading Ralf
if i recall, it was E820h where Ralf said some BIOS's expect the high word of eax to be 0
Hi,
I got it from OSDev Wiki & topic is "Detecting Memory (x86)". There is no author name.
mov [mmap_ent], bp ; store the entry count
Should I declare the mmap_ent as:
mmap_ent db 0
How can I use it for indirect addressing ?
Zulfi.
those guys over there use NASM, mostly
for MASM, you can use
mov mmap_ent,bp ; store the entry count
but, BP is a word register, so mmap_ent should be a word
mmap_ent dw ?
Thanks for removing this confusion. I really appreciate your replies. Its very good forum. Replies come immediately.
Zulfi.
Hi,
Can somebody plz guide me with this statement:
mov [es:di + 20], dword 1
I am getting following error:
sect8_2.asm(277) : error A2032: invalid use of register
Zulfi.
try this
mov dword ptr es:[di+20],1
not sure if that will work in 16-bit mode - if not, you'll have to split it up
mov word ptr es:[di+20],1
mov word ptr es:[di+22],0
Hi,
Thanks. In this code they have not specified the declaration for the buffer of the list pointed by ES:DI. Should I declare it as:
buffer db ?
and then point ES:DI towards it using following code:
push es
push cs
pop es
mov di, offset buffer+LoadOfs
What is the function of bp?
xor bp, bp ; keep an entry count in bp
I cant understand this entry count?
I want to first print this qword Base address. The loop counter should be set to 64??
Kindly somebody guide me with this.
Zulfi.
Hi,
Quote
What is the function of bp?
Code:
xor bp, bp ; keep an entry count in bp
I cant understand this entry count?
A call to Int 15H Fn E820 returns information about a memory
block. You supply a buffer for the BIOS to fill with this information.
This code snippet calls this an "entry". BP is a count of the memory
blocks in that computer. You call the BIOS Int 15H more than once
to get a map of the memory.
Regards,
Steve
the buffer needs to be large enough to hold all the entries
the problem is, you do not know how many entries there will be on any given computer - lol
but, you are in luck :bg
you are only interested in the last entry
if i remember, it is 20 bytes per entry
just use the same 20 bytes over and over
when the function tells you there are no more entries, you will have the one you want in the buffer
Hi,
Thanks for the reply.
Quote
BP is a count of the memory
blocks in that computer.
But these blocks can be of different sizes (qword or dword) and some of them can be filled and some are unused???
Should I declare the buffer as 'qword'? I want to do it in steps. First I want to print the Base address which is of 'qword' size.
Zulfi.
you could define a structure
have a look at Steve's memory map code to see how it is done (i think he did it that way :P )
something like this...
MMap_Descriptor STRUCT
BaseAddress_Lo dd ?
BaseAddress_Hi dd ?
ByteLength_Lo dd ?
ByteLength_Hi dd ?
RangeType dd ?
MMap_Descriptor ENDS
now, MMap_Descriptor is a new data type
MMap_Table MMAP_Descriptor <>
now, you have a structure named MMap_Table of the type MMap_Descriptor
you can access one of the elements like this
mov eax,MMap_Table.ByteLength_Lo
Thanks. I never worked on structures in Assembly language but your example shows that its not difficult.
I cant understand following fields:
ByteLength_Lo dd ?
ByteLength_Hi dd ?
RangeType dd ?
BaseAddress is clear to me.
Zulfi.
Hi,
According to that Article :
Quoteincrement DI by your list entry size:
The structure which you told me is of 80 bytes. Should I increase DI by 80 bytes for next call?
Should I have one more dd field in the structure for ACPI 3.0 Extended Attributes bitfield??
From this structure it seems that each time I invoke int 15h I would get a base address of a region.
Kindly somebody guide me with this.
Zulfi.
Hi,
QuoteI cant understand following fields:
ByteLength_Lo dd ?
MMap_Descriptor STRUCT
BaseAddress_Lo dd ?
BaseAddress_Hi dd ?
ByteLength_Lo dd ?
ByteLength_Hi dd ?
RangeType dd ?
MMap_Descriptor ENDS
This corresponds to the description in the article.
Quote
* First qword = Base address
* Second qword = Length of "region" (if this value is 0, ignore the entry)
* Next dword = Region "type"
o Type 1: Usable (normal) RAM
o Type 2: Reserved - unusable
o Type 3: ACPI reclaimable memory
o Type 4: ACPI NVS memory
o Type 5: Area containing bad memory
* Next dword = ACPI 3.0 Extended Attributes bitfield (if 24 bytes are
returned, instead of 20)
So if I rearrange things a bit, it becomes:
MMap_Descriptor STRUCT
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DD ? ; * Next dword = Region "type"
ACPI_Attrib DD ? ; * Next dword = ACPI 3.0 Extended Attri
MMap_Descriptor ENDS
(I added a record for the attributes like you mentioned.)
So Dave showed you the structure using DWORD sized fields,
which is a bit easier when programming 32-bit code.
Quote
The structure which you told me is of 80 bytes. Should I increase DI by 80 bytes for next call?
Actually what Dave showed you was 20 bytes, five
DWORDS. The one I just showed was 24 bytes. So
you would declare multiple structures and increment for
each new call, or reuse the first one each time.
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
HTH,
Steve N.
Thanks. Very good explanations by you people. Will these five variables be enough to check the entire memory or I may need more?
Zulfi.
Hi,
Different computers will have different numbers of blocks.
In the other thread with MichaelW's software, the examples
posted showed two with six blocks and one with four. And
there should be another to show the end block. Five was
just an example showing the allocation of structures. They
are not all that big, so starting with ten or sixteen won't hurt
much. MichaelW seems to reuse just one in a loop. (If I
read his program correctly.)
Regards,
Steve
Very Good. I must do some programming now. And inform you people about the results.
Zulfi.
Hi,
I want to print this base address once its stored in the structure i.e I want to print the following field:
BaseAddress DQ ?
Can somebody guide me in this regard?
Zulfi.
Hi,
I am putting my code for memory map but still I dont have any clue to display the base address:
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry
mov ecx, 24 ; ask for 24 bytes
int 15h
jc short failed ; carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short failed
jmp short jmpin
jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short skipent
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
je short skipent
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
jne short e820f
mov ah,0
mov end_of_list, ah
e820f:
mov mmap_ent, bp ; store the entry count
pop es
ret
failed:
stc ; "function unsupported" error exit
ret
displayBaseAddress:
ret
Can somebody help me with displaying the base address??
Zulfi.
Zulfi
this routine will convert it to a zero-terminated ASCII string
use the display routine we have used before to display it
;-----------------------------------------------------------------------
Qw2Hex PROC NEAR
;convert a QWORD from a memory location to ASCIIZ hexidecimal string
;Call With: DS:SI = address of binary QWORD input value
; DS:DI = address of 17-byte ASCII buffer
push ax
push cx
push si
push di
mov cx,8
add si,7
Qw2Hx0: mov al,[si]
dec si
mov ah,al
shr al,1
shr al,1
shr al,1
shr al,1
cmp al,0Ah
sbb al,69h
das
mov [di],al
inc di
mov al,ah
and al,0Fh
cmp al,0Ah
sbb al,69h
das
mov [di],al
inc di
dec cx
jnz Qw2Hx0
mov [di],cl
pop di
pop si
pop cx
pop ax
ret
Qw2Hex ENDP
;-----------------------------------------------------------------------
EDIT - fixed a typo
jnz Qw2Hx0
Thanks . I would try this.
Zulfi.
this version is probably better, Zulfi
it can be used for smaller integers, as well
you have to tell it how many binary bytes to convert in CX
mov si,offset BinaryValue
mov di,offset AsciiBuffer
mov cx,sizeof BinaryValue
call MB2Hex
;-------------------------------------------------------------------------------
MB2Hex PROC NEAR
;convert a multi-byte binary from a memory location to ASCIIZ hexidecimal string
;Call With: DS:SI = address of binary input value
; DS:DI = address of ASCII buffer (minimum length = 2 x CX + 1)
; CX = number of binary input bytes to convert
push ax
push cx
push di
add si,cx
MB2Hx0: dec si
mov al,[si]
mov ah,al
shr al,1
shr al,1
shr al,1
shr al,1
cmp al,0Ah
sbb al,69h
das
mov [di],al
inc di
mov al,ah
and al,0Fh
cmp al,0Ah
sbb al,69h
das
mov [di],al
inc di
dec cx
jnz MB2Hx0
mov [di],cl
pop di
pop cx
pop ax
ret
MB2Hex ENDP
;-------------------------------------------------------------------------------
Hi,
Cough. Dave beat me to it. Twice. Oh well, here is my
version anyway. Why waste typing effort?
Regards,
Steve
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Call with DS:SI pointing to a QWORD (eight bytes) to be
; displayed as hexadecimal.
QW2Hex$:
PUSH SI ; Save registers used by routine.
PUSH AX
PUSH CX
STD ; String instructions decrement.
ADD SI,7 ; Point to last byte, (Intel big end).
MOV CX,8 ; Number of bytes to print.
QW_1:
LODSB ; Get a byte.
CALL TOASCII ; Display as hex.
LOOP QW_1
CLD ; Restore default.
POP CX
POP AX
POP SI
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
CALL ConOutByte
POP DX
POP AX
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Hi,
Fine. I actually tried Dave's work last night but it didnt work. I would try your's now.Its very good to get these 2 different versions. I would try to understand them as its difficult to understand Assembly programs without the help of an alg.
Zulfi.
the first one had a typo in it, Zulfi - i fixed it
here is a little demo program using the multi-byte version...
Hi Steve,
Quote
Call with DS:SI pointing to a QWORD (eight bytes) to be
; displayed as hexadecimal.
Thanks for your code. I have one prob. which is stated in the comment. In my code, ES:DI points to the QWORD which is natural after executing 15h. This comment means I cant use your code.
Hi Dave,
Thanks for your help. I was able to compile your program. I would check your updated version some time maybe tomorrow.
I appreciate your consistent help in solving my problems.
Zulfi.
it's kind of fun Zulfi
i get to keep my hand in 16-bit code so i don't forget it all - lol
but, you should try to understand the code we provide - learn from it
it would be great to see you post good code you have written yourself :bg
Quote from: zak100 on March 08, 2010, 06:49:30 PM
quote
Call with DS:SI pointing to a QWORD (eight bytes) to be
; displayed as hexadecimal.
/quote
Thanks for your code. I have one prob. which is stated in the comment. In my code, ES:DI points to the QWORD which is natural after executing 15h. This comment means I cant use your code.
Hi Zulfi,
Try changing:
LODSB ; Get a byte.
To something like:
MOV AL,ES:[DI] ; Get a byte
DEC DI
And PUSH/POP DI instead of SI. That _should_ work.
It is handy to use LODSB, which defaults to DS:SI.
Regards,
Steve
you could also fix it by moving segment values around in the segment registers by using push and pop
Hi,
I would try. Thanks for guidance and encouragement.
Zulfi.
Hi,
What is the purpose of this DB?
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
Zulfi.
0D4h,0Ah is the opcode for the AAM instruction (ASCII adjust multiply)
it essentially divides the value in AL by 10 and places the quotient in AH and the remainder in AL
by modifying the opcode to 0D4h,10h, we can alter the AAM instruction to divide by 16 instead of 10
so, it splits the lower 4 bits from the upper 4 bits
it is an "undocumented" opcode that has worked since the 8088 - intel and amd have always supported it in new CPUs
it saves some code because it is small
AAM is not a particularly fast instruction, though
on pentiums it is about 18 clock cycles - a mov/shift/and combination is probably slightly faster
on the 8088, it was 84 clock cycles if i remember correctly
if you want speed, code it the other way
if you want small size, use AAM :bg
Zulfi,
DB is a data definition directive that allocates one or more unsigned bytes. It's the same directive that you would use in the data segment, but here it is used in the code segment to "synthesize" a form of the AAM instruction that behaves differently than the normal form. You can walk through it in DEBUG to see how it behaves:
-a
0B10:0100 mov al, 63 ; load 99d into AL
0B10:0102 aam ; convert to unpacked BCD in AX
0B10:0104 mov al, 63 ; load 99d into AL
0B10:0106 db d4 10 ; convert to unpacked BCH in AX
0B10:0108 nop ; this is just a filler
0B10:0109
-r
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B10 ES=0B10 SS=0B10 CS=0B10 IP=0100 NV UP EI PL NZ NA PO NC
0B10:0100 B063 MOV AL,63
-t 4
AX=0063 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B10 ES=0B10 SS=0B10 CS=0B10 IP=0102 NV UP EI PL NZ NA PO NC
0B10:0102 D40A AAM
AX=0909 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B10 ES=0B10 SS=0B10 CS=0B10 IP=0104 NV UP EI PL NZ NA PE NC
0B10:0104 B063 MOV AL,63
AX=0963 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B10 ES=0B10 SS=0B10 CS=0B10 IP=0106 NV UP EI PL NZ NA PE NC
0B10:0106 D410 AAM 10
AX=0603 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=0B10 ES=0B10 SS=0B10 CS=0B10 IP=0108 NV UP EI PL NZ NA PE NC
0B10:0108 90 NOP
-q
Note that I added the comments after I captured the output. Also note that I labeled the output for the second form as BCH (Binary-Coded Hex) for want of a better term.
Quote from: dedndave on March 09, 2010, 07:34:02 PM
...
it saves some code because it is small
AAM is not a particularly fast instruction, though
...
if you want speed, code it the other way
if you want small size, use AAM :bg
Hi,
I mostly wanted to show another way to do the job. And
if you are going to call DOS or BIOS to emit a character, the
speed is moot. I probably underdocumented it though.
Regards,
Steve N.
i was just trying to give Zulfi a heads up on using an undocumented opcode - lol
every now and then, he is likely to see some hard-coded instruction - good to know what it is
Hi,
I cant understand following set of instruction:
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
I have found that DAS subtract 6 or 60 h depending on the value of lower and upper nibble in AL.
What is the significance of 69H.
I need an example in this regard.
Thanks for helping me.
Zulfi.
the CMP AL,10h sets or clears the carry flag for the SBB instruction
the DAS instruction acts like this (copied from Randy Hyde's AoA)
if ( (al and 0Fh) > 9 or (AuxC = 1)) then
al := al -6
AuxC = 1
endif
if (al > 9Fh or Carry = 1) then
al := al - 60h
Carry := 1 ;Set the Carry flag
endif
so, there is no "magic", Zulfi - lol
in computers, there rarely is
microwave circuits - now, that's another subject :P
Thanks. Kindly say something about 69h also.
Zulfi.
; AL = 0 to 0Fh
cmp al,0Ah
sbb al,69h
das
; AL = ASCII hexidecimal
; initial AL CF after CMP AL after SBB AC after SBB AL after DAS
;
; 0 CY 96h AC 30h
; 1 CY 97h AC 31h
; 2 CY 98h AC 32h
; 3 CY 99h AC 33h
; 4 CY 9Ah AC 34h
; 5 CY 9Bh AC 35h
; 6 CY 9Ch AC 36h
; 7 CY 9Dh AC 37h
; 8 CY 9Eh AC 38h
; 9 CY 9Fh AC 39h
; 0Ah NC 0A1h NA 41h
; 0Bh NC 0A2h NA 42h
; 0Ch NC 0A3h NA 43h
; 0Dh NC 0A4h NA 44h
; 0Eh NC 0A5h NA 45h
; 0Fh NC 0A6h NA 46h
;
; in this code, the carry flag is always set after the SBB instruction
; the auxilliary carry flag is similar to carry, but applies to the lower nybble of the result
;
; DAS pseudo-code:
;
; if ( (al and 0Fh) > 9 or (AuxC = 1)) then
; al := al -6
; AuxC = 1
; endif
; if (al > 9Fh or Carry = 1) then
; al := al - 60h
; Carry := 1
; endif
Hi,
Sorry Zulfi, I probably should not have said "magic". But as
shown in my other posts, I have a defective sense of humor.
It probably should have said "This converts binary to ASCII,
but how this is done is too complex to fit in the margin". The
69H just happens to work with the CMP, SBB, and DAS sequence.
(And that appears to be magic until you work out how it really works.)
dedndave shows exactly how that works out in his last post. You
can walk through the code in DEBUG (or another debugger/emulator)
to see how it works for yourself.
Regards,
Steve
A:\>debug
-a
1673:0100 nop
1673:0102 cmp al,a
1673:0104 sbb al,69
1673:0106 das
1673:0107 jmp 100
1673:0109
-t4
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1673 ES=1673 SS=1673 CS=1673 IP=0102 NV UP EI PL ZR NA PE NC
1673:0102 3C0A CMP AL,0A
AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1673 ES=1673 SS=1673 CS=1673 IP=0104 NV UP EI NG NZ AC PE CY
1673:0104 1C69 SBB AL,69
AX=0096 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1673 ES=1673 SS=1673 CS=1673 IP=0106 NV UP EI NG NZ AC PE CY
1673:0106 2F DAS
AX=0030 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=1673 ES=1673 SS=1673 CS=1673 IP=0107 OV UP EI PL NZ AC PE CY
1673:0107 EBF7 JMP 0100
-rax
AX 0030
:9
-t5
Repeat as necessary!
Hi,
I think it should help me. Thanks for giving me so much time.
Zulfi.
Hi,
I am facing prob with DAS:
AL=AL-CF-69
AL=0-1-69
AL=0-6A
AL=96H using 2's complement
DAS:
if ((96H and 0FH) > 9 or (AUXC=1)) ----TRUE because AUXC =1
al=al-6
al= 96 -6
al=90h
At this point AL should be 30H instead of 90H.
Can somebody help me with this prob.
Zulfi.
; if ( (al and 0Fh) > 9 or (AuxC = 1)) then
; al := al -6
; AuxC = 1
; endif
; if (al > 9Fh or Carry = 1) then
; al := al - 60h
; Carry := 1
; endif
the last section subtracts another 60h
for this code, the carry flag is always set just prior to the DAS instruction
Ok. Thanks for your reply.
Zulfi.
Hi,
I have written the code and I now understand most of it but its not printing any new stuff i.e base address and length of region.
Following is the code:
;Declarations
arr db 10 dup(0)
VAL1 db 0
VAL2 db 0
AscBuf db 8 dup (0),' Kb Total Memory',0
mmap_ent dw ?
end_of_list db 1
MMap_Descriptor STRUCT
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DW ? ; * Next dword = Region "type"
ACPI_Attrib DW ? ; * Next dword = ACPI 3.0 Extended Attri
MMap_Descriptor ENDS
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
;Calling procedure
call do_e820_Step1
;procedure
;---------------do_e820_Step1
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry. This reqd to set last
;dword to 1 before each call
mov ecx, 24 ; ask for 24 bytes
int 15h
jc short failed ; carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short failed
;jmp short jmpin
;jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short skipent
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if the entire
; entry should be ignored
je short skipent
mov ecx, dword ptr es:[di+8]; get lower dword of memory region length
test ecx, ecx; ; is the qword=0????
jne short goodent
mov ecx, dword ptr es:[di+12];
jecxz skipent
goodent:
inc bp
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
je short e820f
next_call2:
call QW2Hex$ ;Displaying the base address
add di, 8 ;Length of region starts 15 bytes from current val
;In the procedure we adding 7 to di
call QW2Hex$ ;Displaying the length of region
add di, 24
e820f:
mov mmap_ent, bp ; store the entry count
pop es
ret
failed:
stc ; "function unsupported" error exit
pop es
ret
;----other procdures
;--------------------------------- By Steve
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Call with DS:SI pointing to a QWORD (eight bytes) to be
; displayed as hexadecimal. Not now. SI removed
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
STD ; String instructions decrement.
ADD DI,7 ; Point to last byte, (Intel big end).
mov si ,offset arr+LoadOfs
MOV CX,8 ; Number of bytes to print. QWORD = 8 bytes
;
QW_1:
MOV AL,ES:[DI] ; Get a byte
DEC DI
CALL TOASCII ; Display as hex.
mov dl, VAL1
mov [si], dl ; store the values in array and display array later
inc si
mov dl, VAL2
mov [si], dl
inc si
LOOP QW_1
;
;Displaying the array contents
mov ax,0B800h
mov es,ax
xor di,di
mov di,50h
mov cx,8
mov si,offset arr+LoadOfs
mov ah,1Fh
nextval: mov al, [si]
inc si
stosw ; <= You are automatically incrementing DI
loop nextval
CLD ; Restore default.
POP CX
POP AX
POP DI
RET
;---------------------------------------------------
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
mov VAL1, al
;CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
mov VAL2,al
; CALL ConOutByte
POP DX
POP AX
RET
Kindly some body help me with this.
Zulf.
Hi,
What environment are you using to test your program?
I see one piece where you have a typo from where I posted
some code and edited it later to fix it.
RangeType DD ? ; * Next dword = Region "type"
ACPI_Attrib DD ? ; * Next dword = ACPI 3.0 Extended Attri
Anyway I am using similar code to yours, and finally got it
working. I don't see much difference in the individual routines
between your code and mine, except for printing characters.
And formatting output.
Your posted code does not assemble for me. So the lack of
exit code and defining an entry point are problems to check on.
And I would use more than five of those descriptor structures
as my test machine is using seven of them.
Regards,
Steve N.
Hi,
Sorry for not posting a compilable version. I have shortened my code and its able to print:
70027002.
I am printing both the base address and region length. I dont know if its the correct value.
I am using a lable 'next_call2' at which point I am displaying the values by calling your routines.
Kindly check if its correct or not. Let me know where to add your two variables.
;//portion of memMap code from original file sect8_2.asm
;//for masm forum
;ml /c memMp2.asm
;link16 /tiny memMp2.obj,memMp2.bin;
;DEBUG Btl3p_3.BIN
;-w 100 0 0 1
;-q
;DEBUG memMp2.BIN
;-w 100 0 1 1
;-q
;DISPLAYING real Time using int 1AH
.MODEL TINY
.386
.CODE
;----------------------------------------------------------------------------------
LoadOfs EQU 0 ;must match the value in the bootloader source file
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
;---------------------- initialize ES segment register
ORG 0
Start: push cs
pop ds
;-----------clear screen
mov ax, 3
int 10h
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
xor di, di
mov ax, 0B800h
mov es, ax
mov si, offset msg0+LoadOfs
mov ah, 41h; attribute byte
cld;
msgloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
jz TimerMesg
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgloop
;---------------------- done - halt
TimerMesg:
xor di, di
mov ax, 0B820h
mov es, ax
mov si, offset msgA+LoadOfs
mov ah, 41h; attribute byte
cld;
msgAloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
;jz RTime
jz mem
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgAloop
mov cx, 1000
;DISPLAY_TIMER:
;-------------Find Total Memory
mem: cld
;call FindTotalMem ;calculate total memory (sets the SI register)
mov ah,7 ;display attribute
mov di,0 ;display position
;call Dsply ;display total memory
call do_e820_Step1
;call Qw2Hex by Dave (instead using code provided by Fortran or Steve)
Halt0: hlt
jmp Halt0
Msg0 db "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs db 0
cnt db 0; Its value represents the digits of Timer
s db 0; selector for secs minutes and hrs used in displayCnt
arr db 10 dup(0)
VAL1 db 0
VAL2 db 0
AscBuf db 8 dup (0),' Kb Total Memory',0
mmap_ent dw ?
end_of_list db 1
MMap_Descriptor STRUCT
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DW ? ; * Next dword = Region "type"
ACPI_Attrib DW ? ; * Next dword = ACPI 3.0 Extended Attri
MMap_Descriptor ENDS
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
;---------------do_e820_Step1
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry. This reqd to set last
;dword to 1 before each call
mov ecx, 24 ; ask for 24 bytes
int 15h
jc short failed ; carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short failed
;jmp short jmpin
;jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short skipent
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if the entire
; entry should be ignored
je short skipent
mov ecx, dword ptr es:[di+8]; get lower dword of memory region length
test ecx, ecx; ; is the qword=0????
jne short goodent
mov ecx, dword ptr es:[di+12];
jecxz skipent
goodent:
inc bp
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
je short e820f
next_call2:
call QW2Hex$ ;Displaying the base address <---------------
add di, 8 ;Length of region starts 15 bytes from current val
;In the procedure we adding 7 to di <-----------
call QW2Hex$ ;Displaying the length of region
add di, 24
e820f:
mov mmap_ent, bp ; store the entry count
pop es
ret
failed:
stc ; "function unsupported" error exit
pop es
ret
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
STD ; String instructions decrement.
ADD DI,7 ; Point to last byte, (Intel big end).
mov si ,offset arr+LoadOfs
MOV CX,8 ; Number of bytes to print. QWORD = 8 bytes
;
QW_1:
MOV AL,ES:[DI] ; Get a byte
DEC DI
CALL TOASCII ; Display as hex.
mov dl, VAL1
mov [si], dl ; store the values in array and display array later
inc si
mov dl, VAL2
mov [si], dl
inc si
LOOP QW_1
;
;Displaying the array contents
mov ax,0B800h
mov es,ax
xor di,di
mov di,50h
mov cx,8
mov si,offset arr+LoadOfs
mov ah,1Fh
nextval: mov al, [si]
inc si
stosw ; <= You are automatically incrementing DI
loop nextval
CLD ; Restore default.
POP CX
POP AX
POP DI
RET
;---------------------------------------------------
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
mov VAL1, al
;CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
mov VAL2,al
; CALL ConOutByte
POP DX
POP AX
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;----------------------------------------------------------------------------------
END Start
Zulfi.
Hi Zulfi,
Okay, I got it to work. I sure hope your machine boots
faster than mine if you need to reboot each time. I used
DEBUG to walk through the program. Anyway, some minimal
changes to your code.
PAGE ,132 ;## Added for better listing.
...
MMap_Descriptor STRUC ;## changed for older MASM, you can ignore.
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DD ? ; * Next dword = Region "type" ## change typo.
ACPI_Attrib DD ? ; * Next dword = ACPI 3.0 Extended Attri ## change typo.
MMap_Descriptor ENDS
...
call QW2Hex$ ;Displaying the base address <---------------
add di, 8 ;Length of region starts 15 bytes from current val
;## You are not pausing after showing the first value before showing the second.
;## And they both print at the same location on screen.
MOV AX,0 ;## Pause?
INT 16H
;In the procedure we adding 7 to di <-----------
call QW2Hex$ ;Displaying the length of region
...
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
PUSH ES ;## You are using ES then changing it to display the characters.
...
mov di,50h
mov cx,16 ;## 8 bytes will be 16 characters. And it comes out backwards...
mov si,offset arr+LoadOfs
...
POP ES ;##
POP CX
POP AX
POP DI
This got me the same values as MichaelW's and my code gave
on my computer. I may have missed something, but that was
most of what I did.
HTH,
Steve N.
Thanks Steve. I am little bit slow. I am interested in this. I am impressed by quick response from you people. I would try to get back on this as early as possible.
Zulfi.
Hi,
I am getting 16 0s as base address and following value as length of region:
7002700270027002
What does it mean??
Thanks for your help. I am still trying to print it using base:length of Region format (style).
Zulfi.
Hi,
When I got that value it meant that the ES register was
pointing to the wrong segment. It was pointing to the video
segment and not your data area. 20 hex is a space and
07H is the default background attribute.
Regards,
Steve
Hi,
Thanks for your attention. By wrong you mean that there is a technical error in my code ??
Quote
<<20 hex is a space and
07H is the default background attribute.>>
This means that the value printed is not the length of region.
Zulfi.
Hi,
QuoteBy wrong you mean that there is a technical error in my code ??
My post in reply 51 has eight pieces of code marked with ##.
Did you make all of those changes to your code? More changes
are _still_ needed, but that was the minimum to show the region
length data in some form. Actually two of the ## marked pieces
are sort of extra, but the rest are needed.
QuoteThis means that the value printed is not the length of region.
Exactly. The length of the region is stored in your program's data
by the BIOS. The 20072007H is in the video display memory. On my
computer the length printed out as 000000000009FC00, after reformatting
it. You should see something similar for the length on your computer.
Steve
Thanks for your reply. I am checking what I missed.
Zulfi.
Hi,
I checked and I found that I forgot PUSH and POP ES.
But I am getting 0's for base but for length of region I am getting:
004f000000000000
I am also showing you my code:
;//portion of memMap code from original file sect8_2.asm
;//Updated by Steve :masm forum
;ml /c memMp3.asm
;link16 /tiny memMp3.obj,memMp3.bin;
;DEBUG Btl3p_3.BIN
;-w 100 0 0 1
;-q
;DEBUG memMp3.BIN
;-w 100 0 1 1
;-q
;DISPLAYING real Time using int 1AH
.MODEL TINY
.386
.CODE
;----------------------------------------------------------------------------------
LoadOfs EQU 0 ;must match the value in the bootloader source file
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
;---------------------- initialize ES segment register
ORG 0
Start: push cs
pop ds
;-----------clear screen
mov ax, 3
int 10h
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
xor di, di
mov ax, 0B800h
mov es, ax
mov si, offset msg0+LoadOfs
mov ah, 41h; attribute byte
cld;
msgloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
jz TimerMesg
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgloop
;---------------------- done - halt
TimerMesg:
xor di, di
mov ax, 0B820h
mov es, ax
mov si, offset msgA+LoadOfs
mov ah, 41h; attribute byte
cld;
msgAloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
;jz RTime
jz mem
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgAloop
mov cx, 1000
;DISPLAY_TIMER:
;-------------Find Total Memory
mem: cld
;call FindTotalMem ;calculate total memory (sets the SI register)
mov ah,7 ;display attribute
mov di,0 ;display position
;call Dsply ;display total memory
call do_e820_Step1
;call Qw2Hex by Dave (instead using code provided by Fortran or Steve)
Halt0: hlt
jmp Halt0
Msg0 db "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs db 0
cnt db 0; Its value represents the digits of Timer
s db 0; selector for secs minutes and hrs used in displayCnt
arr db 10 dup(0)
VAL1 db 0
VAL2 db 0
AscBuf db 8 dup (0),' Kb Total Memory',0
mmap_ent dw ?
end_of_list db 1
MMap_Descriptor STRUCT
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DW ? ; * Next dword = Region "type"
ACPI_Attrib DW ? ; * Next dword = ACPI 3.0 Extended Attri
MMap_Descriptor ENDS
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
;---------------do_e820_Step1
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry. This reqd to set last
;dword to 1 before each call
mov ecx, 24 ; ask for 24 bytes
int 15h
jc short failed ; carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short failed
;jmp short jmpin
;jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short skipent
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if the entire
; entry should be ignored
je short skipent
mov ecx, dword ptr es:[di+8]; get lower dword of memory region length
test ecx, ecx; ; is the qword=0????
jne short goodent
mov ecx, dword ptr es:[di+12];
jecxz skipent
goodent:
inc bp
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
je short e820f
next_call2:
call QW2Hex$ ;Displaying the base address <---------------
add di, 8 ;Length of region starts 15 bytes from current val
;In the procedure we adding 7 to di <-----------
;## You are not pausing after showing the first value before showing the second.
;## And they both print at the same location on screen.
MOV AX,0 ;## Pause?
INT 16H
call QW2Hex$ ;Displaying the length of region
add di, 24
e820f:
mov mmap_ent, bp ; store the entry count
pop es
ret
failed:
stc ; "function unsupported" error exit
pop es
ret
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
PUSH ES
STD ; String instructions decrement.
ADD DI,7 ; Point to last byte, (Intel big end).
mov si ,offset arr+LoadOfs
MOV CX,8 ; Number of bytes to print. QWORD = 8 bytes
;
QW_1:
MOV AL,ES:[DI] ; Get a byte
DEC DI
CALL TOASCII ; Display as hex.
mov dl, VAL1
mov [si], dl ; store the values in array and display array later
inc si
mov dl, VAL2
mov [si], dl
inc si
LOOP QW_1
;
;Displaying the array contents
mov ax,0B800h
mov es,ax
xor di,di
mov di,50h
mov cx,16 ;## 8 bytes will be 16 characters. And it comes out backwards...
mov si,offset arr+LoadOfs
mov ah,1Fh
nextval: mov al, [si]
inc si
stosw ; <= You are automatically incrementing DI
loop nextval
CLD ; Restore default.
POP ES
POP CX
POP AX
POP DI
RET
;---------------------------------------------------
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
mov VAL1, al
;CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
mov VAL2,al
; CALL ConOutByte
POP DX
POP AX
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;----------------------------------------------------------------------------------
END Start
Zulfi.
Hi Zulfi,
Quote
I checked and I found that I forgot PUSH and POP ES.
Right. Fits the symptoms.
QuoteBut I am getting 0's for base but for length of region I am getting:
004f000000000000
Except for being backwards that looks okay. To "unbackwards"
the number change the code something like.
Either pull this out and make it a separate routine. That
would be a start to change where the number prints out later on.
;Displaying the array contents
mov ax,0B800h
mov es,ax
xor di,di
mov di,50h ; <= You will want to make this changable to print in different places.
mov cx,16 ;## 8 bytes will be 16 characters. And it comes out backwards...
mov si,offset arr+LoadOfs
mov ah,1Fh
nextval: mov al, [si]
inc si
stosw ; <= You are automatically incrementing DI
loop nextval
Or move it to be after this line for a quick fix.
CLD ; Restore string instruction direction default.
Tricky.
Regards,
Steve N.
Hi,
Thanks. I would try what you have said. If you have some more time, kindly tell me what you mean by:
Quote
That
would be a start to change where the number prints out later on.
Sorry for taking so much of your time.
Zulfi.
Hi,
Right now it prints the number in one place only. You will
probably want to be able to print it anywhere on the screen
some time. That allows formatting the program output. Having
a smaller routine can make it easier to see how and where to
change the code.
Steve
Hi,
Thanks for your reply. Its clear to me now.
Zulfi.
Hi,
I am trying to do it with a macro which was developed on this forum. It was working previously but now I am getting syntax error.
I dont have any clue for it.
;//portion of memMap code from original file sect8_2.asm
;//Updated by Steve :masm forum
;ml /c memMp3.asm
;link16 /tiny memMp3.obj,memMp3.bin;
;DEBUG Btl3p_3.BIN
;-w 100 0 0 1
;-q
;DEBUG memMp3.BIN
;-w 100 0 1 1
;-q
;DISPLAYING real Time using int 1AH
.MODEL TINY
.386
print_mesg macro offsetStr, offsetScr, msgSize
LOCAL xlat0
mov ax,cs
mov ds,ax
push ax
mov ax,xlat0
push ax
retf
;display the message at B800:50h
xlat0: mov ax,0B800h
mov es,ax
mov di, offsetScr
mov si, offsetStr
cld
mov ah,1Fh
mov cx,msgSize
endm
.CODE
;----------------------------------------------------------------------------------
LoadOfs EQU 0 ;must match the value in the bootloader source file
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
;---------------------- initialize ES segment register
ORG 0
Start: push cs
pop ds
;-----------clear screen
mov ax, 3
int 10h
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
xor di, di
mov ax, 0B800h
mov es, ax
mov si, offset msg0+LoadOfs
mov ah, 41h; attribute byte
cld;
msgloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
jz TimerMesg
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgloop
;---------------------- done - halt
TimerMesg:
xor di, di
mov ax, 0B820h
mov es, ax
mov si, offset msgA+LoadOfs
mov ah, 41h; attribute byte
cld;
msgAloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
;jz RTime
jz mem
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgAloop
mov cx, 1000
;DISPLAY_TIMER:
;-------------Find Total Memory
mem: cld
;call FindTotalMem ;calculate total memory (sets the SI register)
mov ah,7 ;display attribute
mov di,0 ;display position
;call Dsply ;display total memory
call do_e820_Step1
;call Qw2Hex by Dave (instead using code provided by Fortran or Steve)
Halt0: hlt
jmp Halt0
Msg0 db "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs db 0
cnt db 0; Its value represents the digits of Timer
s db 0; selector for secs minutes and hrs used in displayCnt
arr db 10 dup(0)
VAL1 db 0
VAL2 db 0
AscBuf db 8 dup (0),' Kb Total Memory',0
mmap_ent dw ?
end_of_list db 1
MMap_Descriptor STRUCT
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DW ? ; * Next dword = Region "type"
ACPI_Attrib DW ? ; * Next dword = ACPI 3.0 Extended Attri
MMap_Descriptor ENDS
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
;---------------do_e820_Step1
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry. This reqd to set last
;dword to 1 before each call
mov ecx, 24 ; ask for 24 bytes
int 15h
jc short failed ; carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short failed
;jmp short jmpin
;jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short skipent
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if the entire
; entry should be ignored
je short skipent
mov ecx, dword ptr es:[di+8]; get lower dword of memory region length
test ecx, ecx; ; is the qword=0????
jne short goodent
mov ecx, dword ptr es:[di+12];
jecxz skipent
goodent:
inc bp
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
je short e820f
next_call2:
call QW2Hex$ ;Displaying the base address <---------------
add di, 8 ;Length of region starts 15 bytes from current val
;In the procedure we adding 7 to di <-----------
;## You are not pausing after showing the first value before showing the second.
;## And they both print at the same location on screen.
MOV AX,0 ;## Pause?
INT 16H
call QW2Hex$ ;Displaying the length of region
add di, 24
e820f:
mov mmap_ent, bp ; store the entry count
pop es
ret
failed:
stc ; "function unsupported" error exit
pop es
ret
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
PUSH ES
STD ; String instructions decrement.
ADD DI,7 ; Point to last byte, (Intel big end).
mov si ,offset arr+LoadOfs
MOV CX,8 ; Number of bytes to print. QWORD = 8 bytes
;
QW_1:
MOV AL,ES:[DI] ; Get a byte
DEC DI
CALL TOASCII ; Display as hex.
mov dl, VAL1
mov [si], dl ; store the values in array and display array later
inc si
mov dl, VAL2
mov [si], dl
inc si
LOOP QW_1
;
;Displaying the array contents<------------------
;mov ax,0B800h
;mov es,ax
;xor di,di
;mov di,50h
;mov cx,16 ;## 8 bytes will be 16 characters. And it comes out backwards...
;mov si,offset arr+LoadOfs
;mov ah,1Fh
;nextval: mov al, [si]
;inc si
;stosw ; <= You are automatically incrementing DI
;loop nextval
;CLD ; Restore default.
print_mesg macro offset arr+LoadOfs, 50h, 16;<----------SYNTAX ERROR
nextval: lodsb
stosw
loop nextval
POP ES
POP CX
POP AX
POP DI
RET
;---------------------------------------------------
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
mov VAL1, al
;CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
mov VAL2,al
; CALL ConOutByte
POP DX
POP AX
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;----------------------------------------------------------------------------------
END Start
I am getting arror at the following spot in the code:
<----------SYNTAX ERROR
The error is:
D:\masm prog\OS10_MemMap_totMem>ml /c memMp3.asm
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997. All rights reserved.
Assembling: memMp3.asm
memMp3.asm(238) : error A2008: syntax error : arr
D:\masm prog\OS10_MemMap_totMem>
Can somebody guide me with this?
Zulfi.
when you define a macro, you use the word "macro" - not when you invoke it
also, the offset arr+LoadOfs may be a bit much to pass as a single argument
you might try this, Zulfi
MyArg EQU <offset arr+LoadOfs>
print_mesg MyArg, 50h, 16
Thanks.
Its my fault but I have learned something new.
Zulfi.
Hi,
This time its printing 16 0s as Base address and then:
0000 0000 0000 F400
as the length of region. Macro has solved the backward problem though I am not much clear about it.
Zulfi.
Hi,
Those numbers look okay for the base and size. You can
compare using the MEM /C command and look for conventional
memory.
The following lines are intended to be "paired". Comment
both or uncomment both. Since they are not now being
used, you should delete or comment them.
STD ; String instructions decrement.
;CLD ; Restore default.
Regards,
Steve N.
Hi,
I would comment the 'std' in my next run. However now I want to print the Base and length side by side. For this I have parameterized the macro call.
print_mesg MyArg, ScrCoord, 16;<------------------
I have declared ScrCoord as:
ScrCoord dw 50h ;dx stores the screen location for displaying Base address & region length
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Macro argument
The whole code is given below:
;//portion of memMap code from original file sect8_2.asm
;//Updated by Steve :masm forum
;"Solved the prob of backward printing of the length of region"
;Beyond memMp3: printing the base address & pause & then the offset at different locations
; both visible
;-------------------------------------------------------------
;ml /c memMp4.asm
;link16 /tiny memMp4.obj,memMp4.bin;
;DEBUG Btl3p_3.BIN
;-w 100 0 0 1
;-q
;DEBUG memMp4.BIN
;-w 100 0 1 1
;-q
.MODEL TINY
.386
print_mesg macro offsetStr, offsetScr, msgSize
LOCAL xlat0
mov ax,cs
mov ds,ax
push ax
mov ax,xlat0
push ax
retf
;display the message at B800:50h
xlat0: mov ax,0B800h
mov es,ax
mov di, offsetScr
mov si, offsetStr
cld
mov ah,1Fh
mov cx,msgSize
endm
.CODE
;----------------------------------------------------------------------------------
LoadOfs EQU 0 ;must match the value in the bootloader source file
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
;---------------------- initialize ES segment register
ORG 0
Start: push cs
pop ds
;-----------clear screen
mov ax, 3
int 10h
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
xor di, di
mov ax, 0B800h
mov es, ax
mov si, offset msg0+LoadOfs
mov ah, 41h; attribute byte
cld;
msgloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
jz TimerMesg
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgloop
;---------------------- done - halt; NOT A CLK PROG
TimerMesg:
xor di, di
mov ax, 0B820h
mov es, ax
mov si, offset msgA+LoadOfs
mov ah, 41h; attribute byte
cld;
msgAloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
;jz RTime
jz mem
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgAloop
mov cx, 1000
;DISPLAY_TIMER:
;-------------Find Total Memory
mem: cld
;call FindTotalMem ;calculate total memory (sets the SI register)
mov ah,7 ;display attribute
mov di,0 ;display position
;call Dsply ;display total memory
call do_e820_Step1
;call Qw2Hex by Dave (instead using code provided by Fortran or Steve)
Halt0: hlt
jmp Halt0
Msg0 db "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs db 0
cnt db 0; Its value represents the digits of Timer
s db 0; selector for secs minutes and hrs used in displayCnt
arr db 10 dup(0)
VAL1 db 0
VAL2 db 0
ScrCoord dw 50h ;dx stores the screen location for displaying Base address & region length
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Macro argument
AscBuf db 8 dup (0),' Kb Total Memory',0
mmap_ent dw ?
end_of_list db 1
MyArg EQU <offset arr+LoadOfs>
MMap_Descriptor STRUCT
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DW ? ; * Next dword = Region "type"
ACPI_Attrib DW ? ; * Next dword = ACPI 3.0 Extended Attri
MMap_Descriptor ENDS
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
;---------------do_e820_Step1
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry. This reqd to set last
;dword to 1 before each call
mov ecx, 24 ; ask for 24 bytes
int 15h
jc short failed ; carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short failed
;jmp short jmpin
;jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short skipent
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if the entire
; entry should be ignored
je short skipent
mov ecx, dword ptr es:[di+8]; get lower dword of memory region length; i.e from 8 to 11
test ecx, ecx; ; is the qword=0????
jne short goodent
mov ecx, dword ptr es:[di+12];i.e from 12 to 15
jecxz skipent
goodent:
inc bp
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
je short e820f
next_call2:
;--------------------------- ;NOTE QW2HEX$ converts to Hex & prints using Macro
call QW2Hex$ ;Displaying the base address
;-------------------------- Incrementing the screen coordinates
;push dx
;mov dx,ScrCoord
;add dx, 20h
;mov ScrCoord, dx
;pop dx
;------------------------------
add di, 8 ;Length of region starts 15 bytes from current val
;In the procedure we adding 7 to di
;## You are not pausing after showing the first value before showing the second.
;## And they both print at the same location on screen.
MOV AX,0 ;## Pause?
INT 16H
call QW2Hex$ ;Displaying the length of region
;-------------------------- Incrementing the screen coordinates
;push dx
;mov dx,ScrCoord
;add dx, 30h
;mov ScrCoord, dx
;pop dx
;-------------------------
add di, 24
e820f:
mov mmap_ent, bp ; store the entry count
pop es
ret
failed:
stc ; "function unsupported" error exit
pop es
ret
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
PUSH ES
STD ; String instructions decrement.
ADD DI,7 ; Point to last byte, (Intel big end).
; When called 1st DI=0. Now DI =7. So print from 7 to 0. So it pints the Base address
; When called 2nd time DI=8. After adding DI=15. So it prints the length of region
mov si ,offset arr+LoadOfs
MOV CX,8 ; Number of bytes to print. QWORD = 8 bytes
;
QW_1:
MOV AL,ES:[DI] ; Get a byte
DEC DI
CALL TOASCII ; Display as hex.
mov dl, VAL1
mov [si], dl ; store the values in array and display array later
inc si
mov dl, VAL2
mov [si], dl
inc si
LOOP QW_1
;---------------------------Calling Macro with the screen coordinates
;print_mesg MyArg, 50h, 16;
print_mesg MyArg, ScrCoord, 16;<------------------
nextval: lodsb
stosw
loop nextval
POP ES
POP CX
POP AX
POP DI
RET
;---------------------------------------------------
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
mov VAL1, al
;CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
mov VAL2,al
; CALL ConOutByte
POP DX
POP AX
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;----------------------------------------------------------------------------------
END Start
I am seeing the two messages but its not printing any values. Can somebody help me with this?
Zulfi.
Hi Zulfi,
I took a look at your code, but on a computer that
is not too conveniently set up, so I may have not gotten
things quite right.
You have:
print_mesg macro offsetStr, offsetScr, msgSize
LOCAL xlat0
mov ax,cs
mov ds,ax
push ax
mov ax,xlat0
push ax
retf
;display the message at B800:50h
xlat0: mov ax,0B800h
mov es,ax
mov di, offsetScr
mov si, offsetStr
cld
mov ah,1Fh
mov cx,msgSize
endm
I think it should be something more like:
print_mesg macro offsetStr, offsetScr, msgSize
LOCAL xlat0
mov ax,cs
mov ds,ax
; push ax ; I do not see why you are doing this?
; mov ax,xlat0
; push ax
; retf
;display the message at B800:50h
xlat0: mov ax,0B800h
mov es,ax
mov di,OFFSET offsetScr ; This is where the error in printing occurs, fix?
mov si, offsetStr
cld
mov ah,1Fh
mov cx,msgSize
endm
Actually, I don't know if the OFFSET should be in the
macro or in the line where you invoke the macro. I
just found the wrong value in DI when it was being used.
So maybe:
print_mesg OFFSET MyArg, ScrCoord, 16;<------------------
And you still need to fix this.
RangeType DD ? ; * Next dword = Region "type"
ACPI_Attrib DD ? ; * Next dword = ACPI 3.0 Extended Attri
HTH,
Steve N.
Thanks for your reply.
For the offset Dave told me to use a macro:
MyArg EQU <offset arr+LoadOfs>
Thus when I use:
print_mesg MyArg, 50h, 16;
It works fine. But when i use a variable for 50h i.e :
print_mesg MyArg, ScrCoord, 16;
Its not working.
This is the problem.
If somebody has any solution for this, kindly help me.
I would check about the second part of your statement later.
Zulfi.
Hi,
My mistake. What I posted was wrong. Adding an
OFFSET is not the answer. And I managed to put the
OFFSET on the wrong argument on the macro call anyway.
But the DI register had a bad value in it in DEBUG. I will
try to find out where it came from. It ended up writing
to a different page of video memory, so I saw nothing
on screen.
Regards,
Steve N.
Hi,
Okay, here is the problem:
arr db 10 dup(0)
VAL1 db 0
VAL2 db 0
ScrCoord dw 50h ;dx stores the screen location for displaying Base address & region ScrCoord dw 50h ;dx stores the screen location for displaying Base address & region length
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Macro argument
AscBuf db 8 dup (0),' Kb Total Memory',0
ScrCoord is being overwritten by the binary to ASCII routine.
So instead of it being 50H it is 3030H when it is first used. Not
actually tracked down, so this is a guess, arr is 10 and it should
be at least 16 (10H). See if that helps.
Steve N.
Yes, it helped. I would also try Debug.
Thanks.
Zulfi.
Quote from: zak100 on June 04, 2010, 10:08:39 AM
Yes, it helped. I would also try Debug.
Thanks.
Zulfi.
Hi,
Most of the work to get it running in DEBUG is to change
ORG 0 to ORG 100H and create a *.COM executable. I
also got rid of the code that used the RETF as it crashed
the program in a VDM.
Regards,
Steve
Thanks.
Zulfi.
Hi,
I am trying to update the code by printing the base address, pause and then the length of region. Currently I am printing the base address then pause and length of the region at the same place where base is located. I am using the following code:
push dx ;<---------------------
mov dx,ScrCoord
add dx, 20h
mov ScrCoord, dx
pop dx
This code is giving me prob because I cant see any test messages and computer hangs up.
I have tried Debug also but after int 15h it fails and goes to stc instruction.
The whole code is :
;//portion of memMap code from original file sect8_2.asm
;//Updated by Steve :masm forum
;"Solved the prob of backward printing of the length of region"
;Beyond memMp3: printing the base address & pause & then the offset at different locations
; both visible
; using arguments for print_mesg macro e.g:
; print_mesg MyArg, ScrCoord, 16;
;-------------------------------------------------------------
;ml /c memMp4.asm
;link16 /tiny memMp4.obj,memMp4.bin;
;DEBUG Btl3p_3.BIN
;-w 100 0 0 1
;-q
;DEBUG memMp4.BIN
;-w 100 0 1 1
;-q
.MODEL TINY
.386
print_mesg macro offsetStr, offsetScr, msgSize
LOCAL xlat0
mov ax,cs
mov ds,ax
push ax
mov ax,xlat0
push ax
retf
;display the message at B800:50h
xlat0: mov ax,0B800h
mov es,ax
mov di, offsetScr
mov si, offsetStr
cld
mov ah,1Fh
mov cx,msgSize
endm
.CODE
;----------------------------------------------------------------------------------
LoadOfs EQU 0 ;must match the value in the bootloader source file
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
;---------------------- initialize ES segment register
ORG 0
Start: push cs
pop ds
;-----------clear screen
mov ax, 3
int 10h
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
xor di, di
mov ax, 0B800h
mov es, ax
mov si, offset msg0+LoadOfs
mov ah, 41h; attribute byte
cld;
msgloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
jz TimerMesg
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgloop
;---------------------- done - halt; NOT A CLK PROG
TimerMesg:
xor di, di
mov ax, 0B820h
mov es, ax
mov si, offset msgA+LoadOfs
mov ah, 41h; attribute byte
cld;
msgAloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
;jz RTime
jz mem
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgAloop
mov cx, 1000
;DISPLAY_TIMER:
;-------------Find Total Memory
mem: cld
;call FindTotalMem ;calculate total memory (sets the SI register)
mov ah,7 ;display attribute
mov di,0 ;display position
;call Dsply ;display total memory
call do_e820_Step1
;call Qw2Hex by Dave (instead using code provided by Fortran or Steve)
Halt0: hlt
jmp Halt0
Msg0 db "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs db 0
cnt db 0; Its value represents the digits of Timer
s db 0; selector for secs minutes and hrs used in displayCnt
arr db 16 dup(0)
VAL1 db 0
VAL2 db 0
ScrCoord dw 50h ;dx stores the screen location for displaying Base address & region length
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Macro argument
AscBuf db 8 dup (0),' Kb Total Memory',0
mmap_ent dw ?
end_of_list db 1
MyArg EQU <offset arr+LoadOfs>
MMap_Descriptor STRUCT
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DW ? ; * Next dword = Region "type"
ACPI_Attrib DW ? ; * Next dword = ACPI 3.0 Extended Attri
MMap_Descriptor ENDS
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
;---------------do_e820_Step1
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry. This reqd to set last
;dword to 1 before each call
mov ecx, 24 ; ask for 24 bytes
int 15h
jc short failed ; carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short failed
;jmp short jmpin
;jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short skipent
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if the entire
; entry should be ignored
je short skipent
mov ecx, dword ptr es:[di+8]; get lower dword of memory region length; i.e from 8 to 11
test ecx, ecx; ; is the qword=0????
jne short goodent
mov ecx, dword ptr es:[di+12];i.e from 12 to 15
jecxz skipent
goodent:
inc bp
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
je short e820f
next_call2:
;--------------------------- ;NOTE QW2HEX$ converts to Hex & prints using Macro
call QW2Hex$ ;Displaying the base address
;-------------------------- Incrementing the screen coordinates
push dx ;<---------------------NEW
mov dx,ScrCoord
add dx, 20h
mov ScrCoord, dx
pop dx
;------------------------------
add di, 8 ;Length of region starts 15 bytes from current val
;In the procedure we adding 7 to di
;## You are not pausing after showing the first value before showing the second.
;## And they both print at the same location on screen.
MOV AX,0 ;## Pause?
INT 16H
call QW2Hex$ ;Displaying the length of region
;-------------------------- Incrementing the screen coordinates
push dx<------NEW
mov dx,ScrCoord
add dx, 30h
mov ScrCoord, dx
pop dx
;-------------------------
add di, 24
e820f:
mov mmap_ent, bp ; store the entry count
pop es
ret
failed:
stc ; "function unsupported" error exit
pop es
ret
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
PUSH ES
STD ; String instructions decrement.
ADD DI,7 ; Point to last byte, (Intel big end).
; When called 1st DI=0. Now DI =7. So print from 7 to 0. So it pints the Base address
; When called 2nd time DI=8. After adding DI=15. So it prints the length of region
mov si ,offset arr+LoadOfs
MOV CX,8 ; Number of bytes to print. QWORD = 8 bytes
;
QW_1:
MOV AL,ES:[DI] ; Get a byte
DEC DI
CALL TOASCII ; Display as hex.
mov dl, VAL1
mov [si], dl ; store the values in array and display array later
inc si
mov dl, VAL2
mov [si], dl
inc si
LOOP QW_1
;---------------------------Calling Macro with the screen coordinates
;print_mesg MyArg, 50h, 16;
print_mesg MyArg, ScrCoord, 16;<------------------
nextval: lodsb
stosw
loop nextval
POP ES
POP CX
POP AX
POP DI
RET
;---------------------------------------------------
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
mov VAL1, al
;CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
mov VAL2,al
; CALL ConOutByte
POP DX
POP AX
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;----------------------------------------------------------------------------------
END Start
Can somebody help me with this?
Zulfi.
Hi,
Actually, with the changes I suggested, it is working for me.
If you are using Windows 2000, XP, or such, the INT 15H
is going to fail. In reply #69 the stuff about OFFSET was
bad. But I commented out the RETF code in your macro
because it crashed the program on my computer. Maybe
it is doing the same to yours? And your STRUCT still needs
fixing, though that is not the problem now.
Dave, or anyone, is the order he is pushing the segment
and address backwards? And what does that code accomplish?
Regards,
Steve
The segment would be pushed first, placing it at the higher address and the offset at the lower address.
My program is crashing with int 15h. For 32 bit registers, Debug is showing DB 66 as the instruction instead of the original instruction in the program. i got the Debug tutorial also by MichealW which I would also check later on.
In order to avoid int 15h, I am writing a simple program to see if my code works and if it doesnt I can troubleshoot using debug.
Zulfi.
Hi,
I have tried printing two strings in another program using the macro which I am using in my program, reply#76. It works fine. It prints the first string then pause and then the 2nd string.
The code for that program is :
.MODEL TINY
.386
print_mesg macro offsetStr, offsetScr, msgSize
LOCAL xlat0
mov ax,cs
mov ds,ax
push ax
mov ax,xlat0
push ax
retf
;display the message at B800:50h
xlat0: mov ax,0B800h
mov es,ax
mov di, offsetScr
mov si, offsetStr
cld
mov ah,1Fh
mov cx,msgSize
endm
;------------------
.CODE
;----------------------------------------------------------------------------------
LoadOfs EQU 0 ;must match the value in the bootloader source file
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
;---------------------- initialize ES segment register
ORG 0
Start: push cs
pop ds
;-----------clear screen
mov ax, 3
int 10h
;----------------------msg0
overdata:
xor di, di
mov ax, 0B800h
mov es, ax
mov si, offset msg0+LoadOfs
mov ah, 41h; attribute byte
cld;
msgloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
jz TimerMesg
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgloop
;--------------
TimerMesg: print_mesg MyArg1, ScrCoord, 16;
disp0: lodsb
stosw
loop disp0
;--------------changing screen Coordinates
push dx ;<---------------------
mov dx,ScrCoord
add dx, 20h
mov ScrCoord, dx
pop dx
;--------------
MOV AX,0 ;## Pause?
INT 16H
;---------------
print_mesg MyArg2, ScrCoord, 16;
disp1: lodsb
stosw
loop disp1
Halt0: hlt
jmp Halt0
Msg0 db "We be bootin234!",0
arr1 db '1234567890abcdef',0
arr2 db '!!!!!!!!!!!!!!!!',0
ScrCoord dw 50h ;dx stores the screen location for displaying Base address & region length
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Macro argument
MyArg1 EQU <offset arr1+LoadOfs>
MyArg2 EQU <offset arr2+LoadOfs>
END Start
But when I am trying the same thing with my code in reply# 76, its not working.
Sorry to say, I cant relate the following quote with my program:
Quote
The segment would be pushed first, placing it at the higher address and the offset at the lower address.
Can somebody help me with my prob.?
Zulfi.
Hi,
Thanks MichaelW, I can never remember those kinds
of things.
Quote
Sorry to say, I cant relate the following quote with my program:
It means that the code section I was talking about is
not coded incorrectly.
QuoteDebug is showing DB 66 as the instruction instead of the original
instruction in the program.
That would be a 32-bit instruction (80386 or newer) and
DEBUG can only work with 16-bit (8086) instructions.
Steve N.
Japheth's DOS Debug clone can handle instruction sets through the Pentium Pro.
http://www.japheth.de/debxxf.html
Thanks for providing me this link. I would try to download it. If anybody having any clue to my printing prob (printing base address and region length side by side using Macro), kindly let me know.
Zulfi.
Zulfi
long ago, i used to make a special floppy that replaced COMMAND.COM with the old DEBUG.COM program
DEBUG.COM came with older versions of DOS - newer versions were EXE's
also, DOS versions older than 3.0 (i think) did not have the EXEC loader installed during CONFIG.SYS
DOS 3 and above had the EXEC loader, so you could install an EXE as a SYS file (tricky - lol)
even so, you can load COMMAND.COM, then use the COMSPEC and SHELL commands in AUTOEXEC.BAT to load an EXE
that way, you can debug through your program without a windows OS loaded
i don't have a floppy drive to play with it at the moment, so you may have to fart around with it a bit :bg
Hi,
I think you are right. I must run my program through Debug utility. I would try MichealW's link to find out the bug with my code.
If it works with int 15h its fine, otherwise I have try to resort to your tricks.
Zulfi.
i bet Steve or Michael can tell you how to set up a floppy for debugging (hint hint)
Hi,
I just have a bootable floppy set up with with a large RAM
disk. You can copy COMMAND.COM to the RAM disk, set
COMSPEC to point to it so you don't have to swap diskettes
after running a program. And copy what ever you need to a
sub-directory on the RAM drive. Do your work, copy the results
back to a floppy, and off you go.
If I follow what Dave was saying, in CONFIG.SYS point
COMSPEC to DEBUG.EXE.
I use the RAM disk and leave COMMAND.COM on the floppy.
Here is the CONFIG.SYS for a DOS 6.2 diskette.
REM Normal Boot
DEVICE=A:\DOS\HIMEM.SYS
FILES=40
DOS=UMB
LASTDRIVE=J
DEVICEHIGH=A:\DOS\ANSI.SYS
DOS=HIGH
DEVICEHIGH=A:\DOS\RAMDRIVE.SYS 8192 /E
DEVICEHIGH=A:\DOS\SETVER.EXE
SHELL=A:\DOS\COMMAND.COM A:\DOS /P
And AUTOEXEC.BAT.
echo off
REM Normal Boot
LH /S A:\DOS\SMARTDRV.EXE
PROMPT $p$g
PATH A:\DOS;A:\utility;
rem mkdir G:\temp
rem SET TEMP=G:\TEMP
rem SET TMP=G:\TEMP
sertype
doskey
SET COMSPEC=A:\DOS\COMMAND.COM
Regards,
Steve
thanks Steve
well - what i was refering to was actually either
1) replacing command.com with debug
or
2) setting it up so debug was executed as a command.com shell command
as i said - it has been a long time since i have had to do this
i used to have the requirement to sometimes troubleshoot config.sys type device drivers in this manner
Hi Dave,
For 1) just use COMSPEC in CONFIG.SYS. (Or REName,
shudder.) But I need DIR (short memory?) and the like,
so that's not what I try.
What I posted will get you 2). If you want, add DEBUG
to AUTOEXEC.BAT. With a file name argument you don't
even need a good memory. Here I just end up with the
code off the boot diskette, so I don't [fill in your favorite
stupidity] and junk the boot diskette.
Cheers,
Steve N.
right - he probably doesn't need to go through all the trouble i was going through
i wanted to see the driver in memory before COMMAND.COM was loaded
that is why i went that route
Hi,
Sorry, is this exercise going to help me to get around with int 15h problem
during Debugging?
I am using a floppy disk in which I am storing the bootloader &
the kernel. I have got following Questions:
i) Do I have to use another floppy?
ii) Do I have to change my config.sys and autoexec.bat?
iii)I dont know if I have Dos 6.2. When I type ver, its telling
me the version of OS & not DOS?
iv)If i change my config.sys & Autoexec.bat with the listing provided by
Steve, is it going to do everything, I mean setup the RAM disk & load the
Debug.
Thanks for telling me this new thing.
Zulfi.
Hi Zulfi,
Since your code is working for me in DEBUG, I will redo it
as a boot loader to see if anything changes. But that may
take a while.
Quote from: zak100 on June 09, 2010, 04:32:05 AM
Hi,
Sorry, is this exercise going to help me to get around with int 15h problem
during Debugging?
Well, that was the idea. But of course it may not work. Or
you can procede as you are doing now.
Quote
I am using a floppy disk in which I am storing the bootloader &
the kernel. I have got following Questions:
i) Do I have to use another floppy?
Probably a very good idea to do so, but not required.
Quote
ii) Do I have to change my config.sys and autoexec.bat?
If you mean reusing the CONFIG.SYS and AUTOEXEC.BAT
from a Windows system, then yes you cannot use that on a
DOS floppy.
Quote
iii)I dont know if I have Dos 6.2. When I type ver, its telling
me the version of OS & not DOS?
Right, you probably do not have MS-DOS 6.2. You can get
"FreeDOS" or another real-mode MS-DOS clone if you don't
have access to a DOS or Windows 9x system. From what
you have said, you probably have some version of NT style
Windows.
www.freedos.org/ (http://www.freedos.org/)
Quote
iv)If i change my config.sys & Autoexec.bat with the listing provided by
Steve, is it going to do everything, I mean setup the RAM disk & load the
Debug.
You will have to format a bootable DOS diskette. Then copy
the RAM Disk driver, DEBUG, DOSKEY, your code, an _old_
version of MASM, and LINK16 to the disk. Then you can use
the CONFIG.SYS and AUTOEXEC.BAT I posted assuming you
put everything in the same places I did. You don't need to
worry about the RAM drive, that is just an extra I use. Oh,
EXE2BIN will be needed for making a COM style executable.
And you may want an editor.
The basic idea was to avoid rebooting after each modification
of the code. That drove me nuts. I had/have computers set
up with DOS so things were fairly simple for me to switch over
from a boot loader to DEBUG. The computer I mostly used
for this is no longer usable, so things are going a bit slower
now.
HTH,
Steve N.
Hi,
Okay, another failure mode found. My version of this code
assembles to longer than 512 bytes for the boot loader binary.
So I had to modify the boot sector to load two sectors. Or
it's silently off to la-la land. And at least it now works as an
independent boot.
Regards,
Steve N.
Hi Steve and Dave (and everybody else who has helped me with this problem),
I have decided to continue my work on memory map. I am working on Debug related stuff in another thread. I have completed the code (using the downloaded stuff), but its not giving me any results. It hangs up after printing character 'A'.
; Entire code of MemMap: Printing the base address and length in a loop
;-------------------------------------------------------------
;ml /c memMp4.asm
;link16 /tiny memMp4.obj,memMp4.bin;
;DEBUG Btl3p_3.BIN
;-w 100 0 0 1
;-q
;DEBUG memMp4.BIN
;-w 100 0 1 1
;-q
.MODEL TINY
.386
print_mesg macro offsetStr, offsetScr, msgSize
LOCAL xlat0
mov ax,cs
mov ds,ax
push ax
mov ax,xlat0
push ax
retf
;display the message at B800:50h
xlat0: mov ax,0B800h
mov es,ax
mov di, offsetScr
mov si, offsetStr
cld
mov ah,1Fh
mov cx,msgSize
endm
.CODE
;----------------------------------------------------------------------------------
LoadOfs EQU 0 ;must match the value in the bootloader source file
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
;---------------------- initialize ES segment register
ORG 0
Start: push cs
pop ds
;-----------clear screen
mov ax, 3
int 10h
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
xor di, di
mov ax, 0B800h
mov es, ax
mov si, offset msg0+LoadOfs
mov ah, 41h; attribute byte
cld;
msgloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
jz TimerMesg
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgloop
;---------------------- done - halt; NOT A CLK PROG
TimerMesg:
xor di, di
mov ax, 0B820h
mov es, ax
mov si, offset msgA+LoadOfs
mov ah, 41h; attribute byte
cld;
msgAloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
;jz RTime
jz mem
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgAloop
mov cx, 1000
;DISPLAY_TIMER:
;-------------Find Total Memory
mem: cld
;call FindTotalMem ;calculate total memory (sets the SI register)
mov ah,7 ;display attribute
mov di,0 ;display position
;call Dsply ;display total memory
call do_e820_Step1
;call Qw2Hex by Dave (instead using code provided by Fortran or Steve)
Halt0: hlt
jmp Halt0
Msg0 db "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs db 0
cnt db 0; Its value represents the digits of Timer
s db 0; selector for secs minutes and hrs used in displayCnt
arr db 16 dup(0)
VAL1 db 0
VAL2 db 0
ScrCoord dw 50h ;dx stores the screen location for displaying Base address & region length
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Macro argument
AscBuf db 8 dup (0),' Kb Total Memory',0
mmap_ent dw ?
end_of_list db 1
MyArg EQU <offset arr+LoadOfs>
MMap_Descriptor STRUCT
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DW ? ; * Next dword = Region "type"
ACPI_Attrib DW ? ; * Next dword = ACPI 3.0 Extended Attri
MMap_Descriptor ENDS
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
;---------------do_e820_Step1
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry. This reqd to set last
;dword to 1 before each call
mov ecx, 24 ; ask for 24 bytes
int 15h
jc short failed ; carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short failed
jmp short jmpin
e8201p:
mov eax, 0e820h
mov dword ptr es:[di + 20], 1
mov ecx, 24
int 24h
jc short e820f
mov edx, 0534D4150h
jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short skipent
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if the entire
; entry should be ignored
je short skipent
mov ecx, dword ptr es:[di+8]; get lower dword of memory region length; i.e from 8 to 11
test ecx, ecx; ; is the qword=0????
jne short goodent
mov ecx, dword ptr es:[di+12];i.e from 12 to 15
jecxz skipent
goodent:
inc bp
;--------------------------- ;NOTE QW2HEX$ converts to Hex & prints using Macro
call QW2Hex$ ;Displaying the base address
;## You are not pausing after showing the first value before showing the second.
;## And they both print at the same location on screen.
MOV AX,0 ;## Pause?
INT 16H
push di
add di, 8 ;Length of region starts 15 bytes from current val
;In the procedure we adding 7 to di
call QW2Hex$ ;Displaying the length of region
pop di
add di, 24
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
jne short e8201p
;-------------------------
e820f:
mov mmap_ent, bp ; store the entry count
pop es
ret
failed:
stc ; "function unsupported" error exit
pop es
ret
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
PUSH ES
STD ; String instructions decrement.
ADD DI,7 ; Point to last byte, (Intel big end).
; When called 1st DI=0. Now DI =7. So print from 7 to 0. So it pints the Base address
; When called 2nd time DI=8. After adding DI=15. So it prints the length of region
mov si ,offset arr+LoadOfs
MOV CX,8 ; Number of bytes to print. QWORD = 8 bytes
;
QW_1:
MOV AL,ES:[DI] ; Get a byte
DEC DI
CALL TOASCII ; Display as hex.
mov dl, VAL1
mov [si], dl ; store the values in array and display array later
inc si
mov dl, VAL2
mov [si], dl
inc si
LOOP QW_1
;---------------------------Calling Macro with the screen coordinates
;print_mesg MyArg, 50h, 16;
print_mesg MyArg, ScrCoord, 16;<------------------
nextval: lodsb
stosw
loop nextval
POP ES
POP CX
POP AX
POP DI
RET
;---------------------------------------------------
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
mov VAL1, al
;CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
mov VAL2,al
; CALL ConOutByte
POP DX
POP AX
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;----------------------------------------------------------------------------------
END Start
Can anybody check the problem?
Zulfi.
Hi,
Did you make the changes suggested in Reply #93? I made
only minor changes to your code and it is working for me. Alter
the boot sector to load two sectors instead of one. And of course
write out two sectors from DEBUG.
If you did make those changes, I would add a failure message
for the test for a "good interrupt".
failed:
: Write a message to the screen. "INT E820 not supported".
stc ; "function unsupported" error exit
pop es
ret
Thanks. I read your reply again and now its clear to me. I would try to do the required changes. I have not checked the size of my binary yet.
Zulfi.
Hi Steve, Dave ( and every person who is helping me with this code),
I have modified the boot sector program. I dont know whether its correct or not so I want to get some comment from you people.
The code is given below:
;*
;ml /c btl3p_4.asm
;link16 /tiny btl3P_4.obj,btl3P_4.bin;
;
;DEBUG btlder3P_4.BIN
;-w 100 0 0 1
;-q
;DEBUG sect4_2.BIN
;-w 100 0 1 1
;-q
;*
.MODEL TINY
.CODE
;----------------------------------------------------------------------------------
LoadOfs EQU 0
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
;---------------------- branch to executable code
ORG 0
Boot0: jmp short Boot1
nop
;---------------------- OEM identifier
ORG 3
DB "Zulfi OS"
;---------------------- BIOS parameter block for 1.44 Mb floppy disk
ORG 0Bh
bpbBytesPerSector DW 512
bpbSectorsPerCluster DB 2; 1
bpbReservedSectors DW 1
bpbNumberOfFATs DB 2
bpbRootEntries DW 112; 224
bpbTotalSectors DW 1440; 2880
bpbMedia DB 0F9H; 0F0h
bpbSectorsPerFAT DW 3; 9
bpbSectorsPerTrack DW 9; 18; different (18)
bpbHeadsPerCylinder DW 2
bpbHiddenSectors DD 0
bpbTotalSectorsBig DD 0
bsDriveNumber DB 0
bsUnused DB 0
bsExtBootSignature DB 29h
bsSerialNumber DD 0a0a1a2a3h
bsVolumeLabel DB "MOS FLOPPY "
bsFileSystem DB "FAT12 "
SectorNum DB 1
LoadOfsvar DW LoadOfs
;---------------------- initialize SS:SP
Boot1: cli ;disable maskable interrupts
xor di,di
mov ss,di
mov sp,7C00h ;SS:SP = 0000:7C00
sti ;enable maskable interrupts
;---------------------- display 'A' character
cld
mov ax,0B800h
mov es,ax
mov ax,1F41h
stosw
;---------------------- wait for a keypress
mov ah,0
int 16h
;--------------------- read bootloader
ReadSectorLoop:
mov cx,5 ;retry count
Reset0: push cx
mov ah,0 ;reset floppy disk function
mov dl,0 ;drive A:
int 13h
mov ax,LoadSeg ;read sector into address LoadSeg:LoadOfs
mov es,ax
mov bx,LoadOfsVar
call ReadSectors
pop cx
jnc PreReadNextSector
loop Reset0
jc ReadError ;After 5th try display error message
jmp Exec0
PreReadNextSector:
inc SectorNum
cmp SectorNum, 3; ---------------reading first 2 sectors
jz Exec0
add LoadOfsVar, 512
jmp ReadSectorLoop
;---------------------- failed 5 times - halt
;---display 'F' character to show the failure occured
ReadError:
mov ax, 0B800h
mov es, ax
mov Di,4
mov ax, 9c46h
stosw
Halt0: hlt
jmp Halt0
;----------------------
ReadSectors:
mov ax, 201h ;ah=2 function, al=1 (read 1 sector only)
mov ch,0; Track
mov cl, sectorNum ;Sector start with 1 not 0
xor dx, dx; Head 0, drive 0
int 13h
ret
;---------------------- execute the bootloader code
Exec0:
db 0EAh ;JMP FAR instruction
dw LoadOfs ;offset
dw LoadSeg ;segment
;---------------------- boot sector signature
ORG 1FEh
dw 0AA55h
;----------------------------------------------------------------------------------
END Boot0
About the Kernel, do I have to break it into two separate executable programs? Kindly advise me how to break the Kernel?
Zulfi.
Hi,
QuoteAbout the Kernel, do I have to break it into two separate executable programs?
I didn't. I did a little less work with my version. Here is
what I did.
COMMENT * Original code by dedndave on MASM32 Forum. Modifications,
additions, tpyos, and corrections FORTRANS (Steve) on MASM32 Forum.
27 November 2009
10 June 2010 load two sectors.
REM Create BooSect.BIN, NOT sure about ML switches.
\MASM32\BIN\ML /AT /c /Fl /Fm BootSect.ASM
\MASM32\BIN\LINK16 BootSect.OBJ;
EXE2BIN BootSect.EXE
11/27/2009 04:02p 40 BOOTLOAD.BIN
11/27/2009 04:02p 512 BOOTSECT.BIN
06/09/2010 03:24p 548 TEST22.BIN
DEBUG BootSect.BIN
-w 100 0 0 1
-q
DEBUG BootLoad.BIN
-w 100 0 1 2
-q
TODO: Use a different sector to write/read BootLoad.BIN to.
Convert to hexadecimal and display contents of CS and IP.
Fix up messages...
*
.MODEL TINY
.CODE
;----------------------------------------------------------------------
LoadOfs EQU 0
LoadSeg EQU 1000h
;----------------------------------------------------------------------
;---------------------- branch to executable code
ORG 0
Boot0: jmp short Boot1
NOP ; - - - Mods to deadndave's code: Win2K error fix,
; - - - original was a zero.
;---------------------- OEM identifier
ORG 3
DB "Steve OS"
;---------------------- BIOS parameter block for 1.44 Mb floppy disk
; - - - Mod to 720K - - -
ORG 0Bh
bpbBytesPerSector DW 512
bpbSectorsPerCluster DB 1 ; 2 ; 1 Mods to deadndave's code: Cluster size,
; may/may not have caused a problem? He was okay?
bpbReservedSectors DW 1
bpbNumberOfFATs DB 2
bpbRootEntries DW 112 ; 224 Mods to deadndave's code: 720 K
bpbTotalSectors DW 1440 ; 2880 diskette instead of 1.44 M
bpbMedia DB 0F9H ; 0F0h
bpbSectorsPerFAT DW 3 ; 9
bpbSectorsPerTrack DW 9 ; 18
bpbHeadsPerCylinder DW 2
bpbHiddenSectors DD 0
bpbTotalSectorsBig DD 0
bsDriveNumber DB 0
bsUnused DB 0
bsExtBootSignature DB 29h
bsSerialNumber DD 0DeadBeefH
bsVolumeLabel DB "MOS FLOPPY "
bsFileSystem DB "FAT12 "
;---------------------- initialize SS:SP
Boot1: cli ;disable maskable interrupts
xor di,di
mov ss,di
mov sp,7C00h ;SS:SP = 0000:7C00
sti ;enable maskable interrupts
;---------------------- display 'A' character
cld
mov ax,0B800h ; CGA text memory segment
mov es,ax
mov ax,1F41h
stosw ; Store character and attribute.
;---------------------- wait for a keypress
mov ah,0 ; Keboard BIOS wait for character.
int 16h
;---------------------- read the bootloader code
mov cx,5 ;retry count
Reset0: push cx
mov ah,0 ;reset floppy disk function
mov dl,0 ;drive A:
int 13h
mov ax,LoadSeg ;read sector into address LoadSeg:LoadOfs
mov es,ax
mov bx,LoadOfs
mov cx,2 ;cylinder 0, sector 2 (1 based)
xor dx,dx ;head 0, drive 0
mov ax,202h ;read 2 sectors
int 13h
pop cx
jnc Exec0
loop Reset0
;---------------------- failed 5 times - halt
; - - - Display 'F' character - - -
; - - - to show the failure occured.
mov ax,0B800h
mov es,ax
mov DI,4 ; Move a bit to avoid the 'A',
mov ax,9C46h; 9C attribute should be ugly.
stosw
Halt0: HLT
jmp Halt0
;---------------------- execute the bootloader code
Exec0:
db 0EAh ;JMP FAR instruction
dw LoadOfs ;offset
dw LoadSeg ;segment
;---------------------- boot sector signature
ORG 1FEh
dw 0AA55h
;----------------------------------------------------------------------------------
END Boot0
Hi,
Thanks for your help. The boot sector code is working. But my kernel is still showing only the base address & region length of only the first region. I posted its (kernel) code on June 14, 2010. Can somebody please guide me with this?
Zulfi.
e8201p:
mov eax, 0e820h
mov dword ptr es:[di + 20], 1
mov ecx, 24
int 24h
int 24h? Maybe try int 15h.
Hi,
Thanks for your help sinsi. In my opinion it should work but now I am not even getting the base address and length of 1st region. However I am getting 'A' and all the string messages. Kindly provide me more guidance on this.
Zulfi.
Hi,
Quote from: zak100 on June 19, 2010, 06:14:41 PM
Thanks for your help. The boot sector code is working. But my kernel is still showing only the base address & region length of only the first region. I posted its (kernel) code on June 14, 2010. Can somebody please guide me with this?
Well, one of the things you should do is preserve the contents of
EBX to do another Int 15H. The 0E820H function wants the value
it returned from the last call to allow it to get the next region. The
OSDev Wiki code does this, but your printing the values changes
it. That code was intended to store all the regions and let the user
process them afterwards. And in debugging the code I found that
you can get very strange errors sometimes if you have an invalid
value in EBX.
MichaelW's MemMap code process each region after the interrupt,
like you are doing. So you may want to look at his code to see how
and where he uses EBX. I am using the Wiki code as you started
with, but process all the regions afterward. This lets me sort the
entries as suggested in the Wiki article. A bit of warning, if you store
the values in an array, you should count the regions returned so you
don't overflow your array. That was messy on one of my machines.
Just to show the effect of the sort, I'll post the output of my program
and MichaelW's.
Regards,
Steve N.
SRN's MemTest
Memory Map returned by system interrupt 15H Function E820H:
Base Length Usable Size Type
00000000 0009FC00 654336 Usable (normal) RAM.
0009FC00 00000400 0 Reserved, not available.
000F0000 00010000 0 Reserved, not available.
00100000 0FEF0000 267321344 Usable (normal) RAM.
0FFF0000 00003000 0 ACPI NVS memory.
0FFF3000 0000D000 0 ACPI reclaimable memory.
FFFF0000 00010000 0 Reserved, not available.
-------- -------- -----------
Total Usable Memory: 267975680
MichaelW's MemMap.exe
Memory Map returned by Interrupt 15h Function E820h:
BASE=00000000h LENGTH=0009FC00h (654336)TYPE=AVAILABLE
BASE=0009FC00h LENGTH=00000400h (1024)TYPE=RESERVED
BASE=000F0000h LENGTH=00010000h (65536)TYPE=RESERVED
BASE=FFFF0000h LENGTH=00010000h (65536)TYPE=RESERVED
BASE=00100000h LENGTH=0FEF0000h (267321344)TYPE=AVAILABLE
BASE=0FFF3000h LENGTH=0000D000h (53248)TYPE=ACPI_RECLAIM
------------------------------------------------------------
TOTAL LENGTH 0FFBD000h (268161024)
Extended Memory size returned by Interrupt 15h Function 88h = 0 bytes
Extended Memory size from CMOS RAM = 67043328 bytes
Press any normal key to exit...
Hi,
I tried to search MichealW's code on this forum but I am not lucky in this regard. Can you people provide me a link for his code?
Zulfi.
Do you mean this?:
http://www.masm32.com/board/index.php?topic=7679.msg56497#msg56497
Hi,
Thanks MichealW.
Quote
Well, one of the things you should do is preserve the contents of
EBX to do another Int 15H.
I have checked this code but I didnt see any explicit instruction for preserving ebx.
xor ebx, ebx
callLoop:
mov eax, 0e820h
mov edx, 'SMAP'
mov ecx, SIZEOF smmard
; Set DI to the offset address of smmard.
mov di, OFFSET smmard
int 15h
; Preserve CF for later test.
pushf
.IF eax != 'SMAP'
popf
print NL,"Interrupt 15h Function E820h not supported or not available.",NL,NL
jmp callFunction88h
.ENDIF
; The function may indicate that the last range
; has been returned by setting the carry flag
; or by returning zero in EBX.
popf
jc finish
test ebx, ebx
jz finish
print NL,"BASE=",hexdword$(smmard.baseLo),"h "
print "LENGTH=",hexdword$(smmard.lengthLo),"h "
print chr$(40),dword$(smmard.lengthLo),chr$(41)
loc ,44
print "TYPE="
.IF smmard.rangeType == RT_AVAILABLE
print "AVAILABLE"
.ELSEIF smmard.rangeType == RT_RESERVED
print "RESERVED"
.ELSEIF smmard.rangeType == RT_ACPI_RECLAIM
print "ACPI_RECLAIM"
.ELSEIF smmard.rangeType == RT_ACPI_NVS
print "ACPI_NVS"
.ENDIF
; Update the total length.
mov eax,smmard.lengthLo
add memTotal,eax
jmp callLoop
In my code I have tried to preserve ebx by saving it in a variable
storeEBX and later on I am retrieving its value but its not
working. Since I have put my memory map code in a loop, its not
displaying any base address. Earlier it was printing one base address
and its length.
;//portion of memMap code from original file sect8_2.asm
;//Updated by Steve :masm forum
;"Solved the prob of backward printing of the length of region"
;Beyond memMp3: printing the base address & pause & then the offset at different locations
; both visible
; using arguments for print_mesg macro e.g:
; print_mesg MyArg, ScrCoord, 16;
; Entire code of MemMap: Printing the base address and length in a loop
;-------------------------------------------------------------
;ml /c memMp4.asm
;link16 /tiny memMp4.obj,memMp4.bin;
;DEBUG btl5.BIN
;-w 100 0 0 1
;-q
;DEBUG memMp4.BIN
;-w 100 0 1 2
;-q
.MODEL TINY
.386
print_mesg macro offsetStr, offsetScr, msgSize
LOCAL xlat0
mov ax,cs
mov ds,ax
push ax
mov ax,xlat0
push ax
retf
;display the message at B800:50h
xlat0: mov ax,0B800h
mov es,ax
mov di, offsetScr
mov si, offsetStr
cld
mov ah,1Fh
mov cx,msgSize
endm
.CODE
;----------------------------------------------------------------------------------
LoadOfs EQU 0 ;must match the value in the bootloader source file
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
;---------------------- initialize ES segment register
ORG 0
Start: push cs
pop ds
;-----------clear screen
mov ax, 3
int 10h
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
xor di, di
mov ax, 0B800h
mov es, ax
mov si, offset msg0+LoadOfs
mov ah, 41h; attribute byte
cld;
msgloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
jz TimerMesg
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgloop
;---------------------- done - halt; NOT A CLK PROG
TimerMesg:
xor di, di
mov ax, 0B820h
mov es, ax
mov si, offset msgA+LoadOfs
mov ah, 41h; attribute byte
cld;
msgAloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
;jz RTime
jz mem
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgAloop
mov cx, 1000
;DISPLAY_TIMER:
;-------------Find Total Memory
mem: cld
;call FindTotalMem ;calculate total memory (sets the SI register)
mov ah,7 ;display attribute
mov di,0 ;display position
;call Dsply ;display total memory
call do_e820_Step1
;call Qw2Hex by Dave (instead using code provided by Fortran or Steve)
Halt0: hlt
jmp Halt0
Msg0 db "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs db 0
cnt db 0; Its value represents the digits of Timer
s db 0; selector for secs minutes and hrs used in displayCnt
arr db 16 dup(0)
VAL1 db 0
VAL2 db 0
ScrCoord dw 50h ;dx stores the screen location for displaying Base address & region length
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Macro argument
AscBuf db 8 dup (0),' Kb Total Memory',0
mmap_ent dw ?
end_of_list db 1
MyArg EQU <offset arr+LoadOfs>
storeEBX dq 0 ;<<<<<<<<<<<<<<<<<<<<------------------------------------
MMap_Descriptor STRUCT
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DW ? ; * Next dword = Region "type"
ACPI_Attrib DW ? ; * Next dword = ACPI 3.0 Extended Attri
MMap_Descriptor ENDS
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
;---------------do_e820_Step1
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry. This reqd to set last
;dword to 1 before each call
mov ecx, 24 ; ask for 24 bytes
int 15h
mov storeEBX, ebx;<<<<<<<<<<<<<<<<<<<<<-----------------------------
jc short failed ; carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short failed
jmp short jmpin
e8201p:
mov ebx, storeEBX;<<<<<<<<<<<<<<<<---------------------------
mov eax, 0e820h
mov dword ptr es:[di + 20], 1
mov ecx, 24
int 15h
jc short e820f
mov edx, 0534D4150h
jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short skipent
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if the entire
; entry should be ignored
je short skipent
mov ecx, dword ptr es:[di+8]; get lower dword of memory region length; i.e from 8 to 11
test ecx, ecx; ; is the qword=0????
jne short goodent
mov ecx, dword ptr es:[di+12];i.e from 12 to 15
jecxz skipent
goodent:
inc bp
;--------------------------- ;NOTE QW2HEX$ converts to Hex & prints using Macro
call QW2Hex$ ;Displaying the base address
;## You are not pausing after showing the first value before showing the second.
;## And they both print at the same location on screen.
MOV AX,0 ;## Pause?
INT 16H
push di
add di, 8 ;Length of region starts 15 bytes from current val
;In the procedure we adding 7 to di
call QW2Hex$ ;Displaying the length of region
pop di
add di, 24
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
jne short e8201p
;-------------------------
e820f:
mov mmap_ent, bp ; store the entry count
pop es
ret
failed:
stc ; "function unsupported" error exit
pop es
ret
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
PUSH ES
STD ; String instructions decrement.
ADD DI,7 ; Point to last byte, (Intel big end).
; When called 1st DI=0. Now DI =7. So print from 7 to 0. So it pints the Base address
; When called 2nd time DI=8. After adding DI=15. So it prints the length of region
mov si ,offset arr+LoadOfs
MOV CX,8 ; Number of bytes to print. QWORD = 8 bytes
;
QW_1:
MOV AL,ES:[DI] ; Get a byte
DEC DI
CALL TOASCII ; Display as hex.
mov dl, VAL1
mov [si], dl ; store the values in array and display array later
inc si
mov dl, VAL2
mov [si], dl
inc si
LOOP QW_1
;---------------------------Calling Macro with the screen coordinates
;print_mesg MyArg, 50h, 16;
print_mesg MyArg, ScrCoord, 16;<------------------
nextval: lodsb
stosw
loop nextval
POP ES
POP CX
POP AX
POP DI
RET
;---------------------------------------------------
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
mov VAL1, al
;CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
mov VAL2,al
; CALL ConOutByte
POP DX
POP AX
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;----------------------------------------------------------------------------------
END Start
Kindly help me in this regard.
Zulfi.
Hi,
The code of yours that I got working (for one entry) was from
Reply #76. You have moved some code around since then. The
the code that prints the results in particular. The code in the first
posting has the "cure" for the current problem. (I think.) The
problem (on my machine) is currently with this code.
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short skipent
On my machine it now takes the jump (not 24 bytes). So you
need something like this logic from the first posting.
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short .notext
That way you can process ACPI that predates the 3.x speci-
fication.
Regards,
Steve
Hi Steve,
Thanks for your help. I have added the notext code which you told me. Its now showing the 1st region and its length. But its not showing beyond that. Kindly guide me with this problem,
;ml /c memMp5.asm
;link16 /tiny memMp5.obj,memMp5.bin;
;DEBUG btl5.BIN
;-w 100 0 0 1
;-q
;DEBUG memMp5.BIN
;-w 100 0 1 2
;-q
.MODEL TINY
.386
print_mesg macro offsetStr, offsetScr, msgSize
LOCAL xlat0
mov ax,cs
mov ds,ax
push ax
mov ax,xlat0
push ax
retf
;display the message at B800:50h
xlat0: mov ax,0B800h
mov es,ax
mov di, offsetScr
mov si, offsetStr
cld
mov ah,1Fh
mov cx,msgSize
endm
.CODE
;----------------------------------------------------------------------------------
LoadOfs EQU 0 ;must match the value in the bootloader source file
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
;---------------------- initialize ES segment register
ORG 0
Start: push cs
pop ds
;-----------clear screen
mov ax, 3
int 10h
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
xor di, di
mov ax, 0B800h
mov es, ax
mov si, offset msg0+LoadOfs
mov ah, 41h; attribute byte
cld;
msgloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
jz TimerMesg
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgloop
;---------------------- done - halt; NOT A CLK PROG
TimerMesg:
xor di, di
mov ax, 0B820h
mov es, ax
mov si, offset msgA+LoadOfs
mov ah, 41h; attribute byte
cld;
msgAloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
;jz RTime
jz mem
stosw; transfers the contents of al to mem location ptd by es:di
jmp msgAloop
mov cx, 1000
;DISPLAY_TIMER:
;-------------Find Total Memory
mem: cld
;call FindTotalMem ;calculate total memory (sets the SI register)
mov ah,7 ;display attribute
mov di,0 ;display position
;call Dsply ;display total memory
call do_e820_Step1
;call Qw2Hex by Dave (instead using code provided by Fortran or Steve)
Halt0: hlt
jmp Halt0
Msg0 db "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs db 0
cnt db 0; Its value represents the digits of Timer
s db 0; selector for secs minutes and hrs used in displayCnt
arr db 16 dup(0)
VAL1 db 0
VAL2 db 0
ScrCoord dw 50h ;dx stores the screen location for displaying Base address & region length
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< Macro argument
AscBuf db 8 dup (0),' Kb Total Memory',0
mmap_ent dw ?
end_of_list db 1
MyArg EQU <offset arr+LoadOfs>
storeEBX dd 0 ; 32 bits
MMap_Descriptor STRUCT
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DW ? ; * Next dword = Region "type"
ACPI_Attrib DW ? ; * Next dword = ACPI 3.0 Extended Attri
MMap_Descriptor ENDS
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
;---------------do_e820_Step1
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry. This reqd to set last
;dword to 1 before each call
mov ecx, 24 ; ask for 24 bytes
int 15h
mov storeEBX, ebx
jc short failed ; carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne short failed
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je short failed
jmp short jmpin
e8201p:
mov ebx, storeEBX
mov eax, 0e820h
mov dword ptr es:[di + 20], 1
mov ecx, 24
int 15h
jc short e820f
mov edx, 0534D4150h
jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short notext
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if the entire
; entry should be ignored
je short skipent
notext:
mov ecx, dword ptr es:[di+8]; get lower dword of memory region length; i.e from 8 to 11
test ecx, ecx; ; is the qword=0????
jne short goodent
mov ecx, dword ptr es:[di+12];i.e from 12 to 15
jecxz skipent
goodent:
inc bp
;--------------------------- ;NOTE QW2HEX$ converts to Hex & prints using Macro
call QW2Hex$ ;Displaying the base address
;## You are not pausing after showing the first value before showing the second.
;## And they both print at the same location on screen.
MOV AX,0 ;## Pause?
INT 16H
push di
add di, 8 ;Length of region starts 15 bytes from current val
;In the procedure we adding 7 to di
call QW2Hex$ ;Displaying the length of region
pop di
add di, 24
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
jne short e8201p
;-------------------------
e820f:
mov mmap_ent, bp ; store the entry count
pop es
ret
failed:
stc ; "function unsupported" error exit
pop es
ret
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
PUSH ES
STD ; String instructions decrement.
ADD DI,7 ; Point to last byte, (Intel big end).
; When called 1st DI=0. Now DI =7. So print from 7 to 0. So it pints the Base address
; When called 2nd time DI=8. After adding DI=15. So it prints the length of region
mov si ,offset arr+LoadOfs
MOV CX,8 ; Number of bytes to print. QWORD = 8 bytes
;
QW_1:
MOV AL,ES:[DI] ; Get a byte
DEC DI
CALL TOASCII ; Display as hex.
mov dl, VAL1
mov [si], dl ; store the values in array and display array later
inc si
mov dl, VAL2
mov [si], dl
inc si
LOOP QW_1
;---------------------------Calling Macro with the screen coordinates
;print_mesg MyArg, 50h, 16;
print_mesg MyArg, ScrCoord, 16;<------------------
nextval: lodsb
stosw
loop nextval
POP ES
POP CX
POP AX
POP DI
RET
;---------------------------------------------------
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
mov VAL1, al
;CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
mov VAL2,al
; CALL ConOutByte
POP DX
POP AX
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;----------------------------------------------------------------------------------
END Start
Zulfi.
Hi Zulfi,
Okay. I went and tried to follow what you were trying to do
and minimally fix it up. It is (more or less) working now (for me).
I can see if you need to reboot for each change, it would take
a while to progress. You should be able to clean things up from
here I think. A bunch of changes were only reformatting, as I
looked at the code. That was only to help me debug things
quicker. Look for ## marking most of the real changes. And
if something does not make sense to you, ask, I may have
torpedoed it.
Tested as both a separate boot and as a DOS COM program.
If in doubt, hit a key... Enjoy!
HTH,
Steve N.
PAGE ,132
; DeadNDave/Zulfi/zak100 code from 26 June 2010, MASM32 forum.
; 27 June 2010, Mods by FORTRANS/Steve N. {Idiosyncratic formatting & fixes.}
; Look for ##.
;ml /c memMp5.asm
;link16 /tiny memMp5.obj,memMp5.bin;
;DEBUG btl5.BIN
;-w 100 0 0 1
;-q
;DEBUG memMp5.BIN
;-w 100 0 1 2
;-q
.MODEL TINY
.386
print_mesg macro offsetStr, offsetScr, msgSize
LOCAL xlat0
mov ax,cs
mov ds,ax
; push ax ; ## ??
; mov ax,xlat0
; push ax
; retf
;display the message at B800:50h
xlat0: mov ax,0B800h
mov es,ax
mov di, offsetScr
mov si, offsetStr
cld
mov ah,1Fh
mov cx,msgSize
endm
DOSish EQU 0 ; ## EQUate = 1 to use DEBUG in a VDM, 0 = BootLoader...
.CODE
;----------------------------------------------------------------------------------
;IF DOSish? Okay, what was Dave doing? ##?
LoadOfs EQU 0 ;must match the value in the bootloader source file
LoadSeg EQU 1000h
;----------------------------------------------------------------------------------
IF DOSish ; ## DEBUGing?
ORG 100H ; DOS COM file load point.
ELSE
ORG 0 ; deadndave load point.
ENDIF
;---------------------- initialize DS segment register
Start: push cs
pop ds
;-----------clear screen
mov ax, 3
int 10h
;---------------------- writing a message on screen at startup, character by character- we can't use int 21h
overdata:
xor di, di
mov ax, 0B800h
mov es, ax
mov si, offset msg0+LoadOfs
mov ah, 41h ; attribute byte
cld
msgloop:
lodsb; loads al with a byte of data pted by ds:si
or al, al
jz SHORT TimerMesg
stosw ; transfers the contents of al to mem location ptd by ES:DI
jmp msgloop
;---------------------- done - halt; NOT A CLK PROG
TimerMesg:
xor di, di
mov ax, 0B820h
mov es, ax
mov si, offset msgA+LoadOfs
mov ah, 41h ; attribute byte
cld
msgAloop:
lodsb ; loads al with a byte of data pted by DS:SI
or al, al
;jz RTime
jz SHORT mem
stosw ; transfers the contents of al to mem location ptd by es:di
jmp msgAloop
;DISPLAY_TIMER:
;-------------Find Total Memory
mem:
cld
;call FindTotalMem ;calculate total memory (sets the SI register)
mov ah,7 ;display attribute
mov di,0 ;display position
;call Dsply ;display total memory
call do_e820_Step1
;call Qw2Hex by Dave (instead using code provided by Fortran or Steve)
Halt0:
IF DOSish
MOV AH,04CH ; DOS 2+ Exit.
INT 21H
ELSE
HLT
JMP Halt0
ENDIF
Msg0 db "We be bootin234!",0
msgA db 'Total minutes elapsed since Kernel start is',0
clkcounter db 0
secs db 0
mins db 0
hrs db 0
cnt db 0 ; Its value represents the digits of Timer
s db 0 ; selector for secs minutes and hrs used in displayCnt
arr db 16 dup(0)
VAL1 db 0
VAL2 db 0
ScrCoord dw 50h ; dx stores the screen location for displaying Base address & region length
; Macro argument
AscBuf db 8 dup (0),' Kb Total Memory',0
mmap_ent dw ?
end_of_list db 1
MyArg EQU <offset arr+LoadOfs>
storeEBX dd 0 ; 32 bits
MMap_Descriptor STRUC ; Old MASM
BaseAddress DQ ? ; * First qword = Base address
ByteLength DQ ? ; * Second qword = Length of "region"
RangeType DD ? ; * Next dword = Region "type" ##
ACPI_Attrib DD ? ; * Next dword = ACPI 3.0 Extended Attri ##
MMap_Descriptor ENDS
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
;---------------do_e820_Step1
do_e820_Step1:
push es
push cs
pop es
mov di, offset call15_1+LoadOfs
xor ebx, ebx ; ebx must be 0 to start
xor bp, bp ; keep an entry count in bp
mov edx,0534D4150h ; Place "SMAP" into edx
mov eax, 0e820h
mov dword ptr es:[di + 20], 1 ; force a valid ACPI 3.X entry. This reqd to set last
;dword to 1 before each call
mov ecx, 24 ; ask for 24 bytes
int 15h
mov storeEBX, ebx
jc failed ;## carry set on first call means "unsupported function"
mov edx, 0534D4150h ; Some BIOSes apparently trash this register?
cmp eax, edx ; on success, eax must have been reset to "SMAP"
jne failed ; ## as above, now is out of range...
test ebx, ebx ; ebx = 0 implies list is only 1 entry long (worthless)
je failed ; ## as above, now is out of range...
jmp short jmpin
e8201p:
CMP BP,5 ;## Oh yeah. Prevent buffer overflow.
JAE E820F
mov ebx, storeEBX
MOV EDX,0534D4150H ; ## Place "SMAP" into EDX
mov eax, 0e820h
mov dword ptr es:[di + 20], 1
mov ecx, 24
int 15h
jc short e820f
MOV [storeEBX],EBX ; ##
mov edx, 0534D4150h
jmpin:
jcxz skipent ; skip any 0 length entries
cmp cl, 20 ; got a 24 byte ACPI 3.X response?
jbe short notext
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if
; the entire entry should be ignored
je short skipent
notext:
mov ecx, dword ptr es:[di+8]; get lower dword of memory region length; i.e from 8 to 11
test ecx, ecx; ; is the qword=0????
jne short goodent
mov ecx, dword ptr es:[di+12] ; i.e from 12 to 15
jecxz skipent
goodent:
inc bp
;--- ;NOTE QW2HEX$ converts to Hex & prints using Macro
call QW2Hex$ ;Displaying the base address
ADD [ScrCoord],40 ; ## Move print region.
;## You are not pausing after showing the first value before showing the second.
;## And they both print at the same location on screen.
MOV AX,0 ;## Pause?
INT 16H
push di
add di, 8 ;Length of region starts 15 bytes from current val
;In the procedure we adding 7 to di
call QW2Hex$ ;Displaying the length of region
pop di
add di, 24
ADD [ScrCoord],120 ; ## Move print region.
skipent:
test ebx, ebx ; if ebx resets to 0, list is complete
jne short e8201p
;-------------------------
e820f:
mov mmap_ent, bp ; store the entry count
pop es
CLC
ret
failed:
stc ; "function unsupported" error exit
pop es
ret
QW2Hex$:
PUSH DI ; Save registers used by routine.
PUSH AX
PUSH CX
PUSH ES
STD ; String instructions decrement.
ADD DI,7 ; Point to last byte, (Intel big end).
; When called 1st DI=0. Now DI=7. So print from 7 to 0. So it prints the Base address
; When called 2nd time DI=8. After adding DI=15. So it prints the length of region
mov si,offset arr+LoadOfs
MOV CX,8 ; Number of bytes to print. QWORD = 8 bytes
;
QW_1:
MOV AL,ES:[DI] ; Get a byte
DEC DI
CALL TOASCII ; Display as hex.
mov dl, VAL1
mov [si], dl ; store the values in array and display array later
inc si
mov dl, VAL2
mov [si], dl
inc si
LOOP QW_1
;--- Calling Macro with the screen coordinates
;print_mesg MyArg, 50h, 16;
print_mesg MyArg, ScrCoord, 16;<------------------
nextval: lodsb
stosw
loop nextval
POP ES
POP CX
POP AX
POP DI
RET
;---------------------------------------------------
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; This routine converts the one byte binary number in the
; AL register into its hexadecimal ASCII representation and
; prints these two bytes to the standard output or console.
; 4 March 2010,
; Changed TOASCII routine to use AAM varient instead of MOV,
; AND, and SHR codes on nybbles.
TOASCII:
PUSH AX ; Make safer for debugging.
PUSH DX
XOR AH,AH ; Clear AH for AAM using base 16.
DB 0D4H, 10H ; Isolates high nybble in AH and low
; nybble in AL.
PUSH AX ; Save low nybble.
MOV AL,AH ; And process high digit first.
CMP AL,10 ; Convert to ASCII hex using "magic".
SBB AL,69H
DAS
MOV DL,AL
mov VAL1, al
;CALL ConOutByte ; DOS Fn 2 or BIOS 10H Fn 0EH (or whatever).
POP AX ; Retrieve low digit in AL.
CMP AL,10 ; Convert to ASCII hex.
SBB AL,69H
DAS
MOV DL,AL
mov VAL2,al
; CALL ConOutByte
POP DX
POP AX
RET
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;----------------------------------------------------------------------------------
END Start
Hi,
Thanks for your reply. I have not yet tested it but just to inform you that I am about to start working on it, I am writing this. I have made a quick look at it and I am not to able to digest the indirect addressing with storeEBX.
There maybe other Qs which I would ask you once I have gone through the code thoroughly.
Thanks for making it workable and signifying the changes.
Zulfi.
Hi,
It is not indirect addressing. It is part of my idiosyncratic
formatting that I warned about.
MOV [storeEBX],EBX
mov storeEBX, ebx
These produce the exact same code. I like using the brackets
to indicate storage to a variable. Some assemblers do produce
different code for the above (i.e. NASM). But not MASM. Just
my habit.
Regards,
Steve N.
Hi Steve,
Thanks for this explanation.
Zulfi.
Hi,
Thanks Steve. Its working now. I got following 5 regions with base addresses and lengths:
0000 0000 0000 0000 0000 0000 0009 F400
0000 0000 0009 F400 0000 0000 0000 0C00
0000 0000 000F 0000 0000 0000 0001 0000
0000 0000 0010 0000 0000 0000 1F5E 0000
0000 0000 1F6E 0000 0000 0000 0000 3000
Thanks for formatting.
Let me know about the correctness of this result.
Zulfi.
Hi,
Glad it works for you. Your results look good as well. But
when I compare that to some of my computers, it looks as
if you should alter the program to print out more memory
blocks. If you look at the six or seven regions in Reply #102,
you will see a region starting at FFFF 0000 and the same
length as the block at 000F 0000. Those should be the
computer's BIOS regions. You are not showing both of
those regions yet. You could look at the results there
to see what else you mayl want your program to print out
Cheers,
Steve N.
Hi,
Thanks Steve for guiding me upto this point and for pointing out the regions not being printed. I would try to look at this problem first before going into the details of other stuff shown in those sample printouts (reply#102). Right now I have no clue why those regions were left out.
Zulfi.
Hi,
They were left out as you only defined five buffers for
the data returned by the interrupt. If you call that
interrupt more than that, you crash the program as you
overwrite the executing progam. (Quick guess how I
found that out.) I then put in a test to prevent that
from happening.
CMP BP,5 ;## Oh yeah. Prevent buffer overflow.
JAE E820F
Regards,
Steve N.
Hi Steve,
I am now getting following 9 regions:
0000 0000 0000 0000 0000 0000 0009 F400
0000 0000 0009 F400 0000 0000 0000 0C00
0000 0000 000F 0000 0000 0000 0001 0000
0000 0000 0010 0000 0000 0000 1F5E 0000
0000 0000 1F6E 0000 0000 0000 0000 3000
0000 0000 1F6E 3000 0000 0000 0000 D000
0000 0000 1F6F 0000 0000 0000 0001 0000
0000 0000 E000 0000 0000 0000 0800 0000
0000 0000 FEC0 0000 0000 0000 0140 0000
I cant see the BIOS region.
I tried with 12 buffers:
Call15_1 MMap_Descriptor <> ; Set DI to point to the first one, and
Call15_2 MMap_Descriptor <> ; increment by 24 to point to second.
Call15_3 MMap_Descriptor <>
Call15_4 MMap_Descriptor <>
Call15_5 MMap_Descriptor <>
call15_6 MMap_Descriptor <>
call15_7 MMap_Descriptor <>
call15_8 MMap_Descriptor <>
call15_9 MMap_Descriptor <>
call15_0 MMap_Descriptor <>
call15_A MMap_Descriptor <>
call15_B MMap_Descriptor <>
and the comparison code is given below:
CMP BP,12 ;## Oh yeah. Prevent buffer overflow.
;Total buffers=8, last one is:
;call15_8 MMap_Descriptor <>
JAE E820F
But its not going beyond 9. Is it the maximum number of regions??
My other prob. is non-printing of BIOS regions.
Kindly guide me in this regard. I appreciate your help and guidance.
Zulfi.
I have not been keeping up with this thread, but on some (probably older) systems the BIOS is duplicated in E block and F block, for example:
BASE=00000000H LENGTH=0009F800 (653312) TYPE=AVAILABLE
BASE=0009F800H LENGTH=00000800 (2048) TYPE=RESERVED
BASE=000E0000H LENGTH=00020000 (131072) TYPE=RESERVED
BASE=00100000H LENGTH=0FF00000 (267386880) TYPE=AVAILABLE
Also, if the goal is to assemble the entire map in memory, it should be possible to count the number of blocks in the first pass, allocate the required memory, then make another pass to read the information into the allocated memory.
Hi,
QuoteI cant see the BIOS region.
Well, you got the one at 000F 000. All the machines I have
tested have had one at FFFF 0000. Most of those were older
machines though. You could put in some checks to see if it
was skipped by the code as it does make some checks.
test byte ptr es:[di + 20], 1 ; if so: is the "ignore this data" bit clear?
;Bit 0 of the extended Attributes indicates if
; the entire entry should be ignored
je short skipent
That seems unlikely, but you could comment out the JE line
and see what happens.
I have heard of some BIOS'es hiding parts of the BIOS after
it boots up, but have no further information about that. So if
that is all that are reported, that is probably all there is.
Cheers
Steve
Hi,
Modifying the code to increase the number of records, I got
same seven regions on my machine. So I think things are
working okay on my machine.
Steve N.
Hi Steve,
Thanks for your reply.
If I am getting 9 regions, is it wrong?
Zulfi.
Hi,
Your results look reasonable. The program works on my
machine. So, probably not wrong.
Steve
Hi,
Thanks for your reply. I feel that the number of regions depend upon the amount of memory (RAM). If I have more memory, I can even get more than nine regions???
Zulfi.