Changeset View
Changeset View
Standalone View
Standalone View
sys/i386/i386/locore.s
Show First 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
#include <machine/cputypes.h> | #include <machine/cputypes.h> | ||||
#include <machine/psl.h> | #include <machine/psl.h> | ||||
#include <machine/pmap.h> | #include <machine/pmap.h> | ||||
#include <machine/specialreg.h> | #include <machine/specialreg.h> | ||||
#include "assym.inc" | #include "assym.inc" | ||||
/* | /* | ||||
* XXX | |||||
* | |||||
* Note: This version greatly munged to avoid various assembler errors | |||||
* that may be fixed in newer versions of gas. Perhaps newer versions | |||||
* will have more pleasant appearance. | |||||
*/ | |||||
/* | |||||
* PTmap is recursive pagemap at top of virtual address space. | * PTmap is recursive pagemap at top of virtual address space. | ||||
* Within PTmap, the page directory can be found (third indirection). | * Within PTmap, the page directory can be found (third indirection). | ||||
*/ | */ | ||||
.globl PTmap,PTD,PTDpde | .globl PTmap,PTD,PTDpde | ||||
.set PTmap,(PTDPTDI << PDRSHIFT) | .set PTmap,(PTDPTDI << PDRSHIFT) | ||||
.set PTD,PTmap + (PTDPTDI * PAGE_SIZE) | .set PTD,PTmap + (PTDPTDI * PAGE_SIZE) | ||||
.set PTDpde,PTD + (PTDPTDI * PDESIZE) | .set PTDpde,PTD + (PTDPTDI * PDESIZE) | ||||
/* | /* | ||||
* Compiled KERNBASE location and the kernel load address | * Compiled KERNBASE location and the kernel load address, now identical. | ||||
*/ | */ | ||||
.globl kernbase | .globl kernbase | ||||
.set kernbase,KERNBASE | .set kernbase,KERNBASE | ||||
.globl kernload | .globl kernload | ||||
.set kernload,KERNLOAD | .set kernload,KERNLOAD | ||||
/* | /* | ||||
* Globals | * Globals | ||||
*/ | */ | ||||
.data | .data | ||||
ALIGN_DATA /* just to be sure */ | ALIGN_DATA /* just to be sure */ | ||||
.space 0x2000 /* space for tmpstk - temporary stack */ | .space 0x2000 /* space for tmpstk - temporary stack */ | ||||
tmpstk: | tmpstk: | ||||
.globl bootinfo | .globl bootinfo | ||||
bootinfo: .space BOOTINFO_SIZE /* bootinfo that we can handle */ | bootinfo: .space BOOTINFO_SIZE /* bootinfo that we can handle */ | ||||
.globl KERNend | |||||
KERNend: .long 0 /* phys addr end of kernel (just after bss) */ | |||||
physfree: .long 0 /* phys addr of next free page */ | |||||
.globl IdlePTD | |||||
IdlePTD: .long 0 /* phys addr of kernel PTD */ | |||||
#if defined(PAE) || defined(PAE_TABLES) | |||||
.globl IdlePDPT | |||||
IdlePDPT: .long 0 /* phys addr of kernel PDPT */ | |||||
#endif | |||||
.globl KPTmap | |||||
KPTmap: .long 0 /* address of kernel page tables */ | |||||
.globl KPTphys | |||||
KPTphys: .long 0 /* phys addr of kernel page tables */ | |||||
.globl proc0kstack | |||||
proc0kstack: .long 0 /* address of proc 0 kstack space */ | |||||
p0kpa: .long 0 /* phys addr of proc0's STACK */ | |||||
vm86phystk: .long 0 /* PA of vm86/bios stack */ | |||||
.globl vm86paddr, vm86pa | |||||
vm86paddr: .long 0 /* address of vm86 region */ | |||||
vm86pa: .long 0 /* phys addr of vm86 region */ | |||||
/********************************************************************** | |||||
* | |||||
* Some handy macros | |||||
* | |||||
*/ | |||||
#define R(foo) ((foo)-KERNBASE) | |||||
#define ALLOCPAGES(foo) \ | |||||
movl R(physfree), %esi ; \ | |||||
movl $((foo)*PAGE_SIZE), %eax ; \ | |||||
addl %esi, %eax ; \ | |||||
movl %eax, R(physfree) ; \ | |||||
movl %esi, %edi ; \ | |||||
movl $((foo)*PAGE_SIZE),%ecx ; \ | |||||
xorl %eax,%eax ; \ | |||||
cld ; \ | |||||
rep ; \ | |||||
stosb | |||||
/* | |||||
* fillkpt | |||||
* eax = page frame address | |||||
* ebx = index into page table | |||||
* ecx = how many pages to map | |||||
* base = base address of page dir/table | |||||
* prot = protection bits | |||||
*/ | |||||
#define fillkpt(base, prot) \ | |||||
shll $PTESHIFT,%ebx ; \ | |||||
addl base,%ebx ; \ | |||||
orl $PG_V,%eax ; \ | |||||
orl prot,%eax ; \ | |||||
1: movl %eax,(%ebx) ; \ | |||||
addl $PAGE_SIZE,%eax ; /* increment physical address */ \ | |||||
addl $PTESIZE,%ebx ; /* next pte */ \ | |||||
loop 1b | |||||
/* | |||||
* fillkptphys(prot) | |||||
* eax = physical address | |||||
* ecx = how many pages to map | |||||
* prot = protection bits | |||||
*/ | |||||
#define fillkptphys(prot) \ | |||||
movl %eax, %ebx ; \ | |||||
shrl $PAGE_SHIFT, %ebx ; \ | |||||
fillkpt(R(KPTphys), prot) | |||||
.text | .text | ||||
/********************************************************************** | /********************************************************************** | ||||
* | * | ||||
* This is where the bootblocks start us, set the ball rolling... | * This is where the bootblocks start us, set the ball rolling... | ||||
* | * | ||||
*/ | */ | ||||
NON_GPROF_ENTRY(btext) | NON_GPROF_ENTRY(btext) | ||||
/* Tell the bios to warmboot next time */ | /* Tell the bios to warmboot next time */ | ||||
movw $0x1234,0x472 | movw $0x1234,0x472 | ||||
/* Set up a real frame in case the double return in newboot is executed. */ | /* Set up a real frame in case the double return in newboot is executed. */ | ||||
xorl %ebp,%ebp | |||||
pushl %ebp | pushl %ebp | ||||
movl %esp, %ebp | movl %esp, %ebp | ||||
/* Don't trust what the BIOS gives for eflags. */ | /* Don't trust what the BIOS gives for eflags. */ | ||||
pushl $PSL_KERNEL | pushl $PSL_KERNEL | ||||
popfl | popfl | ||||
/* | /* | ||||
Show All 9 Lines | |||||
* | * | ||||
* XXX we don't check that there is memory for our bss and page tables | * XXX we don't check that there is memory for our bss and page tables | ||||
* before using it. | * before using it. | ||||
* | * | ||||
* Note: we must be careful to not overwrite an active gdt or idt. They | * Note: we must be careful to not overwrite an active gdt or idt. They | ||||
* inactive from now until we switch to new ones, since we don't load any | * inactive from now until we switch to new ones, since we don't load any | ||||
* more segment registers or permit interrupts until after the switch. | * more segment registers or permit interrupts until after the switch. | ||||
*/ | */ | ||||
movl $R(end),%ecx | movl $end,%ecx | ||||
movl $R(edata),%edi | movl $edata,%edi | ||||
subl %edi,%ecx | subl %edi,%ecx | ||||
xorl %eax,%eax | xorl %eax,%eax | ||||
cld | cld | ||||
rep | rep | ||||
stosb | stosb | ||||
call recover_bootinfo | call recover_bootinfo | ||||
/* Get onto a stack that we can trust. */ | /* Get onto a stack that we can trust. */ | ||||
/* | /* | ||||
* XXX this step is delayed in case recover_bootinfo needs to return via | * XXX this step is delayed in case recover_bootinfo needs to return via | ||||
* the old stack, but it need not be, since recover_bootinfo actually | * the old stack, but it need not be, since recover_bootinfo actually | ||||
* returns via the old frame. | * returns via the old frame. | ||||
*/ | */ | ||||
movl $R(tmpstk),%esp | movl $tmpstk,%esp | ||||
call identify_cpu | call identify_cpu | ||||
call create_pagetables | call pmap_cold | ||||
/* | |||||
* If the CPU has support for VME, turn it on. | |||||
*/ | |||||
testl $CPUID_VME, R(cpu_feature) | |||||
jz 1f | |||||
movl %cr4, %eax | |||||
orl $CR4_VME, %eax | |||||
movl %eax, %cr4 | |||||
1: | |||||
/* Now enable paging */ | |||||
#if defined(PAE) || defined(PAE_TABLES) | |||||
movl R(IdlePDPT), %eax | |||||
movl %eax, %cr3 | |||||
movl %cr4, %edx | |||||
orl $CR4_PAE, %edx | |||||
movl %edx, %cr4 | |||||
#else | |||||
movl R(IdlePTD), %eax | |||||
movl %eax,%cr3 /* load ptd addr into mmu */ | |||||
#endif | |||||
movl %cr0,%edx /* get control word */ | |||||
orl $CR0_PE|CR0_PG,%edx /* enable paging */ | |||||
movl %edx,%cr0 /* and let's page NOW! */ | |||||
pushl $begin /* jump to high virtualized address */ | |||||
ret | |||||
begin: | |||||
/* | |||||
* Now running relocated at KERNBASE where the system is linked to run. | |||||
* | |||||
* Remove the lowest part of the double mapping of low memory to get | |||||
* some null pointer checks. | |||||
*/ | |||||
movl $0,PTD | |||||
movl %eax,%cr3 /* invalidate TLB */ | |||||
/* set up bootstrap stack */ | /* set up bootstrap stack */ | ||||
movl proc0kstack,%eax /* location of in-kernel stack */ | movl proc0kstack,%eax /* location of in-kernel stack */ | ||||
/* | /* | ||||
* Only use bottom page for init386(). init386() calculates the | * Only use bottom page for init386(). init386() calculates the | ||||
* PCB + FPU save area size and returns the true top of stack. | * PCB + FPU save area size and returns the true top of stack. | ||||
*/ | */ | ||||
leal PAGE_SIZE(%eax),%esp | leal PAGE_SIZE(%eax),%esp | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | |||||
1: | 1: | ||||
/* | /* | ||||
* If we have a kernelname copy it in | * If we have a kernelname copy it in | ||||
*/ | */ | ||||
movl BI_KERNELNAME(%ebx),%esi | movl BI_KERNELNAME(%ebx),%esi | ||||
cmpl $0,%esi | cmpl $0,%esi | ||||
je 2f /* No kernelname */ | je 2f /* No kernelname */ | ||||
movl $MAXPATHLEN,%ecx /* Brute force!!! */ | movl $MAXPATHLEN,%ecx /* Brute force!!! */ | ||||
movl $R(kernelname),%edi | movl $kernelname,%edi | ||||
cmpb $'/',(%esi) /* Make sure it starts with a slash */ | cmpb $'/',(%esi) /* Make sure it starts with a slash */ | ||||
je 1f | je 1f | ||||
movb $'/',(%edi) | movb $'/',(%edi) | ||||
incl %edi | incl %edi | ||||
decl %ecx | decl %ecx | ||||
1: | 1: | ||||
cld | cld | ||||
rep | rep | ||||
Show All 11 Lines | 2: | ||||
je got_bi_size /* no, sizeless version */ | je got_bi_size /* no, sizeless version */ | ||||
movl BI_SIZE(%ebx),%ecx | movl BI_SIZE(%ebx),%ecx | ||||
got_bi_size: | got_bi_size: | ||||
/* | /* | ||||
* Copy the common part of the bootinfo struct | * Copy the common part of the bootinfo struct | ||||
*/ | */ | ||||
movl %ebx,%esi | movl %ebx,%esi | ||||
movl $R(bootinfo),%edi | movl $bootinfo,%edi | ||||
cmpl $BOOTINFO_SIZE,%ecx | cmpl $BOOTINFO_SIZE,%ecx | ||||
jbe got_common_bi_size | jbe got_common_bi_size | ||||
movl $BOOTINFO_SIZE,%ecx | movl $BOOTINFO_SIZE,%ecx | ||||
got_common_bi_size: | got_common_bi_size: | ||||
cld | cld | ||||
rep | rep | ||||
movsb | movsb | ||||
#ifdef NFS_ROOT | #ifdef NFS_ROOT | ||||
#ifndef BOOTP_NFSV3 | #ifndef BOOTP_NFSV3 | ||||
/* | /* | ||||
* If we have a nfs_diskless structure copy it in | * If we have a nfs_diskless structure copy it in | ||||
*/ | */ | ||||
movl BI_NFS_DISKLESS(%ebx),%esi | movl BI_NFS_DISKLESS(%ebx),%esi | ||||
cmpl $0,%esi | cmpl $0,%esi | ||||
je olddiskboot | je olddiskboot | ||||
movl $R(nfs_diskless),%edi | movl $nfs_diskless,%edi | ||||
movl $NFSDISKLESS_SIZE,%ecx | movl $NFSDISKLESS_SIZE,%ecx | ||||
cld | cld | ||||
rep | rep | ||||
movsb | movsb | ||||
movl $R(nfs_diskless_valid),%edi | movl $nfs_diskless_valid,%edi | ||||
movl $1,(%edi) | movl $1,(%edi) | ||||
#endif | #endif | ||||
#endif | #endif | ||||
/* | /* | ||||
* The old style disk boot. | * The old style disk boot. | ||||
* (*btext)(howto, bootdev, cyloffset, esym); | * (*btext)(howto, bootdev, cyloffset, esym); | ||||
* Note that the newer boot code just falls into here to pick | * Note that the newer boot code just falls into here to pick | ||||
* up howto and bootdev, cyloffset and esym are no longer used | * up howto and bootdev, cyloffset and esym are no longer used | ||||
*/ | */ | ||||
olddiskboot: | olddiskboot: | ||||
movl 8(%ebp),%eax | movl 8(%ebp),%eax | ||||
movl %eax,R(boothowto) | movl %eax,boothowto | ||||
movl 12(%ebp),%eax | movl 12(%ebp),%eax | ||||
movl %eax,R(bootdev) | movl %eax,bootdev | ||||
ret | ret | ||||
/********************************************************************** | /********************************************************************** | ||||
* | * | ||||
* Identify the CPU and initialize anything special about it | * Identify the CPU and initialize anything special about it | ||||
* | * | ||||
Show All 21 Lines | identify_cpu: | ||||
pushfl | pushfl | ||||
movl $0x5555, %eax | movl $0x5555, %eax | ||||
xorl %edx, %edx | xorl %edx, %edx | ||||
movl $2, %ecx | movl $2, %ecx | ||||
clc | clc | ||||
divl %ecx | divl %ecx | ||||
jz trynexgen | jz trynexgen | ||||
popfl | popfl | ||||
movl $CPU_386,R(cpu) | movl $CPU_386,cpu | ||||
jmp 3f | jmp 3f | ||||
trynexgen: | trynexgen: | ||||
popfl | popfl | ||||
movl $CPU_NX586,R(cpu) | movl $CPU_NX586,cpu | ||||
movl $0x4778654e,R(cpu_vendor) # store vendor string | movl $0x4778654e,cpu_vendor # store vendor string | ||||
movl $0x72446e65,R(cpu_vendor+4) | movl $0x72446e65,cpu_vendor+4 | ||||
movl $0x6e657669,R(cpu_vendor+8) | movl $0x6e657669,cpu_vendor+8 | ||||
movl $0,R(cpu_vendor+12) | movl $0,cpu_vendor+12 | ||||
jmp 3f | jmp 3f | ||||
try486: /* Try to toggle identification flag; does not exist on early 486s. */ | try486: /* Try to toggle identification flag; does not exist on early 486s. */ | ||||
pushfl | pushfl | ||||
popl %eax | popl %eax | ||||
movl %eax,%ecx | movl %eax,%ecx | ||||
xorl $PSL_ID,%eax | xorl $PSL_ID,%eax | ||||
pushl %eax | pushl %eax | ||||
popfl | popfl | ||||
pushfl | pushfl | ||||
popl %eax | popl %eax | ||||
xorl %ecx,%eax | xorl %ecx,%eax | ||||
andl $PSL_ID,%eax | andl $PSL_ID,%eax | ||||
pushl %ecx | pushl %ecx | ||||
popfl | popfl | ||||
testl %eax,%eax | testl %eax,%eax | ||||
jnz trycpuid | jnz trycpuid | ||||
movl $CPU_486,R(cpu) | movl $CPU_486,cpu | ||||
/* | /* | ||||
* Check Cyrix CPU | * Check Cyrix CPU | ||||
* Cyrix CPUs do not change the undefined flags following | * Cyrix CPUs do not change the undefined flags following | ||||
* execution of the divide instruction which divides 5 by 2. | * execution of the divide instruction which divides 5 by 2. | ||||
* | * | ||||
* Note: CPUID is enabled on M2, so it passes another way. | * Note: CPUID is enabled on M2, so it passes another way. | ||||
*/ | */ | ||||
Show All 10 Lines | |||||
trycyrix: | trycyrix: | ||||
popfl | popfl | ||||
/* | /* | ||||
* IBM Bluelighting CPU also doesn't change the undefined flags. | * IBM Bluelighting CPU also doesn't change the undefined flags. | ||||
* Because IBM doesn't disclose the information for Bluelighting | * Because IBM doesn't disclose the information for Bluelighting | ||||
* CPU, we couldn't distinguish it from Cyrix's (including IBM | * CPU, we couldn't distinguish it from Cyrix's (including IBM | ||||
* brand of Cyrix CPUs). | * brand of Cyrix CPUs). | ||||
*/ | */ | ||||
movl $0x69727943,R(cpu_vendor) # store vendor string | movl $0x69727943,cpu_vendor # store vendor string | ||||
movl $0x736e4978,R(cpu_vendor+4) | movl $0x736e4978,cpu_vendor+4 | ||||
movl $0x64616574,R(cpu_vendor+8) | movl $0x64616574,cpu_vendor+8 | ||||
jmp 3f | jmp 3f | ||||
trycpuid: /* Use the `cpuid' instruction. */ | trycpuid: /* Use the `cpuid' instruction. */ | ||||
xorl %eax,%eax | xorl %eax,%eax | ||||
cpuid # cpuid 0 | cpuid # cpuid 0 | ||||
movl %eax,R(cpu_high) # highest capability | movl %eax,cpu_high # highest capability | ||||
movl %ebx,R(cpu_vendor) # store vendor string | movl %ebx,cpu_vendor # store vendor string | ||||
movl %edx,R(cpu_vendor+4) | movl %edx,cpu_vendor+4 | ||||
movl %ecx,R(cpu_vendor+8) | movl %ecx,cpu_vendor+8 | ||||
movb $0,R(cpu_vendor+12) | movb $0,cpu_vendor+12 | ||||
movl $1,%eax | movl $1,%eax | ||||
cpuid # cpuid 1 | cpuid # cpuid 1 | ||||
movl %eax,R(cpu_id) # store cpu_id | movl %eax,cpu_id # store cpu_id | ||||
movl %ebx,R(cpu_procinfo) # store cpu_procinfo | movl %ebx,cpu_procinfo # store cpu_procinfo | ||||
movl %edx,R(cpu_feature) # store cpu_feature | movl %edx,cpu_feature # store cpu_feature | ||||
movl %ecx,R(cpu_feature2) # store cpu_feature2 | movl %ecx,cpu_feature2 # store cpu_feature2 | ||||
rorl $8,%eax # extract family type | rorl $8,%eax # extract family type | ||||
andl $15,%eax | andl $15,%eax | ||||
cmpl $5,%eax | cmpl $5,%eax | ||||
jae 1f | jae 1f | ||||
/* less than Pentium; must be 486 */ | /* less than Pentium; must be 486 */ | ||||
movl $CPU_486,R(cpu) | movl $CPU_486,cpu | ||||
jmp 3f | jmp 3f | ||||
1: | 1: | ||||
/* a Pentium? */ | /* a Pentium? */ | ||||
cmpl $5,%eax | cmpl $5,%eax | ||||
jne 2f | jne 2f | ||||
movl $CPU_586,R(cpu) | movl $CPU_586,cpu | ||||
jmp 3f | jmp 3f | ||||
2: | 2: | ||||
/* Greater than Pentium...call it a Pentium Pro */ | /* Greater than Pentium...call it a Pentium Pro */ | ||||
movl $CPU_686,R(cpu) | movl $CPU_686,cpu | ||||
3: | 3: | ||||
ret | |||||
/********************************************************************** | |||||
* | |||||
* Create the first page directory and its page tables. | |||||
* | |||||
*/ | |||||
create_pagetables: | |||||
/* Find end of kernel image (rounded up to a page boundary). */ | |||||
movl $R(_end),%esi | |||||
/* Include symbols, if any. */ | |||||
movl R(bootinfo+BI_ESYMTAB),%edi | |||||
testl %edi,%edi | |||||
je over_symalloc | |||||
movl %edi,%esi | |||||
movl $KERNBASE,%edi | |||||
addl %edi,R(bootinfo+BI_SYMTAB) | |||||
addl %edi,R(bootinfo+BI_ESYMTAB) | |||||
over_symalloc: | |||||
/* If we are told where the end of the kernel space is, believe it. */ | |||||
movl R(bootinfo+BI_KERNEND),%edi | |||||
testl %edi,%edi | |||||
je no_kernend | |||||
movl %edi,%esi | |||||
no_kernend: | |||||
addl $PDRMASK,%esi /* Play conservative for now, and */ | |||||
andl $~PDRMASK,%esi /* ... round up to PDR boundary */ | |||||
movl %esi,R(KERNend) /* save end of kernel */ | |||||
movl %esi,R(physfree) /* next free page is at end of kernel */ | |||||
/* Allocate Kernel Page Tables */ | |||||
ALLOCPAGES(NKPT) | |||||
movl %esi,R(KPTphys) | |||||
addl $(KERNBASE-(KPTDI<<(PDRSHIFT-PAGE_SHIFT+PTESHIFT))),%esi | |||||
movl %esi,R(KPTmap) | |||||
/* Allocate Page Table Directory */ | |||||
#if defined(PAE) || defined(PAE_TABLES) | |||||
/* XXX only need 32 bytes (easier for now) */ | |||||
ALLOCPAGES(1) | |||||
movl %esi,R(IdlePDPT) | |||||
#endif | |||||
ALLOCPAGES(NPGPTD) | |||||
movl %esi,R(IdlePTD) | |||||
/* Allocate KSTACK */ | |||||
ALLOCPAGES(TD0_KSTACK_PAGES) | |||||
movl %esi,R(p0kpa) | |||||
addl $KERNBASE, %esi | |||||
movl %esi, R(proc0kstack) | |||||
ALLOCPAGES(1) /* vm86/bios stack */ | |||||
movl %esi,R(vm86phystk) | |||||
ALLOCPAGES(3) /* pgtable + ext + IOPAGES */ | |||||
movl %esi,R(vm86pa) | |||||
addl $KERNBASE, %esi | |||||
movl %esi, R(vm86paddr) | |||||
/* | |||||
* Enable PSE and PGE. | |||||
*/ | |||||
#ifndef DISABLE_PSE | |||||
testl $CPUID_PSE, R(cpu_feature) | |||||
jz 1f | |||||
movl $PG_PS, R(pseflag) | |||||
movl %cr4, %eax | |||||
orl $CR4_PSE, %eax | |||||
movl %eax, %cr4 | |||||
1: | |||||
#endif | |||||
#ifndef DISABLE_PG_G | |||||
testl $CPUID_PGE, R(cpu_feature) | |||||
jz 2f | |||||
movl $PG_G, R(pgeflag) | |||||
movl %cr4, %eax | |||||
orl $CR4_PGE, %eax | |||||
movl %eax, %cr4 | |||||
2: | |||||
#endif | |||||
/* | |||||
* Initialize page table pages mapping physical address zero through the | |||||
* (physical) end of the kernel. Many of these pages must be reserved, | |||||
* and we reserve them all and map them linearly for convenience. We do | |||||
* this even if we've enabled PSE above; we'll just switch the corresponding | |||||
* kernel PDEs before we turn on paging. | |||||
* | |||||
* XXX: We waste some pages here in the PSE case! | |||||
* | |||||
* This and all other page table entries allow read and write access for | |||||
* various reasons. Kernel mappings never have any access restrictions. | |||||
*/ | |||||
xorl %eax, %eax | |||||
movl R(KERNend),%ecx | |||||
shrl $PAGE_SHIFT,%ecx | |||||
fillkptphys($PG_RW) | |||||
/* Map page table pages. */ | |||||
movl R(KPTphys),%eax | |||||
movl $NKPT,%ecx | |||||
fillkptphys($PG_RW) | |||||
/* Map page directory. */ | |||||
#if defined(PAE) || defined(PAE_TABLES) | |||||
movl R(IdlePDPT), %eax | |||||
movl $1, %ecx | |||||
fillkptphys($PG_RW) | |||||
#endif | |||||
movl R(IdlePTD), %eax | |||||
movl $NPGPTD, %ecx | |||||
fillkptphys($PG_RW) | |||||
/* Map proc0's KSTACK in the physical way ... */ | |||||
movl R(p0kpa), %eax | |||||
movl $(TD0_KSTACK_PAGES), %ecx | |||||
fillkptphys($PG_RW) | |||||
/* Map ISA hole */ | |||||
movl $ISA_HOLE_START, %eax | |||||
movl $ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx | |||||
fillkptphys($PG_RW) | |||||
/* Map space for the vm86 region */ | |||||
movl R(vm86phystk), %eax | |||||
movl $4, %ecx | |||||
fillkptphys($PG_RW) | |||||
/* Map page 0 into the vm86 page table */ | |||||
movl $0, %eax | |||||
movl $0, %ebx | |||||
movl $1, %ecx | |||||
fillkpt(R(vm86pa), $PG_RW|PG_U) | |||||
/* ...likewise for the ISA hole */ | |||||
movl $ISA_HOLE_START, %eax | |||||
movl $ISA_HOLE_START>>PAGE_SHIFT, %ebx | |||||
movl $ISA_HOLE_LENGTH>>PAGE_SHIFT, %ecx | |||||
fillkpt(R(vm86pa), $PG_RW|PG_U) | |||||
/* | |||||
* Create an identity mapping for low physical memory, including the kernel. | |||||
* This is only used to map the 2 instructions for jumping to 'begin' in | |||||
* locore (we map everything to avoid having to determine where these | |||||
* instructions are). ACPI resume will transiently restore the first PDE in | |||||
* this mapping (and depend on this PDE's page table created here not being | |||||
* destroyed). See pmap_bootstrap() for more details. | |||||
* | |||||
* Note: There are errata concerning large pages and physical address zero, | |||||
* so a PG_PS mapping should not be used for PDE 0. Our double mapping | |||||
* avoids this automatically by not using PG_PS for PDE #KPDI so that PAT | |||||
* bits can be set at the page level for i/o pages below 1 MB. | |||||
*/ | |||||
movl R(KPTphys), %eax | |||||
xorl %ebx, %ebx | |||||
movl $NKPT, %ecx | |||||
fillkpt(R(IdlePTD), $PG_RW) | |||||
/* | |||||
* Install PDEs for PTs covering enough kva to bootstrap. Then for the PSE | |||||
* case, replace the PDEs whose coverage is strictly within the kernel | |||||
* (between KERNLOAD (rounded up) and KERNend) by large-page PDEs. | |||||
*/ | |||||
movl R(KPTphys), %eax | |||||
movl $KPTDI, %ebx | |||||
movl $NKPT, %ecx | |||||
fillkpt(R(IdlePTD), $PG_RW) | |||||
cmpl $0,R(pseflag) | |||||
je done_pde | |||||
movl R(KERNend), %ecx | |||||
movl $(KERNLOAD + PDRMASK) & ~PDRMASK, %eax | |||||
subl %eax, %ecx | |||||
shrl $PDRSHIFT, %ecx | |||||
movl $KPTDI + ((KERNLOAD + PDRMASK) >> PDRSHIFT), %ebx | |||||
shll $PDESHIFT, %ebx | |||||
addl R(IdlePTD), %ebx | |||||
orl $(PG_V|PG_RW|PG_PS), %eax | |||||
1: movl %eax, (%ebx) | |||||
addl $(1 << PDRSHIFT), %eax | |||||
addl $PDESIZE, %ebx | |||||
loop 1b | |||||
done_pde: | |||||
/* install a pde recursively mapping page directory as a page table */ | |||||
movl R(IdlePTD), %eax | |||||
movl $PTDPTDI, %ebx | |||||
movl $NPGPTD,%ecx | |||||
fillkpt(R(IdlePTD), $PG_RW) | |||||
#if defined(PAE) || defined(PAE_TABLES) | |||||
movl R(IdlePTD), %eax | |||||
xorl %ebx, %ebx | |||||
movl $NPGPTD, %ecx | |||||
fillkpt(R(IdlePDPT), $0x0) | |||||
#endif | |||||
ret | ret | ||||
#ifdef XENHVM | #ifdef XENHVM | ||||
/* Xen Hypercall page */ | /* Xen Hypercall page */ | ||||
.text | .text | ||||
.p2align PAGE_SHIFT, 0x90 /* Hypercall_page needs to be PAGE aligned */ | .p2align PAGE_SHIFT, 0x90 /* Hypercall_page needs to be PAGE aligned */ | ||||
NON_GPROF_ENTRY(hypercall_page) | NON_GPROF_ENTRY(hypercall_page) | ||||
.skip 0x1000, 0x90 /* Fill with "nop"s */ | .skip 0x1000, 0x90 /* Fill with "nop"s */ | ||||
#endif | #endif |