- .code16
- # rewrite with AT&T syntax by falcon at 081012
- #
- # setup.s (C) 1991 Linus Torvalds
- #
- # setup.s is responsible for getting the system data from the BIOS,
- # and putting them into the appropriate places in system memory.
- # both setup.s and system has been loaded by the bootblock.
- #
- # This code asks the bios for memory/disk/other parameters, and
- # puts them in a "safe" place: 0x90000-0x901FF, ie where the
- # boot-block used to be. It is then up to the protected mode
- # system to read them from there before the area is overwritten
- # for buffer-blocks.
- #
- # NOTE! These had better be the same as in bootsect.s!
- .equ INITSEG, 0x9000 # we move boot here - out of the way
- .equ SYSSEG, 0x1000 # system loaded at 0x10000 (65536).
- .equ SETUPSEG, 0x9020 # this is the current segment
- .global _start, begtext, begdata, begbss, endtext, enddata, endbss
- .text
- begtext:
- .data
- begdata:
- .bss
- begbss:
- .text
- ljmp $SETUPSEG, $_start #boot/bootsetup.s中,會透過ljmp $SETUPSEG, $0跳到這一行
- _start:
- # ok, the read went well so we get current cursor position and save it for
- # posterity.
- mov $INITSEG, %ax # this is done in bootsect already, but...,這裡原先是放用來執行bootsect的code,
- #但現在已經用不到了,改為放從bios讀到的資訊(cursor pos,memory size,...)
- mov %ax, %ds
- mov $0x03, %ah # read cursor pos
- xor %bh, %bh
- int $0x10 # save it in known place, con_init fetches
- mov %dx, %ds:0 # it from 0x90000.
- # Get memory size (extended mem, kB)
- mov $0x88, %ah
- int $0x15
- mov %ax, %ds:2
- # Get video-card data:
- mov $0x0f, %ah
- int $0x10
- mov %bx, %ds:4 # bh = display page
- mov %ax, %ds:6 # al = video mode, ah = window width
- # check for EGA/VGA and some config parameters
- mov $0x12, %ah
- mov $0x10, %bl
- int $0x10
- mov %ax, %ds:8
- mov %bx, %ds:10
- mov %cx, %ds:12
- # Get hd0 data
- mov $0x0000, %ax
- mov %ax, %ds
- lds %ds:4*0x41, %si
- mov $INITSEG, %ax
- mov %ax, %es
- mov $0x0080, %di
- mov $0x10, %cx
- rep
- movsb
- # Get hd1 data
- mov $0x0000, %ax
- mov %ax, %ds
- lds %ds:4*0x46, %si
- mov $INITSEG, %ax
- mov %ax, %es
- mov $0x0090, %di
- mov $0x10, %cx
- rep
- movsb
- # Check that there IS a hd1 :-)
- mov $0x01500, %ax
- mov $0x81, %dl
- int $0x13
- jc no_disk1
- cmp $3, %ah
- je is_disk1
- no_disk1:
- mov $INITSEG, %ax
- mov %ax, %es
- mov $0x0090, %di
- mov $0x10, %cx
- mov $0x00, %ax
- rep
- stosb
- is_disk1:
- # now we want to move to protected mode ...
- cli # no interrupts allowed !
- # first we move the system to it's rightful place,system大小=tools/kernel=121508bytes
- mov $0x0000, %ax
- cld # 'direction'=0, movs moves forward,SI DI遞增
- do_move: #第一次為將資料從source 0x1000 移到destination 0x0000,移65536bytes,
- #之後為source與dest分別加0x1000再做相同的動作,直到src=0x9000時,則跳出迴圈
- mov %ax, %es # destination segment
- add $0x1000, %ax
- cmp $0x9000, %ax #因為這邊system大小為121508bytes,故最少只須搬兩次(65536*2),即最少只須cmp到$0x3000
- jz end_move
- mov %ax, %ds # source segment
- sub %di, %di
- sub %si, %si
- mov $0x8000, %cx
- rep
- movsw
- jmp do_move
- # then we load the segment descriptors
- end_move:
- mov $SETUPSEG, %ax # right, forgot this at first. didn't work :-)
- mov %ax, %ds
- lidt idt_48 # load idt with 0,0
- lgdt gdt_48 # load gdt with whatever appropriate
- # that was painless, now we enable A20
- #call empty_8042 # 8042 is the keyboard controller
- #mov $0xD1, %al # command write
- #out %al, $0x64
- #call empty_8042
- #mov $0xDF, %al # A20 on
- #out %al, $0x60
- #call empty_8042
- inb $0x92, %al # open A20 line(Fast Gate A20).
- orb $0b00000010, %al
- outb %al, $0x92
- # well, that went ok, I hope. Now we have to reprogram the interrupts :-(
- # we put them right after the intel-reserved hardware interrupts, at
- # int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
- # messed this up with the original PC, and they haven't been able to
- # rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
- # which is used for the internal hardware interrupts as well. We just
- # have to reprogram the 8259's, and it isn't fun.
- mov $0x11, %al # initialization sequence(ICW1)
- # ICW4 needed(1),CASCADE mode,Level-triggered
- out %al, $0x20 # send it to 8259A-1
- .word 0x00eb,0x00eb # jmp $+2, jmp $+2
- out %al, $0xA0 # and to 8259A-2
- .word 0x00eb,0x00eb
- mov $0x20, %al # start of hardware int's (0x20)(ICW2)
- out %al, $0x21 # from 0x20-0x27
- .word 0x00eb,0x00eb
- mov $0x28, %al # start of hardware int's 2 (0x28)
- out %al, $0xA1 # from 0x28-0x2F
- .word 0x00eb,0x00eb # IR 7654 3210
- mov $0x04, %al # 8259-1 is master(0000 0100) --\
- out %al, $0x21 # |
- .word 0x00eb,0x00eb # INT /
- mov $0x02, %al # 8259-2 is slave( 010 --> 2)
- out %al, $0xA1
- .word 0x00eb,0x00eb
- mov $0x01, %al # 8086 mode for both
- out %al, $0x21
- .word 0x00eb,0x00eb
- out %al, $0xA1
- .word 0x00eb,0x00eb
- mov $0xFF, %al # mask off all interrupts for now
- out %al, $0x21
- .word 0x00eb,0x00eb
- out %al, $0xA1
- # well, that certainly wasn't fun :-(. Hopefully it works, and we don't
- # need no steenking BIOS anyway (except for the initial loading :-).
- # The BIOS-routine wants lots of unnecessary data, and it's less
- # "interesting" anyway. This is how REAL programmers do it.
- #
- # Well, now's the time to actually move into protected mode. To make
- # things as simple as possible, we do no register set-up or anything,
- # we let the gnu-compiled 32-bit programs do that. We just jump to
- # absolute address 0x00000, in 32-bit protected mode.
- #mov $0x0001, %ax # protected mode (PE) bit
- #lmsw %ax # This is it!
- mov %cr0, %eax # get machine status(cr0|MSW)
- bts $0, %eax # turn on the PE-bit
- mov %eax, %cr0 # protection enabled
-
- # segment-descriptor (INDEX:TI:RPL)
- .equ sel_cs0, 0x0008 # select for code segment 0 ( 001:0 :00)
- ljmp $sel_cs0, $0 # jmp offset 0 of code segment 0 in gdt
- # This routine checks that the keyboard command queue is empty
- # No timeout is used - if this hangs there is something wrong with
- # the machine, and we probably couldn't proceed anyway.
- empty_8042:
- .word 0x00eb,0x00eb
- in $0x64, %al # 8042 status port
- test $2, %al # is input buffer full?
- jnz empty_8042 # yes - loop
- ret
- gdt:
- .word 0,0,0,0 # dummy
- .word 0x07FF # 8Mb - limit=2047 (2048*4096=8Mb)
- .word 0x0000 # base address=0
- .word 0x9A00 # code read/exec
- .word 0x00C0 # granularity=4096, 386
- .word 0x07FF # 8Mb - limit=2047 (2048*4096=8Mb)
- .word 0x0000 # base address=0
- .word 0x9200 # data read/write
- .word 0x00C0 # granularity=4096, 386
- idt_48:
- .word 0 # idt limit=0
- .word 0,0 # idt base=0L
- gdt_48:
- .word 0x800 # gdt limit=2048, 256 GDT entries
- .word 512+gdt, 0x9 # gdt base = 0X9xxxx,
- # 512+gdt is the real gdt after setup is moved to 0x9020 * 0x10
-
- .text
- endtext:
- .data
- enddata:
- .bss
- endbss: