9
0
Fork 0

Add functions to be able to boot with BIOSs help

These functions are special: They are running in the 16 bit real mode world
to bring up barebox on an x86 box.

Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Juergen Beisert 2010-01-12 11:15:41 +01:00 committed by Sascha Hauer
parent 2bdd75bd02
commit 7dcc15e819
12 changed files with 1027 additions and 0 deletions

20
arch/x86/boot/Kconfig Normal file
View File

@ -0,0 +1,20 @@
if X86_BIOS_BRINGUP
menu "BIOS boot source "
config X86_HDBOOT
bool "HD boot"
help
Add code to boot from harddisk
config X86_VESA
bool
default y if X86_GENERIC_HAS_VIDEO
config X86_VGA
bool
default y if X86_GENERIC_HAS_VIDEO
endmenu
endif

13
arch/x86/boot/Makefile Normal file
View File

@ -0,0 +1,13 @@
CPPFLAGS += -D__I386__ -fno-strict-aliasing -m32 -g -Os -march=i386 \
-mregparm=3 -fno-strict-aliasing -fomit-frame-pointer -ffreestanding \
-fno-toplevel-reorder -fno-unit-at-a-time -fno-stack-protector \
-mpreferred-stack-boundary=2
obj-$(CONFIG_X86_HDBOOT) += boot_main.o boot_hdisk.o
obj-$(CONFIG_X86_BIOS_BRINGUP) += prepare_uboot.o a20.o bioscall.o regs.o tty.o pmjump.o main_entry.o
obj-$(CONFIG_X86_VESA) += console_vesa.o
obj-$(CONFIG_X86_VGA) += console_vga.o
obj-$(CONFIG_X86_SERIAL) += console_serial.o

170
arch/x86/boot/a20.c Normal file
View File

@ -0,0 +1,170 @@
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright 2007-2008 rPath, Inc. - All Rights Reserved
* Copyright 2009 Intel Corporation; author H. Peter Anvin
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2.
*
* ----------------------------------------------------------------------- */
/*
* Enable A20 gate (return -1 on failure)
*/
#include <asm/segment.h>
#include <asm/io.h>
#include "boot.h"
#define MAX_8042_LOOPS 100000
#define MAX_8042_FF 32
/* be aware of: */
THIS_IS_REALMODE_CODE
static int __bootcode empty_8042(void)
{
u8 status;
int loops = MAX_8042_LOOPS;
int ffs = MAX_8042_FF;
while (loops--) {
io_delay();
status = inb(0x64);
if (status == 0xff) {
/* FF is a plausible, but very unlikely status */
if (!--ffs)
return -1; /* Assume no KBC present */
}
if (status & 1) {
/* Read and discard input data */
io_delay();
(void)inb(0x60);
} else if (!(status & 2)) {
/* Buffers empty, finished! */
return 0;
}
}
return -1;
}
/* Returns nonzero if the A20 line is enabled. The memory address
used as a test is the int $0x80 vector, which should be safe. */
#define A20_TEST_ADDR (4*0x80)
#define A20_TEST_SHORT 32
#define A20_TEST_LONG 2097152 /* 2^21 */
static int __bootcode a20_test(int loops)
{
int ok = 0;
int saved, ctr;
set_fs(0x0000);
set_gs(0xffff);
saved = ctr = rdfs32(A20_TEST_ADDR);
while (loops--) {
wrfs32(++ctr, A20_TEST_ADDR);
io_delay(); /* Serialize and make delay constant */
ok = rdgs32(A20_TEST_ADDR+0x10) ^ ctr;
if (ok)
break;
}
wrfs32(saved, A20_TEST_ADDR);
return ok;
}
/* Quick test to see if A20 is already enabled */
static int __bootcode a20_test_short(void)
{
return a20_test(A20_TEST_SHORT);
}
/* Longer test that actually waits for A20 to come on line; this
is useful when dealing with the KBC or other slow external circuitry. */
static int __bootcode a20_test_long(void)
{
return a20_test(A20_TEST_LONG);
}
static void __bootcode enable_a20_bios(void)
{
struct biosregs ireg;
initregs(&ireg);
ireg.ax = 0x2401;
intcall(0x15, &ireg, NULL);
}
static void __bootcode enable_a20_kbc(void)
{
empty_8042();
outb(0xd1, 0x64); /* Command write */
empty_8042();
outb(0xdf, 0x60); /* A20 on */
empty_8042();
outb(0xff, 0x64); /* Null command, but UHCI wants it */
empty_8042();
}
static void __bootcode enable_a20_fast(void)
{
u8 port_a;
port_a = inb(0x92); /* Configuration port A */
port_a |= 0x02; /* Enable A20 */
port_a &= ~0x01; /* Do not reset machine */
outb(port_a, 0x92);
}
/*
* Actual routine to enable A20; return 0 on ok, -1 on failure
*/
#define A20_ENABLE_LOOPS 255 /* Number of times to try */
int __bootcode enable_a20(void)
{
int loops = A20_ENABLE_LOOPS;
int kbc_err;
while (loops--) {
/* First, check to see if A20 is already enabled
(legacy free, etc.) */
if (a20_test_short())
return 0;
/* Next, try the BIOS (INT 0x15, AX=0x2401) */
enable_a20_bios();
if (a20_test_short())
return 0;
/* Try enabling A20 through the keyboard controller */
kbc_err = empty_8042();
if (a20_test_short())
return 0; /* BIOS worked, but with delayed reaction */
if (!kbc_err) {
enable_a20_kbc();
if (a20_test_long())
return 0;
}
/* Finally, try enabling the "fast A20 gate" */
enable_a20_fast();
if (a20_test_long())
return 0;
}
return -1;
}

