📄 start32.s
字号:
/* #defines because ljmp wants a number, probably gas bug *//* .equ KERN_CODE_SEG,_pmcs-_gdt */#define KERN_CODE_SEG 0x08 .equ KERN_DATA_SEG,_pmds-_gdt/* .equ REAL_CODE_SEG,_rmcs-_gdt */#define REAL_CODE_SEG 0x18 .equ REAL_DATA_SEG,_rmds-_gdt .equ CR0_PE,1#ifdef GAS291#define DATA32 data32;#define ADDR32 addr32;#define LJMPI(x) ljmp x#else#define DATA32 data32#define ADDR32 addr32/* newer GAS295 require #define LJMPI(x) ljmp *x */#define LJMPI(x) ljmp x#endif/* Size of segment allocated to first32.c in protected mode */#define FIRST32SIZE (6*1024)/* * NOTE: if you write a subroutine that is called from C code (gcc/egcs), * then you only have to take care of %ebx, %esi, %edi and %ebp. These * registers must not be altered under any circumstance. All other registers * may be clobbered without any negative side effects. If you don't follow * this rule then you'll run into strange effects that only occur on some * gcc versions (because the register allocator may use different registers). * * All the data32 prefixes for the ljmp instructions are necessary, because * the assembler emits code with a relocation address of 0. This means that * all destinations are initially negative, which the assembler doesn't grok, * because for some reason negative numbers don't fit into 16 bits. The addr32 * prefixes are there for the same reasons, because otherwise the memory * references are only 16 bit wide. Theoretically they are all superfluous. * One last note about prefixes: the data32 prefixes on all call _real_to_prot * instructions could be removed if the _real_to_prot function is changed to * deal correctly with 16 bit return addresses. I tried it, but failed. *//**************************************************************************START - Where all the fun begins....**************************************************************************//* this must be the first thing in the file because we enter from the top */ .global _start_start:/* We have to use our own GDT when running in our segment because the old GDT will have the wrong descriptors for the real code segments */ sgdt gdtsave /* save old GDT */ lgdt gdtarg /* load ours */ /* reload the segment registers */ movl $KERN_DATA_SEG,%eax movl %eax,%ds movl %eax,%es movl %eax,%ss movl %eax,%fs movl %eax,%gs /* flush prefetch queue, and reload %cs:%eip */ ljmp $KERN_CODE_SEG,$1f1: /* save the stack pointer and jump to the routine */ movl %esp,%eax movl %eax,initsp movl $RELOC+FIRST32SIZE,%esp /* change stack */ /* copy the arguments on the stack over */ pushl 12(%eax) /* bootp */ pushl 8(%eax) /* header */ pushl 4(%eax) /* ebinfo */ call first /* fall through */_exit:/* we reset sp to the location just before entering first instead of relying on the return from first because exit could have been called from anywhere */ movl initsp,%ebx movl %ebx,%esp lgdt gdtsave /* restore old GDT */ ret .globl exitexit: movl 4(%esp),%eax jmp _exit/**************************************************************************CONSOLE_PUTC - Print a character on console**************************************************************************/ .globl console_putcconsole_putc: pushl %ebp movl %esp,%ebp pushl %ebx pushl %esi pushl %edi movb 8(%ebp),%cl call _prot_to_real .code16 movl $1,%ebx movb $0x0e,%ah movb %cl,%al int $0x10 DATA32 call _real_to_prot .code32 popl %edi popl %esi popl %ebx popl %ebp ret/**************************************************************************E820_MEMSIZE - Get a listing of memory regions**************************************************************************/ .globl meme820#define SMAP 0x534d4150meme820: pushl %ebp movl %esp, %ebp pushl %ebx pushl %esi pushl %edi movl 8(%ebp), %edi /* Address to return e820 structures at */ subl $RELOC, %edi movl 12(%ebp), %esi /* Maximum number of e820 structurs to return */ pushl %esi call _prot_to_real .code16 xorl %ebx, %ebxjmpe820: movl $0xe820, %eax movl $SMAP, %edx movl $20, %ecx /* %di was setup earlier */ int $0x15 jc bail820 cmpl $SMAP, %eax jne bail820good820: /* If this is useable memory, we save it by simply advancing %di by * sizeof(e820rec) */ decl %esi testl %esi,%esi jz bail820 addw $20, %diagain820: cmpl $0, %ebx /* check to see if %ebx is set to EOF */ jne jmpe820bail820: DATA32 call _real_to_prot .code32 popl %eax subl %esi, %eax /* Compute how many structure we read */ /* Restore everything else */ popl %edi popl %esi popl %ebx movl %ebp, %esp popl %ebp ret/**************************************************************************MEMSIZE - Determine size of extended memory**************************************************************************/ .globl memsizememsize: pushl %ebx pushl %esi pushl %edi call _prot_to_real .code16 stc # fix to work around buggy xorw %cx,%cx # BIOSes which dont clear/set xorw %dx,%dx # carry on pass/error of # e801h memory size call # or merely pass cx,dx though # without changing them. movw $0xe801,%ax int $0x15 jc 3f cmpw $0,%cx # Kludge to handle BIOSes jne 1f # which report their extended cmpw $0,%dx # memory in AX/BX rather than je 2f # CX/DX. The spec I have read1: movw %cx,%ax # seems to indicate AX/BX movw %dx,%bx # are more reasonable anyway...2: andl $0xffff,%eax andl $0xffff,%ebx shll $6,%ebx addl %ebx,%eax jmp 4f3: movw $0x8800,%ax int $0x15 andl $0xffff,%eax4: movl %eax,%esi DATA32 call _real_to_prot .code32 movl %esi,%eax popl %edi popl %esi popl %ebx ret/**************************************************************************BASEMEMSIZE - Get size of the conventional (base) memory**************************************************************************/ .globl basememsizebasememsize: call _prot_to_real .code16 int $0x12 movw %ax,%cx DATA32 call _real_to_prot .code32 movw %cx,%ax ret/**************************************************************************XSTART - Transfer control to the kernel just loaded in real mode**************************************************************************/ .globl xstartxstart: pushl %ebp movl %esp,%ebp pushl %ebx pushl %esi pushl %edi movl 8(%ebp),%eax/* Convert to segment:offset form */ movl %eax,%ebx andl $0xF,%eax andl $0xFFFFFFF0,%ebx shll $12,%ebx orl %eax,%ebx call _prot_to_real .code16 movl $((RELOC<<12)+(1f-RELOC)),%eax pushl %eax pushl %ebx lret1: addw $4,%sp /* XXX or is this 10 in case of a 16bit "ret" */ DATA32 call _real_to_prot .code32 popl %edi popl %esi popl %ebx popl %ebp ret/**************************************************************************_REAL_TO_PROT - Go from REAL mode to Protected Mode**************************************************************************/ .globl _real_to_prot_real_to_prot: .code16 cli cs ADDR32 lgdt gdtarg-_start movl %cr0,%eax orl $CR0_PE,%eax movl %eax,%cr0 /* turn on protected mode */ /* flush prefetch queue, and reload %cs:%eip */ DATA32 ljmp $KERN_CODE_SEG,$1f1: .code32 /* reload other segment registers */ movl $KERN_DATA_SEG,%eax movl %eax,%ds movl %eax,%es movl %eax,%ss addl $RELOC,%esp /* Fix up stack pointer */ xorl %eax,%eax movl %eax,%fs movl %eax,%gs popl %eax /* Fix up return address */ addl $RELOC,%eax pushl %eax ret/**************************************************************************_PROT_TO_REAL - Go from Protected Mode to REAL Mode**************************************************************************/ .globl _prot_to_real_prot_to_real: .code32 popl %eax subl $RELOC,%eax /* Adjust return address */ pushl %eax subl $RELOC,%esp /* Adjust stack pointer */#ifdef GAS291 ljmp $REAL_CODE_SEG,$1f-RELOC /* jump to a 16 bit segment */#else ljmp $REAL_CODE_SEG,$1f-_start /* jump to a 16 bit segment */#endif /* GAS291 */1: .code16 movw $REAL_DATA_SEG,%ax movw %ax,%ds movw %ax,%ss movw %ax,%es movw %ax,%fs movw %ax,%gs /* clear the PE bit of CR0 */ movl %cr0,%eax andl $0!CR0_PE,%eax movl %eax,%cr0 /* make intersegment jmp to flush the processor pipeline * and reload %cs:%eip (to clear upper 16 bits of %eip). */ DATA32 ljmp $(RELOC)>>4,$2f-_start2: /* we are in real mode now * set up the real mode segment registers : %ds, $ss, %es */ movw %cs,%ax movw %ax,%ds movw %ax,%es movw %ax,%ss sti DATA32 ret /* There is a 32 bit return address on the stack */ .code32/**************************************************************************GLOBAL DESCRIPTOR TABLE**************************************************************************/ .align 4_gdt:gdtarg: .word 0x27 /* limit */ .long _gdt /* addr */ .byte 0,0_pmcs: /* 32 bit protected mode code segment */ .word 0xffff,0 .byte 0,0x9f,0xcf,0_pmds: /* 32 bit protected mode data segment */ .word 0xffff,0 .byte 0,0x93,0xcf,0_rmcs: /* 16 bit real mode code segment */ .word 0xffff,(RELOC&0xffff) .byte (RELOC>>16),0x9b,0x00,(RELOC>>24)_rmds: /* 16 bit real mode data segment */ .word 0xffff,(RELOC&0xffff) .byte (RELOC>>16),0x93,0x00,(RELOC>>24)gdtsave: .long 0,0,0 /* previous GDT *//* Other variables */initsp: .long 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -