flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Re-Start...

Author
Thread Post new topic Reply to topic
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 21 Sep 2014, 14:55
Hi All,

It has been a long time since I delved into playing with my OS: http://board.flatassembler.net/topic.php?t=5911

Recently I've made a lot of learning progress on my approach, which had been through a method of going form protected mode back to real mode in order to use BIOS interrupts, but alas, since 64 bit machines are more prevalent now, I figured it was time to work out the use of i/o ports to do the things I wish within my OS. In getting to this point I have worked out PCI enumeration and can get to my mass storage controller (listed as an IDE controller, but really is a SATA controller). Reading the BARs I get these I/O ports:
Code:
BAR0=0000DC01
BAR1=0000D881
BAR2=0000D801
BAR3=0000D481
BAR4=0000D401    


These are not all of the I/O ports associated with my controller, as a comparison, using Windows System Information I/O there are a total of 16 I/O ports list, the five above are a part of that listing. In reading a ton of SATA, AHCI, and IDE materials I am not finding a mechanism to find those other ports (ala the other ports do contain two HDDs and a BD). For now I have hard coded the ports in and I can interface with the drives, ID them, etcetera, but would like to know a mechanism to retrieving the rest of the I/O ports. Can anyone point me to where I might find this information?

My current list of references:
http://wiki.osdev.org/ATA_PIO_Mode
http://wiki.osdev.org/PCI_IDE_Controller
https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0CB4QFjAA&url=http%3A%2F%2Fwww.knowledgetek.com%2FgraphicsNew%2FSerialATA_Revision_3_2_Gold(with%2520Links).pdf&ei=teUeVK3TNdSfyATDuoGgDg&usg=AFQjCNH3729CdfXFzM4spoIYeJBfF25dHA&sig2=cE2L2B1_3HvkYrWJCzdm_g&bvm=bv.75775273,d.b2U
82801eb-82801er-serial-ata-manual.pdf
serial-ata-ahci-spec-rev1-3-1.pdf

I have also search within OS Construction and the returned items do not cover what to do if your controller has more than 5 I/O ports (BTW, according to one document BAR4 is supposed to be bus mastering, whatever that means, perhaps that is the BAR I need to manipulate to derive the rest of the ports?).

Thanks in advance for any ideas, assistance,

Smiddy
Post 21 Sep 2014, 14:55
View user's profile Send private message Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 21 Sep 2014, 15:26
the PCI Configuration Space can

1) include multiple controllers which can account for your other drives.
2) an ATA Controller can have a "Slave" drive that is effectively hidden. in order to access it you have to write the "Drive bit" in one of the control registers.
3) there is also the possibility that the controller is an AHCI controller.

BAR4 is the address of a collection of IO ports that allows you to use hardware that is equivalent to DMA. the Command Register is the word at offset 0, the Status Register is the word at offset 2, and finally the address of the PRD (Physical Region Descriptor table base address within system memory) is the DWORD at offset 4.

I wrote a PCI Enumerator and an ATA driver so I've been through what your doing.

- Stefan

_________________
byte me.
Post 21 Sep 2014, 15:26
View user's profile Send private message Visit poster's website Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 21 Sep 2014, 16:19
Thanks!

I think I may have stumbled onto it, but it is NOT clear.

My controller is defined as 01h class code 01h subclass, which is NOT AHCI (01h and 06h respectively). However, in BAR5 there is an address which I believe contain the HBA memory registers, with the Port 0 offset at 100h. I will review that memory locale shortly. If at each 100h locale are the I/O port, I think I figured it out.

To answer your points:

1) yeah, only one shows up (if configured in BIOS), 01h class and 01h subclass even when forcing AHCI.
2) Yep, I can access the masters (no slave installed, but have IDE code to ID them if they were)
3) See 1) above. LOL!

I find it pretty confusing because it isn't very clear cut.

Smiddy
Post 21 Sep 2014, 16:19
View user's profile Send private message Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 21 Sep 2014, 17:00
I played with my BIOS some and it seems that the actual controller my HDDs and BD are on is hidden from PCI enumeration. No 01h Class present. In this case what do you do? Man this is frustrating...


