12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039 |
- /*++
- Copyright (c) 2017 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- archsup.S
- Abstract:
- This module implements AMD64 processor architecture features not
- implementable in C.
- Author:
- Evan Green 8-Jun-2017
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------ Includes
- //
- #include <minoca/kernel/x64.inc>
- //
- // ---------------------------------------------------------------------- Code
- //
- ASSEMBLY_FILE_HEADER
- //
- // KERNEL_API
- // BOOL
- // ArAreInterruptsEnabled (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine determines whether or not interrupts are currently enabled
- on the processor.
- Arguments:
- None.
- Return Value:
- TRUE if interrupts are enabled in the processor.
- FALSE if interrupts are globally disabled.
- --*/
- PROTECTED_FUNCTION(ArAreInterruptsEnabled)
- xorl %eax, %eax # Clear RAX.
- pushfq # Get Rflags.
- popq %rdi # Rflags in rdi.
- andl $IA32_EFLAG_IF, %edi # Isolate the Interrupt flag.
- setnz %al # Set eax to 1 if non-zero.
- ret #
- END_FUNCTION(ArAreInterruptsEnabled)
- //
- // KERNEL_API
- // BOOL
- // ArDisableInterrupts (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine disables all interrupts on the current processor.
- Arguments:
- None.
- Return Value:
- TRUE if interrupts were previously enabled.
- FALSE if interrupts were previously disabled.
- --*/
- PROTECTED_FUNCTION(ArDisableInterrupts)
- xorl %eax, %eax # Zero eax.
- pushfq # Push flags.
- cli # Clear the interrupt flag.
- popq %rdi # Pop flags into eax.
- andl $IA32_EFLAG_IF, %edi # Isolate the Interrupt flag.
- setnz %al # Set eax to 1 if non-zero.
- ret
- END_FUNCTION(ArDisableInterrupts)
- //
- // KERNEL_API
- // VOID
- // ArEnableInterrupts (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine enables interrupts on the current processor.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- PROTECTED_FUNCTION(ArEnableInterrupts)
- sti # Set the interrupt flag.
- ret #
- END_FUNCTION(ArEnableInterrupts)
- //
- // VOID
- // ArLoadKernelDataSegments (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine switches the data segments DS and ES to the kernel data
- segment selectors.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- FUNCTION(ArLoadKernelDataSegments)
- LOAD_KERNEL_DATA_SEGMENTS # Load the kernel data segments.
- ret #
- END_FUNCTION(ArLoadKernelDataSegments)
- //
- // ULONG
- // ArGetProcessorFlags (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine gets the current processor's flags register.
- Arguments:
- None.
- Return Value:
- Returns the current flags.
- --*/
- FUNCTION(ArGetProcessorFlags)
- pushfq # Push the flags onto the stack.
- popq %rax # Pop them into the return value.
- ret #
- END_FUNCTION(ArGetProcessorFlags)
- //
- // VOID
- // ArLoadTr (
- // USHORT TssSegment
- // )
- //
- /*++
- Routine Description:
- This routine loads a TSS (Task Selector State).
- Arguments:
- TssSegment - Supplies the segment selector in the GDT that describes the
- TSS.
- Return Value:
- None.
- --*/
- FUNCTION(ArLoadTr)
- ltr %di # Load the Task Register.
- ret # That's it!
- END_FUNCTION(ArLoadTr)
- //
- // VOID
- // ArStoreTr (
- // PULONG TssSegment
- // )
- //
- /*++
- Routine Description:
- This routine retrieves the current TSS (Task Selector State) register.
- Arguments:
- TssSegment - Supplies a pointer where the current TSS segment register will
- be returned.
- Return Value:
- None.
- --*/
- FUNCTION(ArStoreTr)
- str (%rdi) # Store the TR register.
- ret # Return
- END_FUNCTION(ArStoreTr)
- //
- // VOID
- // ArLoadIdtr (
- // PVOID IdtBase
- // )
- //
- /*++
- Routine Description:
- This routine loads the given Interrupt Descriptor Table.
- Arguments:
- IdtBase - Supplies a pointer to the base of the IDT.
- Return Value:
- None.
- --*/
- FUNCTION(ArLoadIdtr)
- lidt (%rdi) # Load the IDT register.
- ret # That's it!
- END_FUNCTION(ArLoadIdtr)
- //
- // VOID
- // ArStoreIdtr (
- // PTABLE_REGISTER IdtRegister
- // )
- //
- /*++
- Routine Description:
- This routine stores the interrupt descriptor table register into the given
- value.
- Arguments:
- IdtRegister - Supplies a pointer that will receive the value.
- Return Value:
- None.
- --*/
- FUNCTION(ArStoreIdtr)
- sidt (%rdi) # Store the IDT register.
- ret # Return politely.
- END_FUNCTION(ArStoreIdtr)
- //
- // VOID
- // ArLoadGdtr (
- // PTABLE_REGISTER Gdt
- // )
- //
- /*++
- Routine Description:
- This routine loads a global descriptor table.
- Arguments:
- Gdt - Supplies a pointer to the Gdt pointer, which contains the base and
- limit for the GDT.
- Return Value:
- None.
- --*/
- FUNCTION(ArLoadGdtr)
- lgdt (%rdi) # Load the GDT.
- //
- // In order to load the new GDT, a long jump of some kind is needed. Use a
- // far return for this purpose, returning from this routine in the process.
- //
- popq %rax # Pop the return address into a register.
- pushq $KERNEL_CS # Push the return segemnt.
- pushq %rax # Push the return address.
- retfq # Do a 64-bit far return, loading the GDT.
- END_FUNCTION(ArLoadGdtr)
- //
- // VOID
- // ArStoreGdtr (
- // PTABLE_REGISTER GdtRegister
- // )
- //
- /*++
- Routine Description:
- This routine stores the GDT register into the given value.
- Arguments:
- GdtRegister - Supplies a pointer that will receive the value.
- Return Value:
- None.
- --*/
- FUNCTION(ArStoreGdtr)
- sgdt (%rdi) # Store the GDT register.
- ret # Return politely.
- END_FUNCTION(ArStoreGdtr)
- //
- // PVOID
- // ArGetFaultingAddress (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine determines which address caused a page fault.
- Arguments:
- None.
- Return Value:
- Returns the faulting address.
- --*/
- FUNCTION(ArGetFaultingAddress)
- movq %cr2, %rax # Return CR2.
- ret #
- END_FUNCTION(ArGetFaultingAddress)
- //
- // VOID
- // ArSetFaultingAddress (
- // PVOID Value
- // )
- //
- /*++
- Routine Description:
- This routine sets the CR2 register.
- Arguments:
- Value - Supplies the value to set.
- Return Value:
- None.
- --*/
- FUNCTION(ArSetFaultingAddress)
- movq %rdi, %cr2
- ret
- END_FUNCTION(ArSetFaultingAddress)
- //
- // UINTN
- // ArGetCurrentPageDirectory (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine returns the active page directory.
- Arguments:
- None.
- Return Value:
- Returns the page directory currently in use by the system.
- --*/
- FUNCTION(ArGetCurrentPageDirectory)
- movq %cr3, %rax # Return CR3.
- ret #
- END_FUNCTION(ArGetCurrentPageDirectory)
- //
- // VOID
- // ArSetCurrentPageDirectory (
- // UINTN Value
- // )
- //
- /*++
- Routine Description:
- This routine sets the CR3 register.
- Arguments:
- Value - Supplies the value to set.
- Return Value:
- None.
- --*/
- FUNCTION(ArSetCurrentPageDirectory)
- movq %rdi, %cr3
- ret
- END_FUNCTION(ArSetCurrentPageDirectory)
- //
- // VOID
- // ArInvalidateTlbEntry (
- // PVOID Address
- // )
- //
- /*++
- Routine Description:
- This routine invalidates one TLB entry corresponding to the given virtual
- address.
- Arguments:
- Address - Supplies the virtual address whose associated TLB entry will be
- invalidated.
- Return Value:
- None.
- --*/
- FUNCTION(ArInvalidateTlbEntry)
- invlpg (%rdi) # Invalidate the TLB entry.
- ret #
- END_FUNCTION(ArInvalidateTlbEntry)
- //
- // VOID
- // ArCleanEntireCache (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine cleans the entire data cache.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- FUNCTION(ArCleanEntireCache)
- wbinvd # Write back invalidate cache.
- ret
- END_FUNCTION(ArCleanEntireCache)
- //
- // VOID
- // ArInvalidateEntireTlb (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine invalidates the entire TLB.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- FUNCTION(ArInvalidateEntireTlb)
- movq %cr3, %rax # Reloading CR3 causes the entire TLB to
- movq %rax, %cr3 # be flushed.
- ret
- END_FUNCTION(ArInvalidateEntireTlb)
- //
- // VOID
- // ArProcessorYield (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine executes a short processor yield in hardware.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- FUNCTION(ArProcessorYield)
- pause
- ret
- END_FUNCTION(ArProcessorYield)
- //
- // KERNEL_API
- // VOID
- // ArWaitForInterrupt (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine halts the processor until the next interrupt comes in. This
- routine should be called with interrupts disabled, and will return with
- interrupts enabled.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- PROTECTED_FUNCTION(ArWaitForInterrupt)
- sti # Enables interrupts one instruction later.
- hlt # Simtaneously halt and enable interrupts.
- ret
- END_FUNCTION(ArWaitForInterrupt)
- //
- // VOID
- // ArSerializeExecution (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine acts a serializing instruction, preventing the processor
- from speculatively executing beyond this point.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- FUNCTION(ArSerializeExecution)
- movq %cr2, %rax # Control register accesses are
- movq %rax, %cr2 # cheap (ish) and serializing.
- ret
- END_FUNCTION(ArSerializeExecution)
- //
- // VOID
- // ArInvalidateInstructionCache (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine invalidate the processor's instruction cache, indicating
- that a page containing code has changed.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- FUNCTION(ArInvalidateInstructionCache)
- ret
- END_FUNCTION(ArInvalidateInstructionCache)
- //
- // VOID
- // ArCpuid (
- // PULONG Eax,
- // PULONG Ebx,
- // PULONG Ecx,
- // PULONG Edx
- // )
- //
- /*++
- Routine Description:
- This routine executes the CPUID instruction to get processor architecture
- information.
- Arguments:
- Eax - Supplies a pointer to the value that EAX should be set to when the
- CPUID instruction is executed. On output, contains the contents of
- EAX immediately after the CPUID instruction.
- Ebx - Supplies a pointer to the value that EBX should be set to when the
- CPUID instruction is executed. On output, contains the contents of
- EAX immediately after the CPUID instruction.
- Ecx - Supplies a pointer to the value that ECX should be set to when the
- CPUID instruction is executed. On output, contains the contents of
- EAX immediately after the CPUID instruction.
- Edx - Supplies a pointer to the value that EDX should be set to when the
- CPUID instruction is executed. On output, contains the contents of
- EAX immediately after the CPUID instruction.
- Return Value:
- None.
- --*/
- FUNCTION(ArCpuid)
- pushq %rbx # Save the only non-volatile involved.
- movq %rdx, %r8 # Save rcx into R8
- movq %rcx, %r9 # Save rdx into R9.
- movl (%rdi), %eax # Dereference to get eax.
- movl (%rsi), %ebx # Dereference to get ebx.
- movl (%r8), %ecx # Dereference to get ecx.
- movl (%r9), %edx # Dereference to get edx.
- cpuid # Fire off the CPUID instruction.
- movl %edx, (%r9) # Save the resulting edx.
- movl %ecx, (%r8) # Save the resulting ecx.
- movl %ebx, (%rsi) # Save the resulting ebx.
- movl %eax, (%rdi) # Save the resulting eax.
- popq %rbx # Restore the non-volatile.
- ret
- END_FUNCTION(ArCpuid)
- //
- // UINTN
- // ArGetControlRegister0 (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine returns the current value of CR0.
- Arguments:
- None.
- Return Value:
- Returns CR0.
- --*/
- FUNCTION(ArGetControlRegister0)
- movq %cr0, %rax
- ret
- END_FUNCTION(ArGetControlRegister0)
- //
- // VOID
- // ArSetControlRegister0 (
- // UINTN Value
- // )
- //
- /*++
- Routine Description:
- This routine sets the CR0 register.
- Arguments:
- Value - Supplies the value to set.
- Return Value:
- None.
- --*/
- FUNCTION(ArSetControlRegister0)
- movq %rdi, %cr0
- ret
- END_FUNCTION(ArSetControlRegister0)
- //
- // UINTN
- // ArGetControlRegister4 (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine returns the current value of CR4.
- Arguments:
- None.
- Return Value:
- Returns CR4.
- --*/
- FUNCTION(ArGetControlRegister4)
- movq %cr4, %rax
- ret
- END_FUNCTION(ArGetControlRegister4)
- //
- // VOID
- // ArSetControlRegister4 (
- // UINTN Value
- // )
- //
- /*++
- Routine Description:
- This routine sets the CR4 register.
- Arguments:
- Value - Supplies the value to set.
- Return Value:
- None.
- --*/
- FUNCTION(ArSetControlRegister4)
- movq %rdi, %cr4
- ret
- END_FUNCTION(ArSetControlRegister4)
- //
- // UINTN
- // ArGetDebugRegister0 (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine returns the current value of DR0.
- Arguments:
- None.
- Return Value:
- Returns DR0.
- --*/
- FUNCTION(ArGetDebugRegister0)
- movq %dr0, %rax
- ret
- END_FUNCTION(ArGetDebugRegister0)
- //
- // VOID
- // ArSetDebugRegister0 (
- // UINTN Value
- // )
- //
- /*++
- Routine Description:
- This routine sets the DR0 register.
- Arguments:
- Value - Supplies the value to set.
- Return Value:
- None.
- --*/
- FUNCTION(ArSetDebugRegister0)
- movq %rdi, %dr0
- ret
- END_FUNCTION(ArSetDebugRegister0)
- //
- // UINTN
- // ArGetDebugRegister1 (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine returns the current value of DR1.
- Arguments:
- None.
- Return Value:
- Returns DR1.
- --*/
- FUNCTION(ArGetDebugRegister1)
- movq %dr1, %rax
- ret
- END_FUNCTION(ArGetDebugRegister1)
- //
- // VOID
- // ArSetDebugRegister1 (
- // UINTN Value
- // )
- //
- /*++
- Routine Description:
- This routine sets the DR1 register.
- Arguments:
- Value - Supplies the value to set.
- Return Value:
- None.
- --*/
- FUNCTION(ArSetDebugRegister1)
- movq %rdi, %dr1
- ret
- END_FUNCTION(ArSetDebugRegister1)
- //
- // UINTN
- // ArGetDebugRegister2 (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine returns the current value of DR2.
- Arguments:
- None.
- Return Value:
- Returns DR2.
- --*/
- FUNCTION(ArGetDebugRegister2)
- movq %dr2, %rax
- ret
- END_FUNCTION(ArGetDebugRegister2)
- //
- // VOID
- // ArSetDebugRegister2 (
- // UINTN Value
- // )
- //
- /*++
- Routine Description:
- This routine sets the DR2 register.
- Arguments:
- Value - Supplies the value to set.
- Return Value:
- None.
- --*/
- FUNCTION(ArSetDebugRegister2)
- movq %rdi, %dr2
- ret
- END_FUNCTION(ArSetDebugRegister2)
- //
- // UINTN
- // ArGetDebugRegister3 (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine returns the current value of DR3.
- Arguments:
- None.
- Return Value:
- Returns DR3.
- --*/
- FUNCTION(ArGetDebugRegister3)
- movq %dr3, %rax
- ret
- END_FUNCTION(ArGetDebugRegister3)
- //
- // VOID
- // ArSetDebugRegister3 (
- // UINTN Value
- // )
- //
- /*++
- Routine Description:
- This routine sets the DR3 register.
- Arguments:
- Value - Supplies the value to set.
- Return Value:
- None.
- --*/
- FUNCTION(ArSetDebugRegister3)
- movq %rdi, %dr3
- ret
- END_FUNCTION(ArSetDebugRegister3)
- //
- // UINTN
- // ArGetDebugRegister6 (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine returns the current value of DR6.
- Arguments:
- None.
- Return Value:
- Returns DR6.
- --*/
- FUNCTION(ArGetDebugRegister6)
- movq %dr6, %rax
- ret
- END_FUNCTION(ArGetDebugRegister6)
- //
- // VOID
- // ArSetDebugRegister6 (
- // UINTN Value
- // )
- //
- /*++
- Routine Description:
- This routine sets the DR6 register.
- Arguments:
- Value - Supplies the value to set.
- Return Value:
- None.
- --*/
- FUNCTION(ArSetDebugRegister6)
- movq %rdi, %dr6
- ret
- END_FUNCTION(ArSetDebugRegister6)
- //
- // UINTN
- // ArGetDebugRegister7 (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine returns the current value of DR7.
- Arguments:
- None.
- Return Value:
- Returns DR7.
- --*/
- FUNCTION(ArGetDebugRegister7)
- movq %dr7, %rax
- ret
- END_FUNCTION(ArGetDebugRegister7)
- //
- // VOID
- // ArSetDebugRegister7 (
- // UINTN Value
- // )
- //
- /*++
- Routine Description:
- This routine sets the DR7 register.
- Arguments:
- Value - Supplies the value to set.
- Return Value:
- None.
- --*/
- FUNCTION(ArSetDebugRegister7)
- movq %rdi, %dr7
- ret
- END_FUNCTION(ArSetDebugRegister7)
- //
- // VOID
- // ArFxSave (
- // PFPU_CONTEXT Buffer
- // )
- //
- /*++
- Routine Description:
- This routine saves the current x87 FPU, MMX, XMM, and MXCSR registers to a
- 512 byte memory location.
- Arguments:
- Buffer - Supplies a pointer to the buffer where the information will be
- saved. This buffer must be 16-byte aligned.
- Return Value:
- None.
- --*/
- FUNCTION(ArFxSave)
- addq $0xF, %rdi # Round up to nearest alignment requirement.
- andq $~0xF, %rdi # Align.
- clts # Clear the TS flag, Enabling FPU access.
- fxsave (%rdi) # Save the state into there.
- ret
- END_FUNCTION(ArFxSave)
- //
- // VOID
- // ArFxRestore (
- // PFPU_CONTEXT Buffer
- // )
- //
- /*++
- Routine Description:
- This routine restores the current x87 FPU, MMX, XMM, and MXCSR registers
- from a 512 byte memory location.
- Arguments:
- Buffer - Supplies a pointer to the buffer where the information will be
- loaded from. This buffer must be 16-byte aligned.
- Return Value:
- None.
- --*/
- FUNCTION(ArFxRestore)
- addq $0xF, %rdi # Round up to nearest alignment requirement.
- andq $~0xF, %rax # Align.
- clts # Clear the TS flag, Enabling FPU access.
- fxrstor (%rdi) # Load the state from there.
- ret
- END_FUNCTION(ArFxRestore)
- //
- // VOID
- // ArEnableFpu (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine clears the TS bit of CR0, allowing access to the FPU.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- FUNCTION(ArEnableFpu)
- clts # Use the dedicated instruction for this.
- ret # Return.
- END_FUNCTION(ArEnableFpu)
- //
- // VOID
- // ArDisableFpu (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine sets the TS bit of CR0, disallowing access to the FPU.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- FUNCTION(ArDisableFpu)
- movq %cr0, %rax # Get CR0.
- andq $CR0_TASK_SWITCHED, %rax # See if it's already disabled.
- jnz ArDisableFpuReturn # Jump out without writing if it's already off.
- orq $CR0_TASK_SWITCHED, %rax # Turn on that bit.
- movq %rax, %cr0 # Write CR0.
- ArDisableFpuReturn:
- ret # Return.
- END_FUNCTION(ArDisableFpu)
- //
- // VOID
- // ArInitializeFpu (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine resets the FPU state.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- FUNCTION(ArInitializeFpu)
- fninit # Reset the FPU state.
- ret # Return.
- END_FUNCTION(ArInitializeFpu)
- //
- // ULONGLONG
- // ArReadTimeStampCounter (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine reads the time stamp counter from the current processor. It
- is essential that callers of this function understand that this returns
- instruction cycles, which does not always translate directly into units
- of time. For example, some processors halt the timestamp counter during
- performance and CPU idle state transitions. In other cases, the timestamp
- counters of all processors are not in sync, so as execution of a thread
- bounces unpredictably from one core to another, different timelines may be
- observed. Additionally, one must understand that this intrinsic is not a
- serializing instruction to the hardware, so the processor may decide to
- execute any number of instructions after this one before actually snapping
- the timestamp counter. To all those who choose to continue to use this
- primitive to measure time, you have been warned.
- Arguments:
- None.
- Return Value:
- Returns the current instruction cycle count since the processor was started.
- --*/
- FUNCTION(ArReadTimeStampCounter)
- rdtsc # Store the timestamp counter in EDX:EAX.
- shlq $32, %rdx # Shift rdx into its high word.
- orq %rdx, %rax # OR rdx into rax.
- ret # And return!
- END_FUNCTION(ArReadTimeStampCounter)
- //
- // ULONGLONG
- // ArReadMsr (
- // ULONG Msr
- // )
- //
- /*++
- Routine Description:
- This routine reads the requested Model Specific Register.
- Arguments:
- Msr - Supplies the MSR to read.
- Return Value:
- Returns the 64-bit MSR value.
- --*/
- FUNCTION(ArReadMsr)
- movq %rdi, %rcx # Load the MSR number into ecx.
- xorq %rax, %rax # Clear high bits of rax.
- rdmsr # Read the MSR into EDX:EAX.
- shlq $32, %rdx # Shift rdx into its high word.
- orq %rdx, %rax # OR rdx into rax.
- ret # Return.
- END_FUNCTION(ArReadMsr)
- //
- // VOID
- // ArWriteMsr (
- // ULONG Msr,
- // ULONGLONG Value
- // )
- //
- /*++
- Routine Description:
- This routine writes the requested Model Specific Register.
- Arguments:
- Msr - Supplies the MSR to write.
- Value - Supplies the 64-bit value to write.
- Return Value:
- None.
- --*/
- FUNCTION(ArWriteMsr)
- movq %rdi, %rcx # Load the MSR number into ECX.
- movq %rsi, %rdx # Load rdx with the whole 64-bit word.
- shrq $32, %rdx # Shift rdx right to put the high bits in edx.
- movl %esi, %eax # Put the low bits into eax.
- wrmsr # Write the MSR.
- ret # Return.
- END_FUNCTION(ArWriteMsr)
- //
- // PVOID
- // ArReadFsbase (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine reads the fs: base register.
- Arguments:
- None.
- Return Value:
- Returns the fsbase pointer.
- --*/
- FUNCTION(ArReadFsbase)
- rdfsbase %rax # Read fsbase into rax.
- ret # Return.
- END_FUNCTION(ArReadFsbase)
- //
- // VOID
- // ArWriteFsbase (
- // PVOID Fsbase
- // )
- //
- /*++
- Routine Description:
- This routine writes the fs: base register.
- Arguments:
- Fsbase - Supplies the new fsbase value to write.
- Return Value:
- None.
- --*/
- FUNCTION(ArWriteFsbase)
- wrfsbase %rdi # Write fsbase.
- ret # Return.
- END_FUNCTION(ArWriteFsbase)
- //
- // PVOID
- // ArReadGsbase (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine reads the gs: base register.
- Arguments:
- None.
- Return Value:
- Returns the gsbase pointer.
- --*/
- FUNCTION(ArReadGsbase)
- rdgsbase %rax # Read gsbase into rax.
- ret # Return.
- END_FUNCTION(ArReadGsbase)
- //
- // VOID
- // ArWriteGsbase (
- // PVOID Gsbase
- // )
- //
- /*++
- Routine Description:
- This routine writes the gs: base register.
- Arguments:
- Gsbase - Supplies the new gsbase value to write.
- Return Value:
- None.
- --*/
- FUNCTION(ArWriteGsbase)
- wrgsbase %rdi # Write gsbase.
- ret # Return.
- END_FUNCTION(ArWriteGsbase)
- //
- // VOID
- // ArSwapGs (
- // VOID
- // )
- //
- /*++
- Routine Description:
- This routine exchanges the GS base hidden register with the kernel GS base
- MSR.
- Arguments:
- None.
- Return Value:
- None.
- --*/
- FUNCTION(ArSwapGs)
- swapgs # Swap gs.
- ret # Return.
- END_FUNCTION(ArSwapGs)
- //
- // KERNEL_API
- // VOID
- // ArMonitor (
- // PVOID Address,
- // UINTN Ecx,
- // UINTN Edx
- // )
- //
- /*++
- Routine Description:
- This routine arms the monitoring hardware in preparation for an mwait
- instruction.
- Arguments:
- Address - Supplies the address pointer to monitor.
- Ecx - Supplies the contents to load into the ECX (RCX in 64-bit) register
- when executing the monitor instruction. These are defined as hints.
- Edx - Supplies the contents to load into the EDX/RDX register. These are
- also hints.
- Return Value:
- None.
- --*/
- PROTECTED_FUNCTION(ArMonitor)
- movq %rdi, %rax # Load the address to rax.
- movq %rsi, %rcx # Load the first set of hints.
- # The second set of hints is already in rdx.
- monitor # Arm the monitoring hardware.
- ret # Return.
- END_FUNCTION(ArMonitor)
- //
- // KERNEL_API
- // VOID
- // ArMwait (
- // UINTN Eax,
- // UINTN Ecx
- // )
- //
- /*++
- Routine Description:
- This routine executes the mwait instruction, which is used to halt the
- processor until a specified memory location is written to. It is also used
- on Intel processors to enter C-states. A monitor instruction must have
- been executed prior to this to set up the monitoring region.
- Arguments:
- Eax - Supplies the contents to load into EAX/RAX when executing the mwait
- instruction. This is a set of hints, including which C-state to enter
- on Intel processors.
- Ecx - Supplies the contents to load into the ECX (RCX in 64-bit) register
- when executing the mwait instruction. This is 1 when entering a C-state
- with interrupts disabled to indicate that an interrupt should still
- break out.
- Return Value:
- None.
- --*/
- PROTECTED_FUNCTION(ArMwait)
- movq %rdi, %rax # Load eax.
- movq %rsi, %rcx # Load ecx.
- mwait # Go down.
- ret # Return.
- END_FUNCTION(ArMwait)
- //
- // KERNEL_API
- // VOID
- // ArIoReadAndHalt (
- // USHORT IoPort
- // )
- //
- /*++
- Routine Description:
- This routine performs a single 8-bit I/O port read and then halts the
- processor until the next interrupt comes in. This routine should be called
- with interrupts disabled, and will return with interrupts enabled.
- Arguments:
- IoPort - Supplies the I/O port to read from.
- Return Value:
- None.
- --*/
- PROTECTED_FUNCTION(ArIoReadAndHalt)
- movq %rdi, %rdx # Move 1st parameter to dx.
- inb %dx, %al # Perform the I/O port read.
- sti # Enables interrupts one instruction later.
- hlt # Simtaneously halt and enable interrupts.
- ret
- END_FUNCTION(ArIoReadAndHalt)
- //
- // UINTN
- // ArSaveProcessorContext (
- // PPROCESSOR_CONTEXT Context
- // )
- //
- /*++
- Routine Description:
- This routine saves the current processor context, including the
- non-volatile general registers and the system level control registers. This
- function appears to return twice, once when the context is saved and then
- again when the context is restored. Because the stack pointer is restored,
- the caller of this function may not return without either abandoning the
- context or calling restore. Returning and then calling restore would almost
- certainly result in stack corruption.
- Arguments:
- Context - Supplies a pointer to the context area to save into.
- Return Value:
- Returns 0 after the context was successfully saved (first time).
- Returns the value in the context return address register when the restore
- function is called (the second time). By default this value is 1, though it
- can be manipulated after the initial save is complete.
- --*/
- FUNCTION(ArSaveProcessorContext)
- movq %rdi, %r10 # Save rdi into a volatile register.
- movl $1, %eax # Get default return value.
- cld # Increment edi upon stosd.
- stosq # Save it.
- movq (%rsp), %rax # Get the return address.
- stosq # Save it.
- xorl %eax, %eax # Zero out rax.
- movw %cs, %ax # Get CS.
- stosq # Save it.
- pushfq # Push rflags.
- popq %rax # Get rflags in rax.
- stosq # Save it.
- movq %r10, (%rdi) # Save original rdi.
- movq %rsi, 8(%rdi) # Save rsi.
- movq %rdx, 16(%rdi) # Save rdx.
- movq %rcx, 24(%rdi) # Save rcx.
- movq %r8, 32(%rdi) # Save r8.
- movq %r9, 40(%rdi) # Save r9.
- addq $48, %rdi # Advance over arguments.
- movq %rbx, %rax # Get rbx.
- stosq # Save it.
- movq %rbp, %rax # Get rbp.
- stosq # Save it.
- movq %rsp, %rax # Get rsp.
- addq $8, %rax # Pop off return address.
- stosq # Save it.
- movq %r12, (%rdi) # Save r12.
- movq %r13, 8(%rdi) # Save r13.
- movq %r14, 16(%rdi) # Save r14
- movq %r15, 24(%rdi) # Save r15
- addq $32, %rdi # Advance pointer for r12-r15.
- movq %dr7, %rax # Get dr7.
- stosq # Save it.
- movq %dr6, %rax # Get dr6.
- stosq # Save it.
- movq %dr0, %rax # Get dr0.
- stosq # Save it.
- movq %dr1, %rax # Get dr1.
- stosq # Save it.
- movq %dr2, %rax # Get dr2.
- stosq # Save it.
- movq %dr3, %rax # Get dr3.
- stosq # Save it.
- movq %rdi, (%rdi) # Save VA of this structure member.
- addq $8, %rdi # Advance over VA member.
- movq %cr0, %rax # Get cr0.
- stosq # Save it.
- movq %cr2, %rax # Get cr2. Why is there no cr1?
- stosq # Save it.
- movq %cr3, %rax # Get the all-important cr3.
- stosq # Save it.
- movq %cr4, %rax # Get cr4.
- stosq # Save it.
- movl $X86_MSR_FSBASE, %ecx # Load MSR number.
- rdmsr # Read FSBASE.
- shlq $32, %rdx # Shift rdx into its high word.
- orq %rdx, %rax # OR rdx into rax.
- stosq # Save it.
- movl $X86_MSR_GSBASE, %ecx # Load MSR number.
- rdmsr # Read GSBASE.
- shlq $32, %rdx # Shift rdx into its high word.
- orq %rdx, %rax # OR rdx into rax.
- stosq # Save it.
- movl $X86_MSR_KERNEL_GSBASE, %ecx # Load MSR number.
- rdmsr # Read kernel GSBASE.
- shlq $32, %rdx # Shift rdx into its high word.
- orq %rdx, %rax # OR rdx into rax.
- stosq # Save it.
- movl $X86_MSR_EFER, %ecx # Load MSR number.
- rdmsr # Read EFER.
- shlq $32, %rdx # Shift rdx into its high word.
- orq %rdx, %rax # OR rdx into rax.
- stosq # Save it.
- xor %eax, %eax # Clear out upper bits of rax.
- str %ax # Get the TR register.
- stosq # Save it.
- pushq %rdi # Save rdi temporarily.
- movq %rax, %rdi # Set the TSS segment as the first param.
- call ArClearTssBusyBit # Clear the busy bit from the TSS.
- popq %rdi # Restore rdi.
- sidt (%rdi) # Save IDT base/limit.
- addq $10, %rdi # Advance over IDT area.
- sgdt (%rdi) # Save GDT base/limit.
- xor %eax, %eax # Zero out return value.
- ret
- END_FUNCTION(ArSaveProcessorContext)
- //
- // VOID
- // ArRestoreProcessorContext (
- // PPROCESSOR_CONTEXT Context
- // )
- //
- /*++
- Routine Description:
- This routine restores the current processor context, including the
- non-volatile general registers and the system level control registers. This
- function does not return, but instead jumps to the return address from
- the caller of the save context function.
- Arguments:
- Context - Supplies a pointer to the context to restore.
- Return Value:
- Does not return, at least not conventionally.
- --*/
- FUNCTION(ArRestoreProcessorContext)
- ##
- ## Note that the processor must already be running in 64-bit mode. This
- ## function cannot be used to trampoline from 32-bit to 64-bit mode.
- ##
- movq %rdi, %rsi # Load the pointer into rsi (for stosq).
- movq 16(%rdi), %rax # Load CS into rax.
- addq $(PROCESSOR_CONTEXT_SIZE - 20), %rsi # Get to the IDT location.
- std # Decrement rsi during lodsq.
- ##
- ## After loading the GDT, a far return is needed for it to take effect.
- ## this also loads CS.
- ##
- pushq %rax # Push CS.
- movq ArRestoreProcessorContextJump@GOTPCREL(%rip), %rax
- pushq %rax # Push "return" address (just below).
- lgdt 10(%rsi) # Load the new GDT.
- retfq # Far return to load the new GDT.
- ArRestoreProcessorContextJump:
- lidt (%rsi) # Load the IDT.
- subq $8, %rsi # Retreat to tr.
- lodsq # Pop a value and retreat.
- ltr %ax # Load the task segment.
- lodsq # Pop a value and retreat.
- movl $X86_MSR_EFER, %ecx # Load the MSR number.
- movq %rax, %rdx # Load rdx with the whole 64-bit word.
- shrq $32, %rdx # Put the high bits in edx.
- wrmsr # Write the MSR.
- lodsq # Pop a value and retreat.
- movl $X86_MSR_KERNEL_GSBASE, %ecx # Load the MSR number.
- movq %rax, %rdx # Load rdx with the whole 64-bit word.
- shrq $32, %rdx # Put the high bits in edx.
- wrmsr # Write the MSR.
- lodsq # Pop a value and retreat.
- movl $X86_MSR_GSBASE, %ecx # Load the MSR number.
- movq %rax, %rdx # Load rdx with the whole 64-bit word.
- shrq $32, %rdx # Put the high bits in edx.
- wrmsr # Write the MSR.
- lodsq # Pop a value and retreat.
- movl $X86_MSR_FSBASE, %ecx # Load the MSR number.
- movq %rax, %rdx # Load rdx with the whole 64-bit word.
- shrq $32, %rdx # Put the high bits in edx.
- wrmsr # Write the MSR.
- lodsq # Pop a value and retreat.
- movq %rax, %cr4 # Load CR4.
- lodsq # Pop a value and retreat.
- movq %rax, %cr3 # Load CR3.
- lodsq # Pop a value and retreat.
- movq %rax, %cr2 # Load CR2.
- lodsq # Pop a value and retreat.
- movq %rax, %cr0 # Load CR0.
- lodsq # Pop a value and retreat.
- movq %rax, %rsi # Load the new VA.
- subq $8, %rsi # Retreat beyond the VA.
- lodsq # Pop a value and retreat.
- movq %rax, %dr3 # Restore a debug register.
- lodsq # Pop a value and retreat.
- movq %rax, %dr2 # Restore a debug register.
- lodsq # Pop a value and retreat.
- movq %rax, %dr1 # Restore a debug register.
- lodsq # Pop a value and retreat.
- movq %rax, %dr0 # Restore a debug register.
- lodsq # Pop a value and retreat.
- movq %rax, %dr6 # Restore a debug register.
- lodsq # Pop a value and retreat.
- movq %rax, %dr7 # Restore a debug register.
- movq (%rsi), %r15 # Restore a general register.
- movq -8(%rsi), %r14 # Restore a general register.
- movq -16(%rsi), %r13 # Restore a general register.
- movq -24(%rsi), %r12 # Restore a general register.
- movq -32(%rsi), %rax # Get RSP.
- movq %rax, %rsp # Restore rsp.
- movq -40(%rsi), %rbp # Restore a general register.
- movq -48(%rsi), %rbx # Restore a general register.
- movq -56(%rsi), %r9 # Restore an argument register.
- movq -64(%rsi), %r8 # Restore an argument register.
- movq -72(%rsi), %rcx # Restore an argument register.
- movq -80(%rsi), %rdx # Restore an argument register.
- movq -88(%rsi), %r10 # Restore RSI into R10 (volatile) for now.
- movq -96(%rsi), %rdi # Restore an argument register.
- movq -104(%rsi), %rax # Get RFLAGS.
- subq $120, %rsi # Advance beyond the registers and CS.
- pushq %rax # Push rflags.
- lodsq # Pop a value and retreat.
- movq %rax, %r11 # Save rip in r11 (a volatile register).
- lodsq # Pop rax, the return value, into place.
- movq %r10, %rsi # Restore RSI (held in R10 from above).
- popfq # Pop rflags (including direction flag).
- jmp *%r11 # Jump off to the return value.
- END_FUNCTION(ArRestoreProcessorContext)
- //
- // --------------------------------------------------------- Internal Functions
- //
|