/* $NetBSD: start_rom.S,v 1.3 2010/12/20 01:12:44 jakllsch Exp $ */ /* * ROM startup * mostly from freebsd:sys/arch/i396/boot/netboot/start2.S */ #include #define addr32 .byte 0x67 reloc = RELOC #ifndef BOOTSTACK #define BOOTSTACK 0xfffc #endif bootstack = BOOTSTACK .text .code16 textstart: /* At entry, the processor is in 16 bit real mode and the code is being * executed from an address it was not linked to. Code must be pic and * 32 bit sensitive until things are fixed up. */ .word 0xaa55 /* bios extension signature */ .byte 0 /* no. of 512B blocks - set by genprom */ jmp 1f /* enter from bios here */ .byte 0 /* checksum */ #ifdef PCIROM . = 0x18 /* required offset of pointer */ .word (pcidata - textstart) pcidata: .ascii "PCIR" .word PCI_VID .word PCI_DID .word 0 /* pointer to vital product data */ .word (pcidataend - pcidata) .long (0 + (PCI_CLASS << 8)) /* class, revision */ .word 0 /* no. of 512B blocks - set by genprom */ .word 0 /* revision */ .byte 0 /* code type */ .byte 0x80 /* "indicator" - last image */ .word 0 /* reserved */ pcidataend: #endif 1: pushl %eax push %ds xor %ax,%ax mov %ax, %ds /* check signature */ mov 0x304, %ax cmp $0x4d52, %ax /* $0x4d52 == 'MR' */ jz 2f /* we have been here - don't clobber saved vector */ /* save old INT19 vector to a secret location (???) */ movw 0x64, %ax movw %ax, 0x300 movw 0x66, %ax movw %ax, 0x302 /* set INT19 vector to our entry */ movl $(_C_LABEL(start)-reloc), %eax movw %ax, 0x64 mov %cs, %ax movw %ax, 0x66 /* set a signature (is this a safe location?) */ movw $0x4d52, %ax /* 0x4d52 == 'MR' */ movw %ax, 0x304 2: pop %ds popl %eax #ifdef ROMDEBUG push %ds pushl %eax mov %cs, %ax mov %ax, %ds pop %ax pushl %esi movw $(imesg-textstart), %si call message popl %esi pop %ds #endif lret #ifdef ROMDEBUG imesg: .asciz "bsd rom installed\r\n" cmesg: .asciz "bsd rom called\r\n" rmesg: .asciz "bsd rom relocated\r\n" emesg: .asciz "bsd rom done\r\n" /* * message: write the message in %ds:%esi to console */ message: pushl %eax pushl %ebx pushl %edx nextb: cld lodsb /* load a byte into %al */ testb %al, %al jz done movb $0x0e, %ah movw $0x0001, %bx int $0x10 jmp nextb done: movb $0x00, %ah /* wait for keypress */ int $0x16 popl %edx popl %ebx popl %eax ret #endif /* ROMDEBUG */ /************************************************************************** START - Where all the fun begins.... **************************************************************************/ ENTRY(start) .code16 cli mov %cs, %ax mov %ax, %ds #ifdef ROMDEBUG movw $(cmesg-textstart), %si call message #endif cld /* copy to reloc and jump to copy */ xor %si, %si xor %di, %di movw $(reloc>>4), %ax mov %ax, %es movl $(_C_LABEL(edata)-reloc), %ecx cs rep movsb ljmpl $(reloc>>4), $1f-reloc /* Jmp to RELOC:1f */ 1: nop mov %cs, %ax mov %ax, %ds mov %ax, %es mov %ax, %ss movw $bootstack, %ax mov %ax, %sp /* clear bss */ xor %ax, %ax movl $_C_LABEL(edata), %edi movl $_C_LABEL(end), %ecx subw %di, %cx cld rep stosb #ifdef ROMDEBUG mov $(rmesg-textstart), %si call message #endif calll _C_LABEL(real_to_prot) .code32 call _C_LABEL(main) ENTRY(_rtt) call _C_LABEL(prot_to_real) .code16 #ifdef ROMDEBUG mov $(emesg-textstart), %si call message #endif /* jump to saved vector */ xor %ax, %ax mov %ax, %ds movw 0x302, %ax push %ax movw 0x300, %ax push %ax lret /************************************************************************** GLOBAL DESCRIPTOR TABLE **************************************************************************/ #ifdef __ELF__ .align 16 #else .align 4 #endif gdt: .word 0, 0 .byte 0, 0x00, 0x00, 0 #ifdef SUPPORT_LINUX /* additional dummy */ .word 0, 0 .byte 0, 0x00, 0x00, 0 #endif /* code segment */ .globl flatcodeseg flatcodeseg = . - gdt bootcodeseg = . - gdt .word 0xffff, 0 .byte 0, 0x9f, 0xcf, 0 /* data segment */ .globl flatdataseg flatdataseg = . - gdt bootdataseg = . - gdt .word 0xffff, 0 .byte 0, 0x93, 0xcf, 0 /* 16 bit real mode */ bootrealseg = . - gdt .word 0xffff, 0 .byte 0, 0x9f, 0x0f, 0 /* limits (etc) for data segment in real mode */ bootrealdata = . - gdt .word 0xffff, 0 .byte 0, 0x92, 0x00, 0 gdtlen = . - gdt #ifdef __ELF__ .align 16 #else .align 4 #endif gdtarg: .word gdtlen-1 /* limit */ .long gdt /* addr */ CR0_PE = 0x1 /************************************************************************** REAL_TO_PROT - Go from REAL mode to Protected Mode **************************************************************************/ ENTRY(real_to_prot) .code16 cli pushl %eax .code32 addr32 /* don't know the syntax for this! */ lgdt %cs:gdtarg-reloc .code16 movl %cr0, %eax orl $CR0_PE, %eax mov %eax, %cr0 /* turn on protected mode */ /* jump to relocation, flush prefetch queue, and reload %cs */ ljmpl $bootcodeseg, $1f 1: .code32 /* reload other segment registers */ movl $bootdataseg, %eax mov %ax, %ds mov %ax, %es mov %ax, %ss add $reloc, %esp /* Fix up stack pointer */ movl 4(%esp), %eax /* Fix up return Address */ add $reloc, %eax movl %eax, 4(%esp) popl %eax ret /************************************************************************** PROT_TO_REAL - Go from Protected Mode to REAL Mode **************************************************************************/ ENTRY(prot_to_real) .code32 pushl %eax movl 4(%esp), %eax /* Fix up return Address */ sub $reloc, %eax movl %eax, 4(%esp) sub $reloc, %esp /* Adjust stack pointer */ /* * Load the segment registers while still in protected mode. * Otherwise the control bits don't get changed. * The correct values are loaded later. */ movw $bootrealdata, %ax movw %ax, %ds movw %ax, %es movw %ax, %ss ljmp $bootrealseg, $1f /* jump to a 16 bit segment */ 1: .code16 /* clear the PE bit of CR0 */ mov %cr0, %eax andl $~CR0_PE, %eax mov %eax, %cr0 /* make intersegment jmp to flush the processor pipeline * and reload CS register */ ljmpl $(reloc)>>4, $2f-reloc 2: /* we are in real mode now * set up the real mode segment registers : DS, SS, ES */ mov %cs, %ax mov %ax, %ds mov %ax, %es mov %ax, %ss sti popl %eax retl ENTRY(pbzero) .code32 jmp _C_LABEL(bzero) ENTRY(vpbcopy) ENTRY(pvbcopy) .code32 jmp _C_LABEL(bcopy) ENTRY(vtophys) .code32 movl 4(%esp), %eax ret