99
arch/x86/boot/bioscall.S Normal file
View File

@ -0,0 +1,99 @@
/* -----------------------------------------------------------------------
*
* Copyright 2009 Intel Corporation; author H. Peter Anvin
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2 or (at your
* option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
/*
* "Glove box" for BIOS calls. Avoids the constant problems with BIOSes
* touching registers they shouldn't be.
*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
.file "bioscall.S"
.code16
.section .boot.text.intcall, "ax"
.globl intcall
.type intcall, @function
intcall:
/* Self-modify the INT instruction. Ugly, but works. */
cmpb %al, 3f
je 1f
movb %al, 3f
jmp 1f /* Synchronize pipeline */
1:
/* Save state */
pushfl
pushw %fs
pushw %gs
pushal
/* Copy input state to stack frame */
subw $44, %sp
movw %dx, %si
movw %sp, %di
movw $11, %cx
rep; movsd
/* Pop full state from the stack */
popal
popw %gs
popw %fs
popw %es
popw %ds
popfl
/* Actual INT */
.byte 0xcd /* INT opcode */
3: .byte 0
/* Push full state to the stack */
pushfl
pushw %ds
pushw %es
pushw %fs
pushw %gs
pushal
/* Re-establish C environment invariants */
cld
movzwl %sp, %esp
movw %cs, %ax
movw %ax, %ds
movw %ax, %es
/* Copy output state from stack frame */
movw 68(%esp), %di /* Original %cx == 3rd argument */
andw %di, %di
jz 4f
movw %sp, %si
movw $11, %cx
rep; movsd
4: addw $44, %sp
/* Restore state and return */
popal
popw %gs
popw %fs
popfl
retl
.size intcall, .-intcall
/* ------------------------------------------------------------------------ */
.code16
.section .boot.text.die, "ax"
.globl die
.type die, @function
die:
hlt
jmp die
.size die, .-die
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

193
arch/x86/boot/boot.h Normal file
View File