Windows 7 64 bit sees them fine, but I suspect maybe it is using ACPI to determine if installed. I was hoping to avoid that. Sad
Post 21 Sep 2014, 17:00
View user's profile Send private message Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 21 Sep 2014, 17:51
I've never seen this situation with IDE drives. I have, however, seen it with Floppy controllers and the PnP enumeration technique. perhaps your enumerator isn't accounting for the type of controller that is present. have you written a "dumping" routine that prints all of the controllers available?

- Stefan

_________________
byte me.
Post 21 Sep 2014, 17:51
View user's profile Send private message Visit poster's website Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 21 Sep 2014, 20:09
Yep, that is essentially what I've done first, hit ever bus...get the installed devices. There are no mass storage devices present (01h Class). Sad If I hard code the ports though I can interface with them.
Post 21 Sep 2014, 20:09
View user's profile Send private message Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 21 Sep 2014, 20:12
Code:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; PCI.ASM - Devloped to test things:
;;
;; To Assemble: fasm pci.asm
;;
;; 1.00.0 - Initial release. Going to work on PCI devices
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    format  MZ                      ; For FASM EXE format
    entry   main:BeginPCI           ; Entry is into the main segment, just below

    segment main use16

BeginPCI:

    jmp Start

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Program data items
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ProgramMessage          db 13,10,'PCI - 1.00.0 Testing PCI Stuff... -smiddy',13,10,13,10,0
RebootMessage           db 13,10,'Press any key to reboot...',13,10,0

TheEndOfLine            db 13,10,0
TheSpace                db ' ',0
ThePort                 db 'Port: ',0
TypeHeaderMessage       db 'Type X Header',0
NumberToConvert         dd 1,2,3        ; 96-bit Number

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; This is the start of the pragram
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Start:

    mov ax,9000h                         ; Set up stack
    mov ss,ax
    mov sp,9500h                         ; Stack pointer setup
    mov ax,cs                            ; Setup the rest of the segment registers
    mov ds,ax
    mov es,ax
    mov fs,ax
    mov gs,ax
    mov [CodeSegment],ax                 ; Save current codesegment for decisions later

    mov si,ProgramMessage                ; Load program message
    call PrintString                     ; Display welcome message

    call PCIDump                         ; Calls the testing function to run

    cmp [CodeSegment],0202h              ; Compare for booted executeable
    je .Reboot                           ; Yes, go to reboot routine

    mov ax,4C00h                         ; Terminate program if in DOS
    int 21h                              ; DOS interrupt call

.Reboot:

    mov si,RebootMessage                 ; Load reboot message into SI
    call PrintString

    mov ax,0                             ; Load INT 16h get key function
    int 16h                              ; BIOS interrupt call

    db 0EAh                              ; Machine language to jump to
                                         ;    address FFFF:0000 (reboot)

    dw 0
    dw 0FFFFh                            ; No return required
                                         ;    we're rebooting!

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; PCIDump - Dump all Device and Vendor ID's to the screen
;;
;;   IN:  Nothing
;;  OUT:  Nothing, All registers preserved
;; http://pci-ids.ucw.cz/read/PC/ - Online list of Device and Vendor ID's
;;
;; Configuration Mechanism One has two IO port rages associated with it.
;; The address port (0xcf8-0xcfb) and the data port (0xcfc-0xcff).
;; A configuration cycle consists of writing to the address port to specify which device and register you want to access and then reading or writing the data to the data port.

PCI_CONFIG_ADDRESS      EQU     0x0CF8
PCI_CONFIG_DATA         EQU     0x0CFC

;; address dd 10000000000000000000000000000000b
;;            /\     /\      /\   /\ /\    /\
;;          E    Res    Bus    Dev  F  Reg   0
;;  Bits
;;  31            Enable bit = set to 1
;;  30 - 24       Reserved = set to 0
;;  23 - 16       Bus number = 256 options
;;  15 - 11       Device/Slot number = 32 options
;;  10 - 8        Function number = will leave at 0 (8 options)
;;   7 - 2        Register number = will leave at 0 (64 options) 64 x 4 bytes = 256 bytes worth of accessible registers
;;   1 - 0        Set to 0
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PCIDump:

    push edx
    push ecx
    push ebx
    push eax

    xor ecx, ecx
    xor eax, eax

    mov ecx, 0x80000000             ; Bit 31 must be set

.CheckNext:

    mov byte [NumberOfRegisters],0
    mov eax, ecx
    mov dx, PCI_CONFIG_ADDRESS
    out dx, eax
    mov dx, PCI_CONFIG_DATA
    in eax, dx                      ; EAX now holds the Device and Vendor ID
    cmp eax, 0xffffffff             ; 0xFFFFFFFF means no device present on that Bus and Slot
    je .NothingThere
    push ecx                        ; Save counter ECX
    push eax                        ; Save EAX for second use
    mov eax,ecx                     ; Put counter into ToHex for displaying
    mov cl,32
    call ToHex
    mov si,HexBuffer
    call PrintString
    mov si,TheSpace
    call PrintString
    pop eax                         ; Restore resulting EAX, show Device ID and Vendor ID
    mov cl,32
    call ToHex
    mov si,HexBuffer
    call PrintString
    mov si,TheSpace
    call PrintString
    pop ecx
    push ecx
    mov eax,ecx
    mov al,08h                       ; Get register 8's data
    mov dx, PCI_CONFIG_ADDRESS
    out dx, eax
    mov dx, PCI_CONFIG_DATA
    in eax,dx
    mov cl,32
    call ToHex
    mov si,HexBuffer
    call PrintString
    mov si,TheSpace
    call PrintString
    pop ecx
    push ecx
    mov eax,ecx
    mov al,0Ch                       ; Lets see what type of header we have from register C
    mov dx, PCI_CONFIG_ADDRESS
    out dx, eax
    mov dx, PCI_CONFIG_DATA
    in eax,dx
    and eax,0FF0000h                 ; Just want to check bits 23 - 16
    shr eax,16
    cmp al,2
    je .Type02
    cmp al,1
    je .Type01
    jmp .Type00

.Type02:

    mov byte [TypeHeaderMessage+5],'2'
    mov si,TypeHeaderMessage
    call PrintString
    mov si,TheEndOfLine
    call PrintString
    pop ecx
    jmp .NothingThere

.Type01:

    mov byte [TypeHeaderMessage+5],'1'
    mov si,TypeHeaderMessage
    call PrintString
    mov si,TheEndOfLine
    call PrintString
    pop ecx
    jmp .NothingThere

.Type00:

    pop ecx
    push ecx
    mov eax,ecx
    mov al,10h                        ; Register 10h
    mov dx, PCI_CONFIG_ADDRESS
    out dx, eax
    mov dx, PCI_CONFIG_DATA
    in eax,dx
    cmp eax,0
    je .Type00p2
    mov cl,32
    call ToHex
    mov si,HexBuffer
    call PrintString
    mov si,TheSpace
    call PrintString
    inc byte [NumberOfRegisters]

.Type00p2:

    pop ecx
    push ecx
    mov eax,ecx
    mov al,14h                        ; Register 14h
    mov dx, PCI_CONFIG_ADDRESS
    out dx, eax
    mov dx, PCI_CONFIG_DATA
    in eax,dx
    cmp eax,0
    je .Type00p3
    mov cl,32
    call ToHex
    mov si,HexBuffer
    call PrintString
    mov si,TheSpace
    call PrintString
    inc byte [NumberOfRegisters]

.Type00p3:

    pop ecx
    push ecx
    mov eax,ecx
    mov al,18h                        ; Register 18h
    mov dx, PCI_CONFIG_ADDRESS
    out dx, eax
    mov dx, PCI_CONFIG_DATA
    in eax,dx
    cmp eax,0
    je .Type00p4
    mov cl,32
    call ToHex
    mov si,HexBuffer
    call PrintString
    mov si,TheSpace
    call PrintString
    inc byte [NumberOfRegisters]

