Annotation of linux/boot/boot.s, revision 1.1.1.2

1.1.1.2 ! root        1: ;
        !             2: ;      boot.s
        !             3: ;
        !             4: ; boot.s is loaded at 0x7c00 by the bios-startup routines, and moves itself
        !             5: ; out of the way to address 0x90000, and jumps there.
        !             6: ;
        !             7: ; It then loads the system at 0x10000, using BIOS interrupts. Thereafter
        !             8: ; it disables all interrupts, moves the system down to 0x0000, changes
        !             9: ; to protected mode, and calls the start of system. System then must
        !            10: ; RE-initialize the protected mode in it's own tables, and enable
        !            11: ; interrupts as needed.
        !            12: ;
        !            13: ; NOTE! currently system is at most 8*65536 bytes long. This should be no
        !            14: ; problem, even in the future. I want to keep it simple. This 512 kB
        !            15: ; kernel size should be enough - in fact more would mean we'd have to move
        !            16: ; not just these start-up routines, but also do something about the cache-
        !            17: ; memory (block IO devices). The area left over in the lower 640 kB is meant
        !            18: ; for these. No other memory is assumed to be "physical", ie all memory
        !            19: ; over 1Mb is demand-paging. All addresses under 1Mb are guaranteed to match
        !            20: ; their physical addresses.
        !            21: ;
        !            22: ; NOTE1 abouve is no longer valid in it's entirety. cache-memory is allocated
        !            23: ; above the 1Mb mark as well as below. Otherwise it is mainly correct.
        !            24: ;
        !            25: ; NOTE 2! The boot disk type must be set at compile-time, by setting
        !            26: ; the following equ. Having the boot-up procedure hunt for the right
        !            27: ; disk type is severe brain-damage.
        !            28: ; The loader has been made as simple as possible (had to, to get it
        !            29: ; in 512 bytes with the code to move to protected mode), and continuos
        !            30: ; read errors will result in a unbreakable loop. Reboot by hand. It
        !            31: ; loads pretty fast by getting whole sectors at a time whenever possible.
1.1       root       32: 
1.1.1.2 ! root       33: ; 1.44Mb disks:
1.1       root       34: sectors = 18
1.1.1.2 ! root       35: ; 1.2Mb disks:
        !            36: ; sectors = 15
        !            37: ; 720kB disks:
        !            38: ; sectors = 9
1.1       root       39: 
                     40: .globl begtext, begdata, begbss, endtext, enddata, endbss
                     41: .text
                     42: begtext:
                     43: .data
                     44: begdata:
                     45: .bss
                     46: begbss:
                     47: .text
                     48: 
                     49: BOOTSEG = 0x07c0
                     50: INITSEG = 0x9000
1.1.1.2 ! root       51: SYSSEG  = 0x1000                       ; system loaded at 0x10000 (65536).
1.1       root       52: ENDSEG = SYSSEG + SYSSIZE
                     53: 
                     54: entry start
                     55: start:
                     56:        mov     ax,#BOOTSEG
                     57:        mov     ds,ax
                     58:        mov     ax,#INITSEG
                     59:        mov     es,ax
                     60:        mov     cx,#256
                     61:        sub     si,si
                     62:        sub     di,di
                     63:        rep
                     64:        movw
                     65:        jmpi    go,INITSEG
                     66: go:    mov     ax,cs
                     67:        mov     ds,ax
                     68:        mov     es,ax
                     69:        mov     ss,ax
1.1.1.2 ! root       70:        mov     sp,#0x400               ; arbitrary value >>512
1.1       root       71: 
1.1.1.2 ! root       72:        mov     ah,#0x03        ; read cursor pos
1.1       root       73:        xor     bh,bh
                     74:        int     0x10
                     75:        
                     76:        mov     cx,#24
1.1.1.2 ! root       77:        mov     bx,#0x0007      ; page 0, attribute 7 (normal)
1.1       root       78:        mov     bp,#msg1
1.1.1.2 ! root       79:        mov     ax,#0x1301      ; write string, move cursor
1.1       root       80:        int     0x10
                     81: 
1.1.1.2 ! root       82: ; ok, we've written the message, now
        !            83: ; we want to load the system (at 0x10000)
1.1       root       84: 
                     85:        mov     ax,#SYSSEG
1.1.1.2 ! root       86:        mov     es,ax           ; segment of 0x010000
1.1       root       87:        call    read_it
                     88:        call    kill_motor
                     89: 
1.1.1.2 ! root       90: ; if the read went well we get current cursor position ans save it for
        !            91: ; posterity.
1.1       root       92: 
1.1.1.2 ! root       93:        mov     ah,#0x03        ; read cursor pos
1.1       root       94:        xor     bh,bh
1.1.1.2 ! root       95:        int     0x10            ; save it in known place, con_init fetches
        !            96:        mov     [510],dx        ; it from 0x90510.
1.1       root       97:                
1.1.1.2 ! root       98: ; now we want to move to protected mode ...
1.1       root       99: 
1.1.1.2 ! root      100:        cli                     ; no interrupts allowed !
1.1       root      101: 
1.1.1.2 ! root      102: ; first we move the system to it's rightful place
1.1       root      103: 
                    104:        mov     ax,#0x0000
