/* * kexec: Linux boots Linux * * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation (version 2 of the License). * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #if 1 #define TTYS0_BASE 0x3f8 #define TTYS0_RBR (TTYS0_BASE+0x00) #define TTYS0_TBR TTYS0_RBR #define TTYS0_LSR (TTYS0_BASE+0x05) /* uses: ax, dx */ #define TTYS0_TX_AL \ mov %al, %ah ; \ 9: mov $TTYS0_LSR, %dx ; \ inb %dx, %al ; \ test $0x20, %al ; \ je 9b ; \ mov $TTYS0_TBR, %dx ; \ mov %ah, %al ; \ outb %al, %dx ; \ 9: mov $TTYS0_LSR, %dx ; \ inb %dx, %al ; \ test $0x40, %al ; \ jz 9b /* uses: ax, dx */ #define TTYS0_TX_CHAR(byte) \ mov byte, %al ; \ TTYS0_TX_AL /* uses: ax, dx */ #define TTYS0_TX_HEX32(lword) \ mov lword, %eax ; \ shr $28, %eax ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $24, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $20, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $16, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $12, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $8, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $4, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL #define DEBUG_CHAR(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n') #define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n') #else #define DEBUG_CHAR(x) #define DEBUG_TX_HEX32(x) #endif #undef i386 .text .globl entry16, entry16_regs .arch i386 .balign 16 entry16: .code32 DEBUG_CHAR('a') /* Setup the classic BIOS interrupt table at 0x0 */ lidt idtptr DEBUG_CHAR('b') /* Provide us with 16bit segments that we can use */ lgdt gdt DEBUG_CHAR('c') /* Note we don't disable the a20 line, (this shouldn't be required) * The code to do it is in kexec_test and it is a real pain. * I will worry about that when I need it. */ /* Load 16bit data segments, to ensure the segment limits are set */ movl $0x10, %eax movl %eax, %ds movl %eax, %es movl %eax, %ss movl %eax, %fs movl %eax, %gs DEBUG_CHAR('d') /* switch to 16bit mode */ ljmp $0x08, $1f - entry16 1: .code16 DEBUG_CHAR('e') /* Disable Paging and protected mode */ /* clear the PG & PE bits of CR0 */ movl %cr0,%eax andl $~((1 << 31)|(1<<0)),%eax movl %eax,%cr0 DEBUG_CHAR('f') /* make intersegment jmp to flush the processor pipeline * and reload %cs:%eip (to clear upper 16 bits of %eip). */ ljmp *(realptr - entry16) 3: DEBUG_CHAR('g') /* we are in real mode now * set up the real mode segment registers : %ds, $ss, %es */ /* Setup the data segment */ movw %cs, %ax movw %ax, %ds DEBUG_CHAR('h') /* Load the registers */ movl eax - entry16, %eax movl ebx - entry16, %ebx movl ecx - entry16, %ecx movl edx - entry16, %edx movl esi - entry16, %esi movl edi - entry16, %esi movl esp - entry16, %esp movl ebp - entry16, %ebp movw es - entry16, %es movw ss - entry16, %ss movw fs - entry16, %fs movw gs - entry16, %gs movw ds - entry16, %ds /* Jump to the kernel entrypoint */ ljmp %cs:*(realdest - entry16) .balign 4 entry16_regs: eax: .long 0x00000000 ebx: .long 0x00000000 ecx: .long 0x00000000 edx: .long 0x00000000 esi: .long 0x00000000 edi: .long 0x00000000 esp: .long 0x00000000 ebp: .long 0x00000000 ds: .word 0x0000 es: .word 0x0000 ss: .word 0x0000 fs: .word 0x0000 gs: .word 0x0000 realdest: ip: .word 0x0000 cs: .word 0x0000 .size entry16_regs, . - entry16_regs .balign 16 realptr: .word 3b - entry16 .word 0x0000 .data .balign 4 idtptr: /* 256 entry idt at 0 */ .word 0x400 - 1 .word 0, 0 gdt: /* 0x00 unusable segment so used as the gdt ptr */ .word gdt_end - gdt - 1 .long gdt .word 0 /* 0x08 16 bit real mode code segment */ .word 0xffff, 0x0000 .byte 0x00, 0x9b, 0x00, 0x00 /* 0x10 16 bit real mode data segment */ .word 0xffff, 0x0000 .byte 0x00, 0x93, 0x00, 0x00 gdt_end: /* * kexec: Linux boots Linux * * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation (version 2 of the License). * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #if 1 #define TTYS0_BASE 0x3f8 #define TTYS0_RBR (TTYS0_BASE+0x00) #define TTYS0_TBR TTYS0_RBR #define TTYS0_LSR (TTYS0_BASE+0x05) /* uses: ax, dx */ #define TTYS0_TX_AL \ mov %al, %ah ; \ 9: mov $TTYS0_LSR, %dx ; \ inb %dx, %al ; \ test $0x20, %al ; \ je 9b ; \ mov $TTYS0_TBR, %dx ; \ mov %ah, %al ; \ outb %al, %dx ; \ 9: mov $TTYS0_LSR, %dx ; \ inb %dx, %al ; \ test $0x40, %al ; \ jz 9b /* uses: ax, dx */ #define TTYS0_TX_CHAR(byte) \ mov byte, %al ; \ TTYS0_TX_AL /* uses: ax, dx */ #define TTYS0_TX_HEX32(lword) \ mov lword, %eax ; \ shr $28, %eax ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $24, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $20, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $16, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $12, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $8, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ shr $4, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL ; \ ; \ mov lword, %eax ; \ and $0x0f, %al ; \ add $'0', %al ; \ cmp $'9', %al ; \ jle 9f ; \ add $39, %al ; \ 9: ; \ TTYS0_TX_AL #define DEBUG_CHAR(x) TTYS0_TX_CHAR($x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n') #define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x) ; TTYS0_TX_CHAR($'\r') ; TTYS0_TX_CHAR($'\n') #else #define DEBUG_CHAR(x) #define DEBUG_TX_HEX32(x) #endif .data .globl setup16_debug_start, setup16_debug_end, setup16_debug_size, setup16_debug_align .globl setup16_debug_regs .globl setup16_debug_kernel_pre_protected .globl setup16_debug_first_code32 .globl setup16_debug_old_code32 setup16_debug_start: _reloc = . .balign 16 .code32 DEBUG_CHAR('a') /* Compute where I am running at */ call 1f 1: popl %ebx subl $(1b - _reloc), %ebx /* Remember where I am running at */ movl %ebx, location - _reloc(%ebx) DEBUG_CHAR('b') /* Fixup my real mode segment */ movl %ebx, %eax shrl $4, %eax movw %ax, 2 + realptr - _reloc(%ebx) DEBUG_CHAR('c') /* Fixup the gdt */ movl %ebx, %eax shll $16, %eax movl %ebx, %ecx shrl $16, %ecx andl $0xff, %ecx movl %ebx, %edx andl $0xff000000, %edx orl %edx, %ecx addl %ebx, gdtaddr - _reloc(%ebx) addl %ebx, debug_gdtaddr - _reloc(%ebx) orl %eax, 0x08 + gdt - _reloc(%ebx) orl %ecx, 0x0c + gdt - _reloc(%ebx) orl %eax, 0x10 + gdt - _reloc(%ebx) orl %ecx, 0x14 + gdt - _reloc(%ebx) DEBUG_CHAR('d') /* Setup the classic BIOS interrupt table at 0x0 */ lidt idtptr - _reloc(%ebx) /* Provide us with 16bit segments that we can use */ lgdt gdtptr - _reloc(%ebx) /* Note we don't disable the a20 line, (this shouldn't be required) * The code to do it is in kexec_test and it is a real pain. * I will worry about that when I need it. */ /* Load 16bit data segments, to ensure the segment limits are set */ movl $0x10, %eax movl %eax, %ds movl %eax, %es movl %eax, %ss movl %eax, %fs movl %eax, %gs /* switch to 16bit mode */ ljmp $0x08, $2f - _reloc 2: .code16 DEBUG_CHAR('e') /* Disable Paging and protected mode */ /* clear the PG & PE bits of CR0 */ movl %cr0,%eax andl $~((1 << 31)|(1<<0)),%eax movl %eax,%cr0 DEBUG_CHAR('f') /* make intersegment jmp to flush the processor pipeline * and reload %cs:%eip (to clear upper 16 bits of %eip). */ ljmp *(realptr - _reloc) 3: DEBUG_CHAR('g') /* we are in real mode now * set up the real mode segment registers : %ds, $ss, %es */ /* Setup the data segment */ movw %cs, %ax movw %ax, %ds DEBUG_CHAR('h') /* Load the registers */ movl eax - _reloc, %eax movl ebx - _reloc, %ebx movl ecx - _reloc, %ecx movl edx - _reloc, %edx movl esi - _reloc, %esi movl edi - _reloc, %esi movl esp - _reloc, %esp movl ebp - _reloc, %ebp movw es - _reloc, %es movw ss - _reloc, %ss movw fs - _reloc, %fs movw gs - _reloc, %gs movw ds - _reloc, %ds /* Jump to the kernel entrypoint */ ljmp %cs:*(realdest - _reloc) setup16_debug_regs: eax: .long 0x00000000 ebx: .long 0x00000000 ecx: .long 0x00000000 edx: .long 0x00000000 esi: .long 0x00000000 edi: .long 0x00000000 esp: .long 0x00000000 ebp: .long 0x00000000 ds: .word 0x0000 es: .word 0x0000 ss: .word 0x0000 fs: .word 0x0000 gs: .word 0x0000 realdest: ip: .word 0x0000 cs: .word 0x0000 .balign 16 realptr: .word 3b - _reloc .word 0x0000 idtptr: /* 256 entry idt at 0 */ .word 0x400 - 1 .word 0, 0 gdtptr: .word gdt_end - gdt - 1 gdtaddr: .long gdt - _reloc gdt: /* dummy */ .word 0, 0, 0, 0 /* 16 bit real mode code segment */ .word 0xffff, 0x0000 .byte 0x00, 0x9b, 0x00, 0x00 /* 16 bit real mode data segment */ .word 0xffff, 0x0000 .byte 0x00, 0x93, 0x00, 0x00 gdt_end: debug_gdt: /* 0x00 */ .word debug_gdt_end - debug_gdt - 1 debug_gdtaddr: .long debug_gdt - _reloc .word 0 /* 0x08 */ .word 0, 0, 0, 0 /* Nothing in the first gdt entry */ /* 0x10 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */ .word 0xFFFF, 0x00, 0x9A00, 0x00CF /* 0x18 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */ .word 0xFFFF, 0x0000, 0x9200, 0x00CF /* 0x20 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */ .word 0xFFFF, 0x00, 0x9A00, 0x00CF /* 0x28 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */ .word 0xFFFF, 0x0000, 0x9200, 0x00CF /* 0x30 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */ .word 0xFFFF, 0x00, 0x9A00, 0x00CF /* 0x38 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */ .word 0xFFFF, 0x0000, 0x9200, 0x00CF /* 0x40 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */ .word 0xFFFF, 0x00, 0x9A00, 0x00CF /* 0x48 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */ .word 0xFFFF, 0x0000, 0x9200, 0x00CF /* 0x50 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */ .word 0xFFFF, 0x00, 0x9A00, 0x00CF /* 0x58 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */ .word 0xFFFF, 0x0000, 0x9200, 0x00CF /* 0x60 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */ .word 0xFFFF, 0x00, 0x9A00, 0x00CF /* 0x68 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */ .word 0xFFFF, 0x0000, 0x9200, 0x00CF debug_gdt_end: setup16_debug_kernel_pre_protected: .code16 DEBUG_CHAR('i') cli # no interrupts allowed ! movb $0x80, %al # disable NMI for bootup # sequence outb %al, $0x70 lret setup16_debug_first_code32: .code32 .byte 0xbf /* movl $0x12345678, %edi */ location: .long 0x12345678 DEBUG_CHAR('j') .byte 0xb8 /* movl $0x10000, %eax */ setup16_debug_old_code32: .long 0x10000 jmp %eax setup16_debug_end: setup16_debug_size: .long setup16_debug_end - setup16_debug_start setup16_debug_align: .long 16