.Type00p4:

    pop ecx
    push ecx
    mov eax,ecx
    mov al,1Ch                        ; Register 1Ch
    mov dx, PCI_CONFIG_ADDRESS
    out dx, eax
    mov dx, PCI_CONFIG_DATA
    in eax,dx
    cmp eax,0
    je .Type00p5
    mov cl,32
    call ToHex
    mov si,HexBuffer
    call PrintString
    mov si,TheSpace
    call PrintString
    inc byte [NumberOfRegisters]

.Type00p5:

    pop ecx
    push ecx
    mov eax,ecx
    mov al,20h                        ; Register 20h
    mov dx, PCI_CONFIG_ADDRESS
    out dx, eax
    mov dx, PCI_CONFIG_DATA
    in eax,dx
    cmp eax,0
    je .Type00p6
    mov cl,32
    call ToHex
    mov si,HexBuffer
    call PrintString
    mov si,TheSpace
    call PrintString
    inc byte [NumberOfRegisters]

.Type00p6:

    pop ecx
    push ecx
    mov eax,ecx
    mov al,24h                        ; Register 24h
    mov dx, PCI_CONFIG_ADDRESS
    out dx, eax
    mov dx, PCI_CONFIG_DATA
    in eax,dx
    cmp eax,0
    je .Type00pFinishLine
    mov cl,32
    call ToHex
    mov si,HexBuffer
    call PrintString
    cmp byte[NumberOfRegisters],5
    je .Type00p7

.Type00pFinishLine:

    mov si,TheEndOfLine
    call PrintString

.Type00p7:

    pop ecx                         ; Repopulate ECX counter

.NothingThere:

    add ecx, 0x800
    cmp ecx, 0x81000000             ; The end has been reached (already looked at 8192 devices)
    jne .CheckNext

.DumpDevicesEnd:

    pop eax
    pop ebx
    pop ecx
    pop edx

    ret

; -----------------------------------------------------------------------------
; os_pci_read_reg -- Read a register from a PCI device
;  IN:  BL  = Bus number
;       CL  = Device/Slot/Function number
;       DL  = Register number
; OUT:  EAX = Register information
;       All other registers preserved
PCIReadReg:

    push edx
    push ecx
    push ebx

    shl ebx, 16                     ; Move Bus number to bits 23 - 16
    shl ecx, 8                      ; Move Device/Slot/Fuction number to bits 15 - 8
    mov bx, cx
    shl edx, 2
    mov bl, dl
    and ebx, 0x00ffffff             ; Clear bits 31 - 24
    or ebx, 0x80000000              ; Set bit 31
    mov eax, ebx
    mov dx, PCI_CONFIG_ADDRESS
    out dx, eax
    mov dx, PCI_CONFIG_DATA
    in eax, dx

    pop ebx
    pop ecx
    pop edx

    ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Dumps DS:SI to the screen using video BIOS call or DOS call
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

PrintString:

    pusha

.DoItAgain:

    lodsb                          ; Load byte at DS:SI into AL
    or al,al                       ; Test if character is 0
                                   ;    (end of string)
    jz .Done                       ; Go to Done if Zero

    cmp [CodeSegment],0202h        ; Did we boot this puppy?
    jne .DOS                       ; No, then do DOS routine

    ;;;;;;;;;;;;;;;;;;;;;;;
    ;; BIOS Print Character
    ;;;;;;;;;;;;;;;;;;;;;;;

.BIOS:

    mov ah,0Eh                     ; Put character on screen at the
                                   ;    currrent cursor location
    mov bx,7                       ; Video attribute for the character
    int 10h                        ; Call BIOS

    jmp .DoItAgain

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; DOS Print Character (added to use pipes)
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