1.1.1.2 ! root      105:        cld                     ; 'direction'=0, movs moves forward
1.1       root      106: do_move:
1.1.1.2 ! root      107:        mov     es,ax           ; destination segment
1.1       root      108:        add     ax,#0x1000
                    109:        cmp     ax,#0x9000
                    110:        jz      end_move
1.1.1.2 ! root      111:        mov     ds,ax           ; source segment
1.1       root      112:        sub     di,di
                    113:        sub     si,si
                    114:        mov     cx,#0x8000
                    115:        rep
                    116:        movsw
                    117:        j       do_move
                    118: 
1.1.1.2 ! root      119: ; then we load the segment descriptors
1.1       root      120: 
                    121: end_move:
                    122: 
1.1.1.2 ! root      123:        mov     ax,cs           ; right, forgot this at first. didn't work :-)
1.1       root      124:        mov     ds,ax
1.1.1.2 ! root      125:        lidt    idt_48          ; load idt with 0,0
        !           126:        lgdt    gdt_48          ; load gdt with whatever appropriate
1.1       root      127: 
1.1.1.2 ! root      128: ; that was painless, now we enable A20
1.1       root      129: 
                    130:        call    empty_8042
1.1.1.2 ! root      131:        mov     al,#0xD1                ; command write
1.1       root      132:        out     #0x64,al
                    133:        call    empty_8042
1.1.1.2 ! root      134:        mov     al,#0xDF                ; A20 on
1.1       root      135:        out     #0x60,al
                    136:        call    empty_8042
                    137: 
1.1.1.2 ! root      138: ; well, that went ok, I hope. Now we have to reprogram the interrupts :-(
        !           139: ; we put them right after the intel-reserved hardware interrupts, at
        !           140: ; int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
        !           141: ; messed this up with the original PC, and they haven't been able to
        !           142: ; rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
        !           143: ; which is used for the internal hardware interrupts as well. We just
        !           144: ; have to reprogram the 8259's, and it isn't fun.
        !           145: 
        !           146:        mov     al,#0x11                ; initialization sequence
        !           147:        out     #0x20,al                ; send it to 8259A-1
        !           148:        .word   0x00eb,0x00eb           ; jmp $+2, jmp $+2
        !           149:        out     #0xA0,al                ; and to 8259A-2
1.1       root      150:        .word   0x00eb,0x00eb
1.1.1.2 ! root      151:        mov     al,#0x20                ; start of hardware int's (0x20)
1.1       root      152:        out     #0x21,al
                    153:        .word   0x00eb,0x00eb
1.1.1.2 ! root      154:        mov     al,#0x28                ; start of hardware int's 2 (0x28)
1.1       root      155:        out     #0xA1,al
                    156:        .word   0x00eb,0x00eb
1.1.1.2 ! root      157:        mov     al,#0x04                ; 8259-1 is master
1.1       root      158:        out     #0x21,al
                    159:        .word   0x00eb,0x00eb
1.1.1.2 ! root      160:        mov     al,#0x02                ; 8259-2 is slave
1.1       root      161:        out     #0xA1,al
                    162:        .word   0x00eb,0x00eb
1.1.1.2 ! root      163:        mov     al,#0x01                ; 8086 mode for both
1.1       root      164:        out     #0x21,al
                    165:        .word   0x00eb,0x00eb
                    166:        out     #0xA1,al
                    167:        .word   0x00eb,0x00eb
1.1.1.2 ! root      168:        mov     al,#0xFF                ; mask off all interrupts for now
1.1       root      169:        out     #0x21,al
                    170:        .word   0x00eb,0x00eb
                    171:        out     #0xA1,al
                    172: 
1.1.1.2 ! root      173: ; well, that certainly wasn't fun :-(. Hopefully it works, and we don't
        !           174: ; need no steenking BIOS anyway (except for the initial loading :-).
        !           175: ; The BIOS-routine wants lots of unnecessary data, and it's less
        !           176: ; "interesting" anyway. This is how REAL programmers do it.
        !           177: ;
        !           178: ; Well, now's the time to actually move into protected mode. To make
        !           179: ; things as simple as possible, we do no register set-up or anything,
        !           180: ; we let the gnu-compiled 32-bit programs do that. We just jump to
        !           181: ; absolute address 0x00000, in 32-bit protected mode.
        !           182: 
        !           183:        mov     ax,#0x0001      ; protected mode (PE) bit
        !           184:        lmsw    ax              ; This is it!
        !           185:        jmpi    0,8             ; jmp offset 0 of segment 8 (cs)
        !           186: 
        !           187: ; This routine checks that the keyboard command queue is empty
        !           188: ; No timeout is used - if this hangs there is something wrong with
        !           189: ; the machine, and we probably couldn't proceed anyway.
1.1       root      190: empty_8042:
                    191:        .word   0x00eb,0x00eb
1.1.1.2 ! root      192:        in      al,#0x64        ; 8042 status port
        !           193:        test    al,#2           ; is input buffer full?
        !           194:        jnz     empty_8042      ; yes - loop
1.1       root      195:        ret
                    196: 
1.1.1.2 ! root      197: ; This routine loads the system at address 0x10000, making sure
        !           198: ; no 64kB boundaries are crossed. We try to load it as fast as
        !           199: ; possible, loading whole tracks whenever we can.
        !           200: ;
        !           201: ; in:  es - starting address segment (normally 0x1000)
        !           202: ;
        !           203: ; This routine has to be recompiled to fit another drive type,
        !           204: ; just change the "sectors" variable at the start of the file
        !           205: ; (originally 18, for a 1.44Mb drive)
        !           206: ;
        !           207: sread: .word 1                 ; sectors read of current track
        !           208: head:  .word 0                 ; current head
        !           209: track: .word 0                 ; current track
1.1       root      210: read_it:
                    211:        mov ax,es
                    212:        test ax,#0x0fff
1.1.1.2 ! root      213: die:   jne die                 ; es must be at 64kB boundary
        !           214:        xor bx,bx               ; bx is starting address within segment
1.1       root      215: rp_read:
                    216:        mov ax,es
1.1.1.2 ! root      217:        cmp ax,#ENDSEG          ; have we loaded all yet?
1.1       root      218:        jb ok1_read
                    219:        ret
                    220: ok1_read:
                    221:        mov ax,#sectors
                    222:        sub ax,sread
                    223:        mov cx,ax
                    224:        shl cx,#9
                    225:        add cx,bx
                    226:        jnc ok2_read
                    227:        je ok2_read
                    228:        xor ax,ax
                    229:        sub ax,bx
                    230:        shr ax,#9
                    231: ok2_read:
                    232:        call read_track
                    233:        mov cx,ax
                    234:        add ax,sread
                    235:        cmp ax,#sectors
                    236:        jne ok3_read
                    237:        mov ax,#1
                    238:        sub ax,head
                    239:        jne ok4_read
                    240:        inc track
                    241: ok4_read:
                    242:        mov head,ax
                    243:        xor ax,ax
                    244: ok3_read:
                    245:        mov sread,ax
                    246:        shl cx,#9
                    247:        add bx,cx
                    248:        jnc rp_read
                    249:        mov ax,es
                    250:        add ax,#0x1000
                    251:        mov es,ax
                    252:        xor bx,bx
                    253:        jmp rp_read
                    254: 
                    255: read_track:
                    256:        push ax
                    257:        push bx
                    258:        push cx
                    259:        push dx
                    260:        mov dx,track
                    261:        mov cx,sread
                    262:        inc cx
                    263:        mov ch,dl
                    264:        mov dx,head
                    265:        mov dh,dl
                    266:        mov dl,#0
                    267:        and dx,#0x0100
                    268:        mov ah,#2
                    269:        int 0x13
                    270:        jc bad_rt
                    271:        pop dx
                    272:        pop cx
                    273:        pop bx
                    274:        pop ax
                    275:        ret
                    276: bad_rt:        mov ax,#0
                    277:        mov dx,#0
                    278:        int 0x13
                    279:        pop dx
                    280:        pop cx
                    281:        pop bx
                    282:        pop ax
                    283:        jmp read_track
                    284: 
                    285: /*
                    286:  * This procedure turns off the floppy drive motor, so
                    287:  * that we enter the kernel in a known state, and
                    288:  * don't have to worry about it later.
                    289:  */
                    290: kill_motor:
                    291:        push dx
                    292:        mov dx,#0x3f2
                    293:        mov al,#0
                    294:        outb
                    295:        pop dx
                    296:        ret
                    297: 
                    298: gdt:
1.1.1.2 ! root      299:        .word   0,0,0,0         ; dummy
1.1       root      300: 
1.1.1.2 ! root      301:        .word   0x07FF          ; 8Mb - limit=2047 (2048*4096=8Mb)
        !           302:        .word   0x0000          ; base address=0
        !           303:        .word   0x9A00          ; code read/exec
        !           304:        .word   0x00C0          ; granularity=4096, 386
        !           305: 
        !           306:        .word   0x07FF          ; 8Mb - limit=2047 (2048*4096=8Mb)
        !           307:        .word   0x0000          ; base address=0
        !           308:        .word   0x9200          ; data read/write
        !           309:        .word   0x00C0          ; granularity=4096, 386
1.1       root      310: 
                    311: idt_48:
1.1.1.2 ! root      312:        .word   0                       ; idt limit=0
        !           313:        .word   0,0                     ; idt base=0L
1.1       root      314: 
                    315: gdt_48:
1.1.1.2 ! root      316:        .word   0x800           ; gdt limit=2048, 256 GDT entries
        !           317:        .word   gdt,0x9         ; gdt base = 0X9xxxx
1.1       root      318:        
                    319: msg1:
                    320:        .byte 13,10
                    321:        .ascii "Loading system ..."
                    322:        .byte 13,10,13,10
                    323: 
                    324: .text
                    325: endtext:
                    326: .data
                    327: enddata:
                    328: .bss
                    329: endbss:

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.