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

1.1       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.
                     32: 
                     33: | 1.44Mb disks:
                     34: sectors = 18
                     35: | 1.2Mb disks:
                     36: | sectors = 15
                     37: | 720kB disks:
                     38: | sectors = 9
                     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
                     51: SYSSEG  = 0x1000                       | system loaded at 0x10000 (65536).
                     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
                     70:        mov     sp,#0x400               | arbitrary value >>512
                     71: 
                     72:        mov     ah,#0x03        | read cursor pos
                     73:        xor     bh,bh
                     74:        int     0x10
                     75:        
                     76:        mov     cx,#24
                     77:        mov     bx,#0x0007      | page 0, attribute 7 (normal)
                     78:        mov     bp,#msg1
                     79:        mov     ax,#0x1301      | write string, move cursor
                     80:        int     0x10
                     81: 
                     82: | ok, we've written the message, now
                     83: | we want to load the system (at 0x10000)
                     84: 
                     85:        mov     ax,#SYSSEG
                     86:        mov     es,ax           | segment of 0x010000
                     87:        call    read_it
                     88:        call    kill_motor
                     89: 
                     90: | if the read went well we get current cursor position ans save it for
                     91: | posterity.
                     92: 
                     93:        mov     ah,#0x03        | read cursor pos
                     94:        xor     bh,bh
                     95:        int     0x10            | save it in known place, con_init fetches
                     96:        mov     [510],dx        | it from 0x90510.
                     97:                
                     98: | now we want to move to protected mode ...
                     99: 
                    100:        cli                     | no interrupts allowed !
                    101: 
                    102: | first we move the system to it's rightful place
                    103: 
                    104:        mov     ax,#0x0000
                    105:        cld                     | 'direction'=0, movs moves forward
                    106: do_move:
                    107:        mov     es,ax           | destination segment
                    108:        add     ax,#0x1000
                    109:        cmp     ax,#0x9000
                    110:        jz      end_move
                    111:        mov     ds,ax           | source segment
                    112:        sub     di,di
                    113:        sub     si,si
                    114:        mov     cx,#0x8000
                    115:        rep
                    116:        movsw
                    117:        j       do_move
                    118: 
                    119: | then we load the segment descriptors
                    120: 
                    121: end_move:
                    122: 
                    123:        mov     ax,cs           | right, forgot this at first. didn't work :-)
                    124:        mov     ds,ax
                    125:        lidt    idt_48          | load idt with 0,0
                    126:        lgdt    gdt_48          | load gdt with whatever appropriate
                    127: 
                    128: | that was painless, now we enable A20
                    129: 
                    130:        call    empty_8042
                    131:        mov     al,#0xD1                | command write
                    132:        out     #0x64,al
                    133:        call    empty_8042
                    134:        mov     al,#0xDF                | A20 on
                    135:        out     #0x60,al
                    136:        call    empty_8042
                    137: 
                    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
                    150:        .word   0x00eb,0x00eb
                    151:        mov     al,#0x20                | start of hardware int's (0x20)
                    152:        out     #0x21,al
                    153:        .word   0x00eb,0x00eb
                    154:        mov     al,#0x28                | start of hardware int's 2 (0x28)
                    155:        out     #0xA1,al
                    156:        .word   0x00eb,0x00eb
                    157:        mov     al,#0x04                | 8259-1 is master
                    158:        out     #0x21,al
                    159:        .word   0x00eb,0x00eb
                    160:        mov     al,#0x02                | 8259-2 is slave
                    161:        out     #0xA1,al
                    162:        .word   0x00eb,0x00eb
                    163:        mov     al,#0x01                | 8086 mode for both
                    164:        out     #0x21,al
                    165:        .word   0x00eb,0x00eb
                    166:        out     #0xA1,al
                    167:        .word   0x00eb,0x00eb
                    168:        mov     al,#0xFF                | mask off all interrupts for now
                    169:        out     #0x21,al
                    170:        .word   0x00eb,0x00eb
                    171:        out     #0xA1,al
                    172: 
                    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.
                    190: empty_8042:
                    191:        .word   0x00eb,0x00eb
                    192:        in      al,#0x64        | 8042 status port
                    193:        test    al,#2           | is input buffer full?
                    194:        jnz     empty_8042      | yes - loop
                    195:        ret
                    196: 
                    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
                    210: read_it:
                    211:        mov ax,es
                    212:        test ax,#0x0fff
                    213: die:   jne die                 | es must be at 64kB boundary
                    214:        xor bx,bx               | bx is starting address within segment
                    215: rp_read:
                    216:        mov ax,es
                    217:        cmp ax,#ENDSEG          | have we loaded all yet?
                    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:
                    299:        .word   0,0,0,0         | dummy
                    300: 
                    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
                    310: 
                    311: idt_48:
                    312:        .word   0                       | idt limit=0
                    313:        .word   0,0                     | idt base=0L
                    314: 
                    315: gdt_48:
                    316:        .word   0x800           | gdt limit=2048, 256 GDT entries
                    317:        .word   gdt,0x9         | gdt base = 0X9xxxx
                    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.