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:
parent
2bdd75bd02
commit
7dcc15e819
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -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++);
|
||||||
|
}
|
Loading…
Reference in New Issue