|  | #include <arch/mmu.h> | 
|  |  | 
|  | .set PROT_MODE_CSEG,0x8		# code segment selector | 
|  | .set PROT_MODE_DSEG,0x10        # data segment selector | 
|  | .set CR0_PE_ON,0x1		# protected mode enable flag | 
|  |  | 
|  | ############################################################################### | 
|  | # ENTRY POINT | 
|  | #   This code should be stored in the first sector of the hard disk. | 
|  | #   After the BIOS initializes the hardware on startup or system reset, | 
|  | #   it loads this code at physical address 0x7c00 - 0x7d00 (512 bytes). | 
|  | #   Then the BIOS jumps to the beginning of it, address 0x7c00, | 
|  | #   while running in 16-bit real-mode (8086 compatibility mode). | 
|  | #   The Code Segment register (CS) is initially zero on entry. | 
|  | # | 
|  | # This code switches into 32-bit protected mode so that all of | 
|  | # memory can accessed, then calls into C. | 
|  | ############################################################################### | 
|  |  | 
|  | .globl start					# Entry point | 
|  | start:		.code16				# This runs in real mode | 
|  | cli				# Disable interrupts | 
|  | cld				# String operations increment | 
|  |  | 
|  | # Set up the important data segment registers (DS, ES, SS). | 
|  | xorw	%ax,%ax			# Segment number zero | 
|  | movw	%ax,%ds			# -> Data Segment | 
|  | movw	%ax,%es			# -> Extra Segment | 
|  | movw	%ax,%ss			# -> Stack Segment | 
|  |  | 
|  | # Set up the stack pointer, growing downward from 0x7c00. | 
|  | movw	$start,%sp         	# Stack Pointer | 
|  |  | 
|  | # Enable A20: | 
|  | #   For fascinating historical reasons (related to the fact that | 
|  | #   the earliest 8086-based PCs could only address 1MB of physical memory | 
|  | #   and subsequent 80286-based PCs wanted to retain maximum compatibility), | 
|  | #   physical address line 20 is tied to low when the machine boots. | 
|  | #   Obviously this a bit of a drag for us, especially when trying to | 
|  | #   address memory above 1MB.  This code undoes this. | 
|  |  | 
|  | seta20.1:	inb	$0x64,%al		# Get status | 
|  | testb	$0x2,%al		# Busy? | 
|  | jnz	seta20.1		# Yes | 
|  | movb	$0xd1,%al		# Command: Write | 
|  | outb	%al,$0x64		#  output port | 
|  | seta20.2:	inb	$0x64,%al		# Get status | 
|  | testb	$0x2,%al		# Busy? | 
|  | jnz	seta20.2		# Yes | 
|  | movb	$0xdf,%al		# Enable | 
|  | outb	%al,$0x60		#  A20 | 
|  |  | 
|  | # Switch from real to protected mode: | 
|  | #   Up until now, there's been no protection, so we've gotten along perfectly | 
|  | #   well without explicitly telling the processor how to translate addresses. | 
|  | #   When we switch to protected mode, this is no longer true! | 
|  | #   We need at least to set up some "segments" that tell the processor it's | 
|  | #   OK to run code at any address, or write to any address. | 
|  | #   The 'gdt' and 'gdtdesc' tables below define these segments. | 
|  | #   This code loads them into the processor. | 
|  | #   We need this setup to ensure the transition to protected mode is smooth. | 
|  |  | 
|  | real_to_prot:	cli			# Don't allow interrupts: mandatory, | 
|  | # since we didn't set up an interrupt | 
|  | # descriptor table for handling them | 
|  | lgdt	gdtdesc		# load GDT: mandatory in protected mode | 
|  | movl	%cr0, %eax	# Turn on protected mode | 
|  | orl	$CR0_PE_ON, %eax | 
|  | movl	%eax, %cr0 | 
|  |  | 
|  | # CPU magic: jump to relocation, flush prefetch queue, and | 
|  | # reload %cs.  Has the effect of just jmp to the next | 
|  | # instruction, but simultaneously loads CS with | 
|  | # $PROT_MODE_CSEG. | 
|  | ljmp	$PROT_MODE_CSEG, $protcseg | 
|  |  | 
|  | # we've switched to 32-bit protected mode; tell the assembler | 
|  | # to generate code for that mode | 
|  | protcseg:	.code32 | 
|  | # Set up the protected-mode data segment registers | 
|  | movw	$PROT_MODE_DSEG, %ax	# Our data segment selector | 
|  | movw	%ax, %ds		# -> DS: Data Segment | 
|  | movw	%ax, %es		# -> ES: Extra Segment | 
|  | movw	%ax, %fs		# -> FS | 
|  | movw	%ax, %gs		# -> GS | 
|  | movw	%ax, %ss		# -> SS: Stack Segment | 
|  |  | 
|  | call cmain			# finish the boot load from C. | 
|  | # cmain() should not return | 
|  | spin:		jmp spin			# ..but in case it does, spin | 
|  |  | 
|  | .p2align 2			# force 4 byte alignment | 
|  | gdt:		SEG_NULL				# null seg | 
|  | SEG(STA_X|STA_R, 0x0, 0xffffffff)	# code seg | 
|  | SEG(STA_W, 0x0, 0xffffffff)	        # data seg | 
|  |  | 
|  | gdtdesc:	.word	0x17			# sizeof(gdt) - 1 | 
|  | .long	gdt			# address gdt |