1 #include "asm.h" 2 #include "memlayout.h" 3 #include "mmu.h" 4 5 # Each non-boot CPU ("AP") is started up in response to a STARTUP 6 # IPI from the boot CPU. Section B.4.2 of the Multi-Processor 7 # Specification says that the AP will start in real mode with CS:IP 8 # set to XY00:0000, where XY is an 8-bit value sent with the 9 # STARTUP. Thus this code must start at a 4096-byte boundary. 10 # 11 # Because this code sets DS to zero, it must sit 12 # at an address in the low 2^16 bytes. 13 # 14 # Startothers (in main.c) sends the STARTUPs one at a time. 15 # It copies this code (start) at 0x7000. It puts the address of 16 # a newly allocated per-core stack in start-4,the address of the 17 # place to jump to (mpenter) in start-8, and the physical address 18 # of entrypgdir in start-12. 19 # 20 # This code combines elements of bootasm.S and entry.S. 21 22 .code16 23 .globl start 24 start: 25 cli 26 27 # Zero data segment registers DS, ES, and SS. 28 xorw %ax,%ax 29 movw %ax,%ds 30 movw %ax,%es 31 movw %ax,%ss 32 33 # Switch from real to protected mode. Use a bootstrap GDT that makes 34 # virtual addresses map directly to physical addresses so that the 35 # effective memory map doesn't change during the transition. 36 lgdt gdtdesc 37 movl %cr0, %eax 38 orl $CR0_PE, %eax 39 movl %eax, %cr0 40 41 # Complete the transition to 32-bit protected mode by using a long jmp 42 # to reload %cs and %eip. The segment descriptors are set up with no 43 # translation, so that the mapping is still the identity mapping. 44 ljmpl $(SEG_KCODE<<3), $(start32) 45 46 //PAGEBREAK! 47 .code32 # Tell assembler to generate 32-bit code now. 48 start32: 49 # Set up the protected-mode data segment registers 50 movw $(SEG_KDATA<<3), %ax # Our data segment selector 51 movw %ax, %ds # -> DS: Data Segment 52 movw %ax, %es # -> ES: Extra Segment 53 movw %ax, %ss # -> SS: Stack Segment 54 movw $0, %ax # Zero segments not ready for use 55 movw %ax, %fs # -> FS 56 movw %ax, %gs # -> GS 57 58 # Turn on page size extension for 4Mbyte pages 59 movl %cr4, %eax 60 orl $(CR4_PSE), %eax 61 movl %eax, %cr4 62 # Use entrypgdir as our initial page table 63 movl (start-12), %eax 64 movl %eax, %cr3 65 # Turn on paging. 66 movl %cr0, %eax 67 orl $(CR0_PE|CR0_PG|CR0_WP), %eax 68 movl %eax, %cr0 69 70 # Switch to the stack allocated by startothers() 71 movl (start-4), %esp 72 # Call mpenter() 73 call *(start-8) 74 75 movw $0x8a00, %ax 76 movw %ax, %dx 77 outw %ax, %dx 78 movw $0x8ae0, %ax 79 outw %ax, %dx 80 spin: 81 jmp spin 82 83 .p2align 2 84 gdt: 85 SEG_NULLASM 86 SEG_ASM(STA_X|STA_R, 0, 0xffffffff) 87 SEG_ASM(STA_W, 0, 0xffffffff) 88 89 90 gdtdesc: 91 .word (gdtdesc - gdt - 1) 92 .long gdt 93