.DOS:

    mov dl,al                      ; Put character into DL
    mov ah,2                       ; Output Character (Interrupt 21h, service 2)
    int 21h

    jmp .DoItAgain

.Done:

    popa

    ret                            ; Return to caller

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ToHex
;; Loads HexBuffer with ASCII corresponding to 8, 16, or 32 bit interger in hex.
;; Requires interger in AL, AX, or EAX depending on bit size
;; Requires the number of bits in the CL
;; Returns a full buffer or an empty buffer on error
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ToHex:

    pusha

    MOV BX,0                                ; Load BX with pointer offset
    MOV edx,EAX                             ; Save the EAX to EDX
    CMP CL,8                                ; Check for 8 bits
    JNE .Check16
    JMP .ConverterLoop                      ; Start loading the buffer

.Check16:

    CMP CL,10h                              ; Check for 16 bits
    JNE .Check32
    JMP .ConverterLoop                      ; Start loading the buffer

.Check32:

    CMP CL,20h                              ; Check for 32 bits
    JNE .ErrorBits

.ConverterLoop:

    MOV EAX,edx                             ; Reload EAX with the converter
    SUB CL,4                                ; Lower bit count by 4 bits
    SHR EAX,CL

    AND AL,0Fh
    ADD AL,'0'
    CMP AL,'9'
    JBE .LoadBuffer
    ADD AL,'A'-'0'-10                       ; Convert to "A" to "F"

.LoadBuffer:

    MOV [HexBuffer + BX],AL                 ; Load buffer with AL
    INC BX                                  ; Increment buffer pointer
    CMP CL,0                                ; Check if we're done
    JNE .ConverterLoop                              ; Do next byte

.ErrorBits:

    MOV byte [HexBuffer + BX],0             ; End the string with a zero

    popa

    RET

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; StringLength:
;;
;;  Assumes string start at ES:EDI
;;
;;  Returns the string length in the ECX
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

StringLength:

    push edi
    push eax

    sub ecx,ecx
    sub al,al
    not ecx
    cld
    repne scasb
    not ecx
    dec ecx

    pop eax
    pop edi

    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; AddCommas:
;;
;;  Assumes string start at DS:ESI (currently assumes that DecimalBuffer is used)
;;
;;  Populates CommasBuffer with at most three extra commas
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

NumberOfCommas     dd 0
TheCommasMessage   db 'The number of commas = ',0
NumberOfCharacters dd 0
TheCharactersMessage db 'The number of characters left to display = ',0
TheStringLength    dd 0
StringLengthMessage db 'The string length is = ',0

AddCommas:

    push eax
    push ebx
    push ecx
    push edx

    mov ecx,0

    mov ecx,0                        ; Initialize ECX
    mov edi,DecimalBuffer            ; Load non-comma'd buffer
    call StringLength                ; Get the length of the string in ECX

    mov [TheStringLength],ecx        ; Save the String's length for use later
    mov edx,0                        ; Initialize EDX to 0, for division
    mov eax,ecx                      ; Load accumulator with length
    mov ebx,3                        ; load up the divisor to do modula
    div ebx                          ; Divide by 3, get the integer result in EAX (number of commas),
                                     ; and remainder in EDX (number of characters before a comma)
                                     ; EAX contains the number of commas

    mov [NumberOfCommas],eax
    mov [NumberOfCharacters],edx

    mov ebx,0                        ; EBX is use to count up the DecimalBuffer
    mov ecx,0                        ; ECX is now use to count up the CommaBuffer
    cmp edx,0                        ; If EDX is zero, then
    je .ReduceCommas                 ; We need to reduce the number of commas
                                     ; Otherwise we start the addition of commas process

.LoopThroughCommas:

    dec edx                          ; Remove a character to add
    mov al,[DecimalBuffer+ebx]       ; Get a character to copy to CommaBuffer
    mov [CommaBuffer+ecx],al         ; Add to CommaBuffer
    inc ebx                          ; Next character
    inc ecx                          ; Next character
    cmp edx,0
    je .AddComma                     ; If EDX = 0 then we add a comma
    jmp .LoopThroughCommas           ; Do it again

