/*-1* Copyright (c) 2001 Takanori Watanabe <[email protected]>2* Copyright (c) 2001-2012 Mitsuru IWASAKI <[email protected]>3* Copyright (c) 2003 Peter Wemm4* Copyright (c) 2008-2012 Jung-uk Kim <[email protected]>5* All rights reserved.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829#include <machine/asmacros.h>30#include <machine/specialreg.h>31#include <x86/ppireg.h>32#include <x86/timerreg.h>3334#include "assym.inc"3536/*37* Resume entry point. The BIOS enters here in real mode after POST with38* CS set to the page where we stored this code. It should configure the39* segment registers with a flat 4 GB address space and EFLAGS.IF = 0.40* Depending on the previous sleep state, we may need to initialize more41* of the system (i.e., S3 suspend-to-RAM vs. S4 suspend-to-disk).42*/4344.data /* So we can modify it */4546ALIGN_TEXT47.code1648wakeup_start:49/*50* Set up segment registers for real mode and a small stack for51* any calls we make. Set up full 32-bit bootstrap kernel flags52* since resumectx() doesn't restore flags. PSL_KERNEL gives53* bootstrap kernel flags (with interrupts disabled), not normal54* kernel flags.55*/56cli /* make sure no interrupts */57mov %cs, %ax /* copy %cs to %ds. Remember these */58mov %ax, %ds /* are offsets rather than selectors */59mov %ax, %ss60movw $PAGE_SIZE, %sp61pushl $PSL_KERNEL62popfl6364/* To debug resume hangs, beep the speaker if the user requested. */65testb $~0, resume_beep - wakeup_start66jz 1f67movb $0, resume_beep - wakeup_start6869/* Set PIC timer2 to beep. */70movb $(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT), %al71outb %al, $TIMER_MODE7273/* Turn on speaker. */74inb $IO_PPI, %al75orb $PIT_SPKR, %al76outb %al, $IO_PPI7778/* Set frequency. */79movw $0x4c0, %ax80outb %al, $TIMER_CNTR281shrw $8, %ax82outb %al, $TIMER_CNTR2831:8485/* Re-initialize video BIOS if the reset_video tunable is set. */86testb $~0, reset_video - wakeup_start87jz 1f88movb $0, reset_video - wakeup_start89lcall $0xc000, $39091/* When we reach here, int 0x10 should be ready. Hide cursor. */92movb $0x01, %ah93movb $0x20, %ch94int $0x109596/* Re-start in case the previous BIOS call clobbers them. */97jmp wakeup_start981:99100/*101* Find relocation base and patch the gdt descript and ljmp targets102*/103xorl %ebx, %ebx104mov %cs, %bx105sall $4, %ebx /* %ebx is now our relocation base */106107/*108* Load the descriptor table pointer. We'll need it when running109* in 16-bit protected mode.110*/111lgdtl bootgdtdesc - wakeup_start112113/* Enable protected mode */114movl $CR0_PE, %eax115mov %eax, %cr0116117/*118* Now execute a far jump to turn on protected mode. This119* causes the segment registers to turn into selectors and causes120* %cs to be loaded from the gdt.121*122* The following instruction is:123* ljmpl $bootcode32 - bootgdt, $wakeup_32 - wakeup_start124* but gas cannot assemble that. And besides, we patch the targets125* in early startup and its a little clearer what we are patching.126*/127wakeup_sw32:128.byte 0x66 /* size override to 32 bits */129.byte 0xea /* opcode for far jump */130.long wakeup_32 - wakeup_start /* offset in segment */131.word bootcode32 - bootgdt /* index in gdt for 32 bit code */132133/*134* At this point, we are running in 32 bit legacy protected mode.135*/136ALIGN_TEXT137.code32138wakeup_32:139140mov $bootdata32 - bootgdt, %eax141mov %ax, %ds142143/* Restore EFER, CR4 and CR3. */144movl wakeup_efer - wakeup_start(%ebx), %eax145movl wakeup_efer - wakeup_start + 4(%ebx), %edx146cmpl $0, %eax147jne 1f148cmpl $0, %edx149je 2f1501: movl $MSR_EFER, %ecx151wrmsr1522: movl wakeup_cr4 - wakeup_start(%ebx), %eax153cmpl $0, %eax154je 3f155mov %eax, %cr41563: movl wakeup_cr3 - wakeup_start(%ebx), %eax157mov %eax, %cr3158159/* Get PCB and return address. */160movl wakeup_ret - wakeup_start(%ebx), %edx161movl wakeup_pcb - wakeup_start(%ebx), %ecx162163/* Enable paging. */164mov %cr0, %eax165orl $CR0_PG, %eax166mov %eax, %cr0167168/* Jump to return address. */169jmp *%edx170171.data172173resume_beep:174.byte 0175reset_video:176.byte 0177178ALIGN_DATA179bootgdt:180.long 0x00000000181.long 0x00000000182183bootcode32:184.long 0x0000ffff185.long 0x00cf9b00186187bootdata32:188.long 0x0000ffff189.long 0x00cf9300190bootgdtend:191192bootgdtdesc:193.word bootgdtend - bootgdt /* Length */194.long bootgdt - wakeup_start /* Offset plus %ds << 4 */195196ALIGN_DATA197wakeup_efer:198.long 0199.long 0200wakeup_cr4:201.long 0202wakeup_cr3:203.long 0204wakeup_pcb:205.long 0206wakeup_ret:207.long 0208wakeup_gdt: /* not used */209.word 0210.long 0211dummy:212213214