flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Building a better bootloader

Author
Thread Post new topic Reply to topic
SeproMan



Joined: 11 Oct 2009
Posts: 60
Location: Belgium
SeproMan
Is there any sense in adding code to detect the presence of a 32-bit cpu or could I just rely on exception 6 being generated on the first occurence of say MOVZX or BSF ?
And would such an exception crash the system in an orderly fashion ?

Why should I put CLI and STI around the pair of instructions to setup the stack ?
CLI
MOV SS,AX
MOV SP,BP
STI
As I understand interrupts blocked via CLI get already blocked via MOV SS,AX.

Intel docs are not very clear on the matter of wraparounding. So if SP=2 and I wanted to push a double word, what would happen ?
Is this a limit violation triggering exception 12 ?

Thanks for any answers

_________________
Real Address Mode.
Post 25 Jul 2010, 13:11
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4240
Location: 2018
edfed
use CPUID for CPU identification.
use ID flag in EFLAG to know if CPU supports CPUID.

and thats all for CPU identification



for the CLI (change stack) sti.

it is purelly logic, because interrupts use the stack to save context, then, if you change the stack without disabling interrupts, you will have unpredicted results.
Post 25 Jul 2010, 13:23
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17639
Location: In your JS exploiting you and your system
revolution
Well lots of questions:

>Is there any sense in adding code to detect the presence of a 32-bit cpu or could I just rely on exception 6 being generated on the first occurence of say MOVZX or BSF ?

Don't rely on old 16-bit CPUs to generate exceptions. Always check. It is simple to do, no sense in leaving out the check.

>And would such an exception crash the system in an orderly fashion ?

The is no such thing as an orderly crash!

>Why should I put CLI and STI around the pair of instructions to setup the stack ?

Because some very old CPUs don't inhibit interrupts after SS update. Most do though.

>Intel docs are not very clear on the matter of wraparounding. So if SP=2 and I wanted to push a double word, what would happen ?

This one is easy to check, set up a test and see what happens. I'm not really sure, but I expect RM will fault, and PM will depend upon your limit settings.
Post 25 Jul 2010, 13:31
View user's profile Send private message Visit poster's website Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 764
Location: Massachusetts, USA
bitshifter
Also we can screw with the flags register to check x86-ness...
http://board.flatassembler.net/topic.php?p=115968#115968
Post 25 Jul 2010, 19:34
View user's profile Send private message Reply with quote
egos



Joined: 10 Feb 2009
Posts: 144
egos
Good questions.
SeproMan wrote:
Is there any sense in adding code to detect the presence of a 32-bit cpu or could I just rely on exception 6 being generated on the first occurence of say MOVZX or BSF ?
Yes, there is. I do this through IOPL bits. By this reason I'm using only i8086 instructions in my 1st stage bootloaders. But some others do not this.

Quote:
Why should I put CLI and STI around the pair of instructions to setup the stack ?
CLI
MOV SS,AX
MOV SP,BP
STI
Early processors did not disable interrupts after loading ss. Now that is tradition and wanting compatibility.
Post 26 Jul 2010, 19:57
View user's profile Send private message Reply with quote
SeproMan



Joined: 11 Oct 2009
Posts: 60
Location: Belgium
SeproMan
Please review my bootloader. I made separate versions for FAT12, FAT16 and FAT32 volumes.
Upon booting it looks for an user-named program in the root directory and then executes it .COM-style.
This is not true .COM because :
1) The file extension can be anything
2) SP will not be initialized at FFFEh to allow for an executable bigger than 64KB
If the user wanted to run an MS-DOS EXE, I programmed a conversion utility EXE2COM (not to be confused with EXE2BIN) that basically adds an EXE loader to the program file.