.AddComma:

    mov byte [CommaBuffer+ecx],','   ; Add comma
    inc ecx                          ; Next character, a comma

.ReduceCommas:

    mov edx,3                        ; Reset number of characters to move
    dec byte [NumberOfCommas]        ; Reduce number of commas left by one
    jnz .LoopThroughCommas           ; Not clean, then loop again

.OverAlgo:

    mov al,[DecimalBuffer+ebx]       ; Get a character to copy to CommaBuffer
    mov [CommaBuffer+ecx],al         ; Add to CommaBuffer
    mov al,[DecimalBuffer+ebx+1]     ; Get a character to copy to CommaBuffer
    mov [CommaBuffer+ecx+1],al       ; Add to CommaBuffer
    mov al,[DecimalBuffer+ebx+2]     ; Get a character to copy to CommaBuffer
    mov [CommaBuffer+ecx+2],al       ; Add to CommaBuffer
    mov al,0                         ; Get set to end the string in CommaBuffer
    mov [CommaBuffer+ecx+3],al          ; Add to CommaBuffer

.Done:


    pop edx
    pop ecx
    pop ebx
    pop eax

    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; AddForwardSpaces:
;;
;;  Assumes string start at ES:EDI, total length in EAX
;;
;;  Prints forward spaces to the screen given total length in EAX
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

AddForwardSpaces:

    push edi
    push esi
    push eax
    push ecx

    call StringLength
    cmp eax,ecx
    jbe .Done                   ; If less or equal than total length, nothing to do.

.MainLoop:

    mov si,TheSpace
    call PrintString

    inc ecx
    cmp eax,ecx
    ja .MainLoop

.Done:

    pop ecx
    pop eax
    pop esi
    pop edi

    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NewToDecimal - Used to convert 96 bit DS:ESI value to decimal placing the decimal string
;;                into DecimalBuffer.
;;
;; Uses 96-bit from DS:ESI as input
;;
;; Updates DecimalBuffer with ascii representation of decimal numbers.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

NewToDecimal:

    pusha                        ; Save the registers so we can restore them

    mov eax,[DS:ESI]             ; Grab the first bits upto 32
    mov [BigNumber],eax          ; Load variable upto 32-bits
    mov eax,[DS:ESI+4]           ; Grab the middle bits up to 64
    mov [BigNumber+4],eax        ; Load varible upto 64-bits
    mov eax,[DS:ESI+8]           ; Grab the last bits up to 96
    mov [BigNumber+8],eax        ; Load variable upto 96-bits
    mov edx,0                    ; Initialize remainder
    mov ebx,10                   ; Divisor of 10
    mov ecx,0                    ; Initialize character counter

.LoopBigNumber8:

    mov eax,[BigNumber+8]        ; Load in top 32 bits
    div ebx                      ; Divide by 10
    mov [BigNumber+8],eax        ; Save the result, and the remainder is in the EDX

.LoopBigNumber4:

    mov eax,[BigNumber+4]        ; Load in the middle 32 bits
    div ebx                      ; Divide by 10
    mov [BigNumber+4],eax        ; Save the result, and the remainder is in the EDX

.LoopBigNumber:

    mov eax,[BigNumber]          ; Load in the last 32 bits
    div ebx                      ; Divide by 10
    mov [BigNumber],eax          ; Save the result, and the remainder is in EDX

    mov al,dl                    ; Save remainder, to be converted
    add al,48                    ; Convert remainder number to text
    mov [TempBuffer+ecx],al      ; Save the character into TempBuffer
    inc ecx
    mov edx,0                    ; Regroup the remainder, so we can continue
    cmp dword [BigNumber+8],0    ; Are the top 32 bits clear?
    ja .LoopBigNumber8           ; Nope, keep reducing this BigNumber
    cmp dword [BigNumber+4],0    ; Are the middle 32 bits clear?
    ja .LoopBigNumber4           ; Nope, keep reducing this BigNumber
    cmp dword [BigNumber],0      ; Are the last 32 bits clear?
    ja .LoopBigNumber            ; Nope, keep reducing this BirNumber
    mov al,0                     ; The BigNumber is now clear, so load up end of string
    mov [TempBuffer+ecx],al      ; End the string (for now)
    mov edi,TempBuffer           ; Setup to get string length
    call StringLength            ; Get the string length in ECX
    mov ebx,0                    ; Setup EBX for DecimalBuffer

