; This bootsector looks for 386+ processor, and if it finds it prints the canonical ; hello world. ;logical values %define FALSE 0x00 %define TRUE 0x01 ;real-mode segments %define LOADSEG 0x07C0 %define STACKSEG 0x9000 %define VIDEOSEG 0xB800 ;BIOS functions %define BIOS_10_PUTCHAR 0x0E %define BIOS_16_GETKEY 0x00 ;text styles %define PLAIN 0x07 %define EMPH 0x20 [BITS 16] ; the bios starts out in 16-bit real mode [ORG 0] ; data offset = 0 jmp start ;******************************************* ; Data used in the boot-loading process ;******************************************* ;data bootdrv db 0 ;messages bootmsg db 'ONABSE-SIM, from Pietro Braione',13,10 db 'V.1.0 jan 2003',13,10,0 rebootmsg db 'Press any key to reboot',13,10,0 processormsg db 'Checking for 386+ processor: ',0 need386 db 'Sorry... 386+ required!',13,10,0 found386 db 'Found!',13,10,0 ;******************************************* ; Functions we are going to use ... ;******************************************* message: ; Dump ds:si to screen. ; Modifies: ax, bx, si + int 0x10 func 0x0E side effects. lodsb ; Load byte at ds:si into al or al,al ; Test if character is 0 (end) jz .done mov ah,BIOS_10_PUTCHAR ; Put character mov bx,PLAIN ; Attribute int 0x10 ; Call BIOS jmp message .done: ret ; ******************************************************************** getkey: ; Waits for a keypress. ; Modifies: ah + int 0x16 func 0 side effects. mov ah,BIOS_16_GETKEY int 0x16 ret ; ******************************************************************** detect_cpu: ; Test if 8088/8086 is present, putting the result in al. ; Modifies: ax. pushf ; Save the flags original value mov al,FALSE ; Inits al ; First tries to clear bit 12-15 (always set in 88/86/188/186) xor ah,ah ; Clear ah push ax ; Copy ax on the stack... popf ; ...and then into flags pushf ; Read flags back into ax... pop ax ; ...using the same stack roundtrip and ah,0xF0 ; Check if high nibble is set cmp ah,0xF0 je .no386 ; If not, processor is 88/86/188/186 ; Then tries to set NT, which is bit 14 of flags (only 386, not 286) mov ah,0x40 ; Set bit 14 of ax push ax ; Copy ax onto the flags as before popf pushf ; Copy the flags into ax as before pop ax and ah,0x40 ; Check if bit 14 is clear jz .no386 ; If not, processor is 286 ; 386 detected mov al,TRUE ; CPU is not 386 .no386: popf ; Pop the original flags back ret ; ******************************************* ; The actual code of our boot loading process ; ******************************************* start: ; Adjust segment registers mov ax,LOADSEG ; BIOS loads bootsector at segment LOADSEG. We set ds accordingly mov ds,ax ; so we don't have to add LOADSEG<<4 to all our data addresses ; Quickly save what drive we booted from mov [bootdrv], dl ; Set up a stack mov ax,STACKSEG mov ss,ax mov sp,0xFFFF ; Let's use the whole segment. Why not? We can :) ; Display our startup message mov si,bootmsg call message ; Check for 386 processor mov si,processormsg ; Tells the user we're checking if the CPU is 386 or + call message call detect_cpu cmp al,0x00 jnz .go_on mov si,need386 ; No 386? Stops everything call message jmp $ .go_on: mov si,found386 ; 386 found: say ok call message [BITS 32] ; use 386 instructions from now on (I don't want to manually include ; operand-size(66h) or address-size(67h) prefixes... it's annoying :) ; we are done jmp $ ; hangs ; ******************************************* ; Epilogue ; ******************************************* ; pads with zero to sector size - 2 times 510-($-$$) db 0 dw 0xAA55 ; marks as boot sector ; pads with zeros to floppy size - use it if necessary ; (it isn't with Bochs and VMware) ;times 1474560-($-$$) db 0