📄 boothead.s
字号:
_peekchar: movb ah, #0x01 ! Keyboard status int 0x16 jnz getc ! Keypress? mov ax, #-1 ! No key ret_getchar: xorb ah, ah ! Read character from keyboard int 0x16getc: cmpb al, #0x0D ! Carriage return? jnz nocr movb al, #0x0A ! Change to linefeednocr: xorb ah, ah ! ax = al ret! int putchar(int c);! Write a character in teletype mode. The putc and putk synonyms! are for the kernel printk function that uses one of them.! Newlines are automatically preceded by a carriage return.!.define _putchar, _putc, _putk_putchar:_putc:_putk: mov bx, sp movb al, 2(bx) ! al = character to be printed testb al, al ! 1.6.* printk adds a trailing null jz nulch cmpb al, #0x0A ! al = newline? jnz putc movb al, #0x0D call putc ! putc('\r') movb al, #0x0A ! Restore the '\n' and print itputc: movb ah, #0x0E ! Print character in teletype mode mov bx, #0x0001 ! Page 0, foreground color int 0x10 ! Call BIOS VIDEO_IOnulch: ret! void reset_video(unsigned mode);! Reset and clear the screen..define _reset_video_reset_video: mov bx, sp mov ax, 2(bx) ! Video mode mov cur_vid_mode, ax testb ah, ah jnz xvesa ! VESA extended mode? int 0x10 ! Reset video (ah = 0) jmp setcurxvesa: mov bx, ax ! bx = extended mode mov ax, #0x4F02 ! Reset video int 0x10setcur: xor dx, dx ! dl = column = 0, dh = row = 0 xorb bh, bh ! Page 0 movb ah, #0x02 ! Set cursor position int 0x10 retrestore_video: ! To restore the video mode on exit mov ax, old_vid_mode cmp ax, cur_vid_mode je vidok push ax call _reset_video pop axvidok: ret! u32_t get_tick(void);! Return the current value of the clock tick counter. This counter! increments 18.2 times per second. Poll it to do delays. Does not! work on the original PC, but works on the PC/XT..define _get_tick_get_tick: xorb ah, ah ! Code for get tick count int 0x1A mov ax, dx mov dx, cx ! dx:ax = cx:dx = tick count ret! Functions used to obtain info about the hardware, like the type of video! and amount of memory. Boot uses this information itself, but will also! pass them on to a pure 386 kernel, because one can't make BIOS calls from! protected mode. The video type could probably be determined by the kernel! too by looking at the hardware, but there is a small chance on errors that! the monitor allows you to correct by setting variables..define _get_bus ! returns type of system bus.define _get_video ! returns type of display.define _get_memsize ! returns amount of low memory in K.define _get_ext_memsize ! returns amount of extended memory in K! u16_t get_bus(void)! Return type of system bus, in order: XT, AT, MCA._get_bus: call _getprocessor xor dx, dx ! Assume XT cmp ax, #286 ! An AT has at least a 286 jb got_bus inc dx ! Assume AT movb ah, #0xC0 ! Code for get configuration int 0x15 jc got_bus ! Carry clear and ah = 00 if supported testb ah, ah jne got_bus eseg movb al, 5(bx) ! Load feature byte #1 inc dx ! Assume MCA testb al, #0x02 ! Test bit 1 - "bus is Micro Channel" jnz got_bus dec dx ! Assume AT testb al, #0x40 ! Test bit 6 - "2nd 8259 installed" jnz got_bus dec dx ! It is an XTgot_bus: push ds pop es ! Restore es mov ax, dx ! Return bus code ret! u16_t get_video(void)! Return type of display, in order: MDA, CGA, mono EGA, color EGA,! mono VGA, color VGA._get_video: mov ax, #0x1A00 ! Function 1A returns display code int 0x10 ! al = 1A if supported cmpb al, #0x1A jnz no_dc ! No display code function supported mov ax, #2 cmpb bl, #5 ! Is it a monochrome EGA? jz got_video inc ax cmpb bl, #4 ! Is it a color EGA? jz got_video inc ax cmpb bl, #7 ! Is it a monochrome VGA? jz got_video inc ax cmpb bl, #8 ! Is it a color VGA? jz got_videono_dc: movb ah, #0x12 ! Get information about the EGA movb bl, #0x10 int 0x10 cmpb bl, #0x10 ! Did it come back as 0x10? (No EGA) jz no_ega mov ax, #2 cmpb bh, #1 ! Is it monochrome? jz got_video inc ax jmp got_videono_ega: int 0x11 ! Get bit pattern for equipment and ax, #0x30 ! Isolate color/mono field sub ax, #0x30 jz got_video ! Is it an MDA? mov ax, #1 ! No it's CGAgot_video: ret! u16_t get_memsize(void);! Ask the BIOS how much normal memory there is._get_memsize: int 0x12 ! Returns the size (in K) in ax ret! u32_t get_ext_memsize(void);! Ask the BIOS how much extended memory there is._get_ext_memsize: call _getprocessor cmp ax, #286 ! Only 286s and above have extended memory jb no_ext movb ah, #0x88 ! Code for get extended memory size clc ! Carry will stay clear if call exists int 0x15 ! Returns size (in K) in ax for AT's jnc got_extno_ext: xor ax, ax ! Error, no extended memorygot_ext: xor dx, dx ret! Functions to leave the boot monitor..define _bootstrap ! Call another bootstrap.define _minix ! Call Minix! void _bootstrap(int device, struct part_entry *entry)! Call another bootstrap routine to boot MS-DOS for instance. (No real! need for that anymore, now that you can format floppies under Minix).! The bootstrap must have been loaded at BOOTSEG from "device"._bootstrap: call restore_video mov bx, sp movb dl, 2(bx) ! Device to boot from mov si, 4(bx) ! ds:si = partition table entry xor ax, ax mov es, ax ! Vector segment mov di, #BUFFER ! es:di = buffer in low core mov cx, #PENTRYSIZE ! cx = size of partition table entry rep movsb ! Copy the entry to low core mov si, #BUFFER ! es:si = partition table entry mov ds, ax ! Some bootstraps need zero segment registers cli mov ss, ax mov sp, #BOOTOFF ! This should do it sti jmpf BOOTOFF, 0 ! Back to where the BIOS loads the boot code! u32_t minix(u32_t koff, u32_t kcs, u32_t kds,! char *bootparams, size_t paramsize);! Call Minix._minix: push bp mov bp, sp ! Pointer to arguments mov dx, #0x03F2 ! Floppy motor drive control bits movb al, #0x0C ! Bits 4-7 for floppy 0-3 are off outb dx ! Kill the motors push ds mov ax, #0x0040 ! BIOS data segment mov ds, ax andb 0x003F, #0xF0 ! Clear diskette motor status bits of BIOS pop ds cli ! No more interruptions test _k_flags, #K_I386 ! Switch to 386 mode? jnz minix386! Call Minix in real mode.minix86: push 18(bp) ! # bytes of boot parameters push 16(bp) ! address of boot parameters test _k_flags, #K_RET ! Can the kernel return? jz noret86 push cs mov ax, #ret86 push ax ! Monitor far return addressnoret86: mov ax, 8(bp) mov dx, 10(bp) call abs2seg push dx ! Kernel code segment push 4(bp) ! Kernel code offset mov ax, 12(bp) mov dx, 14(bp) call abs2seg mov ds, dx ! Kernel data segment mov es, dx ! Set es to kernel data too retf ! Make a far call to the kernel! Call Minix in 386 mode.minix386: cseg mov cs_real-2, cs ! Patch CS and DS into the instructions that cseg mov ds_real-2, ds ! reload them when switching back to real mode mov dx, ds ! Monitor ds mov ax, #p_gdt ! dx:ax = Global descriptor table call seg2abs mov p_gdt_desc+2, ax movb p_gdt_desc+4, dl ! Set base of global descriptor table mov ax, 12(bp) mov dx, 14(bp) ! Kernel ds (absolute address) mov p_ds_desc+2, ax movb p_ds_desc+4, dl ! Set base of kernel data segment mov dx, ss ! Monitor ss xor ax, ax ! dx:ax = Monitor stack segment call seg2abs ! Minix starts with the stack of the monitor mov p_ss_desc+2, ax movb p_ss_desc+4, dl mov ax, 8(bp) mov dx, 10(bp) ! Kernel cs (absolute address) mov p_cs_desc+2, ax movb p_cs_desc+4, dl mov dx, cs ! Monitor cs xor ax, ax ! dx:ax = Monitor code segment call seg2abs mov p_mcs_desc+2, ax movb p_mcs_desc+4, dl push #MCS_SELECTOR push #bios13 ! Far address to BIOS int 13 support push #0 push 18(bp) ! 32 bit size of parameters on stack push #0 push 16(bp) ! 32 bit address of parameters (ss relative) test _k_flags, #K_RET ! Can the kernel return? jz noret386 push #MCS_SELECTOR push #ret386 ! Monitor far return addressnoret386: push #0 push #CS_SELECTOR push 6(bp) push 4(bp) ! 32 bit far address to kernel entry point call real2prot ! Switch to protected mode mov ax, #DS_SELECTOR ! Kernel data mov ds, ax mov ax, #ES_SELECTOR ! Flat 4 Gb mov es, ax .data1 o32 ! Make a far call to the kernel retf! Minix-86 returns here on a halt or reboot.ret86: mov 8(bp), ax mov 10(bp), dx ! Return value jmp return! Minix-386 returns here on a halt or reboot.ret386: .data1 o32 mov 8(bp), ax ! Return value call prot2real ! Switch to real modereturn: mov sp, bp ! Pop parameters sti ! Can take interrupts again call _get_video ! MDA, CGA, EGA, ... movb dh, #24 ! dh = row 24 cmp ax, #2 ! At least EGA? jb is25 ! Otherwise 25 rows push ds mov ax, #0x0040 ! BIOS data segment mov ds, ax movb dh, 0x0084 ! Number of rows on display minus one pop dsis25: xorb dl, dl ! dl = column 0 xorb bh, bh ! Page 0 movb ah, #0x02 ! Set cursor position int 0x10 mov cur_vid_mode, #-1 ! Minix may have messed things up mov ax, 8(bp) mov dx, 10(bp) ! dx-ax = return value from the kernel pop bp ret ! Continue as if nothing happened! Support function for Minix-386 to make a BIOS int 13 call (disk I/O)..define bios13bios13: mov bp, sp call prot2real mov ax, 8(bp) ! Load parameters mov bx, 10(bp) mov cx, 12(bp) mov dx, 14(bp) mov es, 16(bp) sti ! Enable interrupts int 0x13 ! Make the BIOS call cli ! Disable interrupts mov 8(bp), ax ! Save results mov 10(bp), bx mov 12(bp), cx mov 14(bp), dx mov 16(bp), es call real2prot mov ax, #DS_SELECTOR ! Kernel data mov ds, ax .data1 o32 retf ! Return to the kernel! Switch from real to protected mode.real2prot: lgdt p_gdt_desc ! Global descriptor table .data1 0x0F,0x20,0xC0 ! mov eax, cr0 .data1 o32 mov msw, ax ! Save cr0 orb al, #0x01 ! Set PE (protection enable) bit .data1 0x0F,0x22,0xC0 ! mov cr0, eax jmpf cs_prot, MCS_SELECTOR ! Set code segment selectorcs_prot: mov ax, #SS_SELECTOR ! Set data selectors mov ds, ax mov es, ax mov ss, ax movb ah, #0xDF ! Code for A20 enable jmp gate_A20! Switch from protected to real mode.prot2real: lidt p_idt_desc ! Real mode interrupt vectors .data1 o32 mov ax, msw ! Saved cr0 .data1 0x0F,0x22,0xC0 ! mov cr0, eax jmpf cs_real, 0xDEAD ! Reload cs registercs_real: mov ax, #0xBEEFds_real: mov ds, ax ! Reload data segment registers mov es, ax mov ss, ax movb ah, #0xDD ! Code for A20 disable !jmp gate_A20! Enable (ah = 0xDF) or disable (ah = 0xDD) the A20 address line.gate_A20: call kb_wait movb al, #0xD1 ! Tell keyboard that a command is coming outb 0x64 call kb_wait movb al, ah ! Enable or disable code outb 0x60 call kb_wait mov ax, #25 ! 25 microsec delay for slow keyboard chip0: out 0xED ! Write to an unused port (1us) dec ax jne 0b retkb_wait: inb 0x64 testb al, #0x02 ! Keyboard input buffer full? jnz kb_wait ! If so, wait ret.data .align 2! Global descriptor tables. UNSET = 0 ! Must be computed! For "Extended Memory Block Move".x_gdt:x_null_desc: ! Null descriptor .data2 0x0000, 0x0000 .data1 0x00, 0x00, 0x00, 0x00x_gdt_desc: ! Descriptor for this descriptor table .data2 6*8-1, UNSET .data1 UNSET, 0x00, 0x00, 0x00x_src_desc: ! Source segment descriptor .data2 0xFFFF, UNSET .data1 UNSET, 0x92, 0x00, 0x00x_dst_desc: ! Destination segment descriptor .data2 0xFFFF, UNSET .data1 UNSET, 0x92, 0x00, 0x00x_bios_desc: ! BIOS segment descriptor (scratch for int 0x15) .data2 UNSET, UNSET .data1 UNSET, UNSET, UNSET, UNSETx_ss_desc: ! BIOS stack segment descriptor (scratch for int 0x15) .data2 UNSET, UNSET .data1 UNSET, UNSET, UNSET, UNSET! Protected mode descriptor table.p_gdt:p_null_desc: ! Null descriptor .data2 0x0000, 0x0000 .data1 0x00, 0x00, 0x00, 0x00p_gdt_desc: ! Descriptor for this descriptor table .data2 8*8-1, UNSET .data1 UNSET, 0x00, 0x00, 0x00p_idt_desc: ! Real mode interrupt descriptor table descriptor .data2 0x03FF, 0x0000 .data1 0x00, 0x00, 0x00, 0x00p_ds_desc: ! Kernel data segment descriptor (4 Gb flat) .data2 0xFFFF, UNSET .data1 UNSET, 0x92, 0xCF, 0x00p_es_desc: ! Physical memory descriptor (4 Gb flat) .data2 0xFFFF, 0x0000 .data1 0x00, 0x92, 0xCF, 0x00p_ss_desc: ! Monitor data segment descriptor (64 kb flat) .data2 0xFFFF, UNSET .data1 UNSET, 0x92, 0x00, 0x00p_cs_desc: ! Kernel code segment descriptor (4 Gb flat) .data2 0xFFFF, UNSET .data1 UNSET, 0x9A, 0xCF, 0x00p_mcs_desc: ! Monitor code segment descriptor (64 kb flat) .data2 0xFFFF, UNSET .data1 UNSET, 0x9A, 0x00, 0x00.bss .comm old_vid_mode, 2 ! Video mode at startup .comm cur_vid_mode, 2 ! Current video mode .comm msw, 4 ! Saved machine status word (cr0)