Tag Archives: boot

The Warp Boot Sequence

Understanding the boot sequence of Warp is important to administrators and support personnel. It also helps to provide additional insight into the architechture of OS/2 Warp. Such an understanding will enable you to determine what can cause problems for your computer hardware as well as for Warp during boot.

Turning on the computer

When the computer is first turned on the power supply prevents the computer from taking any action by maintaining an electrical signal called “Power Good” in the off state until all power supply voltages have settled into the normal operational range. Only when the power supply is working correctly does it turn on the “Power Good” signal.

When the “Power Good” signal is turned on, some electronic circuitry in the computer sets the processor’s instruction pointer to the location in ROM BIOS which contains the POST program code. The computer loads the instruction at that location into the processor and starts the processor execution cycle. At this point the processor is in “Real” mode which means that it is effectively a fast 8086.

Power On Self Test

The Power On Self Test is located on a type of integrated circuit chip called Read Only Memory (ROM), along with some other programs such as BIOS. Power On Self Test (POST) is performed by most IBM PCs and PC compatible computers. POST is a critical part of the boot process because it provides some assurance that the hardware components of the computer are working correctly. Unfortunately, POST (and all DOS based diagnostic programs – there are no OS/2 based 32 bit diagnostic programs) is usually a 16 bit DOS class of program. It is therefore unable to test all aspects of a 32 bit computer. Even if POST or diagnostic programs were true 32 bit programs it would still be impossible to test every electronic circuit and component in a computer. At best a well written diagnostic program can only test about 80% of the components in a computer; POST, which is designed only to provide a quick check of the computer’s critical components does not even check that much. This means that there is still a good chance that a computer which passes both POST and diagnostics can still have a hardware defect which would cause problems with Warp or application programs.

POST first displays a count of installed memory as it performs a quick test of RAM. When that is complete you should see the total amount of RAM installed in your computer on the screen. Warp will recognize and utilize the amount of RAM displayed during the POST memory count.

If the memory count does not appear on the screen, it could be that the computer has been configured not to perform POST, the display is defective, or that the computer has a defective power supply. If the memory count does not show up on your screen, replace the display with one which is known to be good, and ensure that the computer has been configured to perform the POST. If that does not resolve the problem, replace the power supply.

POST then Initializes some interrupt vectors, and loads BIOS into RAM where it will perform better than if it were left in ROM. ROM is not only slower than RAM, but also it can only be read 8 bits at a time. When copied to RAM, BIOS can be read 16 bits at a time. Remember that POST is a 16 bit program, not 32 bit, and the processor is still in Real mode which means that it cannot execute 32 bit instructions or data transfers.

Next. the Power On Self Test scans for I/O adapters and links the adapter BIOS code into the system BIOS from ROM. It is at this time that you will see the BIOS code for your Adaptec SCSI adapter, for example, loaded. Hardware adpater conflicts may cause hangs during this part of POST. If you see the memory count and other messages on your screen during POST but POST never completes, you probably have an adapter conflict. You can tell that POST has not completed because the computer will not beep. If POST completes, whether successfully or with errors, it always produces one or more beeps.

After the BIOS code for the various I/O adapters has been integrated, the computer’s loadable ABIOS is refreshed, if it has one. Some computers have ABIOS, but many do not. Again, ABIOS is an Advanced BIOS which is capable of supporting a true multitasking operating system.

This normally completes POST and, if there were no errors detected, POST causes the computer to produce one short beep. Of course, if you observe any error messages on the screen, or POST beeps any other beep or combination of beeps, the computer has a hardware problem which should immediately be repaired.

Loading the Bootstrap program

The word “boot” is a short form of the term “bootstrap”. It refers to the fact that computers are really incapable of performing an action of any kind without a program of some sort to help them do it. Computers are so dumb that without some help they cannot even start themselves. To overcome this problem, designers have developed small programs called bootstrap loaders which enable it to “pull itself up by the bootstraps” and become smart enough to find and load the operating system. This bootstrap loader is located on the boot sector of the hard drive.

After POST completes with the “OK” beep, it issues an interruupt 19h to BIOS. BIOS interrup 19h searches for a boot sector on the disks specified in the computer’s boot sequence. Interrupt 19 loads into RAM the first boot sector found in the boot sequence into memory location 7C00h and transfers control of the computer to the bootstrap loader.

