4 * OS loader for marmot. Tasks done here (in no particular
7 * set up protected mode data structures
9 * set up initial page tables
10 * switch to 64 bit mode
11 * set up timer devices
12 * install disk drivers
19 .section .loader, "xa"
30 /* VESA error message is already in %si */
31 jc RealModeFlamingDeath
33 /* enter protected mode */
41 orb $1, %al /* CR0.PE => 1 */
45 .byte 0x66 /* technically still in 16 bit mode */
46 ljmp $CS32, $IntoProtectedMode
50 /****** Real mode subroutines ******/
53 * RealModeFlamingDeath --
55 * Print an error message and reboot.
59 .global RealModeFlamingDeath
69 /* wait for keypress, then reboot */
74 /* should never be reached */
82 * Zero out all bytes in .bss.
98 * Get the memory map from the BIOS using int 15,e820.
104 movl %ebx, e820_entries
126 pushw $RealModeFlamingDeath
137 /* Just do this the old fashioned way, via the kbd controller. */
157 * 16 bit version of MaskNMI.
174 * Move the GDT into its place in memory and issue lgdt.
180 movw $(GDTEnd - GDTStart), %cx
182 movl $GDT, DTLocation
183 movw $(GDTEnd - GDTStart), DTSize
189 /****** Protected mode code ******/
192 .global IntoProtectedMode
208 /* Remap IRQs and set up IDT */
214 /* Get CPUID info and verify 64 bit support */
218 /* no 64 bit mode? bail */
224 /* Look for other processors (startup IPI will be sent later) */
229 /* Set up initial page tables and enter long mode */
231 call InitialPageSetup
251 /* turn on paging and move into long mode */
253 orl $0x80000000, %eax
256 /* jump to 64 bit CS */
265 * Build the IDT and issue lidt.
270 /* first zero out the entire 64 bit IDT area */
272 movl $((GDT - IDT) >> 2), %ecx
273 1: movl $0, -4(%edi,%ecx,4)
277 /* make a trap gate for #0-19d */
279 movl $(IDT + 20 * 16), %edi /* offset into IDT */
281 movl (IDTJumpTable-4)(,%ecx,4), %edx
283 movl $(CS64 << 16), %eax
298 /* NMI (2), DF (8), and MC (18) use IST 3 instead of 2 */
299 orb $1, (16 * 2 + 4)(%edi)
300 orb $1, (16 * 8 + 4)(%edi)
301 orb $1, (16 * 18 + 4)(%edi)
303 /* load the new IDT */
305 movl $IDT, DTLocation
306 movw $(GDT - IDT), DTSize
315 * Remap IRQs to start at 0x20, masking all 16. Gate
316 * installation and IRQ unmasking is done later in irq.c.
321 movb $0x11, %al /* need ICW4 */
326 outb %al, $0x21 /* map master to 0x20-0x27 */
328 outb %al, $0xa1 /* map slave to 0x28-0x2f */
331 outb %al, $0x21 /* master IRQ2 cascades to slave */
333 outb %al, $0xa1 /* slave to IRQ2 */
335 movb $1, %al /* 80x86 mode */
338 /* done - mask all interrupts */
354 xorl %ecx, %ecx /* ecx is the address of the current page */
355 xorl %edx, %edx /* edx is the top 4 bytes of table entries */
357 /* For the address in ecx:
358 * bits 47-39 - index into pml4 table (always 0 here)
359 * bits 38-30 - index into pdp table (always 0 here)
360 * bits 29-21 - index into pd table
361 * bits 20-12 - index into page table
366 movl $(PDPTBASE | 3), %eax /* 3 == S/W/P */
368 movl %edx, (PML4BASE + 4)
372 movl $(PDBASE | 3), %eax /* 3 == S/W/P */
374 movl %edx, (PDPTBASE + 4)
379 /* ebp is the byte index into the pd table */
382 andl $(0x1ff << 3), %ebp
385 movl $(PTBASE | 3), %eax
391 /* ebp is the byte index into the page table */
394 andl $(0x1ff << 3), %ebp
397 /* pages here are identity mapped */
399 andl $0xfffff000, %eax
405 /* increment to next page */
407 cmpl e820_map + 8, %ecx
416 * Search various locations for the MP floating pointer structure.
418 * During later ACPI initialization, if an MADT is found, that
419 * information overrides what is found here.
423 /* According to MP spec, the places to look are:
425 * - First kB of EBDA (address can be found at 40:0e)
426 * - Last kB of system base memory (basemem top in CMOS)
427 * - In BIOS ro space between e0000 and fffff.
432 movw 0x40e, %cx /* segment of EBDA */
437 testw %ax, %ax /* ax = number of kB in EBDA */
447 /* Last kB of system base memory */
451 * VMW BIOS differs in mem amount between CMOS and BDA - use CMOS
452 * here, even though the value in the BDA is correct and the value
453 * in CMOS RAM is not. The reasoning is that on VMW, the MP
454 * structure isn't located there anyways, Linux uses the
455 * value from the CMOS as well, and it seems to work, and the the
456 * ACPI tables will very probably be used instead, so it's not too
459 * XXX: Need to check how real hardware behaves and adjust
460 * accordingly (and file a PR if appropriate).
471 /* Linux also searches the first kB of memory - try that, too */
486 /* MP block not found */
487 NoBIOS: xorl %eax, %eax
489 movl %eax, MPFloatingPointer
494 /* bytes 15h | 16h << 8 */
512 * Look through the address range ecx-edx to find the MP
513 * table. If it is found, return its address in eax,
514 * otherwise return 0 in eax.
539 * Check if the processor supports long mode. Return with
540 * carry clear if it does not, carry set otherwise.
543 /* check number of extended functions */
544 movl $0x80000000, %eax
546 cmpl $0x80000000, %eax
552 1: movl $0x80000001, %eax
558 /****** long mode code ******/
563 xorq %rbp, %rbp /* will be using frame pointer now */
567 /* Fill in the TSS now that stacks can be allocated. */
589 call CursorInit /* have to wait for mouse irq installation */
592 movq $0xff000000, %rdi
596 movl $HelloMessage, %ecx
611 * Mask/unmask NMI using external hardware.
633 * Populate the task state segment with entries for the three
634 * IDT-related stacks and with the entries for the IO bitmask.
642 /* First zero all bytes */
643 movl $tss_start, %edi
644 movl $(tss_end - tss_start), %esi
647 /* Set IO bitmask to all 1s (for now) */
651 movq %rax, tss_iomap(%rip)
652 movq %rax, tss_iomap+8(%rip)
653 movq %rax, tss_iomap+16(%rip)
654 movq %rax, tss_iomap+24(%rip)
655 movb %al, tss_end - 1
658 movl $(tss_iomap - tss_start), %eax
659 movw %ax, tss_iomap_base
662 * Allocate stacks for the ISTs.
664 * The order here needs to be from low address to high address
665 * (IRQ => CRITICAL => FAULT). This takes advantage of the
666 * adjacency of the stacks' virtual addresses and should save
670 movq $IRQ_STACK_BOTTOM, %rbx
671 leaq (IRQ_STACK_TOP - IRQ_STACK_BOTTOM)(%rbx), %rdi
673 movq %rbx, tss_ist1 /* top of IRQ stack */
675 leaq (CRITICAL_STACK_TOP - CRITICAL_STACK_BOTTOM)(%rbx), %rdi
677 movq %rbx, tss_ist2 /* top of critical stack */
679 leaq (FAULT_STACK_TOP - FAULT_STACK_BOTTOM)(%rbx), %rdi
681 movq %rbx, tss_ist3 /* top of fault stack */
690 * Stack allocation subroutine.
692 * Call with %rbx = bottom, %rdi = top.
693 * Return with %rax = %rbx = top
700 /* %rbx should be the limit and %rdi the base. */
703 1: movq $0x8000000000000002, %rsi /* NX|RW */
705 leaq PAGE_SIZE(%rax), %rdi
716 * Determine CPU features and install pointer to vendor-specific
717 * TestCPUFeature routine.
719 * XXX: should use alloc() insteald of PageAlloc()
725 /* alloc a kernel page for this info */
726 movq $MM_VA_KERNEL_HEAP, %rdi
727 movq $2, %rsi /* RW */
729 movq %rax, %r9 /* %r9 is base of structure */
730 leaq 24(%rax), %r10 /* %r10 is index into feature array */
733 /* data structure is:
737 * uint64 nHypervisor;
748 xorl %eax, %eax /* function 0 */
750 addq $8, %r9 /* point to next (hv) count */
751 movq $0, (%r9) /* zero hv count */
753 /* Bit 31 of %ecx of CPUID leaf 0x1 is the hypervisor present bit. */
754 btl $31, (16 + 16 + 8)(%r9)
755 jnc 1f /* no hypervisor present */
757 movl $0x40000000, %eax
761 movl $0x80000000, %eax
770 * Loop over base, hypervisor, or extended CPUID functions.
772 * Call with %r9 pointing to count entry, %r10 pointing to
775 * Adjusts %r10, uses %rax, %rbx, %rcx, %rdx, %r11, and %r12.
782 /* %r9 points to count, %r10 is current cpuid entry, %r11 is
783 * limit, %r12 is current function.
788 movq %rax, %r11 /* Store max function */
791 movb $0, 3(%r9) /* zero out high byte (0, 4, 8) */
817 .asciz "E820 memory map failed!"
819 .asciz "Welcome to Marmot!"
823 /* tval and tval2 are generic data holders for vprobe GUEST:test */
832 .quad 0x00df9a000000ffff /* CS32 */
833 .quad 0x00af9a000000ffff /* CS64 */
834 .quad 0x00cf92000000ffff /* DS */
835 .quad 0x008089007f000089 /* TS descriptor */
836 .quad 0x0000000000000000 /* TS continued */
837 .quad 0x0000000000000000 /* PRIV CS */
838 .quad 0x0000000000000000 /* PRIV DS */
839 .quad 0x0000000000000000 /* USER CS */
840 .quad 0x0000000000000000 /* USER DS */
873 .global frameBufferSize
892 .fill (20 * MAX_E820), 1, 0
895 .global MPFloatingPointer
944 .global tss_iomap_base
950 .quad 0 /* ports 0 - 63 */
951 .quad 0 /* ports 64 - 127 */
952 .quad 0 /* ports 128 - 191 */
953 .quad 0 /* ports 192 - 255 */