Annotation of linux/boot/boot.s, revision 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.