Code:
; ****************************************
; * BootACom v1.00 (c) 2010 Luc FRANÇOIS *
; * Last modified : 01/08/2010       *
; *   Total lines   : 259 lines        *
; ****************************************
;
DBR=0700h
; On startup CS:IP=0090h:0100h, SS:SP=0090h:0100h, DS=0090h, ES=0090h
; ----------------------------------------------
NewDBR12:    jmp     near Start
; ----------------------------------------------
              db      'BootACom'            ; +03 * bsOEMName
           dw      ?                       ; +11   bpbBytesPerSector
           db      ?                       ; +13   bpbSectorsPerCluster
                dw      ?                       ; +14   bpbReservedSectors
          db      ?                       ; +16   bpbNumberOfFATs
             dw      ?                       ; +17   bpbRootEntries
              dw      ?                       ; +19 * bpbTotalSectors16
           db      ?                       ; +21 * bpbMedia
            dw      ?                       ; +22   bpbFATSize16
                dw      ?                       ; +24   bpbSectorsPerTrack
          dw      ?                       ; +26   bpbNumberOfHeads
            dd      ?                       ; +28   bpbHiddenSectors
            dd      ?                       ; +32 * bpbTotalSectors32
           db      ?                       ; +36   bsDriveNumber
               db      ?                       ; +37 * bsReserved1
         db      ?                       ; +38 * bsBootSignature
             dd      ?                       ; +39 * bsVolumeSerialNumber
                db      'NO NAME    '         ; +43 * bsVolumeLabel
               db      'FAT12   '            ; +54 * bsFileSystem
; ----------------------------------------------
            db      11 dup ' '            ;Max. 11 chars (blanks padded)
; ----------------------------------------------
; IN (ch=0,edx,es) OUT (ebx,edx)
ReadSectorEx:     xor     ebx,ebx
; ---   ---   ---   ---   ---   ---   ---   ---
; IN (ch=0,edx,es:bx) OUT (bx,edx)
ReadSector: push    di                      ;(1) EDX=LBA
                mov     di,5                    ;Possible retries
