#include #include #include #include #include #include #include #include .text .code32 #define sym_phys(sym) ((sym) - __XEN_VIRT_START) #define BOOT_CS32 0x0008 #define BOOT_CS64 0x0010 #define BOOT_DS 0x0018 #define BOOT_PSEUDORM_CS 0x0020 #define BOOT_PSEUDORM_DS 0x0028 ENTRY(start) jmp __start .align 4 /*** MULTIBOOT HEADER ****/ #define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_HEADER_MODS_ALIGNED | \ MULTIBOOT_HEADER_WANT_MEMORY) /* Magic number indicating a Multiboot header. */ .long MULTIBOOT_HEADER_MAGIC /* Flags to bootloader (see Multiboot spec). */ .long MULTIBOOT_HEADER_FLAGS /* Checksum: must be the negated sum of the first two fields. */ .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) .section .init.text, "ax" .Lbad_cpu_msg: .asciz "ERR: Not a 64-bit CPU!" .Lbad_ldr_msg: .asciz "ERR: Not a Multiboot bootloader!" bad_cpu: mov $(sym_phys(.Lbad_cpu_msg)),%esi # Error message jmp print_err not_multiboot: mov $(sym_phys(.Lbad_ldr_msg)),%esi # Error message print_err: mov $0xB8000,%edi # VGA framebuffer 1: mov (%esi),%bl test %bl,%bl # Terminate on '\0' sentinel 2: je 2b mov $0x3f8+5,%dx # UART Line Status Register 3: in %dx,%al test $0x20,%al # Test THR Empty flag je 3b mov $0x3f8+0,%dx # UART Transmit Holding Register mov %bl,%al out %al,%dx # Send a character over the serial line movsb # Write a character to the VGA framebuffer mov $7,%al stosb # Write an attribute to the VGA framebuffer jmp 1b gdt_boot_descr: .word 6*8-1 .long sym_phys(trampoline_gdt) __start: cld cli /* Initialise GDT and basic data segments. */ lgdt %cs:sym_phys(gdt_boot_descr) mov $BOOT_DS,%ecx mov %ecx,%ds mov %ecx,%es mov %ecx,%ss /* Check for Multiboot bootloader */ cmp $0x2BADB002,%eax jne not_multiboot /* Set up trampoline segment 64k below EBDA */ movzwl 0x40e,%eax /* EBDA segment */ cmp $0xa000,%eax /* sanity check (high) */ jae 0f cmp $0x4000,%eax /* sanity check (low) */ jae 1f 0: movzwl 0x413,%eax /* use base memory size on failure */ shl $10-4,%eax 1: /* * Compare the value in the BDA with the information from the * multiboot structure (if available) and use the smallest. */ testb $MBI_MEMLIMITS,(%ebx) jz 2f /* not available? BDA value will be fine */ mov 4(%ebx),%edx cmp $0x100,%edx /* is the multiboot value too small? */ jb 2f /* if so, do not use it */ shl $10-4,%edx cmp %eax,%edx /* compare with BDA value */ cmovb %edx,%eax /* and use the smaller */ 2: /* Reserve 64kb for the trampoline */ sub $0x1000,%eax /* From arch/x86/smpboot.c: start_eip had better be page-aligned! */ xor %al, %al shl $4, %eax mov %eax,sym_phys(trampoline_phys) /* Save the Multiboot info struct (after relocation) for later use. */ mov $sym_phys(cpu0_stack)+1024,%esp push %ebx call reloc mov %eax,sym_phys(multiboot_ptr) /* Initialize BSS (no nasty surprises!) */ mov $sym_phys(__bss_start),%edi mov $sym_phys(_end),%ecx sub %edi,%ecx xor %eax,%eax rep stosb /* Interrogate CPU extended features via CPUID. */ mov $0x80000000,%eax cpuid xor %edx,%edx cmp $0x80000000,%eax # any function > 0x80000000? jbe 1f mov $0x80000001,%eax cpuid 1: mov %edx,sym_phys(cpuid_ext_features) mov %edx,sym_phys(boot_cpu_data)+CPUINFO86_ext_features /* Check for availability of long mode. */ bt $29,%edx jnc bad_cpu /* Initialise L2 boot-map page table entries (16MB). */ mov $sym_phys(l2_bootmap),%edx mov $PAGE_HYPERVISOR|_PAGE_PSE,%eax mov $8,%ecx 1: mov %eax,(%edx) add $8,%edx add $(1<= 0xa0 && pfn < 0xc0 .long (pfn << PAGE_SHIFT) | PAGE_HYPERVISOR_NOCACHE | MAP_SMALL_PAGES .else .long (pfn << PAGE_SHIFT) | PAGE_HYPERVISOR | MAP_SMALL_PAGES .endif .long 0 pfn = pfn + 1 .endr .size l1_identmap, . - l1_identmap