.LoopToReverse:

    mov al,[TempBuffer+ecx-1]    ; In reverse order (as we got here, reversely), grab a letter
    mov [DecimalBuffer+ebx],al   ; Then place that letter in DecimalBuffer
    inc ebx                      ; Move the pointer plus one character (byte)
    dec ecx                      ; Move the point minus once character
    jnz .LoopToReverse           ; Did we hit zero (0)? If not, loop!
    mov al,0                     ; Load the string terminator into AL
    mov [DecimalBuffer+ebx],al   ; Cap off the DecimalBuffer string

    popa                         ; Restore registers to where they were before entering

    ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Uninitiated variables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

CodeSegment             rw 1        ; Saves the codesegment for decisions
HexBuffer               rb 18       ; Sixteen bytes with the ending zero
DecimalBuffer           rb 28       ; twenty six bytes with the ending zero
TempBuffer              rb 28
ResultBuffer            rb 28       ; Split up the result and remainder
RemainderBuffer         rb 28       ; Split up the result and remainder
CommaBuffer             rb 38       ; thirty six bytes for DecimalBuffer information
CommasNeeded            rd 1        ; Saving commas needed
TheRemainder            rd 1        ; Saving the Remainder
TheResult               rd 1        ; Saving the Result
OrderOfTens             rd 1        ; Saving order of tens (10^n)
ZeroNotLoaded           rb 1        ; Used for checking zero starting numbers
NumberOfRegisters       rb 1        ; Used to determine number of registered displayed
DivisorNumber           rw 1        ; Used to keep track of division
BigNumber               rd 3        ; Save some room for 96 bits of number    
Post 21 Sep 2014, 20:12
View user's profile Send private message Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 23 Sep 2014, 14:04
Lesson Learned: If a device function 0 is present, then you have to check all functions. Do not assume that once a function fails, that subsequent functions are not there, unless it is function 0 that fails.

I was finally able to enumerate the mass storage device, which was under function 5, with no function 4...weird!

I had to change the above code significantly in order to get it working properly too...I'll post an update to that later once I get it to pause between pages, since it enumerates way more devices than are screen areas.

I also want to look up for type 1 (and type 2) configuration areas.

Anyhow, I now can ID my drives though enumeration. Next work on AHCI...
Post 23 Sep 2014, 14:04
View user's profile Send private message Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 23 Sep 2014, 22:18
what are you referring to by type 1 and 2?
Post 23 Sep 2014, 22:18
View user's profile Send private message Visit poster's website Reply with quote
BAiC



Joined: 22 Mar 2011
Posts: 272
Location: California
BAiC 23 Sep 2014, 23:31
nevermind.. been awhile since I last dealt with PCI enumeration.
Post 23 Sep 2014, 23:31
View user's profile Send private message Visit poster's website Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 24 Sep 2014, 03:34
Smile
Post 24 Sep 2014, 03:34
View user's profile Send private message Reply with quote
tom tobias



Joined: 09 Sep 2003
Posts: 1320
Location: usa
tom tobias 27 Sep 2014, 12:07
Well done smiddy, glad to learn that you are back at it, with your usual good humor, and excellent documentation skills.

looking forward to your next elaboration....

tom
Post 27 Sep 2014, 12:07
View user's profile Send private message Reply with quote
smiddy



Joined: 31 Oct 2004
Posts: 557
smiddy 28 Sep 2014, 11:16
Thanks Tom!

Although, more of an embellishment than anything else, "...on the shoulders of giants!"
Post 28 Sep 2014, 11:16
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.