Implement a LoaderEntry, a function to setup a pagetable, a function to switch to long mode, a function to switch to real mode, Int386 to call interrupts, add some defines for amd64, enable full debug output.

now setupldr should compile, and start it's work. It boots into long mode, reads the memory layout from bios and finally crashes, because the page table is limited to a single page of 2MB atm

svn path=/branches/ros-amd64-bringup/; revision=34727
This commit is contained in:
Timo Kreuzer
2008-07-24 02:27:00 +00:00
parent 9ee9e193f1
commit ceaa5e63d3
7 changed files with 491 additions and 7 deletions
@@ -0,0 +1,303 @@
.intel_syntax noprefix
.text
.code16
//.org 0x8000
#define STACK16ADDR 0x7000 /* The 16-bit stack top will be at 0000:7000 */
#define STACK64ADDR 0x74000 /* The 64-bit stack top will be at 0x74000 */
.global RealEntryPoint
RealEntryPoint:
cli
/* Setup real mode segment registers */
xor ax, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Setup a real mode stack */
mov sp, stack16
/* Zero BootDrive and BootPartition */
xor eax, eax
mov _BootDrive, eax
mov _BootPartition, eax
/* Store the boot drive */
mov _BootDrive, dl
/* Store the boot partition */
mov _BootPartition, dh
/* Load the GDT */
lgdt gdtptr
/* Load the IDT */
// lidt idtptr
call x86_16_EnableA20
call x86_16_BuildPageTables
/* Switch to long mode */
call x86_16_SwitchToLong
.code64
/* GO! */
xor rcx, rcx
call _BootMain
/* Return into real mode */
call x86_64_SwitchToReal
.code16
// int 0x19
/* We should never get here */
stop:
jmp stop
nop
nop
/** 16 Bit helper functions ***************************************************/
.code16
x86_16_Empty8042:
.word 0x00eb,0x00eb // jmp $+2, jmp $+2
in al, 0x64
cmp al, 0xff // legacy-free machine without keyboard
jz empty_8042_ret // controllers on Intel Macs read back 0xFF
test al, 0x02
jnz x86_16_Empty8042
empty_8042_ret:
ret
x86_16_EnableA20:
pusha
call x86_16_Empty8042
mov al, 0xD1 // command write
out 0x64, al
call x86_16_Empty8042
mov al, 0xDF // A20 on
out 0x60, al
call x86_16_Empty8042
popa
ret
/*
* We defines one 2MB page at the start of memory, so we can access the first
* 2MBs as if paging was disabled
*/
#define PML4_PAGENUM 60 // Put it high enough so it doesn't interfere with freeldr
#define PAGESIZE 4096
#define PDP_PAGENUM (PML4_PAGENUM + 1)
#define PD_PAGENUM (PDP_PAGENUM + 1)
#define PML4_ADDRESS (PML4_PAGENUM * PAGESIZE)
#define PDP_ADDRESS (PDP_PAGENUM * PAGESIZE)
#define PML4_SEG (PML4_ADDRESS / 16)
x86_16_BuildPageTables:
pusha
push es
mov ax, PML4_SEG
mov es, ax
cld
xor di, di
/* One entry in the PML4 pointing to PDP */
mov ax, ((PDP_PAGENUM << 12) & 0xffff) | 0x00f
stosw
mov ax, (PDP_PAGENUM >> 4)
stosw
xor ax,ax
mov cx, 0x07fe
rep stosw
/* One entry in the PDP pointing to PD */
mov ax, ((PD_PAGENUM << 12) & 0xffff) | 0x00f
stosw
mov ax, (PD_PAGENUM >> 4)
stosw
xor ax,ax
mov cx, 0x07fe
rep stosw
/* One entry in the PD defining a 2MB page */
mov ax, 0x018f
stosw
xor ax,ax
mov cx,0x07ff
rep stosw
/* Return */
pop es
popa
ret
#define LMODE_CS 0x08
#define LMODE_DS 0x10
#define RMODE_CS 0x18 /* RMode code selector, base 0 limit 64k */
#define RMODE_DS 0x20 /* RMode data selector, base 0 limit 64k */
//.global x86_16_SwitchToLong
x86_16_SwitchToLong:
cli
xor ax,ax
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
/* Get the return address off the stack */
pop word ptr code64ret
/* Save 16-bit stack pointer */
mov stack16, sp
mov eax, 0x00a0 // Set PAE and PGE: 10100000b
mov cr4, eax
mov edx, PML4_ADDRESS // Point cr3 at PML4
mov cr3, edx
mov ecx, 0xC0000080 // Specify EFER MSR
rdmsr // Enable long mode
or eax, 0x00000100
wrmsr
mov ebx, cr0 // Activate long mode
or ebx, 0x80000001 // by enabling paging and protection simultaneously
mov cr0, ebx // skipping protected mode entirely
jmp LMODE_CS:offset LongCat //Load CS with 64 bit segment and flush the instruction cache
.code64
LongCat:
/* Set up 64 bit stack */
mov rsp, stack64
/* Put the return address back onto the stack */
push qword ptr code64ret
/* Now return in long mode! */
ret
/** 64 But functions **********************************************************/
.code64
.global x86_64_SwitchToReal
x86_64_SwitchToReal:
/* Get the return address off the stack */
pop qword ptr code64ret
/* Save 64-bit stack pointer */
mov stack64, rsp
/* Step 1 - deactivate long mode, by disabling paging */
mov rax, cr0
and rax, 0x000000007fffffff //~0x80000000
mov cr0, rax
/* Step 2 - disable long mode in EFER MSR */
mov rcx, 0xC0000080 // Specify EFER MSR
rdmsr
and eax, ~0x00000100 // Disable EFER.LME
wrmsr
.code32
/* jmp to 16-bit segment to set the limit correctly */
jmp RMODE_CS: offset SwitchToReal2
SwitchToReal2:
.code16
/* Step 3 - Disable Protected Mode */
mov eax, cr0
and eax, ~0x00000001
mov cr0, eax
/* Clear prefetch queue & correct CS */
jmp 0:offset BeReal
BeReal:
/* Restore segment registers */
mov ax, 0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
/* Rstore 16 bit stack */
mov sp, stack16
// lidt rmode_idtptr /* Load IDTR with real mode value */
// sti /* These are ok now */
/* Put the return address back onto the stack */
push word ptr code64ret
/* Now return in real mode! */
ret
/** Some data *****************************************************************/
.code64
stack16:
.quad STACK16ADDR
stack64:
.quad STACK64ADDR
code64ret:
.quad 0
gdt:
.quad 0x0000000000000000
.quad 0x0020980000000000
.quad 0x0000900000000000
.word 0xFFFF, 0x0000, 0x9E00, 0x0000 /* 16-bit real mode CS */
.word 0xFFFF, 0x0000, 0x9200, 0x0000 /* 16-bit real mode DS */
/* GDT table pointer */
gdtptr:
.word 0x27 /* Limit */
.long gdt /* Base Address */
.global _BootDrive
_BootDrive:
.long 0
.global _BootPartition
_BootPartition:
.long 0
///////////////////////////////////////////////////////////////////////////////
/* Need to include them here, because of linking issues between 64 / 16 bit */
//#include "debug16.S"
#include "int386.S"
#include "boot.S"
#include "i386pnp.S"
@@ -0,0 +1,170 @@
/*
* FreeLoader
* Copyright (C) 1998-2002 Brian Palmer <brianp@sginet.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
.intel_syntax noprefix
.text
.code16
#define ASM
#include <arch.h>
Int386_REGS:
Int386_eax:
.long 0
Int386_ebx:
.long 0
Int386_ecx:
.long 0
Int386_edx:
.long 0
Int386_esi:
.long 0
Int386_edi:
.long 0
Int386_ds:
.word 0
Int386_es:
.word 0
Int386_fs:
.word 0
Int386_gs:
.word 0
Int386_eflags:
.long 0
Int386_vector:
.quad 0
Int386_regsin:
.quad 0
Int386_regsout:
.quad 0
/*
* int Int386(int ivec, REGS* in, REGS* out);
*/
EXTERN(_Int386)
.code64
/* Get the function parameters */
mov Int386_vector, rcx
mov Int386_vector_opcode, cl
mov Int386_regsin, rdx
mov Int386_regsout, r8
/* Save all registers + segment registers */
// push ds
// push es
push fs
push gs
push rbx
push rcx
push rdx
push rsi
push rdi
/* Copy the input regs to our variables */
lea rdi, Int386_REGS
mov esi, Int386_regsin
mov ecx, 0x24
rep movsb
call x86_64_SwitchToReal
.code16
/* Setup the registers */
mov ax, cs:Int386_ds
mov ds, ax /* DS register */
mov ax, cs:Int386_es
mov es, ax /* ES register */
mov ax, cs:Int386_fs
mov fs, ax /* FS register */
mov ax, cs:Int386_gs
mov gs, ax /* GS register */
mov eax, cs:Int386_eax /* EAX register */
mov ebx, cs:Int386_ebx /* EBX register */
mov ecx, cs:Int386_ecx /* ECX register */
mov edx, cs:Int386_edx /* EDX register */
mov esi, cs:Int386_esi /* ESI register */
mov edi, cs:Int386_edi /* EDI register */
/* Do not set the flags register */
/* only return its value in regsout */
//pushl Int386_eflags
//popfl /* EFLAGS register */
/* Call the interrupt vector */
/*int Int386_vector*/
Int386_int_opcode:
.byte 0xcd
Int386_vector_opcode:
.byte 0x00
/* Save the registers */
mov cs:Int386_eax, eax /* EAX register */
mov cs:Int386_ebx, ebx /* EBX register */
mov cs:Int386_ecx, ecx /* ECX register */
mov cs:Int386_edx, edx /* EDX register */
mov cs:Int386_esi, esi /* ESI register */
mov cs:Int386_edi, edi /* EDI register */
mov ax, ds /* DS register */
mov cs:Int386_ds, ax
mov ax, es /* ES register */
mov cs:Int386_es, ax
mov ax, fs /* FS register */
mov cs:Int386_fs, ax
mov ax, gs /* GS register */
mov cs:Int386_gs, ax
pushf
pop cs:Int386_eflags /* EFLAGS register */
call x86_16_SwitchToLong
.code64
/* Copy the variables to the output regs */
lea rsi, Int386_REGS
mov rdi, Int386_regsout
mov rcx, 0x24
rep movsb
/* Restore segment and all other registers */
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
pop gs
pop fs
// pop es
// pop ds
/* Get return value */
xor rax, rax
mov eax, Int386_eax
ret
+4 -4
View File
@@ -23,11 +23,11 @@
#ifdef DBG
//#define DEBUG_ALL
#define DEBUG_ALL
//#define DEBUG_INIFILE
//#define DEBUG_REACTOS
//#define DEBUG_CUSTOM
#define DEBUG_NONE
//#define DEBUG_NONE
#if defined (DEBUG_ALL)
ULONG DebugPrintMask = DPRINT_WARNING | DPRINT_MEMORY | DPRINT_FILESYSTEM |
@@ -243,7 +243,7 @@ VOID DebugPrintHeader(ULONG Mask)
VOID DebugPrint(ULONG Mask, char *format, ...)
{
va_list ap;
char Buffer[4096];
char Buffer[2096];
char *ptr = Buffer;
// Mask out unwanted debug messages
@@ -271,7 +271,7 @@ VOID DebugPrint(ULONG Mask, char *format, ...)
VOID DebugPrint1(char *format, ...)
{
va_list ap;
char Buffer[4096];
char Buffer[2096];
char *ptr = Buffer;
va_start(ap, format);
@@ -84,6 +84,7 @@
<file>i386disk.c</file>
<file>i386rtl.c</file>
<file>i386vid.c</file>
<file>loader.c</file>
<file>pccons.c</file>
<file>pcdisk.c</file>
<file>pcmem.c</file>
@@ -26,7 +26,6 @@
<file>i386cpu.S</file>
<file>i386idt.S</file>
<file>i386trap.S</file>
<!-- file>linux.S</file -->
<file>mb.S</file>
</directory>
</if>
+2 -2
View File
@@ -106,14 +106,14 @@ typedef struct _MASTER_BOOT_RECORD
// i386 BIOS Disk Functions (i386disk.c)
//
///////////////////////////////////////////////////////////////////////////////////////
#ifdef __i386__
#if defined(__i386__) || defined(_M_AMD64)
BOOLEAN DiskResetController(ULONG DriveNumber);
BOOLEAN DiskInt13ExtensionsSupported(ULONG DriveNumber);
//VOID DiskStopFloppyMotor(VOID);
BOOLEAN DiskGetExtendedDriveParameters(ULONG DriveNumber, PVOID Buffer, USHORT BufferSize);
#endif // defined __i386__
#endif // defined __i386__ || defined(_M_AMD64)
///////////////////////////////////////////////////////////////////////////////////////
//
+11
View File
@@ -50,6 +50,17 @@ typedef struct
#endif // defined __i386__ or _PPC_ or _MIPS_
#if defined (_AMD64_)
#define MM_PAGE_SIZE 4096
#define MM_PAGE_MASK 0xFFF
#define MM_PAGE_SHIFT 12
#define MM_SIZE_TO_PAGES(a) \
( ((a) >> MM_PAGE_SHIFT) + ((a) & MM_PAGE_MASK ? 1 : 0) )
#endif
// HEAP and STACK size
#define HEAP_PAGES 0x400
#define STACK_PAGES 0x00