If no valid, bootable boot sector is found on any of the disks in the boot sequence, the boot sector contains a little bit of code which displays an error message. If the disk (or diskette) was formatted by OS/2, one of the following messages is presented.

OS/2 !! SYS01475
OS/2 !! SYS02027


The file OS2LDR cannot be found. Insert a system diskette and restart the system

If the disk (or diskette) was formatted by DOS, the following message is presented.

Non-System disk or disk error
Replace and strike any key when ready

All of these messages mean exactly the same thing: a valid boot record cannot be found. Refer to “OS/2 !! SYS01475 error message” for more details and how to recover.

If a valid boot block is found, it is loaded into RAM and control of the computer is turned over to it.

OS2BOOT Loads the operating system loader

The OS/2 Boot block finds and loads OS2BOOT. The Boot block is very small – only 16 blocks (sectors) in size. Because of this it is not very smart. One of the issues for the operating system at this time is that the HPFS drivers are not yet loaded, but the Boot block needs to be able to locate the OS2BOOT file on the HPFS volume. To enable this to happen, the Boot block uses a micro HPFS which enables it to locate files in the root directory. The boot block loads the OS2BOOT file.

OS2LDR loads the operating system

The OS2BOOT file and the OS2LDR both use a min-HPFS file system that is larger and more complex than the micro-HPFS file system used by the Boot block which can read the root, \OS2 and \OS2\BOOT directories. The OS2BOOT file loads the OS2LDR file and transfers control of the system to it.

OS2LDR in turn loads OS2KRNL which is the kernel of the operating system. Control is transferred to the OS2KRNL and the first OS/2 logo and copyright message is displayed during kernel initialization. The kernel is still using the mini-HPFS file system.

Processing the CONFIG.SYS file

The OS2KRNL reads the CONFIG.SYS file and begins processing of the statements in a combination sorted and native (unsorted) sequence. The CONFIG.SYS statements are processed in order shown below.

BASEDEV statements in the following order:


At this point, the OS/2 Logo changes to “Loading, please wait…”.

IFS statements are processed. The HPFS file system must be first IFS installed because the first one listed in the CONFIG.SYS file in native order replaces the mini-HPFS.

AUTOCHECK runs HPFS if the dirty file system flag is set.

DEVICE= statements processed.
CALL= statements processed.
RUN= statements processed.
Other statements are processed.
SET variable statements are processed.

All of the device drivers loaded at this time. A Trap error in a device driver can cause system hang at this point.

The program specified by PROTSHELL= statement is started. This is the Graphical Programming Interface which enables OS/2 to support a GUI workplace shell.

STARTUP.CMD and the Workplace Shell are started

The STARTUP.CMD is started if one is present.

If SET AUTOSTART=FOLDERS is specified in the CONFIG.SYS file, then theWorkplace Shell is started. All previously open folders will be opened. Desktop objects are displayed.

If SET AUTOSTART=PROGRAMS is specified in the CONFIG.SYS file, then Program objects which were open at shutdown are restarted.

If SET AUTOSTART=CONNECTIONS is specified, then network objects active at shutdown will be restarted. This may cause the logon prompt to be displayed.

The Boot process is complete

The system is now up and running under user control.

Boot Sector Example – by Jeff Weeks

Note: From OSRC, pulled from Wayback Machine

(c)1997 Jeff Weeks and Code X software

Writting your own boot sector is probably actually easier then you think. All you really need to know is how the Intel processor boots up. A valid boot sector has the code 0xAA55 at an offset of 510, and is located in the very first sector of the disk. Therefore, the BIOS simply checks drive 0 (A:) for this code. If not found, it then checks drive 128 (C:). If a valid boot sector is found, it is loaded into memory at location 0:07C00h.

So, all you have to do is write a boot sector, assemble it into a plain binary file (their is no format or header to a boot sector), and write it to the first sector of your disk. The best way to do that would be to either use nasm (The netwide assembler can produce plain binary files) or assemble into a DOS .EXE and remove the first 512 bytes. You can also write your own program to write the bootsector to sector 1 of the disk using BIOS INT 13h AH=02h.

Pretty simple eh? Well, in case you’re still a little confused, here’s a little bootsector from PolyOS that simply switches to protected mode, after checking that you have a 386+ computer. Actually, it even loads in the PolyFS superblock and checks if it’s valid, but that’s about it. Soon it’ll load in the kernel and jump to it. The bootesctor was written with Nasm.


; ------------------------------------------------------------------------
; PolyOS boot loader code            (c)1997 Jeff Weeks of Code X Software
; ------------------------------------------------------------------------
; This little bit of assembly is the boot loader for my operating system.
; ------------------------------------------------------------------------
[BITS 16]       ; the bios starts out in 16-bit real mode
[ORG 0]
; ------------------------------------------------------------------------
; ------------------------------------------------------------------------
; This sector detects your processor.  If a 386 is found, it loads the
; kernel from the disk and executes it (atleast it will in the future :).
; ------------------------------------------------------------------------
jmp start       ; skip over our data and functions
; -------------------------------------
; Data used in the boot-loading process
; ------------------------------------------------------------------------
        bootdrv         db 0
        bootmsg         db 'Booting PolyOS (c)1997 Cipher of Code X',13,10,0
        loadmsg         db 'Loading kernel',13,10,0
        jumpmsg         db 'Jumping to kernel',13,10,0
        rebootmsg       db 'Press any key to reboot',13,10,0
        ; these are used in the processor identification
        processormsg    db 'Checking for 386+ processor: ',0
        need386         db 'Sorry... 386+ required!',13,10,0
        found386        db 'Excellent!',13,10,0
        ; these are used when entering protected mode
        a20msg          db 'Setting A20 address line',13,10,0
        pmodemsg        db 'Setting CR0 -> Entering PMode',13,10,0
        ; Here's the locations of my IDT and GDT.  Remember, Intel's are
        ; little endian processors, therefore, these are in reversed order.
        ; Also note that lidt and lgdt accept a 32-bit address and 16-bit 
        ; limit, therefore, these are 48-bit variables.
        pIDT            dw 7FFh         ; limit of 256 IDT slots
                        dd 0000h        ; starting at 0000
        pGDT            dw 17FFh        ; limit of 768 GDT slots
                        dd 0800h        ; starting at 0800h (after IDT)
; ------------------------------------------
; Functions used in the boot-loading process
; ------------------------------------------------------------------------
                mov si, processormsg    ; tell the user what we're doing
                call message
                ; test if 8088/8086 is present (flag bits 12-15 will be set)
                pushf                   ; save the flags original value
                xor ah,ah               ; ah = 0
                push ax                 ; copy ax into the flags
                popf                    ; with bits 12-15 clear
                pushf                   ; Read flags back into ax
                pop ax       
                and ah,0f0h             ; check if bits 12-15 are set
                cmp ah,0f0h
                je no386                ; no 386 detected (8088/8086 present)
                ; check for a 286 (bits 12-15 are clear)
                mov ah,0f0h             ; set bits 12-15
                push ax                 ; copy ax onto the flags
                pushf                   ; copy the flags into ax
                pop ax
                and ah,0f0h             ; check if bits 12-15 are clear
                jz no386                ; no 386 detected (80286 present)
                popf                    ; pop the original flags back
                mov si, found386
                call message
                ret                     ; no 8088/8086 or 286, so ateast 386
                mov si,need386          ; tell the user the problem
                call message
                jmp reboot              ; and reboot when key pressed
;       ------------------------------------------------------------------
        message:                        ; Dump ds:si to screen.
                lodsb                   ; load byte at ds:si into al
                or al,al                ; test if character is 0 (end)
                jz done
                mov ah,0eh              ; put character
                mov bx,0007             ; attribute
                int 0x10                ; call BIOS
                jmp message
;       ------------------------------------------------------------------
                mov ah, 0               ; wait for key
                int 016h
;       ------------------------------------------------------------------        
                mov si, rebootmsg       ; be polite, and say we're rebooting
                call message
                call getkey             ; and even wait for a key :)
                db 0EAh                 ; machine language to jump to FFFF:0000 (reboot)
                dw 0000h
                dw 0FFFFh
                ; no ret required; we're rebooting! (Hey, I just saved a byte :)
; -------------------------------------------
; The actual code of our boot loading process
; ------------------------------------------------------------------------
        mov ax,0x7c0    ; BIOS puts us at 0:07C00h, so set DS accordinly
        mov ds,ax       ; Therefore, we don't have to add 07C00h to all our data
        mov [bootdrv], dl ; quickly save what drive we booted from
        cli             ; clear interrupts while we setup a stack
        mov ax,0x9000   ; this seems to be the typical place for a stack
        mov ss,ax
        mov sp,0xffff   ; let's use the whole segment.  Why not?  We can :)
        sti             ; put our interrupts back on
        ; Interestingly enough, apparently the processor will disable 
        ; interupts itself when you directly access the stack segment!
        ; Atleast it does in protected mode, I'm not sure about real mode.
        mov si,bootmsg  ; display our startup message
        call message
        call detect_cpu ; check if we've got a 386
.386    ; use 386 instructions from now on (I don't want to manually include
        ; operand-size(66h) or address-size(67h) prefixes... it's annoying :)
        mov si,loadmsg  ; tell the user we're loading the kernel
        call message
        call getkey
        ; first, reset the disk controller
        xor ax, ax
        int 0x13
        jc reboot       ; reboot on error
        ; then load in the PolyFS superblock
        mov ax,0x09000          ; superblock goes to 9000:0000 (above stack)
        mov es,ax
        xor bx,bx
        ; I could condense a few of these high/low 8-bit movs into one 16-bit
        ; mov, but, for simplicity, I'll leave it as is, unless necessary.
        mov ax,0x0202           ; load one block (two sectors)
        mov ch,0                ; cylinder = 0
        mov cl,3                ; sector = 2 (starts at sector 1 not 0)
        mov dh,0                ; head = 0 = side one
        mov dl,[bootdrv]        ; disk = what we booted from
        int 0x13                ; read it
        jc read_me              ; if there's an error then we'll try again.
                                ; Often there is not error but requires a few
                                ; tries.  Ofcourse, this may end up as an 
                                ; infinite loop... but only on a bad disk...
        ; Check if we have a valid super block (BTW: ES still equals 0x9000)
        mov di, 0               ; offset of PolyFS magic signature
        mov si, polymagic       ; offset of PolyFS magic to check for (in ds)
        cmpsw                   ; compare ES:[DI] with DS:[SI]
        jnz reboot              ; reboot on error (otherwise, we've got a PolyFS)
	; Ideally, we'd load the kernel right here
        mov si, a20msg          ; tell the user we're setting the A20 line
        call message
        ; set A20 line
        cli                     ; no more interuptions! :)
        xor cx, cx
        in al, 64h              ; get input from keyboard status port
        test al, 02h            ; test the buffer full flag
        loopnz clear_buf        ; loop until buffer is empty
        mov al, 0D1h            ; keyboard: write to output port
        out 64h, al             ; output command to keyboard
        in al, 64h              ; wait 'till buffer is empty again
        test al, 02h
        loopnz clear_buf2
        mov al, 0dfh            ; keyboard: set A20
        out 60h, al             ; send it to the keyboard controller
        mov cx, 14h
wait_kbc:                       ; this is approx. a 25uS delay to wait
        out 0edh, ax            ; for the kb controler to execute our 
        loop wait_kbc           ; command.
        ; the A20 line is on now.  Let's load in our ITD and GDT tables...
        ; Ideally, there will actually be data in their locations (by loading 
        ; the kernel)
        lidt [pIDT]
        lgdt [pGDT]
        ; now let's enter pmode...
        mov si, pmodemsg
        call message
        call getkey
        mov eax, cr0            ; load the control register in
        or  al, 1               ; set bit 1: pmode bit
        mov cr0, eax            ; copy it back to the control register
        jmp $+2                 ; and clear the prefetch queue
        ; jump to the kernel that we've loaded in...
        ; For now, we'll actually just reboot (this really doesn't 
        ; work in protected mode, but it does reboot :)
        db 0xEA
        dw 0x0000
        dw 0xFFFF
        ; The boot sector is supposed to have to have 0xAA55 at the end of 
        ; the sector (the word at 510 bytes) to be loaded by the BIOS...
        times 510-($-$$) db 0
        dw 0xAA55