@ -0,0 +1,193 @@
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright 2007 rPath, Inc. - All Rights Reserved
* Copyright 2009 Intel Corporation; author H. Peter Anvin
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2.
*
* ----------------------------------------------------------------------- */
/**
* @file
* @brief Main declarations for the real mode code
*/
#ifndef BOOT_BOOT_H
#define BOOT_BOOT_H
#define STACK_SIZE 512 /* Minimum number of bytes for stack */
/** Carry flag */
#define X86_EFLAGS_CF 0x00000001
/** PE flag */
#define X86_CR0_PE 0x00000001
#ifndef __ASSEMBLY__
#include <types.h>
/* we are still in real mode here! */
#define THIS_IS_REALMODE_CODE asm(".code16gcc");
struct biosregs {
union {
struct {
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t _esp;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
uint32_t _fsgs;
uint32_t _dses;
uint32_t eflags;
};
struct {
uint16_t di, hdi;
uint16_t si, hsi;
uint16_t bp, hbp;
uint16_t _sp, _hsp;
uint16_t bx, hbx;
uint16_t dx, hdx;
uint16_t cx, hcx;
uint16_t ax, hax;
uint16_t gs, fs;
uint16_t es, ds;
uint16_t flags, hflags;
};
struct {
uint8_t dil, dih, edi2, edi3;
uint8_t sil, sih, esi2, esi3;
uint8_t bpl, bph, ebp2, ebp3;
uint8_t _spl, _sph, _esp2, _esp3;
uint8_t bl, bh, ebx2, ebx3;
uint8_t dl, dh, edx2, edx3;
uint8_t cl, ch, ecx2, ecx3;
uint8_t al, ah, eax2, eax3;
};
};
};
/* functions in the realmode part */
extern int enable_a20(void);
extern void initregs(struct biosregs *regs);
extern void intcall(uint8_t int_no, const struct biosregs *ireg, struct biosregs *oreg);
extern void boot_puts(char*);
extern void __attribute__((noreturn)) die(void);
extern void __attribute__((noreturn)) protected_mode_jump(void);
struct gdt_ptr {
uint16_t len;
uint32_t ptr;
} __attribute__((packed));
/* These functions are used to reference data in other segments. */
static inline uint16_t ds(void)
{
uint16_t seg;
asm("movw %%ds,%0" : "=rm" (seg));
return seg;
}
static inline void set_fs(uint16_t seg)
{
asm volatile("movw %0,%%fs" : : "rm" (seg));
}
static inline uint16_t fs(void)
{
uint16_t seg;
asm volatile("movw %%fs,%0" : "=rm" (seg));
return seg;
}
static inline void set_gs(uint16_t seg)
{
asm volatile("movw %0,%%gs" : : "rm" (seg));
}
static inline uint16_t gs(void)
{
uint16_t seg;
asm volatile("movw %%gs,%0" : "=rm" (seg));
return seg;
}
typedef unsigned int addr_t;
static inline uint8_t rdfs8(addr_t addr)
{
uint8_t v;
asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*(uint8_t *)addr));
return v;
}
static inline uint16_t rdfs16(addr_t addr)
{
uint16_t v;
asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*(uint16_t *)addr));
return v;
}
static inline uint32_t rdfs32(addr_t addr)
{
uint32_t v;
asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*(uint32_t *)addr));
return v;
}
static inline void wrfs8(uint8_t v, addr_t addr)
{
asm volatile("movb %1,%%fs:%0" : "+m" (*(uint8_t *)addr) : "qi" (v));
}
static inline void wrfs16(uint16_t v, addr_t addr)
{
asm volatile("movw %1,%%fs:%0" : "+m" (*(uint16_t *)addr) : "ri" (v));
}
static inline void wrfs32(uint32_t v, addr_t addr)
{
asm volatile("movl %1,%%fs:%0" : "+m" (*(uint32_t *)addr) : "ri" (v));
}
static inline uint8_t rdgs8(addr_t addr)
{
uint8_t v;
asm volatile("movb %%gs:%1,%0" : "=q" (v) : "m" (*(uint8_t *)addr));
return v;
}
static inline uint16_t rdgs16(addr_t addr)
{
uint16_t v;
asm volatile("movw %%gs:%1,%0" : "=r" (v) : "m" (*(uint16_t *)addr));
return v;
}
static inline uint32_t rdgs32(addr_t addr)
{
uint32_t v;
asm volatile("movl %%gs:%1,%0" : "=r" (v) : "m" (*(uint32_t *)addr));
return v;
}
static inline void wrgs8(uint8_t v, addr_t addr)
{
asm volatile("movb %1,%%gs:%0" : "+m" (*(uint8_t *)addr) : "qi" (v));
}
static inline void wrgs16(uint16_t v, addr_t addr)
{
asm volatile("movw %1,%%gs:%0" : "+m" (*(uint16_t *)addr) : "ri" (v));
}
static inline void wrgs32(uint32_t v, addr_t addr)
{
asm volatile("movl %1,%%gs:%0" : "+m" (*(uint32_t *)addr) : "ri" (v));
}
/** use the built in memset function for the real mode code */
#define memset(d,c,l) __builtin_memset(d,c,l)
#endif /* __ASSEMBLY__ */
#endif /* BOOT_BOOT_H */

176
arch/x86/boot/boot_hdisk.S Normal file
View File

@ -0,0 +1,176 @@
/*
* Copyright (C) 2009 Juergen Beisert, Pengutronix
*
* This code was inspired by the GRUB2 project.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
/**
* @file
* @brief Loading the barebox image from a disk drive in LBA mode
*/
/**
* @fn void real_start(void)
* @brief A very simple and small loader to fetch all required sectors
* from the boot media.
*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
.file "boot_hdisk.S"
.code16
/*
* These symbols are generated by the linker, because they need a
* special layout. This layout is needed to be able to setup this
* bootloader by patching the binary when it gets stored into the
* master boot record.
*/
.extern indirect_sector_lba
.extern boot_stack
.extern start_pre_uboot
.extern boot_disk
.section .boot_code, "ax"
.globl real_start
.type real_start, @function
real_start:
xorw %ax, %ax /* set up %ds and %ss as offset from 0 */
movw %ax, %ds
movw %ax, %ss
/* set up the REAL stack */
movw $boot_stack, %sp
sti /* we're safe again */
/* save drive reference first thing! */
movb %dl, boot_disk
pushw %dx
movw $notification_string, %si
call output_message
/*
* This boot code only supports LBA. We fail here, if the BIOS
* does not support LBA for the harddisk
*/
/* check if LBA is supported */
movb $0x41, %ah
movw $0x55aa, %bx
int $0x13
/*
* %dl may have been clobbered by INT 13, AH=41H.
* This happens, for example, with AST BIOS 1.04.
*/
popw %dx
pushw %dx
/* stop if no LBA support */
jc no_lba
cmpw $0xaa55, %bx
jne no_lba
andw $1, %cx
jz no_lba
lba_mode:
/*
* Load the indirect sector. Its content is ready for use,
* provided by the installer
*/
movw $indirect_sector_lba, %si
movb $0x42, %ah
int $0x13
jc no_lba /* error? Then die */
/*
* Now loop through all valid entries in the indirect sector
*/
movw $indirect_area, %si
load_loop:
/*
* Stop if this "Disk Address Packet Structure" is invalid
* We call it invalid, if the size member is zero. If it is invalid
* we are optimistic and calling the loaded image
*/
movw (%si), %ax
cmpw $0x0000, %ax
je start_main
/*
* Load this entry
*/
movb $0x42, %ah
int $0x13
jc no_lba
addw (%si), %si /* next entry */
cmpw $indirect_area + 512, %si
jne load_loop
/*
* fall through to start u-boot.
*/
start_main:
movw $jmp_string, %si
call output_message
jmp start_pre_uboot
/*
* die if there is no LBA support
*/
no_lba: movw $chs_string, %si
call output_message
hlt
/*
* message: write the string pointed to by %si
*
* WARNING: trashes %si, %ax, and %bx
*/
/*
* Use BIOS "int 10H Function 0Eh" to write character in teletype mode
* %ah = 0xe %al = character
* %bh = page %bl = foreground color (graphics modes)
*/
1:
movw $0x0001, %bx
movb $0xe, %ah
int $0x10 /* display this char */
output_message:
lodsb
cmpb $0, %al
jne 1b /* if not end of string, next char */
ret
/* ---------------------------------------------------------------------- */
.section .boot_data
notification_string: .asciz "UBOOT2 "
chs_string: .asciz "CHS "
jmp_string: .asciz "JMP "
#endif

58
arch/x86/boot/boot_main.S Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2009 Juergen Beisert, Pengutronix
*
* This code was inspired by the GRUB2 project.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
/**
* @file
* @brief Common boot sector main routine to be entered by the BIOS
*/
/**
* @fn void _start(void)
*
* @brief Fix segment:offset settings of some buggy BIOSs
*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
.file "boot_main.S"
.code16
.extern real_start
.section .boot_start, "ax"
.type _start, @function
/*
* The BIOS loads this code to address 0x00007c00.
* The code should be called with CS:IP 0:0x7c00 (hopefully).
*/
.globl _start
_start:
cli /* we're not safe here! */
/*
* It seems there are implementations in the wild which call this
* code with CS:IP 0x07C0:0000 instead. We fix it immediately.
*/
ljmp $0, $real_start
.size _start, .-_start
#endif

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2009 Juergen Beisert, Pengutronix
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
/**
* @file
* @brief Start of the 32 bit flat mode
*/
#include <string.h>
/* These symbols are generated by the linker */
extern char __bss_start;
extern char __bss_end;
extern void start_barebox(void);
/**
* Called plainly from assembler that switches from real to flat mode
*
* @note The C environment isn't initialized yet
*/
void uboot_entry(void)
{
/* clear the BSS first */
memset(&__bss_start, 0x00, &__bss_end - &__bss_start);
start_barebox();
}

89
arch/x86/boot/pmjump.S Normal file
View File

@ -0,0 +1,89 @@
/* ----------------------------------------------------------------------- *
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright 2007 rPath, Inc. - All Rights Reserved
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2.
*
* ----------------------------------------------------------------------- */
/**
* @file
* @brief The actual transition into protected mode
*
* Note: This function is running in flat and real mode. Due to some
* other restrictions it must running from an address space below 0x10000
*/
/**
* @fn void protected_mode_jump(void)
* @brief Switches the first time from real mode to flat mode
*/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#include <asm/modes.h>
#include "boot.h"
.file "pmjump.S"
.code16
.section .boot.text.protected_mode_jump, "ax"
.globl protected_mode_jump
.type protected_mode_jump, @function
protected_mode_jump:
jmp 1f /* Short jump to serialize on 386/486 */
1:
movw $__BOOT_DS, %cx
movw $__BOOT_TSS, %di
movl %cr0, %edx
orb $X86_CR0_PE, %dl /* enable protected mode */
movl %edx, %cr0
/* Transition to 32-bit flat mode */
data32 ljmp $__BOOT_CS, $in_pm32
/* ------------------------------------------------------------------------ */
.section ".text.in_pm32","ax"
.code32
.extern uboot_entry
.extern __bss_end
.type in_pm32, @function
in_pm32:
# Set up data segments for flat 32-bit mode
movl %ecx, %ds
movl %ecx, %es
movl %ecx, %fs
movl %ecx, %gs
movl %ecx, %ss
/*
* Our flat mode code uses its own stack area behind the bss. With this we
* are still able to return to real mode temporarely
*/
movl $__bss_end + 32768, %esp
# Set up TR to make Intel VT happy
ltr %di
# Clear registers to allow for future extensions to the
# 32-bit boot protocol
xorl %ecx, %ecx
xorl %edx, %edx
xorl %ebx, %ebx
xorl %ebp, %ebp
xorl %edi, %edi
# Set up LDTR to make Intel VT happy
lldt %cx
jmp uboot_entry
.size protected_mode_jump, .-protected_mode_jump
#endif

View File

@ -0,0 +1,86 @@
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright 2007 rPath, Inc. - All Rights Reserved
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2.
*
* ----------------------------------------------------------------------- */
/*
* Prepare the machine for transition to protected mode.
*/
#include <asm/segment.h>
#include <asm/modes.h>
#include <asm/io.h>
#include "boot.h"
/* be aware of: */
THIS_IS_REALMODE_CODE
/*
* While we are in flat mode, we can't handle interrupts. But we can't
* switch them off for ever in the PIC, because we need them again while
* entering real mode code again and again....
*/
static void __bootcode realmode_switch_hook(void)
{
asm volatile("cli");
outb(0x80, 0x70); /* Disable NMI */
io_delay();
}
/*
* Reset IGNNE# if asserted in the FPU.
*/
static void __bootcode reset_coprocessor(void)
{
outb(0, 0xf0);
io_delay();
outb(0, 0xf1);
io_delay();
}
/**
* Setup and register the global descriptor table (GDT)
*
* @note This is for the first time only
*/
static void __bootcode setup_gdt(void)
{
/* Xen HVM incorrectly stores a pointer to the gdt_ptr, instead
of the gdt_ptr contents. Thus, make it static so it will
stay in memory, at least long enough that we switch to the
proper kernel GDT. */
static struct gdt_ptr __bootdata gdt_ptr;
gdt_ptr.len = gdt_size - 1;
gdt_ptr.ptr = (uint32_t)&gdt + (ds() << 4);
asm volatile("lgdtl %0" : : "m" (gdt_ptr));
}
static char a20_message[] __bootdata = "A20 gate not responding, unable to boot...\n";
/*
* Actual invocation sequence
*/
void __bootcode start_pre_uboot(void)
{
/* Hook before leaving real mode, also disables interrupts */
realmode_switch_hook();
/* Enable the A20 gate */
if (enable_a20()) {
boot_puts(a20_message);
die();
}
/* Reset coprocessor (IGNNE#) */
reset_coprocessor();
setup_gdt();
/* Actual transition to protected mode... */
protected_mode_jump();
}

34
arch/x86/boot/regs.c Normal file
View File

@ -0,0 +1,34 @@
/* -----------------------------------------------------------------------
*
* Copyright 2009 Intel Corporation; author H. Peter Anvin
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2 or (at your
* option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
/**
* @file
* @brief Simple helper function for initializing a register set.
*
* Note that this sets EFLAGS_CF in the input register set; this
* makes it easier to catch functions which do nothing but don't
* explicitly set CF.
*/
#include <asm/segment.h>
#include "boot.h"
/* be aware of: */
THIS_IS_REALMODE_CODE
void __bootcode initregs(struct biosregs *reg)
{
memset(reg, 0, sizeof *reg);
reg->eflags |= X86_EFLAGS_CF;
reg->ds = ds();
reg->es = ds();
reg->fs = fs();
reg->gs = gs();
}

45
arch/x86/boot/tty.c Normal file
View File

@ -0,0 +1,45 @@
/* -*- linux-c -*- ------------------------------------------------------- *
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright 2007 rPath, Inc. - All Rights Reserved
* Copyright 2009 Intel Corporation; author H. Peter Anvin
*
* This file is part of the Linux kernel, and is made available under
* the terms of the GNU General Public License version 2.
*
* ----------------------------------------------------------------------- */
/**
* @file
* @brief Very simple screen I/O for the initialization stage
*
* @todo Probably should add very simple serial I/O?
* @attention This is real mode code!
*/
#include <asm/segment.h>
#include "boot.h"
/* be aware of: */
THIS_IS_REALMODE_CODE
static void __bootcode putchar(int ch)
{
struct biosregs ireg;
if (ch == '\n')
putchar('\r'); /* \n -> \r\n */
initregs(&ireg);
ireg.bx = 0x0007;
ireg.cx = 0x0001;
ireg.ah = 0x0e;
ireg.al = ch;
intcall(0x10, &ireg, NULL);
}
void __bootcode boot_puts(char *str)
{
while (*str)
putchar(*str++);
}