.Retry:                pusha                           ;(2)
                jmp     near .CHS               ;{'jmp near .CHS','push dword
               push    edx es bx               ;(4)...                   0'}
         push    1                       ;Read 1 sector
              push    16                      ;Length of Data Address Packet
              mov     si,sp                   ;DS=SS
              mov     ah,42h
              jmp     short .Read
.CHS:                push    edx                     ;(3)
                mov     ax,[bp+24]              ;bpbSectorsPerTrack [1,63]
          mul     word [bp+26]            ;bpbNumberOfHeads [1,256]
           xchg    cx,ax                   ;'mov cx,ax' -> CX=Sectors ...
         pop     ax dx                   ;(3)                PerCylinder
             div     cx                      ;CX=SectorsPerCylinder
              xchg    cx,ax                   ;'mov cx,ax' Cylinder
             xchg    ch,cl                   ; -> CH=Cylinder[0-7]
            shl     cl,6                    ; -> CL[6-7]=Cylinder[8-9]
               xchg    ax,dx                   ;'mov ax,dx'
              div     byte [bp+24]            ;bpbSectorsPerTrack
         mov     dh,al                   ;Head
               or      cl,ah                   ; -> CL[0-5]=Sector-1
            inc     cx                      ; -> CL[0-5]=Sector
              pusha                           ;(4) 'sub sp,16'
          mov     ax,0201h                ;Read 1 sector
.Read:            mov     dl,[bp+36]              ;bsDriveNumber
              int     13h                     ;BIOS 'Extended Read' or
          jnc     .OK                     ;     'Read Disk Sectors'
         mov     ah,00h
              int     13h                     ;BIOS 'Reset Disk System'
         popa                            ;(4a) 'add sp,16'
         popa                            ;(2a)
               dec     di
          jnz     .Retry
              mov     cl,2                    ;CH=0
               jmp     short FatalError
.OK:            popa                            ;(4b) 'add sp,16'
         popa                            ;(2b)
               pop     di                      ;(1)
                add     bx,[bp+11]              ;bpbBytesPerSector
          inc     edx
         ret
; ----------------------------------------------
Start:           mov     ax,(DBR-256)/16
             mov     bp,256
              cli
         mov     ss,ax
               mov     sp,bp
               sti
         mov     ds,ax
               mov     es,ax
               mov     cx,bp
               mov     si,7C00h-(DBR-256)
          mov     di,bp
               cld
         rep movsw
           jmp     far 0000h:DBR+Continue
; ----------------------------------------------
Continue: stosw                           ;Signature <> MS-DOS (20CDh)
          mov     [bp+36],dl              ;bsDriveNumber
; ----------------------------------------------
; Make sure CPU is 32-bit
             pushf                           ;(1)
                pushf
               pop     ax
          xor     ax,7000h                ;Try flipping 'NT' and 'IOPL'
           push    ax
          popf
                pushf
               pop     bx
          popf                            ;(1)
                cmp     ax,bx
               je      CPU_OK
              inc     cx                      ; -> CX=1
; ---   ---   ---   ---   ---   ---   ---   ---
; IN (cx)
FatalError: mov     ax,0E07h                ;Beep [1,3] time(s)
         xor     bx,bx
               int     10h                     ;BIOS 'Teletype Character'
                loop    FatalError
.Crash:               jmp     short .Crash
; ----------------------------------------------
; Patch code if IBM/MS INT 13 Extensions are available
CPU_OK:               test    dl,dl
               jns     .1                      ;Only for drives 80h-FFh
            mov     bx,55AAh
            mov     ah,41h
              int     13h                     ;BIOS 'Installation Check'
                jc      .1                      ;Not supported
              cmp     bx,0AA55h
           jne     .1                      ;Not installed
              shr     cx,1
                jnc     .1                      ;No 42h-44h,47h,48h functions
               mov     word [bp+62+11+8],6A66h ;'jmp near .CHS' -> 'push dword
; ----------------------------------------------                           0'}
; Calculate and push some temporary variables
; --------ggffffeeddddccbbbbaaaa <- BP
; LBA of FAT1
.1:         movzx   edx,word [bp+14]        ;bpbReservedSectors
         add     edx,[bp+28]             ;bpbHiddenSectors
           push    edx                     ;(a) FAT1_LBA
; LBA of Root
              movzx   eax,word [bp+22]        ;bpbFATSize16
               movzx   cx,byte [bp+16]         ;bpbNumberOfFATs
.2:             add     edx,eax                 ;FATSize32
          loop    .2
          push    edx                     ;(b) Root_LBA
; LBA of Data Region
               mov     bx,[bp+11]              ;bpbBytesPerSector
          shr     bx,5                    ; -> BX=RootEntriesPerSector
             mov     ax,[bp+17]              ;bpbRootEntries, each 32 bytes
              push    ax                      ;(c) RootEntries
.3:             inc     edx
         sub     ax,bx
               jnbe    .3
          push    edx                     ;(d) DataRegion_LBA
; Reserve memory to cache 2 FAT sectors
              int     12h                     ;BIOS 'Get Memory Size'
           cwd                             ; -> DX=0
                shl     ax,6                    ;Convert it from KB to õ
           stosw                           ;MS-DOS has pspNXTGRAF here
         shl     bx,1                    ; -> BX=ParagraphsPerSector
              sub     ax,bx
               sub     ax,bx
               pusha                           ;(e) DiskBuffer
                                             ;(f) CachedFATSectors_LBA, none
                                             ;(g) ParagraphsPerSector
; ----------------------------------------------
                push    (DBR+512+256)/16
            pop     es
; Find file 'ProgramName' in Root Directory
         mov     edx,[bp-8]              ;(b) Root_LBA
NextRootSector:    call    ReadSectorEx            ; -> EBX, EDX
            xor     di,di                   ;ES:DI Current Root Sector
.NextRootEntry:   cmp     [es:di],ch          ;CH=0
               je      .eFile                  ;End of Root
                cmp     byte [es:di],0E5h   ;2 lines that could be dropped
              je      .SkipEntry              ;Skip free entry
            test    byte [es:di+11],00011000b ;dirAttributes DIRECTORY|VOL.
         jnz     .SkipEntry              ;Is no file (Could even be LFN)
             pusha
               lea     si,[bp+62]              ;ProgramName
                mov     cl,11                   ;CH=0
               repe cmpsb
          popa
                je      NameFound
.SkipEntry:    add     di,32                   ;To next entry
              dec     word [bp-10]            ;(c) RootEntries
.eFile:         jz      eFile                   ;File not found!
            cmp     di,bx                   ;BX=BytesPerSector
          jb      .NextRootEntry
              jmp     short NextRootSector
; ----------------------------------------------
FollowChain:    pop     ax
; ClusterToSector in EDX
.NextCluster:     lea     edx,[esi-2]
         bsf     cx,[bp+13]              ;bpbSectorsPerCluster {1,2,4,..
                shl     edx,cl                  ;CX=[0,7]       8,16,32,64,128}
                add     edx,[bp-14]             ;(d) DataRegion_LBA
         mov     cl,[bp+13]              ;bpbSectorsPerCluster, CH=0
.LoopInCluster:call  ReadSectorEx            ; -> EBX, EDX
            call    ax                      ;{CallBack2}
              loop    .LoopInCluster
; ClusterToCluster
                push    es                      ;(1)
                mov     es,[bp-16]              ;(e) DiskBuffer
             mov     edx,esi                 ;High words are/become zero
         shr     si,1
                pushf                           ;(2)
                add     dx,si                   ; -> DX=RoundDown(Cluster*1.5)
           mov     si,[bp+11]              ;bpbBytesPerSector {512...4096}
           bsf     cx,si                   ; -> CX=[9,12]
           dec     si
          and     si,dx                   ;Offset in a sector of 1st FAT
              shr     dx,cl                   ;Relative sector in 1st FAT
         add     edx,[bp-4]              ;(a) FAT1_LBA
               cmp     edx,[bp-20]             ;(f) CachedFATSectors_LBA ?
         je      .ReadEntry              ;Yes, No need to reload
             mov     [bp-20],edx             ;(f) CachedFATSectors_LBA
           call    ReadSectorEx            ; -> EBX, EDX
            call    ReadSector              ; -> BX, EDX
.ReadEntry:      mov     si,[es:si]          ;12 useful bits
             popf                            ;(2)
                jnc     .Even
.Odd:              shr     si,4
.Even:              and     si,0FFFh
            pop     es                      ;(1)
                jmp     short .NextCluster
eFile:                mov     cl,3                    ;CH=0
               jmp     near FatalError
; ----------------------------------------------
NameFound:   movzx   esi,word [es:di+26]         ;dirFirstCluster
            mov     edi,[es:di+28]              ;dirFileSize
                test    edi,edi
             jz      eFile                   ;Not much of a file!
; ----------------------------------------------
; Load file 'ProgramName'
             call    FollowChain             ;This is a de facto jump!
CallBack2:     sub     edi,ebx                 ;FileSize
           jbe     RunImage
            mov     bx,es
               add     bx,[bp-22]              ;(g) ParagraphsPerSector
            mov     es,bx
               cmp     bx,[bp-16]              ;(e) DiskBuffer
             ja      eFile                   ;File is too big!
           ret
; ----------------------------------------------
; No need to pop last callback address. Saves us 1 byte
; Start the program .COM-style
; We won't initialize SP=FFFEh to allow for executables bigger than 64KB
RunImage:      mov     cl,(DBR+512)/16 ;CH=0
               mov     ss,cx
               mov     sp,bp
               mov     ds,cx
               mov     es,cx
               push    cx bp
               retf
; ----------------------------------------------
            db      510-($-$$) dup 0
            dw      0AA55h
; ----------------------------------------------
    

_________________
Real Address Mode.
Post 01 Aug 2010, 13:14
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-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.

Website powered by rwasa.